5.2 KiB
5.2 KiB
#109 — Support audio & vidéo (lecteurs HTML5 intégrés)
Version livrée : 2.18.0 · Statut : ✅ · Impact : 🟡 Zone : backend (
main,indexer,media_types,bookslm) + frontend (viewer.js,utils.js,style.css,sw.js).
Contexte
Le socle média de #108 (backend/media_types.py) exposait déjà
AUDIO_EXTENSIONS / VIDEO_EXTENSIONS, mais ces fichiers n'étaient ni indexés
ni affichables : ils tombaient dans le chemin binaire « Ce fichier est binaire
et ne peut pas être affiché » + bouton download.
Ce qui a été livré
A. Backend
- Indexation :
AUDIO_EXTENSIONSetVIDEO_EXTENSIONSsont intégrées àSUPPORTED_EXTENSIONS(indexer.py). La brancheis_media(ext)existante indexe nom / taille / mtime sans jamais lire les octets (content: ""), donc le TF-IDF et les logs restent propres. Le watcher et le filtreext:suivent automatiquement. - Streaming : le helper Range de
pdf/streama été extrait en_stream_file_with_range(file_path, request, media_type)(206 +Content-Range+Accept-Ranges,416sur plage invalide,FileResponsesimple sinon, lectures offloadées viaasyncio.to_thread).pdf/streaml'utilise désormais aussi (comportement inchangé, tests de régression). - Nouvel endpoint
GET /api/media/{vault}?path=…: sert audio/vidéo avec le MIMEmedia_types.media_mime_type(surcharges.m4a→audio/mp4,.opus/.oga→audio/ogg,.mov→video/quicktime,.m4v→video/mp4). - Gardes-fous :
_resolve_safe_path,check_vault_access, etOBSIGATE_MEDIA_MAX_INLINE_MB(défaut 500 Mo) — au-delà, l'endpoint renvoie413et la vue fichier bascule sur l'UI de téléchargement. api_file_view()renvoie, avant toutread_text(),is_audio/is_video/stream_url/media_mime/size_bytes. Au-delà de la limite :unsupported: true+media_too_large: true.
B/C. Frontend — lecteurs
viewer.jsdispatchedata.is_audio→renderAudioViewer()etdata.is_video→renderVideoViewer().- Audio :
<audio controls preload="metadata">pleine largeur, artwork placeholder (icône Lucideaudio-lines), durée lue vialoadedmetadata, toolbar (titre, voûte + taille, badge durée, ouvrir l'original, télécharger). - Vidéo :
<video controls playsinline preload="metadata">centrée sur une scène noire letterboxée (max-height: calc(100vh - 180px)), même toolbar avec durée + résolution.
- Audio :
renderMediaFallback(): sur l'événementerrorde l'élément média (codec hors web-natif :.mkv,.avi, HEVC…) ou si le fichier est trop volumineux, remplace le lecteur par l'UI binaire + messageviewer.media_unsupported/viewer.media_too_large+ Télécharger / Ouvrir dans un nouvel onglet.- Pause au changement de vue :
_mediaViewerCleanupmet en pause et détache la source quandrenderFile()re-rend la zone (changement d'onglet, navigation) — pas de lecture persistante en v1 (cohérence #75). EXT_ICONS(utils.js) : audio →audio-lines, vidéo →video.- i18n FR/EN (
viewer.media_unsupported,viewer.media_too_large).
D. Recherche & intégrations
- Filtres
ext:mp3,ext:mp4, etc. opérationnels (les médias entrent dans l'index). - Récents / dashboards : previews vides (aucun texte extrait) — comportement naturel de la branche binaire.
- BooksLM :
_file_entry()ignore désormais tout média (is_media) — les octets ne sont jamais envoyés au modèle ; les images restent gérées à part viaload_vault_image_data_url(vision). - Hors scope v1 (porte notée) : transcription audio via Whisper.
E. Mobile & PWA
- Le service worker ne met jamais en cache le flux média
(
/api/media/{vault}), tout en conservant le cache des miniatures (/api/media/{vault}/thumb) et la stratégie Network First pour le reste. Les requêtesRangeétaient déjà exclues.
F. Tests
tests/test_media_stream.py: 206 +Content-Range+ 1024 octets,416hors borne,200+Accept-Rangessans Range, suffix range,413au-delà de la limite,403path traversal,403vault sans accès,400non-média, MIME.mov, régressionpdf/stream.tests/test_media_indexing.py:.mp3/.mp4/.flacdans l'arborescence et l'index,content == "", watcher pertinent, filtreext:mp3.tests/frontend/media-viewer.test.mjs: helpers purs (formatMediaDuration,buildMediaUrl) + vérifications statiques (dispatch,<audio>/<video>, fallback, CSS, icônes, i18n, service worker, endpoints backend).tests/e2e/media-viewer.spec.js: lecture<audio>et<video>via/api/media+ réponse206sur requêteRange. Fixtures :test_vault/sample-audio.mp3(sine 1 s) ettest_vault/sample-video.webm(VP8 64×64).
Limitations connues
- Formats hors web-natifs (
.mkv,.avi, HEVC, AC-4) : non lisibles sans transcodage (ffmpeg hors scope) → repli téléchargement / lecteur de l'OS. - HLS, sous-titres
<track src=".vtt">et vignettes vidéo : hors scope v1. - Gros médias (> 500 Mo par défaut) : pas de lecture intégrée (protège le worker
uvicorn unique) ; ajustable via
OBSIGATE_MEDIA_MAX_INLINE_MB.