-
beatbump v1.0.0
StableAll checks were successfulCI / Web (vitest + svelte-check ceiling) (push) Successful in 1m3sCI / Shell (shellcheck) (push) Successful in 21sCI / Python (py_compile + ruff) (push) Successful in 14sCI / Harness headers (X-Ytm-Harness on every Playwright context) (push) Successful in 10sCI / Compose (deploy/compose.yml config) (push) Successful in 14sCI / Go (vet + test) (push) Successful in 2m11sRelease / Build and push images (push) Successful in 2m3sRelease / Forgejo release (push) Successful in 11sreleased this
2026-10-06 12:12:49 +00:00 | 0 commits to main since this releaseFirst public release of the fork. Compared with upstream Beatbump (a SvelteKit
YouTube Music front end with a Go server), this release turns the app into a
self-hosted music service that owns its data: a local library indexed by
Meilisearch and served next to YouTube, automatic acquisition, a real offline
mode, personal rows and statistics, multi-device continuity, a French
interface, and the operations and browser-harness tooling that kept it in
production during the programme.Added
Library (own the data)
- Unified search over the local library and YouTube, with instant, typo-tolerant
local suggestions ("daft pnk" finds Daft Punk) and direct play from the
overlay; results header with All / Songs / Albums / Artists / Playlists chips,
the local library in its own shelf, duplicates removed. - Local Artists, Albums, Songs and Genres pages (grids, sort and
filters remembered per page, infinite scroll, A-Z index on mobile), local
artist, album and playlist pages (an album page is rebuilt from the index
when its document is missing), playable genres, a Mixes page. - Best copy served when a track exists both locally and online; quality score
per track (codec, bitrate, sample rate) and transparent upgrade in place. - Automatic acquisition: following an artist downloads its discography slowly
through the yubal sidecar (po-token, rate limited, residential egress);
download queue with pause / resume / retry; daily cap of 20 albums per
profile with an explicit refusal; prefetch, share, download, mixes and the
browser harness never trigger server acquisition (X-Ytm-Prefetch). - Artist variants ("feat.", case, accents) grouped for display: "Also as" chips,
"Play all" over the group, "+N variants" badge; duplicate album detection
(two sources, editions such as Live / Remix / Demo kept apart) with a
suggested copy, one copy per title in mixes and related rows. - Library hygiene on the About page: albums without a year ("No year" chip),
rare genres (collapsed section), close artist names; genre cleanup
(composite values split, "Singer/Songwriter" and "AC/DC" kept whole,
soundtracks grouped). - "In your library" section in the player's Related tab (same artist, same
genre;GET /api/v1/local/related); "You already own it" banner on a YouTube
album present locally, pointing to the local copy. - Play all / Shuffle on favourites, server playlists, local artists and genres;
radio targeted at an album, an artist or the favourites; "Save the queue" as
a playlist; listening history grouped by day with "Replay this day" and a CSV
export. - Album metadata on local tracks, album art fallback for tracks without an
embedded image, initials placeholder when no image exists, covers served from
a disk cache in the bridge sidecar.
Player and queue
- Audio served same-origin through the Go server (
/localf,/vp,/cover
to the bridge,/audto iv-vp), next-track prefetch (+2 at low priority),
non-library tracks streamed at full speed through iv-vp instead of a
throttled proxy. - Structured
player.jsonerrors ({error, status, reason, videoId}with
400 / 404 / 502 / 504) surfaced as French toasts, one retry on 502 / 504,
guarded auto-skip that never cascades; media element errors mapped the same
way; one silent source reload on a decode error before any message, the
cached copy purged only on a second online failure and never for pinned or
local tracks. - Queue: "Play next" and "Add to queue" on songs, albums, singles and
playlists, "Clear the queue" (keeps the current track), swipe to remove,
drag and drop by touch, mouse (250 ms and 6 px guard) and keyboard
(Alt+arrows), "Already in the queue" notice with Dedupe Automix, removing
the playing row plays its replacement, drags replayed on the updated queue. - Radio by default (a real YouTube radio even for a local track), local
continuation at the end of a local queue that stays in the same universe
(decade, genre, year), playback context line ("Album: X · 4/14",
Favourites, Queue, Offline) with "Back to the album" after a "Play next". - Exact resume on reopen: queue, position and context restored paused
("Remember last track" on by default), "Resume the queue" pill, nothing
acquired or cached before the first play, no double counting. - Sleep timer (15 / 30 / 45 / 60 min, end of track, end of album, in 3 tracks,
+10 min, 3 s fade) that holds on a locked iPhone; complete keyboard
shortcuts with a "?" sheet; heart in the mini bar and the full-screen player;
the whole last second of every track is played. - Synchronised lyrics (lrclib.net): click a line to seek, auto-scroll that
pauses when you scroll, A-/A+ persisted, last lyrics cached offline. - Lock screen and headset: ±10 s, position updates on every jump, 512 px local
cover, position 0 honoured, "previous" restarts the track after 3 s, a play
command counts as a gesture for cross-device resume. - Share from the full-screen player and from a local album (native share sheet,
copied link otherwise) with link previews (title, artist, cover) for
messengers and a start time; the video mode is hidden, this is a music player.
Offline (PWA)
- Service-worker audio cache: Range / 206, LRU quota from 500 MB to unlimited,
keys per video id, in-flight de-duplication, the playing track protected
from eviction, list reconciled with the Cache API, eviction broadcast to
every tab. - Offline page: albums, artists and recent views, Play all / Shuffle / Mixtape
(target duration, no artist twice, not heard for 30 days, new seed), per
album state ("9/12 ready") with "Complete", failed downloads with "Retry". - Pinning of tracks and albums (never evicted), persistent storage requested at
the first pin, "Storage protected: yes / no" and usage in Settings. - "Keep offline" on local and YouTube albums, server playlists and favourites:
two downloads at a time then pinning, "9/14 ready" progress, cancel from the
toast, quota respected, survives navigation; "Ready offline" badge on rows
and cards; evicted entries marked "To re-download" with per-row and global
buttons. - Sober first day: a track is cached (and the next one prefetched) only after
a counted listen, with the "Kept offline (N MB)" line; data saver mode
(no prefetch, no automatic cache); auto-cache switch and quota in Settings. - "Free 500 MB" (oldest passing listens first, never pinned tracks, preview
before confirming), "Prepare a pack" by size (100 / 250 / 500 MB) or by
duration (30 min to 4 h) that cancels in under a second and checks the free
space first, "Refresh my pack" (replaces only really listened tracks with
tracks of the same duration, pinned ones untouched), weekend pack card,
"Take 1 h of music" first-day card. - Offline listens queued and sent back when the network returns (idempotent
replay, client timestamp accepted within 7 days and 5 min of the server
clock); "Offline" banner on online pages; account pages explain they need
the server and show the local copy of the favourites. - Installable app named "Musique": maskable icons, manifest shortcuts (Resume,
Offline, Search, For you, Album of the day, Commute pack), Android
share_target(YouTube links, app album links, Spotify / Deezer / Apple
titles sent to search), install prompt at the right moment (after a first
"Keep offline" or the third visit, compact bar after the first sound, 14-day
snooze),/bienvenueinstall page with a QR code generated in the app and
"Send to a friend". - Deployment-safe service worker: the previous version's cache is kept, hashed
files are served from the caches, the update toast ("Reload now") is
deferred while music plays, routes carry the shell ETag so a rollback never
freezes the browser on the new shell, adeploy-survivesprobe replays
update and rollback on an installed profile before any promotion that
touches the worker.
Home and discovery
- Personal rows loaded after the first paint and hidden when empty: Resume
(last track plus the ten last listens), For you (varied: at most two tracks
per album and three per artist), Recently acquired, Never played,
Rediscover (much played more than 60 days ago, forgotten for 30), New from
your artists (last 30 days), "Arrived in ", Album of the day, "An
artist you never played", "Your week" card on Mondays. - An album appears in one row only (fixed priority), at most four personal
rows above the YouTube rows, the rest behind "More for you"; the home is
painted instantly from a local cache (kept up to 24 h of inactivity, warmed
at start-up) then refreshed; it no longer waits for YouTube and retries once
with a "Retry" button. - Guided first visit without dead ends ("Launch a mix", "Tell me your first
name"); the empty search box shows Resume, Trending and the five last
searches. - Mixes by decade, genre, decade x genre and release year (40 sampled tracks),
"In your library" on Explore, Mix button on Explore, "Your artists" and
"Keep offline" on every mix. - Smart queue: skips are recorded, a track skipped twice in 30 days leaves
For you and the continuation, no repeat within 3 hours, shuffle avoids the
same artist twice in a row. - The Related tab is back (YouTube moved it; detected by page type, hidden
when empty); preloading of album / artist / playlist pages on hover or touch.
Statistics
- "Your month" (
/library/stats): listens, minutes, tracks, artists,
favourite hour (24 h histogram), local versus YouTube, top tracks / artists /
albums over 7, 30 or 365 days; a listen counts after 30 s (or half of a short
track), never on a track change. - Listening streaks (current and record), day x hour grid, decades, yearly
view (month, number-one artist and album, distinct albums, new artists),
"Share my week" and "Share my year" with your own numbers only. - IANA time zone for series, grid and year (DST handled), skips purged after
90 days, history over the last 200 listens.
Identity and multi-device
- Sign in by first name (server-side profile); an anonymous local profile keeps
the same features on the device. Giving a first name attaches the device's
history, favourites, follows and playlists to the named profile (never
merges two names, a single adoption even with two tabs, in-flight writes
follow the name); "this device only" banner on History and Stats until then. - Sign in / out seen by every tab (BroadcastChannel), state re-checked when the
page comes back; one login lock per profile with a clear message and an
automatic retry. - Cross-device resume: each device publishes its queue, position and name every
15 s while playing, at pause and when hidden (named profiles only, never
offline); "Resume from : title at m:ss" card on the home (nothing
starts on its own), "Continue here" pauses the other device, device name
editable in Account;PUT/GET /api/v1/me/nowplaying. - Favourites written through one helper to IndexedDB and the server profile;
server playlists (create, add, remove, delete) and follows persist across
devices.
French interface
- The entire interface is in French with the informal address (search, menus,
player, queue, Account, Library, Settings, Explore, error pages),
lang="fr", the app is called "Musique"; only YouTube data stays as it is. - One word per concept (Pour toi, Radio, Mix, Mixtape, Garder hors-ligne),
consistent units (Mo / Go), French error pages per status that never show
raw YouTube text; a structural test prevents English words from returning
on the programme's screens.
Mobile and accessibility
- 44 px touch targets throughout (the 12 px mobile root had collapsed every
rem-based minimum), 16 px gutter, 12 px text floor, full-screen player that
fits 390x844 and 360x780 without scrolling, swipe-down close, queue drawer
reduced to its handle and inert when closed, progress line on the mobile
mini bar. - Contrast at or above 4.9:1 on disabled states and buttons (checked by the
harness), one button system (solid, translucent, text; green reserved for
states), named navigation icons, row thumbnails as "Play
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Unified search over the local library and YouTube, with instant, typo-tolerant