Split software arch desc for easier manintenance. Many fixes related to next video playing and remote playback
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
# 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<MediaItem>
|
||||
Manager->>Manager: Extract Jellyfin IDs
|
||||
|
||||
Manager->>Jellyfin: POST /Sessions/{id}/Playing<br/>{itemIds, startIndex}
|
||||
Jellyfin-->>Manager: 200 OK
|
||||
|
||||
Manager->>Jellyfin: POST /Sessions/{id}/Playing/Seek<br/>{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()<br/>- Check repeat mode<br/>- Check shuffle<br/>- Update history"]
|
||||
|
||||
QueueNext --> None["None<br/>(at end)"]
|
||||
QueueNext --> Some["Some(next)"]
|
||||
QueueNext --> Same["Same<br/>(repeat one)"]
|
||||
|
||||
Some --> PlayItem["play_item(next)<br/>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<br/>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
|
||||
Reference in New Issue
Block a user