#!/bin/sh # Publish a recording, screenshot or audio file to catcrafts.net and print the # URL to put in the fediverse post. # # usage: tools/publish-media.sh [-r] [-c CRF] ... # # -r, --raw upload the file unchanged (no transcode, no poster) # -c, --crf N AV1 quality, lower is better (default 32) # # WHY THIS EXISTS: the media used to be uploaded to a third-party file host and # then mirrored back at build time by tools/fetch-media.sh. That worked until a # 167 MB recording hit the mirror's size cap, and the deploy failed on a file we # had sitting on disk the whole time. Publishing to our own origin FIRST inverts # it — the URL in the post is already the URL the page wants, so there is nothing # to download, no size cap to clear, and no third party who can be slow, rate- # limit us, or delete the file that IS the post. # # The name is the content hash, matching what fetch-media.sh produces, which is # what makes Caddy's one-year immutable cache on /media honest: different bytes # can never appear under a name someone already has cached. # # TRANSCODE: phone recordings are enormous for what they show — the one that # started this was 78 s of a dark room at 17 Mbps, 167 MB, where denoising and # AV1 give the same picture in 15 MB. Dark handheld footage is mostly sensor # noise, which is expensive to encode and worth nothing, so hqdn3d earns its # place before the encoder rather than after it. # # ROTATION: phones record landscape and attach a display matrix instead of # rotating pixels. Transcoding bakes the rotation into the frames, so what every # downstream consumer measures is what the viewer actually sees — see the # rotation note in fetch-media.sh for what goes wrong when it does not. # # FALLBACK: AV1 alone locks out Safari before 17 and Apple hardware older than # A17/M3 — which surfaced the first time an AV1 link was posted and an iPhone # viewer got "bad media error" from the raw file. So every transcode also emits # an H.264 sibling, uploaded as .h264.mp4 next to the AV1 (same trick as # the poster: named after the AV1's hash so fetch-media.sh finds it with nothing # to look up). The URL this script prints for the post is the H.264 one, because # a post's link is fetched raw — Lemmy apps and browsers play that exact file, # with no negotiation in front of it — and it must be the encoding # everything can play. Our own pages recognise the .h264.mp4 name, serve the AV1 # to browsers that can take it, and keep the H.264 as the fallback. # # AUDIO: the same two rails, for the same reason. Opus in WebM is the efficient # one — the first file through here, 93 s of speech, went from a 1.5 MB 128k MP3 # to 553 KB — and an MP3 sibling is the one that plays everywhere, so the MP3 is # the URL printed for the post. The primary does not have to be universal # precisely because the sibling is. # # Two ways the audio path deliberately differs from the video path above. It does # not fold everything to mono: here the audio IS the content rather than a # rounding error next to a picture, so the source's channel layout survives and # sets the bitrate. And a source that is ALREADY an MP3 is copied to the # compatibility rail untouched rather than re-encoded — MP3 to MP3 spends a # second generation of lossy artefacts to arrive at the same rail, and speech, # which is most of what gets published here, is where that is most audible. # # Nothing downstream builds an