Skip to content

add audio prefetch cache with sliding window pre-downloads#46

Merged
nyakuoff merged 9 commits intonyakuoff:mainfrom
ssantss:feature/prefetch-cache
Mar 9, 2026
Merged

add audio prefetch cache with sliding window pre-downloads#46
nyakuoff merged 9 commits intonyakuoff:mainfrom
ssantss:feature/prefetch-cache

Conversation

@ssantss
Copy link
Copy Markdown
Contributor

@ssantss ssantss commented Mar 3, 2026

Summary

  • Adds an optional prefetch cache that pre-downloads upcoming tracks to disk for uninterrupted playback
  • Sliding window mechanism: caches current track + N tracks ahead (configurable: 1/3/5/10 or entire queue)
  • New prefetchCount setting in Settings > Playback (Off by default), persisted to localStorage and cloud synced
  • 4 new IPC handlers for background audio downloads via yt-dlp
  • Cached count badge ("3 cached") displayed in the queue Up Next header
  • Full i18n support across all 12 languages

Implementation Details

  • Module: self-contained IIFE prefetch-cache.js with public API (getCachedPath, onTrackChanged, clear, destroy, etc.)
  • Generation counter: invalidates stale async download loops when queue mutations occur, preventing race conditions and file leaks
  • Sliding window: includes current track (prevents eviction during playback) + N upcoming tracks. Window recalculates on track change or setting change
  • Sequential downloads: one-at-a-time queue, respects audio quality preference, skips already-cached tracks
  • Playback integration: playTrack() checks cache before fetching from network; pathToFileUrl() converts paths to file:// URLs (cross-platform with backslash normalization for
    Windows)
  • Queue hooks: every queue mutation calls onTrackChanged() or clear() (play, shuffle, add, remove, load state)

UI Changes

  • Settings > Playback: new "Prefetch cache" select (Off / 1 track / 3 tracks / 5 tracks / 10 tracks / Entire queue) with experimental badge
  • Queue header: "Up Next" shows a cached count pill (e.g. "3 cached") when prefetch is active
Grabacion.de.pantalla.desde.2026-03-03.15-23-48.mp4

Testing

  • Enable prefetch in Settings > Playback > Prefetch cache (e.g. "3 tracks")
  • Play a track — verify upcoming tracks start downloading in background
  • Check "Up Next" header shows cached count badge (e.g. "2 cached")
  • Skip forward — old tracks get evicted, new ones download automatically
  • Disconnect network after caching — cached tracks play without interruption
  • Enable shuffle — prefetch clears and restarts with new order
  • Set prefetch to "Entire queue" — all tracks in queue get cached
  • Set prefetch to "Off" — cache cleared, badge disappears
  • Close and reopen app — prefetch setting persists
  • Sign in on two devices — prefetch setting syncs via cloud

Notes

  • Works seamlessly with the crossfade engine — cached files use the same audio pipeline as network streams
  • No conflicts with loudness normalization or Discord RPC
  • Partial files are cleaned up on SIGTERM; current track is never evicted during playback
  • If a cached file is deleted externally, getCachedPath() returns null and falls back to networ

ssantss and others added 9 commits February 27, 2026 15:53
Downloads upcoming tracks to disk via yt-dlp so playback continues
even without internet. Configurable window size (Off/1/3/5/10/Entire
queue) in settings with EXPERIMENTAL tag. Sequential downloads,
automatic eviction on track change, cache invalidation on quality
change, and full cleanup on app quit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Trigger onTrackChanged on startup when queue exists (fixes no
  downloads until setting is toggled)
- Sync prefetch state after cloud load
- Add cached track indicator (SVG icon) in queue artist line
- Add onCacheUpdateCb for live DOM updates without full re-render
- Remove redundant --extract-audio flag from yt-dlp download

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap the SVG download icon for a simple 6px accent-colored dot next
to the artist name in queue items. Update settings description to
explain the dot meaning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rors

- Fix currently-playing track file deleted mid-playback (include current
  track in cache window to prevent eviction while audio is using it)
- Clean up partial files after SIGTERM cancel (--no-part leaves corrupt
  files that passed the existence check, causing broken playback)
- Add generation counter to prevent concurrent _processQueue loops
  (clear() + immediate onTrackChanged() caused race condition)
- Fix _activeDownloadProc callback clobbering new process reference
- Add pathToFileUrl() helper for correct Windows file:// URLs
- Fix path traversal in cache:deleteFile (add path.sep to startsWith)
- Use getState().queue instead of stale captured queue reference
- Replace per-track dot indicator with global counter pill badge
- Add missing prefetch hooks for clear queue, remove item, drag reorder,
  and Start Radio skip-restart (×3)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolved 5 conflicts:
- 3x start-radio: use main's startRadio() helper with I18n
- playTrack: keep prefetch cache lookup + I18n toast
- queue header: wrap data-i18n in span to preserve cached count
- Add queue.cached translation key to all 12 locales
- Add data-i18n attributes to prefetch settings label, description,
  and all 6 select options in index.html
- Add 8 translation keys to all 12 locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts in app.js (state defaults/saveState/loadState/cloudSync),
main.js (CSP: keep both http: and file: in media-src), and 11 locale
files (keep both prefetch + plugin i18n keys).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ssantss
Copy link
Copy Markdown
Contributor Author

ssantss commented Mar 7, 2026

Don't forget to check this

@nyakuoff
Copy link
Copy Markdown
Owner

nyakuoff commented Mar 7, 2026

Hey! I've been busy with work lately, I will handle this PR and the currently open issues tomorrow

@nyakuoff nyakuoff merged commit 793ca27 into nyakuoff:main Mar 9, 2026
@ssantss ssantss deleted the feature/prefetch-cache branch March 30, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants