Coin web de Frédéric Péters

fpeters@0d.be

Régie et toute la musique de l’internet

5 janvier 2022, 17:05

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),

Capture d’écran recherche en cours

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.

Capture d’écran téléchargement en cours

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

Capture d’écran téléchargement terminé

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…