Releases: mholzi/beatify
v3.3.2 — Region-Aware Apple Music & Playback Recovery
v3.3.2 — Region-Aware Apple Music & Playback Recovery
Apple Music tracks no longer silently fail for users on non-US storefronts. When playback breaks, you get a clear path forward instead of a frozen screen.
✨ What's New
Storefront-Aware Apple Music
Beatify's playlists historically stored a single Apple Music URI per song — typically a US-storefront track ID. For users on DE, GB, FR, ES, NL, IT storefronts, some subset of those tracks simply isn't in their catalog. This release ships a per-region URI map for 2,204 ISRC-resolved songs across all 22 playlists, and a runtime resolver that picks the right track ID based on hass.config.country. Region-locked songs get filtered out at playlist load — they never even reach MA. Closes #808.
Playback Recovery That Actually Recovers
When 3 songs in a row genuinely fail to play, the game now pauses with a recovery banner naming your provider and pointing at the exact fix — "Settings → Music Assistant → [Apple Music] → Reconnect, then click Resume." The Resume button restores the prior phase. The round-flow itself also got tougher: the timer reliably advances to REVEAL even when individual scoring throws (#816), the title-match fast-path returns within ~1s instead of timing out at 15s (#813), and Round 1 no longer freezes on cold MA start (#803). Worst-case round-advance lag dropped from ~20s to ~3s; typical case is under 1 second.
🔧 Under the Hood
Apple Music wizard selection honored end-to-end (#808 root cause) · TTS announcements actually play on Gemini/Cloud/etc. (#793) · Deezer routing fixed (#797) · stale-title detection rejects "speaker stuck on prior track" (#795) · speaker is media_stop'd on stale-title detect (#801) · MA URI cascade respects user's provider choice instead of walking all five (#805) · admin can reclaim their role from any phase (#790) · End game works from PAUSED phase · WS reconnect budget 5s → 20s for fresh-server starts (#814) · floating mini-timer always visible during round (#817) · Playlist Hub layout tighter, cards 17% bigger (#821) · wizard "Game language" defaults to browser language (#815, #822) · 3 untranslated home-view strings now in en/de/es/fr/nl · playlist-health-check skill enriched with a Mode 2 to refresh per-region URIs on demand · 442 unit tests · 18 release candidates over 4 days.
🙏 Contributors
@Levtos — Almost every fix in this release traces back to his patient stress-testing on AirPlay + Apple Music + MA. Surfaced #795, #801, #805, #808, #814, #815, #816, #817, #821, #822 with detailed logs, fast retest cycles, and clear repro steps every time.
@Ziigmund84 — Reported #797 (Deezer) and #803 (Round 1 cold-start lag) with logs pinpointing the exact failure modes.
@szszl0 — Reported #793 (Gemini TTS not playing) — the bug that affected every modern TTS entity.
22 playlists · 2,481 songs · 5 music platforms · 5 languages
v3.3.1 — Apple Music, Reset Button & Recovery Paths
v3.3.1 — Apple Music, Reset Button & Recovery Paths
Apple Music plays cleanly on Music Assistant setups again. The wizard tells you up front when your speaker can't play your service. And when a game does get stuck, you have a one-click way out — plus an admin session that survives a dropped connection.
✨ What's New
Apple Music via Music Assistant
Beatify now emits MA's native apple_music://track/<id> URI instead of the short music.apple.com/song/<id> URL that MA's parser silently rejected. Apple-Music-only setups had been seeing No playable items found on every fallback. Closes #772 and the remaining failure from @Levtos's #768 follow-up.
Wizard Knows What Your Speaker Can Play
Each speaker in Step 1 wears a capability badge — "All services" for MA, "Spotify only" for Sonos direct, "Spotify, Apple Music" for Alexa. In Step 2, providers your speaker can't play render dimmed with a lock icon; clicking one opens a card explaining how to set up MA. Continue is blocked until you pick something that actually works. Locale word order respected across en/de/es/fr/nl ("nur Spotify" in German).
Emergency Reset Button
A small ⟲ icon in the admin header. One click ends any active game, clears localStorage, unregisters the service worker, and reloads — same effective state as a fresh install. Backed by a new rate-limited endpoint that doesn't require an admin token, since the situation that needs this button is one where your token may be unreachable.
Recovery When Playback Fails
Beatify no longer advances the question + countdown when MA fails to actually start a track — strict-detection compares speaker state before and after the wait, treats "neither media_title nor position_updated_at moved" as a hard failure that falls through to the next URI candidate. MA timeout extended 8s → 15s for AirPlay. Closes #777.
Admin Session Survives a Dropped WebSocket
If your admin WS drops mid-game, reconnecting with the same name returns you to your admin role regardless of phase. Previously got bounced to name-entry → reload loop during REVEAL. pause_game also captures the admin name on every reason now, not just admin_disconnected. Closes #790.
🔧 Under the Hood
Service worker actually activates now (closes #780, all CACHE_VERSION bumps now do what they say) · admin footer reads version from manifest.json instead of a constant that drifted to v3.2.0-rc29 since April (#784) · CI restored after two months untracked (#786, #787) · 6 stale unit tests fixed properly (#788) · 17 new tests · 12 new i18n keys across en/de/es/fr/nl
🙏 Contributors
@Levtos — Almost every fix in this release traces back to his patient stress-testing on AirPlay + HomePod + Denon + Apple Music + MA. Surfaced #777, #790, the German word-order bug, and asked for the "großen roten Button" that became the reset feature.
24 playlists · 2,481 songs · 5 music platforms · 5 languages
v3.3.0 — Playlist Hub, Arcade Dashboard & Provider Fallback
v3.3.0 — Playlist Hub, Arcade Dashboard & Provider Fallback
Browsing playlists is now a first-class UI instead of a wizard dropdown. The admin dashboard picks up the Arcade language we shipped for the player views. And Music Assistant setups no longer stall when the user's primary provider doesn't carry a track.
✨ What's New
Playlist Hub
The wizard's step-3 playlist picker has been replaced by a dedicated mobile hub. Browse curated bundled defaults, community playlists reorganized by country, and pass-through playlists from your Music Assistant providers — all in one place, with a labeled select pill, back button, and floating select-and-start FAB. Each playlist now carries a source tag so you can tell bundled from community from local at a glance, and local-usage endpoints power the "recently played / most played" surfacing. Ships with translations across en/de/es/fr/nl.
Admin Dashboard — Arcade Refresh
The admin playing and reveal views drop the top-right round indicator in favor of a single chip strip (intro/closest-wins badge · round · submissions meter). The album art is now ringed by an animated cyan timer that matches the player screen's pulse at ≤10s. The reveal view adopts the same chip-strip pattern and moves the motivator into it — less visual noise, more information density, matching the player-side Arcade look we shipped in v3.2.
Provider Fallback for Music Assistant
If your MA setup has only Apple Music (or only Tidal, or only YT Music) and a track's primary URI is Spotify, Beatify no longer gives up. It tries the user's selected provider first, then falls back through every alternate URI on the song — with an ~8s timeout per candidate and a learned preference so subsequent rounds start instantly on the provider that actually worked. Closes #768, reported and verified by @Levtos.
🔧 Under the Hood
5 broken streaming URIs fixed across 3 playlists (eurodance-90s, koelner-karneval) · share card footer domain corrected (beatify.fun → beatify.life) · README screenshots refreshed to match v3.2.0 UI
🙏 Contributors
@Levtos — Patient end-to-end testing of the provider fallback across multiple rc builds, with precise MA logs distinguishing "fallback works" from "data still stale" — exactly what the fix needed.
24 playlists · 2,481 songs · 5 music platforms · 5 languages
v3.2.0 — Onboarding, Redesigns & Design System
Warning
Browser hard-reset required. This release rewrites the cache-control policy for all Beatify HTML. Your browser may still be holding months-old admin.html and player.html from the previous cache regime. After updating, do a hard reset once on every device — ⌘-Shift-R (Mac) / Ctrl-Shift-R (Win/Linux), or long-press reload on mobile and pick "Empty cache and hard reload" / "Clear cookies and site data". From this release forward, new versions roll out on next refresh automatically — no more private-window workarounds.
v3.2.0 — Onboarding, Redesigns & Design System
New players learn the game before the host starts. Admins get a proper first-run wizard instead of a raw settings dump. And every major player screen was rebuilt against a brand-new design system.
✨ What's New
First-Run Wizard
Five-step guided setup for new admins: Speakers → Music service → Playlist → Game mode → Lights/Voice. Runs automatically on first load, skippable afterwards. Multi-select playlists, dynamic difficulty hints that show the exact point distribution, WLED preset configuration, TTS test button, and Lights/Voice toggles that only appear if Home Assistant actually has the entities. After finishing, every chip on the admin dashboard is pre-selected — first thing you see is the Start Game button.
Admin Home View — "Ready to Host"
After the wizard (or on any subsequent load), admins land on a branded "Ready to host" screen: big Beatify wordmark, glowing QR hero card, meta line confirming playlist + game mode, Edit setup / Start game CTA. Once guests scan, they appear as Jackbox-style colored tiles — host in pink with a 👑 crown, guests cycling cyan → green → orange in join order. The flow — Join as player → Start game — is now the enforced path instead of buried in dropdowns.
Player Onboarding Tour
Players who scan the QR drop into a swipeable 4-card tour that teaches the mechanics in order: guess the year (animated slider), double-or-nothing bet (12 × 2 = 24), steal an answer, guess the artist. Auto-advances after 4s per card, Skip/Next always visible, ends on a "You're in, {name}!" pulse screen. A "Replay the tour" link in the lobby refreshes anyone. The host sees LEARNING players as dashed tiles with a cyan TOUR badge plus a confirm modal before starting — so nobody gets blindsided at round 1.
Gameplay Redesigned Arcade-Style
The active-round screen was rebuilt around the year guess as the hero. Massive 128px year number, neon timer circle that flips red and pulses at ≤10s, 3D tile buttons for artist/movie challenges, gradient 3D Submit button. When you submit, the year locks green, the slider freezes, and Submit morphs into a "Waiting for others" ghost state. No layout reflow, no mystery disappearances — everything stays visible until the reveal.
Round Reveal Redesigned as a Duel
After each round, you see your guess × gap-count × correct year side-by-side as a comparison, not a report. The full points breakdown (base · speed · streak · bonuses · bet multiplier) and round analytics (difficulty · avg guess · closest player · play count · furthest-off list) now live in tappable bottom-sheet popups instead of stacked cards. Cleaner main screen, full math one tap away.
End-Game Podium + Vinyl Share Card
Winner now dominates the end view — 40–64px name in the pink→cyan wordmark gradient, framed by a pink-bordered hero card. #2 and #3 demote to compact chips below. The share card was rebuilt from scratch as a vinyl-record design (navy base, pink/cyan radial glows, pink→cyan gradient label with your score, concentric groove rings, optional 🏆 WINNER badge) and now previews inline on the end screen, not just in the exported PNG.
Player Lobby Tile Grid
Lobby switches from flat chip cards to the same Jackbox-style tile grid the admin home-view uses. Host wears the pink "leader" variant with a 👑 crown; guests cycle cyan → green → orange → dim-cyan in join order; current player gets a cyan "YOU" chip. Disconnected players dim to 50% with a small "away" badge.
DESIGN.md — Authoritative Design System
New design-system reference checked into the repo: neon party-show aesthetic, typography (Outfit for display, Inter for UI), color palette (pink + cyan, with purple reserved for analytics/steal), spacing scale, motion tokens, patterns, anti-patterns, and a risk log for deliberate category departures. Every visual change in this release maps back to a token or pattern.
🔧 Under the Hood
Browser cache overhaul (no-cache HTML + conditional GETs on static) · 90+ broken streaming URIs fixed across 7 playlists · 14 game-logic fixes (scoring crashes, steal exploits, intro broadcast, winner ties) · 21 playlist bugs hardened (security, I/O, validation, perf, UX) · admin session handoff rewrite (HTTPS cookies, race-proof reconnect) · view-routing fixes (tour/ready/lobby stacking, Revanche home-view, End button stuck after rematch) · Spotify playlist import removed (Nov 2024 API deprecation broke client-credentials) · admin-player spoiler guard · 0-player game-start blocked · countdown timer sticky · kick-disconnected-players · year selector ± buttons · Launcher WebView popup fix · Vitest coverage for wizard + player modules · 5 new i18n namespaces across en/de/es/fr/nl
24 playlists · 2,481 songs · 5 music platforms · 5 languages
v3.1.0 — Admin Makeover & Stability
v3.1.0 — Admin Makeover & Stability
The admin dashboard got a complete redesign. Hosts who play along get the full experience. And the codebase got a deep stability pass.
✨ What's New
Admin Dashboard Overhaul
The admin spectator view has been rebuilt from the ground up. It now mirrors the player layout pixel-for-pixel: large centered album cover, big countdown timer, player-dot submission tracker with bet/steal badges, leaderboard with streaks and rank changes, and a podium end screen. The host sees the same game everyone else sees — just without the guess inputs. Reported by @maxlin1.
Admin Joins as Player — Full Experience
When the host taps "Join as Player", they're now redirected to the player page with all 18 game features (bet, steal, artist challenge, movie quiz, confetti, reactions, share cards) plus a fixed admin control bar at the bottom. No more degraded mini-UI.
Wake Lock
The screen stays awake during gameplay on mobile devices. No more frantic tapping to prevent your phone from sleeping mid-round.
WebSocket Reconnect on Tab Return
Switching apps or locking your phone no longer kills the admin connection. The WebSocket auto-reconnects when you come back, and all controls show a clear error message if the connection is lost instead of silently failing.
Intro Round for Non-Playing Admin
Admins who don't join as player can now confirm intro rounds. Previously, players were stuck on "Waiting for host..." indefinitely.
🔧 Under the Hood
16 bug fixes (WebSocket session recovery, confetti triggers, i18n rendering, Party Lights lifecycle, multi-provider playback) · 6 security hardening fixes (authenticated endpoints, credential handling) · 12 performance fixes · 6 architecture improvements · 8 code quality fixes · 3 dead code removals · 15 broken streaming URIs replaced
🙏 Contributors
@maxlin1 — Detailed bug reports with root cause analysis, implementation suggestions, and screenshots for the admin dashboard overhaul, WebSocket reliability, and gameplay UX issues.
24 playlists · 2,482 songs · 5 music platforms · 5 languages
Beatify v3.0.0 — Dynamic Lights, Balanced Playlists & Security Hardening
v3.0.0 — Dynamic Lights, Balanced Playlists & Security Hardening
Your lights dance with the music. Playlists share the stage equally. And the codebase got a full security audit.
✨ What's New
Dynamic Light Effects & WLED Support
Party Lights are no longer static. In Dynamic mode, lights pulse between blue shades during playback and react to game events — gold flash for exact matches, green for off-by-one, orange for streak milestones. WLED users can now map configurable presets to each game phase instead of being locked into static colors. Three modes: Static (original), Dynamic (new default), and WLED.
Balanced Playlist Selection
Selecting multiple playlists no longer means the largest one dominates. Beatify now picks a random playlist first (equal weight), then a random song from it. A 290-song Carnival playlist combined with a 30-song Gen Z playlist now produces a 50/50 mix instead of 91/9. Cross-playlist duplicates are automatically deduplicated. Proposed by @maxlin1.
+10s Seek Forward
New button in the admin control bar lets the host skip past silent intros. Reads the current playback position from Home Assistant and seeks forward 10 seconds, with stale-position correction for accurate seeking. Requested by @Scribblerman.
Admin Spectator Mode
The admin can now watch and control the game without being a player. Start the game, manage rounds, adjust volume — all from a separate session while players play on their phones.
Closest Wins Mode
New game mode: only the player with the closest guess scores each round. All-or-nothing showdown that changes the strategy entirely.
HA Sensor Entities
Beatify now exposes live game state as Home Assistant entities — current round, leader, top score, player count, and game active status. Use them in automations, dashboards, or Lovelace cards.
TTS Announcements
Voice feedback for game start and winner reveal via any HA TTS entity. Per-announcement toggles and a test button in admin settings. Requested by community.
Gen Z Anthems Playlist
30 songs from TiK ToK to Good Luck, Babe! spanning 2009–2024 with URIs for all 5 providers and fun facts in 5 languages.
Music Assistant + YouTube Music Fix
MA+YTMusic no longer skips songs during slow buffering. Title verification prevents race conditions where a previous song is falsely confirmed. Hard failure detection distinguishes actual errors from slow loads. Contributed by @Scribblerman (Tobias Koops).
🔧 Under the Hood
Security hardening (timing-safe token comparison, rate limiting, TTS input validation, HA 2026.4+ blocking scandir fix) · 20+ bug fixes · 8 architecture refactors including RoundManager extraction · 268 broken streaming URIs replaced across 5 playlists · iOS Safari double-tap zoom fix · Volume button labels in 5 languages · Responsive result cards · Collapsible admin sections · Dark theme QR URL contrast fix
🙏 Contributors
@Scribblerman (Tobias Koops) — Music Assistant + YouTube Music playback fix, +10s seek forward feature request, and extensive playtesting that caught critical regressions.
@maxlin1 — Balanced playlist selection proposal with full implementation spec including cross-playlist deduplication, and the dynamic light effects & WLED feature request.
@semichcsc-byte — Feature request for game mode options (playing without year guessing).
24 playlists · 2,482 songs · 5 music platforms · 5 languages
Beatify v2.9.1 — Party Lights, Dutch & Stability
v2.9.1 — Party Lights, Dutch & Stability
Smart home joins the party. Dutch makes five. And a systematic code review closed a dozen bugs.
✨ What's New
Party Lights
Beatify now controls your smart home lights during games. Lobby glows purple, playing turns blue, reveal warms up — and the end screen kicks off a rainbow celebration. Three intensity presets: Subtle (scales from your pre-game brightness), Medium, and Party. Pick lights in the admin UI and preview the effect before your guests arrive.
Dutch Language Support
Dutch joins English, German, French, and Spanish as the fifth supported language. Full UI translations contributed by @rononline, plus Dutch fun facts and awards for all 361 songs across every playlist.
My Home Assistant Install Badge
One-click install from the README via the My Home Assistant redirect.
🔧 Under the Hood
12 bugs fixed from a systematic code review including Dutch fun facts missing from game state, the Party Lights preview button, admin claim guard, null song scoring, async_timeout compatibility for Python <3.11, and 39 dead streaming URIs replaced. Assets shrunk 38% via esbuild minification (590KB → 364KB). Five architecture refactors and 46 new unit tests for PartyLightsService.
23 playlists · 2,453 songs · 5 music platforms · 5 languages
Beatify v2.8.0 — Deezer, Smarter Intro Mode & Architecture Overhaul 🎵
v2.8.0 — Deezer, Smarter Intro Mode & Architecture Overhaul 🎵
Five streaming services. Cleaner code. Tighter security. And a brand new playlist.
✨ What's New
Deezer Support
Deezer joins Spotify, YouTube Music, Apple Music and Tidal as the fifth supported streaming service. Over 2,000 Deezer URIs have been added across 19 playlists, with automatic URI resolution and the same one-tap playback experience. Players on Deezer Premium can now host games without switching platforms.
Smarter Intro Mode
Intro rounds no longer catch players off guard. The first three rounds are always normal, giving everyone time to settle in. When the first intro round triggers (20% chance per round from round 4 onwards), an admin-confirmed splash screen explains the rules and waits for the host to press "Start" before music plays. Duration has been increased from 10 to 15 seconds for a fairer challenge.
Music Assistant + YouTube Music Fix
Music Assistant with YouTube Music takes 5–15 seconds to resolve URIs and buffer audio. Previously this caused hangs, timeouts, and skipped songs. Playback now uses non-blocking service calls with state polling — Beatify waits for actual speaker output before starting the round timer. Includes pre-flight availability checks for all platforms and resilient error handling during polling. Contributed by @Scribblerman.
90s & 2000s Hip Hop Bangers
40 tracks spanning 1990–2008 from 23 artists including 2Pac, Notorious B.I.G., Eminem, JAY-Z, Nas, Missy Elliott, Dr. Dre, Kanye West, OutKast, and Snoop Dogg. Fully enriched with fun facts in 4 languages, chart info, certifications, and streaming URIs across all 5 platforms.
🔧 Under the Hood
Refactored player.js into ES modules — the monolithic 3,000-line file is now split into focused modules · split scoring god functions into testable units · removed dead code · added unit tests for stats, analytics, WebSocket, and media player modules · rate limiting, input validation, and stale-IP sweep on the playlist-requests endpoint · XSS protection for player names · skeleton loading states replace raw "Loading..." text · hardcoded English strings replaced with i18n calls · French language support completed · iOS WebSocket reconnect on foreground · 276 broken streaming URIs fixed across 10 playlists
23 playlists · 2,453 songs · 5 music platforms · 4 languages
Beatify v2.7.0 — UX Polish & Playlist Expansion 🎵
v2.7.0 — UX Polish & Playlist Expansion 🎵
Your end screen just got a serious upgrade — and two new playlists are in the mix.
✨ What's New
PWA: Add to Homescreen
Beatify now installs as a Progressive Web App. Tap the install prompt on the admin screen or use the explicit install button in the header — and Beatify lives on your homescreen like a real app.
Share Your Results
The end screen now includes a shareable result card — a Wordle-style emoji grid of your round results. On mobile, the native share sheet opens directly. On desktop, it downloads as a card image.
Revanche (Rematch)
Players can now challenge for a rematch directly from the end screen — no need to scan QR codes again. One tap and everyone's back in the lobby.
Greatest Metal Songs playlist
52 legendary tracks across all major metal subgenres (1970–2020), fully enriched with certifications, awards and streaming links.
Dutch Top 100 enriched
The Top 100 Allertijden Nederlandstalig now includes fun facts in 4 languages and alternative artist suggestions for every track.
22 playlists · 2,415 songs · 4 music platforms · 4 languages
Beatify v2.6.0 — Highlights Reel 🎬
v2.6.0 — Highlights Reel 🎬
The party doesn't end at the podium anymore.
✨ What's New
Game Highlights Reel
Every game now ends with an auto-generated highlight reel — the Top 8 moments your group created. Exact year matches, killer streaks, bold bets, speed records, heartbreaking near-misses, epic comebacks, photo finishes. All captured, all celebrated.
🐛 Bug Fixes
- Streak-10 milestone was incorrectly tracked as
streak_7— fixed - "End game first" error when starting a new game from the end screen — fixed
- Streak bonus notification: text contrast and padding fixed
- Result cards carousel: horizontal scroll, one card per view
21 playlists · 2,363 songs · 4 music platforms · 4 languages