Fix warnings and update tracability
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 14s
🏗️ Build and Test JellyTau / Build Android APK (push) Has been skipped
Traceability Validation / Check Requirement Traces (push) Failing after 1s

This commit is contained in:
2026-02-28 20:54:25 +01:00
parent c5be9eb18c
commit 3a9c126dfe
59 changed files with 1285 additions and 396 deletions
+2 -2
View File
@@ -33,10 +33,10 @@
let failedAttempts = 0;
const MAX_SILENT_FAILURES = 3; // Don't log errors for first 3 attempts
onMount(async () => {
onMount(() => {
// Detect platform
try {
const platformName = await platform();
const platformName = platform();
isAndroid = platformName === "android";
} catch (err) {
console.error("Platform detection failed:", err);
+8 -2
View File
@@ -3,7 +3,7 @@
import { page } from "$app/stores";
import { goto } from "$app/navigation";
import { invoke } from "@tauri-apps/api/core";
import type { MediaItem } from "$lib/api/types";
import type { MediaItem, Library } from "$lib/api/types";
import { library, libraryItems, isLibraryLoading, currentLibrary, libraries } from "$lib/stores/library";
import { auth } from "$lib/stores/auth";
import { isServerReachable } from "$lib/stores/connectivity";
@@ -66,6 +66,7 @@
});
async function loadItem() {
if (!itemId) return;
loading = true;
error = null;
seasonData = [];
@@ -171,7 +172,12 @@
return `${minutes}m`;
}
function handleItemClick(clickedItem: MediaItem) {
function handleItemClick(clickedItem: MediaItem | Library) {
if (!("type" in clickedItem)) {
// Library item - navigate to library
goto(`/library/${clickedItem.id}`);
return;
}
switch (clickedItem.type) {
case "Series":
case "Season":
@@ -9,7 +9,7 @@
*/
const config = {
itemTypes: ["Movie"],
itemTypes: ["Movie" as const],
title: "Movie Genres",
backPath: "/library",
genreIcon:
+1 -1
View File
@@ -10,7 +10,7 @@
*/
const config = {
itemType: "MusicAlbum",
itemType: "MusicAlbum" as const,
title: "Albums",
backPath: "/library/music",
searchPlaceholder: "Search albums or artists...",
@@ -10,7 +10,7 @@
*/
const config = {
itemType: "MusicArtist",
itemType: "MusicArtist" as const,
title: "Artists",
backPath: "/library/music",
searchPlaceholder: "Search artists...",
+1 -1
View File
@@ -9,7 +9,7 @@
*/
const config = {
itemTypes: ["MusicAlbum"],
itemTypes: ["MusicAlbum" as const],
title: "Genres",
backPath: "/library/music",
genreIcon:
@@ -9,7 +9,7 @@
*/
const config = {
itemType: "Playlist",
itemType: "Playlist" as const,
title: "Playlists",
backPath: "/library/music",
searchPlaceholder: "Search playlists...",
+1 -1
View File
@@ -10,7 +10,7 @@
*/
const config = {
itemType: "Audio",
itemType: "Audio" as const,
title: "Tracks",
backPath: "/library/music",
searchPlaceholder: "Search tracks or artists...",
+1 -1
View File
@@ -9,7 +9,7 @@
*/
const config = {
itemTypes: ["Series"],
itemTypes: ["Series" as const],
title: "TV Genres",
backPath: "/library",
genreIcon:
+28 -7
View File
@@ -143,6 +143,10 @@
} catch (e) {
// Ignore - queue status will update via polling
}
// Fetch next episode for video skip button
if (isVideo) {
fetchNextEpisode(item);
}
return;
}
@@ -411,8 +415,11 @@
loading = false;
// Fetch next episode for video episodes (for skip button)
console.log("[NextEpisode] Post-load check: isVideo=", isVideo, "currentMedia=", currentMedia?.type, currentMedia?.name);
if (isVideo && currentMedia) {
fetchNextEpisode(currentMedia);
} else {
console.log("[NextEpisode] Skipped fetchNextEpisode - isVideo:", isVideo, "currentMedia:", !!currentMedia);
}
} catch (e) {
console.error("loadAndPlay error:", e);
@@ -528,21 +535,35 @@
async function fetchNextEpisode(media: MediaItem) {
nextEpisode = null;
if (media.type !== "Episode" || !media.seriesId) return;
console.log("[NextEpisode] fetchNextEpisode called:", { type: media.type, seriesId: media.seriesId, seasonId: media.seasonId, indexNumber: media.indexNumber, id: media.id, name: media.name });
if (media.type !== "Episode" || !media.seasonId || media.indexNumber == null) {
console.log("[NextEpisode] Skipping - not an episode or missing seasonId/indexNumber");
return;
}
try {
const repo = auth.getRepository();
const episodes = await repo.getNextUpEpisodes(media.seriesId, 1);
if (episodes.length > 0 && episodes[0].id !== media.id) {
nextEpisode = episodes[0];
// Fetch all episodes in the season sorted by episode number
const result = await repo.getItems(media.seasonId, { sortBy: "IndexNumber", sortOrder: "Ascending", limit: 500 });
const episodes = result.items.filter(e => e.type === "Episode");
console.log("[NextEpisode] Season has", episodes.length, "episodes, current index:", media.indexNumber);
// Find the episode after the current one by index number
const currentIdx = episodes.findIndex(e => e.id === media.id);
if (currentIdx >= 0 && currentIdx < episodes.length - 1) {
nextEpisode = episodes[currentIdx + 1];
console.log("[NextEpisode] Set nextEpisode:", nextEpisode.name, "index:", nextEpisode.indexNumber);
} else {
console.log("[NextEpisode] No next episode in season (current position:", currentIdx, "of", episodes.length, ")");
}
} catch (e) {
console.error("Failed to fetch next episode:", e);
console.error("[NextEpisode] Failed to fetch next episode:", e);
}
}
function handleSkipToNextEpisode() {
if (nextEpisode) {
goto(`/player/${nextEpisode.id}`);
// Use replaceState so "close/back" returns to the library, not the previous episode
goto(`/player/${nextEpisode.id}`, { replaceState: true });
}
}
@@ -605,7 +626,7 @@
<VideoPlayer
media={currentMedia}
{streamUrl}
mediaSourceId={mediaSourceId}
mediaSourceId={mediaSourceId ?? undefined}
initialPosition={videoInitialPosition}
needsTranscoding={videoNeedsTranscoding}
onClose={handleClose}
+1
View File
@@ -1,3 +1,4 @@
<!-- TRACES: UR-023 | DR-048 -->
<script lang="ts">
import { onMount } from "svelte";
import { invoke } from "@tauri-apps/api/core";