Tuto - Envoyer un flux RSS sur un compte Bluesky

Le réseau social est à la mode et remplace un peu Twitter/X. Mais c’est en voulant rediriger des posts facebook d’une association sur un compte que je me suis lancé là dedans.

Je ne reviendrais pas sur la méthode pour transformer un flux Facebook en flux RSS avec FetchRSS… Le tuto est sur n’importe quel flux RSS, dont celui du blog ici par exemple. Le but est de transformer ça en plusieurs étapes pour que ça donne un post bluesky avec une photo par exemple. J’ai pour cela utilisé le site Pipedream qui offre de larges possibilités d’interfaçage. Et pourtant je n’ai pas utilisé l’intégration de Bluesky dedans. Le résultat est fortement inspiré des scripts de Raymond Camden comme celui-ci.

1ère étape - Le Trigger

…ou déclencheur. Après avoir créé votre compte gratuit pipedream, vous n’avez qu’à créer un projet à l’intérieur duquel vous créez un workflow. Le premier élément de ce workflow est un trigger RSS. Il vous est proposé directement en principe. Vous faites ensuite un copier-coller de votre flux RSS dans Feed URL, vous pouvez aussi régler la prise en compte des premiers éléments. Il vous propose de tester et de sélectionner élément qui servira à tous les tests des éléments suivants.

2ème étape - Mettre en forme le texte

Bluesky est limité à 300 caractères. Je laisse un marge avec ce que je vais rajouter ensuite donc je vais faire une limitation à 200 dans cette partie (dans const maxLength). Le but c’est de supprimer tout ce qui est lié à du codage HTML/XML et de limiter la taille. On va créer un script NodeJS qui va utiliser quelques outils internes fort pratique. J’ai appelé ce script transform_text, nom que je reprends dans les scripts suivants.

import { decode } from 'html-entities';

export default defineComponent({
  async run({ steps, $ }) {
    const truncateText = (text, maxLength) => {
      if (text.length > maxLength) {
        return text.slice(0, maxLength) + '...';
      }
      return text;
    };

    const stripHtmlTags = (text) => {
      return text.replace(/<[^>]*>/g, ''); // Remove HTML tags
    };

    // Example: Assume the RSS feed has 'description' and 'link' fields
    const rssDescription = steps.trigger.event.description || '';
    const rssLink = steps.trigger.event.link || '#'; // Fallback URL if none is provided
    const maxLength = 200; // Set your desired maximum length
    
    // Sanitize and truncate the description
    const sanitizedDescription = decode(stripHtmlTags(rssDescription));
    const truncatedDescription = truncateText(sanitizedDescription, maxLength);

    // Add "texte" with the URL
    const finalDescription = `${truncatedDescription} 
#hashtag
    
texte: ${rssLink}`;
    
    // Log or return the final description
    console.log("Final Description:", finalDescription);
    return finalDescription;
  },
});

3ème étape - Rajout de l’image et envoi

On va reprendre l’élément image intégré éventuellement dans le RSS pour l’intégrer comme image dans le post. Là j’ai mis des textes exemples. Idem pour les logins Bluesky, c’est un exemple et il faut créer un mot de passe d’application dans les paramètres de sécurité de Bluesky. On prend aussi un autre script NodeJS qui suit le précédent. Il va réutiliser le résultat précédent pour que ça soit tout joli avec une image en dessous et éventuellement un tag générique, un petit message avec une URL vers le billet complet.

import * as cheerio from 'cheerio';
import Atproto  from '@atproto/api';
const { RichText, BskyAgent } = Atproto;

export default defineComponent({
  async run({ steps, $ }) {
    const agent = new BskyAgent({
       service: 'https://bsky.social'
    });

    // login bluesky
  await agent.login({
    identifier: 'tonidentifianbluesky',
    password: 'aaa-bbb-ccc-ddd'
  });
     
    if (!steps.trigger.event.link) {
      throw new Error("Missing required link in webhook data");
    }

    // Fetch image from URL instead of reading from file system
    const imageResponse = await fetch(steps.trigger.event["media:content"]["@"].url); // Assuming image URL is provided in trigger
    const imageBuffer = await imageResponse.arrayBuffer();
    const image = Buffer.from(imageBuffer);
    
    const { data } = await agent.uploadBlob(image, { encoding: 'image/jpeg' });
    const imageBlob = data.blob;
   
  }

//rich text
    const rt = new RichText({text: steps.transform_text.$return_value});
    await rt.detectFacets(agent);

// post on bluesky
    await agent.post({
      $type: 'app.bsky.feed.post',
      text: rt.text,
      facets: rt.facets, 
      embed: imageBlob ? {
        $type: 'app.bsky.embed.images', 
        images:[{
          alt: 'texte descriptif de la photo', 
          image: imageBlob
        }]
      } : undefined,
      langs: ['en-US'],
      createdAt: new Date().toISOString()
    })
    
    return steps.trigger.event
  },
})
    

Voilà, à vous de jouer et d’adapter, sans abuser de l’envoi. Mon prochain tuto sera de faire pareil avec une instance Mastodon, évidemment….on peut d’ailleurs enchaîner les deux dans la même série de scripts.


Ecrit le : 02/05/2025
Categorie : tuto
Tags : tuto,pipedream,bluesky

Commentaires : par Mastodon ou E-Mail.