feat: live AzuraCast radio mode for footer player (#65)#71
Open
adurrr wants to merge 2 commits into
Open
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a new
<podcast-live>Web Component that polls an AzuraCastnowplayingAPI and renders real-time track metadata in the persistent footer.What it does
<podcast-live>element placed as a sibling of<podcast-footer>inbaseof.html. Polls a configurable AzuraCastnowplayingAPI at a default 15s interval (60s when idle, exponential backoff on errors).LIVEbadge with a pulse animation (respectsprefers-reduced-motion: reduce), the current track title, artist, and a 24H start→end time computed from the track'selapsedandduration.LIVEbadge + the badge'saria-label("Live radio currently broadcasting") signals the live state.Listen Livebutton in the regular footer appears when a<podcast-live>is configured and the current audio source is NOT the live stream. Clicking it dispatchespodcast-playwith the live URL → single-stream enforcement automatically pauses any other source.Listen Live(or thePodcastLive's own button) to start.data-azuracast-api-urlMUST be HTTPS (enforced at both template-time and runtime).javascript:,data:, malformed URLs all set state to "error" and skip fetch.Configuration
The example site demonstrates with Quantum Radio (
radio.erb.pw/api/live/nowplaying/subspace). SeeexampleSite/content/posts/live-mode.mdfor a working example.Latent bug fix
The existing
AzuracastAdapterwas readingazuracast-api-url(nodata-prefix) but the docs example useddata-azuracast-api-url. Users following the docs got "missing azuracast-api-url attribute" errors. Standardized on the documenteddata-azuracast-api-urlwith backward-compat fallback to the old name.Test plan (TDD)
npx vitest run— 166/166 tests pass (32 new + 134 pre-existing)<podcast-live>tests covering: registration/rendering, state machine, polling, single-stream integration, 24H time formatting, URL sanitization, CSS animation, cleanupvi.runAllTimersAsync(fires future timers) withvi.runOnlyPendingTimersAsyncwhere appropriate, then withawait Promise.resolve()chains for pure microtask draining; fixed off-by-one in C4/C5 backoff timing testsgo test -v -timeout 120s ./tests/hugo/...— 3 new shortcode tests pass (positive / omitted / bad-scheme); full suite still passesnpm run format:check— passesFiles changed
assets/js/podcast-player.jsPodcastLiveclass (250+ lines);AzuracastAdapterattribute fix; "Listen Live" button + handler in footer; new i18n keys in both classes'DEFAULT_I18Nlayouts/_shortcodes/podcast-player.htmllive-modeanddata-azuracast-api-urlparams (HTTPS validation)i18n/en.toml+exampleSite/i18n/es.tomlplayer_listen_livekeyexampleSite/layouts/_default/baseof.html<podcast-live>element (Quantum Radio) + i18nKeys slice updateexampleSite/content/posts/live-mode.mdexampleSite/content/docs/advanced.md+homepage-setup.md+ EStests/js/web-component.test.jstests/hugo/shortcode_test.go+ 2 newtestdata/dirsWhat's NOT in this PR
cd exampleSite && hugo server→ visit/posts/live-mode/→ clickListen Live→ see Quantum Radio's now-playing). The unit tests cover the component logic; E2E can be added in a follow-up.<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