This commit is contained in:
parent
593bdb17d4
commit
faf881fa0c
10 changed files with 201 additions and 8 deletions
|
|
@ -113,7 +113,8 @@ cat > "$WORK/Caddyfile" <<EOF
|
|||
Cross-Origin-Resource-Policy "same-origin"
|
||||
}
|
||||
|
||||
@static path /catcrafts*.wasm /runtime.js /dom-env.js /dom-webgpu.js /catcrafts-head.js /files.json /variants.json /styles.css /favicon.svg /robots.txt /*.wgsl /*.jpg /posts.json /rates.json
|
||||
rewrite /apple-touch-icon-precomposed.png /apple-touch-icon.png
|
||||
@static path /catcrafts*.wasm /runtime.js /dom-env.js /dom-webgpu.js /catcrafts-head.js /files.json /variants.json /styles.css /favicon.svg /favicon.ico /apple-touch-icon.png /robots.txt /*.wgsl /*.jpg /posts.json /rates.json
|
||||
handle @static {
|
||||
header Cache-Control "no-store"
|
||||
file_server
|
||||
|
|
|
|||
80
tools/make-icons.sh
Executable file
80
tools/make-icons.sh
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
#!/bin/sh
|
||||
# Rasterise favicon.svg into the icon files clients ask for by path.
|
||||
#
|
||||
# favicon.svg alone is not enough. Two families of request arrive at the web
|
||||
# root for icons no markup ever points at, and both were the top entries in the
|
||||
# 404 report before these files existed:
|
||||
#
|
||||
# /favicon.ico
|
||||
# The unconditional root-path fallback. A client that cannot use an SVG
|
||||
# favicon — Safari, historically — ignores the declared <link rel="icon">
|
||||
# and asks for this instead, and every non-browser client that never runs
|
||||
# JS (feed readers, the Slack/Discord/WhatsApp/Telegram unfurlers, crawlers)
|
||||
# does the same on the static shell where the head is injected by
|
||||
# catcrafts-head.js rather than served. Nothing declares this file; the
|
||||
# fix is purely that the path resolves.
|
||||
#
|
||||
# /apple-touch-icon.png, /apple-touch-icon-precomposed.png
|
||||
# What iOS/iPadOS and macOS Safari probe at the root when a page declares
|
||||
# no <link rel="apple-touch-icon"> — the Add to Home Screen, Favorites and
|
||||
# Start Page tile. The pages DO declare one now (RenderDocument and
|
||||
# catcrafts-head.js), so the plain path is the one actually in use, and
|
||||
# -precomposed is only reached by clients predating that link being
|
||||
# honoured. ("Precomposed" meant "gloss and rounded corners are already
|
||||
# baked in", from when iOS <7 applied a glossy overlay to the plain one.)
|
||||
#
|
||||
# So only ONE file is produced here: -precomposed is a Caddy rewrite onto
|
||||
# apple-touch-icon.png (deploy/Caddyfile.example). A byte-identical second
|
||||
# copy would be a duplicate to keep in sync in git AND a second entry in
|
||||
# the wasm bundle's VFS — one more file fetched at every boot that nothing
|
||||
# ever reads. The size-suffixed names (apple-touch-icon-180x180.png and
|
||||
# friends) are not produced at all: they have never appeared in the logs,
|
||||
# so shipping them would answer a question nobody asked.
|
||||
#
|
||||
# Checked in rather than built, unlike sitemap.xml and feed.xml. Those drift
|
||||
# with every post; these drift only when favicon.svg is deliberately redrawn,
|
||||
# and generating them in CI would mean installing librsvg and ImageMagick into
|
||||
# the deploy container to produce identical bytes on every push.
|
||||
#
|
||||
# SO: re-run this after ANY edit to favicon.svg, and commit the results.
|
||||
#
|
||||
# Third copy of the same geometry to keep in sync — favicon.svg is the source,
|
||||
# RenderNav in shared/interfaces/Catcrafts.Shared-Views.cppm inlines it as
|
||||
# paths with CSS-variable colours, and these rasters fall out of the SVG here.
|
||||
|
||||
set -eu
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
SRC="favicon.svg"
|
||||
# The <rect> fill from favicon.svg. Only used to flatten the Apple icon: iOS
|
||||
# composites alpha against black and applies its own squircle mask, so the
|
||||
# artwork must reach the edges fully opaque instead of carrying the SVG's own
|
||||
# rounded corners.
|
||||
BG="#0b0d10"
|
||||
|
||||
for cmd in rsvg-convert magick; do
|
||||
command -v "$cmd" >/dev/null 2>&1 || {
|
||||
echo "make-icons: $cmd not found (pacman -S librsvg imagemagick)" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
# favicon.ico: multi-resolution, transparency kept. The rounded corners read
|
||||
# correctly against both a light and a dark tab bar, and 48px is what Windows
|
||||
# shortcut and some bookmark surfaces pick.
|
||||
for px in 16 32 48; do
|
||||
rsvg-convert -w "$px" -h "$px" "$SRC" -o "$TMP/ico-$px.png"
|
||||
done
|
||||
magick "$TMP/ico-16.png" "$TMP/ico-32.png" "$TMP/ico-48.png" favicon.ico
|
||||
|
||||
# apple-touch-icon.png: 180x180 is the largest size iOS asks for, and it
|
||||
# downsamples the rest itself. Opaque, per the note on BG above.
|
||||
rsvg-convert -w 180 -h 180 "$SRC" -o "$TMP/touch.png"
|
||||
magick "$TMP/touch.png" -background "$BG" -alpha remove -alpha off \
|
||||
-strip apple-touch-icon.png
|
||||
|
||||
echo "make-icons: wrote favicon.ico apple-touch-icon.png"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
# Publish a recording or screenshot to catcrafts.net and print the URL to put in
|
||||
# the fediverse post.
|
||||
# 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] <file>...
|
||||
#
|
||||
|
|
@ -40,6 +40,24 @@
|
|||
# with no <source> 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 <source> 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 <audio> element yet: fetch-media.sh does not match
|
||||
# these names and the post renderer has no audio case. So the printed URL is for
|
||||
# posting and for linking by hand, not yet for embedding in a post body.
|
||||
|
||||
set -eu
|
||||
|
||||
|
|
@ -116,10 +134,12 @@ for src in $FILES; do
|
|||
case "$ext" in
|
||||
mp4|webm|mov|mkv|avi) kind=video ;;
|
||||
png|jpg|jpeg|webp|gif|avif) kind=image ;;
|
||||
mp3|m4a|aac|opus|oga|ogg|flac|wav|wma|aiff) kind=audio ;;
|
||||
esac
|
||||
|
||||
poster=""
|
||||
fallback=""
|
||||
fallback_suffix=""
|
||||
if [ "$RAW" = 1 ] || [ "$kind" = other ]; then
|
||||
payload="$src"
|
||||
out_ext="$ext"
|
||||
|
|
@ -137,6 +157,7 @@ for src in $FILES; do
|
|||
# the players most likely to be shaky about AV1 anyway, and the audio is
|
||||
# a rounding error next to the video either way.
|
||||
fallback="$WORK/h264.mp4"
|
||||
fallback_suffix=h264.mp4
|
||||
echo " transcoding H.264 fallback (crf 23)…"
|
||||
# Same source and same denoise as the AV1, so the two encodings show the
|
||||
# same frames. CRF is x264's own scale (not comparable to SVT-AV1's);
|
||||
|
|
@ -156,6 +177,42 @@ for src in $FILES; do
|
|||
at=$(awk -v d="$dur" 'BEGIN { printf "%.2f", (d > 3 ? d / 3 : 0) }')
|
||||
ffmpeg -nostdin -v error -ss "$at" -i "$payload" -frames:v 1 \
|
||||
-vf "scale=720:-2" -c:v libwebp -quality 80 "$poster" -y
|
||||
elif [ "$kind" = audio ]; then
|
||||
payload="$WORK/out.webm"
|
||||
out_ext=webm
|
||||
fallback_suffix=mp3
|
||||
# Channel count sets the bitrate instead of being flattened by it: 48k of
|
||||
# mono Opus is comfortable for speech, and stereo music at that figure
|
||||
# would not be. These are VBR targets, not ceilings, and libopus does not
|
||||
# track them evenly — on the first file through here the 48k target came
|
||||
# out at 45 kbps while 64k ran away to 76, which is why the mono rail sits
|
||||
# at the lower figure rather than splitting the difference.
|
||||
ch=$(ffprobe -v error -select_streams a:0 -show_entries stream=channels \
|
||||
-of default=nw=1:nk=1 "$src" </dev/null 2>/dev/null \
|
||||
| head -n1 || true)
|
||||
case "$ch" in ''|*[!0-9]*) ch=1 ;; esac
|
||||
if [ "$ch" -gt 1 ]; then ab=96k; else ab=48k; fi
|
||||
echo " transcoding to Opus ($ab, ${ch}ch)…"
|
||||
# -vn drops cover art, which arrives as a still video stream and belongs
|
||||
# in neither output — without it an MP3 carrying album art fails the
|
||||
# encode outright. -map_metadata -1 drops the ID3 tags, which on a file
|
||||
# from someone else carry their tooling and their file naming. 48 kHz is
|
||||
# the rate Opus works at internally, so saying it makes the resample of
|
||||
# the usual 44.1 kHz source explicit rather than implied.
|
||||
ffmpeg -nostdin -v error -i "$src" -vn -map_metadata -1 \
|
||||
-c:a libopus -b:a "$ab" -ar 48000 \
|
||||
"$payload" -y
|
||||
fallback="$WORK/fallback.mp3"
|
||||
if [ "$ext" = mp3 ]; then
|
||||
echo " MP3 fallback: source is already MP3, copied unchanged"
|
||||
cp "$src" "$fallback"
|
||||
else
|
||||
echo " transcoding MP3 fallback (128k)…"
|
||||
# Fixed 128k, decodable by anything, and the same "bigger is
|
||||
# acceptable on the compatibility rail" trade the H.264 above makes.
|
||||
ffmpeg -nostdin -v error -i "$src" -vn -map_metadata -1 \
|
||||
-c:a libmp3lame -b:a 128k "$fallback" -y
|
||||
fi
|
||||
else
|
||||
payload="$WORK/out.webp"
|
||||
out_ext=webp
|
||||
|
|
@ -171,17 +228,19 @@ for src in $FILES; do
|
|||
# their own. That is the whole point: fetch-media.sh finds both by name,
|
||||
# with nothing to look up — the poster when the instance made no thumbnail
|
||||
# (pict-rs will not read AV1, so for these uploads that is the normal
|
||||
# case), the fallback for every browser that cannot decode AV1.
|
||||
# case), the fallback for every browser that cannot decode AV1. Audio's MP3
|
||||
# sibling is named the same way, after the Opus file's hash.
|
||||
if [ -n "$poster" ] && [ -f "$poster" ]; then
|
||||
publish_file "$poster" "$hash.poster.webp"
|
||||
fi
|
||||
post_name="$name"
|
||||
if [ -n "$fallback" ] && [ -f "$fallback" ]; then
|
||||
post_name="$hash.h264.mp4"
|
||||
post_name="$hash.$fallback_suffix"
|
||||
publish_file "$fallback" "$post_name"
|
||||
fi
|
||||
|
||||
# The postable URL is the H.264 one when it exists — see FALLBACK above.
|
||||
# The postable URL is the compatibility rail when there is one: the H.264
|
||||
# video or the MP3 audio — see FALLBACK and AUDIO above.
|
||||
url="$SITE_ORIGIN/media/$post_name"
|
||||
# Confirm it is actually being served before handing over a URL that is about
|
||||
# to be pasted into a post, where a 404 is public and permanent.
|
||||
|
|
|
|||
Loading…
Reference in a new issue