KeiruaProd

I help my clients acquire new users and make more money with their web businesses. I have ten years of experience with SaaS projects. If that’s something you need help with, we should get in touch!
< Back to article list

Bannière Twitter dynamique

Projet du weekend: je me suis bricolé une bannière Twitter dynamique.

C’est à la mode sur Twitch/YT, j’avais envie de la même chose, on va voir comment j’ai codé ça.

Sur Twitter c’est pas répandu mais ce n’est pas une idée nouvelle.

J’ai vu récemment @tdinh_me et @acemtp se lancer là dedans, il y en a sans doute plein d’autres.

Pour faire ça il nous faut 3 trucs:

L’API

L’API Twitter est mal documentée sur https://developer.twitter.com, il y a 2 versions. On doit utiliser l’API version 1, pour laquelle on veut les droits en lecture/écriture. Je me suis fait mordre avec juste l’accès lecture. La version 2 ne permet pas de mettre à jour la bannière de profil. C’est dommage car c’est elle que Twitter compte privilégier à l’avenir.

Après avoir créé le projet correctement, on obtient des identifiants qui permettent alors d’effectuer des requêtes vers l’API.

On range les valeurs dans un fichier .env, pour ne pas inclure les clés directement dans le code versionné du projet.

# config.env
API_KEY="do"
API_KEY_SECRET="re"
ACCESS_TOKEN="mi"
ACCESS_TOKEN_SECRET="fa"

Passons au code Python : on veut récupérer la photo de profil des 5 derniers followers.

J’ai utilisé dotenv pour récupérer mes identifiants Twitter dans les variables d’environnement, et Tweepy pour solliciter l’API.

import os

import tweepy
from dotenv import load_dotenv


# Load environment variables from .env file
load_dotenv("config.env")

if __name__ == "__main__":
    auth = tweepy.OAuthHandler(os.getenv("API_KEY"), os.getenv("API_KEY_SECRET"))
    auth.set_access_token(os.getenv("ACCESS_TOKEN"), os.getenv("ACCESS_TOKEN_SECRET"))
    api = tweepy.API(auth)
    latest_followers = api.get_followers(count=5, skip_status=True)
    print([follower.profile_image_url_https for follower in latest_followers])

On tient quelque chose \o/

Générer la bannière

On peut maintenant générer la bannière complète :

J’ai utilisé la librairie PIL pour générer dynamiquement le reste :

Quand on est satisfait, on génère un fichier PNG et on l’envoie via l’API twitter

Il y a quelques optimisations, par exemple je mets en cache les images déjà téléchargées. En pseudo-code, l’esprit est le suivant:

# Load environment variables from .env file
load_dotenv("config.env")

if __name__ == "__main__":
    auth = tweepy.OAuthHandler(os.getenv("API_KEY"), os.getenv("API_KEY_SECRET"))
    auth.set_access_token(os.getenv("ACCESS_TOKEN"), os.getenv("ACCESS_TOKEN_SECRET"))
    api = tweepy.API(auth)
    latest_followers = api.get_followers(count=5, skip_status=True)
	download_images(latest_followers)
	image = generate_header(latest_followers, WIDTH, HEIGHT)
	image.save(header_filename)
	api.update_profile_banner(header_filename)

Déploiement

On a maintenant besoin de faire la mise à jour à intervalle régulier. Le plus simple, c’est cron, un outil linux qui sert à dire “execute telle opération à telle fréquence”

Mes machines pro/perso ne tournant pas en continu, il nous faut un serveur allumé en continu. J’ai des machines “labo” qui me servent pour ce genre de bricolages. J’utilise ansible pour gérer la configuration de mes outils. Oldie but very goodie.

J’ai donc déployé ce projet avec ansible sur la machine distante, en lui indiquant:

---
  - name: Deploiement
    hosts: bot_machine
    become: yes
    become_user: root
    tasks:
      - name: "Installe les dépendances"
        apt:
          pkg:
            - python3
            - python3-venv
            - vim
          state: latest
          update_cache: true
      - name: "Crée les répertoire nécessaires"
        file:
          path: ""
          state: directory
        with_items:
          - '/twitter-banner'
          - '/twitter-banner/cache'
      - name: "Envoie le code"
        copy: src= dest=
        with_items:
          - { src: 'twitter-header-bot-with-followers.py', dest: '/twitter-banner/bot.py' }
          - { src: 'twitter-header-follow.png', dest: '/twitter-banner/twitter-header-follow.png' }
          - { src: 'requirements.txt', dest: '/twitter-banner/requirements.txt' }
          - { src: 'fonts', dest: '/twitter-banner/' }
          - { src: 'config.env', dest: '/twitter-banner/config.env' }
          - { src: 'cron.sh', dest: '/twitter-banner/cron.sh' }
      - name: "Installe les dépendances du projet dans un environnement virtuel"
        pip:
          requirements: /twitter-banner/requirements.txt
          virtualenv: /twitter-banner/venv
          virtualenv_command: /usr/bin/python3 -m venv
      - name: "Ajoute notre bot dans un cron"
        ansible.builtin.cron:
          name: "Bot"
          minute: "*"
          hour: "*"
          job: "/bin/bash /twitter-banner/cron.sh"