commit cfddc1edea70307cc101a6cc9e45a5f622ba6220 Author: Duncan Tourolle Date: Mon Jan 26 22:21:54 2026 +0100 First working POC diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..396c52d --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# OS files +.DS_Store +Thumbs.db + +# Node.js +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Build output +/build +/dist +/.svelte-kit +/package + +# Environment variables +.env +.env.* +!.env.example + +# Testing +coverage +.nyc_output +*.lcov + +# WebdriverIO E2E tests +e2e/logs/ +e2e/screenshots/ +wdio-*.log + +# Vitest +.vitest + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +# IDE +.idea +.vscode +*.swp +*.swo +*~ + +# Logs +logs +*.log diff --git a/PRELOADING.md b/PRELOADING.md new file mode 100644 index 0000000..c945ebb --- /dev/null +++ b/PRELOADING.md @@ -0,0 +1,212 @@ +# 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 settings +- `player_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` +1. **On playback start** - When state changes to "playing" +2. **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 + +```typescript +{ + queuePrecacheEnabled: true, + queuePrecacheCount: 3, + albumAffinityEnabled: true, + albumAffinityThreshold: 3, + storageLimit: 10737418240, // 10GB + wifiOnly: false +} +``` + +### Updating Configuration + +```typescript +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` - Added `get_upcoming()` method +- `src-tauri/src/download/cache.rs` - Made `CacheConfig` serializable, updated defaults +- `src-tauri/src/commands/player.rs` - Added preload commands and `SmartCacheWrapper` +- `src-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 +```bash +cd src-tauri +cargo test queue::tests::test_get_upcoming +cargo test cache::tests::test_default_config +``` + +All tests pass ✅ + +### Manual Testing + +1. **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 + +2. **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) + +3. **Repeat mode** + - Enable Repeat All + - Play to end of queue + - Verify wraps around and continues preloading + +4. **Already downloaded** + - Download all tracks in an album + - Play the album + - Check logs show: `already_downloaded: 3, queued: 0` + +## Future Enhancements + +1. **Album Affinity** - If user plays 3+ tracks from an album, auto-download the rest +2. **WiFi Detection** - Respect `wifi_only` setting on mobile +3. **Storage Management** - Auto-evict LRU items when storage limit reached +4. **Smart Priority** - Boost priority as track gets closer in queue +5. **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: `queuePrecacheEnabled` should 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 `queuePrecacheCount` in config +- Enable `wifiOnly` mode +- 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). diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ffe688 --- /dev/null +++ b/README.md @@ -0,0 +1,495 @@ +# JellyTau + +A cross-platform Jellyfin client built with Tauri, SvelteKit, and TypeScript. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer). + +--- + +# Requirements Specification + +## 1. User Requirements + +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| UR-001 | Run the app on multiple platforms (Linux, Android) | High | In Progress | +| UR-002 | Access media when online or offline | High | Done | +| UR-003 | Play videos | High | Planned | +| UR-004 | Play audio uninterrupted | High | Planned | +| UR-005 | Control media playback (pause, play, skip, scrub) | High | In Progress | +| UR-006 | Control media when device is on lock screen or via BLE headsets | Medium | Planned | +| UR-007 | Navigate media in library | High | Done | +| UR-008 | Search media across libraries | High | Done | +| UR-009 | Connect to Jellyfin to access media | High | Done | +| UR-010 | Control playback of Jellyfin remote sessions | Low | Planned | +| UR-011 | Download media on demand | Medium | Done | +| UR-012 | Login info shall be stored securely and persistently | High | Done | +| UR-013 | View and manage downloaded media | Medium | Done | +| UR-014 | Make and edit playlists of music that sync back to Jellyfin | Medium | Planned | +| UR-015 | View and manage current audio queue (add, reorder tracks) | Medium | Done | +| UR-016 | Change system settings while playing (brightness, volume) | Low | Planned | +| UR-017 | Like or unlike audio, albums, movies, etc. | Medium | Done | +| UR-018 | Choose to download series, albums, songs, artist discography | Medium | Done | +| UR-019 | Resume playback from where you left off (movies, shows, albums) | High | Done | +| UR-020 | Select subtitles for video content | High | Planned | +| UR-021 | Select audio track for video content | High | Planned | +| UR-022 | Control streaming quality and transcoding settings | Medium | Planned | +| UR-023 | View "Next Up" / Continue Watching on home screen; auto-play next episode with countdown popup | Medium | In Progress | +| UR-024 | View recently added content on server | Medium | Planned | +| UR-025 | Sync watch history and progress back to Jellyfin | High | Done | +| UR-026 | Sleep timer for audio playback | Low | Planned | +| UR-027 | Audio equalizer for sound customization | Low | Planned | +| UR-028 | Navigate to artist/album by tapping names in now playing view | High | Done | +| UR-029 | Toggle between grid and list view in library | Medium | Done | +| UR-030 | Quick genre browsing and filtering | Medium | Done | +| UR-031 | Crossfade between audio tracks | Low | Planned (Linux only) | +| UR-032 | Gapless playback for seamless album listening | Medium | Done (Linux only) | +| UR-033 | Volume normalization to prevent volume jumps between tracks | Low | Done (Linux only) | +| UR-034 | Rich home screen with hero banners, carousels, and personalized sections | High | Planned | +| UR-035 | View cast/crew (actors, directors) on movie/show detail pages | High | Planned | +| UR-036 | Navigate to actor/person page showing their filmography | Medium | Planned | +| UR-037 | Visually appealing video library with poster grids and metadata | High | Planned | +| UR-038 | Movie/show detail page with backdrop, ratings, and rich metadata | High | Planned | +| UR-039 | Navigate between main sections via bottom navigation bar | High | In Progress | + +--- + +## 2. Software Requirements + +### 2.1 Integration Requirements + +External system integrations and platform-specific implementations. + +| ID | Requirement | Category | Traces To | Status | +|----|-------------|----------|-----------|--------| +| IR-001 | Build system supporting multiple targets (Linux, Android) | Build | UR-001 | Done | +| IR-002 | Build scripts for Android and Linux | Build | UR-001 | Done | +| IR-003 | Integration of libmpv for Linux playback | Playback | UR-003, UR-004 | In Progress | +| IR-004 | Integration of ExoPlayer for Android playback | Playback | UR-003, UR-004 | In Progress (basic playback works, audio settings missing) | +| IR-005 | MPRIS D-Bus integration for Linux lockscreen/media controls | Platform | UR-006 | Planned | +| IR-006 | Android MediaSession integration for lockscreen controls | Platform | UR-006 | In Progress | +| IR-007 | Bluetooth AVRCP integration via system media session | Platform | UR-006 | Planned | +| IR-008 | Android audio focus handling (pause on call) | Platform | UR-004, UR-006 | In Progress | +| IR-009 | Jellyfin API client for authentication | API | UR-009, UR-012 | Done | +| IR-010 | Jellyfin API client for library browsing | API | UR-007, UR-008 | Done | +| IR-011 | Jellyfin API client for playback streaming | API | UR-003, UR-004 | Done | +| IR-012 | Jellyfin Sessions API for remote playback control | API | UR-010 | Planned | +| IR-021 | Android MediaRouter integration for remote volume in system panel | Platform | UR-010, UR-016 | Planned | +| IR-013 | SQLite integration for local database | Storage | UR-002, UR-011 | Done | +| IR-014 | Secure credential storage (keyring/keychain) | Security | UR-012 | Done | +| IR-015 | Jellyfin API client for playback progress reporting | API | UR-019, UR-025 | Done | +| IR-016 | Jellyfin API client for subtitle/audio track info | API | UR-020, UR-021 | Planned | +| IR-017 | Jellyfin API client for transcoding parameters | API | UR-022 | Planned | +| IR-018 | libmpv subtitle rendering and selection | Playback | UR-020 | Planned | +| IR-019 | libmpv audio track selection | Playback | UR-021 | Planned | +| IR-020 | libmpv/ExoPlayer equalizer integration | Playback | UR-027 | Planned | +| IR-022 | Jellyfin API client for person/cast data | API | UR-035, UR-036 | Planned | +| IR-023 | Database schema for person/cast caching | Storage | UR-035, UR-036 | Planned | +| IR-024 | Jellyfin API client for home screen data (featured, continue watching) | API | UR-034 | Planned | + +### 2.2 Jellyfin API Requirements + +API endpoints and data contracts required for Jellyfin integration. + +| ID | Requirement | Endpoint Category | Traces To | Status | +|----|-------------|-------------------|-----------|--------| +| JA-001 | Server connection and discovery | System | UR-009 | Done | +| JA-002 | User authentication (username/password) | Users | UR-009, UR-012 | Done | +| JA-003 | Get user library views | UserViews | UR-007 | Done | +| JA-004 | Get library items (paginated) | Items | UR-007 | Done | +| JA-005 | Get item details and metadata | Items | UR-007 | Done | +| JA-006 | Search across libraries | Items | UR-008 | Done | +| JA-007 | Get playback info and stream URL | MediaInfo | UR-003, UR-004 | Done | +| JA-008 | Get available subtitles for item | MediaInfo | UR-020 | Planned | +| JA-009 | Get available audio tracks for item | MediaInfo | UR-021 | Planned | +| JA-010 | Report playback start | Sessions | UR-025 | Done | +| JA-011 | Report playback progress (periodic) | Sessions | UR-025 | Done | +| JA-012 | Report playback stopped | Sessions | UR-025 | Done | +| JA-013 | Get resume position for item | UserData | UR-019 | Done | +| JA-014 | Get "Next Up" items | Shows | UR-023 | Planned | +| JA-015 | Get "Continue Watching" items | Items | UR-023 | Planned | +| JA-016 | Get recently added items | Items | UR-024 | Planned | +| JA-017 | Mark item as favorite | UserData | UR-017 | Done | +| JA-018 | Remove item from favorites | UserData | UR-017 | Done | +| JA-019 | Get/create/update playlists | Playlists | UR-014 | Planned | +| JA-020 | Add/remove items from playlist | Playlists | UR-014 | Planned | +| JA-021 | Get active sessions list | Sessions | UR-010 | Planned | +| JA-022 | Send playback commands to remote session (play/pause/stop) | Sessions | UR-010 | Planned | +| JA-023 | Send seek command to remote session | Sessions | UR-010 | Planned | +| JA-024 | Send next/previous track commands to remote session | Sessions | UR-010 | Planned | +| JA-025 | Play specific item on remote session | Sessions | UR-010 | Planned | +| JA-026 | Send volume/mute commands to remote session | Sessions | UR-010 | Planned | +| JA-027 | Get transcoding options | MediaInfo | UR-022 | Planned | +| JA-028 | Get image/artwork URLs | Images | UR-007 | Done | +| JA-029 | Get cast/crew for item (actors, directors) | Items | UR-035 | Planned | +| JA-030 | Get person details and filmography | Persons | UR-036 | Planned | +| JA-031 | Get items by person (actor/director filmography) | Items | UR-036 | Planned | + +### 2.3 Development Requirements + +Internal architecture, components, and application logic. + +| ID | Requirement | Category | Traces To | Status | +|----|-------------|----------|-----------|--------| +| DR-001 | Player state machine (idle, loading, playing, paused, seeking, error) | Player | UR-005 | Done | +| DR-002 | MediaItem struct tracking source, location, duration, metadata | Player | UR-003, UR-004 | Done | +| DR-003 | Source-agnostic media abstraction (Remote, Local, DirectUrl) | Player | UR-002, UR-011 | Done | +| DR-004 | PlayerBackend trait for platform-agnostic playback | Player | UR-003, UR-004 | Done | +| DR-005 | Queue manager with shuffle, repeat, history | Player | UR-005, UR-015 | Done | +| DR-006 | Audio pre-caching for seamless track transitions | Player | UR-004 | Planned | +| DR-007 | Library browsing screens (grid view, search, filters) | UI | UR-007, UR-008 | Done | +| DR-008 | Album/Series detail view with track listing | UI | UR-007 | Done | +| DR-009 | Audio player UI (mini player, full screen) | UI | UR-005 | Done | +| DR-010 | Video player UI (fullscreen, controls overlay) | UI | UR-003, UR-005 | Planned | +| DR-011 | Search bar with cross-library search | UI | UR-008 | Done | +| DR-012 | Local database for media metadata cache | Storage | UR-002 | Done | +| DR-013 | Repository pattern for online/offline data access | Storage | UR-002 | Done | +| DR-014 | Offline mutation queue for sync-back operations | Storage | UR-002, UR-014, UR-017 | Planned | +| DR-015 | Download manager with queue and progress tracking | Storage | UR-011, UR-018 | Done | +| DR-016 | Thumbnail caching and sync with server | Storage | UR-007 | Done | +| DR-017 | "Manage Downloads" screen for local media management | UI | UR-013 | Done | +| DR-018 | Download buttons on library/album/player screens | UI | UR-011, UR-018 | Done | +| DR-019 | Playlist creation and editing UI | UI | UR-014 | Planned | +| DR-020 | Queue management UI (add, remove, reorder) | UI | UR-015 | Done | +| DR-021 | Like/favorite functionality on media items | UI | UR-017 | Done | +| DR-022 | Resume position tracking and restoration on play | Player | UR-019 | Done | +| DR-023 | Subtitle selection UI in video player | UI | UR-020 | Planned | +| DR-024 | Audio track selection UI in video player | UI | UR-021 | Planned | +| DR-025 | Quality/transcoding settings UI | UI | UR-022 | Planned | +| DR-026 | "Continue Watching" / "Next Up" home section | UI | UR-023 | Planned | +| DR-027 | "Recently Added" home section | UI | UR-024 | Planned | +| DR-028 | Playback progress sync service (periodic reporting) | Player | UR-025 | Done | +| DR-029 | Sleep timer with countdown and auto-stop | Player | UR-026 | Planned | +| DR-030 | Equalizer UI with presets and custom bands | UI | UR-027 | Planned | +| DR-031 | Clickable artist/album links in now playing view | UI | UR-028 | Done | +| DR-032 | List view option for library browsing (albums, artists) | UI | UR-029 | Done | +| DR-033 | Genre browsing screen with quick filters | UI | UR-030 | Done | +| DR-034 | Crossfade engine with configurable duration (0-12s) | Player | UR-031 | Planned | +| DR-035 | Gapless playback between sequential tracks | Player | UR-032 | Done | +| DR-036 | Volume normalization with preset levels (Loud/Normal/Quiet) | Player | UR-033 | Done | +| DR-037 | Remote session browser and control UI | UI | UR-010 | Planned | +| DR-038 | Home screen with hero banner carousel (featured/continue watching) | UI | UR-034 | Planned | +| DR-039 | Home screen horizontal carousels (recently added, recommendations) | UI | UR-034, UR-024 | Planned | +| DR-040 | Cast/crew section on movie/show detail pages | UI | UR-035 | Planned | +| DR-041 | Person/actor detail page with filmography grid | UI | UR-036 | Planned | +| DR-042 | Video library grid with poster cards, year, and rating badges | UI | UR-037 | Planned | +| DR-043 | Movie/show detail page with backdrop hero, synopsis, and metadata | UI | UR-038 | Planned | +| DR-044 | Horizontal scrolling actor/cast row with profile images | UI | UR-035 | Planned | +| DR-045 | Bottom navigation bar with Home, Library, Search buttons | UI | UR-039 | In Progress | +| DR-046 | Dedicated search page with input and results | UI | UR-039 | In Progress | +| DR-047 | Next episode auto-play popup with configurable countdown | Player | UR-023 | In Progress | +| DR-048 | Video settings (auto-play toggle, countdown duration) | Settings | UR-023, UR-026 | In Progress | + +--- + +## 3. Traceability Matrix + +### User Requirements to Software Requirements + +| User Req | Integration Requirements | Development Requirements | +|----------|-------------------------|-------------------------| +| UR-001 | IR-001, IR-002 | - | +| UR-002 | IR-013 | DR-003, DR-012, DR-013, DR-014 | +| UR-003 | IR-003, IR-004, IR-011 | DR-002, DR-004, DR-010 | +| UR-004 | IR-003, IR-004, IR-008, IR-011 | DR-002, DR-004, DR-006 | +| UR-005 | - | DR-001, DR-005, DR-009 | +| UR-006 | IR-005, IR-006, IR-007, IR-008 | - | +| UR-007 | IR-010 | DR-007, DR-008, DR-016 | +| UR-008 | IR-010 | DR-007, DR-011 | +| UR-009 | IR-009, IR-010, IR-011 | - | +| UR-010 | IR-012, IR-021 | DR-037 | +| UR-011 | IR-013 | DR-003, DR-015, DR-018 | +| UR-012 | IR-009, IR-014 | - | +| UR-013 | IR-013 | DR-017 | +| UR-014 | - | DR-014, DR-019 | +| UR-015 | - | DR-005, DR-020 | +| UR-016 | - | - | +| UR-017 | - | DR-014, DR-021 | +| UR-018 | IR-013 | DR-015, DR-018 | +| UR-019 | IR-015 | DR-022 | +| UR-020 | IR-016, IR-018 | DR-023 | +| UR-021 | IR-016, IR-019 | DR-024 | +| UR-022 | IR-017 | DR-025 | +| UR-023 | IR-010 | DR-026, DR-047, DR-048 | +| UR-024 | IR-010 | DR-027 | +| UR-025 | IR-015 | DR-028 | +| UR-026 | - | DR-029, DR-048 | +| UR-027 | IR-020 | DR-030 | +| UR-028 | - | DR-031 | +| UR-029 | - | DR-032 | +| UR-030 | IR-010 | DR-033 | +| UR-031 | - | DR-034 | +| UR-032 | - | DR-035 | +| UR-033 | - | DR-036 | +| UR-034 | IR-010, IR-024 | DR-038, DR-039 | +| UR-035 | IR-022, IR-023 | DR-040, DR-044 | +| UR-036 | IR-022, IR-023 | DR-041 | +| UR-037 | IR-010 | DR-042 | +| UR-038 | IR-010 | DR-043 | +| UR-039 | - | DR-045, DR-046 | + +--- + +## 4. Test Traceability + +### Unit Tests to Software Requirements + +| Test ID | Test Description | Traces To | Status | +|---------|-----------------|-----------|--------| +| UT-001 | Player state transitions | DR-001 | Pending | +| UT-002 | MediaItem source URL resolution | DR-002, DR-003 | Pending | +| UT-003 | Queue next/previous navigation | DR-005 | Pending | +| UT-004 | Queue shuffle order generation | DR-005 | Pending | +| UT-005 | Queue repeat mode behavior | DR-005 | Pending | +| UT-006 | Jellyfin authentication flow | IR-009 | Pending | +| UT-007 | Jellyfin library items parsing | IR-010 | Pending | +| UT-008 | Repository pattern online/offline switching | DR-013 | Pending | +| UT-009 | Offline mutation queue persistence | DR-014 | Pending | +| UT-010 | Download queue management | DR-015 | Done | +| UT-011 | Resume position storage and retrieval | DR-022 | Pending | +| UT-012 | Sleep timer countdown logic | DR-029 | Pending | +| UT-013 | Playback progress reporting throttling | DR-028 | Pending | +| UT-014 | Database open and in-memory mode | IR-013, DR-012 | Done | +| UT-015 | Database migrations run successfully | IR-013, DR-012 | Done | +| UT-016 | All database tables created | IR-013, DR-012 | Done | +| UT-017 | FTS5 search table created | IR-013, DR-012 | Done | +| UT-018 | Server CRUD operations | IR-013, DR-012 | Done | +| UT-019 | User CRUD operations | IR-013, DR-012 | Done | +| UT-020 | Cascade delete server removes users | IR-013, DR-012 | Done | +| UT-021 | Item insert and FTS search | IR-013, DR-012 | Done | +| UT-022 | User data playback position storage | IR-013, DR-012, DR-022 | Done | +| UT-023 | Sync queue operations | IR-013, DR-014 | Done | +| UT-024 | Downloads table operations | IR-013, DR-015 | Done | +| UT-025 | Migrations are idempotent | IR-013, DR-012 | Done | +| UT-026 | NullBackend volume default value | DR-004 | Done | +| UT-027 | NullBackend set volume | DR-004 | Done | +| UT-028 | NullBackend volume clamping (high/low) | DR-004 | Done | +| UT-029 | NullBackend volume boundary values | DR-004 | Done | +| UT-030 | PlayerController volume default | DR-004, DR-009 | Done | +| UT-031 | PlayerController set volume | DR-004, DR-009 | Done | +| UT-032 | PlayerController muted default | DR-004, DR-009 | Done | +| UT-033 | PlayerController volume delegates to backend | DR-004, DR-009 | Done | +| UT-034 | Download event serialization roundtrip | DR-015 | Done | +| UT-035 | Download event completed serialization | DR-015 | Done | +| UT-036 | Download event failed serialization | DR-015 | Done | +| UT-037 | Download worker exponential backoff | DR-015 | Done | +| UT-038 | Download worker error retryable check | DR-015 | Done | +| UT-039 | Download manager creation | DR-015 | Done | +| UT-040 | Download manager set max concurrent | DR-015 | Done | +| UT-041 | Download info serialization | DR-015 | Done | +| UT-042 | Download command filename sanitization | DR-015, DR-018 | Done | +| UT-043 | Download command filename extension preservation | DR-015, DR-018 | Done | +| UT-044 | Offline item serialization | DR-017 | Done | +| UT-045 | Smart cache default config | DR-015 | Done | +| UT-046 | Smart cache album affinity tracking | DR-015 | Done | +| UT-047 | Smart cache queue precache config | DR-015 | Done | +| UT-048 | Smart cache storage limit check | DR-015 | Done | + +### Integration Tests + +| Test ID | Test Description | Traces To | Status | +|---------|-----------------|-----------|--------| +| IT-001 | End-to-end authentication with Jellyfin server | IR-009, UR-009 | Pending | +| IT-002 | Library browsing and item loading | IR-010, UR-007 | Pending | +| IT-003 | Audio playback via libmpv | IR-003, UR-004 | Pending | +| IT-004 | Video playback via libmpv | IR-003, UR-003 | Pending | +| IT-005 | MPRIS lockscreen controls on Linux | IR-005, UR-006 | Pending | +| IT-006 | Offline mode with local database | IR-013, UR-002 | Pending | +| IT-007 | Media download and local playback | DR-015, UR-011 | Pending | +| IT-008 | Subtitle track selection via libmpv | IR-018, UR-020 | Pending | +| IT-009 | Audio track selection via libmpv | IR-019, UR-021 | Pending | +| IT-010 | Playback progress sync to Jellyfin | IR-015, UR-025 | Pending | +| IT-011 | Resume playback from server position | IR-015, UR-019 | Pending | +| IT-012 | Equalizer bands via libmpv | IR-020, UR-027 | Pending | + +--- + +## 5. Development Commands + +```bash +# Activate Rust environment (fish shell) +source "$HOME/.cargo/env.fish" + +# Install dependencies +bun install + +# Development +bun run tauri dev + +# Type checking +bun run check + +# Build for Linux +bun run tauri build + +# Build for Android +bun run tauri android build +``` + +--- + +## 6. Architecture Overview + +``` +jellytau/ +├── src/ # Svelte frontend +│ ├── lib/ +│ │ ├── api/ # Jellyfin API client (repository pattern) +│ │ ├── components/ # UI components (player, library) +│ │ └── stores/ # Svelte stores (auth, library, player, queue) +│ └── routes/ # SvelteKit pages +├── src-tauri/ # Rust backend +│ ├── src/ +│ │ ├── commands/ # Tauri commands +│ │ └── player/ # Player architecture +│ │ ├── state.rs # State machine +│ │ ├── media.rs # MediaItem, MediaSource +│ │ ├── queue.rs # Queue management +│ │ └── backend.rs # PlayerBackend trait +│ └── gen/android/ # Android project +└── README.md +``` + +--- + +## 7. Technical Debt + +### Linux Keyring Integration Workaround + +**Issue**: The `keyring-rs` crate (v3.x) has issues with retrieving credentials from the Linux Secret Service API, despite successfully saving them. + +**Symptoms**: +- Credentials are saved to the system keyring successfully (verified with `secret-tool search`) +- Retrieval via the `keyring-rs` library fails with `NoEntry` error +- Session restoration fails on app restart even though credentials exist + +**Root Cause**: +The `keyring-rs` library's Linux backend doesn't correctly retrieve entries from the Secret Service that it previously stored. This appears to be a bug in how the library interfaces with the Secret Service D-Bus API. + +**Current Workaround**: +We bypass the `keyring-rs` library on Linux and use direct system calls to `secret-tool`: +- **Save**: `secret-tool store --label