FLOZz Daily Mix : un générateur de playlist pour Nextcloud Music et Subsonic

En début d'été j'avais publié un article sur ma décision de quitter Spotify pour le remplacer par mon propre cloud musical basé sur Nextcloud Music. Dans la conclusion de l'article, j'expliquais qu'une des fonctionnalités de Spotify qui allait beaucoup me manquer était les Daily Mix mais que j'allais y remédier. Et bah c'est de ça dont il va être question aujourd'hui ! 😁️

Les Daily Mix sont des playlists thématiques générées spécifiquement pour vous chaque jour par Spotify. Vous pouvez en avoir une orientée Pop / Rock, une autre orientée Metal, encore une autre plutôt Electro, etc. en fonction de vos goûts musicaux, ou plus précisément en fonction de ce que Spotify connait de vos goûts. Ces playlists permettent de lancer de la musique en un clic sans avoir à réfléchir et à sélectionner manuellement des morceaux ou des albums à écouter.

Aujourd'hui je vais vous parler de FLOZz Daily Mix, une petite application reproduisant, en partie, cette fonctionnalité, mais pour les clouds musicaux implémentant l'API Open Subsonic, comme c'est le cas de Nextcloud Music.

Au final, il ne s'agit que d'un truc qui génère des listes de lecture aléatoires me direz-vous ? Et bien oui... mais non !

Je trouve que les playlists totalement aléatoires sont... meh... pas terribles 😅️. Elles sont souvent peu intéressantes à écouter et la plupart du temps quand je vois les premiers titres, bah.. elles ne me donnent pas spécialement envie... Bref, il leur manque quelque chose.

Contraintes

Pour générer mes Daily Mix, je m'impose quelques contraintes. La principale est de n'utiliser que des données en provenance du cloud pour lequel les playlists sont générées ; il n'est pas question de dépendre d'autres APIs telles que Last.fm.

La seule exception à ceci sera pour la gestion des genres musicaux : il est nécessaire d'en avoir une liste complète, avec les relations entre chaque genre (par exemple le J-Rock descend de l'Alternative Rock qui lui-même descend du Rock). Ces données seront récupérées dans la base de données de MusicBrainz et intégrées à l'application (elles seront hardcodées et pas téléchargées dynamiquement).

Bref, en dehors de l'API Subsonic du cloud visé, logiciel doit se suffire à lui-même.

Pour ce qui est des dépendances (Python) de l'application on va là aussi aller à l'essentiel et en avoir le moins possible. Il n'y en a d'ailleurs aucune actuellement. 😁️

Constitution d'une playlist

Même si j'ai dit en introduction que les playlists totalement aléatoires ne me conviennent pas, on ne peut pas travailler sans un peu d'aléa. FLOZz Daily Mix en utilise donc (beaucoup) lors de la génération des différents mixes, mais pas n'importe comment.

Pour que les listes de lecture générées soient intéressantes, elles sont bâties sur un squelette qui nous permettra de sélectionner des musiques selon différents critères et de les placer de manière stratégique.

Voici un petit schéma de ce squelette :

Schéma du squelette utilisé pour la génération de playlist

Pour chaque type d'emplacement on va calculer un score à partir de différents critères qui dépendent de ce qu'on cherche à y placer, et on va mixer ce score avec des nombres aléatoires afin de sélectionner un pool de musiques éligibles à l'emplacement.

Les musiques seront ensuite tirées au sort à partir de ces pools lors du remplissage des playlists. L'aléatoire intervient donc deux fois : lors de la sélection des musiques, puis lors du remplissage des listes de lecture.

En plus de tout ça, quelques contraintes supplémentaires sont appliquées à la génération :

  • On essaye autant que possible de ne pas avoir deux musiques du même artiste à la suite ; on refait d'ailleurs le tirage au sort de la musique jusqu'à trois fois pour éviter que cela ne se produise (mais des fois ça se produit quand même 🤷️).
  • On ne met pas deux fois la même musique dans une même playlist. Il est toutefois possible qu'une chanson apparaisse plusieurs fois dans un mix si elle existe en plusieurs exemplaires dans le cloud (par exemple dans un Album, dans un Single et dans un Best of) car du point de vue du cloud il s'agit de trois titres différents.

Voyons à présent plus en détail les critères utilisés pour remplir les différents emplacements des listes de lecture.

Musiques « intéressantes »

Pour commencer, on va essayer de placer des musiques « intéressantes », ici représentées en jaune.

Comme vous pouvez le constater, il y en a davantage en début de liste. Il s'agit d'une « accroche », pour donner envie d'écouter ; j'ai en effet plus envie d'écouter la playlist si je vois plein de musiques que j'adore dans les premiers titres. Les musiques « intéressantes » sont ensuite plus espacées mais continuent quand même à être placées à intervalle régulier pour maintenir l'intérêt, pour pouvoir par moment relever la tête de mon code et me dire « ah ouais je l'aime bien celle-là ! ».

Mais qu'est-ce qu'une musique intéressante me demanderez-vous ?

Le principal critère pour déterminer si une musique est plus intéressante qu'une autre c'est la note. Chaque piste peut en effet se voir attribuer une note entre 0 et 5 (la plupart du temps c'est affiché sous forme d'étoiles par les clients). Le score d'intérêt est réajusté à la hausse si la musique a été likée (information affichée sous la forme d'un petit cœur sur la plupart des clients). De même, si la musique a peu d'écoutes (moins de 10), on lui rajoute un petit boost qui diminue lorsque le nombre d'écoutes augmente.

Note

Au sujet des notes :

Lorsqu'une musique n'a pas encore été notée, sa note est de zéro. Dans FLOZz Daily Mix, je ne considère donc pas zéro comme une note valide pour la sélection, et les titres à 0 se voient attribuer la note neutre de 3 à la place.

Pour y voir plus clair, voici comment j'utilise concrètement les notes :

  • (0 étoile) : titre pas encore noté, on le considère à 3.
  • ⭐ (1 étoile) : titre que j'aime pas, je ne veux pas le voir apparaître dans les playlists.
  • ⭐⭐ (2 étoiles) : titre que j'aime pas trop, je veux le voir apparaître rarement dans les playlists.
  • ⭐⭐⭐ (3 étoiles) : neutre. C'est la note de la plupart des musiques de ma collection.
  • ⭐⭐⭐⭐ (4 étoiles) : titre que j'aime bien et que je veux voir apparaître plus souvent dans les playlists.
  • ⭐⭐⭐⭐⭐ (5 étoiles) : titre que j'aime vraiment beaucoup, à écouter sans modération ! 🤩
  • ... et si le titre à un petit like ♥️ en plus, ça rehausse un peu la note.

Note minimale d'admissibilité :

La note minimale pour qu'un titre puisse apparaître dans une playlist est donc de 2 par défaut, mais ce paramètre est configurable (on en reparle un peu plus tard 😉️).

Musiques « fraîches »

Une fois les musiques intéressantes positionnées, place à la fraîcheur ! les musiques « fraîches » sont représentées en vert dans le schéma ci-dessus.

Comme pour les musiques intéressantes, on en place davantage en début de playlist puis on en distille à intervalle régulier.

Les musiques « fraîches » sont celles récemment importées dans le cloud. En effet, si je viens d'ajouter un nouvel album, il est très probable que j'ai très envie de l'écouter, donc on s'arrange pour qu'il apparaisse dans les playlists.

En plus de la date d'ajout au cloud, le score de fraîcheur est calculé avec la date de parution des titres : si les titres ont été édités il y a moins de 5 ans ils reçoivent un petit boost qui diminue avec les années. Et comme pour les musiques intéressantes, un petit boost est également accordé si le titre a peu été écouté.

Fond de catalogue

Viennent ensuite les musiques du « back catalog », représentées en violet dans mon schéma. Afin de ne pas laisser des titres prendre la poussière indéfiniment au fin fond du catalogue, on place quelques titres qui n'ont pas été écoutés depuis longtemps dans les playlists générées.

Le seul critère utilisé pour sélectionner ces musiques, c'est la date de dernière écoute.

Note

NOTE : Seuls les titres ayant déjà été écoutés au moins une fois peuvent prétendre à ces emplacements. Les titres jamais écoutés devraient quant à eux arriver à se frayer un chemin dans les emplacements des musiques « fraîches ».

Musiques « régulières »

Et pour finir, représenté en gris-bleu, les musiques « régulières ». Il s'agit simplement de titres tirés au hasard, mais avec une pondération en fonction de leur note. Un titre bien noté a ainsi un peu plus de chance d'être choisi qu'un titre moins bien noté.

Filtrage des titres

Pour chaque mix généré, les musiques peuvent être filtrées en fonction d'un certain nombre de critères. Pour le moment il y en a quatre de disponibles :

  • La durée minimale de la piste (60 secondes par défaut). Ça permet d'éliminer la plupart des intros et des interludes.
  • La durée maximale de la piste (600 secondes par défaut), pour éviter les musiques trop longues.
  • Le filtrage du titre selon une expression régulière, qui permet d'éliminer des titres qui comportent certains mots. Par exemple l'expression "^.*(intro(duction)?|instrumental|acoustic).*$" permet d'écarter les intros ainsi que les versions instrumentales et les versions acoustiques.
  • La note minimale de la piste (2 par défaut). Si la note de la piste est en dessous de cette valeur, elle sera écartée. Cependant il est important de rappeler qu'une piste non notée (note égale à 0) est considérée comme ayant une note de 3.

Ces filtres permettent déjà d'effectuer un premier tri des musiques, mais ils sont insuffisants. À terme je vais en rajouter d'autres, telle que le genre de la musique ou encore une fourchette de date de parution de l'album. Ça permettrait par exemple de créer des mixes contenant uniquement des morceaux Pop et Rock des années 80.

Comment utiliser FLOZz Daily Mix pour générer des playlists ?

FLOZz Daily Mix est un petit logiciel en ligne de commande écrit en Python. Il se configure via un fichier de configuration dans lequel on peut définir les informations d'accès au cloud et l'ensemble des mixes que l'on souhaite générer. L'idée étant de le lancer toutes les nuits avec une tâche cron pour qu'il régénère de nouvelles playlists chaque jour.

Si vous cherchez le code source, vous le trouverez sur GitHub :

Installation

Pour installer FLOZz Daily Mix c'est très simple. Pour commencer on va s'assurer qu'on a bien une installation complète de Pytnon 3 de disponible. Sous Debian et Ubuntu on peut installer tout le nécessaire à l'aide de la commande suivante :

sudo apt install python3 python3-venv

Ensuite, on va créer un petit environnement virtuel Python pour pas mettre le bazar sur le système :

python3 -m venv ./daily-mix.venv
#               ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
#     dossier dans lequel sera installée l'app

Puis on installe l'application :

./daily-mix.venv/bin/pip install flozz-daily-mix

Et voilà, c'est prêt, on peut le lancer avec la commande suivante :

./daily-mix.venv/bin/flozz-daily-mix --help

Note

NOTE : Je n'ai pas trop prévu de faire tourner FLOZz Daily Mix sous Windows, mais il n'y a pas de raison que ça ne fonctionne pas. Par contre les chemins seront un peu différents sur cet OS. Notamment le dossier "bin" du virtualenv se nommera "Scripts" sur ce système, ce qui nous donnera des commandes comme :

.\daily-mix.venv\Scripts\pip install flozz-daily-mix

Configuration

Comme je l'ai dit plus tôt, FLOZz Daily Mix se configure à l'aide d'un fichier de configuration. Voici un rapide exemple pour voir à quoi ça ressemble, tout du moins au moment où j'écris ces lignes :

[subsonic]
api_url = https://nextcloud.example.org/apps/music/subsonic
api_username = foobar
api_password = s3cr3tp4ssw0rd
api_legacy_authentication = true

[playlist:mix1]
name = FLOZz Mix 1
description = FLOzz Daily Mix
max_tracks = 60
min_track_duration = 60
max_track_duration = 600
ignore_tracks_matching = ^.*(intro(duction)?|instrumental|acoustic).*$
minimal_track_rating = 2

[playlist:topmix1]
name = FLOZz Top Mix
description = Best musics!
max_tracks = 60
minimal_track_rating = 4

Si vous cherchez une version plus à jour et documentée de cette configuration, vous la trouverez sur GitHub :

Avis

Important :

Notez bien que chaque playlist est configurée dans une section nommée [playlist:<PLAYLIST_ID>]. Cet identifiant doit être unique dans toute la configuration et ne doit pas être modifié une fois les mixes générés.

En effet, FLOZz Daily Mix va rajouter cet ID dans la description des différentes playlists, ce qui lui permettra de retrouver celles qu'il a générées et de les mettre à jour. Si d'aventure il ne trouvait pas l'une des playlists, il considèrera qu'elle est nouvelle et il la créera donc de toute pièce.

Il est également important de noter que FLOZz Daily Mix ne supprimera jamais aucune playlist. Si vous en supprimez une de votre configuration, il faudra également la supprimer manuellement de votre cloud.

Générer les mixes

Une fois la configuration écrite, vous pouvez générer vos mixes à l'aide de la commande suivante :

./daily-mix.venv/bin/flozz-daily-mix generate ma_config.conf

La commande va prendre un certain temps pour récupérer les données sur le cloud, puis elle va générer les playlists et enfin les créer (ou les mettre à jour) directement sur votre cloud musical.

Si vous souhaitez simplement voir ce que ça donne dans rien modifier sur votre cloud, c'est possible en rajoutant quelques options :

./daily-mix.venv/bin/flozz-daily-mix generate --dry-run --print-playlist ma_config.conf
  • --dry-run permet d'éviter d'écrire quoi que ce soit dans le cloud,
  • --print-playlist permet d'afficher le contenu des playlists générées dans le terminal, ce qui donnera un résultat similaire à celui-ci :
Capture d'écran : example de playlist

Mise en place de la tâche planifiée

Une fois satisfait de votre configuration, vous pouvez configurer une tâche planifiée si vous souhaitez que ça se lance automatiquement toutes les nuits. Pour ce faire, sur la plupart des distrib' Linux actuelles, vous pouvez créer le fichier "/etc/cron.d/flozz-daily-mix" et y placer un contenu similaire à celui-ci :

0 3 * * * nom_utilisateur /opt/daily-mix.venv/bin/flozz-daily-mix generate /etc/flozz-daily-mix.conf

Ici le cron sera exécuté tous les jours à 3h du matin. Il vous faudra bien entendu remplacer nom_utilisateur par le nom d'un utilisateur valide sur le système, et adapter le chemin vers l'installation de FLOZz Daily Mix et vers votre fichier de configuration.

Conclusion

Je n'ai pas pour habitude d'utiliser mon nom ou mon pseudo pour nommer mes projets, car je trouve que ça fait mégalo, mais dans le cas présent ça m'a semblé pertinent, car les playlists sont générées selon des critères qui me sont propres. Dit autrement, ça fonctionne avec ma bibliothèque musicale, avec la manière dont j'ai taggé mes musiques et le résultat me convient. Il est possible que ça convienne également à d'autres, c'est pour ça que je partage le logiciel, mais je ne garantis rien. 😄️

J'utilise FLOZz Daily Mix depuis quelques mois maintenant, en le faisant évoluer petit à petit, et j'en suis plutôt satisfait. Il y aura forcément quelques petits réglages à faire au niveau de la pondération des critères qui interviennent dans le calcul des différents scores, mais ça se fera avec le temps.

Pour le moment mon principal focus de développement va être l'ajout de la gestion des genres ; c'est une fonctionnalité importante pour pouvoir enfin générer des mixes thématiques. Comme je l'ai dit un peu plus tôt, ça va être un gros morceau, car il faut gérer les relations entre les différents genres. Par exemple si je veux une playlist « Metal », il ne faut pas que seuls les morceaux taggés « Metal » soient sélectionnés, mais aussi tous ceux taggés avec un sous-genre du Metal. Je vais également devoir refaire une passe sur l'ensemble de ma bibliothèque pour m'assurer que le genre de toutes les musiques est correctement défini.

Une fois les genres implémentés, je vais probablement rajouter quelques filtres simples comme ceux permettant de définir une année de parution minimale et maximale. Et avant de sortir la v1.0.0, je vais m'assurer de la compatibilité de l'application avec les autres clouds supportant l'API Open Subsonic, notamment en implémentant l'authentification par jeton.

Il me reste donc un peu de boulot sur ce projet, mais ça avance tranquillement. J'espère en tout cas que cette application pourra être utile à certains et que cet article vous aura intéressé.

À bientôt ! 😁️