• v1.0.0 96b55e047d

    beatbump v1.0.0
    All checks were successful
    CI / Web (vitest + svelte-check ceiling) (push) Successful in 1m3s
    CI / Shell (shellcheck) (push) Successful in 21s
    CI / Python (py_compile + ruff) (push) Successful in 14s
    CI / Harness headers (X-Ytm-Harness on every Playwright context) (push) Successful in 10s
    CI / Compose (deploy/compose.yml config) (push) Successful in 14s
    CI / Go (vet + test) (push) Successful in 2m11s
    Release / Build and push images (push) Successful in 2m3s
    Release / Forgejo release (push) Successful in 11s
    Stable

    ekaii-bot released this 2026-10-06 12:12:49 +00:00 | 0 commits to main since this release

    First 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, /aud to 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.json errors ({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), /bienvenue install 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, a deploy-survives probe 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