feat(downloads): offline downloads for songs, albums and playlists - #2129
Open
gossip31 wants to merge 1 commit into
Open
feat(downloads): offline downloads for songs, albums and playlists#2129gossip31 wants to merge 1 commit into
gossip31 wants to merge 1 commit into
Conversation
Adds an offline download system to the Electron build. Songs,
albums and playlists can be downloaded via the existing context
menu or via a download button in album/playlist headers, and play
from disk when available.
Main process owns a queue (max 3 concurrent) backed by a manifest
under {userData}/downloads. Files stream to <serverId>/<songId>.<ext>
via electron net.request; failed jobs retry twice on a 4s delay
before surfacing. A new feishin-local:// protocol serves songs back
to the renderer; it streams via createReadStream and rejects any
manifest entry whose relative path escapes the downloads root.
useSongUrl prefers the local URL when a song is in the manifest;
getSongUrl returns the absolute file path so the MPV engine can
play it directly. CSP allows media-src and connect-src for
feishin-local:.
The renderer mirrors the manifest in a zustand store. A floating
panel shows active and queued downloads with per-song progress
plus an aggregate progress bar tracked against a session total so
the bar fills monotonically across a playlist. The dedicated
DOWNLOAD_STATUS table column renders a green check, a ring
progress, a queued clock or a failed glyph per row with a hover
title carrying the size and relative date. The album and playlist
detail headers gain a download button that shows N/M progress and
disables itself mid-download. A new /downloads route lists what's
on disk grouped by album or artist with multi-select delete,
search, sort, and a top-N storage breakdown bar.
Toasts coalesce to one per session: a debounced start notice when
new songs are queued and a single summary on drain ("N songs
downloaded" / "Download failed — title (+M)" / "N downloaded · M
failed"). Failed events that carry the "will retry" marker are
suppressed so retries don't spam.
Settings migration v28 → v29 (idempotent through v30) injects the
new sidebar entry and the DOWNLOAD_STATUS column into existing
persisted layouts (song, playlist-song, queue-song, album-detail,
full-screen, side-queue).
Translation keys live under common.* / setting.* / page.sidebar.*
in en.json; other locales fall back to English until translated.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Author
|
Addresses #1066 |
Owner
|
Thanks for the PR. This might take me a bit of time to review! |
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.
Summary
Adds an offline download system to the Electron build. Songs, albums and playlists can be downloaded via the existing context menu or via a download button in album/playlist detail headers, and play back from disk when available.
Design
Main process owns a queue (3 concurrent) backed by a manifest under
{userData}/downloads. Files stream to<serverId>/<songId>.<ext>via electronnet.request; failed jobs retry up to twice on a 4 s backoff before surfacing as terminal failures.A new
feishin-local://protocol scheme serves songs back to the renderer. The handler streams viacreateReadStream(no whole-file reads) and rejects any manifest entry whose resolved path escapes the downloads root. The scheme is registered withcorsEnabled,secure,standard,stream,supportFetchAPIandbypassCSP; CSP allowsmedia-srcandconnect-srcforfeishin-local:.Player integration:
useSongUrlprefers the local URL when a song is in the manifest.getSongUrlreturns the absolute file path so the MPV engine can play it directly.Renderer state: a zustand store mirrors the manifest.
useDownloadBridgehydrates on mount, reconciles, and listens todownloads-progressevents.UI
DOWNLOAD_STATUStable column rendering a green check, a ring progress, a queued clock or a failed glyph per row with hover tooltips. Wired into song / playlist-song / queue-song / album-detail / full-screen / side-queue tables.N/Mprogress and disables itself mid-download./downloadsroute lists downloaded songs grouped by album or artist with search, sort, multi-select delete, per-group delete, per-row hover delete and a top-N storage breakdown bar.N songs downloaded/Download failed — title (+M)/N downloaded · M failed).(will retry)failures are suppressed.Migration
Settings version
v28 → v29(guard is loose throughv30) injects the new sidebar entry and theDOWNLOAD_STATUScolumn into existing persisted column layouts. DefaultalbumDetailenabled-columns also includes the new column for fresh installs.i18n
New keys live under
common.*,setting.*andpage.sidebar.*inen.json. Other locales fall back to English at runtime until translated.Known limitations / follow-ups
isElectron()and falls back to the existing OS-download path for single songs./downloadsroute is case-sensitive on album/artist strings.en.json; thei18nextextractor config in this repo writes to a non-existent path, so keys were added manually.Test plan
{userData}/downloads/<serverId>/..partis removed, no manifest entry./downloadspage (single, group, multi-select) → file removed from disk, manifest updated, badge clears.