# Data Flow ## Repository Query Flow (Cache-First) ```mermaid sequenceDiagram participant UI as Svelte Component participant Client as RepositoryClient (TS) participant Rust as Tauri Command participant Hybrid as HybridRepository participant Cache as OfflineRepository (SQLite) participant Server as OnlineRepository (HTTP) UI->>Client: getItems(parentId) Client->>Rust: invoke("repository_get_items", {handle, parentId}) Rust->>Hybrid: get_items() par Parallel Racing Hybrid->>Cache: get_items() with 100ms timeout Hybrid->>Server: get_items() (no timeout) end alt Cache returns with content Cache-->>Hybrid: Result with items Hybrid-->>Rust: Return cache result else Cache timeout or empty Server-->>Hybrid: Fresh result Hybrid-->>Rust: Return server result end Rust-->>Client: SearchResult Client-->>UI: items[] Note over UI: Reactive update ``` **Key Points:** - Cache queries have 100ms timeout for responsiveness - Server queries always run for fresh data - Cache wins if it has meaningful content - Automatic fallback to server if cache is empty/stale - Background cache updates (planned) ## Playback Initiation Flow ```mermaid sequenceDiagram participant User participant AudioPlayer participant Tauri as Tauri IPC participant Command as player_play_item() participant Controller as PlayerController participant Backend as PlayerBackend participant Store as Frontend Store User->>AudioPlayer: clicks play AudioPlayer->>Tauri: invoke("player_play_item", {item}) Tauri->>Command: player_play_item() Command->>Command: Convert PlayItemRequest -> MediaItem Command->>Controller: play_item(item) Controller->>Backend: load(item) Note over Backend: State -> Loading Controller->>Backend: play() Note over Backend: State -> Playing Controller-->>Command: Ok(()) Command-->>Tauri: PlayerStatus {state, position, duration, volume} Tauri-->>AudioPlayer: status AudioPlayer->>Store: player.setPlaying(media, position, duration) Note over Store: UI updates reactively ``` ## Playback Mode Transfer Flow ```mermaid sequenceDiagram participant UI as Cast Button participant Store as playbackMode store participant Rust as Tauri Command participant Manager as PlaybackModeManager participant Player as PlayerController participant Jellyfin as Jellyfin API UI->>Store: transferToRemote(sessionId) Store->>Rust: invoke("playback_mode_transfer_to_remote", {sessionId}) Rust->>Manager: transfer_to_remote() Manager->>Player: Get current queue Player-->>Manager: Vec Manager->>Manager: Extract Jellyfin IDs Manager->>Jellyfin: POST /Sessions/{id}/Playing
{itemIds, startIndex} Jellyfin-->>Manager: 200 OK Manager->>Jellyfin: POST /Sessions/{id}/Playing/Seek
{positionTicks} Jellyfin-->>Manager: 200 OK Manager->>Player: stop() Manager->>Manager: mode = Remote {sessionId} Manager-->>Rust: Ok(()) Rust-->>Store: PlaybackMode Store->>UI: Update cast icon ``` ## Queue Navigation Flow ```mermaid flowchart TB User["User clicks Next"] --> Invoke["invoke('player_next')"] Invoke --> ControllerNext["controller.next()"] ControllerNext --> QueueNext["queue.next()
- Check repeat mode
- Check shuffle
- Update history"] QueueNext --> None["None
(at end)"] QueueNext --> Some["Some(next)"] QueueNext --> Same["Same
(repeat one)"] Some --> PlayItem["play_item(next)
Returns new status"] ``` ## Volume Control Flow ```mermaid sequenceDiagram participant User participant Slider as Volume Slider participant Handler as handleVolumeChange() participant Tauri as Tauri IPC participant Command as player_set_volume participant Controller as PlayerController participant Backend as MpvBackend/NullBackend participant Events as playerEvents.ts participant Store as Player Store participant UI User->>Slider: adjusts (0-100) Slider->>Handler: oninput event Handler->>Handler: Convert 0-100 -> 0.0-1.0 Handler->>Tauri: invoke("player_set_volume", {volume}) Tauri->>Command: player_set_volume Command->>Controller: set_volume(volume) Controller->>Backend: set_volume(volume) Backend->>Backend: Clamp to 0.0-1.0 Note over Backend: MpvBackend: Send to MPV loop Backend-->>Tauri: emit "player-event" Tauri-->>Events: VolumeChanged event Events->>Store: player.setVolume(volume) Store-->>UI: Reactive update Note over UI: Both AudioPlayer and
MiniPlayer stay in sync ``` **Key Implementation Details:** - Volume is stored in the backend (NullBackend/MpvBackend) - `PlayerController.volume()` delegates to backend - `get_player_status()` returns `controller.volume()` (not hardcoded) - Frontend uses normalized 0.0-1.0 scale, UI shows 0-100