ProtoFlix

Journal des changements

Tout ce qui change dans ProtoFlix, le jour où ça change : ce qui est ajouté, corrigé, et ce qui a été essayé pour de vrai.

139 entrées

    1. Ajouté

      Lire sur la TV et la piloter depuis le téléphone

      • « Lire sur la TV » (ADR 0044) : depuis la fiche d'un film ou d'un épisode, ou depuis le lecteur du téléphone, on choisit une TV où ProtoFlix tourne et la lecture y démarre. Depuis la fiche, la TV reprend où son compte s'était arrêté ; depuis le lecteur, là où en était le téléphone, dont le lecteur se ferme. Essayé sur la TV de référence et le Pixel 9 Pro : Interstellar démarre sur la TV en quelques secondes, au bon endroit.
      • Le téléphone comme télécommande : ce que lit la TV, en direct (titre, position, lecture ou pause) ; lecture et pause, ±10/30 s, la barre de progression, épisode suivant et précédent, pistes audio et sous-titres, volume de la TV, et en secours les flèches, OK, Retour et Accueil (dans ProtoFlix). Une barre en bas de l'application suit la TV pilotée. Sur la TV, un bandeau discret dit qui la pilote.
      • Tout passe par le serveur, aussi hors de la maison : la TV s'annonce, les commandes lui arrivent par le flux d'événements, à elle seule (/api/v1/remote/…, migration 00044). Le compte connecté sur la TV la pilote sans rien demander ; un autre compte du serveur doit être accepté une fois sur la TV (« Accepter / Refuser »), et peut être retiré dans ses réglages.
      • La TV reste joignable ProtoFlix fermé : un service démarre avec elle. Pour qu'un envoi ouvre ProtoFlix depuis l'écran d'accueil d'Android, la TV doit l'autoriser à « afficher par-dessus les autres applications » (Réglages > Compte de ProtoFlix) ; sans cela, le téléphone dit d'ouvrir ProtoFlix d'abord. Depuis l'économiseur de ProtoFlix, l'envoi l'ouvre sans autorisation. Pas de Google Cast.
    2. Ajouté

      Économiseur d'écran de la TV, partie serveur

      • Module « Économiseur d'écran » (screensaver, ADR 0043), éteint de base. Il rend pour chaque compte la scène que la TV dessine (GET /api/v1/screensaver/scene?client=tv) : jusqu'à 60 images de fond des films et séries que la personne peut voir, limite d'âge comprise, mélangées et gardées dans le même ordre une heure ; les réglages de l'horloge et de la veille de nuit ; et des bulles. Module éteint : 404 module_disabled, la TV garde l'économiseur du système.
      • Bulles : « Ce soir sur ProtoFlix » (le prochain épisode à regarder et les derniers ajouts) ; la météo d'Open-Meteo, sans compte : la ville est située une fois, puis seules des coordonnées arrondies au dixième de degré partent, et la réponse est gardée 15 minutes ; Home Assistant : les entités choisies, avec une étiquette si on veut, mises en forme par le serveur (« 1,2 kW », « À la maison »), et une bulle de tâches par liste todo.*. Home Assistant n'est lu que pendant qu'une TV demande la scène, au plus toutes les 30 s ; son jeton est un secret qui ne quitte pas le serveur. Le module peut joindre l'adresse de Home Assistant même locale, et elle seule. Un connecteur en panne retire sa bulle, sans casser la scène.
      • Photos privées en fond, en option : celles de la personne connectée à la TV, seules ou en alternance avec les films. Désactivées de base.
    3. Ajouté

      Économiseur d'écran de la TV, partie TV

      • Économiseur d'écran sur la TV (ADR 0043). Les images de fond des films et des séries défilent, très assombries, désaturées et vignettées, avec un fondu lent. Au premier plan : une horloge à aiguilles, l'heure en grand et la date, et des bulles d'information. Pour ne pas marquer l'écran, l'ensemble se décale chaque minute et l'horloge change de côté chaque heure. La nuit, il est plus sombre encore.
      • Lancement : dans l'application après quelques minutes sans touche, jamais pendant un film ou une chaîne ; et comme économiseur du système Android TV, à choisir dans les réglages de la TV. Un aperçu est dans Réglages > Affichage.
      • Musique : elle laisse maintenant l'écran se mettre en veille. L'économiseur montre ce qui joue.
      • La scène vient du module screensaver du serveur (GET /api/v1/screensaver/scene, contrat dans api/screensaver/). Sans ce module, l'aperçu et l'économiseur du système prennent les fonds de la bibliothèque, et l'application ne se met pas en veille d'elle-même.
    4. Amélioré

      TV : moins de conversions, son à l'heure

      • Sous-titres image dessinés par la TV. Un sous-titre PGS, DVB ou DVD choisi dans un film envoyé tel quel reste dans le fichier : la TV le décode et le dessine à sa place sur l'image, au lieu que le serveur convertisse tout le film pour l'incruster. Forrest Gump en 4K HDR se lit maintenant sans conversion avec ses sous-titres du Blu-ray. Seule une application qui le déclare (capabilities.subtitles) en profite ; une plus ancienne garde l'incrustation.
      • Décodeurs DTS et TrueHD de la TV réparés. La version publiée de l'application ne chargeait pas les décodeurs de FFmpeg (une fonction appelée par le code natif était retirée à la construction) : chaque film en DTS était converti par le serveur. Interstellar se lit maintenant tel quel.
      • Son et image à l'heure. Le lecteur de la TV passe en mode tunnel quand la TV le permet : c'est elle qui cale l'image sur le son qu'elle joue vraiment. Mesuré en filmant la TV (flash et bip), le son s'est rapproché de son image de 53 à 64 ms. Un réglage « Synchro du son » dans le panneau des pistes, par pas de 25 ms et gardé par la TV, compense en plus une barre de son lente.
    5. Modifié

      Le domaine du projet : protoflix.club

      • Le dépôt officiel des modules est maintenant https://modules.protoflix.club. Les fichiers signés n'ont pas changé ; l'ancienne adresse modules.klarvi.fr sert encore le même dépôt le temps que les serveurs installés prennent cette version.
      • Le relais de notifications est en ligne à https://push.protoflix.club. Un serveur l'utilise avec PROTOFLIX_PUSH_RELAY=https://push.protoflix.club : ses téléphones reçoivent alors les notifications tout de suite, par Firebase.
      • Le service de soumission des modules prendra l'adresse soumettre.modules.protoflix.club.
    1. Corrigé

      Icônes de l'app TV

      • Quatre icônes de l'app TV étaient mal tracées : Effacer, Cercle coché et Image perdaient une partie de leur dessin, hors du cadre, et Zap était écrite dans une notation que tous les lecteurs ne lisent pas. « trash-2 » montre maintenant une corbeille, comme sur le site, et non plus la touche Effacer.
    2. Amélioré

      Conversion plus rapide, tons HDR sur l'iGPU Intel

      • Tons HDR sur l'iGPU Intel. Avec un iGPU Intel, les tons HDR10 se calculent maintenant sur la carte, quand le film décrit son écran de mastering. Sur un UHD 750, 30 s de 4K HDR se convertissent en environ 4,5 s au lieu de 14 à 17 s, avec presque pas de processeur. Le démarrage passe à 0,5 s et les sauts à moins d'une seconde, deux fois mieux que Jellyfin sur la même machine. La luminosité est corrigée pour égaler celle de la table du processeur.
      • Sur le processeur. x264 a des réglages plus légers (17 % plus rapide, différence de qualité négligeable), l'image est réduite par zscale au lieu de scale, et la table de tons travaille en virgule flottante. Une conversion 4K vers 1080p est environ 25 % plus rapide qu'avant.
      • Les mesures face à Jellyfin et Emby sont dans docs/testing/benchmarks/ovh-protoflix-jellyfin-emby.md. En HDR sans carte graphique, ProtoFlix reste plus lent que Jellyfin.
    3. Ajouté

      Migration depuis Emby

      • La migration accepte maintenant Emby comme source, en plus de Jellyfin. Elle a été essayée contre un vrai Emby 4.10.2 : films retrouvés par leur chemin, et pour chaque compte, films vus, positions et favoris importés. Un second import ne change rien. L'interface web ne propose encore que Jellyfin ; l'API prend "source": "emby".
      • La même série d'essais a validé la migration depuis Jellyfin 12.4 : chaque compte qui a son équivalent dans ProtoFlix récupère ce qu'il a vu, ses positions et ses favoris. Un compte sans équivalent est laissé de côté.
    4. Modifié

      FFmpeg 5.1 suffit : Debian 12

      • ProtoFlix fonctionne maintenant avec FFmpeg 5.1, celui de Debian 12, au lieu de 6.1 minimum. Le paquet accepte ce FFmpeg, et la chaîne VAAPI y marche avec le FFmpeg et le pilote Intel de la distribution.
      • Avant FFmpeg 6.0, le moteur ne sait pas lire le fichier que le serveur lui ouvre : il le rouvre par /dev/fd/3, et seuls les formats de fichiers multimédias lui sont permis. Une liste de lecture piégée ne peut donc pas lui faire lire d'autres fichiers. Sous Landlock, le lanceur ne lui permet de relire que ce fichier-là.
      • Avant FFmpeg 6.1, une conversion ne prend pas d'avance au démarrage : elle travaille aussi vite qu'elle peut, et elle est mise en pause quand elle a trop d'avance sur le lecteur.
      • Toute la suite de tests du moteur passe sous FFmpeg 5.1 et 7.1. Le paquet n'a pas encore été installé sur un Debian 12 vierge, et Ubuntu 22.04 (FFmpeg 4.4) reste refusé.
    5. Corrigé

      Couleurs saturées en HDR sous FFmpeg 7.1

      • Sous FFmpeg 7.1, celui de Debian 13, la conversion HDR sans table de tons (HLG, pic du film inconnu, aperçus) rendait certaines couleurs très saturées n'importe comment : un bleu vif sortait presque noir. Ces couleurs sont maintenant ramenées au bord de la gamme avant la dernière étape, comme le faisaient déjà les versions plus récentes. La chaîne ralentit d'environ 15 %.
    6. Ajouté

      Accélération VAAPI : graphismes Intel et AMD

      • Le serveur se sert maintenant de la partie graphique intégrée aux processeurs Intel et AMD, la plus courante sur un serveur domestique, par VAAPI. Elle décode le H.264 et le HEVC (10 bits compris), réduit l'image et l'encode en H.264, presque sans processeur. Les tons HDR restent sur le processeur, comme avec Nvidia, mais la réduction se fait sur la carte avant.
      • Au démarrage, chaque carte trouvée dans /dev/dri est essayée sur quelques images. Si un essai échoue, la conversion reste sur le processeur. Il faut le pilote VAAPI de la carte : intel-media-va-driver-non-free pour Intel, mesa-va-drivers pour AMD. L'utilisateur du service doit être dans le groupe render, ce que fait déjà le paquet.
      • Mesuré sur un Intel UHD 750 : six conversions 4K vers 1080p tiennent ensemble le temps réel. La limite est fixée à quatre (docs/testing/benchmarks/vaapi-intel-uhd750.md). Les Radeon n'ont pas encore été essayées sur du vrai matériel.
    7. Ajouté

      Docteur de lecture et Accueil des proches

      • Deux nouveaux modules intégrés, éteints par défaut, dans Modules > Système (ADR 0040).
      • Docteur de lecture : pendant une lecture, Infos puis « Pourquoi ça saccade ? » dit si la lecture est fluide, combien de fois et combien de temps elle a attendu, et d’où vient le problème : réseau trop lent, serveur qui ne convertit pas assez vite, appareil qui peine, accélération matérielle qui a lâché. Chaque constat a son remède, et les raisons du plan de lecture s’y ajoutent. Les lectures en cours et l’historique de l’administration ont aussi leur diagnostic. Allumé, le module garde un résumé des mesures de chaque lecture (débit reçu, réserve, vitesse de conversion, attentes pendant que la conversion était en retard), au plus une écriture par minute.
      • Accueil des proches : une invitation se partage avec un QR code et un message prêt à envoyer, sur l’adresse publique du serveur et avec un mot d’accueil, tous deux réglés dans le module. L’invité voit ce mot, puis arrive sur /bienvenue : il y mesure sa connexion (« la Full HD passe sans souci… ») et suit un guide pour sa TV Android, son téléphone, son ordinateur ou un autre appareil. Le débit mesuré apparaît sous son nom dans la page des comptes.
      • Serveur : GET /api/v1/playback/sessions/{id}/diagnosis, GET /api/v1/welcome, POST /api/v1/me/welcome/speed, GET /api/v1/admin/welcome/checks ; la consultation d’une invitation ajoute welcome. Migration 00043 (playback_health, welcome_checks).
      • La TV et le téléphone n’ont encore ni l’un ni l’autre.
    8. Ajouté

      Application mobile : musique

      • Un onglet « Musique » dans l’application du téléphone, quand le serveur en a : écoutés récemment, listes du compte, albums, artistes. La musique continue écran éteint, avec ses commandes dans la notification, sur l’écran verrouillé et aux boutons du casque ; une barre au-dessus des onglets dit ce qui joue. La recherche trouve aussi les artistes, albums et titres. Construit et vérifié côté serveur, pas encore essayé sur un téléphone.
    1. Ajouté

      Application mobile : mise à jour depuis le serveur

      • L’application du téléphone se met à jour depuis son serveur, comme celle de la TV : le paquet du serveur la porte, un point sur le bouton du compte signale une nouvelle version, « Mettre à jour » la télécharge et Android demande confirmation. Version 0.2.0 de l’application.
      • Serveur : GET /api/v1/clients/android-mobile et /apk ; deploy/package/build.sh ajoute l’APK du téléphone avec PROTOFLIX_MOBILE_APK_DIR.
      • La version optimisée de l’application se construisait de nouveau mal depuis l’ajout du scanner de codes QR (fragment 1.0 refusé par lint) : corrigé.
    2. Ajouté

      Application mobile : écrans des modules

      • Les modules s’affichent dans l’application du téléphone comme sur la TV et le site : un onglet de la barre du bas, une rangée de l’accueil, une section et un bouton sur la fiche d’un titre. Un module qui ne parle pas des téléphones y montre ce qu’il montre au site ; dans la fiche du module, « Dans les applications » a maintenant une ligne « Téléphones ». Essayé sur le Pixel 9 Pro avec le module de démonstration : compteur, note écrite par formulaire, confirmation avant d’effacer, images du module.
      • Serveur : le client mobile des surfaces (ADR 0030).
      • Le lecteur du téléphone a un bouton par module qui parle du moment joué, comme le panneau de la TV. Vérifié par l’API, pas encore sur un téléphone.
    3. Corrigé

      Pages d’un module après une action

      • Après une action, une autre page du même module pouvait s’afficher telle qu’avant pendant son délai de relecture : une note gardée depuis la page « Nouvelle note » n’apparaissait pas tout de suite sur la page principale qui s’ouvrait ensuite. Une action vide maintenant le cache de toutes les pages de son module, sur le site, la TV et le téléphone.
    4. Ajouté

      Application mobile : connexion par code QR

      • Connecter un téléphone sans taper d’adresse ni de mot de passe : sur le web, compte, « Appareils connectés », « Connecter un téléphone » affiche un code QR ; dans l’application, « Scanner un code QR » le lit, et le téléphone se retrouve connecté à ce serveur avec ce compte. Le code vaut 2 minutes et une seule fois ; le web le renouvelle et dit quel téléphone s’est connecté. Un code expiré ou déjà utilisé est refusé avec un message qui dit d’en afficher un nouveau.
      • Serveur : POST /api/v1/me/sign-in-links, GET /api/v1/me/sign-in-links/{id}, POST /api/v1/auth/sign-in-links/redeem ; codes d’erreur sign_in_link_expired et sign_in_link_used.
      • Android : le scanner de Google Play services (play-services-code-scanner), sans permission caméra.
    5. Ajouté

      Application mobile : hors ligne

      • Garder un film ou un épisode sur le téléphone pour le regarder sans réseau : « Télécharger » sur sa page, au choix de la qualité d’origine (le fichier tel quel si le téléphone le lit) ou d’une conversion 1080p, 720p ou 480p, avec la taille prévue. Le téléchargement passe par le gestionnaire d’Android et reprend après une coupure. Les copies sont dans une rangée « Sur l’appareil » de l’accueil ; sans réseau, l’accueil ne montre qu’elles.
      • Ce qui est regardé sans réseau rejoint le serveur au retour du réseau : position, épisode vu, historique.
      • Serveur : /api/v1/me/offline (demander, suivre, télécharger avec Range, retirer une copie ; envoyer la progression) et la tâche offline.convert. Nouveau droit « Garder des titres sur son téléphone » dans les comptes (web), désactivé par défaut sauf pour les administrateurs. Migration 42.
      • La barre d’onglets de l’application défile quand les onglets ne tiennent plus.
    6. Ajouté

      Modules décrits : les écrans, ADR 0037

      • Format 2 du graphe : une mise en page par écran, faite de widgets (les blocs de l’ADR 0030) dont les propriétés sont écrites ou liées aux valeurs que donne la logique, et qui se répètent sur une liste. Carte « Donner les valeurs de l’écran ». Les graphes au format 1 ne changent pas.
      • Vérifications et moteur : la mise en page est vérifiée comme le graphe, et remplie par le même code que les cartes de blocs. La fiche du relecteur décrit chaque écran.
      • Éditeur : onglets Écrans et Logique, comme l’éditeur de widgets d’Unreal. Concepteur avec palette, hiérarchie, écran rendu pour le site ou la TV, détails ; liaisons, répétition, actions ; un clic mène à la logique d’un écran ou crée le point de départ d’une action.
    7. Changé

      L’éditeur de modules, ergonomie

      • En-tête : une action principale (« Essayer », puis « Installer »), « Publier » pour la soumission et l’export, une pastille d’état qui mène à la carte fautive.
      • Canevas : grille, zoom, plan du graphe, une forme de carte par rôle, une couleur par famille, des broches typées aux noms français, un rangement qui fait courir les liens de gauche à droite.
      • Câbles tirés à la souris ; lâchés dans le vide, ils ouvrent la recherche des cartes qui les acceptent, et la carte choisie arrive reliée. Recherche au clic droit, au double-clic ou avec « / », avec la fiche de la carte à côté.
      • Menus au clic droit sur une carte ou une broche ; Ctrl+D, Ctrl+C, Ctrl+V, F, Maj+F, et la liste des raccourcis (?).
      • Info-bulles sur les broches ; la fiche complète d’une carte quand on reste dessus : ce qu’elle fait, quand, comment, ses broches, un exemple, le piège. Les 99 cartes, en français et en anglais.
      • Panneau de droite réglable en largeur ; l’inspecteur aux couleurs de la carte ; le module en un coup d’œil quand aucune carte n’est choisie ; les commentaires sur les cartes.
      • Page des brouillons : chaque brouillon avec le dessin de son graphe, et « Partir d’un exemple » (GET /admin/blueprints/examples, POST /admin/blueprints/drafts/{id}/start), rangé à l’ouverture.
    8. Ajouté

      Modules décrits : soumission, ADR 0038 lot 7 et ADR 0039

      • Vérification automatique d'un module décrit pour le catalogue communautaire, la même partout : refus, points à regarder, informations ; rien n'est contacté sauf le DNS sur demande ; chaque écran est essayé hors ligne et sa page passe la vérification du serveur.
      • Fiche du relecteur en Markdown : ce que le module contacte et pourquoi, ce qu'il montre et garde, sa logique carte par carte, l'essai de ses écrans.
      • Éditeur : « Vérifier pour soumettre », avec l'export du module et de sa fiche. pfrepo review pour le relecteur.
      • Service de soumission pfsubmit (ADR 0039), pas déployé. Les auteurs s'inscrivent par un lien envoyé par courriel, envoient leur module, suivent la relecture et échangent avec le relecteur ; un module refusé par la vérification automatique ne va pas plus loin.
      • pfrepo community pour le relecteur : la file, la fiche, le téléchargement vérifié, les décisions et les messages.
      • Brouillons des conditions des auteurs et de la politique de confidentialité, dans docs/legal/, à faire relire avant l'ouverture.
    9. Ajouté

      Modules décrits : écrans et réglages, ADR 0038 lot 6

      • Concepteur de réglages : aide, valeur par défaut, bornes, choix, ordre ; avec « Ce que verra l'administrateur », dessiné par les composants de la fiche d'un module.
      • Images d'un brouillon (PNG, JPEG ou WebP vérifiés sur leurs octets, 512 Kio, 32 au plus), proposées à la carte « Image du module » et mises dans le paquet. Routes /admin/blueprints/drafts/{id}/assets.
      • Aperçu des écrans, web et TV, dans les deux langues : la réponse d'un essai passe par la vérification du serveur (surfaces.Preview) puis par les blocs du site ; les actions s'y essaient.
      • La TV n'a pas de rendu dans le site : son aperçu en donne seulement les proportions et la taille du texte.
    10. Ajouté

      Modules décrits : l'éditeur, ADR 0038 lot 5

      • Modules → Créer un module : un éditeur de modules sans code dans l'administration, en SVG et React, sans dépendance. Brouillons gardés par le serveur ; canevas de cartes reliées, palette avec recherche, liens typés, fonctions et variables, annulation, rangement, clavier et lecteurs d'écran.
      • Vérification en direct : les broches de chaque carte, la raison d'un refus et la carte en cause, et ce que le module demandera ; les capacités du manifeste suivent le graphe.
      • Essai pas à pas d'un événement : chaque carte avec ses valeurs sur le canevas, le journal, les requêtes, la réponse ; les secrets ne sont jamais montrés.
      • Installation sur ce serveur comme un fichier non signé, avec l'avertissement d'un module non officiel ; export .pfmod.
      • Routes /api/v1/admin/blueprints : catalogue des cartes, vérification, essai, brouillons, paquet, préparation de l'installation.
    11. Ajouté

      Modules décrits : réseau, ADR 0038 lot 4

      • Cartes Requête HTTP, Lire du XML et Lire un flux RSS ou Atom. L'hôte d'une requête est écrit dans son adresse (https, un nom public, port 443) ou lu dans le réglage que l'administrateur saisit ; les valeurs des trous sont échappées. Un secret ne va que dans un en-tête ou le corps.
      • Module d'exemple x.rss_accueil : un flux RSS dans une rangée de l'accueil et sur une page, fait sans code.
    12. Ajouté

      Modules décrits : installation, ADR 0038 lot 3

      • Un manifeste peut porter "engine": { "id": "engine.blueprint", "format": 1 } au lieu d'un programme. Le serveur lit alors graph.json, recalcule les capacités du graphe et refuse un manifeste qui en déclare d'autres, au chargement, à l'installation et dans pfrepo.
      • Le moteur engine.blueprint s'installe depuis le dépôt officiel comme un module ("kind": "engine"), sans processus propre ; un module décrit le trouve à chaque démarrage, et ses fichiers sont vérifiés avant le lancement.
      • Les archives de modules peuvent porter graph.json et les images assets/ ; seul bin/ est exécutable.
      • deploy/package/dev-modules.sh pose aussi un module décrit et le moteur dans le dossier de développement.
    13. Ajouté

      Modules décrits : moteur, ADR 0038 lot 2

      • Moteur officiel des modules décrits, engine.blueprint (server/modules/blueprint) : il se présente comme moteur, reçoit du serveur le graphe du module, le vérifie de nouveau et sert module.configure, module.check, surface.render et surface.action, avec ses minuteries.
      • Interpréteur à budget (internal/blueprint/engine) : 10 000 cartes par événement, 1,8 s pour une surface, 32 Mio de valeurs, 20 requêtes, 8 appels imbriqués. Un dépassement arrête le fil sans rien écrire et n'est pas rattrapé par « Essayer ». Les valeurs gardées, par personne ou pour le module, sont écrites à la fin d'une exécution réussie, avec un quota.
      • Le protocole des modules gagne engine dans module.hello et described dans sa réponse.
      • Le graphe exemple-surfaces refait exemple.surfaces, réponse pour réponse.
    14. Ajouté

      Modules décrits : format, ADR 0038 lot 1

      • ADR 0038 : une quatrième famille de modules, faits sans code. Un graphe de cartes (graph.json, format 1) exécuté par un moteur officiel confiné ; capacités déduites du graphe ; budgets ; canaux de distribution et principe de la soumission.
      • api/blueprints/ : schéma du graphe, catalogue des 99 cartes de la version 1 (cards.json), exemples, et 25 graphes hostiles refusés avec leur raison (boucles, récursion, secret dans une adresse ou au journal, hôte caché, adresse IP…).
      • internal/blueprint : lecture, vérification et analyse d'un graphe, partagées par le serveur et le moteur.
    15. Ajouté

      Notifications, lot 2 : le relais

      • relay/ : le relais de notifications du projet (ADR 0034), un programme Go sans dépendance. Un téléphone y échange son jeton FCM contre une poignée ; un serveur y envoie des notifications chiffrées pour le téléphone et signées par sa clé d'installation ; le relais les passe à FCM sans pouvoir les lire. La première installation qui écrit à une poignée est la seule qui pourra lui écrire. Unité deploy/systemd/protoflix-relay.service, exploitation dans docs/operations/push-relay.md.
      • Serveur : PUT et DELETE /api/v1/me/devices/current/push (poignée et clé du téléphone, la clé scellée) ; avec PROTOFLIX_PUSH_RELAY, chaque notification part aussitôt aux téléphones concernés, une par sorte et par téléphone toutes les 10 minutes au plus.
      • Essayé de bout en bout sur ce PC : serveur, relais et faux FCM ; le téléphone ouvre ce que le relais n'a pu lire.
    16. Ajouté

      Notifications, lot 1

      • Serveur : il garde 30 jours ce qu'un compte doit savoir sans regarder (ADR 0034) : alerte du gardien, tâche abandonnée, nouvelle version pour les administrateurs ; fin ou échec de ses téléchargements pour chacun. GET /api/v1/me/notifications. Une sorte et ses paramètres, jamais une phrase ; le même événement n'est jamais dit deux fois. Migration 41 (39 et 40 sont à la branche des téléchargements).
      • Application Android : elle demande au serveur ce qui est nouveau toutes les 15 minutes au mieux, sans Google, et l'affiche en notifications système ; un toucher ouvre la page concernée.
    17. Ajouté

      Application mobile : administration

      • Onglet « Serveur » pour les administrateurs : alertes du gardien et disques, lectures en cours avec leur plan, mises à jour, bibliothèques à analyser, tâches à relancer ou annuler, comptes et invitations (envoyées par la feuille de partage), appareils à déconnecter. Les gestes qui ne se rattrapent pas demandent confirmation.
      • Téléchargements depuis le téléphone : la file du serveur, l'ajout d'un lien ou d'un magnet, pause, reprise, retrait ; « Partager » un lien vers ProtoFlix depuis une autre application.
      • Serveur : DELETE /api/v1/admin/sessions/{id} arrête la lecture de quelqu'un. Son lecteur reçoit session_stopped et s'arrête au lieu d'ouvrir une nouvelle session ; la TV et le mobile le respectent.
    18. Corrigé

      Son en avance après un saut

      • Dans Chrome, après un saut ou une reprise en cours d'épisode, le son pouvait partir jusqu'à 10 s en avance sur l'image quand la vidéo était copiée et le son converti (AC-3 en AAC, par exemple). La vidéo copiée repart de l'image clé précédente, le son du point demandé, et FFmpeg mettait cet écart dans une liste d'édition que Chrome ignore. Les morceaux portent maintenant l'écart dans leurs propres horodatages (use_editlist=0). Trouvé par la session web sur une vraie lecture de Lost. Ce premier correctif ne suffisait pas : sans liste d'édition, FFmpeg étirait le premier échantillon de son sur tout l'écart, et Chrome, qui compte les échantillons, jouait encore le son en avance. Le son converti repart désormais de la même image clé que la vidéo (-noaccurate_seek), il n'y a donc plus d'écart du tout. Trouvé par la session TV sur Interstellar (6,5 s d'avance). Restait un petit écart, jusqu'à quelques centièmes de seconde selon l'entrelacement du fichier (60 ms d'avance mesurés sur Interstellar) : le son est maintenant coupé ou complété de silence à l'échantillon près pour partir exactement avec l'image (-copyts, aresample), et le décalage annoncé au client est l'instant de décodage de l'image clé.
    19. Ajouté

      Disques lents : reconnaissance et lecture anticipée

      • Le serveur reconnaît le disque de chaque source : SSD, disque mécanique, USB ou partage réseau. L'API le donne dans disk (ADR 0029).
      • Sur un disque lent, ouvrir la fiche d'un film ou d'une série réveille le disque en arrière-plan, pendant qu'on lit le résumé.
      • Lecture anticipée sur les disques lents : un seul fil par disque lit par blocs de 16 Mio devant chaque lecture directe et chaque conversion, en priorité disque basse. Le disque fait de longues lectures au lieu de sauter d'un fichier à l'autre. 256 Mio de mémoire au plus en tout, réglable par PROTOFLIX_READAHEAD_MIB (0 l'arrête).
      • Pas encore mesuré sur un vrai disque mécanique ou USB : c'est l'étape suivante, avant le tampon sur le SSD.
    20. Ajouté

      Application mobile : lecture

      • Lecture sur Android : reprise où l'on s'était arrêté ou depuis le début, épisodes, paysage plein écran, commandes au toucher (±10 s, double toucher, barre de lecture), son et sous-titres, « À propos de cette lecture » avec le mode et les raisons du serveur, épisode suivant, image dans l'image en quittant l'application.
      • Serveur : profil android-mobile@1, les règles du lecteur Media3 de la TV sous un nom à lui.
      • apps/core : la logique de lecture commune (Playback) sur une interface de lecteur (MediaPlayer), avec Media3Player et la détection des décodeurs (DeviceCaps, venue de la TV) pour Android. La TV garde pour l'instant son propre contrôleur.
      • Essayé sur un Pixel 9 Pro : HEVC 10 bits en Matroska lu tel quel, MPEG-2 converti avec ses raisons ; APK optimisé de 2,3 Mo, démarrage à froid en 243 ms.
    21. Ajouté

      Application mobile, Android

      • apps/mobile (écrans en Compose Multiplatform, pour Android puis iOS) et apps/mobile-android (l'application Android) : choix du serveur, avec les serveurs du réseau trouvés par mDNS ; connexion par mot de passe ou par un code saisi sur la page /appareil du site ; accueil (titre mis en avant, Reprendre, films et séries récents, Ma liste) ; Films et Séries en grilles qui se chargent au défilement ; fiche avec saisons, épisodes et distribution ; recherche au fil de la frappe. Les jetons, la police et les icônes sont ceux du web ; le français fait foi. La lecture n'est pas encore là (étape 4 de docs/mobile/plan.md).
      • Essayée sur un Pixel 9 Pro contre un serveur local jetable : APK optimisé de 1,6 Mo, démarrage à froid en 363 ms.
      • La recherche des serveurs sur le réseau passe de la TV à core, pour les deux applications.
    22. Modifié

      Code partagé des applications

      • apps/core : module Kotlin Multiplatform (Android, iOS, et Windows natif pour les tests) qui porte les formes de l'API, son client, les surfaces de modules, le choix des pistes et WebVTT. La TV s'en sert ; l'application mobile s'en servira. Le client d'API ne dépend plus d'OkHttp : chaque plateforme lui donne son transport, et il dit au serveur quel client il est (tv, plus tard mobile).
      • TV : rien ne change à l'écran. Mêmes 53 tests (22 passés dans core), plus 6 sur le client d'API ; le profil de référence couvre aussi core.
    23. Modifié

      Applications natives

      • android-tv/ devient apps/, un projet Gradle qui accueillera aussi le code commun et l'application mobile (ADR 0033, ADR 0034 pour les notifications). L'application TV y est le module :tv : même APK à l'octet près en taille, mêmes 53 tests. Le paquet prend désormais tv-release.apk (PROTOFLIX_TV_APK_DIR=apps/tv/build/outputs/apk/release).
    24. Corrigé

      Surfaces

      • Le direct demande de relire la page quand une ligne part après une action (oublier un téléchargement) : la page gardée était effacée avec le cache, et rien ne permettait plus de voir le changement.
      • Le contrat dit que la route des actions demande client (et accepte blocks), comme le serveur l'exige.
    25. Ajouté

      Surfaces, blocs version 2 servis

      • Le serveur sert la version 2 des blocs : en-tête, grande carte, onglets, recherche, champ d'une ligne, courbe, et dans les lignes leurs actions, leurs détails et une affiche. Il retire ce qu'un client ne doit pas voir (un bloc réservé au site, ce qu'une app de version 1 ne sait pas dessiner) et vérifie les nouvelles règles : une action destructive pose sa question, l'id d'un élément en direct est unique.
      • Le direct : GET /surfaces/{module}/{surface}/live rend l'état des éléments en direct, relu au plus toutes les 2 s pour tous les écrans, et demande de relire la page quand une ligne arrive ou part.
      • Un fichier (un .torrent) peut accompagner une action : 2 Mio au plus, corps de 3 Mio ; 30 actions par minute et par compte.
      • Une œuvre nommée par un module s'affiche avec son affiche ou son image de fond, si le compte peut la voir.
      • Les surfaces parlent la langue du compte, sinon celle du serveur : la page Téléchargements n'est plus en anglais sur le site.
      • La page Téléchargements des surfaces passe en version 2, avec pause, reprise, annulation, relance et « tout mettre en pause » ; elle est désactivée par défaut partout, le site gardant sa propre page.
    26. Modifié
      • Les images des modules sont servies sous /api/v1/surface-assets/{module}/{fichier} : l'ancienne adresse se confondait avec le direct d'une surface nommée assets.
    27. Ajouté

      Gardien de la bibliothèque, ADR 0032

      • Le gardien de la bibliothèque, intégré au serveur. Il calcule le SHA-256 de chaque fichier en tâche de fond (guardian.checksum, chaque heure), à 25 Mio/s au plus (PROTOFLIX_GUARDIAN_RATE_MIB, 0 l'arrête), en priorité d'entrées-sorties idle et nice 19 sous Linux, sans chasser du cache ce que l'on regarde. Il se met en pause pendant une lecture, une conversion ou une chaîne TV. Chaque fichier est relu tous les 90 jours (PROTOFLIX_GUARDIAN_VERIFY_DAYS).
      • Un fichier dont la taille ou la date change est « remplacé » : nouvelle référence, sans alerte. Même taille, même date et un autre contenu, relu deux fois : « corrompu », alerte grave et ligne WARN au journal. Si Linux montre une écriture (ctime), le fichier est « réécrit », un simple avertissement. Un fichier illisible, ou deux lectures qui diffèrent, déclenchent aussi une alerte.
      • La santé des disques, toutes les 10 minutes (guardian.disks), sans droits root. Il relie chaque source et les données du serveur à leur disque par /proc/self/mountinfo, /sys/block et /dev/disk/by-id (partitions, LVM, RAID logiciel). Il surveille la place libre, l'absence, la lecture seule, les erreurs d'entrée-sortie et SMART. Les rapports SMART sont déposés par un minuteur root optionnel (deploy/smart/, PROTOFLIX_SMART_DIR) : le serveur ne lance jamais smartctl.
      • Ce qu'on perdrait si un disque mourait : œuvres perdues, œuvres qui perdraient une version, œuvres qui ont une copie ailleurs (même version ou même SHA-256), fichiers hors catalogue. Un volume RAID 1, 5, 6 ou 10 ne fait rien perdre. Le lien entre source et disque reste en base : un disque absent dit encore ce qu'il portait.
      • Routes GET /admin/guardian, GET /admin/guardian/disks/{id}/loss, GET /admin/guardian/files, POST /admin/guardian/verify, POST /admin/guardian/files/{id}/accept, POST /admin/guardian/alerts/{id}/acknowledge, et GET /admin/guardian/sources/{id}/sha256sums au format de sha256sum -c. Événement guardian.updated (administrateurs). Migration 00038_guardian.sql.
      • Web : page Gestion › Serveur › Gardien de la bibliothèque (/admin/serveur/gardien), ouverte depuis la page Serveur et la recherche de la console. Elle donne l'état en une phrase, les alertes avec ce qu'il faut faire, les sommes de contrôle et les disques. Pas de route ni d'entrée à elle dans le rail : le premier chargement est à 24 octets de son budget.
    28. Ajouté

      Migration depuis Jellyfin, ADR 0031

      • ADR 0031 : comment ProtoFlix reprend un foyer venu de Jellyfin, Emby ou Plex. Il dit ce qu'on reprend et ce qu'on ne reprend pas, comment on lit chaque source (API ou base hors ligne, formats vérifiés), comment on fait correspondre fichiers et œuvres, comment l'administrateur conduit l'opération, et pourquoi l'outil est intégré au serveur.
      • Page /admin/migration « Venir de Jellyfin », ouverte depuis la page Bibliothèques : un aperçu à blanc, puis l'import.
        • Ce qu'on reprend : pour chaque utilisateur de Jellyfin rattaché à un compte ProtoFlix, ce qu'il a vu (avec la date, dans l'historique), où il en est et ses favoris, qui vont dans « Ma liste ».
        • Ce qu'on ne touche pas : Jellyfin ne reçoit que des requêtes de lecture. Un état plus récent dans ProtoFlix est gardé. Relancer l'import n'écrit rien deux fois.
        • Correspondance : par le chemin du fichier, après réécriture des dossiers (proposée d'elle-même quand le nom du dossier est le même), puis par les identifiants TMDB, IMDb ou TVDB, puis par un nom de fichier unique. La page liste ce qui n'a pas trouvé de correspondance.
      • API POST /api/v1/admin/migration/preview et POST /api/v1/admin/migration/import (administrateurs seulement). La clé d'API de Jellyfin vient avec chaque requête : elle n'est jamais conservée. Nouveaux codes d'erreur : source_unauthorized, source_forbidden, source_unreachable, source_unexpected, source_not_supported, migration_running. L'import est inscrit au journal d'audit.
      • Pas encore : Emby (lecteur écrit, à essayer sur un vrai serveur), Plex, la création des comptes et des bibliothèques, les listes de lecture, les collections et les métadonnées verrouillées. Essayé seulement contre un faux Jellyfin, pas encore contre celui du Pixel.
    29. Ajouté

      Blocs des surfaces, version 2, ADR 0030

      • Le contrat de la version 2 des blocs, pour des surfaces aussi riches qu'une page faite main : en-tête, grande carte, onglets, recherche, champ d'une ligne (avec envoi de fichier sur le site), courbe ; dans les lignes et les cartes, leurs actions, leurs détails, une affiche ; des blocs réservés à un client ; le direct par GET /surfaces/{module}/{surface}/live. Exemples partagés : downloads-v2.json, search.json, live.json. Pas encore servi.
      • App TV : la version 2 des blocs, annoncée par blocks=2.
        • En-tête, grande carte, onglets, courbe.
        • Recherche : le clavier de la télécommande, les résultats à côté.
        • Lignes et cartes : détails, affiche, texte de progression, panneau d'actions.
        • Direct : relecture par /live, changements en place.
        • Les blocs réservés au site sont écartés.
        • Les tests lisent les trois nouveaux exemples. Pas encore essayé sur la TV, faute d'un serveur qui serve la version 2.
    30. Ajouté

      Surfaces : comptes supprimés

      • Un compte supprimé est oublié par les modules : son pseudonyme rejoint la liste d'attente de chaque module qui en a, et le module la reçoit par subject.forget, à son démarrage ou dès son prochain appel de surface. Le module de démonstration efface alors les notes de la personne.
    31. Ajouté

      Surfaces des modules, ADR 0030

      • Le cœur des surfaces : /surfaces, une surface (avec ETag et refresh_s), ses actions, les images des modules, et /admin/surfaces pour choisir, surface par surface et client par client, ce qui s'affiche et pour qui. Ce qu'un module rend est vérifié contre le vocabulaire avant d'atteindre un client : texte coupé, listes bornées, aucune adresse extérieure ni champ inconnu ; une réponse lente, fausse ou absente devient sa dernière réponse valide, ou un avertissement. Un module ne reçoit qu'un pseudonyme du compte. Événement surface.updated.
      • Première surface : la page Téléchargements (les siens, ou tous les comptes pour un administrateur, en cours et 30 jours d'historique). Affichée sur le site, désactivée sur la TV tant que l'administrateur ne l'active pas.
    32. Ajouté

      Surfaces des modules externes, ADR 0030

      • Un module externe peut déclarer des surfaces dans son manifeste : leur emplacement, leurs clients par défaut, leur public, leur fraîcheur, leurs libellés fr/en et leur icône. Le serveur l'interroge par surface.render et surface.action, avec 2 s au plus, 256 Kio pour une page et 64 Kio pour une action.
      • Le module ne reçoit jamais le compte : subject est un pseudonyme propre à lui (HMAC avec une clé par module, scellée, effacée par la purge).
      • Ses images viennent du dossier assets/ de son paquet, signé avec lui : PNG, JPEG ou WebP vérifiés sur leurs octets, 512 Kio au plus.
      • Module de démonstration exemple.surfaces, qui utilise chaque bloc et chaque emplacement, et deploy/package/dev-modules.sh pour le poser dans un dossier de développement.
    33. Ajouté

      Contrat des surfaces, ADR 0030

      • Le vocabulaire des blocs que les modules affichent dans la TV et le site : api/surfaces/schema.json (version 1), avec ses exemples partagés par le serveur, le site et la TV (api/surfaces/examples/). Les routes /surfaces, /surfaces/{module}/{surface}, ses actions, et /admin/surfaces sont au contrat, pas encore servies.
    34. Ajouté

      Sous-titres : épisodes, nettoyage, langues

      • Sur la fiche d'une série, chercher et ajouter des sous-titres pour l'épisode choisi.
      • Les sous-titres gardés d'un fichier qui a quitté les bibliothèques sont retirés une fois par jour : fichier disparu de la base, ou supprimé depuis 30 jours.
      • Module OpenSubtitles 1.1.1 : ses refus portent leur cause.
      • Les refus du service de sous-titres ont leur code : subtitles_quota et subtitles_busy (429, avec Retry-After), subtitles_login (422). Le web les écrit dans la langue du compte. Le protocole des modules gagne reason et retry_after sur une erreur ; un serveur plus ancien garde le texte du module.
    35. Ajouté

      Photos HEIC

      • « Ma bibliothèque » lit aussi la date, l'appareil et le lieu des photos HEIC, comme ceux des JPEG.
    36. Retiré

      Contrat

      • GET/PUT /admin/downloads/settings, jamais servies : ces réglages sont ceux du module Téléchargements et du module BitTorrent.
    37. Modifié

      Modules : publication et offre gratuite d'OpenSubtitles

      • qBittorrent et Transmission sont publiés sur le dépôt officiel modules.klarvi.fr, signés depuis le code actuel.
      • Module OpenSubtitles 1.1.0, réglé sur l'offre gratuite. Il envoie au plus 4 requêtes par seconde (le service en permet 5 par adresse IP) et réessaie une fois quand le service répond « trop de demandes ». Il ne se reconnecte pas tant que le compte réglé ne change pas.
      • Les téléchargements restants du jour s'affichent après une recherche et après un ajout : 5 sans compte, 20 avec un compte gratuit. Le champ quota de l'API les donne avec l'heure du renouvellement. Une fois le quota épuisé, le message donne cette heure et conseille un compte.
      • Un résultat déjà ajouté pour un fichier est marqué saved et refusé avant d'être téléchargé : chaque téléchargement compte dans le quota.
      • Mentions légales du dépôt : texte prêt dans docs/operations/mentions-legales-depot.md, sans l'identité de l'éditeur, à remplir avant publication sur le site vitrine.
    38. Modifié

      Fonctions du serveur, ADR 0022

      • Les mises à jour, TMDB et MusicBrainz ne sont plus des modules du catalogue, mais des fonctions du serveur, réglées là où on s'en sert : PATCH /admin/updates (et feature dans sa réponse), GET /admin/metadata-sources et PATCH /admin/metadata-sources/{id}. Leurs garanties ne changent pas : désactivées jusqu'au oui de l'administrateur, hôtes contactés affichés, clé chiffrée. Les réglages existants sont gardés tels quels, sans migration. /admin/modules et /modules ne les listent plus.
    1. Sécurité

      Service média, ADR 0028

      • Sans Landlock, FFmpeg peut tourner sous un compte à part : protoflix media-service, avec PROTOFLIX_MEDIA_SERVICE. Le serveur ne lui passe que des descripteurs (le fichier, le dossier de la tâche, les sorties). Ce compte n'a ni la base, ni la clé, ni la bibliothèque, ni le réseau. Unité deploy/systemd/protoflix-media.service, à activer à la main.
    2. Corrigé
      • Les essais matériels du démarrage écrivent dans leur propre dossier par noms relatifs.
      • Le dossier temporaire des moteurs est propre à chaque processus.
    3. Ajouté

      Module BitTorrent

      • Le module downloads.bittorrent, à installer et désactivé par défaut, récupère les liens magnet sans service de débridage, dans un processus confiné. Seuls les fichiers audio et vidéo sont pris, puis relus par le serveur. Par défaut, aucun envoi aux autres participants, aucun port entrant, aucune adresse du réseau local et aucun partage une fois le fichier arrivé.
    4. Sécurité

      FFmpeg isolé, ADR 0028

      • FFmpeg et ffprobe passent par le lanceur confiné du serveur : ni base, ni clé, ni réseau pour un fichier, et seul le dossier de la tâche en écriture. Sans Landlock, comme sur le Pixel 6, le filtre reste mais les fichiers du compte restent lisibles : le journal le dit au démarrage. PROTOFLIX_ISOLATE_MEDIA=false le coupe.
    5. Ajouté

      Photos de « Ma bibliothèque »

      • L'envoi accepte JPEG, PNG, GIF, WebP et HEIC. /api/v1/me/library/photos les liste par date de prise de vue et sert le fichier et ses vignettes. Date, appareil et lieu sont lus dans le fichier et montrés à son propriétaire seul ; les vignettes ne gardent aucune métadonnée.
    6. Ajouté

      MusicBrainz

      • Le module « MusicBrainz », désactivé par défaut, retrouve une pochette et une année pour les albums dont les fichiers n'en disent rien. Ce que disent les fichiers reste prioritaire, un album au nom douteux est laissé tel quel, et la musique de « Ma bibliothèque » n'est jamais envoyée.
    7. Ajouté

      Listes de lecture

      • /api/v1/music/playlists : chaque compte crée ses listes, y ajoute des pistes, y compris de son espace privé, les ordonne et les renomme. Nul autre compte n'y a accès, administrateur compris. Une piste dont le droit a été retiré disparaît de la vue sans laisser de trace.
    8. Ajouté

      Modules, lot 8

      • Module OpenSubtitles : chercher des sous-titres pour un film ou un épisode depuis sa fiche, puis les ajouter. Ils sont gardés par le serveur, hors des bibliothèques, et proposés à tous à la lecture. Réservé aux administrateurs et aux comptes qui peuvent télécharger.
    9. Ajouté

      Modules, lot 7

      • Modules qBittorrent et Transmission : un magnet est confié au client de l'administrateur, puis ses fichiers audio et vidéo terminés sont copiés dans la bibliothèque choisie. Le serveur ne rejoint toujours pas le réseau pair-à-pair.
      • Module de recherche : POST /api/v1/downloads/search et une recherche sur la page des téléchargements, à travers les indexeurs Torznab que l'administrateur ajoute. Aucun n'est fourni.
      • Capacité network_configured : un module ne joint que les adresses saisies par l'administrateur, réseau local compris.
    10. Modifié

      Modules, lot 5

      • Mega-Debrid devient un module à installer, signé et confiné, et quitte le binaire du serveur. Un compte déjà relié le reste, mais il faut installer puis activer le module. Sans lui, les liens d'hébergeurs et les torrents sont refusés, et les liens directs fonctionnent.
      • Le module « Mises à jour » couvre aussi les modules : recherche quotidienne et, en automatique, installation aux heures réglées des versions officielles qui ne demandent aucun nouveau droit.
      • Le serveur connaît le dépôt officiel, https://modules.klarvi.fr, et sa clé racine. Il ne le contacte que sur demande de l'administrateur, ou si le module « Mises à jour » est activé.
    11. Ajouté

      Suppression de compte

      • DELETE /api/v1/accounts/{id} supprime un compte et tout ce qu'il possède, espace privé compris, après confirmation. Désactiver un compte reste le moyen de tout garder.
      • PROTOFLIX_PRIVATE_MAX_GIB plafonne l'ensemble des espaces privés.
    12. Corrigé
      • Supprimer une bibliothèque efface aussi ses titres de l'index de recherche.
    13. Modifié

      App Android TV : mise en scène

      • Ouverture des films et des chaînes reprise du site : rideau, logo qui fait sa mise au point, ligne de chargement, et une image déjà à sa forme quand le rideau se lève. Le symbole de lecture a disparu. Un épisode montre le logo de sa série, son nom, sa saison et son numéro.
      • Écran de pause : titre, résumé, temps restant et heure de fin.
      • Page TV refaite : le programme en grand, bande « en ce moment », thèmes, numéro de chaîne tapé à la télécommande, ici et dans le lecteur.
      • Nouvel effet « Mise en scène », actif en Cinéma. Le préréglage Léger garde une ouverture sobre, sans animation.
      • Un titre ajouté au serveur apparaît seul sur l'accueil et dans les grilles, sans déplacer le curseur.
      • Qualité automatique : l'app mesure son débit et applique le conseil du serveur. Une qualité choisie à la main n'est jamais touchée.
      • Bande-annonce sur la fiche : un fichier gardé avec le film se lit dans l'app, une vidéo YouTube s'ouvre dans l'app YouTube.
      • Fiche : l'épisode sous la télécommande montre son image, sa saison, son numéro et son résumé ; la distribution en photos, la saga et le même genre suivent. Une personne ouvre ce qu'elle a fait.
      • Recherche : les ajouts récents avant la première lettre.
      • Sous-titres en ligne depuis le lecteur, pour un administrateur ou un compte qui peut télécharger : ceux faits pour ce fichier d'abord, gardés par le serveur et affichés aussitôt.
      • Surfaces des modules sur la TV (ADR 0030) : pages dans le rail, étages de l'accueil, sections et boutons de la fiche, lignes du lecteur, dessinées à partir des blocs du contrat ; un module qui s'en tient à eux apparaît sans nouvelle version de l'app.
      • L'app TV suit les modules actifs du serveur : TV en direct, enregistrements et sous-titres en ligne n'apparaissent que si leur module tourne, et suivent un changement en moins d'une minute.
      • Historique dans Ma liste, et listes de lecture de musique.
      • Musique sur la TV : écoutés dernièrement, albums, pistes et lecture en cours, une session par piste comme pour un film. La musique continue pendant qu'on parcourt l'app, derrière l'économiseur d'écran ; pages d'artiste ; artistes, albums et pistes dans la recherche.
      • Enregistrements de la box dans la TV en direct, quand l'administrateur les a activés : du plus récent au plus ancien, lus en plein écran avec avance et recul. Les bandes-annonces gardées avec le film passent par le même lecteur, qui gagne une barre de temps.
      • Ma bibliothèque sur la TV : les vidéos et les photos de l'espace privé du compte, les photos par mois, en plein écran et en diaporama.
      • Fin d'épisode : au générique, une carte propose le suivant avec un anneau de compte à rebours, ou de rester pour le générique. Fin d'un film : « Revoir » ou « Retour à la fiche », au lieu d'un retour sans prévenir.
      • Mises à jour de l'app depuis son serveur : GET /api/v1/clients/android-tv et son fichier, portés par le paquet à côté de l'interface web. La TV propose la version plus récente dans Réglages › À propos, un appui puis la confirmation d'Android. L'app est signée avec sa clé définitive : passer de l'ancienne version demande une désinstallation, une seule fois.
    14. Ajouté

      Téléchargements vers « Ma bibliothèque »

      • POST /api/v1/downloads accepte destination: "private" : le fichier arrive dans l'espace du compte, compte dans son quota et reste invisible des autres, administrateur compris.
    15. Ajouté

      Mises à jour, ADR 0027

      • Le module « Mises à jour », désactivé par défaut, cherche chaque jour une version signée du serveur et de son interface web. Elle s'installe en un clic (POST /api/v1/admin/updates/apply) ou seule la nuit, attend la fin des lectures, et revient à la version précédente, base comprise, si la nouvelle ne répond pas.
      • protoflix-release signe les versions publiées. Sans clé dans le binaire, ou dans une image Docker, le module explique pourquoi il ne peut rien faire.
    16. Ajouté

      Bandes-annonces

      • La fiche d'un film ou d'une série remplit enfin trailers : les fichiers de la bibliothèque (Dune-trailer.mp4, dossier trailers/), servis avec les droits de l'œuvre, et les vidéos YouTube connues de TMDB, triées selon les langues du spectateur.
      • Le module TMDB gagne le réglage « Bandes-annonces YouTube », actif par défaut. Le serveur ne contacte jamais YouTube : c'est le client qui le fait, après l'accord du spectateur.
    17. Ajouté

      Ma bibliothèque, ADR 0018

      • Chaque compte qui a un quota peut envoyer ses vidéos et sa musique : envoi reprenable après une coupure, quota et place vérifiés avant le premier octet, type réel vérifié à la fin. GET /api/v1/me/library, /me/library/uploads, DELETE /me/library/items/{id}. Pas de photos pour l'instant.
      • Nul autre compte n'y a accès, administrateur compris : il voit « Contenu privé » dans les lectures. L'espace reste hors de l'accueil et de la recherche de son propriétaire tant qu'il ne le demande pas.
    18. Ajouté

      Installer des modules, ADR 0024

      • L'administration installe, met à jour et retire des modules externes, depuis un dépôt signé ou depuis un fichier : /api/v1/admin/module-store, écran « Installer des modules », et protoflix module install serveur arrêté. Aucun dépôt n'est contacté sans demande de l'administrateur.
      • Chaque installation montre d'abord ce que le module pourra faire, et ce qu'une mise à jour demande de plus. Une mise à jour qui échoue à son contrôle revient seule à la version précédente, données comprises ; POST /api/v1/admin/modules/{id}/rollback y revient à la demande.
      • Les modules hors du dépôt officiel, dépôts tiers ou fichiers sans signature, sont possibles après acceptation du risque. Leur identifiant commence par x., et ils portent la mention « Non officiel ».
      • cmd/pfrepo signe et publie un dépôt (guide : docs/operations/module-repository.md). Le dépôt officiel n'existe pas encore : aucune clé officielle n'est livrée, donc aucun module n'est officiel.
      • Unité systemd : les appels Landlock sont autorisés et PrivateIPC activé. Compose : init: true.
    19. Corrigé

      Modules

      • Couper puis rallumer aussitôt un module externe l'affichait à tort en erreur : le serveur interrogeait encore l'ancien processus.
    20. Ajouté

      Modules externes, ADR 0024

      • Un module peut tourner comme un programme séparé et confiné : il parle au serveur par un protocole décrit dans docs/api/module-protocol.md, et n'atteint le réseau que par des hôtes déclarés. Pour l'instant, ces modules se chargent seulement depuis PROTOFLIX_MODULES_DEV_DIR, sans signature, pour en développer. Le téléchargement et les mises à jour restent à faire.
      • Le catalogue donne des avis par module (notices), affichés sur sa fiche : module de développement, et machine sans Landlock, où le module peut lire et modifier les fichiers du compte du serveur.
    21. Ajouté

      Modules

      • La TV entre dans le catalogue de modules : livetv.freebox et livetv.iptv, désactivés sur un serveur neuf. Un serveur qui a déjà une Freebox ou une liste les garde activés à la mise à jour. Désactivée, une source n'a plus ni flux ni chaînes, et ne contacte plus rien ; ses données restent.
      • POST /api/v1/admin/modules/{id}/purge efface les données et les réglages d'un module désactivé, avec confirmation et ligne d'audit. Les bibliothèques ne sont jamais touchées.
    22. Ajouté

      Qualité automatique pendant la lecture, ADR 0026

      • En qualité auto, le signal de lecture accepte throughput_bps et buffer_ms et peut répondre adapt : le client rouvre une session sous la nouvelle limite. Descente immédiate, remontée lente, de plus en plus lente après chaque échec. Une qualité choisie à la main ne change jamais.
      • Une limite de débit baisse aussi la définition : 720p sous 6,4 Mb/s, 480p sous 3,2, 360p sous 1,6.
    23. Ajouté

      Musique, ADR 0025

      • Une bibliothèque de musique est lue : étiquettes des fichiers, sinon chemin Artiste/Album (année)/01 - Titre.flac ; albums, artistes, pistes, compilations, pochettes du dossier ou du fichier. API /api/v1/music/*.
      • Lecture directe des formats que lit le client (MP3, FLAC, AAC, Opus, Vorbis, WAV), sinon conversion en AAC. Une piste se lance par la session de lecture habituelle.
      • Tous les fichiers sont réanalysés une fois (ParserVersion 5). La migration reconstruit media_items : une sauvegarde est prise avant.
    24. Sécurité

      Revue complète, `docs/security/review-2026-11-07.md`

      • Une requête transférée par un proxy non déclaré, ou par un proxy déclaré qui ne nomme pas son client, compte comme distante : un inconnu ne peut plus créer le premier administrateur par ce biais. Toutes les lignes de X-Forwarded-For comptent.
      • Code rapide et connexion : les tentatives d'une rafale sont comptées avant la vérification. Un inconnu ne bloque plus le propriétaire d'un compte (limite par adresse et compte, plafond de 50 par compte seul). Changer de mot de passe supprime les codes rapides.
      • Les jetons de lecture cessent avec le compte, l'appareil ou les droits. Un compte tient 2 conversions au plus : la plus ancienne du même appareil cède sa place.
      • TV : 8 flux en tout, 30 démarrages par minute et par compte ; logos jugés sur leurs octets ; un guide nommé par une liste ne vise plus le réseau local.
      • PROTOFLIX_TRANSCODE_DIR n'efface plus que les dossiers de session, et ne peut plus contenir les données.
      • Créer le premier administrateur demande un code écrit dans les journaux du serveur (setup_token, PROTOFLIX_SETUP_TOKEN pour le fixer).
      • Une session ouverte par code rapide n'administre pas avant d'avoir redonné le mot de passe (POST /api/v1/auth/confirm-password, admin_password_required).
      • Droit live_tv_allowed par compte, désactivé pour les enfants, y compris les comptes existants.
      • Effacer son historique efface aussi les lectures terminées que voit l'administrateur.
      • CSP sur l'interface web et les images TV. Base en mode 0600. Aperçus, étiquettes de fichiers, cache de logos et guide bornés. Flux d'événements : droits relus toutes les 25 s. Un compte enfant a toujours une limite d'âge.
    25. Ajouté

      Client Android TV

      • android-tv/ : client natif pour la télécommande (Kotlin, Compose, Media3). Accueil « Les étages », fiche, grilles, recherche, TV en direct, lecteur, plan de lecture expliqué, réglages d'effets, français et anglais. Plans et mesures dans docs/tv/, décision dans l'ADR 0023.
      • Lecteur de la TV en direct : programme, horaires, zapping, liste des chaînes, pause et retour au direct, comme sur le web.
      • Récap d'un épisode (recap, migration 30) : un marqueur de plus, trouvé dans les sous-titres complets du fichier quand ils annoncent « Précédemment dans… ». Bouton sur la TV ; l'API le donne déjà au web, qui ne l'affiche pas encore.
      • Client TV, V1.1 : connexion par code ou QR sans mot de passe, serveur trouvé tout seul sur le réseau, guide des programmes, langues modifiables, rangée « Reprendre » sur l'accueil Android.
      • Serveur : connexion d'un appareil par un code affiché dessus (/api/v1/auth/pairings, /api/v1/me/pairings, page /appareil). Annonce mDNS sur les réseaux privés (PROTOFLIX_DISCOVERY=off pour la couper).
      • Accueil TV plus régulier : plus d'image 4K décodée et envoyée d'un bloc au GPU à chaque titre, une seule bande réutilisée d'un étage à l'autre et défilée par calque, préchargement sans décodage. Pire blocage du fil principal de 99 à 33-49 ms, fils de fond de 9,6 à 1,4 s sur 16 s de parcours. Le compteur gfxinfo reste à environ 20 %, comme Jellyfin sur la même TV : la cible de 5 % n'est pas atteinte.
      • Serveur : profil de lecture androidtv@1. Le lecteur natif ouvre le Matroska et l'audio d'origine : l'application le restreint à ce que la TV déclare. Un lecteur natif choisit lui-même sa piste audio dans le fichier : changer de langue ne demande aucune conversion (SelectsAudio).
      • TV en direct : le flux est demandé à la Freebox à son adresse locale quand la passerelle de la machine est bien la box. Par son nom, la box envoie l'image depuis une adresse publique, qu'un pare-feu limité au réseau local refuse : aucune image n'arrivait (tv_stream_no_data).
    26. Corrigé

      Recherche

      • Une recherche de deux lettres renvoyait une erreur 500 (bm25 dans une requête aplatie par SQLite), web compris.
    27. Corrigé

      Nvidia

      • Les segments sortis de NVENC duraient 10,4 s au lieu de 2 (-forced-idr).
      • La doc Nvidia présentait une mire comme un film : mesures refaites sur de vrais films, l'avantage annoncé de NVENC à 12 Mb/s sur x264 medium à 8 Mb/s n'existe pas (égalité).
    28. Ajouté

      Pour le plan de design

      • Conversion HDR près de deux fois plus rapide : les tons viennent d'une table faite pour le pic du film, lu à l'analyse (hdr_peak_nits ; tous les fichiers sont réanalysés une fois). Sur une carte Nvidia, l'image est réduite sur la carte avant.
      • Guide TV : les images de programme passent par le serveur (image, GET /tv/programmes/{id}/image), l'adresse du spectateur ne part plus chez l'hébergeur du guide.
      • Historique des lectures : conservé sans limite par défaut, durée réglable par l'administrateur (/admin/sessions/history/settings), et bouton pour le vider (DELETE /admin/sessions/history). La reprise et les œuvres vues de chaque compte n'en dépendent pas.
      • Les images donnent leur couleur dominante et un point d'intérêt (dominant_color, focus_x), calculés une fois à leur téléchargement.
      • GET /admin/sessions/history : les lectures terminées, avec leur mode et leurs raisons. GET /admin/sessions/{id}/events : la frise d'une lecture.
      • Les images disent si elles portent du texte (has_text, language).
      • Genres et rôles que TMDB laisse en anglais, traduits en français (« Action & Aventure », « (voix) »). Les œuvres identifiées sont redemandées une fois.
    29. Ajouté

      Nvidia

      • Chaîne Nvidia : décodage NVDEC, mise à l'échelle sur la carte, encodage NVENC, repérés au démarrage en les utilisant, jusqu'à quatre conversions ensemble. Mesurée sur une GTX 1080 par le pilote Windows dans Docker, pas encore sur un vrai Linux. Le mappage de tons HDR reste sur le processeur.
      • Le service systemd et le compose donnent accès aux cartes graphiques, et à rien d'autre de /dev.
    30. Ajouté

      Installation Linux

      • Paquet .deb et archive avec install.sh, construits par deploy/package/build.sh et essayés sur des systèmes vierges par deploy/package/test/run.sh : installation, premier compte, bibliothèque, lecture, mise à jour, retrait.
      • L'image Docker contient maintenant l'interface web et FFmpeg. Le port par défaut du paquet et de l'image est 8097, pour tourner à côté de Jellyfin.
      • FFmpeg 6.1 est le minimum. Avec une version plus ancienne, le serveur le signale et n'analyse plus rien, au lieu de déclarer tous les fichiers illisibles.
    31. Corrigé

      Plan de lecture

      • Une piste HDR convertie en SDR ne donne plus deux raisons pour la même chose : hdr_tone_mapped seule reste.
    32. Corrigé

      Noms de fichiers

      • Noms français reconnus : FRENCH, VFF, HDLight et autres balises, filigranes de sites en tête ou en fin, noms encodés comme une adresse, dossiers « Partie N », « Épisodes spéciaux », « Hors saison », « Épisode 7 » sans saison, dossier de saison complète.
      • Les mots de vrais titres ne coupent plus le nom : The French Connection ne devient plus « The », ni Charlottes Web « Charlottes ».
      • TMDB : second essai en anglais si le nom n'est pas trouvé, fiches vides écartées, préfixes de marque ignorés (« Marvel's »).
      • Devant deux œuvres de même nom, celle qui est au moins deux fois plus connue passe sans arbitrage. Si elles sont proches, l'administrateur tranche toujours.
    33. Ajouté

      Génériques, lectures simultanées

      • Les génériques de début et de fin des séries sont repérés en comparant l'audio des épisodes d'une saison, et donnés sur la fiche de chaque version (markers).
      • Sur le Pixel, trois conversions peuvent tourner ensemble au lieu d'une.
    34. Corrigé

      Repli logiciel

      • Si la chaîne matérielle échoue au démarrage d'une conversion, le processeur prend le relais au lieu de refuser la lecture. Le film se lit, plus lentement, et la session l'indique (software_fallback).
    35. Ajouté

      Taille et débit tenables

      • Sans matériel adapté, le serveur chronomètre son encodeur au démarrage et n'accepte pas une taille qu'il ne tiendrait pas en temps réel. Le plan de lecture le dit (output_limited_by_server).
      • Un encodeur matériel reçoit une fois et demie plus de débit (1080p à 12 Mb/s), à qualité mesurée équivalente à x264 à 8 Mb/s.
      • GET /playback/bandwidth-test : le client mesure sa liaison, et son résultat borne le plan de lecture en qualité automatique.
    36. Ajouté

      HDR

      • Un serveur sans matériel adapté lit désormais les films HDR10, HLG et Dolby Vision à couche de base, convertis en SDR par le processeur, au lieu de les refuser. Dolby Vision profil 5 reste refusé.
      • Un client qui prouve que son décodeur lit le HEVC reçoit l'image d'origine, 4K et HDR compris, sans conversion.
    1. Modifié

      Démarrage et sauts

      • Segments de 2 s au lieu de 6, AAC rapide, et un saut n'attend plus la fin de l'ancienne conversion. Le démarrage et les sauts d'un transcodage sont plus courts. L'audio stéréo converti passe de 128 à 192 kb/s.
      • Une conversion s'arrête de travailler à 60 s d'avance sur le lecteur et reprend à 30 s, y compris quand la lecture est en pause : moins de calcul et de chaleur pour une partie du film qu'on n'atteindra peut-être pas.
    2. Ajouté

      Aperçus

      • Images de la barre de lecture, une toutes les 10 s, sur la fiche de chaque version. À activer par bibliothèque (previews_enabled, désactivé par défaut) : chaque fichier est lu une fois, à basse priorité et un à la fois, dans la limite de 2 Gio.
    3. Ajouté

      Acteurs, réalisateurs, sagas

      • La fiche d'une œuvre donne ses créateurs, réalisateurs, scénaristes et acteurs, et sa saga. Les œuvres déjà identifiées sont redemandées une fois à TMDB ; les valeurs corrigées restent verrouillées.
      • GET /items filtre par personne (person_id) et par saga (collection_id). Nouvelles routes /people/{id} et /collections, dans les droits du compte.
      • La recherche trouve une œuvre par le nom d'une personne ou de sa saga.
    4. Ajouté

      Chapitres

      • La fiche d'une œuvre donne les chapitres de chaque version : début, fin et titre.
    5. Ajouté

      Libellés des tâches

      • Les tâches portent label_key et label_params : l'interface peut les dire dans sa langue. label reste en français pour les autres clients et les tâches plus anciennes.
    6. Ajouté

      Temps réel

      • sessions.updated et sessions.ended : les administrateurs suivent les lectures en cours sans sonder le serveur.
      • catalog.changed : tout compte qui voit une bibliothèque apprend que ce qu'elle liste a changé, sans détail sur les œuvres. Au plus un événement toutes les 5 s par bibliothèque.
      • libraries.updated part aussi quand un scan ou une identification change les compteurs.
    7. Ajouté

      Filtres du catalogue

      • GET /items filtre aussi par années (year_min, year_max) et par qualité (quality=2160p ou hdr, sur n'importe quel fichier présent de l'œuvre). Sa première page donne le nombre total d'œuvres (total).
      • GET /items/facets donne les genres, années et qualités qui mènent à au moins une œuvre, avec leur nombre, dans les droits du compte.
    8. Ajouté

      Langues

      • GET et PUT /me/preferences : langues audio et sous-titres, mode de sous-titres et qualité maximale suivent le compte d'un appareil à l'autre.
      • Langue par défaut du serveur : default_locale dans /server/info, lisible avant la connexion, réglable par PUT /admin/server/default-locale. Les nouveaux comptes la prennent ; les comptes existants gardent la leur.
    9. Ajouté

      Détection automatique

      • Sous Linux, un film ajouté, déplacé ou supprimé sur un disque local est vu tout seul, une vingtaine de secondes après le changement, sans lancer de scan. Les partages réseau et les autres systèmes restent au scan quotidien ou manuel.
    10. Corrigé

      Scan

      • Un film supprimé du disque restait dans les listes, la recherche et les compteurs tant que la suppression n'était pas confirmée, soit 72 h au moins. Il en sort dès le scan. Rien n'est effacé : s'il revient, il retrouve sa fiche et son historique.
      • La date du dernier scan ne suivait que les scans complets : elle semblait figée après un scan rapide. Elle suit maintenant tout scan abouti.
    11. Ajouté

      Images et recherche chez le fournisseur

      • /api/v1/artwork/{id}?w= : 360, 720, 1440 ou 2880 ; cache des images borné à 2 Gio.
      • Administration : GET /admin/metadata/search pour chercher une œuvre sous un autre nom, affiche et résumé des candidats dans la file de validation, DELETE /admin/catalog/review/{id} pour laisser une œuvre telle quelle.
      • Administration : GET /admin/items/{id}/images et PUT, DELETE /admin/items/{id}/artwork/{kind} pour choisir une image. Une image choisie reste, même après un nouveau rapprochement.
      • La fiche porte admin (état du rapprochement, champs corrigés à la main, identifiants externes) pour les administrateurs.
    12. Corrigé

      Images

      • Une image remplacée chez le fournisseur gardait son URL, déclarée immuable : le client et le cache pouvaient garder l'ancienne. Elle reçoit maintenant une nouvelle URL.
    13. Ajouté

      Interface servie par le serveur

      • PROTOFLIX_WEB_DIR : le serveur sert lui-même l'interface web construite, sans second programme. /api/, /livez et /readyz gardent leurs réponses.
    14. Ajouté

      Chaîne matérielle du Pixel 6

      • Avec le ffmpeg de Pixel Server : décodage et encodage sur le bloc vidéo, mise à l'échelle et mappage de tons sur le G2D. Les films HDR10 et Dolby Vision sur base HDR10 se lisent en SDR, y compris avec des sous-titres PGS incrustés. Essayée au démarrage ; sans elle, rien ne change.
      • Détection HDR plus sûre : la première image est lue quand le flux ne dit rien de ses couleurs. Les fichiers sont réanalysés une fois.
    15. Corrigé

      Disque pendant une conversion

      • L'espace libre n'était contrôlé qu'au démarrage d'une conversion, qui pouvait ensuite occuper 40 Gio. Elle s'arrête maintenant sous 2 Gio libres, avec seek_to_continue ; ce qui est produit reste lisible.
    16. Corrigé

      Scan différé

      • Un fichier modifié depuis moins de 2 minutes est considéré en cours de copie : le scan le laisse de côté et un second scan suit 2 min 30 plus tard. Le libellé de ce second scan le dit désormais, au lieu de ressembler à un scan bloqué.
    17. Corrigé

      Fin des lots en cours

      • Téléchargements : le type réel du fichier est lu par ffprobe avant l'import (not_media). Deux imports du même nom ne peuvent plus s'écraser là où le système de fichiers a des liens physiques.
      • Fiche d'une série ou d'une saison : next_episode_id est rempli, selon la même règle que « Reprendre ».
      • Contrat : les routes pas encore servies sont marquées « planifié » (/me/preferences, /admin/downloads/settings, /me/library/uploads).
    18. Ajouté

      Sous-titres image

      • Les sous-titres PGS, VobSub et DVB s'incrustent dans l'image quand on les choisit (subtitle_track_id, subtitle_delivery: burn_in). La vidéo est réencodée : c'est plus coûteux, et en changer demande une nouvelle session. Sans encodeur, ou sur une vidéo HDR sans chaîne matérielle, la lecture continue sans eux (subtitle_burn_in_unavailable).
    19. Corrigé

      Événement des bibliothèques

      • L'événement temps réel libraries.updated envoyait tous ses compteurs à 0 (item_count, file_count, size_bytes, pending_matches). Il porte maintenant les mêmes valeurs que GET /api/v1/libraries. Il part quand une bibliothèque change, pas à chaque fichier scanné.
    20. Ajouté

      Ma liste, Reprendre, Historique

      • GET, PUT et DELETE /api/v1/me/list, GET /api/v1/me/continue, GET et DELETE /api/v1/me/history.
        • Privés au compte, administrateurs compris. Les droits sont appliqués à la lecture : une œuvre devenue invisible est masquée, pas effacée.
        • « Reprendre » donne une entrée par œuvre. Pour une série : le dernier épisode lu s'il n'est pas terminé, sinon le suivant non terminé et présent sur le disque (up_next), y compris à la saison suivante. Une série entièrement vue sort de la liste.
        • Effacer l'historique garde la position dans chaque œuvre et la marque « vu ».
    21. Sécurité

      Destinations des téléchargements

      • Un compte non admin ne peut télécharger que vers les bibliothèques que l'administrateur a ouvertes (accepts_downloads, PATCH /api/v1/libraries/{id}), sinon 403 destination_not_allowed. Fermé par défaut, y compris pour les bibliothèques existantes : les téléchargements non admin en file vers une bibliothèque fermée s'arrêtent à leur prochain démarrage.
    22. Sécurité

      Relecture des téléchargements

      • Disque : une taille maximale par fichier et un espace à garder libre, réglables dans le module (200 Gio et 10 Gio par défaut). Rien ne les limitait, et une réponse compressée de 411 Ko pouvait devenir 200 Mio : les réponses compressées sont maintenant refusées. 100 téléchargements non terminés au plus par compte non admin.
      • Droits : un droit retiré empêche la reprise et arrête ce qui était en file. Une route de débridage coupée par l'admin ne peut plus être demandée par le client.
      • Chemins : les erreurs lues par le propriétaire d'un téléchargement ou de son job ne contiennent plus de chemin du serveur.
      • Sorties réseau (tous les modules) : plages spéciales refusées en plus (dont 192.0.0.0/24, 198.18.0.0/15, 240.0.0.0/4, fec0::/10, 168.63.129.16). NAT64 et 6to4 sont jugés sur l'adresse IPv4 qu'ils portent. Le lien n'est plus envoyé en Referer lors d'une redirection.
    23. Corrigé

      Téléchargements

      • Après une redirection, le fichier prend le nom de la dernière adresse si celui de la première n'est pas un média.
    24. Corrigé

      Compteurs des bibliothèques

      • item_count et admin.pending_matches valaient toujours 0 dans GET /api/v1/libraries. item_count donne maintenant le nombre d'œuvres que le compte peut ouvrir, avec les règles de la liste : limite d'âge du compte comprise, une série compte pour une.
    25. Ajouté

      Lectures en cours

      • GET /api/v1/admin/sessions (admin) : qui lit quoi, sur quel appareil, avec le plan piste par piste, les raisons, l'encodeur et la vitesse de conversion.
        • Aucune URL de média, aucun jeton, aucun chemin : la liste sert à comprendre, pas à regarder.
        • Le titre des bibliothèques privées devra y être masqué quand elles existeront (authn-authz.md) : elles n'existent pas encore.
    26. Ajouté

      Fichiers de sous-titres

      • Fichiers .srt, .ass, .ssa et .vtt posés à côté d'un film (Film.fr.srt, Film.en.forced.srt, dossier Subs) : listés dans la fiche (external) et dans delivery.subtitles.
        • Vus dès qu'ils sont posés, sans nouveau scan. Une session déjà ouverte ne voit que ceux présents à son démarrage.
        • Convertis en WebVTT par le serveur lui-même : aucun processus lancé sur ces fichiers, et ils marchent sans FFmpeg.
        • UTF-8, UTF-16 et Windows-1252 (anciens sous-titres français) sont reconnus. Le balisage autre que gras, italique et souligné est retiré.
    27. Ajouté

      Sous-titres texte

      • Sous-titres intégrés au fichier (SRT, ASS, mov_text, WebVTT…) servis en WebVTT : delivery.subtitles et GET /api/v1/media/s/{jeton}/subtitles/s3.vtt.
        • L'image et le son ne changent pas : la lecture directe reste directe. Changer de sous-titres ne demande ni nouvelle session ni relance.
        • Première extraction : lecture de tout le fichier, 2 à la fois, avec les répliques déjà connues servies pendant ce temps (X-Subtitles-Complete). Résultat gardé entre deux démarrages, 1 Gio au plus.
        • Raisons du plan : subtitle_converted, subtitle_style_lost (ASS).
        • Les sous-titres bitmap (PGS, VobSub) restent non livrés : subtitle_not_yet_supported.
    28. Corrigé
      • timeline_offset_ms après un saut en copie vidéo : il valait la cible du saut alors que la vidéo repart de l'image clé précédente, soit jusqu'à la longueur d'un GOP d'écart (position fausse, et sous-titres décalés d'autant). Il vaut maintenant le début réel.
    1. Ajouté

      Sélecteur de dossiers

      • GET /api/v1/libraries/browse (admin) : parcourt les dossiers du serveur pour choisir une source au lieu de taper un chemin.
        • Sans chemin : les lecteurs sous Windows ; sous Linux, / et les emplacements habituels qui existent ici.
        • Dossiers seulement, jamais de fichier ; dossiers cachés et techniques des NAS masqués.
        • Zones système et données du serveur jamais listées, y compris par un lien symbolique.
        • Mêmes refus que test-path, avec la raison et son code stable (reason_code, problem_code pour test-path) ; media_hint donne le nombre de médias du premier niveau, avec des limites pour qu'un dossier énorme ou un partage lent ne bloque pas.
    2. Ajouté

      Lot 4b, encodage vidéo logiciel

      • Les fichiers que le navigateur ne peut pas décoder sont lus : HEVC hors Safari, MPEG-2, vidéos trop grandes pour le client, qualité réduite à la demande ou par la politique à distance. Sortie H.264 High 8 bits en HLS fMP4, à la définition d'origine dans la limite du client, avec l'audio copié ou converti.
      • Enregistrements TV entrelacés : désentrelacés (yadif), puis encodés.
      • Couleurs : la signalisation SDR d'origine est conservée (testé). Un film HDR que le client ne peut pas afficher reste refusé (hdr_tonemap_unavailable) : pas de couleurs fausses tant que le mappage de tons n'est pas validé (phase 5).
      • Test de démarrage de l'encodeur (quelques images réellement encodées) ; en cas d'échec, seuls les fichiers qui en ont besoin sont refusés.
      • Ressources : au plus un encodage par tranche de 4 cœurs (au moins 1), refus immédiat au-delà (resources_exhausted), jamais de file d'attente. conversion_speed dans la session : sous 1, le lecteur attendra.
      • Vérifié en conditions réelles dans le conteneur (16 cœurs), sur des fichiers synthétiques : HEVC 1080p prêt en 1,6 s, décodé depuis l'URL, produit à 4,9 fois le temps réel ; enregistrement entrelacé lu ; HDR10 refusé avec sa raison. Pas encore dans un vrai navigateur. Les vitesses sur de vrais films et sur une petite machine restent à mesurer.
    3. Ajouté

      Lot 4a, remux et conversion audio

      • Les MKV et les fichiers au son non décodé par le navigateur (AC-3, DTS, TrueHD…) sont lus, sans réencoder l'image : HLS fMP4 (GET /api/v1/media/s/{jeton}/hls/{nom}), vidéo copiée, audio copié ou converti en AAC (canaux conservés dans la limite du client). internal/transcoding supervise, internal/transcoding/ffmpeg est seul à connaître la syntaxe.
      • Choix de la piste audio : une autre piste que celle par défaut passe par le remux (raison audio_track_selection), car un lecteur à qui l'on donne le fichier joue la piste par défaut. Avant, le plan promettait à tort cette piste en lecture directe.
      • Saut PATCH /api/v1/playback/sessions/{id} : relance la conversion à la position demandée ; timeline_offset_ms donne le temps du film au début de la playlist.
      • Sécurité : ffmpeg reçoit le fichier par descripteur et ne voit aucun chemin ; les noms servis sont une liste fixe ; environnement minimal ; aucun détail du moteur dans les réponses.
      • Ressources : 4 conversions au plus, jamais de file d'attente (resources_exhausted) ; espace libre vérifié ; budget disque par conversion ; arrêt si plus aucune progression.
      • Pannes : à l'arrêt, à l'expiration ou à l'abandon d'une session, le processus et ses fichiers disparaissent. Après un kill -9 du serveur, ffmpeg meurt avec lui (Linux) ; au redémarrage, les répertoires sont vidés et les sessions passent failed : le client en recrée une à la position enregistrée.
      • Vidéo entrelacée : l'analyse relève maintenant field_order (migration 00014, normaliseur en version 2, réanalyse automatique au prochain scan). Le plan refuse de copier ces fichiers (raison video_interlaced), car Chromium produit alors des erreurs de décodage aléatoires. Ils seront lisibles avec l'encodage vidéo (lot 4b).
      • PROTOFLIX_TRANSCODE_DIR (par défaut CACHE_DIR/transcode, vidé à chaque démarrage).
      • Vérifié en conditions réelles dans le conteneur, sur un MKV de 10 minutes H.264 + AC-3 :
        • session prête en 378 ms, sortie H.264 + AAC 5.1 décodée par FFmpeg depuis l'URL ;
        • saut à 300 s en 475 ms ;
        • ffmpeg sans chemin sur sa ligne de commande ;
        • noms hors liste refusés (404) ;
        • plus aucun processus ni fichier après l'arrêt ou un kill -9.

      Pas encore essayé dans un vrai navigateur : le lecteur web n'est pas branché. Ces temps viennent d'un fichier synthétique sur disque local : à mesurer sur de vrais films et sur un NAS.

    4. Ajouté

      Lot 3a, lecture directe

      • Moteur de décision internal/playback.Decide (docs/media/playback-decision.md) : une fonction pure qui produit un plan déterministe (lecture directe, remux ou transcodage) avec toutes les raisons.
        • Profils web-chromium@1 (alias chrome, edge), web-firefox@1, web-safari@1 et conservative@1 ; un profil inconnu retombe sur le profil prudent. La déclaration du client ne peut que restreindre.
        • Les limites de qualité demandée et de politique à distance s'appliquent.
        • Testé par une table de cas et par des propriétés vérifiées sur 3 000 entrées aléatoires : déterminisme, une raison pour tout ce qui n'est pas direct, aucune déclaration ne peut élargir le profil.
      • Sessions de lecture (migration 00013) : POST /api/v1/playback/plan-preview, POST /api/v1/playback/sessions, GET (qui renouvelle le jeton) et DELETE.
        • Seule la lecture directe est exécutée. Un plan qui demanderait un remux ou un transcodage répond 503 transcoder_unavailable jusqu'à la phase 4.
      • Fichier GET /api/v1/media/s/{jeton}/file :
        • jeton HMAC lié à la session, valable 4 h, qui ne sert plus dès l'arrêt ou l'expiration de la session ;
        • Range, ETag, If-Range ;
        • fichier ouvert par la racine confinée de la source ;
        • jamais de jeton dans les journaux.
      • Progression PUT …/progress : idempotente (les événements anciens sont ignorés) ; reprise par compte (ItemSummary.progress, la dernière écriture gagne entre appareils) ; vue à 90 % (historique). Une session sans heartbeat passe stalled après 30 s, puis expired après 5 min.
      • PROTOFLIX_PLAYBACK_EXPERIMENTAL (par défaut true) : les règles de compatibilité pas encore mesurées décident, faute de banc. Le plan l'indique (support: experimental).
    5. Corrigé
      • Essai réel de TMDB avec une vraie clé (docs/adr/0016-fournisseur-metadonnees.md). Il a révélé trois défauts, corrigés :
        • un titre écrit sans apostrophe dans le nom de fichier (« d Amelie ») partait en validation au lieu d'être reconnu ;
        • des logos SVG, que le serveur refuse de servir, étaient retenus : seules les images servables le sont désormais ;
        • file de jobs : un job ponctuel d'un type récurrent (metadata.match_all lancé à l'activation du module) replanifiait le type en heurtant l'occurrence déjà prévue, son résultat n'était pas enregistré et il repartait après expiration de son lease. Seule l'occurrence récurrente se replanifie désormais.
      • Tri par titre : « Alien », « Annie Hall » ou « Amélie » étaient rangés sans leur première lettre, comme si « A » était un article. Les clés de tri existantes sont recalculées une fois au démarrage.
    6. Ajouté

      Lot 2f, recherche et corrections

      • Recherche GET /api/v1/search (ADR 0015, accepté), avec SQLite FTS5 (migration 00011) :
        • par titre, titre original et genre ; accents et casse ignorés ;
        • tous les mots requis, le dernier en préfixe (« dun par » trouve « Dune: Part Two ») ;
        • fragments d'au moins 3 caractères à l'intérieur des titres (« xpans » trouve « The Expanse ») ;
        • droits (bibliothèques, limite d'âge) appliqués dans la requête ; les opérateurs saisis sont du texte ordinaire ;
        • ordre stable et pagination par curseur.
      • Mesure sur 50 000 œuvres, sur le poste de développement : P50 14 ms, P95 103 ms (docs/testing/benchmarks/search/).
      • Corrections manuelles PATCH /api/v1/admin/items/{id} : titre, titre original, titre de tri, année, synopsis, classification et genres.
        • Chaque correction devient une valeur verrouillée, prioritaire sur les NFO, TMDB et le nom de fichier.
        • Un champ envoyé à null rend la main aux autres sources.
        • Elle s'applique aussi aux saisons et aux épisodes.
      • Une œuvre en attente de validation le reste jusqu'à un choix ou une correction, même si de nouveaux fichiers arrivent.
    7. Modifié

      Demande du porteur du projet

      • Mot de passe : la longueur minimale passe de 12 à 8 caractères, sans règle de composition. Sont désormais refusés les mots de passe très courants (liste locale), les caractères répétés, les suites (12345678), les rangées de clavier (azertyuiop) et la partie locale de l'e-mail. Contrat mis à jour (minLength: 8).
    8. Ajouté

      Lot 2e, modules et TMDB

      • Modules activables (ADR 0022, accepté) :
        • catalogue, états (désactivé, à configurer, erreur, indisponible, actif) et dépendances ;
        • réglages typés et validés, secrets chiffrés au repos et jamais relus ; null efface ;
        • vérification immédiate après un changement, événement modules.updated ;
        • API /api/v1/modules et /api/v1/admin/modules.
      • Client sortant commun (internal/platform/outbound) : hôtes déclarés uniquement, adresses privées refusées après DNS (SSRF), pas de proxy d'environnement, redirections contrôlées, HTTPS seul, réponses limitées, requêtes espacées, clé jamais écrite dans les erreurs.
      • Module metadata.tmdb (ADR 0016), avec la clé de l'administrateur :
        • recherche et score titre et année ; identifiants des NFO utilisés directement, IMDb et TVDB résolus ;
        • les cas ambigus vont dans une file de validation (GET /api/v1/admin/catalog/review, choix par POST /api/v1/admin/items/{id}/match) ;
        • titres, résumés, genres et classification (pays de la langue choisie), pour les saisons et les épisodes aussi ;
        • un nouvel épisode fait redemander la série ;
        • les NFO et les corrections manuelles restent prioritaires.
      • Images : affiches, fonds, logos et vignettes d'épisodes, servis par GET /api/v1/artwork/{id} après contrôle des droits. Téléchargés au premier usage et mis en cache dans PROTOFLIX_CACHE_DIR (par défaut DATA_DIR/cache). Le SVG est refusé.
      • Les classifications d'âge passent dans un paquet commun (internal/catalog/rating).
      • Vérifié en conditions réelles depuis le conteneur : une fausse clé est refusée par le vrai TMDB (« Clé API refusée par TMDB »), et la clé n'apparaît pas en clair dans la base. Le reste du parcours TMDB est testé contre un faux serveur TMDB. Pas encore validé avec une vraie clé.
    9. Ajouté

      Lot 2d, catalogue

      • Catalogue en couches (ADR 0014, accepté), migration 00009 :
        • une œuvre (film, série › saison › épisode, vidéo perso) a des éditions, chaque édition des versions, chaque version des fichiers ;
        • les métadonnées sont gardées par champ, avec leur source (metadata_values) ;
        • les identifiants TMDB, IMDb et TVDB sont conservés.
      • Identification locale (docs/media/naming.md), par le job catalog.identify mis en file après chaque scan :
        • films : titre, année et édition tirés des noms de release et des dossiers « Titre (Année) » ;
        • séries : S01E02 et 1x02, dossiers de saison ;
        • bonus (bandes-annonces, échantillons) écartés du catalogue ;
        • NFO Kodi, Jellyfin, Radarr et Sonarr, traités comme des entrées hostiles ;
        • copies identiques regroupées dans une même version.
      • Arbitrage des métadonnées : une valeur verrouillée l'emporte, puis manuel, puis NFO, puis fournisseur, puis nom de fichier.
      • Classifications d'âge (FR, MPA, TV, FSK) ramenées aux paliers 0, 10, 12, 16 et 18. Une œuvre sans classification est masquée sous une limite d'âge.
      • API GET /api/v1/items, /items/{id} et /items/{id}/children :
        • filtrées par les bibliothèques visibles et la limite d'âge du compte ; une œuvre invisible répond 404 ;
        • tris added_desc, title_asc (sans l'article) et year_desc, avec un curseur lié au tri ;
        • disponibilité available, source_offline ou missing ;
        • versions triées de la meilleure à la moins bonne ; libellés et badges (2160p, HDR10, Dolby Vision, Atmos, 5.1, 7.1) tirés de l'analyse uniquement ;
        • pistes détaillées, sans aucun chemin.
      • Vérifié en conditions réelles dans le conteneur, avec 2 bibliothèques :
        • Dune : 2 versions et la classification « 12 » tirée du NFO ;
        • la bande-annonce est écartée ;
        • la série est rangée en saisons ;
        • un identifiant inconnu répond 404.
    10. Modifié

      Demandes du front

      • Les jobs exposent subject : ce sur quoi ils portent, en identifiants publics uniquement. Pour un scan ou une analyse, c'est {kind: "source", id, library_id} ; pour un job global, null. Le front n'a plus à deviner la bibliothèque à partir du libellé. Migration 00008.
      • force lève aussi la protection empty_root, pour le cas d'un dossier vraiment vidé. Même forcé, rien n'est supprimé tout de suite : les fichiers passent absents et retrouvent leur identité si le dossier revient (testé).
    11. Ajouté

      Lot 2c, analyse des médias

      • internal/mediaanalysis : description technique d'un fichier indépendante de ffprobe. Elle comprend :
        • le conteneur, la durée et le débit ;
        • les pistes vidéo : codec, profil, définition, cadence exacte (24000/1001), profondeur, couleurs, HDR (hdr10, hlg, dolby_vision avec profil) ;
        • les pistes audio : canaux, disposition, fréquence ;
        • les sous-titres : texte ou image, forcés, pour malentendants ;
        • la langue et le titre des pistes, les chapitres.

      Ce qui n'est pas trouvé reste vide, jamais deviné. Une pochette intégrée n'est pas comptée comme piste vidéo.

      • Adaptateur ffprobe confiné : le fichier est transmis comme descripteur, ffprobe ne voit aucun chemin et ne peut rien ouvrir d'autre. Délai et sorties bornés.
      • Job media.analyze par source, mis en file après chaque scan terminé :
        • les résultats vont dans media_analyses, media_streams et media_chapters (migration 00007) ;
        • un fichier illisible est marqué unreadable et n'est plus retenté tant qu'il ne change pas ;
        • un résultat est ignoré si le fichier a changé pendant l'analyse ;
        • une nouvelle version du normaliseur relance l'analyse.
      • PROTOFLIX_FFPROBE_PATH (par défaut le ffprobe à côté de ffmpeg, sinon celui du PATH). Sans ffprobe, les fichiers sont indexés sans analyse.
      • Image de test deploy/docker/test.Dockerfile (Go 1.27 et FFmpeg 7.1.5 épinglé). Elle sert à check.sh --full pour des tests sur un corpus généré : h264/aac, HEVC 10 bits HDR10 et HLG, MKV multipiste avec sous-titres forcés et chapitres, fichiers corrompu et tronqué, lien hors source. Le profil Dolby Vision est vérifié sur une sortie ffprobe écrite à la main (pas d'encodeur libre).
      • Vérifié en conditions réelles dans le conteneur : la création d'une bibliothèque lance le scan puis l'analyse. Deux fichiers sont analysés en 191 ms ; le fichier corrompu est marqué illisible.
    12. Ajouté

      Lot 2b, scanner

      • Scanner des sources (internal/scanner) :
        • parcours confiné ; seuls les fichiers vidéo et audio sont indexés ;
        • ignorés : fichiers temporaires (.part, .!qB, .crdownload…), fichiers cachés, dossiers techniques des NAS (@eaDir, #recycle, $RECYCLE.BIN…).
      • Fichiers en cours de copie mis en attente (« settling »), puis repris par un scan de suivi.
      • Renommages et déplacements reconnus par taille et empreinte rapide : le fichier garde son identité. Les copies identiques ne sont jamais devinées.
      • Un fichier absent passe en « missing » et n'est supprimé qu'après deux scans complets et 72 h d'absence. Une source hors ligne n'est jamais scannée. Une racine soudain vide ou une disparition massive interrompt le scan sans rien modifier, sauf scan forcé.
      • Jobs library.scan (automatique à la création d'une bibliothèque et à l'ajout d'un dossier) et library.scan_all (réconciliation complète quotidienne) ; POST /api/v1/libraries/{id}/scan avec kind et force.
      • Compteurs réels de fichiers et d'octets dans la vue admin des bibliothèques. Historique des exécutions dans scan_runs.
    13. Ajouté

      Lot 2a, bibliothèques

      • internal/storage : accès en lecture seule confiné à la racine de chaque source par os.Root. Les chemins .., les chemins absolus et les liens symboliques sortants sont refusés. Les racines sont validées : chemin absolu, hors zones système, sans chevauchement avec DATA_DIR ni avec une autre source.
      • Bibliothèques partagées (films, séries, musique, vidéos personnelles) et leurs sources. API /api/v1/libraries : liste, détail, création, renommage, suppression confirmée (X-Confirm-Delete), ajout et retrait de dossiers, test d'un dossier. Un compte ne voit que les bibliothèques de sa politique, sans aucun chemin.
      • Sonde des sources toutes les 2 minutes (job library.probe_sources) : online, unavailable, permission_denied ou io_error, avec horodatage, détail et type de système de fichiers. Une source qui tombe ne fait rien supprimer (vérifié en conditions réelles).
      • Droits par bibliothèque désormais enregistrés (policy_libraries) et validés.
      • internal/platform/fsinfo : détection du système de fichiers, partagée par la base et les bibliothèques.
    14. Ajouté

      Lot 1f, contrôles

      • server/scripts/check.sh : gofmt, go vet, staticcheck v0.8.2, tests, govulncheck v1.9.0 ; avec --full, en plus, tests -race, détection d'écart sqlc et validation du contrat OpenAPI.
      • Test d'architecture (internal/archtest) : les règles de domains.md vérifiées sur le graphe d'imports réel.
      • Test de couverture du contrat : toute route servie doit figurer dans api/openapi.yaml.
      • Workflow GitHub Actions (.github/workflows/server.yml), écrit mais pas encore exécuté (pas de dépôt distant).
    15. Sécurité
      • Chaîne d'outils Go épinglée en go1.27.3 : govulncheck signalait 13 vulnérabilités de la bibliothèque standard (net/http, HTTP/2, crypto/tls, crypto/x509, html/template, mime/multipart) dans go1.27.0, dont certaines atteignables par le serveur.
      • golang.org/x/net v0.62.0. Reste une vulnérabilité signalée dans golang.org/x/crypto v0.58.0, non atteignable par notre code, corrigée seulement dans une version non publiée : à mettre à jour à la prochaine version.
    16. Ajouté

      Lot 1e, jobs

      • File de jobs durable (ADR 0006, accepté) : mise en file idempotente, priorités, acquisition atomique, leases avec heartbeat, nouveaux essais avec backoff et jitter, failed / dead_letter, annulation (y compris en cours d'exécution), libération propre à l'arrêt, récupération des leases expirés, purge.
      • Runner de workers via l'interface jobs.Source (ADR 0020) : concurrence par type, timeouts, progression, paniques rattrapées.
      • Maintenance récurrente maintenance.purge_jobs (quotidienne).
      • API /api/v1/jobs (liste paginée, détail, tentatives, relance, annulation) : l'admin voit tout, un compte seulement ses propres jobs.
      • Flux SSE /api/v1/events filtré par compte, avec reprise par Last-Event-ID, resync et durée limitée à 15 min.
      • Mesures : 1 625 jobs/s ; kill -9 d'un worker sans perte de job (testé avec un vrai processus).
      • Retry-After optionnel pour les erreurs de domaine des autres paquets.
    17. Ajouté

      Lot 1d, identité

      • Comptes individuels (ADR 0009) : création du premier administrateur depuis le réseau local, invitations à usage unique (7 jours), rôles admin/adulte/enfant, droits par compte (limite d'âge, accès distant et qualité maximale à distance, code rapide, quota privé, téléchargements).
      • Appareils et comptes mémorisés : une session par compte et appareil, verrouillage des autres comptes sur un appareil partagé, déverrouillage par mot de passe ou code rapide à 4 chiffres. Le code rapide est lié à l'appareil, supprimé après 5 échecs et refusé à distance par défaut.
      • Jetons de session opaques avec rotation à chaque connexion ou déverrouillage ; seule leur empreinte SHA-256 est stockée. Mode cookie pour les navigateurs (préfixe __Host- en HTTPS) et mode token pour les clients natifs.
      • Protection CSRF (origine autorisée et double soumission), limitation des tentatives en mémoire avec Retry-After, Argon2id aux paramètres OWASP avec au plus 4 hachages simultanés.
      • Journal d'audit des actions d'administration.
      • Endpoints : /api/v1/setup, /auth/login, /auth/logout, /devices/current/accounts…, /me (profil, mot de passe, code rapide, appareils), /accounts (admin), /invitations (admin) et /invitations/by-code/{code} (public).
      • Configuration : PROTOFLIX_LOCAL_NETWORKS, PROTOFLIX_ALLOWED_ORIGINS.
      • Erreurs de domaine génériques (httpapi.CodedError) pour les futurs paquets.
    18. Modifié

      Contrat

      • Invitations publiques sous /api/v1/invitations/by-code/{code} ; révocation par identifiant inv_…. Ajout de session_mode, de PUT /me/password et de nouveaux codes d'erreur (invalid_credentials, session_locked, setup_done, email_taken, device_unknown, csrf_rejected).
    19. Décidé
      • ADR 0017 accepté : BitTorrent et débridage inclus. Les torrents (torrents_enabled, activé par défaut une fois le module ouvert), le partage (seeding_enabled, désactivé par défaut, avec limites de ratio et de durée) et le port entrant (incoming_port_enabled, désactivé par défaut) sont des réglages d'administration. Nouveau code d'erreur torrents_disabled.
    20. Ajouté

      Lot 1c, observabilité

      • OpenTelemetry v1.47.0 : métriques au format Prometheus et traces exportables en OTLP/HTTP (PROTOFLIX_OTLP_ENDPOINT, désactivé par défaut ; sans destination, aucun span n'est enregistré).
      • Écoute d'administration PROTOFLIX_ADMIN_ADDR (désactivée par défaut) : /metrics et /debug/pprof/. Avertissement si elle n'est pas sur loopback.
      • Métriques : durée des requêtes HTTP par motif de route (labels bornés, testé), requêtes en cours, attente et durée de l'écrivain SQLite, issues des transactions, connexions par pool, protoflix_build_info, métriques Go et processus.
      • Span serveur par requête API, nommé par motif de route ; traceparent accepté seulement depuis un proxy de confiance.
      • Journaux : trace_id et span_id ajoutés automatiquement ; le journal d'accès écrit la route et non plus le chemin brut (les futurs jetons de lecture n'y apparaîtront pas) ; durée en duration_ms.
    21. Ajouté

      Lot 1b, persistance

      • Base SQLite embarquée (modernc.org/sqlite v1.61.1, SQLite 3.54.1) : WAL, un seul écrivain (BEGIN IMMEDIATE), un pool de lecture en query_only, tables STRICT.
      • Verrou d'instance DATA_DIR/protoflix.lock : un seul coordinateur par répertoire de données, libéré par le système même après un arrêt brutal.
      • Refus de démarrer si DATA_DIR est sur un système de fichiers réseau (Linux : NFS, SMB, CIFS, Ceph… ; Windows : lecteurs réseau et chemins UNC).
      • Migrations goose v3.29.0 embarquées. Première migration : server_instance, settings. Une base neuve est initialisée automatiquement ; une base existante n'est migrée que par protoflix migrate up ou avec PROTOFLIX_AUTO_MIGRATE=true, après une sauvegarde vérifiée. Une base plus récente que le binaire est refusée.
      • Commandes migrate up|status et backup create|verify|restore (la restauration conserve l'ancienne base).
      • /readyz vérifie la base.
      • Identifiants UUIDv7 et forme publique préfixée (ADR 0008).
      • Requêtes typées générées par sqlc 1.31.1 (server/scripts/sqlc.sh).
      • Banc pilote pur Go contre cgo (docs/testing/benchmarks/sqlite-drivers/).
    22. Modifié
      • Image Docker : PROTOFLIX_AUTO_MIGRATE=true ; le répertoire de données est créé dans l'image avec le propriétaire nonroot (sans cela, un volume nommé n'était pas inscriptible).
      • Le serveur vérifie au démarrage qu'il peut écrire dans DATA_DIR, avec un message explicite.
      • Contrat : route de débridage pour les téléchargements (route, état caching, compte Mega-Debrid côté admin, réglages globaux, pause/reprise de toute une file) et bandes-annonces (trailers dans le détail d'une œuvre). ADR 0017 complété : le connecteur de débridage est soumis à validation humaine.
      • Base de données : SQLite embarqué au lieu de PostgreSQL (ADR 0019, remplace 0004), pour une installation et des mises à jour sans base à administrer. ADR 0002, 0005, 0006, 0008, 0013 et 0015 révisés.
      • Architecture coordinateur + workers distants optionnels via une API interne (ADR 0020).
      • Contrat : has_quick_code, last_device_name, fiche technique par version, next_episode_id, POST /api/v1/playback/plan-preview.
    23. Ajouté
      • Dossier d'architecture (phase 0) : vue d'ensemble, domaines, modèle de données, flux, feuille de route, risques (docs/architecture/).
      • ADR 0001 à 0018 (docs/adr/), dont le modèle de comptes individuels (0009), le module Téléchargements (0017, validation humaine requise) et la bibliothèque privée (0018).
      • Contrat OpenAPI 3.1 préliminaire (api/openapi.yaml) et conventions d'API (docs/api/).
      • Documentation média, sécurité, exploitation et tests (docs/media/, docs/security/, docs/operations/, docs/testing/).
      • Squelette du serveur Go (server/) : sous-commandes serve, migrate (non implémentée), config check et version ; configuration PROTOFLIX_* validée ; logs JSON ; erreurs problem+json ; /livez, /readyz, /api/v1/server/info ; arrêt gracieux.
      • Déploiement : unité systemd durcie et Dockerfile distroless avec compose.yaml (deploy/), non testés en conditions réelles.
    1. Vérifié

      Lot 3a

      Dans le conteneur, avec un vrai fichier MP4 H.264/AAC :

      • fichier servi identique octet pour octet ;
      • 206 Partial Content avec Content-Range ;
      • ffprobe lit le film par l'URL de lecture (20 s) ;
      • jeton falsifié refusé (403) ;
      • reprise enregistrée à 7 s ;
      • URL refusée après l'arrêt (409) ;
      • jeton absent des journaux ;
      • un MKV est refusé avec la raison container_unsupported.