Coin web de Frédéric Péters

Régie et toute la musique de l’internet

Question code à la radio bien visible il y a le site web (piloté par le module panikweb) et pas visible du tout il y a le site de gestion (module panikdb). C’était initialement l’interface de saisie pour le site web, découplé pour pouvoir tourner sur le réseau local de la radio, pour un transfert rapide des podcasts et zéro préoccupation quant au stockage de ceux-ci.

Avec le temps les fonctionnalités se sont développées au-delà et ça fait désormais annuaire des membres, agenda des studios, gestion des tranches musicales, wiki, etc. et écran d’accueil pour la régie, pour indiquer le studio qui est à l’antenne, l’éventuel morceau occupé à être diffusé, l’horaire de la prochaine émission, etc. J’ai régulièrement aussi sur cet écran des envies de diffuser du son, j’avais déjà ajouté la possibilité de chercher dans la base de données des morceaux, et la possibilité d’y piocher au hasard cinq titres, idéal en mode matinale « il est 7h et je n’ai pas préparé de programmation musicale ». Mais l’utilisation reste assez rare et pour l’encourager j’aurais à ajouter des fonctionnalités évidentes comme piocher dans les jingles de la radio.

Ce n’est pas ce que je viens d’ajouter.

Une réalité c’est qu’on n'a pas toujours dans la base de données le morceau qu’on veut diffuser et souvent il y a de la diffusion directement depuis Youtube, tristesse totale et morceaux qui ne démarrent pas ou trop tôt ou qui enchaînent automatiquement. Pour éviter ça des animateurs·ices utilisent parfois des sites random pour télécharger et régulièrement ça ne marche pas et parce que j’ai parfois dépanné ainsi il arrive maintenant qu’on me demande la ligne de commande, là, youtube-dl, pour faire le téléchargement.

De là l’idée d’ajouter à la fenêtre d’ajout d’un morceau de la base de donnée la possibilité de directement aller télécharger. Sans trop s’annoncer si une adresse est saisie dans le champ de recherche, ça va désormais chercher le morceau en question (sur Youtube dans l’exemple ici mais ça marche avec quantité de sites différents, j’aurais pu prendre un lien vers bandcamp),

D’abord une première phase synchrone pour récupérer les métadonnées (titre, durée, etc.) pour l’ajouter à la liste des résultats.

Puis en tâche de fond il y a le téléchargement avec un pourcentage d’avancement affiché.

Et une fois que c’est terminé, c’est bon il peut être ajouté à la playlist pour être joué.

Techniquement il y a mille solutions pour déclencher une tâche asynchrone avec des possibilités bien lourdes ici c’est très simple le fichier JSON des métadonnées est enregistré dans le répertoire de téléchargement et une "path unit" systemd surveille celui-ci, /etc/systemd/system/panikdb-ytdl.path :

[Unit]
Description=Triggers when a track must be downloaded

[Path] 
PathModified=/srv/panikdb/panikdb/media/ytdl/

[Install]
WantedBy=multi-user.target

et déclenche le téléchargement quand un fichier y est posé, /etc/systemd/system/panikdb-ytdl.service,

[Unit]
Description=PanikDB ytdl

[Service]
Type=oneshot
ExecStart=/srv/panikdb/bin/panikdb-ytdl.sh
User=panikdb

Ça se joue donc sans avoir de nouveau processus pour attendre ou surveiller, ça marche tout de suite, une fois qu’on se rappelle qu’il faut démarrer l’unit, ex: systemctl start panikdb-ytdl.path.

Pour le code en lui-même j’étais parti pour juste exécuter la commande youtube-dl avec asyncio et surveiller le fichier en cours de téléchargement etc. mais en fin de la page de manuel il y avait un exemple Python et c’est tout simple, dans les grandes lignes :

def progress_hook(d):
    data['_percent_str'] = d.get('_percent_str')
    data['_status'] = d.get('status')
    with open(filename, 'w') as fd:
        json.dump(data, fp=fd, indent=2)

ydl_opts = {
    'quiet': True,
    'noplaylist': True,
    'format': 'bestaudio',
    'outtmpl': os.path.join(self.ytdl_path, '%(id)s.%(ext)s'),
    'updatetime': False,
    'postprocessors': [
        {
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'opus',
        }
    ],
    'progress_hooks': [progress_hook],
}

with youtube_dl.YoutubeDL(ydl_opts) as ydl:
    ydl.download([url])

Tout ça est évidemment disponible dans le dépôt dédié (la commande précise, ytdl.py est ici).

J’ai toujours en perspective d’exposer proprement tout ce qui existe dans panikdb sur une page, pour que ça puisse servir ou inspirer au-delà de Radio Panik, on verra si ça se fait cette année…

5 janvier 2022, 17:05