diff --git a/docs/requirements.md b/docs/requirements.md index 766df75a..46146aee 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -544,6 +544,9 @@ Internal architecture, components, and application logic. | UT-142 | The audio codecs offered for video direct play: a Dolby device's real `MediaCodecList` output drops `ac3`/`eac3`, AMR and raw PCM are dropped too, a fully-supported list is passed through untouched, a list with nothing decodable still claims `aac`, and stray spacing or casing does not decide whether the user gets sound | DR-148 | Done | | UT-143 | Subtitle URLs resolve to plain strings before they reach the markup (never a Promise), unresolvable tracks are dropped, a stale selection collapses to "Off", and a server-default track is never auto-selected | UR-020, DR-023 | Done | | UT-144 | VideoPlayer actually renders `` children carrying `data-stream-index`, with no `default` attribute and no async `getSubtitleUrl()` bound to `src` | UR-020, DR-023 | Done | +| UT-145 | The frontend's subtitle payload survives the IPC hop: a camelCase `PlayItemRequest` carrying `subtitles` deserializes, `create_media_item` lands them on `MediaItem.subtitles` in the order sent, and a request without the field still defaults to empty | UR-020, IR-016 | Done | +| UT-146 | The subtitle JSON serialized across the JNI boundary uses the keys `JellyTauPlayer.load()` reads — `url`, `language`, `label` and `mime_type`, never `mimeType` | UR-020, IR-016, JA-008 | Done | +| UT-147 | The native subtitle payload and the track-selection index come from the same resolved list: the wire shape keeps `mime_type` and stream order, `playerPlayItem` actually sends it, and the index is a position in the sent list (so a track whose URL failed to resolve cannot shift the others) rather than the menu's row number | UR-020, IR-016 | Done | ### Integration Tests diff --git a/docs/traceability.md b/docs/traceability.md index 3c1bd699..e0dc2fc3 100644 --- a/docs/traceability.md +++ b/docs/traceability.md @@ -1,16 +1,16 @@ # Code Traceability Matrix -**Generated:** 8/11/2026, 7:25:20 PM +**Generated:** 8/11/2026, 7:48:06 PM ## Summary - **Total Files Scanned:** 341 -- **Total TRACES Found:** 583 +- **Total TRACES Found:** 600 - **Requirements Covered:** - User Requirements (UR): 67 - - Integration Requirements (IR): 17 - - Development Requirements (DR): 130 - - Jellyfin API Requirements (JA): 27 + - Integration Requirements (IR): 18 + - Development Requirements (DR): 131 + - Jellyfin API Requirements (JA): 28 ## Requirements by Type @@ -21,17 +21,17 @@ UR-002, UR-003, UR-004, UR-005, UR-007, UR-008, UR-009, UR-010, UR-011, UR-012, ### Integration Requirements (IR) ``` -IR-003, IR-004, IR-009, IR-010, IR-011, IR-012, IR-013, IR-014, IR-015, IR-020, IR-023, IR-025, IR-026, IR-027, IR-028, IR-030, IR-031 +IR-003, IR-004, IR-009, IR-010, IR-011, IR-012, IR-013, IR-014, IR-015, IR-016, IR-020, IR-023, IR-025, IR-026, IR-027, IR-028, IR-030, IR-031 ``` ### Development Requirements (DR) ``` -DR-001, DR-002, DR-003, DR-004, DR-005, DR-006, DR-007, DR-009, DR-010, DR-011, DR-012, DR-013, DR-014, DR-015, DR-016, DR-017, DR-018, DR-020, DR-021, DR-022, DR-023, DR-024, DR-025, DR-026, DR-027, DR-028, DR-029, DR-030, DR-032, DR-033, DR-034, DR-035, DR-036, DR-037, DR-038, DR-039, DR-040, DR-041, DR-043, DR-044, DR-045, DR-047, DR-048, DR-049, DR-050, DR-051, DR-052, DR-053, DR-054, DR-055, DR-056, DR-057, DR-058, DR-059, DR-060, DR-061, DR-062, DR-063, DR-064, DR-065, DR-066, DR-067, DR-068, DR-069, DR-070, DR-074, DR-075, DR-076, DR-077, DR-078, DR-079, DR-080, DR-081, DR-082, DR-083, DR-084, DR-085, DR-086, DR-087, DR-088, DR-089, DR-090, DR-091, DR-092, DR-093, DR-095, DR-096, DR-097, DR-098, DR-099, DR-100, DR-101, DR-102, DR-103, DR-104, DR-105, DR-106, DR-107, DR-108, DR-109, DR-110, DR-111, DR-112, DR-113, DR-114, DR-115, DR-116, DR-117, DR-118, DR-119, DR-120, DR-123, DR-126, DR-127, DR-128, DR-129, DR-130, DR-131, DR-132, DR-133, DR-134, DR-135, DR-136, DR-137, DR-140, DR-141, DR-142, DR-143, DR-147, DR-148 +DR-001, DR-002, DR-003, DR-004, DR-005, DR-006, DR-007, DR-009, DR-010, DR-011, DR-012, DR-013, DR-014, DR-015, DR-016, DR-017, DR-018, DR-020, DR-021, DR-022, DR-023, DR-024, DR-025, DR-026, DR-027, DR-028, DR-029, DR-030, DR-032, DR-033, DR-034, DR-035, DR-036, DR-037, DR-038, DR-039, DR-040, DR-041, DR-043, DR-044, DR-045, DR-047, DR-048, DR-049, DR-050, DR-051, DR-052, DR-053, DR-054, DR-055, DR-056, DR-057, DR-058, DR-059, DR-060, DR-061, DR-062, DR-063, DR-064, DR-065, DR-066, DR-067, DR-068, DR-069, DR-070, DR-074, DR-075, DR-076, DR-077, DR-078, DR-079, DR-080, DR-081, DR-082, DR-083, DR-084, DR-085, DR-086, DR-087, DR-088, DR-089, DR-090, DR-091, DR-092, DR-093, DR-095, DR-096, DR-097, DR-098, DR-099, DR-100, DR-101, DR-102, DR-103, DR-104, DR-105, DR-106, DR-107, DR-108, DR-109, DR-110, DR-111, DR-112, DR-113, DR-114, DR-115, DR-116, DR-117, DR-118, DR-119, DR-120, DR-123, DR-126, DR-127, DR-128, DR-129, DR-130, DR-131, DR-132, DR-133, DR-134, DR-135, DR-136, DR-137, DR-140, DR-141, DR-142, DR-143, DR-147, DR-148, DR-149 ``` ### Jellyfin API Requirements (JA) ``` -JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, JA-017, JA-019, JA-020, JA-021, JA-022, JA-023, JA-024, JA-025, JA-026, JA-028, JA-029, JA-030, JA-031, JA-032, JA-033, JA-034, JA-035 +JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-008, JA-010, JA-011, JA-012, JA-016, JA-017, JA-019, JA-020, JA-021, JA-022, JA-023, JA-024, JA-025, JA-026, JA-028, JA-029, JA-030, JA-031, JA-032, JA-033, JA-034, JA-035 ``` ## Detailed Mapping @@ -153,6 +153,59 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 3 - **Context:** `Unknown` +### IR-016 + +**Locations:** 16 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2254) + - **Line:** 2254 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2810) + - **Line:** 2810 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L302) + - **Line:** 302 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L622) + - **Line:** 622 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1772) + - **Line:** 1772 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L159) + - **Line:** 159 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L282) + - **Line:** 282 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L20) + - **Line:** 20 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L183) + - **Line:** 183 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L218) + - **Line:** 218 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) + - **Line:** 42 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L223) + - **Line:** 223 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L399) + - **Line:** 399 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2501) + - **Line:** 2501 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2558) + - **Line:** 2558 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2590) + - **Line:** 2590 + - **Context:** `Unknown` + ### IR-020 **Locations:** 8 file(s) @@ -251,11 +304,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 17 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2416) - - **Line:** 2416 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2438) + - **Line:** 2438 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 - **Context:** `Unknown` - **File:** [`src/lib/stores/player.ts`](src/lib/stores/player.ts#L8) - **Line:** 8 @@ -307,22 +360,22 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 2 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2294) - - **Line:** 2294 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2316) + - **Line:** 2316 - **Context:** `export type PlaybackProgress = { itemId: string;` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) - - **Line:** 42 +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L60) + - **Line:** 60 - **Context:** `Unknown` ### DR-003 **Locations:** 2 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2398) - - **Line:** 2398 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2420) + - **Line:** 2420 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L124) - - **Line:** 124 +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L142) + - **Line:** 142 - **Context:** `pub enum MediaType {` ### DR-004 @@ -361,8 +414,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 13 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2670) - - **Line:** 2670 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2692) + - **Line:** 2692 - **Context:** `export type RemoteSessionStatus = { position: number; duration: number...` - **File:** [`src/lib/stores/queue.test.ts`](src/lib/stores/queue.test.ts#L4) - **Line:** 4 @@ -700,23 +753,26 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, ### DR-023 -**Locations:** 7 file(s) +**Locations:** 8 file(s) -- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L15) - - **Line:** 15 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L16) - - **Line:** 16 - - **Context:** `Unknown` - **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) - **Line:** 1 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L291) - - **Line:** 291 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L293) + - **Line:** 293 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1729) - - **Line:** 1729 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1739) + - **Line:** 1739 - **Context:** `function toggleSubtitleMenu() {` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1772) + - **Line:** 1772 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L18) + - **Line:** 18 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L20) + - **Line:** 20 + - **Context:** `Unknown` - **File:** [`src/lib/player/adapters/types.ts`](src/lib/player/adapters/types.ts#L15) - **Line:** 15 - **Context:** `Unknown` @@ -775,8 +831,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 18 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 - **Context:** `Unknown` - **File:** [`src/lib/utils/duration.test.ts`](src/lib/utils/duration.test.ts#L4) - **Line:** 4 @@ -834,8 +890,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 10 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2730) - - **Line:** 2730 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2752) + - **Line:** 2752 - **Context:** `export type SessionInfo = { id?: string | null; userId?: string | null...` - **File:** [`src/lib/components/player/SleepTimerModal.svelte`](src/lib/components/player/SleepTimerModal.svelte#L1) - **Line:** 1 @@ -1179,8 +1235,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L241) - **Line:** 241 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 - **Context:** `Unknown` - **File:** [`src/lib/stores/nextEpisode.ts`](src/lib/stores/nextEpisode.ts#L9) - **Line:** 9 @@ -1333,11 +1389,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L145) - **Line:** 145 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L640) - - **Line:** 640 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L664) + - **Line:** 664 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L743) - - **Line:** 743 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L767) + - **Line:** 767 - **Context:** `Unknown` ### DR-053 @@ -1457,8 +1513,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1404) - **Line:** 1404 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2705) - - **Line:** 2705 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2727) + - **Line:** 2727 - **Context:** `export type SearchResult = { items: MediaItem[]; totalRecordCount: num...` - **File:** [`src/lib/components/search/HeaderSearch.svelte`](src/lib/components/search/HeaderSearch.svelte#L12) - **Line:** 12 @@ -1738,18 +1794,18 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/downloads/+page.svelte`](src/routes/downloads/+page.svelte#L14) - **Line:** 14 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1287) - - **Line:** 1287 - - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1295) - - **Line:** 1295 - - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L97) - **Line:** 97 - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L105) - **Line:** 105 - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1287) + - **Line:** 1287 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1295) + - **Line:** 1295 + - **Context:** `Unknown` - **File:** [`src/lib/components/downloads/DownloadedBrowse.svelte`](src/lib/components/downloads/DownloadedBrowse.svelte#L10) - **Line:** 10 - **Context:** `Unknown` @@ -1803,15 +1859,15 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/downloads/+page.svelte`](src/routes/downloads/+page.svelte#L14) - **Line:** 14 - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L105) + - **Line:** 105 + - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L847) - **Line:** 847 - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1295) - **Line:** 1295 - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L105) - - **Line:** 105 - - **Context:** `Unknown` - **File:** [`src/lib/components/library/MediaCard.svelte`](src/lib/components/library/MediaCard.svelte#L26) - **Line:** 26 - **Context:** `Unknown` @@ -1876,15 +1932,15 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/downloads/+page.svelte`](src/routes/downloads/+page.svelte#L14) - **Line:** 14 - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L113) + - **Line:** 113 + - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1303) - **Line:** 1303 - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1856) - **Line:** 1856 - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L113) - - **Line:** 113 - - **Context:** `Unknown` - **File:** [`src/lib/components/library/LibraryGrid.svelte`](src/lib/components/library/LibraryGrid.svelte#L17) - **Line:** 17 - **Context:** `Unknown` @@ -2110,18 +2166,18 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/library/[id]/+page.svelte`](src/routes/library/[id]/+page.svelte#L187) - **Line:** 187 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1342) - - **Line:** 1342 - - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1355) - - **Line:** 1355 - - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L144) - **Line:** 144 - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L154) - **Line:** 154 - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1342) + - **Line:** 1342 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1355) + - **Line:** 1355 + - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L344) - **Line:** 344 - **Context:** `Unknown` @@ -2228,12 +2284,12 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 7 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1369) - - **Line:** 1369 - - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L165) - **Line:** 165 - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1369) + - **Line:** 1369 + - **Context:** `Unknown` - **File:** [`src/lib/components/library/ClearHistoryButton.svelte`](src/lib/components/library/ClearHistoryButton.svelte#L9) - **Line:** 9 - **Context:** `Unknown` @@ -2246,8 +2302,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L235) - **Line:** 235 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1874) - - **Line:** 1874 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1896) + - **Line:** 1896 - **Context:** `Unknown` ### DR-107 @@ -2380,17 +2436,17 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 4 file(s) -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L592) - - **Line:** 592 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L590) + - **Line:** 590 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L808) - - **Line:** 808 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L806) + - **Line:** 806 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2692) - - **Line:** 2692 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2714) + - **Line:** 2714 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2723) - - **Line:** 2723 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2745) + - **Line:** 2745 - **Context:** `Unknown` ### DR-114 @@ -2408,12 +2464,12 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 16 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1498) - - **Line:** 1498 - - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L322) - **Line:** 322 - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1498) + - **Line:** 1498 + - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L840) - **Line:** 840 - **Context:** `Unknown` @@ -2441,20 +2497,20 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L223) - **Line:** 223 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L683) - - **Line:** 683 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L681) + - **Line:** 681 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1814) - - **Line:** 1814 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2602) - - **Line:** 2602 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1836) + - **Line:** 1836 - **Context:** `Unknown` - **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2624) - **Line:** 2624 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2633) - - **Line:** 2633 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2646) + - **Line:** 2646 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2655) + - **Line:** 2655 - **Context:** `Unknown` ### DR-116 @@ -2485,14 +2541,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L4253) - **Line:** 4253 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L624) - - **Line:** 624 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L622) + - **Line:** 622 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L661) - - **Line:** 661 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L659) + - **Line:** 659 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2655) - - **Line:** 2655 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2677) + - **Line:** 2677 - **Context:** `Unknown` ### DR-117 @@ -2646,8 +2702,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/hybrid.rs`](src-tauri/src/repository/hybrid.rs#L46) - **Line:** 46 - **Context:** `pub fn new(online: OnlineRepository, offline: OfflineRepository) -> Se...` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L52) - - **Line:** 52 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L50) + - **Line:** 50 - **Context:** `impl OnlineRepository {` - **File:** [`src-tauri/src/lib.rs`](src-tauri/src/lib.rs#L1339) - **Line:** 1339 @@ -2669,14 +2725,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/player/localSource.ts`](src/lib/player/localSource.ts#L12) - **Line:** 12 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L420) - - **Line:** 420 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L444) + - **Line:** 444 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L472) - - **Line:** 472 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L496) + - **Line:** 496 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2506) - - **Line:** 2506 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2665) + - **Line:** 2665 - **Context:** `Unknown` ### DR-126 @@ -2717,14 +2773,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 3 file(s) -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L392) - - **Line:** 392 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L416) + - **Line:** 416 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L658) - - **Line:** 658 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L682) + - **Line:** 682 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2465) - - **Line:** 2465 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2624) + - **Line:** 2624 - **Context:** `Unknown` ### DR-129 @@ -2828,8 +2884,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L243) - **Line:** 243 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1915) - - **Line:** 1915 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1937) + - **Line:** 1937 - **Context:** `Unknown` - **File:** [`src-tauri/src/lib.rs`](src-tauri/src/lib.rs#L1346) - **Line:** 1346 @@ -2851,8 +2907,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1152) - **Line:** 1152 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2803) - - **Line:** 2803 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2843) + - **Line:** 2843 - **Context:** `export type SyncQueueItem = { id: number; userId: string; operation: s...` - **File:** [`src/lib/components/sync/PendingSyncList.svelte`](src/lib/components/sync/PendingSyncList.svelte#L12) - **Line:** 12 @@ -2989,11 +3045,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 2 file(s) -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L386) - - **Line:** 386 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L384) + - **Line:** 384 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L452) - - **Line:** 452 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L450) + - **Line:** 450 - **Context:** `Unknown` ### DR-141 @@ -3111,6 +3167,17 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 80 - **Context:** `Unknown` +### DR-149 + +**Locations:** 2 file(s) + +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L105) + - **Line:** 105 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L127) + - **Line:** 127 + - **Context:** `Unknown` + ### JA-001 **Locations:** 1 file(s) @@ -3168,6 +3235,35 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 1 - **Context:** `Unknown` +### JA-008 + +**Locations:** 8 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2254) + - **Line:** 2254 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2810) + - **Line:** 2810 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L622) + - **Line:** 622 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L159) + - **Line:** 159 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L183) + - **Line:** 183 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) + - **Line:** 42 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L223) + - **Line:** 223 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2590) + - **Line:** 2590 + - **Context:** `Unknown` + ### JA-010 **Locations:** 2 file(s) @@ -3380,12 +3476,12 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/repository-client.test.ts`](src/lib/api/repository-client.test.ts#L451) - **Line:** 451 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1430) - - **Line:** 1430 - - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L234) - **Line:** 234 - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1430) + - **Line:** 1430 + - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L599) - **Line:** 599 - **Context:** `Unknown` @@ -3395,14 +3491,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L129) - **Line:** 129 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L452) - - **Line:** 452 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L450) + - **Line:** 450 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2375) - - **Line:** 2375 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2397) + - **Line:** 2397 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2416) - - **Line:** 2416 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2438) + - **Line:** 2438 - **Context:** `Unknown` ### JA-033 @@ -3418,31 +3514,31 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L223) - **Line:** 223 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L683) - - **Line:** 683 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L681) + - **Line:** 681 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1814) - - **Line:** 1814 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1836) + - **Line:** 1836 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1874) - - **Line:** 1874 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1896) + - **Line:** 1896 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2602) - - **Line:** 2602 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2624) + - **Line:** 2624 - **Context:** `Unknown` ### JA-034 **Locations:** 3 file(s) -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L592) - - **Line:** 592 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L590) + - **Line:** 590 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L808) - - **Line:** 808 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L806) + - **Line:** 806 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2692) - - **Line:** 2692 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2714) + - **Line:** 2714 - **Context:** `Unknown` ### JA-035 @@ -3452,8 +3548,224 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L243) - **Line:** 243 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1915) - - **Line:** 1915 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1937) + - **Line:** 1937 + - **Context:** `Unknown` + +### UR-002 + +**Locations:** 19 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2420) + - **Line:** 2420 + - **Context:** `Unknown` +- **File:** [`src/lib/stores/connectivity.ts`](src/lib/stores/connectivity.ts#L10) + - **Line:** 10 + - **Context:** `Unknown` +- **File:** [`src/lib/services/syncService.ts`](src/lib/services/syncService.ts#L7) + - **Line:** 7 + - **Context:** `Unknown` +- **File:** [`src/lib/services/offlineCatalog.ts`](src/lib/services/offlineCatalog.ts#L14) + - **Line:** 14 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L142) + - **Line:** 142 + - **Context:** `pub enum MediaType {` +- **File:** [`src-tauri/src/commands/storage/mod.rs`](src-tauri/src/commands/storage/mod.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/offline.rs`](src-tauri/src/commands/offline.rs#L136) + - **Line:** 136 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/sync.rs`](src-tauri/src/commands/sync.rs#L7) + - **Line:** 7 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/sync_drain.rs`](src-tauri/src/commands/sync_drain.rs#L14) + - **Line:** 14 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/sync_drain.rs`](src-tauri/src/commands/sync_drain.rs#L228) + - **Line:** 228 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/catalog.rs`](src-tauri/src/commands/catalog.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/storage/db_service.rs`](src-tauri/src/storage/db_service.rs#L311) + - **Line:** 311 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/storage/mod.rs`](src-tauri/src/storage/mod.rs#L157) + - **Line:** 157 + - **Context:** `pub fn file_size(&self) -> Option {` +- **File:** [`src-tauri/src/storage/schema.rs`](src-tauri/src/storage/schema.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/hybrid.rs`](src-tauri/src/repository/hybrid.rs#L8) + - **Line:** 8 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/lib.rs`](src-tauri/src/lib.rs#L1346) + - **Line:** 1346 + - **Context:** `Unknown` + +### UR-003 + +**Locations:** 20 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2316) + - **Line:** 2316 + - **Context:** `export type PlaybackProgress = { itemId: string;` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2420) + - **Line:** 2420 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src/lib/services/webviewAudio.ts`](src/lib/services/webviewAudio.ts#L18) + - **Line:** 18 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/index.ts`](src/lib/player/adapters/index.ts#L11) + - **Line:** 11 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/rustReportHost.ts`](src/lib/player/adapters/rustReportHost.ts#L13) + - **Line:** 13 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/types.ts`](src/lib/player/adapters/types.ts#L15) + - **Line:** 15 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/webviewAudioAdapter.ts`](src/lib/player/adapters/webviewAudioAdapter.ts#L18) + - **Line:** 18 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/nativeAdapter.ts`](src/lib/player/adapters/nativeAdapter.ts#L24) + - **Line:** 24 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/html5Adapter.ts`](src/lib/player/adapters/html5Adapter.ts#L19) + - **Line:** 19 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/mpv_backend_test.rs`](src-tauri/src/player/mpv_backend_test.rs#L8) + - **Line:** 8 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L39) + - **Line:** 39 + - **Context:** `pub fn playback_failed>(message: S) -> Self {` +- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L245) + - **Line:** 245 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L25) + - **Line:** 25 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L184) + - **Line:** 184 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L60) + - **Line:** 60 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L142) + - **Line:** 142 + - **Context:** `pub enum MediaType {` +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` + +### UR-004 + +**Locations:** 28 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L264) + - **Line:** 264 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2316) + - **Line:** 2316 + - **Context:** `export type PlaybackProgress = { itemId: string;` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2420) + - **Line:** 2420 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/AudioPlayer.svelte`](src/lib/components/player/AudioPlayer.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src/lib/services/preload.ts`](src/lib/services/preload.ts#L5) + - **Line:** 5 + - **Context:** `Unknown` +- **File:** [`src/lib/services/playerEvents.regression.test.ts`](src/lib/services/playerEvents.regression.test.ts#L155) + - **Line:** 155 + - **Context:** `Unknown` +- **File:** [`src/lib/services/preload.test.ts`](src/lib/services/preload.test.ts#L4) + - **Line:** 4 + - **Context:** `Unknown` +- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L287) + - **Line:** 287 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/mpv_backend_test.rs`](src-tauri/src/player/mpv_backend_test.rs#L8) + - **Line:** 8 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L39) + - **Line:** 39 + - **Context:** `pub fn playback_failed>(message: S) -> Self {` +- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L245) + - **Line:** 245 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L25) + - **Line:** 25 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L184) + - **Line:** 184 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L60) + - **Line:** 60 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L142) + - **Line:** 142 + - **Context:** `pub enum MediaType {` +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L1377) + - **Line:** 1377 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L1464) + - **Line:** 1464 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L1495) + - **Line:** 1495 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L299) + - **Line:** 299 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L29) + - **Line:** 29 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L40) + - **Line:** 40 + - **Context:** `pub fn clamp_max_audio_channels(reported: Option) -> u32 {` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L80) + - **Line:** 80 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L105) + - **Line:** 105 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L127) + - **Line:** 127 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L384) + - **Line:** 384 - **Context:** `Unknown` ### UR-007 @@ -3505,8 +3817,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1) - **Line:** 1 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L624) - - **Line:** 624 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L622) + - **Line:** 622 - **Context:** `Unknown` ### UR-023 @@ -3525,8 +3837,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L241) - **Line:** 241 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 - **Context:** `Unknown` - **File:** [`src/lib/stores/nextEpisode.ts`](src/lib/stores/nextEpisode.ts#L9) - **Line:** 9 @@ -3602,8 +3914,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1152) - **Line:** 1152 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2803) - - **Line:** 2803 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2843) + - **Line:** 2843 - **Context:** `export type SyncQueueItem = { id: number; userId: string; operation: s...` - **File:** [`src/lib/components/sync/PendingSyncList.svelte`](src/lib/components/sync/PendingSyncList.svelte#L12) - **Line:** 12 @@ -3710,75 +4022,13 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L243) - **Line:** 243 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1915) - - **Line:** 1915 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1937) + - **Line:** 1937 - **Context:** `Unknown` - **File:** [`src-tauri/src/lib.rs`](src-tauri/src/lib.rs#L1346) - **Line:** 1346 - **Context:** `Unknown` -### UR-026 - -**Locations:** 19 file(s) - -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L241) - - **Line:** 241 - - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 - - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2730) - - **Line:** 2730 - - **Context:** `export type SessionInfo = { id?: string | null; userId?: string | null...` -- **File:** [`src/lib/components/player/SleepTimerModal.svelte`](src/lib/components/player/SleepTimerModal.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src/lib/stores/sleepTimer.ts`](src/lib/stores/sleepTimer.ts#L10) - - **Line:** 10 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.test.ts`](src/lib/services/playerEvents.test.ts#L4) - - **Line:** 4 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L8) - - **Line:** 8 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L264) - - **Line:** 264 - - **Context:** `function handleMediaLoaded(duration: number): void {` -- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L324) - - **Line:** 324 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/sleep_timer.rs`](src-tauri/src/player/sleep_timer.rs#L4) - - **Line:** 4 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/sleep_timer.rs`](src-tauri/src/player/sleep_timer.rs#L81) - - **Line:** 81 - - **Context:** `pub fn cancel(&mut self) {` -- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L6) - - **Line:** 6 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L23) - - **Line:** 23 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/autoplay.rs`](src-tauri/src/player/autoplay.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L328) - - **Line:** 328 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L145) - - **Line:** 145 - - **Context:** `Unknown` - ### UR-027 **Locations:** 23 file(s) @@ -3946,6 +4196,9 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/repository-client.test.ts`](src/lib/api/repository-client.test.ts#L451) - **Line:** 451 - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L234) + - **Line:** 234 + - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L38) - **Line:** 38 - **Context:** `Unknown` @@ -3961,9 +4214,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1430) - **Line:** 1430 - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L234) - - **Line:** 234 - - **Context:** `Unknown` - **File:** [`src/lib/components/player/backgroundAudioHandoff.test.ts`](src/lib/components/player/backgroundAudioHandoff.test.ts#L11) - **Line:** 11 - **Context:** `Unknown` @@ -4042,11 +4292,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L299) - **Line:** 299 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L640) - - **Line:** 640 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L664) + - **Line:** 664 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L743) - - **Line:** 743 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L767) + - **Line:** 767 - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L599) - **Line:** 599 @@ -4057,14 +4307,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L129) - **Line:** 129 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L452) - - **Line:** 452 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L450) + - **Line:** 450 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2375) - - **Line:** 2375 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2397) + - **Line:** 2397 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2416) - - **Line:** 2416 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2438) + - **Line:** 2438 - **Context:** `Unknown` ### UR-048 @@ -4112,8 +4362,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1404) - **Line:** 1404 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2705) - - **Line:** 2705 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2727) + - **Line:** 2727 - **Context:** `export type SearchResult = { items: MediaItem[]; totalRecordCount: num...` - **File:** [`src/lib/components/search/SearchScopeChips.svelte`](src/lib/components/search/SearchScopeChips.svelte#L7) - **Line:** 7 @@ -4242,6 +4492,12 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/downloads/+page.svelte`](src/routes/downloads/+page.svelte#L14) - **Line:** 14 - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L97) + - **Line:** 97 + - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L105) + - **Line:** 105 + - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L847) - **Line:** 847 - **Context:** `Unknown` @@ -4251,12 +4507,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1295) - **Line:** 1295 - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L97) - - **Line:** 97 - - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L105) - - **Line:** 105 - - **Context:** `Unknown` - **File:** [`src/lib/components/library/MediaCard.svelte`](src/lib/components/library/MediaCard.svelte#L26) - **Line:** 26 - **Context:** `Unknown` @@ -4328,15 +4578,15 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/downloads/+page.svelte`](src/routes/downloads/+page.svelte#L14) - **Line:** 14 - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L113) + - **Line:** 113 + - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1303) - **Line:** 1303 - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1856) - **Line:** 1856 - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L113) - - **Line:** 113 - - **Context:** `Unknown` - **File:** [`src/lib/components/library/LibraryGrid.svelte`](src/lib/components/library/LibraryGrid.svelte#L17) - **Line:** 17 - **Context:** `Unknown` @@ -4439,18 +4689,18 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/library/[id]/+page.svelte`](src/routes/library/[id]/+page.svelte#L308) - **Line:** 308 - **Context:** `async function handlePlayAll() {` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1342) - - **Line:** 1342 - - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1355) - - **Line:** 1355 - - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L144) - **Line:** 144 - **Context:** `Unknown` - **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L154) - **Line:** 154 - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1342) + - **Line:** 1342 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1355) + - **Line:** 1355 + - **Context:** `Unknown` - **File:** [`src/lib/components/library/episodeStrip.ts`](src/lib/components/library/episodeStrip.ts#L8) - **Line:** 8 - **Context:** `Unknown` @@ -4514,6 +4764,32 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 9 - **Context:** `Unknown` +### UR-064 + +**Locations:** 7 file(s) + +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L165) + - **Line:** 165 + - **Context:** `Unknown` +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1369) + - **Line:** 1369 + - **Context:** `Unknown` +- **File:** [`src/lib/components/library/ClearHistoryButton.svelte`](src/lib/components/library/ClearHistoryButton.svelte#L9) + - **Line:** 9 + - **Context:** `Unknown` +- **File:** [`src/lib/components/library/SeasonSection.svelte`](src/lib/components/library/SeasonSection.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L387) + - **Line:** 387 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L235) + - **Line:** 235 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1896) + - **Line:** 1896 + - **Context:** `Unknown` + ### UR-067 **Locations:** 39 file(s) @@ -4533,15 +4809,15 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/routes/+page.svelte`](src/routes/+page.svelte#L228) - **Line:** 228 - **Context:** `Unknown` +- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L322) + - **Line:** 322 + - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1498) - **Line:** 1498 - **Context:** `Unknown` - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1956) - **Line:** 1956 - **Context:** `export type GetItemsOptions = { startIndex?: number | null; limit?: nu...` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L322) - - **Line:** 322 - - **Context:** `Unknown` - **File:** [`src/lib/components/library/GenericMediaListPage.svelte`](src/lib/components/library/GenericMediaListPage.svelte#L1) - **Line:** 1 - **Context:** `Unknown` @@ -4611,30 +4887,30 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L223) - **Line:** 223 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L624) - - **Line:** 624 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L622) + - **Line:** 622 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L661) - - **Line:** 661 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L659) + - **Line:** 659 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L683) - - **Line:** 683 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L681) + - **Line:** 681 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1814) - - **Line:** 1814 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2602) - - **Line:** 2602 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1836) + - **Line:** 1836 - **Context:** `Unknown` - **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2624) - **Line:** 2624 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2633) - - **Line:** 2633 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2646) + - **Line:** 2646 - **Context:** `Unknown` - **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2655) - **Line:** 2655 - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2677) + - **Line:** 2677 + - **Context:** `Unknown` ### UR-068 @@ -4699,6 +4975,22 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 8 - **Context:** `Unknown` +### IT-016 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L2956) + - **Line:** 2956 + - **Context:** `Unknown` + +### IT-017 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/catalog.rs`](src-tauri/src/commands/catalog.rs#L854) + - **Line:** 854 + - **Context:** `Unknown` + ### UT-003 **Locations:** 1 file(s) @@ -4723,14 +5015,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 535 - **Context:** `pub enum AddPosition {` -### UT-010 - -**Locations:** 1 file(s) - -- **File:** [`src/lib/stores/downloads.test.ts`](src/lib/stores/downloads.test.ts#L2) - - **Line:** 2 - - **Context:** `Unknown` - ### UT-012 **Locations:** 1 file(s) @@ -4739,14 +5023,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 81 - **Context:** `pub fn cancel(&mut self) {` -### UT-024 - -**Locations:** 1 file(s) - -- **File:** [`src/lib/stores/downloads.test.ts`](src/lib/stores/downloads.test.ts#L2) - - **Line:** 2 - - **Context:** `Unknown` - ### UT-026 **Locations:** 2 file(s) @@ -4830,28 +5106,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 2040 - **Context:** `Unknown` -### UT-052 - -**Locations:** 1 file(s) - -- **File:** [`src/lib/stores/downloads.test.ts`](src/lib/stores/downloads.test.ts#L315) - - **Line:** 315 - - **Context:** `Unknown` - -### UT-060 - -**Locations:** 3 file(s) - -- **File:** [`src/lib/components/player/backgroundAudioHandoff.test.ts`](src/lib/components/player/backgroundAudioHandoff.test.ts#L11) - - **Line:** 11 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/backgroundAudioHandoff.ts`](src/lib/components/player/backgroundAudioHandoff.ts#L4) - - **Line:** 4 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/backgroundAudioHandoff.ts`](src/lib/components/player/backgroundAudioHandoff.ts#L69) - - **Line:** 69 - - **Context:** `Unknown` - ### UT-062 **Locations:** 1 file(s) @@ -4868,14 +5122,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 4 - **Context:** `Unknown` -### UT-071 - -**Locations:** 1 file(s) - -- **File:** [`src/lib/utils/formatBytes.test.ts`](src/lib/utils/formatBytes.test.ts#L4) - - **Line:** 4 - - **Context:** `Unknown` - ### UT-083 **Locations:** 1 file(s) @@ -4892,22 +5138,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 759 - **Context:** `Unknown` -### UT-088 - -**Locations:** 1 file(s) - -- **File:** [`src/lib/components/player/tapGestures.ts`](src/lib/components/player/tapGestures.ts#L21) - - **Line:** 21 - - **Context:** `Unknown` - -### UT-090 - -**Locations:** 1 file(s) - -- **File:** [`src/lib/components/player/VideoPlayer.touchScrub.test.ts`](src/lib/components/player/VideoPlayer.touchScrub.test.ts#L21) - - **Line:** 21 - - **Context:** `Unknown` - ### UT-091 **Locations:** 2 file(s) @@ -4935,26 +5165,20 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 17 - **Context:** `Unknown` -### UT-098 +### UT-096 **Locations:** 1 file(s) -- **File:** [`src/lib/utils/layoutShell.test.ts`](src/lib/utils/layoutShell.test.ts#L158) - - **Line:** 158 +- **File:** [`src/lib/utils/safeArea.test.ts`](src/lib/utils/safeArea.test.ts#L17) + - **Line:** 17 - **Context:** `Unknown` -### UT-105 +### UT-097 -**Locations:** 3 file(s) +**Locations:** 1 file(s) -- **File:** [`src/lib/stores/favorites.ts`](src/lib/stores/favorites.ts#L8) - - **Line:** 8 - - **Context:** `Unknown` -- **File:** [`src/lib/stores/favorites.ts`](src/lib/stores/favorites.ts#L55) - - **Line:** 55 - - **Context:** `Unknown` -- **File:** [`src/lib/stores/favorites.test.ts`](src/lib/stores/favorites.test.ts#L1) - - **Line:** 1 +- **File:** [`src/lib/utils/safeArea.test.ts`](src/lib/utils/safeArea.test.ts#L17) + - **Line:** 17 - **Context:** `Unknown` ### UT-106 @@ -4971,6 +5195,91 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 1 - **Context:** `Unknown` +### UR-014 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/playlist.rs`](src-tauri/src/commands/playlist.rs#L4) + - **Line:** 4 + - **Context:** `Unknown` + +### UR-022 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/player/settings.rs`](src-tauri/src/commands/player/settings.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` + +### UR-031 + +**Locations:** 2 file(s) + +- **File:** [`src-tauri/src/commands/player/settings.rs`](src-tauri/src/commands/player/settings.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/settings.rs`](src-tauri/src/settings.rs#L1) + - **Line:** 1 + - **Context:** `Unknown` + +### UR-042 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/auth.rs`](src-tauri/src/commands/auth.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` + +### UR-044 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/download/pinning.rs`](src-tauri/src/commands/download/pinning.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` + +### UR-046 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/player/remote.rs`](src-tauri/src/commands/player/remote.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` + +### UR-047 + +**Locations:** 1 file(s) + +- **File:** [`src-tauri/src/commands/storage/mod.rs`](src-tauri/src/commands/storage/mod.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` + +### UR-060 + +**Locations:** 7 file(s) + +- **File:** [`src/lib/utils/searchScope.ts`](src/lib/utils/searchScope.ts#L155) + - **Line:** 155 + - **Context:** `Unknown` +- **File:** [`src/lib/utils/searchScope.ts`](src/lib/utils/searchScope.ts#L221) + - **Line:** 221 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/catalog.rs`](src-tauri/src/commands/catalog.rs#L96) + - **Line:** 96 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/storage/schema.rs`](src-tauri/src/storage/schema.rs#L769) + - **Line:** 769 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L333) + - **Line:** 333 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L3017) + - **Line:** 3017 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/domain/search_rank.rs`](src-tauri/src/domain/search_rank.rs#L106) + - **Line:** 106 + - **Context:** `Unknown` + ### UR-066 **Locations:** 6 file(s) @@ -5049,20 +5358,20 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/hybrid.rs`](src-tauri/src/repository/hybrid.rs#L46) - **Line:** 46 - **Context:** `pub fn new(online: OnlineRepository, offline: OfflineRepository) -> Se...` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L52) - - **Line:** 52 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L50) + - **Line:** 50 - **Context:** `impl OnlineRepository {` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L592) - - **Line:** 592 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L590) + - **Line:** 590 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L808) - - **Line:** 808 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L806) + - **Line:** 806 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2692) - - **Line:** 2692 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2714) + - **Line:** 2714 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2723) - - **Line:** 2723 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2745) + - **Line:** 2745 - **Context:** `Unknown` - **File:** [`src-tauri/src/lib.rs`](src-tauri/src/lib.rs#L1339) - **Line:** 1339 @@ -5099,23 +5408,23 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/player/localSource.ts`](src/lib/player/localSource.ts#L55) - **Line:** 55 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L392) - - **Line:** 392 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L416) + - **Line:** 416 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L420) - - **Line:** 420 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L444) + - **Line:** 444 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L472) - - **Line:** 472 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L496) + - **Line:** 496 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L658) - - **Line:** 658 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L682) + - **Line:** 682 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2465) - - **Line:** 2465 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2624) + - **Line:** 2624 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2506) - - **Line:** 2506 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2665) + - **Line:** 2665 - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/download/mod.rs`](src-tauri/src/commands/download/mod.rs#L276) - **Line:** 276 @@ -5218,11 +5527,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L51) - **Line:** 51 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L640) - - **Line:** 640 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L664) + - **Line:** 664 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L743) - - **Line:** 743 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L767) + - **Line:** 767 - **Context:** `Unknown` ### UT-061 @@ -5247,120 +5556,84 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/player/backgroundAudio.commands.test.ts`](src/lib/player/backgroundAudio.commands.test.ts#L7) - **Line:** 7 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L640) - - **Line:** 640 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L664) + - **Line:** 664 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L743) - - **Line:** 743 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L767) + - **Line:** 767 - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L599) - **Line:** 599 - **Context:** `Unknown` -### UR-004 +### UR-026 -**Locations:** 26 file(s) +**Locations:** 19 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L264) - - **Line:** 264 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L241) + - **Line:** 241 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2294) - - **Line:** 2294 - - **Context:** `export type PlaybackProgress = { itemId: string;` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2398) - - **Line:** 2398 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/AudioPlayer.svelte`](src/lib/components/player/AudioPlayer.svelte#L1) +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2752) + - **Line:** 2752 + - **Context:** `export type SessionInfo = { id?: string | null; userId?: string | null...` +- **File:** [`src/lib/components/player/SleepTimerModal.svelte`](src/lib/components/player/SleepTimerModal.svelte#L1) - **Line:** 1 - **Context:** `Unknown` -- **File:** [`src/lib/services/preload.ts`](src/lib/services/preload.ts#L5) - - **Line:** 5 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) + - **Line:** 1 - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.regression.test.ts`](src/lib/services/playerEvents.regression.test.ts#L155) - - **Line:** 155 +- **File:** [`src/lib/stores/sleepTimer.ts`](src/lib/stores/sleepTimer.ts#L10) + - **Line:** 10 - **Context:** `Unknown` -- **File:** [`src/lib/services/preload.test.ts`](src/lib/services/preload.test.ts#L4) +- **File:** [`src/lib/services/playerEvents.test.ts`](src/lib/services/playerEvents.test.ts#L4) - **Line:** 4 - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L287) - - **Line:** 287 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mpv_backend_test.rs`](src-tauri/src/player/mpv_backend_test.rs#L8) +- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L8) - **Line:** 8 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) - - **Line:** 42 +- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L264) + - **Line:** 264 + - **Context:** `function handleMediaLoaded(duration: number): void {` +- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L324) + - **Line:** 324 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L124) - - **Line:** 124 - - **Context:** `pub enum MediaType {` -- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L39) - - **Line:** 39 - - **Context:** `pub fn playback_failed>(message: S) -> Self {` -- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L245) - - **Line:** 245 +- **File:** [`src-tauri/src/player/sleep_timer.rs`](src-tauri/src/player/sleep_timer.rs#L4) + - **Line:** 4 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L25) - - **Line:** 25 +- **File:** [`src-tauri/src/player/sleep_timer.rs`](src-tauri/src/player/sleep_timer.rs#L81) + - **Line:** 81 + - **Context:** `pub fn cancel(&mut self) {` +- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L6) + - **Line:** 6 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L184) - - **Line:** 184 +- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L23) + - **Line:** 23 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/autoplay.rs`](src-tauri/src/player/autoplay.rs#L2) + - **Line:** 2 - **Context:** `Unknown` - **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) - **Line:** 2 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L1377) - - **Line:** 1377 +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L328) + - **Line:** 328 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L1464) - - **Line:** 1464 +- **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L3) + - **Line:** 3 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L1495) - - **Line:** 1495 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L299) - - **Line:** 299 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L29) - - **Line:** 29 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L40) - - **Line:** 40 - - **Context:** `pub fn clamp_max_audio_channels(reported: Option) -> u32 {` -- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L80) - - **Line:** 80 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L386) - - **Line:** 386 +- **File:** [`src-tauri/src/commands/player/timers.rs`](src-tauri/src/commands/player/timers.rs#L145) + - **Line:** 145 - **Context:** `Unknown` -### UT-107 +### UT-098 -**Locations:** 6 file(s) +**Locations:** 1 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1498) - - **Line:** 1498 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L806) - - **Line:** 806 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L821) - - **Line:** 821 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L840) - - **Line:** 840 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L994) - - **Line:** 994 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L1019) - - **Line:** 1019 +- **File:** [`src/lib/utils/layoutShell.test.ts`](src/lib/utils/layoutShell.test.ts#L158) + - **Line:** 158 - **Context:** `Unknown` ### UT-116 @@ -5370,14 +5643,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L300) - **Line:** 300 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L420) - - **Line:** 420 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L444) + - **Line:** 444 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L472) - - **Line:** 472 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L496) + - **Line:** 496 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2506) - - **Line:** 2506 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2665) + - **Line:** 2665 - **Context:** `Unknown` ### UT-117 @@ -5406,145 +5679,18 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 299 - **Context:** `Unknown` -### UR-002 - -**Locations:** 19 file(s) - -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2398) - - **Line:** 2398 - - **Context:** `Unknown` -- **File:** [`src/lib/stores/connectivity.ts`](src/lib/stores/connectivity.ts#L10) - - **Line:** 10 - - **Context:** `Unknown` -- **File:** [`src/lib/services/syncService.ts`](src/lib/services/syncService.ts#L7) - - **Line:** 7 - - **Context:** `Unknown` -- **File:** [`src/lib/services/offlineCatalog.ts`](src/lib/services/offlineCatalog.ts#L14) - - **Line:** 14 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L124) - - **Line:** 124 - - **Context:** `pub enum MediaType {` -- **File:** [`src-tauri/src/commands/storage/mod.rs`](src-tauri/src/commands/storage/mod.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/offline.rs`](src-tauri/src/commands/offline.rs#L136) - - **Line:** 136 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/sync.rs`](src-tauri/src/commands/sync.rs#L7) - - **Line:** 7 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/sync_drain.rs`](src-tauri/src/commands/sync_drain.rs#L14) - - **Line:** 14 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/sync_drain.rs`](src-tauri/src/commands/sync_drain.rs#L228) - - **Line:** 228 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/catalog.rs`](src-tauri/src/commands/catalog.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/storage/db_service.rs`](src-tauri/src/storage/db_service.rs#L311) - - **Line:** 311 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/storage/mod.rs`](src-tauri/src/storage/mod.rs#L157) - - **Line:** 157 - - **Context:** `pub fn file_size(&self) -> Option {` -- **File:** [`src-tauri/src/storage/schema.rs`](src-tauri/src/storage/schema.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/hybrid.rs`](src-tauri/src/repository/hybrid.rs#L8) - - **Line:** 8 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/lib.rs`](src-tauri/src/lib.rs#L1346) - - **Line:** 1346 - - **Context:** `Unknown` - -### UR-003 - -**Locations:** 20 file(s) - -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2294) - - **Line:** 2294 - - **Context:** `export type PlaybackProgress = { itemId: string;` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2398) - - **Line:** 2398 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src/lib/services/webviewAudio.ts`](src/lib/services/webviewAudio.ts#L18) - - **Line:** 18 - - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/index.ts`](src/lib/player/adapters/index.ts#L11) - - **Line:** 11 - - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/rustReportHost.ts`](src/lib/player/adapters/rustReportHost.ts#L13) - - **Line:** 13 - - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/types.ts`](src/lib/player/adapters/types.ts#L15) - - **Line:** 15 - - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/webviewAudioAdapter.ts`](src/lib/player/adapters/webviewAudioAdapter.ts#L18) - - **Line:** 18 - - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/nativeAdapter.ts`](src/lib/player/adapters/nativeAdapter.ts#L24) - - **Line:** 24 - - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/html5Adapter.ts`](src/lib/player/adapters/html5Adapter.ts#L19) - - **Line:** 19 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mpv_backend_test.rs`](src-tauri/src/player/mpv_backend_test.rs#L8) - - **Line:** 8 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) - - **Line:** 42 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L124) - - **Line:** 124 - - **Context:** `pub enum MediaType {` -- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L39) - - **Line:** 39 - - **Context:** `pub fn playback_failed>(message: S) -> Self {` -- **File:** [`src-tauri/src/player/backend.rs`](src-tauri/src/player/backend.rs#L245) - - **Line:** 245 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L25) - - **Line:** 25 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/webview_audio_backend.rs`](src-tauri/src/player/webview_audio_backend.rs#L184) - - **Line:** 184 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` - ### UR-005 **Locations:** 73 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2416) - - **Line:** 2416 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2438) + - **Line:** 2438 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 - **Context:** `Unknown` -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2670) - - **Line:** 2670 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2692) + - **Line:** 2692 - **Context:** `export type RemoteSessionStatus = { position: number; duration: number...` - **File:** [`src/lib/components/player/Controls.svelte`](src/lib/components/player/Controls.svelte#L1) - **Line:** 1 @@ -5757,17 +5903,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 2 - **Context:** `Unknown` -### UR-008 - -**Locations:** 2 file(s) - -- **File:** [`src/lib/components/library/GenericMediaListPage.searchEvent.test.ts`](src/lib/components/library/GenericMediaListPage.searchEvent.test.ts#L12) - - **Line:** 12 - - **Context:** `Unknown` -- **File:** [`src/lib/stores/library.ts`](src/lib/stores/library.ts#L2) - - **Line:** 2 - - **Context:** `Unknown` - ### UR-009 **Locations:** 15 file(s) @@ -5822,8 +5957,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 11 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2398) - - **Line:** 2398 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2420) + - **Line:** 2420 - **Context:** `Unknown` - **File:** [`src/lib/stores/downloads.ts`](src/lib/stores/downloads.ts#L2) - **Line:** 2 @@ -5837,8 +5972,8 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/services/preload.test.ts`](src/lib/services/preload.test.ts#L4) - **Line:** 4 - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L124) - - **Line:** 124 +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L142) + - **Line:** 142 - **Context:** `pub enum MediaType {` - **File:** [`src-tauri/src/commands/download/mod.rs`](src-tauri/src/commands/download/mod.rs#L2040) - **Line:** 2040 @@ -5891,82 +6026,51 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 7 - **Context:** `Unknown` -### UR-019 - -**Locations:** 12 file(s) - -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2473) - - **Line:** 2473 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.test.ts`](src/lib/services/playerEvents.test.ts#L4) - - **Line:** 4 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playbackReporting.test.ts`](src/lib/services/playbackReporting.test.ts#L4) - - **Line:** 4 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playbackReporting.ts`](src/lib/services/playbackReporting.ts#L10) - - **Line:** 10 - - **Context:** `Unknown` -- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L8) - - **Line:** 8 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L6) - - **Line:** 6 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L23) - - **Line:** 23 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/storage/mod.rs`](src-tauri/src/commands/storage/mod.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/playback_reporting.rs`](src-tauri/src/commands/playback_reporting.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) - - **Line:** 2 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/storage/mod.rs`](src-tauri/src/storage/mod.rs#L157) - - **Line:** 157 - - **Context:** `pub fn file_size(&self) -> Option {` - ### UR-020 -**Locations:** 8 file(s) +**Locations:** 23 file(s) -- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L15) - - **Line:** 15 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2254) + - **Line:** 2254 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L16) - - **Line:** 16 +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2810) + - **Line:** 2810 - **Context:** `Unknown` - **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) - **Line:** 1 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L291) - - **Line:** 291 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L293) + - **Line:** 293 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1729) - - **Line:** 1729 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L302) + - **Line:** 302 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L622) + - **Line:** 622 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1739) + - **Line:** 1739 - **Context:** `function toggleSubtitleMenu() {` -- **File:** [`src/lib/player/adapters/types.ts`](src/lib/player/adapters/types.ts#L15) - - **Line:** 15 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1772) + - **Line:** 1772 - **Context:** `Unknown` -- **File:** [`src/lib/player/adapters/html5Adapter.ts`](src/lib/player/adapters/html5Adapter.ts#L19) - - **Line:** 19 +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L18) + - **Line:** 18 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) - - **Line:** 1 +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L159) + - **Line:** 159 - **Context:** `Unknown` - -### UR-021 - -**Locations:** 5 file(s) - -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) - - **Line:** 1 +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L282) + - **Line:** 282 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L20) + - **Line:** 20 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L183) + - **Line:** 183 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L218) + - **Line:** 218 - **Context:** `Unknown` - **File:** [`src/lib/player/adapters/types.ts`](src/lib/player/adapters/types.ts#L15) - **Line:** 15 @@ -5974,22 +6078,40 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src/lib/player/adapters/html5Adapter.ts`](src/lib/player/adapters/html5Adapter.ts#L19) - **Line:** 19 - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) + - **Line:** 42 + - **Context:** `Unknown` - **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) - **Line:** 1 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/storage/series_prefs.rs`](src-tauri/src/commands/storage/series_prefs.rs#L3) +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L223) + - **Line:** 223 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L399) + - **Line:** 399 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2501) + - **Line:** 2501 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2558) + - **Line:** 2558 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2590) + - **Line:** 2590 + - **Context:** `Unknown` + +### UR-036 + +**Locations:** 3 file(s) + +- **File:** [`src/lib/components/library/PersonDetailView.svelte`](src/lib/components/library/PersonDetailView.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/storage/people.rs`](src-tauri/src/commands/storage/people.rs#L3) - **Line:** 3 - **Context:** `Unknown` - -### UR-028 - -**Locations:** 2 file(s) - -- **File:** [`src/lib/components/player/MiniPlayer.svelte`](src/lib/components/player/MiniPlayer.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/AudioPlayer.svelte`](src/lib/components/player/AudioPlayer.svelte#L1) - - **Line:** 1 +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L4) + - **Line:** 4 - **Context:** `Unknown` ### UR-050 @@ -6080,47 +6202,50 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 86 - **Context:** `Unknown` -### UR-061 +### UT-010 -**Locations:** 4 file(s) +**Locations:** 1 file(s) -- **File:** [`src/lib/components/player/tapGestures.ts`](src/lib/components/player/tapGestures.ts#L21) - - **Line:** 21 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.tapSurface.test.ts`](src/lib/components/player/VideoPlayer.tapSurface.test.ts#L5) - - **Line:** 5 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.touchScrub.test.ts`](src/lib/components/player/VideoPlayer.touchScrub.test.ts#L21) - - **Line:** 21 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) - - **Line:** 1 +- **File:** [`src/lib/stores/downloads.test.ts`](src/lib/stores/downloads.test.ts#L2) + - **Line:** 2 - **Context:** `Unknown` -### UR-064 +### UT-024 -**Locations:** 7 file(s) +**Locations:** 1 file(s) -- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1369) - - **Line:** 1369 +- **File:** [`src/lib/stores/downloads.test.ts`](src/lib/stores/downloads.test.ts#L2) + - **Line:** 2 - **Context:** `Unknown` -- **File:** [`src/lib/api/repository-client.ts`](src/lib/api/repository-client.ts#L165) - - **Line:** 165 + +### UT-052 + +**Locations:** 1 file(s) + +- **File:** [`src/lib/stores/downloads.test.ts`](src/lib/stores/downloads.test.ts#L315) + - **Line:** 315 - **Context:** `Unknown` -- **File:** [`src/lib/components/library/ClearHistoryButton.svelte`](src/lib/components/library/ClearHistoryButton.svelte#L9) - - **Line:** 9 + +### UT-060 + +**Locations:** 3 file(s) + +- **File:** [`src/lib/components/player/backgroundAudioHandoff.test.ts`](src/lib/components/player/backgroundAudioHandoff.test.ts#L11) + - **Line:** 11 - **Context:** `Unknown` -- **File:** [`src/lib/components/library/SeasonSection.svelte`](src/lib/components/library/SeasonSection.svelte#L1) - - **Line:** 1 +- **File:** [`src/lib/components/player/backgroundAudioHandoff.ts`](src/lib/components/player/backgroundAudioHandoff.ts#L4) + - **Line:** 4 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L387) - - **Line:** 387 +- **File:** [`src/lib/components/player/backgroundAudioHandoff.ts`](src/lib/components/player/backgroundAudioHandoff.ts#L69) + - **Line:** 69 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L235) - - **Line:** 235 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1874) - - **Line:** 1874 + +### UT-071 + +**Locations:** 1 file(s) + +- **File:** [`src/lib/utils/formatBytes.test.ts`](src/lib/utils/formatBytes.test.ts#L4) + - **Line:** 4 - **Context:** `Unknown` ### UT-085 @@ -6156,10 +6281,26 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 833 - **Context:** `Unknown` +### UT-088 + +**Locations:** 1 file(s) + +- **File:** [`src/lib/components/player/tapGestures.ts`](src/lib/components/player/tapGestures.ts#L21) + - **Line:** 21 + - **Context:** `Unknown` + ### UT-089 **Locations:** 1 file(s) +- **File:** [`src/lib/components/player/VideoPlayer.touchScrub.test.ts`](src/lib/components/player/VideoPlayer.touchScrub.test.ts#L21) + - **Line:** 21 + - **Context:** `Unknown` + +### UT-090 + +**Locations:** 1 file(s) + - **File:** [`src/lib/components/player/VideoPlayer.touchScrub.test.ts`](src/lib/components/player/VideoPlayer.touchScrub.test.ts#L21) - **Line:** 21 - **Context:** `Unknown` @@ -6205,14 +6346,51 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L4253) - **Line:** 4253 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L624) - - **Line:** 624 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L622) + - **Line:** 622 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L661) - - **Line:** 661 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L659) + - **Line:** 659 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2655) - - **Line:** 2655 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2677) + - **Line:** 2677 + - **Context:** `Unknown` + +### UT-105 + +**Locations:** 3 file(s) + +- **File:** [`src/lib/stores/favorites.ts`](src/lib/stores/favorites.ts#L8) + - **Line:** 8 + - **Context:** `Unknown` +- **File:** [`src/lib/stores/favorites.ts`](src/lib/stores/favorites.ts#L55) + - **Line:** 55 + - **Context:** `Unknown` +- **File:** [`src/lib/stores/favorites.test.ts`](src/lib/stores/favorites.test.ts#L1) + - **Line:** 1 + - **Context:** `Unknown` + +### UT-107 + +**Locations:** 6 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L1498) + - **Line:** 1498 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L806) + - **Line:** 806 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L821) + - **Line:** 821 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L840) + - **Line:** 840 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L994) + - **Line:** 994 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L1019) + - **Line:** 1019 - **Context:** `Unknown` ### UT-118 @@ -6227,11 +6405,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 2 file(s) -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L392) - - **Line:** 392 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L416) + - **Line:** 416 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2465) - - **Line:** 2465 +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2624) + - **Line:** 2624 - **Context:** `Unknown` ### UT-121 @@ -6344,32 +6522,49 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 1 - **Context:** `Unknown` -### UT-143 - -**Locations:** 3 file(s) - -- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L15) - - **Line:** 15 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L16) - - **Line:** 16 - - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L291) - - **Line:** 291 - - **Context:** `Unknown` - ### UT-144 **Locations:** 3 file(s) -- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L15) - - **Line:** 15 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L293) + - **Line:** 293 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L16) - - **Line:** 16 +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L18) + - **Line:** 18 - **Context:** `Unknown` -- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L291) - - **Line:** 291 +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L20) + - **Line:** 20 + - **Context:** `Unknown` + +### UT-145 + +**Locations:** 5 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2254) + - **Line:** 2254 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L223) + - **Line:** 223 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L399) + - **Line:** 399 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2501) + - **Line:** 2501 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2558) + - **Line:** 2558 + - **Context:** `Unknown` + +### UR-008 + +**Locations:** 2 file(s) + +- **File:** [`src/lib/components/library/GenericMediaListPage.searchEvent.test.ts`](src/lib/components/library/GenericMediaListPage.searchEvent.test.ts#L12) + - **Line:** 12 + - **Context:** `Unknown` +- **File:** [`src/lib/stores/library.ts`](src/lib/stores/library.ts#L2) + - **Line:** 2 - **Context:** `Unknown` ### UR-010 @@ -6465,14 +6660,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 2 - **Context:** `Unknown` -### UR-014 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/commands/playlist.rs`](src-tauri/src/commands/playlist.rs#L4) - - **Line:** 4 - - **Context:** `Unknown` - ### UR-015 **Locations:** 13 file(s) @@ -6542,11 +6729,78 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 2040 - **Context:** `Unknown` -### UR-022 +### UR-019 -**Locations:** 1 file(s) +**Locations:** 12 file(s) -- **File:** [`src-tauri/src/commands/player/settings.rs`](src-tauri/src/commands/player/settings.rs#L3) +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2495) + - **Line:** 2495 + - **Context:** `Unknown` +- **File:** [`src/lib/services/playerEvents.test.ts`](src/lib/services/playerEvents.test.ts#L4) + - **Line:** 4 + - **Context:** `Unknown` +- **File:** [`src/lib/services/playbackReporting.test.ts`](src/lib/services/playbackReporting.test.ts#L4) + - **Line:** 4 + - **Context:** `Unknown` +- **File:** [`src/lib/services/playbackReporting.ts`](src/lib/services/playbackReporting.ts#L10) + - **Line:** 10 + - **Context:** `Unknown` +- **File:** [`src/lib/services/playerEvents.ts`](src/lib/services/playerEvents.ts#L8) + - **Line:** 8 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L6) + - **Line:** 6 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/events.rs`](src-tauri/src/player/events.rs#L23) + - **Line:** 23 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/mod.rs`](src-tauri/src/player/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/storage/mod.rs`](src-tauri/src/commands/storage/mod.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/playback_reporting.rs`](src-tauri/src/commands/playback_reporting.rs#L3) + - **Line:** 3 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/mod.rs`](src-tauri/src/commands/mod.rs#L2) + - **Line:** 2 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/storage/mod.rs`](src-tauri/src/storage/mod.rs#L157) + - **Line:** 157 + - **Context:** `pub fn file_size(&self) -> Option {` + +### UT-146 + +**Locations:** 3 file(s) + +- **File:** [`src/lib/api/bindings.ts`](src/lib/api/bindings.ts#L2810) + - **Line:** 2810 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/player/media.rs`](src-tauri/src/player/media.rs#L42) + - **Line:** 42 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L2590) + - **Line:** 2590 + - **Context:** `Unknown` + +### UR-021 + +**Locations:** 5 file(s) + +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/types.ts`](src/lib/player/adapters/types.ts#L15) + - **Line:** 15 + - **Context:** `Unknown` +- **File:** [`src/lib/player/adapters/html5Adapter.ts`](src/lib/player/adapters/html5Adapter.ts#L19) + - **Line:** 19 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/player/mod.rs`](src-tauri/src/commands/player/mod.rs#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/commands/storage/series_prefs.rs`](src-tauri/src/commands/storage/series_prefs.rs#L3) - **Line:** 3 - **Context:** `Unknown` @@ -6561,6 +6815,17 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 3 - **Context:** `Unknown` +### UR-028 + +**Locations:** 2 file(s) + +- **File:** [`src/lib/components/player/MiniPlayer.svelte`](src/lib/components/player/MiniPlayer.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/AudioPlayer.svelte`](src/lib/components/player/AudioPlayer.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` + ### UR-030 **Locations:** 2 file(s) @@ -6572,17 +6837,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 2 - **Context:** `Unknown` -### UR-031 - -**Locations:** 2 file(s) - -- **File:** [`src-tauri/src/commands/player/settings.rs`](src-tauri/src/commands/player/settings.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/settings.rs`](src-tauri/src/settings.rs#L1) - - **Line:** 1 - - **Context:** `Unknown` - ### UR-032 **Locations:** 7 file(s) @@ -6650,20 +6904,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 234 - **Context:** `Unknown` -### UR-036 - -**Locations:** 3 file(s) - -- **File:** [`src/lib/components/library/PersonDetailView.svelte`](src/lib/components/library/PersonDetailView.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/storage/people.rs`](src-tauri/src/commands/storage/people.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/repository.rs`](src-tauri/src/commands/repository.rs#L4) - - **Line:** 4 - - **Context:** `Unknown` - ### UR-039 **Locations:** 1 file(s) @@ -6680,14 +6920,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 4 - **Context:** `Unknown` -### UR-042 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/commands/auth.rs`](src-tauri/src/commands/auth.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` - ### UR-043 **Locations:** 2 file(s) @@ -6699,14 +6931,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 3 - **Context:** `Unknown` -### UR-044 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/commands/download/pinning.rs`](src-tauri/src/commands/download/pinning.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` - ### UR-045 **Locations:** 1 file(s) @@ -6715,33 +6939,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 3 - **Context:** `Unknown` -### UR-046 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/commands/player/remote.rs`](src-tauri/src/commands/player/remote.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` - -### UR-047 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/commands/storage/mod.rs`](src-tauri/src/commands/storage/mod.rs#L3) - - **Line:** 3 - - **Context:** `Unknown` - -### UR-051 - -**Locations:** 2 file(s) - -- **File:** [`src/lib/components/library/LibraryGrid.svelte`](src/lib/components/library/LibraryGrid.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` -- **File:** [`src/lib/components/library/MediaCard.svelte`](src/lib/components/library/MediaCard.svelte#L1) - - **Line:** 1 - - **Context:** `Unknown` - ### UR-054 **Locations:** 6 file(s) @@ -6788,46 +6985,81 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 9 - **Context:** `Unknown` -### UT-096 +### UR-061 -**Locations:** 1 file(s) +**Locations:** 4 file(s) -- **File:** [`src/lib/utils/safeArea.test.ts`](src/lib/utils/safeArea.test.ts#L17) - - **Line:** 17 +- **File:** [`src/lib/components/player/tapGestures.ts`](src/lib/components/player/tapGestures.ts#L21) + - **Line:** 21 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.tapSurface.test.ts`](src/lib/components/player/VideoPlayer.tapSurface.test.ts#L5) + - **Line:** 5 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.touchScrub.test.ts`](src/lib/components/player/VideoPlayer.touchScrub.test.ts#L21) + - **Line:** 21 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1) + - **Line:** 1 - **Context:** `Unknown` -### UT-097 +### UT-143 -**Locations:** 1 file(s) +**Locations:** 5 file(s) -- **File:** [`src/lib/utils/safeArea.test.ts`](src/lib/utils/safeArea.test.ts#L17) - - **Line:** 17 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L293) + - **Line:** 293 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L18) + - **Line:** 18 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L20) + - **Line:** 20 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L105) + - **Line:** 105 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/device_profile.rs`](src-tauri/src/repository/device_profile.rs#L127) + - **Line:** 127 - **Context:** `Unknown` -### UR-060 +### UT-147 -**Locations:** 7 file(s) +**Locations:** 8 file(s) -- **File:** [`src/lib/utils/searchScope.ts`](src/lib/utils/searchScope.ts#L155) - - **Line:** 155 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L302) + - **Line:** 302 - **Context:** `Unknown` -- **File:** [`src/lib/utils/searchScope.ts`](src/lib/utils/searchScope.ts#L221) - - **Line:** 221 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L622) + - **Line:** 622 - **Context:** `Unknown` -- **File:** [`src-tauri/src/commands/catalog.rs`](src-tauri/src/commands/catalog.rs#L96) - - **Line:** 96 +- **File:** [`src/lib/components/player/VideoPlayer.svelte`](src/lib/components/player/VideoPlayer.svelte#L1772) + - **Line:** 1772 - **Context:** `Unknown` -- **File:** [`src-tauri/src/storage/schema.rs`](src-tauri/src/storage/schema.rs#L769) - - **Line:** 769 +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L159) + - **Line:** 159 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L333) - - **Line:** 333 +- **File:** [`src/lib/components/player/subtitleTracks.test.ts`](src/lib/components/player/subtitleTracks.test.ts#L282) + - **Line:** 282 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L3017) - - **Line:** 3017 +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L20) + - **Line:** 20 - **Context:** `Unknown` -- **File:** [`src-tauri/src/domain/search_rank.rs`](src-tauri/src/domain/search_rank.rs#L106) - - **Line:** 106 +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L183) + - **Line:** 183 + - **Context:** `Unknown` +- **File:** [`src/lib/components/player/subtitleTracks.ts`](src/lib/components/player/subtitleTracks.ts#L218) + - **Line:** 218 + - **Context:** `Unknown` + +### UR-051 + +**Locations:** 2 file(s) + +- **File:** [`src/lib/components/library/LibraryGrid.svelte`](src/lib/components/library/LibraryGrid.svelte#L1) + - **Line:** 1 + - **Context:** `Unknown` +- **File:** [`src/lib/components/library/MediaCard.svelte`](src/lib/components/library/MediaCard.svelte#L1) + - **Line:** 1 - **Context:** `Unknown` ### UR-065 @@ -6901,22 +7133,6 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **Line:** 1332 - **Context:** `Unknown` -### IT-016 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/repository/offline.rs`](src-tauri/src/repository/offline.rs#L2956) - - **Line:** 2956 - - **Context:** `Unknown` - -### IT-017 - -**Locations:** 1 file(s) - -- **File:** [`src-tauri/src/commands/catalog.rs`](src-tauri/src/commands/catalog.rs#L854) - - **Line:** 854 - - **Context:** `Unknown` - ### UT-014 **Locations:** 2 file(s) @@ -7058,14 +7274,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 3 file(s) -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L452) - - **Line:** 452 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L450) + - **Line:** 450 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2375) - - **Line:** 2375 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2397) + - **Line:** 2397 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2416) - - **Line:** 2416 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2438) + - **Line:** 2438 - **Context:** `Unknown` ### UT-067 @@ -7168,14 +7384,14 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 3 file(s) -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L592) - - **Line:** 592 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L590) + - **Line:** 590 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2692) - - **Line:** 2692 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2714) + - **Line:** 2714 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2723) - - **Line:** 2723 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2745) + - **Line:** 2745 - **Context:** `Unknown` ### UT-100 @@ -7185,20 +7401,20 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, - **File:** [`src-tauri/src/repository/mod.rs`](src-tauri/src/repository/mod.rs#L223) - **Line:** 223 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L683) - - **Line:** 683 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L681) + - **Line:** 681 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1814) - - **Line:** 1814 - - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2602) - - **Line:** 2602 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L1836) + - **Line:** 1836 - **Context:** `Unknown` - **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2624) - **Line:** 2624 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2633) - - **Line:** 2633 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2646) + - **Line:** 2646 + - **Context:** `Unknown` +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L2655) + - **Line:** 2655 - **Context:** `Unknown` ### UT-101 @@ -7453,11 +7669,11 @@ JA-001, JA-002, JA-003, JA-004, JA-005, JA-007, JA-010, JA-011, JA-012, JA-016, **Locations:** 2 file(s) -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L386) - - **Line:** 386 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L384) + - **Line:** 384 - **Context:** `Unknown` -- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L452) - - **Line:** 452 +- **File:** [`src-tauri/src/repository/online.rs`](src-tauri/src/repository/online.rs#L450) + - **Line:** 450 - **Context:** `Unknown` ### UT-141 diff --git a/src-tauri/src/commands/player/mod.rs b/src-tauri/src/commands/player/mod.rs index d916ee15..0b5b118d 100644 --- a/src-tauri/src/commands/player/mod.rs +++ b/src-tauri/src/commands/player/mod.rs @@ -202,6 +202,27 @@ pub struct PlayItemRequest { /// look up the next episode when a background-audio track ends. #[serde(default)] pub series_id: Option, + /// Subtitle tracks to sideload, with URLs the frontend has already resolved. + /// + /// Only the native backends use these: on Android they become the + /// `MediaItem.SubtitleConfiguration`s ExoPlayer renders. The HTML5 path + /// builds its own `` children instead and ignores this list. + /// + /// **Order is the contract.** `player_set_subtitle_track(n)` reaches + /// `JellyTauPlayer.setSubtitleTrack(n)`, which indexes into ExoPlayer's + /// *text track groups* — i.e. the position of the sideloaded configuration, + /// not the Jellyfin stream index (which is kept on each entry for the UI's + /// benefit). So `n` must be a position in this very array, and the array + /// must not be reordered or filtered between building it and sending it. + /// `nativeSubtitleArrayIndex()` on the frontend computes `n` from the same + /// list that is sent here, for exactly this reason. + /// + /// Defaulted so the background-audio handoff and the autoplay/next-episode + /// callers, which have no subtitles to offer, need not send the field. + /// + /// TRACES: UR-020 | IR-016, JA-008 | UT-145 + #[serde(default)] + pub subtitles: Vec, } /// Queue context for remote transfer - what type of queue is this? @@ -373,7 +394,10 @@ pub(super) async fn create_media_item( needs_transcoding: req.needs_transcoding, video_width: None, // Not available from video-only request video_height: None, // Not available from video-only request - subtitles: vec![], + // Sideloaded subtitles, in the order the frontend sent them — that order + // is what `player_set_subtitle_track(n)` indexes into on Android. + // TRACES: UR-020 | IR-016 | UT-145 + subtitles: req.subtitles, series_id: None, // Not available from video-only request server_id: None, // Not available from video-only request }) @@ -2459,6 +2483,141 @@ pub async fn player_disable_jellyfin(player: State<'_, PlayerStateWrapper>) -> R #[cfg(test)] mod tests { + /// The subtitle list the frontend resolved must survive the IPC hop and end + /// up on the `MediaItem` the native backend loads. + /// + /// The bug: `VideoPlayer.svelte` built a fully-resolved subtitle array and + /// then dropped it on the floor — `PlayItemRequest` had no field to put it + /// in — so `create_media_item` always produced `subtitles: vec![]`, + /// `android/mod.rs` serialized `[]` across JNI, and ExoPlayer was handed a + /// `MediaItem` with zero `SubtitleConfiguration`s. Every later + /// `setSubtitleTrack(n)` then found no text track groups and logged + /// "Invalid subtitle track index". + /// + /// The payload below is exactly what the frontend sends: camelCase for the + /// top-level command params (Tauri v2 converts them), and the subtitle + /// entries in the casing of `SubtitleTrack` itself — note `mime_type`. + /// + /// TRACES: UR-020 | IR-016 | UT-145 + #[tokio::test] + async fn test_play_item_request_carries_subtitles_into_media_item() { + use super::{create_media_item, PlayItemRequest}; + + let payload = serde_json::json!({ + "id": "ep-1", + "title": "Pilot", + "streamUrl": "https://jelly.example/Videos/ep-1/master.m3u8", + "videoCodec": "h264", + "needsTranscoding": false, + "subtitles": [ + { + "index": 2, + "url": "https://jelly.example/Videos/ep-1/2/Subtitles/subtitles.vtt", + "language": "eng", + "label": "English (SRT)", + "mime_type": "text/vtt" + }, + { + "index": 3, + "url": "https://jelly.example/Videos/ep-1/3/Subtitles/subtitles.vtt", + "language": null, + "label": null, + "mime_type": "text/vtt" + } + ] + }); + + let req: PlayItemRequest = + serde_json::from_value(payload).expect("frontend payload must deserialize"); + assert_eq!( + req.subtitles.len(), + 2, + "PlayItemRequest must carry the subtitle tracks, not silently ignore them" + ); + + let media = create_media_item(req, None).await.unwrap(); + assert_eq!( + media.subtitles.len(), + 2, + "create_media_item must thread the tracks onto the MediaItem the backend loads" + ); + assert_eq!(media.subtitles[0].index, 2); + assert_eq!(media.subtitles[0].language.as_deref(), Some("eng")); + assert_eq!(media.subtitles[0].label.as_deref(), Some("English (SRT)")); + assert_eq!(media.subtitles[0].mime_type, "text/vtt"); + // Order is the contract: `player_set_subtitle_track(n)` is a position in + // this list (see the note on `PlayItemRequest::subtitles`). + assert_eq!(media.subtitles[1].index, 3); + assert!(media.subtitles[1].language.is_none()); + } + + /// A request without subtitles must still deserialize — the field is + /// defaulted so the background-audio handoff and the autoplay/next-episode + /// callers keep compiling and sending what they always sent. + /// + /// TRACES: UR-020 | IR-016 | UT-145 + #[tokio::test] + async fn test_play_item_request_without_subtitles_defaults_to_empty() { + use super::{create_media_item, PlayItemRequest}; + + let req: PlayItemRequest = serde_json::from_value(serde_json::json!({ + "id": "movie-1", + "title": "Movie", + "streamUrl": "https://jelly.example/Videos/movie-1/stream.mp4", + "videoCodec": "h264", + "needsTranscoding": false + })) + .expect("a subtitle-less payload must still deserialize"); + + assert!(req.subtitles.is_empty()); + assert!(create_media_item(req, None) + .await + .unwrap() + .subtitles + .is_empty()); + } + + /// The JSON handed to Kotlin over JNI must use the keys + /// `JellyTauPlayer.load()` actually reads. + /// + /// `MediaItem` is `rename_all = "camelCase"`, and the instinct (and the + /// house IPC rule) is to camelCase nested structs too — but + /// `JellyTauPlayer.kt` reads `subtitle.optString("mime_type", …)`. Renaming + /// the field would not fail to compile or fail the IPC; it would silently + /// fall back to the default MIME type for every track, so this is asserted + /// on the exact bytes `android/mod.rs` sends. + /// + /// TRACES: UR-020 | IR-016, JA-008 | UT-146 + #[test] + fn test_subtitle_json_for_jni_uses_the_keys_kotlin_reads() { + use crate::player::media::SubtitleTrack; + + let subtitles = vec![SubtitleTrack { + index: 2, + url: "https://jelly.example/subs.vtt".to_string(), + language: Some("eng".to_string()), + label: Some("English".to_string()), + mime_type: "text/vtt".to_string(), + }]; + + // Exactly what player/android/mod.rs passes to loadWithMetadata. + let json = serde_json::to_string(&subtitles).unwrap(); + let parsed: Vec = serde_json::from_str(&json).unwrap(); + let obj = parsed[0].as_object().unwrap(); + + for key in ["url", "language", "label", "mime_type"] { + assert!( + obj.contains_key(key), + "JellyTauPlayer.load() reads `{key}`; serialized keys were {:?}", + obj.keys().collect::>() + ); + } + assert!( + !obj.contains_key("mimeType"), + "camelCasing mime_type silently drops every track's MIME type on Android" + ); + } + /// The audio-only handoff must play a downloaded file when there is one, /// rather than fetching an audio-only stream for media already on disk. /// diff --git a/src-tauri/src/player/media.rs b/src-tauri/src/player/media.rs index 7bf70ecc..035fde4e 100644 --- a/src-tauri/src/player/media.rs +++ b/src-tauri/src/player/media.rs @@ -23,6 +23,23 @@ pub enum QueueContext { } /// Represents a subtitle track +/// +/// 🔴 **Do not add `#[serde(rename_all = "camelCase")]` here.** This is the one +/// struct in the player that deliberately keeps snake_case on the wire, because +/// the *same* serialization feeds two consumers that both spell `mime_type`: +/// +/// * the JNI boundary — `player/android/mod.rs` serializes `MediaItem::subtitles` +/// with `serde_json` and hands the string to `JellyTauPlayer.loadWithMetadata`, +/// whose parser reads `url`, `language`, `label` and `optString("mime_type")`; +/// * the IPC boundary — `PlayItemRequest::subtitles` deserializes this same type +/// from the frontend, and the generated binding (`SubtitleTrack` in +/// `bindings.ts`) therefore also declares `mime_type`. +/// +/// Renaming would not break the build and would not fail the IPC: Kotlin's +/// `optString` would just fall back to its default MIME type for every track, so +/// the failure would be silent. UT-146 asserts the serialized keys. +/// +/// TRACES: UR-020 | IR-016, JA-008 | UT-146 #[derive(specta::Type, Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct SubtitleTrack { /// Stream index in the media source @@ -33,7 +50,8 @@ pub struct SubtitleTrack { pub language: Option, /// Display title pub label: Option, - /// MIME type (e.g., "text/vtt", "application/x-subrip") + /// MIME type (e.g., "text/vtt", "application/x-subrip"). + /// Snake_case on purpose — see the note on the struct. pub mime_type: String, } diff --git a/src-tauri/src/player/mod.rs b/src-tauri/src/player/mod.rs index 029b6ad1..3812d3bd 100644 --- a/src-tauri/src/player/mod.rs +++ b/src-tauri/src/player/mod.rs @@ -32,7 +32,7 @@ pub mod webview_audio_backend; pub use autoplay::{AutoplayDecision, AutoplaySettings}; pub use backend::{NullBackend, PlayerBackend, PlayerError}; pub use events::{PlayerEventEmitter, PlayerStatusEvent, TauriEventEmitter}; -pub use media::{MediaItem, MediaSource, MediaType, QueueContext}; +pub use media::{MediaItem, MediaSource, MediaType, QueueContext, SubtitleTrack}; pub use queue::{QueueManager, RepeatMode}; pub use seek::{determine_video_seek_strategy, VideoSeekStrategy}; pub use session::{MediaSessionManager, MediaSessionType}; diff --git a/src/lib/api/bindings.ts b/src/lib/api/bindings.ts index 81a2e4ce..0cdebb88 100644 --- a/src/lib/api/bindings.ts +++ b/src/lib/api/bindings.ts @@ -2231,7 +2231,29 @@ itemType?: string | null; * Series ID for TV episodes. Needed alongside `item_type` so the backend can * look up the next episode when a background-audio track ends. */ -seriesId?: string | null } +seriesId?: string | null; +/** + * Subtitle tracks to sideload, with URLs the frontend has already resolved. + * + * Only the native backends use these: on Android they become the + * `MediaItem.SubtitleConfiguration`s ExoPlayer renders. The HTML5 path + * builds its own `` children instead and ignores this list. + * + * **Order is the contract.** `player_set_subtitle_track(n)` reaches + * `JellyTauPlayer.setSubtitleTrack(n)`, which indexes into ExoPlayer's + * *text track groups* — i.e. the position of the sideloaded configuration, + * not the Jellyfin stream index (which is kept on each entry for the UI's + * benefit). So `n` must be a position in this very array, and the array + * must not be reordered or filtered between building it and sending it. + * `nativeSubtitleArrayIndex()` on the frontend computes `n` from the same + * list that is sent here, for exactly this reason. + * + * Defaulted so the background-audio handoff and the autoplay/next-episode + * callers, which have no subtitles to offer, need not send the field. + * + * TRACES: UR-020 | IR-016, JA-008 | UT-145 + */ +subtitles?: SubtitleTrack[] } /** * Queue context for remote transfer - what type of queue is this? */ @@ -2769,6 +2791,23 @@ export type StreamKind = "audio" | "video" | "subtitle" | "other" /** * Represents a subtitle track + * + * 🔴 **Do not add `#[serde(rename_all = "camelCase")]` here.** This is the one + * struct in the player that deliberately keeps snake_case on the wire, because + * the *same* serialization feeds two consumers that both spell `mime_type`: + * + * * the JNI boundary — `player/android/mod.rs` serializes `MediaItem::subtitles` + * with `serde_json` and hands the string to `JellyTauPlayer.loadWithMetadata`, + * whose parser reads `url`, `language`, `label` and `optString("mime_type")`; + * * the IPC boundary — `PlayItemRequest::subtitles` deserializes this same type + * from the frontend, and the generated binding (`SubtitleTrack` in + * `bindings.ts`) therefore also declares `mime_type`. + * + * Renaming would not break the build and would not fail the IPC: Kotlin's + * `optString` would just fall back to its default MIME type for every track, so + * the failure would be silent. UT-146 asserts the serialized keys. + * + * TRACES: UR-020 | IR-016, JA-008 | UT-146 */ export type SubtitleTrack = { /** @@ -2788,7 +2827,8 @@ language: string | null; */ label: string | null; /** - * MIME type (e.g., "text/vtt", "application/x-subrip") + * MIME type (e.g., "text/vtt", "application/x-subrip"). + * Snake_case on purpose — see the note on the struct. */ mime_type: string } /** diff --git a/src/lib/components/player/VideoPlayer.svelte b/src/lib/components/player/VideoPlayer.svelte index 4c036a5e..29daaa01 100644 --- a/src/lib/components/player/VideoPlayer.svelte +++ b/src/lib/components/player/VideoPlayer.svelte @@ -18,6 +18,8 @@ resolveSubtitleTracks, reconcileSelectedSubtitle, videoCrossOriginMode, + nativeSubtitleTracks, + nativeSubtitleArrayIndex, type RenderableSubtitleTrack, } from "./subtitleTracks"; import { sleepTimerActive, sleepTimerExpiredSignal } from "$lib/stores/sleepTimer"; @@ -291,6 +293,15 @@ // TRACES: UR-020 | DR-023 | UT-143, UT-144 let renderedSubtitleTracks = $state([]); + // The subtitle list actually handed to the native backend at load time + // (Android/ExoPlayer). Kept because `player_set_subtitle_track` takes a + // *position in this list*, not a Jellyfin stream index — see + // nativeSubtitleArrayIndex. It is written once, from onMount, before the + // play request; it is not derived, because the request is what fixed the + // backend's idea of the track order. + // TRACES: UR-020 | IR-016 | UT-147 + let sentSubtitleTracks = $state([]); + // Cross-origin fetches use the media element's CORS setting; see // videoCrossOriginMode for why this is opt-in and same-origin-only. const videoCrossOrigin = $derived( @@ -596,28 +607,23 @@ console.log("[VideoPlayer] Initializing player for:", media.name); console.log("[VideoPlayer] Stream URL:", currentStreamUrl); - // Build subtitle tracks for native player - const subtitleTracks = []; - if (media.mediaStreams && mediaSourceId) { - const subtitles = media.mediaStreams.filter(s => s.kind === "subtitle"); - for (const sub of subtitles) { - try { - const url = await getSubtitleUrl(sub.index); - if (url) { - subtitleTracks.push({ - index: sub.index, - url: url, - language: sub.language || null, - label: sub.displayTitle || sub.language || `Track ${sub.index}`, - mime_type: "text/vtt" // Jellyfin converts to WebVTT - }); - } - } catch (err) { - console.warn(`[VideoPlayer] Failed to build subtitle URL for track ${sub.index}:`, err); - } - } - console.log(`[VideoPlayer] Built ${subtitleTracks.length} subtitle tracks for native player`); - } + // Resolve subtitle URLs for the native (ExoPlayer) path. These must be + // in hand *before* the play request: ExoPlayer sideloads subtitles as + // MediaItem.SubtitleConfigurations, which have to exist before + // prepare() — there is no way to add one to a loaded item afterwards. + // + // Awaiting here is safe despite the native-mode pitfall: that rule is + // about Svelte *lifecycle* calls (onMount/onDestroy) after an await, + // which throw lifecycle_outside_component and used to be misread as an + // init failure. Nothing is registered here, and the background-audio + // subscriptions above already ran synchronously. resolveSubtitleTracks + // fans the requests out in parallel, so this costs one round trip, not + // one per subtitle stream as the old serial loop did. + // TRACES: UR-020 | IR-016, JA-008 | UT-147 + sentSubtitleTracks = mediaSourceId + ? await resolveSubtitleTracks(media.mediaStreams, (index) => getSubtitleUrl(index)) + : []; + console.log(`[VideoPlayer] Sending ${sentSubtitleTracks.length} subtitle tracks to the backend`); // Call Rust backend to start playback // Rust will choose ExoPlayer (Android), libmpv (Linux), or tell us to use HTML5 @@ -628,6 +634,10 @@ id: media.id, videoCodec: needsTranscoding ? "hevc" : "h264", needsTranscoding: needsTranscoding, + // Order matters: player_set_subtitle_track(n) is a position in this + // array. Previously this array was built and then dropped, so + // ExoPlayer got a MediaItem with no subtitles at all. + subtitles: nativeSubtitleTracks(sentSubtitleTracks), }); // Rust tells us which backend it's using @@ -1747,8 +1757,22 @@ }); } - async function selectSubtitle(streamIndex: number | null, arrayIndex?: number) { - console.log("[VideoPlayer] Selecting subtitle - streamIndex:", streamIndex, "arrayIndex:", arrayIndex); + /** + * Apply the menu's choice. `streamIndex` is always the Jellyfin media-stream + * index (or `null` for "Off") — the UI speaks stream indices throughout. + * + * The native backend does not: `player_set_subtitle_track(n)` reaches + * `JellyTauPlayer.setSubtitleTrack(n)`, which indexes ExoPlayer's text track + * groups, i.e. the position of the sideloaded subtitle configuration. That + * position is derived from `sentSubtitleTracks` — the exact array sent with + * the play request — and not from the menu's row number, which counts every + * subtitle *stream* including ones whose URL never resolved and so were never + * sideloaded. + * + * TRACES: UR-020 | DR-023, IR-016 | UT-147 + */ + async function selectSubtitle(streamIndex: number | null) { + console.log("[VideoPlayer] Selecting subtitle - streamIndex:", streamIndex); selectedSubtitleIndex = streamIndex; showSubtitleMenu = false; @@ -1758,11 +1782,9 @@ } else { // For native backend (Android), send command to change subtitle track try { - // Use array index for ExoPlayer (0-based position in subtitle tracks array) - // If streamIndex is null (disable), pass null; otherwise use arrayIndex - const indexToUse = streamIndex === null ? null : (arrayIndex !== undefined ? arrayIndex : streamIndex); + const indexToUse = nativeSubtitleArrayIndex(sentSubtitleTracks, streamIndex); await commands.playerSetSubtitleTrack(indexToUse); - console.log("[VideoPlayer] Native backend subtitle track changed - arrayIndex:", arrayIndex, "used:", indexToUse); + console.log("[VideoPlayer] Native backend subtitle track changed - streamIndex:", streamIndex, "position:", indexToUse); } catch (error) { console.error("[VideoPlayer] Failed to set subtitle track:", error); } @@ -2135,9 +2157,9 @@ {/if} - {#each subtitleTracks() as track, i} + {#each subtitleTracks() as track}