Skip to content

feat: live AzuraCast radio mode for footer player (#65)#71

Open
adurrr wants to merge 2 commits into
mainfrom
feat/live-radio-mode
Open

feat: live AzuraCast radio mode for footer player (#65)#71
adurrr wants to merge 2 commits into
mainfrom
feat/live-radio-mode

Conversation

@adurrr

@adurrr adurrr commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Adds a new <podcast-live> Web Component that polls an AzuraCast nowplaying API and renders real-time track metadata in the persistent footer.

What it does

  • New <podcast-live> element placed as a sibling of <podcast-footer> in baseof.html. Polls a configurable AzuraCast nowplaying API at a default 15s interval (60s when idle, exponential backoff on errors).
  • Renders a red LIVE badge with a pulse animation (respects prefers-reduced-motion: reduce), the current track title, artist, and a 24H start→end time computed from the track's elapsed and duration.
  • A pulsing LIVE badge + the badge's aria-label ("Live radio currently broadcasting") signals the live state.
  • A Listen Live button in the regular footer appears when a <podcast-live> is configured and the current audio source is NOT the live stream. Clicking it dispatches podcast-play with the live URL → single-stream enforcement automatically pauses any other source.
  • No autoplay — the user must click Listen Live (or the PodcastLive's own button) to start.
  • URL sanitization: data-azuracast-api-url MUST be HTTPS (enforced at both template-time and runtime). javascript:, data:, malformed URLs all set state to "error" and skip fetch.
  • Configuration persists across htmx / Turbo / Turbolinks navigation via the standard persistence markers.

Configuration

{{</* podcast-player
  src=
  source=azuracast
  data-azuracast-api-url="https://radio.example.org/api/live/nowplaying/station-slug"
  live-mode="true"
*/>}}

The example site demonstrates with Quantum Radio (radio.erb.pw/api/live/nowplaying/subspace). See exampleSite/content/posts/live-mode.md for a working example.

Latent bug fix

The existing AzuracastAdapter was reading azuracast-api-url (no data- prefix) but the docs example used data-azuracast-api-url. Users following the docs got "missing azuracast-api-url attribute" errors. Standardized on the documented data-azuracast-api-url with backward-compat fallback to the old name.

Test plan (TDD)

  • npx vitest run166/166 tests pass (32 new + 134 pre-existing)
    • 32 new <podcast-live> tests covering: registration/rendering, state machine, polling, single-stream integration, 24H time formatting, URL sanitization, CSS animation, cleanup
    • Test corrections: replaced vi.runAllTimersAsync (fires future timers) with vi.runOnlyPendingTimersAsync where appropriate, then with await Promise.resolve() chains for pure microtask draining; fixed off-by-one in C4/C5 backoff timing tests
  • go test -v -timeout 120s ./tests/hugo/... — 3 new shortcode tests pass (positive / omitted / bad-scheme); full suite still passes
  • npm run format:check — passes
  • No em-dashes in new doc or CHANGELOG content

Files changed

File Change
assets/js/podcast-player.js New PodcastLive class (250+ lines); AzuracastAdapter attribute fix; "Listen Live" button + handler in footer; new i18n keys in both classes' DEFAULT_I18N
layouts/_shortcodes/podcast-player.html New live-mode and data-azuracast-api-url params (HTTPS validation)
i18n/en.toml + exampleSite/i18n/es.toml New player_listen_live key
exampleSite/layouts/_default/baseof.html <podcast-live> element (Quantum Radio) + i18nKeys slice update
exampleSite/content/posts/live-mode.md New demo post
exampleSite/content/docs/advanced.md + homepage-setup.md + ES New "Live Mode" / "Live Radio Mode" sections
tests/js/web-component.test.js 32 new Vitest tests + corrections to existing tests
tests/hugo/shortcode_test.go + 2 new testdata/ dirs 3 new Go tests

What's NOT in this PR

  • E2E test for the live flow — added to the plan but deferred. Manual testing on localhost will exercise the full flow (cd exampleSite && hugo server → visit /posts/live-mode/ → click Listen Live → see Quantum Radio's now-playing). The unit tests cover the component logic; E2E can be added in a follow-up.
  • The issue mentions <podcast-live> could be placed INSIDE <podcast-footer> (via slot). I chose to place it as a SIBLING because the footer has no <slot> and slot-based composition would require coordinating two lifecycles. The sibling approach is simpler and visually equivalent (CSS positions the live card next to the footer bar).

Closes #65

adurrr added 2 commits June 28, 2026 19:01
Add a new <podcast-live> Web Component that polls an AzuraCast
nowplaying API and renders real-time track metadata (title, artist,
24H start/end time) in the persistent footer. A pulsing LIVE badge
with reduced-motion support signals the live state. A 'Listen Live'
button in the footer switches playback to the live stream and
stops the other source (single-stream enforcement). The metadata
refreshes every 15 seconds while playing and every 60 seconds
otherwise, with exponential backoff on errors. Live config
persists across htmx / Turbo / Turbolinks navigation.
…e mode

The previous commit added a <podcast-live> element to baseof.html,
which made the live element appear on every page and start polling
the AzuraCast nowplaying API on every page load. This caused E2E test
failures because the slow / unreachable network call interfered with
Playwright page.goto timing.

Fix: remove <podcast-live> from baseof.html, add a new
podcast-live shortcode, and update the live-mode example post to use
it. The element is now only present where the user explicitly adds it.

Also fix a related shortcode bug: src="" was rejected by the
existing required param validation, so live mode (which does not
have an audio URL until the AzuraCast adapter resolves it at runtime)
could not be used. Allow empty src when source=azuracast or
live-mode is set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: enable live AzuraCast station on footer player (LIVE badge, now-playing metadata, 24H time, Listen Live CTA)

1 participant