docs: the video's link is its Gitea page, not the raw URL, which its own CSP blocks

Checked the way a browser does it rather than the way curl does, and curl had given a false green:
Gitea sends `Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox` with
every /raw/ response. That is deliberate - it is what makes serving raw HTML and SVG safe - but it
also blocks the media load when a browser navigates straight to a video, so the tab stays blank with
no error. The same URL plays fine as a subresource, which is exactly why the file's page in Gitea
shows a player: that page embeds <video controls src=".../raw/branch/main/...mp4">.

So the declaration's link is the /src/ page URL, and /raw/ is documented as the curl-and-download
URL instead. Everything verified about both URLs is written down in step 5 - including the two ways
to get a player with no Gitea chrome around it, if that is ever wanted: an unlisted YouTube upload,
or dropping the header for this one path on the Gitea host's Caddy proxy, which must stay scoped to
store-assets/ precisely because that header is what protects raw HTML and SVG.

The file itself was never the problem: 200, video/mp4, Content-Disposition: inline, bytes
sha256-identical to the recording, and Range: bytes=0-99 -> 206 with the matching Content-Range.
This commit is contained in:
2026-10-14 13:28:49 +02:00
parent 31a0edbe61
commit 68dcbc5db6
4 changed files with 42 additions and 21 deletions
+28 -13
View File
@@ -283,23 +283,38 @@ action except the items marked **[code]**.
CANCEL"*, 13–18 s) while the scan kept running behind it, and the finished results
(*17 duplicate groups · 54 of 5,385 photos*) at the end.
**The link to paste** is the committed file's own URL — no login, no second host:
**The link to paste** is the file's page in Gitea — what the repository's own *view* of
the file opens, and what plays it:
```
https://gitea.softwareapp-hb.de/fishfacegit/foto-duplicate-finder/raw/branch/main/store-assets/fgs-demo/foreground-service-demo.mp4
https://gitea.softwareapp-hb.de/fishfacegit/foto-duplicate-finder/src/branch/main/store-assets/fgs-demo/foreground-service-demo.mp4
```
Checked from outside this network: **200**, `Content-Type: video/mp4`,
`Content-Length: 1847900` and `Content-Disposition: inline`, so a reviewer's browser plays
it in the tab rather than prompting a download, and the served bytes are identical to the
recording (sha256 match). A `Range: bytes=0-99` request answers **206** with exactly those
100 bytes even though `Accept-Ranges` is not advertised, so seeking works and a player can
start without fetching the whole file first — which matters here because `screenrecord`
writes the `moov` atom at the very end of the file. Two things to know before pasting: the
URL is pinned to `main`, so a re-shoot has to **overwrite the file in place** rather than
be added alongside it; and replacing the video at all means resubmitting the declaration.
(An unlisted YouTube upload of the same file works equally well if a link that survives
future commits is preferred — but then it is a second place to keep in step.)
⚠️ **Not the `/raw/` URL**, even though that is the file itself. Gitea answers raw
responses with `Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline';
sandbox` — a deliberate guard against raw HTML and SVG — and that blocks the media load of a
document that navigates straight to a video: the tab stays blank with no error, which is
exactly how this behaved in a browser. The same URL is fine as a *subresource*: the page
above embeds `<video controls src="…/raw/branch/main/…mp4">`, which is why previewing the
file plays it and opening `/raw/` does not. Use `/raw/` for `curl` and downloads, never as
the link in the form.
Verified about the **page** URL: **200** anonymously, containing that `<video controls>`
element. Verified about the **raw** URL, from outside this network and unauthenticated:
**200**, `Content-Type: video/mp4`, `Content-Length: 1847900`, `Content-Disposition:
inline`, bytes sha256-identical to the recording, and `Range: bytes=0-99` → **206** with
exactly those 100 bytes although `Accept-Ranges` is not advertised (which matters because
`screenrecord` writes the `moov` atom at the very end of the file). Two things to know
before pasting: the URL is pinned to `main`, so a re-shoot has to **overwrite the file in
place** rather than be added alongside it; and replacing the video at all means resubmitting
the declaration.
If a link with no Gitea chrome around the player is preferred later, there are two ways and
neither is needed for the declaration: an unlisted YouTube upload of the same file, or a
rule on the Gitea host's Caddy proxy dropping the header for this one path
(`@fgsdemo path …/store-assets/fgs-demo/*.mp4` plus `header_down @fgsdemo
-Content-Security-Policy`) — **scoped to `store-assets/` only**, since that header is what
makes raw HTML and SVG safe to serve. Neither was tried from here.
Both flags exist because this take found two traps worth knowing before a re-shoot: