f072a3c69c
Once an event left `standard` protection, both halves of the video path were
routed through /api/secure-images, and neither half can carry a video.
galleryQueryService emitted the secure template as a video's `url`. The
lightbox drops that straight into a <video> element; nothing substitutes the
`{{token}}` placeholder (the helper that could, secureToken.service.ts, has no
importers), so the request answered 403 "Invalid or expired token". Even with a
valid token it would still have failed — the secure-images route pipes every
byte through secureImageService.processProtectedImage, which calls sharp() and
throws on an mp4. routes/gallery/media.js bounced the JWT route to that same
endpoint before reaching its own video branch, so there was no way through.
Videos now keep the JWT route at every protection level, on both sides. That is
not a new exposure: thumbnails of those same videos have always been served
from it, and a valid gallery token is still required to reach it. Still images
are unaffected and keep bouncing to the secure endpoint.
VideoPlayer had no `error` listener, so all of this rendered as a poster frozen
at "0:00 / 0:00" behind a play button that did nothing — indistinguishable from
a codec the browser cannot decode, which is the other common cause (HEVC/H.265
phone footage plays in Safari and nowhere else). It now surfaces the failure
and names the codec case, since the answer there is to download the file.
Relates to issue 1370