WCAG 4.1.2: add WebVTT caption support for <video> elements on tfe.php

Problem: <video> elements on tfe.php had no <track kind="captions"> element,
violating WCAG 4.1.2 (name, role, value) for video content.

Changes:
- public/tfe.php: collect all text/vtt files from the thesis file list before
  rendering; skip standalone rendering of .vtt entries; for each MP4 emit a
  <track kind="captions" srclang="fr" label="Sous-titres" default> pointing
  to the N-th VTT file (N-th video paired with N-th caption in document order)
- public/media.php: add text/vtt to allowed MIME list; normalise finfo
  text/plain -> text/vtt for .vtt files; add vtt branch to cache/header
  block (Content-Type: text/vtt; charset=utf-8, 1-day cache)
- public/admin/actions/formulaire.php: allow .vtt uploads (text/vtt MIME,
  vtt extension); normalise text/plain finfo result; set file_type='caption'
  for VTT files so they are distinguishable from other thesis files
- public/admin/add.php: extend files field accept attr to include .vtt;
  update hint text to document the VTT sidecar convention

VTT files uploaded under theses/ inherit the same access_type visibility
gate in media.php as all other thesis content (403 for access_type_id=3).
This commit is contained in:
Pontoporeia
2026-04-03 13:24:26 +02:00
parent 6e68edfbff
commit 94e9060dc7
6 changed files with 58 additions and 8 deletions

View File

@@ -78,8 +78,15 @@ $allowedMimes = [
'application/pdf',
'video/mp4',
'application/zip',
'text/vtt', // WebVTT caption sidecar files
];
// finfo may return 'text/plain' for WebVTT files on some systems;
// re-classify by extension so we don't block them.
if ($mimeType === 'text/plain' && strtolower(pathinfo($realFull, PATHINFO_EXTENSION)) === 'vtt') {
$mimeType = 'text/vtt';
}
if (!in_array($mimeType, $allowedMimes, true)) {
http_response_code(403);
exit;
@@ -100,6 +107,10 @@ if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'], true)) {
// PDFs: cache for 1 day, display inline
header('Cache-Control: public, max-age=86400');
header('Content-Disposition: inline');
} elseif ($ext === 'vtt') {
// WebVTT captions: serve as text/vtt, cache 1 day
header('Content-Type: text/vtt; charset=utf-8');
header('Cache-Control: public, max-age=86400');
} else {
// Everything else: no public caching
header('Cache-Control: private, no-store');