v3: native bandcamp playback and a queue in the global player
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 43s

The player now holds a queue instead of a single item, so albums play
through and single tracks share the same code path. Adds a "stream" item
kind for expiring, remotely-hosted sources: Bandcamp signs its mp3 URLs
for ~24h, so an item carries the page it came from and re-resolves itself
on error or on a stale restored session, falling back to the iframe embed
if that fails too.

Gated behind GERBEUR_BANDCAMP_PLAYER (default "embed"), injected into a
meta tag the same way as site-name/site-emoji.

Also: player header gains artwork and a subtitle, volume persists across
queue advances and reloads, and cross-origin streams get a plain seek bar
rather than a waveform that can never decode.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbtjNsT5wvuABnfqhegZEJ
This commit is contained in:
khannurien
2026-08-22 12:14:28 +00:00
parent eb323a8ba8
commit 2606ef4ccc
30 changed files with 1531 additions and 225 deletions

View File

@@ -98,6 +98,17 @@ export const OG_SITE_NAME = Deno.env.get("GERBEUR_SITE_NAME") || "gerbeur";
// only needs a restart — no rebuild.
export const SITE_EMOJI = Deno.env.get("GERBEUR_SITE_EMOJI") || "🚚";
// Which Bandcamp playback path the frontend uses.
// "embed" — the bandcamp.com iframe (cannot autoplay)
// "native" — resolve the page's mp3 streams and play them in the app's own
// player, which autoplays and supports albums as a queue
// Anything unrecognised falls back to "embed", so a typo degrades safely.
export type BandcampPlayer = "embed" | "native";
export const BANDCAMP_PLAYER: BandcampPlayer =
Deno.env.get("GERBEUR_BANDCAMP_PLAYER")?.trim() === "native"
? "native"
: "embed";
// Background color for generated icons and the manifest. Mirrors the
// hard-coded theme-color in index.html.
export const THEME_COLOR = "#111827";