Git Product home page Git Product logo

sunflower-radio's Introduction

Logo

Radio Tournesol

Python 3.8 Tests

Principe

image

Une webradio est composé de divers éléments :

  • un encodeur de flux audio, par exemple liquidsoap
  • un diffuseur de flux audio, par exemple icecast
  • un client de lecture

Radio Tournesol s'insère dans deux de ces éléments :

  • l'encodage : le programme génère, à partir d'un planning, la configuration pour liquidsoap qui changer de chaîne en fonction des horaires. De plus un scheduler surveille les publicités et demande à liquidsoap de jouer de la musique à la place de la station s'il en détecte ;
  • le client de lecture : Radio Tournesol propose sa propre interface web ainsi qu'une API exposant des données.

Fonctionnement de Radio Tournesol

Scheduler

Un planificateur (Scheduler) s'occupe de gérer des objets chaînes Channel qui contiennent des références vers les stations utilisées. À intervalle de temps régulier, il appelle une méthode process() de ces objets qui va lancer des traitements, par exemple pour aller chercher les informations sur le programme en cours de diffusion.

Channel

Elle est composée de stations. Elle va puiser les métadonnées chez les stations enregistrées. Lors de son instanciation, on indique les stations utilisées, son nom (qui sera aussi son endpoint), ainsi que sa table d'horaires. Par exemple la chaîne Tournesol de Radio Pycolore est définie comme suit :

tournesol = Channel(
    endpoint="tournesol",
    handlers=(AdsHandler,),
    timetable={
        # (weekday1, weekday2, ...)
        (0, 1, 2, 3, 4): [
            # (start, end, station_name),
            ("00:00", "05:00", FranceCulture),
            ("05:00", "07:00", FranceInfo),
            ("07:00", "10:00", FranceInter),
            ("10:00", "11:00", PycolorePlaylistStation),
            ("11:00", "12:00", FranceCulture),
            ("12:00", "14:00", FranceInter),
            ("14:00", "18:00", FranceCulture),
            ("18:00", "20:00", FranceInter),
            ("20:00", "21:00", FranceInfo),
            ("21:00", "22:00", RTL2),
            ("22:00", "00:00", PycolorePlaylistStation),
        ],
        (5,): [
            ("00:00", "06:00", FranceCulture),
            ("06:00", "09:00", FranceInter),
            ("09:00", "11:00", PycolorePlaylistStation),
            ("11:00", "14:00", FranceInter),
            ("14:00", "17:00", FranceCulture),
            ("17:00", "18:00", FranceInter),
            ("18:00", "20:00", FranceInter),
            ("20:00", "21:00", FranceInfo),
            ("21:00", "00:00", FranceCulture),
        ],
        (6,): [
            ("00:00", "06:00", FranceCulture),
            ("06:00", "09:00", FranceInter),
            ("09:00", "11:00", PycolorePlaylistStation),
            ("11:00", "14:00", FranceInter),
            ("14:00", "18:00", FranceMusique),
            # ("18:00", "19:00", RTL2),
            ("18:00", "21:00", FranceInter),
            ("21:00", "22:00", RTL2),
            ("22:00", "00:00", PycolorePlaylistStation),
        ]
    },
)

Dans cet exemple, tournesol fait appel à un Handler, une classe qui altère les métadonnées une fois qu'elles ont été récupérées par la station.

Station

Une station représente une station diffusée sur une plage horaire. Elle doit implémenter quatre méthodes pour alimenter la radio et l'API.

  • get_step() : cette méthode va chercher les informations sur le programme en cours de diffusion. Par exemple , pour une station telle que France Inter, elle va utiliser l'API de Radio France.
  • get_next_step() : idem, mais pour le programme suivant.
  • get_schedule() : renvoie une liste de programme pour une plage de temps donnée.
  • format_stream_metadata() : cette méthode formate des métadonnées pour les envoyer à l'encodeur qui va les inclure dans le flux audio. Elles sont lues par les lecteurs audio.

Client de lecture

Si l'on peut écouter la radio simplement à partir du flux généré par Liquidsoap, il existe aussiun projet d'interface web pour écouter les radios et accéder aux différents programmes depuis le navigateur : Sunflower Webapp.

Contribuer

Vous pouvez cloner le projet pour le tester ou proposer des modifications:

$ git clone https://github.com/Arkelis/sunflower-radio

Installation des dépendances

Les différents composants à installer sur sa machine pour démarrer le projet sont détaillés dans la page INSTALL.md.

Déploiement

Le fichier DEPLOY.md expose la démarche à suivre pour déployer Radio Pycolore sur un serveur Debian 10 Buster.

Feuille de route

Voir les milestones.

  • Mise à jour des champs en temps réel
  • Jingles horaires et de transition
  • Mettre une musique à la place de la pub pour RTL 2
  • Rendre la page du lecteur responsive
  • Thème sombre
  • Faire de la page du lecteur une PWA
  • Faire du projet une lib

sunflower-radio's People

Contributors

adrientiburce avatar arkelis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

adrientiburce

sunflower-radio's Issues

Repenser `get_schedule()`

Actuellement cette méthode appelle get_step() avec un paramètre booléen for_schedule. Cela pose problème car les appels à l'API de Radio France sont faits pour chaque émission ce qui ralentit l'ensemble. À optimiser

Fix API calls by React

  • "Musique" channel calls API when it should not.
  • "Tournesol" channel doest not call when it should.

Déléguer la gestion du planning

Actuellement les méthodes de crawling du planning sont directement dans la classe Channel. Créer une classe ChannelPlanning pour séparer la gestion du planning.

Tester plus

Pour cela il faut se renseigner sur le mocking et rendre ces fonctions plus paramétrables (utiliser le dictionnaire context donné par le watcher par exemple).

  • Core :
    • Timetable
    • Génération config liquidsoap
    • Persistence
  • Spécifique Pycolore :
    • Récupération infos des stations
    • Parsing config lisp (macros Hy)

Fix step détaillées

Réparer l'anomalie illustrée ci dessous

image

  • Il ne devrait pas y avoir d'émission parente
  • On devrait voir le titre de la diffusion à la place du titre de l'émission (en gras)

Cible

image

Rendre le scheduler asynchrone

Chaque station met à jour ses métadonnées en allant fetch des sites / API. Pour pas qu'une station empêche les autres de se mettre à jour, il faudrait rendre la méthode get_metadata() (et donc process() des chaînes et des stations dynamiques) asynchrone. Il est nécessaire de changer de dépendance pour faire des requêtes HTTP (par exemple s'orienter vers aiohttp).

Related issues

Utiliser un seul endpoint d'événements

Au lieu d'avoir un SSE par chaîne, avoir un seul endpoint sur lequel on choisit les chaîne auxquelles on s'abonne grâce à des paramètres d'url.

On passerait donc de :

GET https://api.radio.pycolore.fr/channels/tournesol/events/
GET https://api.radio.pycolore.fr/channels/musique/events/

À simplement :

GET https://api.radio.pycolore.fr/events/?channel=tournesol&channel=musique

Erreur en sortie de pub

Lorsque l'on sort de la pub, erreur fatale signalée par watcher.py :

KeyError: 'station'

Onglets

3 onglets à faire :

  • En direct
  • Programme du jour
  • En ce moment sur les autres chaînes
  • Podcasts favoris

Réguler le nombre d'appel à l'API radiofrance

Les appels à l'API résultent parfois en timeout error. Il faut réguler les tentatives pour éviter de dépasser le nombre d'appels. Il faut au plus 1000 appels en 24h soit un appel toutes les 86 secondes.

Solution : Lors d'un échec d'appel à l'API, planifier la prochaine tentative à t + 90s.

Créer un fichier d'entrée pour les commandes

Créer un module dans le style du manage.py de Django. Idées de commande :

  • (re)start : (re)démarre
    • ... radio : le service liquidsoap
    • ... watcher : le watcher (par défaut)
    • ... all : les deux
  • stop : idem que la commande ci-dessus mais pour arrêter
  • generate-liquisoap-config : génère la config liquidsoap

Mémoriser dernière chaîne visitée

Lorsque l'on se rend sur /, rediriger vers la dernière chaîne visitée (/<endpoint>), on peut mémoriser la dernière chaîne visitée dans un cookie. Il faut permettre à l'utilisateur d'annuler/rétablir cette fonctionnalité.

Continuer l'implémentation du PersistentAttribute

Continuer l'implémentation du descripteur

  • Intégrer le descripteur dans l'objet Channel.
  • Y intégrer le publish_to_redis() : ajouter un booléen notify_changes dans le constructeur.
  • Faire en sorte que Channel et Station n'héritent plus de RedisMixin.
  • Faire une méthode de classe get_view utilisable par le serveur au lieu d'avoir les objets View totalement séparés.

Utiliser React pour le front

  • Pour rendre la page de lecture plus "app-like" (éviter le rechargement lors de changement de chaîne)
  • En prévision d'ajout d'onglets

Implémenter les server sent events

Ils sont fonctionnels mais encore quelques points à finaliser.

  • N'envoyer un serveur push que lorsque les données changent.
  • Envoyer les nouvelles données aussi par SSE

Rendre get_schedule asynchrone

Comportement actuel

channel.get_schedule() regarde les créneaux occupés par les stations dans une chaine, puis appelle séquentiellement station.get_schedule() de la station en question avec le début et la fin du créneau en paramètres.

Cible

  • Ne plus appeler séquentiellement mais de manière concurrente : (tasks asyncio). Peut-être d'abord gérer le planning à part de Channel pour une API plus propre. Le watcher, ainsi que process de Channel doivent donc être asynchrones
  • Regrouper les appels : si une station est utilisée plusieurs fois au cours de la journée, faire un appel groupé ? (donner un itérable de slots au lieu de juste un début et une fin).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.