f5feca7dfa
Two-layer "this is playing right now" visual:
(1) CSS dancing bars — four tiny vertical bars next to the "Now Playing"
label, staggered `@keyframes` pulse while audio plays. Pure CSS, no
JS dependency, tints to the user's WP admin colour scheme via
var(--wp-admin-theme-color). Driven by a single `.is-playing` class
on `.radio-player` toggled from the existing play/pause/error
handlers. Always works.
(2) Web Audio frequency visualizer (progressive upgrade) — on first play,
builds AudioContext + AnalyserNode + canvas drawing pipeline. When
the analyser starts returning real (non-zero) data, hides the bars
and shows the canvas with live frequency bars. Falls back to bars
if AudioContext is unavailable, createMediaElementSource throws, or
the analyser returns all-zeros for >2s (CORS silently blocking).
State machine on player._vizState: no-webaudio / init-failed /
cors-blocked / ok.
`<audio>` element gained `crossorigin="anonymous"` so Web Audio can read
the stream data (SomaFM serves the CORS headers).
Files: radio.php (version), inc/admin-page.php + inc/dashboard-widget.php
(.radio-player__indicator with .radio-player__bars + canvas; crossorigin
on audio), assets/css/radio.css (indicator, bars, radio-bars-dance
keyframes, canvas size), assets/js/radio.js (tryVisualizer,
startVizLoop, stopVizLoop; play/pause/error handlers wire the loop and
toggle is-playing), inc/about.php (history entry).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
157 lines
14 KiB
Markdown
157 lines
14 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to **Radio** are documented here.
|
||
Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versioning: [SemVer](https://semver.org/).
|
||
|
||
---
|
||
|
||
## [Unreleased]
|
||
|
||
---
|
||
|
||
## [0.4.0] — 2026-05-29 — Now-playing indicator: dancing bars + Web Audio visualizer
|
||
|
||
A small visual that instantly says *"this is playing right now."* Two layers — a reliable CSS-only indicator that always works, and a progressive Web Audio upgrade that draws actual frequency data when the browser allows.
|
||
|
||
### Added — dancing bars (always on, CSS only)
|
||
- Four tiny vertical bars next to the "Now Playing" label that pulse with a staggered `@keyframes` animation while the audio is playing, settling to a low static state when paused. Pure CSS — no JS dependency, no audio analysis.
|
||
- Bars use `var(--wp-admin-theme-color)` so they tint to whichever WP admin colour scheme the user has chosen.
|
||
- Driven by a single `.is-playing` class toggled on the `.radio-player` surface from the existing `play` / `pause` / `error` audio handlers.
|
||
|
||
### Added — Web Audio frequency visualizer (progressive upgrade)
|
||
- On first `play`, `tryVisualizer` builds an `AudioContext` + `AnalyserNode` chain on the `<audio>` element and starts drawing live frequency bars on a `<canvas>` next to "Now Playing."
|
||
- `<audio>` now carries `crossorigin="anonymous"` so the Web Audio analyser can actually read the stream data (SomaFM serves the CORS headers).
|
||
- **Graceful fallback:** if `AudioContext` isn't available, or `createMediaElementSource` throws, or the analyser returns all-zeros for 2 s (CORS silently blocking), the visualizer state flips to `cors-blocked` / `init-failed` / `no-webaudio` and the CSS dancing bars remain — the plugin never loses its indicator.
|
||
- Canvas is sized to its CSS box × `devicePixelRatio` so it stays crisp on retina screens.
|
||
|
||
### State machine on `player._vizState`
|
||
| Value | Meaning |
|
||
|---|---|
|
||
| _undefined_ | not yet attempted |
|
||
| `no-webaudio` | browser lacks `AudioContext` |
|
||
| `init-failed` | `createMediaElementSource` threw |
|
||
| `cors-blocked` | analyser returned zeros for >2 s |
|
||
| `ok` | live frequency data flowing → canvas shown, bars hidden |
|
||
|
||
**Files changed:** `radio.php` (version), `inc/admin-page.php` + `inc/dashboard-widget.php` (added `.radio-player__indicator` with `.radio-player__bars` + `<canvas data-radio-viz>`, plus `crossorigin="anonymous"` on the `<audio>`), `assets/css/radio.css` (indicator container, bars + `radio-bars-dance` keyframes, canvas size), `assets/js/radio.js` (`tryVisualizer` / `startVizLoop` / `stopVizLoop`, `play/pause/error` handlers toggle `is-playing` class and drive the loop), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.3.2] — 2026-05-29 — Play-button glyph baseline fix
|
||
|
||
The dashicon used for the play/pause icon was rendering visibly below the button text baseline — the dashicon font sits the glyph low inside its own box, and even with `inline-flex` centering the result looked like the symbol was on a separate row from the word "Play".
|
||
|
||
### Fixed
|
||
- **Play/pause icon now sits on the text baseline.** Swapped the dashicon (`dashicons-controls-play` / `dashicons-controls-pause`) for a plain Unicode glyph (▶ / ‖) which renders on the text baseline like any other character.
|
||
- Flex container changed from `align-items: center` to `align-items: baseline` for the same reason.
|
||
- `font-variant-emoji: text` set so platforms that might otherwise pick up a colour-emoji variant for ▶ keep it as monochrome text.
|
||
|
||
**Files changed:** `radio.php` (version), `inc/admin-page.php` + `inc/dashboard-widget.php` (dashicon span → glyph span), `assets/css/radio.css` (drop the dashicon-sizing rule, add `.radio-player__play-glyph` styling, change play-button flex alignment to baseline), `assets/js/radio.js` (`setPlayIcon` now swaps glyph `textContent` instead of dashicon `className`), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.3.1] — 2026-05-29 — My Radio layout polish + drop dark-auto
|
||
|
||
Quick patch after a real-screen review of the My Radio admin page. v0.3.0 added a lot of features but stretched the player to fill the full admin width and — embarrassingly — introduced a real contrast bug via the dark-auto CSS.
|
||
|
||
### Fixed
|
||
- **Dropped `@media (prefers-color-scheme: dark)` for `theme=auto`.** WordPress admin has no native dark mode, so when the OS was dark, our dark text rendered on the still-white WP postbox = unreadable. `auto` now behaves as light (matching WP's actual scheme); `dark` is still available as an explicit choice.
|
||
- **`theme=dark` now actually reads.** The player surface goes dark (`#1d2327` background + subtle border + padding) so the light text has somewhere to sit, instead of fighting the white WP postbox.
|
||
- **Player no longer stretches edge-to-edge.** `.radio-wrap { max-width: 880px; }` keeps the player a focused settings-page card.
|
||
- **Intro paragraph one-line on normal widths.** Removed the `max-width: 720px` cap that was forcing the wrap.
|
||
- **Volume slider no longer dominates the row.** Fixed width 220px (`flex: 0 0 auto`) — the percent label now sits next to the slider instead of pinned to the far right edge.
|
||
- **Station dropdown** capped at 360px (was full-width) — typical WP form-control width.
|
||
- **Play button icon** shrunk from 18px to 14px so the ▶ glyph sits on the button-text baseline instead of looking like a separate row.
|
||
|
||
**Files changed:** `radio.php` (version), `assets/css/radio.css` (wrap width, intro, play icon, volume, station-select, dark-auto block deleted, dark-surface added), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.3.0] — 2026-05-29 — Dark theme + mute + media keys + current-track display
|
||
|
||
A polish pass that closes the gaps surfaced by a UI review. Two categories: **2nd-look fixes** (things the previous release implied but didn't actually deliver) and **nice-to-haves** (small upgrades that lift the admin-player feel).
|
||
|
||
### Added — features
|
||
- **Mute toggle on the speaker icon.** The icon next to the volume slider is now a button. Click to mute (icon flips to `dashicons-controls-volumeoff`, tinted red); click again to restore the prior volume. Remembers volume across mute/unmute via `data-prev-volume`.
|
||
- **MediaSession API integration.** OS media keys (F8/F9 on Mac, Bluetooth headphone buttons, lock-screen widget on supported platforms) now play/pause the radio. The currently-playing station name, "SomaFM" as artist, and the genre as album are exposed as `MediaMetadata` so they show on the OS overlays.
|
||
- **Current-track display.** Polls `https://somafm.com/songs/{code}.json` every 30 seconds **while playing only** and shows the track as `♪ Title — Artist` under the station description. Best-effort: silently hidden if the endpoint is unreachable / CORS-blocked, so the plugin keeps working regardless.
|
||
|
||
### Fixed — 2nd-look
|
||
- **Dark theme is now actually wired through.** v0.2.0 saved the Theme dropdown (auto / light / dark) but had no CSS to render anything other than light. v0.3.0 adds `admin_body_class` filter → `radio-theme-{auto,light,dark}` body class → corresponding dark-palette CSS for the player + about-cards. `auto` follows the OS via `prefers-color-scheme: dark`.
|
||
- **Settings-page volume slider** no longer uses an inline `oninput=""` handler — the listener moved into `assets/js/radio.js` (`bindSettingsSlider`). Cleaner under strict-CSP environments.
|
||
- **Save errors are surfaced.** AJAX state-save failures were previously swallowed silently — the local UI updated but the user had no signal if the server dropped the request. The plugin now shows a brief notice ("Preferences not saved — check your connection.") in the player's error slot for 3.5 s, then auto-clears.
|
||
- **Hardcoded Gitea URL** in the About page replaced with a `RADIO_GITEA_URL` constant defined in `radio.php`. One place to update if the repo ever moves.
|
||
- **Genre badge layout fix.** Was using `margin-left: auto` inside a wrap-enabled flex row, which caused it to land on its own line on narrow widget widths. Now styled as a small inline pill (rounded `rgba(0,0,0,0.06)` background) that flows naturally next to the station name.
|
||
|
||
### Other
|
||
- Plugin version bumped to **0.3.0**.
|
||
- New localized strings: `mute`, `unmute`, `saveError` (for the JS-driven UI).
|
||
- The mute button has a visible focus ring (`outline: 2px solid var(--wp-admin-theme-color)`) for keyboard navigation.
|
||
- Volume slider input now also exits mute state (sets `audio.muted = false` on drag), so dragging the slider always overrides a prior mute click.
|
||
|
||
**Files changed:** `radio.php` (version, constant, strings, `admin_body_class` filter), `inc/about.php` (constant for changelog URL), `inc/settings.php` (removed inline `oninput`), `inc/admin-page.php` + `inc/dashboard-widget.php` (speaker icon → mute button, added track slot), `assets/css/radio.css` (genre badge pill, mute button, track display, dark-theme rules incl. `prefers-color-scheme` for `auto`), `assets/js/radio.js` (full rewrite incl. `bindMute`, `bindSettingsSlider`, `startTrackPolling`/`stopTrackPolling`, `updateMediaSession`, save-error surfacing).
|
||
|
||
---
|
||
|
||
## [0.2.0] — 2026-05-26
|
||
|
||
### Changed — UI rebuilt to WordPress admin standards
|
||
v0.1.0 worked but looked like a third-party React widget sitting on top of WordPress rather than part of it. v0.2.0 rebuilds the player UI to use WP-native patterns end-to-end.
|
||
|
||
- **Main page** now uses the standard **`.postbox` container** (gray header bar + `.inside` body) instead of a custom rounded-shadow card.
|
||
- **Play button** is now a standard **`.button .button-primary`** with both icon AND text label (Play / Pause), matching every other admin button. Replaces the giant blue circular icon-only button.
|
||
- **Now Playing** uses left-aligned default body text with `.description` muted-gray for the station tagline. Replaces the centered large-typography card.
|
||
- **Genre badge** moved to a small `.radio-player__station-genre` text label aligned right of the station name. Replaces the custom pill.
|
||
- **Volume slider** now uses `accent-color: var(--wp-admin-theme-color)` — adapts to whichever admin colour scheme the user has chosen (Default / Light / Modern / Blue / Coffee / Ectoplasm / Midnight / Ocean / Sunrise).
|
||
- **All link colours** likewise adapt to the user's admin theme via `var(--wp-admin-theme-color, #2271b1)`.
|
||
- **Dashboard widget** content sits bare inside its `.inside` — WordPress already wraps it in a postbox. v0.1.0 was rendering a card inside a card.
|
||
- **About page** cards now use postbox-style gray header bars + WP-standard 1px border + subtle shadow. Replaces the custom rounded grid.
|
||
- **Credit footer** uses `.description` class, smaller and more native.
|
||
|
||
### Net effect
|
||
The plugin feels like part of WordPress now, not bolted onto it. Picks up your admin colour scheme automatically. Closer to WP.org submission criteria — they look for native-styled plugins during plugin review.
|
||
|
||
### Not changed
|
||
- Functionality identical to v0.1.0 — same 44 stations, same audio path, same user_meta persistence, same updater, same AJAX endpoint.
|
||
- No behaviour change for end users; this is purely visual.
|
||
- About page version-history card promotes v0.2.0 to "latest", demotes v0.1.0.
|
||
|
||
---
|
||
|
||
## [0.1.0] — 2026-05-26
|
||
|
||
**Radio is born.** First release of a new standalone WordPress plugin extracted-and-rebuilt from the radio feature that lives inside RangerPlex. Radio stands on its own as a focused, friendly companion plugin for the WordPress dashboard — a tab of background music while you work.
|
||
|
||
### Added — Phase A complete (player exists)
|
||
- **Dashboard widget** at WP Admin → Dashboard showing a compact mini-player with play/pause, station select grouped by genre, and a volume slider.
|
||
- **Dedicated admin page** at WP Admin → Radio → My Radio showing the same controls in a larger format with the station's genre badge and description.
|
||
- **44 SomaFM stations** across **10 genres** (Ambient, Electronic, Lounge, Rock, Metal, Jazz, World, Reggae, Holiday, Specials). Stream URLs use SomaFM's public 128kbps MP3 endpoints — no proxy server required.
|
||
- **Per-user state storage** via `user_meta` (key: `radio_state`). Each WordPress admin remembers their own station choice, volume, and theme preference.
|
||
- **Settings page** at WP Admin → Radio → Settings with default station, default volume, theme (auto/light/dark), and an opt-out for the dashboard widget. Updates panel shown to admins with `manage_options`.
|
||
- **About page** at WP Admin → Radio → About with plain-language explanation of what the plugin does, who it's for, version history, and credits to SomaFM.
|
||
- **Self-hosted update checker** wired up to the Gitea repo (`ranger/a-radio`) from commit 1. Polls `/api/v1/repos/ranger/a-radio/releases/latest` with a `/tags?limit=1` fallback. 12h success cache, 1h negative cache.
|
||
- **AJAX endpoint** `radio_save_state` for persisting station/volume changes without a page reload. Nonce-protected, capability-checked.
|
||
- **Custom admin-menu icon** (`dashicons-format-audio`).
|
||
- **Direct HTML5 `<audio>` playback** — no Node proxy, no PHP stream-passthrough, no server-side resource cost per listener. SomaFM's CORS headers make this work out of the box in modern browsers.
|
||
|
||
### Architecture (locked from day one)
|
||
- **Single-word brand name `Radio`** — no "WP" prefix, no marketplace trademark hurdle.
|
||
- **Public GPL v2+ Gitea repo** at `ranger/a-radio` on `git.davidtkeane.com`.
|
||
- **Per-user state in `user_meta`** under key `radio_state`.
|
||
- **Vanilla JS only** — no React, no build step, no bundler. ~200 lines of JS controlling all interactions.
|
||
- **CSS-only animations, all assets local** — bundle stays sub-100KB.
|
||
- **Single H1 per admin page**, no nested toggle boxes — Tier-1 discipline carried forward from the Logbook + Buddy lineage.
|
||
- **Sanitize on input, escape on output** throughout. Every AJAX endpoint nonce-protected and capability-checked.
|
||
|
||
### Compliance
|
||
- Station list and stream URLs are SomaFM's public, freely-published endpoints. Their terms allow redistribution with attribution.
|
||
- "Powered by SomaFM" credit displayed in both player surfaces, linking to somafm.com.
|
||
- The About page invites users to donate to SomaFM directly.
|
||
|
||
### Not in this release (planned)
|
||
- Phase B — Settings polish + README for WP.org submission + retry logic for transient stream errors.
|
||
- Phase C — Now-playing metadata via SomaFM's per-station song-history endpoint.
|
||
- Phase D — `[ranger_radio]` shortcode so the player can be embedded in posts/pages.
|
||
- Phase E — Favorites system.
|
||
- Phase F — Multi-provider (Radio Paradise, NTS Radio, KEXP, BBC) with a provider abstraction.
|