Lecteur de musique de bureau pour Linux, dans l'esprit de Spotify : affichage animé façon vinyle, gestion de bibliothèque musicale, recherche de pochettes en ligne et lecture audio.
Projet personnel, vibecodé et optimisé pour Manjaro Linux avec PipeWire.
- Fonctionnalités
- Aperçu technique
- Prérequis
- Installation
- Documentation technique
- Dépannage
- Historique de conception
- Statut du projet
- 🎵 Moteur audio GStreamer — pipeline
playbin → pulsesinkdirect, sans bin intermédiaire, pour une lecture sans craquements ni distorsion - 💿 Affichage vinyle animé
- 📀 Grille d'albums avec scrollbar cliquable et défilement fluide
- 🖼️ Pochettes d'album avec cache Cairo pré-converti pour un rendu rapide
- 🔍 Recherche de pochettes en ligne
- 📊 Barre de progression dessinée en Cairo (
Gtk.DrawingArea), plus légère et plus réactive qu'unGtk.Scale - ⌨️ Support des touches multimédia via un service MPRIS2 (D-Bus)
- 📚 Gestion de bibliothèque musicale (scan, base de données SQLite, métadonnées via mutagen)
- 🖱️ Menus contextuels :
- sur les pochettes : ajouter en favori, rechercher une pochette, infos artiste (Wikipédia)
- sur les pistes : ajouter en favori, paroles, infos fichier, vidéo YouTube
- ⚡ Chargement parallèle des pochettes (
ThreadPoolExecutor, 8 workers) - 🔤 Troncature intelligente des noms courts (AC/DC, Led Zeppelin, etc.)
| Composant | Technologie |
|---|---|
| Interface | GTK4 / PyGObject |
| Audio | GStreamer (playbin → pulsesink) |
| Rendu graphique | Cairo |
| Base de données | SQLite |
| Métadonnées | mutagen |
| Images | Pillow |
| Réseau | requests |
| Intégration OS | MPRIS2 (D-Bus) |
- OS recommandé : Manjaro Linux (ou toute distribution Arch-based). Compatible en théorie avec toute distribution Linux disposant de GTK4 et GStreamer.
- Serveur audio : PipeWire (avec le service de compatibilité PulseAudio,
pipewire-pulse) - Bus système : D-Bus (pour le service MPRIS2)
Sur Manjaro/Arch :
sudo pacman -S python python-pip \
gtk4 python-gobject \
gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly \
pipewire pipewire-pulse \
sqlite gitSur Debian/Ubuntu (équivalent, non testé) :
sudo apt install python3 python3-pip \
gir1.2-gtk-4.0 python3-gi python3-gi-cairo \
gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
pipewire pipewire-pulse git| Bibliothèque | Rôle |
|---|---|
PyGObject |
Bindings GTK4 / GObject Introspection |
mutagen |
Lecture des métadonnées audio (ID3, FLAC, etc.) |
Pillow |
Traitement d'images (pochettes) |
requests |
Requêtes HTTP (recherche de pochettes, API externes) |
GStreamer et GTK4 s'installent via les paquets système, pas via pip.
pactl infoLa sortie doit mentionner PipeWire dans le nom du serveur. Si ce n'est pas actif :
systemctl --user status pipewire pipewire-pulsegit clone <url-du-depot> galettify
cd galettifyAvec un environnement virtuel (recommandé) :
python3 -m venv venv
source venv/bin/activate
pip install PyGObject mutagen Pillow requestsSi PyGObject pose problème dans un venv (accès aux bindings système GTK4), l'installer plutôt au niveau système :
pip install --break-system-packages PyGObject mutagen Pillow requests
Si un requirements.txt est fourni :
pip install -r requirements.txtPar défaut, Galettify scanne ~/Musique. Créer le dossier si besoin :
mkdir -p ~/Musiquepython3 galettify.py- ✅ La fenêtre GTK4 s'ouvre sans erreur dans le terminal
- ✅ La bibliothèque
~/Musiqueest scannée et les albums apparaissent en grille - ✅ La lecture d'un morceau ne présente pas de craquements audio
- ✅ Les touches multimédia du clavier contrôlent la lecture (MPRIS2)
rm -rf galettify venvLes données de bibliothèque (base SQLite, cache) sont à supprimer séparément selon leur emplacement configuré.
┌─────────────────────────────┐
│ Interface GTK4 │ ← fenêtre, grille d'albums, menus contextuels
├─────────────────────────────┤
│ Rendu Cairo personnalisé │ ← barre de progression, cache pochettes
├─────────────────────────────┤
│ Moteur audio GStreamer │ ← playbin → pulsesink
├─────────────────────────────┤
│ SQLite (bibliothèque) │ ← métadonnées, favoris, historique
├─────────────────────────────┤
│ MPRIS2 (D-Bus) │ ← touches multimédia, intégration desktop
└─────────────────────────────┘
Le pipeline GStreamer utilisé est playbin → pulsesink en connexion directe, sans bin intermédiaire (audioconvert/audioresample).
⚠️ Point critique : ajouter un bin intermédiaire entreplaybinetpulsesinkprovoque craquements et distorsion. Ne pas réintroduire de conversion/resampling manuel dans le pipeline.
Implémentée via un Gtk.DrawingArea avec rendu Cairo manuel plutôt qu'un Gtk.Scale, ce dernier ralentissant la synchronisation avec le moteur audio.
La scrollbar reste cliquable malgré la présence de gestionnaires GestureClick sur les pochettes (nécessaires pour les clics), grâce à la combinaison de :
PolicyType.ALWAYSset_overlay_scrolling(False)- une classe CSS dédiée (
.album-grid-scroll)
Ces trois éléments sont nécessaires conjointement ; en retirer un seul réintroduit le problème.
- Les pochettes sont converties en surfaces Cairo une seule fois puis mises en cache (
_cairo_surf) pour éviter les reconversions à chaque rendu. - Le chargement se fait en parallèle via un
ThreadPoolExecutor(8 workers) pour ne pas bloquer l'interface pendant le scan.
⚠️ Point d'attention : après modification d'une pochette, il faut invalider le cache mémoire (_THUMB_CACHE) et supprimer le fichier miniature sur disque avant de recharger. Faire l'un sans l'autre laisse l'ancienne image affichée.
SQLite stocke la bibliothèque musicale (métadonnées extraites via mutagen), les favoris, et l'historique de lecture.
Un service MPRIS2 est exposé via D-Bus pour le contrôle par les touches multimédia et l'intégration aux indicateurs système du bureau.
smart_trunc(): gère la troncature d'affichage des noms d'artistes courts (AC/DC, Led Zeppelin...) sans les tronquer de façon incohérente.
- Pochette d'album : favoris, recherche de pochette en ligne, infos artiste (Wikipédia)
- Piste : favoris, paroles, informations fichier, recherche vidéo (YouTube)
| Zone | Règle à respecter |
|---|---|
| Pipeline audio | Toujours playbin → pulsesink direct, jamais de bin de conversion intermédiaire |
| Barre de progression | Ne pas revenir à Gtk.Scale |
| Scrollbar de la grille | Conserver PolicyType.ALWAYS + overlay_scrolling(False) + CSS dédiée |
| Cache des pochettes | Invalider _THUMB_CACHE et supprimer le fichier miniature ensemble |
| Symptôme | Cause probable | Solution |
|---|---|---|
| Craquements / distorsion audio | Bin de conversion intermédiaire dans le pipeline GStreamer | Vérifier que le pipeline est bien playbin → pulsesink direct |
| Pas de son | PipeWire/pulsesink non actif | systemctl --user restart pipewire pipewire-pulse |
| Touches multimédia sans effet | Service MPRIS2 non démarré ou D-Bus indisponible | Vérifier les logs au lancement, echo $DBUS_SESSION_BUS_ADDRESS |
| Pochettes non mises à jour après modification | Cache non invalidé | Vider le cache mémoire et supprimer le fichier miniature associé, puis relancer |
| Scrollbar de la grille d'albums non cliquable | Policy de scrolling incorrecte | Vérifier PolicyType.ALWAYS + overlay_scrolling(False) |
Une réécriture complète du projet en Rust a été explorée dans un objectif de performance/robustesse, puis abandonnée au profit du maintien de la base de code Python existante.
Projet personnel en développement actif.
GNU General Public License v3.0.