Files

6.8 KiB
Raw Permalink Blame History

Validation du lot #3

Protocole

bash tests/run.sh compile le plugin, installe le paquet dans un Jellyfin jetable et exécute la suite complète. Pour ne lancer que le parcours des sous-titres : bash tests/run.sh --test-name-pattern='external subtitles'. node --test tests/history.test.mjs vérifie séparément le navigateur à la frontière HTTP simulée ; ce test ne constitue pas une validation du serveur.

Serveur : Jellyfin 12.0.0, image et digest figés dans tests/run.sh. Lecteur témoin et compagnon : Chromium 149.0.7827.55, Playwright 1.61.1, Jellyfin Web livré avec cette image ; compagnon de 375 × 812 pixels. Hébergement : HTTP local, assets sans préfixe puis suite sous /jellyfin. Les autres clients, HTTPS et reverse proxy ne sont pas qualifiés par ce lot.

Le média est généré par FFmpeg : mire originale, audio synthétique et timecode PTS incrusté à 25 images/s. Deux fichiers SRT externes originaux sont conservés dans tests/fixtures/, avec deux débuts identiques, des intervalles sans bloc actif et du texte contenant des balises. Un second média n'a aucune piste.

Contrat et droits

La source est choisie par égalité avec PlayState.MediaSourceId parmi les sources de Items/{id}/PlaybackInfo. Les valeurs Index des flux sont conservées ; ce ne sont pas les positions dans la liste filtrée. Les libellés comportent cet indice, la langue ou le titre, le codec et les marqueurs forcés/malentendants disponibles.

Sur le serveur testé, le convertisseur Jellyfin renvoie TrackEvents, avec Text, StartPositionTicks et EndPositionTicks en ticks de 100 ns. Le premier bloc du fichier de référence est vérifié à 50 000 000–60 000 000 ticks, texte Block one. Le plugin utilise ce convertisseur existant, sans parseur propre.

L'endpoint natif Videos/{item}/{source}/Subtitles/{index}/Stream.json retourne HTTP 200 sans authentification sur ce serveur. Son contrôleur ne vérifie pas l'utilisateur avant conversion (source Jellyfin v12.0). Cette limite observée justifie la route interne du plugin, conformément à l'ADR d'hébergement et à la décision 2 de la spec.

Compagnon/Subtitles/{item}/{source}/{index} exige un utilisateur authentifié, vérifie la visibilité du média via Jellyfin et l'appartenance de la source et de l'indice de piste, puis appelle le convertisseur. Les tests vérifient 401 sans jeton, 403/404 pour Bob privé de l'accès à la bibliothèque et 404 pour une source ou un indice inconnu. Les droits sont contrôlés côté serveur, pas seulement par masquage dans l'interface. Le plugin ne corrige pas l'endpoint natif de Jellyfin.

Synchronisation

Le compagnon utilise PositionTicks tel que renvoyé par Jellyfin, sans ajouter le temps écoulé depuis LastPlaybackCheckIn. La position reste explicitement une estimation serveur ; l'âge de la dernière remontée du lecteur est distinct. Les pauses conservent l'historique ; les déplacements le reconstruisent à la nouvelle estimation. Une panne efface les données et invalide les réponses tardives.

Le test capture six images vidéo réellement décodées après douze secondes de lecture à 1×. requestVideoFrameCallback().mediaTime identifie leur PTS ; les PNG permettent de contrôler les chiffres incrustés. Il relève ensuite la position affichée dans le compagnon, indépendamment de l'API des sessions. La capture et la lecture du DOM sont séquentielles ; leur petite latence fait partie du relevé. Les fichiers bruts se trouvent dans .test-state/issue-3/ après exécution. Le délai de recalage est mesuré de la commande de déplacement du lecteur jusqu'à l'affichage de la fenêtre attendue, avec le délai d'observation de Playwright inclus.

Mesure finale du 14 septembre 2026, paquet 0.2.0 :

Timecode de l'image (s) Position compagnon (s) Écart absolu (ms)
62,000 60,773 1 227
62,680 61,773 907
63,360 62,773 587
64,040 63,773 267
64,720 63,773 947
65,400 64,773 627

Lecture stable : échec du seuil strict de 500 ms (5 relevés sur 6 le dépassent). Déplacement : réussite sur cet essai, recalage en 1 286 ms, inférieur à deux secondes. La précision en lecture stable de ce couple serveur/lecteur n'est donc pas validée. Aucun lissage supplémentaire ni précision supérieure aux informations reçues n'est revendiqué.

Les mesures brutes et une image témoin à 62 secondes sont conservées. Les timecodes visibles des première et dernière captures ont été relus : 01:02.000 et 01:05.400.

Résultats fonctionnels

Exécution finale : bash tests/run.sh, code de sortie 0 ; compilation Release avec 0 avertissement et 0 erreur, typechecking réussi, contrôle d'installation sans préfixe réussi, puis 6 tests réussis, 0 échec sous /jellyfin (52,5 s). L'archive et sa somme SHA-256 correspondent au DLL compilé. Le conteneur jetable a été supprimé par le runner.

Comportement Frontière vérifiée
Ouverture à 35 s : cinq blocs immédiatement après chargement Lecteur Web + plugin installé
Pause, déplacements avant/arrière, début exact à 20 s et juste avant Lecteur Web + plugin installé
Blocs simultanés, intervalle sans bloc actif, moins de cinq blocs Lecteur Web + plugin installé et navigateur/HTTP simulé
Choix indépendant, présélection disponible, indices de source Lecteur Web + plugin installé
Autre média sans piste : ancien historique effacé Lecteur Web + plugin installé
Refus anonyme, compte sans accès, source/indice incorrect HTTP réel
Réponse retardée, changement de source, sous-titres du lecteur désactivés Navigateur/HTTP simulé
Balises rendues comme texte, piste invalide, pistes graphiques signalées Navigateur/HTTP simulé ; rendu sûr aussi testé sur SRT réel
Perte réseau, contrôles désactivés et ancien historique effacé Navigateur/HTTP simulé et suivi réel

Les vérifications simulées permettent de contrôler des réponses tardives et des états précis ; elles ne qualifient pas une seconde source réelle ni une piste graphique réelle. Ces extensions et la mesure multi-clients restent aux lots suivants.

Revue

Standards : aucune violation documentée. La duplication de navigation du lecteur dans les tests a été corrigée avec un helper partagé ; les sélecteurs de statut sont désormais explicites après l'ajout du statut des pistes.

Spec : aucun écart substantiel relevé dans le code. Les seuils de synchronisation doivent être qualifiés séparément, comme demandé par le ticket ; réussir les assertions fonctionnelles ne suffit pas à déclarer ces seuils atteints.