mastodon icon
twitter icon
youtube icon

Créer un Custom Feed sur BlueSky (Full Stack - Node, MariaDB et Apache)

BlueSky émerge.

Si vous n'êtes pas encore familier avec BlueSky, imaginez un espace en ligne qui rappelle les fonctionnalités de Twitter, où les "skeets" – équivalents des tweets – prennent vie et se propagent. Dans cet univers numérique en constante évolution, je vous propose de découvrir comment façonner votre propre expérience BlueSky. Imaginez pouvoir filtrer, trier et présenter les contenus qui résonnent le plus avec vous. C'est là qu'entre en scène le concept de "feed custom". Plutôt que d'être submergé par une avalanche d'informations, vous avez l'opportunité de choisir ce qui trouve sa place sur votre timeline. Le feed custom, c'est une carte blanche pour ajuster l'algorithme de présentation des skeets en fonction de VOS goûts et de VOS intérêts.

Dans ce billet de blog, nous allons plonger dans les méandres de la création d'un feed custom sur BlueSky. Prêt à plonger ? C'est parti !

feed_1_compressed.jpg
Exemple de feeds sur BlueSky


Mise en place initiale


Pour jeter les bases d'un feed custom sur BlueSky, la première étape consiste à mettre en place l'infrastructure initiale. Nous commencerons par cloner le dépôt officiel du projet depuis GitHub (git clone https://github.com/bluesky-social/feed-generator). Assurez-vous que Node.js est installé sur votre serveur, car le projet est développé en utilisant cette technologie. Avant d'aller plus loin, prenons un moment pour examiner l'architecture globale de ce projet.

struct_2_compressed.jpg
Structure générale du projet


Au coeur de la création de votre feed custom se trouvent trois éléments clés :
  • La "souscription" au "firehose" de BlueSky : Le serveur (src/server.ts) s'abonne au flux WebSocket (ws) de BlueSky, connu sous le nom de "firehose". Ce flux contient une multitude de données, notamment les skeets, les likes, les reskeets, etc. C'est la source brute de l'information que vous allez filtrer et présenter de manière personnalisée.
  • Algorithme de traitement des données (src/subscription.ts) : L'un des éléments cruciaux de ce projet est l'algorithme qui traite les données reçues du flux firehose. Dans le projet de test (src/subscription.ts), tous les skeets qui contiennent le texte "alf" sont identifiés (src/. Les références de ces skeets sont ensuite stockés dans une base de données (better-sqlite)
  • Algorithme de publication de données (src/algos/whats-alf.ts) : Lorsqu'un utilisateur souhaite afficher son feed custom, une requête SQL récupère les skeets filtrés et les présente de manière cohérente et personnalisée à l'utilisateur


Modification du projet pour créer un feed "Charcuterie"


Vous avez maintenant saisi les bases de l'architecture d'un feed custom sur BlueSky, plutôt simple non ? On va maintenant modifier ce projet d'exemple pour créer un feed axé sur la "charcuterie" (parce que, avouons-le, la charcuterie c'est la vie).

Adaptation des variables d'environnement


Nous allons commencer par adapter la configuration du projet à notre environnement spécifique. Il faut adapter le .env.example et ajuster les variables pour refléter les chemins et les paramètres pertinents pour votre serveur.

env_3_compressed.jpg
Configuration des variables d'environnement


Personnalisation de l'algorithme de traitement des données


Maintenant, passons à l'algorithme de traitement des données (src/subscriptions.ts). C'est ici que nous allons filtrer les skeets. Chaque skeet qui évoque la charcuterie ou le pâté sera retenu, donnant naissance à un feed riche en saveurs (C'est de ChatGPT, m'en voulez pas...). On pourra par la suite mettre la logique que l'on souhaite, ici : pourquoi pas un algo de NLP qui vérifie si le skeet parle effectivement de charcuterie ou si le terme est utilisé dans un autre contexte.

logic_4_compressed.jpg
Git diff de l'algorithme de traitement des données provenant du firehose BlueSky


Passage à MariaDB


Vous avez peut-être déjà une stack technologique préférée pour votre site web, c'était le cas pour moi : j'utilise MariaDB pour le reste de mon site, j'ai donc modifié le projet pour refléter cette stack pré-existante. C'était finalement très simple grâce à Kysely (https://kysely.dev/docs/intro).

  • Dans src/db/index.ts, on change le Dialect de Kysely de SqliteDialect à MysqlDialect et on adapte le constructeur.
  • Dans src/db/migrations.ts, il a également fallu que je rajoute la taille des varchar
  • Enfin, dans src/subscriptions.ts, j'ai du modifier la requête SQL pour ignorer les erreurs d'insertions (ce qui remplace les erreurs de conflits). Ca n'est pas exactement similaire, mais pour le moment, ça fera le job


db_5_compressed.jpg
Git diff pour le remplacement de better-sqlite vers MySQL2 et MariaDB


On crée le feed de charcuterie


Pour la récupération des skeets depuis la base de donnée, on va pour le moment copier ce qui se faisait dans le projet exemple : on copie le fichier (src/algos/whats-alf.ts) et on modifie simplement son petit nom. On prépare ensuite le script de publication du feed. Il faudra notamment rentrer votre handle BlueSky ainsi qu'un mot de passe (je conseille de créer un App Password). Une petite remarque : les différentes données qui seront affichées (recordName, displayName et description) sont TOUTES soumises à des contraintes de taille. C'était précisé pour le recordName mais pas pour le reste, alors faites attention !

publish_6_compressed.jpg
Modification du script de publication du feed


Exposer le serveur


L'heure est venue de donner vie au feed en le rendant accessible au monde. Lorsque l'on démarre le serveur Node.js, il est configuré pour discuter sur http://FEEDGEN_LISTENHOST:FEEDGEN_PORT". Pour que le feed soit trouvable sur bsky.app, nous devons permettre au serveur de répondre aux requêtes HTTPS via le port 443.

Je disposais déjà d'une stack Apache en place avec HTTPS activé sur mon blog. Petit problème donc : comment permettre au serveur de décider quelle requêtes doivent attérir sur le blog, et quelle requêtes doivent être traitées par le serveur de génération de custom feed ? La solution : Reverse Proxy.

Les étapes ont été les suivantes :
  • Ajout de bsky.alth.fr au certificat Let's Encrypt : J'ai déjà un certificat SSL valide de Let's Encrypt pour mon domaine, j'ai simplement ajouté "bsky.alth.fr" à la liste des noms de domaine inclus dans le certificat.
  • Activation des modules de proxy de Apache et configuration du Reverse Proxy (Vous pouvez vous inspirer de ce billet de blog pour rediriger une requête https://bsky.alth.fr vers le serveur node-js : https://perhonen.fr/blog/2015/05/un-reverse-proxy-apache-avec-mod_proxy-1713)


On peut vérifier que ça fonctionne : https://bsky.alth.fr/ répond, et si on fait une requête bien formée, le JSON est retourné correctement : https://bsky.alth.fr/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:etms2tmaniqdio6pb5ray7y2/app.bsky.feed.generator/charcuterie

feed_7_compressed.jpg
Réponse du serveur à une requête bien formée


Maintenant que tout est en place, on peut s'amuser à modifier l'algorithme pour le rendre un peu plus complexe qu'une simple recherche de chaîne de caractère. C'est à vous !