koopa-admin-log/scripts/castopod/apply-branding.sh

137 lines
5.7 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Apply hacktivism branding to Castopod (official settings + optional CSS overlay).
#
# Official docs (instance settings — site name/description/icon + 6 accent themes):
# https://docs.castopod.org/main/en/user-guide/instance/settings/
# Docker/compose background:
# https://docs.castopod.org/main/en/getting-started/docker/
#
# Logo: same magician mark as git.hacktivism.ch / bonfire.hacktivism.ch
# (configs/castopod/assets/img/logo.png — ≥512×512 required by Castopod).
# Official accent closest to gold: "amber" (among pine/crimson/lake/amber/jacaranda/onyx).
# Optional warm-dark CSS: NOT official — see configs/castopod/assets/css/theme-hacktivism-overlay.css
set -euo pipefail
ROOT="${KOOPA_CASTOPOD_ROOT:-$HOME/koopa-castopod}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." 2>/dev/null && pwd || true)"
# shellcheck source=lib.sh
source "${SCRIPT_DIR}/lib.sh"
: "${CP_BASEURL:=https://castopod.hacktivism.ch}"
: "${CP_ADMIN_GATEWAY:=cp-admin}"
: "${CP_SITE_NAME:=hacktivism castopod}"
: "${CP_SITE_DESCRIPTION:=Castopod on hacktivism.ch — FOSS Airwaves and free-culture podcasting.}"
: "${CP_THEME:=amber}"
: "${CP_APPLY_OVERLAY:=1}"
BRANDING_DST="${ROOT}/branding"
ICON_SRC=""
CSS_SRC=""
if [[ -d "${REPO_ROOT}/configs/castopod/assets/img" ]]; then
ICON_SRC="${REPO_ROOT}/configs/castopod/assets/img/logo.png"
CSS_SRC="${REPO_ROOT}/configs/castopod/assets/css/theme-hacktivism-overlay.css"
elif [[ -f "${ROOT}/branding/logo.png" ]]; then
ICON_SRC="${ROOT}/branding/logo.png"
CSS_SRC="${ROOT}/branding/theme-hacktivism-overlay.css"
else
echo "missing logo.png (run from koopa-admin-log checkout or copy assets to ${ROOT}/branding/)" >&2
exit 1
fi
install -d -m 755 "${BRANDING_DST}"
if [[ "$(realpath "${ICON_SRC}" 2>/dev/null || echo "${ICON_SRC}")" != "$(realpath "${BRANDING_DST}/logo.png" 2>/dev/null || echo "${BRANDING_DST}/logo.png")" ]]; then
install -m 644 "${ICON_SRC}" "${BRANDING_DST}/logo.png"
fi
if [[ -n "${CSS_SRC}" && -f "${CSS_SRC}" ]]; then
if [[ "$(realpath "${CSS_SRC}" 2>/dev/null || echo "${CSS_SRC}")" != "$(realpath "${BRANDING_DST}/theme-hacktivism-overlay.css" 2>/dev/null || true)" ]]; then
install -m 644 "${CSS_SRC}" "${BRANDING_DST}/theme-hacktivism-overlay.css"
fi
fi
# Mount overlay into public assets if compose branding volume is present
if [[ -d "${ROOT}/branding" ]]; then
# Ensure host path for compose bind exists before recreate
true
fi
COOKIE=$(mktemp /tmp/cp-brand-cj.XXXXXX)
trap 'rm -f "$COOKIE"' EXIT
echo "== admin login =="
cp_admin_login "$COOKIE"
csrf_from() {
local url=$1
local html
html=$(cp_curl -c "$COOKIE" -b "$COOKIE" "$url")
# multiple possible CSRF field names
printf '%s' "$html" | sed -n 's/.*name="csrf_test_name" value="\([^"]*\)".*/\1/p' | head -1
}
echo "== official: general settings (site name/description/icon) =="
# UI/docs: https://docs.castopod.org/main/en/user-guide/instance/settings/
# POST route: /{admin}/settings/instance (SettingsController::attemptInstanceEdit)
GEN_GET="${CP_BASEURL}/${CP_ADMIN_GATEWAY}/settings"
GEN_POST="${CP_BASEURL}/${CP_ADMIN_GATEWAY}/settings/instance"
csrf=$(csrf_from "$GEN_GET")
[[ -n "$csrf" ]] || { echo "ERROR: no CSRF on settings general" >&2; exit 1; }
code=$(cp_curl -c "$COOKIE" -b "$COOKIE" -o /tmp/cp-gen.out -w '%{http_code}' \
-X POST "${GEN_POST}" \
-F "csrf_test_name=${csrf}" \
-F "site_name=${CP_SITE_NAME}" \
-F "site_description=${CP_SITE_DESCRIPTION}" \
-F "site_icon=@${BRANDING_DST}/logo.png;type=image/png")
echo "general POST → HTTP $code"
# accept redirect
if [[ "$code" != "303" && "$code" != "302" && "$code" != "200" ]]; then
echo "WARN: unexpected status; body:" >&2
head -c 400 /tmp/cp-gen.out >&2 || true
fi
echo "== official: theme accent (${CP_THEME}) =="
THEME_URL="${CP_BASEURL}/${CP_ADMIN_GATEWAY}/settings/theme"
csrf=$(csrf_from "$THEME_URL")
[[ -n "$csrf" ]] || { echo "ERROR: no CSRF on settings theme" >&2; exit 1; }
code=$(cp_curl -c "$COOKIE" -b "$COOKIE" -o /tmp/cp-theme.out -w '%{http_code}' \
-X POST "${THEME_URL}" \
--data-urlencode "csrf_test_name=${csrf}" \
--data-urlencode "theme=${CP_THEME}")
echo "theme POST → HTTP $code"
if [[ "${CP_APPLY_OVERLAY}" == "1" && -f "${BRANDING_DST}/theme-hacktivism-overlay.css" ]]; then
echo "== optional: warm-dark CSS overlay (not official) =="
# Serve from container public path via bind (compose) or copy into media volume
podman cp "${BRANDING_DST}/theme-hacktivism-overlay.css" \
koopa-castopod:/app/public/assets/hacktivism-overlay.css 2>/dev/null || true
# Idempotent inject before </head> in public layouts (re-run after image upgrade)
# Themes are root-owned in the image — patch as root (re-run after image upgrade).
# shellcheck disable=SC2016
podman exec -u 0 koopa-castopod sh -c '
LINK="<!-- hacktivism-overlay --><link rel=\"stylesheet\" href=\"/assets/hacktivism-overlay.css\">"
for f in /app/themes/cp_app/home.php \
/app/themes/cp_app/podcast/_layout.php \
/app/themes/cp_app/episode/_layout.php \
/app/themes/cp_app/pages/_layout.php \
/app/themes/cp_app/embed.php; do
[ -f "$f" ] || continue
if grep -q "hacktivism-overlay" "$f"; then
echo "already: $f"
continue
fi
awk -v link="$LINK" "{ if (\$0 ~ /<\\/head>/ && !done) { print link; done=1 } print }" "$f" > "$f.tmp" \
&& mv "$f.tmp" "$f" \
&& echo "patched: $f"
done
' || echo "WARN: layout patch skipped (container missing?)"
fi
# Clear page cache so theme/name show up
podman exec koopa-castopod sh -c 'rm -rf /app/writable/cache/* 2>/dev/null || true' || true
echo "Done. Hard-reload https://castopod.hacktivism.ch/"
echo "Official UI also: ${CP_BASEURL}/${CP_ADMIN_GATEWAY}/settings (and /settings/theme)"