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.