6.4 KiB
Smart Preloading Implementation
This document describes the smart preloading system that automatically queues downloads for upcoming tracks in the playback queue.
Overview
The preloading system monitors playback and automatically queues background downloads for the next 3 tracks in the queue. This ensures smooth playback transitions and offline availability without requiring manual downloads.
Architecture
Backend (Rust)
Smart Cache Engine - /src-tauri/src/download/cache.rs
- Manages preload configuration
- Default settings: preload 3 tracks, works on any connection (not wifi-only)
- Storage limit: 10GB
- Album affinity tracking (future feature)
Queue Manager - /src-tauri/src/player/queue.rs
- New method:
get_upcoming(count)returns next N tracks - Respects shuffle order
- Handles repeat modes (Off, All, One)
- Wraps around when RepeatMode::All is enabled
Preload Command - /src-tauri/src/commands/player.rs
player_preload_upcoming- Main preload endpoint- Checks SmartCache configuration
- Gets upcoming tracks from queue
- Skips already downloaded/queued items
- Queues new downloads with low priority (-100)
- Returns stats: queued_count, already_downloaded, skipped
Configuration Commands
player_set_cache_config- Update preload settingsplayer_get_cache_config- Get current settings
Frontend (TypeScript/Svelte)
Preload Service - /src/lib/services/preload.ts
- Main function:
preloadUpcomingTracks() - Automatically gets current user ID from auth store
- Calls backend preload command
- Fails silently - never interrupts playback
- Logs meaningful results only
Integration Points - /src/lib/services/playerEvents.ts
- On playback start - When state changes to "playing"
- On track advance - After successfully advancing to next track
How It Works
Playback Flow
User plays track/queue
↓
Backend starts playback
↓
Emits "state_changed" event with "playing"
↓
playerEvents.handleStateChanged() catches event
↓
Calls preloadUpcomingTracks()
↓
Backend queues downloads for next 3 tracks (if not already downloaded)
Track Advance Flow
Track ends (or user clicks next)
↓
playerEvents.handlePlaybackEnded() or manual next()
↓
Calls player_next backend command
↓
Backend plays next track, emits "state_changed"
↓
Calls preloadUpcomingTracks() again
↓
Queue is shifted forward, new track gets preloaded
Configuration
Default Settings
{
queuePrecacheEnabled: true,
queuePrecacheCount: 3,
albumAffinityEnabled: true,
albumAffinityThreshold: 3,
storageLimit: 10737418240, // 10GB
wifiOnly: false
}
Updating Configuration
import { updateCacheConfig } from '$lib/services/preload';
await updateCacheConfig({
queuePrecacheCount: 5, // Preload 5 tracks instead of 3
wifiOnly: true // Only preload on WiFi
});
Features
Intelligent Queueing
- ✅ Checks if tracks are already downloaded
- ✅ Skips tracks already in download queue
- ✅ Low priority (-100) so user-initiated downloads go first
- ✅ Respects shuffle and repeat modes
- ✅ No duplicate downloads
Offline First
- ✅ Existing
create_media_item()in player.rs checks local downloads first - ✅ Preloading ensures next tracks become local over time
- ✅ Seamless offline playback without manual intervention
Non-Intrusive
- ✅ Background operation - never blocks playback
- ✅ Fails silently - errors are logged but don't affect UX
- ✅ Automatic - no user interaction required
- ✅ Configurable - users can adjust or disable
Files Changed
Backend
src-tauri/src/player/queue.rs- Addedget_upcoming()methodsrc-tauri/src/download/cache.rs- MadeCacheConfigserializable, updated defaultssrc-tauri/src/commands/player.rs- Added preload commands andSmartCacheWrappersrc-tauri/src/lib.rs- Initialized SmartCache, registered commands
Frontend
src/lib/services/preload.ts- New preload service (created)src/lib/services/playerEvents.ts- Integrated preload triggers
Configuration
src-tauri/Cargo.toml- Added tempfile dev dependency for tests
Testing
Rust Tests
cd src-tauri
cargo test queue::tests::test_get_upcoming
cargo test cache::tests::test_default_config
All tests pass ✅
Manual Testing
-
Start playback
- Play a queue of 5+ tracks
- Check console for:
[Preload] Queued N track(s) for background download - Verify download queue shows 3 pending downloads with priority -100
-
Track advance
- Let track finish or click next
- Check console for new preload log
- Verify queue shifts (old track 2 becomes current, new track gets queued)
-
Repeat mode
- Enable Repeat All
- Play to end of queue
- Verify wraps around and continues preloading
-
Already downloaded
- Download all tracks in an album
- Play the album
- Check logs show:
already_downloaded: 3, queued: 0
Future Enhancements
- Album Affinity - If user plays 3+ tracks from an album, auto-download the rest
- WiFi Detection - Respect
wifi_onlysetting on mobile - Storage Management - Auto-evict LRU items when storage limit reached
- Smart Priority - Boost priority as track gets closer in queue
- Bandwidth Throttling - Limit download speed to not interfere with streaming
Troubleshooting
Preload not working
- Check console for
[Preload]logs - Verify user is logged in:
auth.getUserId()returns value - Check SmartCache config:
queuePrecacheEnabledshould be true
Downloads not starting
- Preload only queues downloads, doesn't start them
- Check download manager is processing queue
- Verify backend has download worker running
Too many downloads
- Reduce
queuePrecacheCountin config - Enable
wifiOnlymode - Adjust
storageLimit
Performance Impact
- Minimal - Background downloads use low priority
- Non-blocking - Async operation, no playback delay
- Bandwidth-friendly - Only downloads when needed
- Storage-aware - Respects configured limits
Summary
Smart preloading transforms JellyTau into an offline-first music player. By automatically queueing downloads for upcoming tracks, it ensures seamless playback and offline availability without requiring users to manually manage downloads. The system is intelligent (checks what's already downloaded), non-intrusive (fails silently), and configurable (users can adjust or disable).