Jellyfin BetaSeries

actif · depuis 2026

Un plugin Jellyfin qui maintient un compte BetaSeries à jour tout seul : ce qu'on finit de regarder sur son serveur est marqué vu, ce qu'on décoche est retiré.

stack
  • ▸C# / .NET 10
  • ▸Plugin Jellyfin 10.11+ / 12+
  • ▸API BetaSeries, OAuth2
  • ▸Page de config HTML/JS dans le dashboard
  • ▸xUnit, Moq
  • ▸GitHub Actions (tests, CodeQL, releases)
links

Ce que ça fait

Un épisode arrive au bout, il est marqué vu sur BetaSeries, à l'heure réelle de la lecture. Une pause ou un film abandonné au tiers ne comptent pas : le plugin attend le seuil de fin déjà configuré dans Jellyfin.

Ça marche aussi dans l'autre sens, et à la main. Cocher un film ou un épisode dans Jellyfin l'envoie sur BetaSeries ; le décocher le supprime de l'historique là-bas. Une saison entière ou une série complète se propagent à tous leurs épisodes d'un coup.

Un serveur, ce sont souvent plusieurs personnes : on crée autant de profils BetaSeries qu'il en faut, on y rattache un ou plusieurs comptes Jellyfin, et chaque profil décide de son côté s'il synchronise les films, les séries, la lecture automatique, les marquages manuels. Deux utilisateurs peuvent aussi partager le même compte BetaSeries.

Un détail qui ne se voit pas mais qui compte : quand on marque un épisode, BetaSeries marque aussi tous les précédents comme vus. Le plugin envoie explicitement bulk=false, donc un épisode marqué reste un épisode marqué, et les dates de l'historique restent celles d'origine.

Comment c'est fait

Une DLL .NET 10 qui écoute les événements du serveur (PlaybackStopped pour la lecture, UserDataSaved pour les coches manuelles) et une page de configuration servie dans le dashboard Jellyfin, avec une fenêtre OAuth2 pour relier un compte sans copier-coller de jeton.

Le gros du travail est dans l'appariement. Jellyfin et BetaSeries ne se connaissent pas, il faut donc passer par les identifiants que les deux stockent, et prévoir le cas où ils manquent : un film se cherche par son TMDB, à défaut par son IMDb ; une série par son TVDB, à défaut par IMDb, à défaut par recherche de titre, validée par le TMDB pour ne pas ramener un homonyme ; un épisode par son TVDB ou par sa position saison/épisode. Un cache de trente secondes absorbe les événements qui arrivent en rafale, et une réponse "déjà vu" de l'API est traitée comme un succès, pas comme une erreur.

Les appels HTTP passent par un client isolé derrière une interface, donc la suite xUnit rejoue toute la résolution, le marquage et le démarquage sans jamais toucher à l'API réelle.

Pourquoi

Mon historique de séries est sur BetaSeries depuis des années : je regardais un épisode, puis j'allais le cocher ailleurs, à la main, ou plus souvent trois semaines plus tard, en essayant de me souvenir de ce que j'avais vu.

J'ai migré de Plex vers Jellyfin il n'y a pas longtemps. Jellyfin est open source et gère les plugins, donc rien n'empêchait de l'ajouter moi-même. Je ne fais pas de .NET, mais avec un LLM et les bonnes specs, en 2h mis bout à bout j'avais un plugin fonctionnel.

Au lieu d'écrire du C# au hasard, j'ai écrit les specs, en détail, comme si je les passais à quelqu'un d'autre : quel événement déclenche quoi, la forme exacte de la configuration, ce que l'API renvoie dans chaque cas bizarre, et les endroits où le plugin doit refuser plutôt que deviner. Un LLM a écrit le code, j'ai lu, corrigé, redemandé, avec un test par comportement décrit. Quand on ne connaît pas le langage, c'est à peu près la seule chose qui permet de vérifier que ça fait ce qui était demandé. Jellyfin Hue est sorti de la même méthode.

← retour aux projets