refactor(logging): route frontend console calls through the logger
TRACES: | DR-204 484 ungated `console.*` calls across 63 non-test frontend files shipped to end users with no way to turn them off. Mechanical substitution, no control flow, error handling or message semantics changed: console.log / console.debug -> log.debug console.info -> log.info console.warn -> log.warn console.error -> log.error Hand-written `"[Scope] …"` prefixes are dropped where the logger's scope now carries them; scope names that already existed are preserved verbatim (`[Auth]`, `[VideoPlayer]`, `[PiP]`, …) and inferred from the filename where a file had none. `src/routes/player/[id]/+page.svelte` keeps its `NextEpisode` and `AutoPlay` sub-scopes as separate loggers rather than flattening them into the page scope. `grep -rn 'console\.' src/` now matches nothing outside the tests and the facade itself.
This commit is contained in:
@@ -24,6 +24,11 @@
|
||||
import { reportSkippedEpisode, shouldSuppressStopReport } from "$lib/services/skipReporting";
|
||||
import { cleanup as cleanupNextEpisode } from "$lib/services/nextEpisodeService";
|
||||
import * as html5Adapter from "$lib/player/html5Adapter";
|
||||
import { createLogger } from "$lib/utils/logger";
|
||||
|
||||
const log = createLogger("PlayerPage");
|
||||
const nextEpisodeLog = createLogger("NextEpisode");
|
||||
const autoPlayLog = createLogger("AutoPlay");
|
||||
|
||||
const itemId = $derived($page.params.id);
|
||||
const queueParam = $derived($page.url.searchParams.get("queue"));
|
||||
@@ -95,7 +100,7 @@
|
||||
const id = itemId;
|
||||
const restart = restartParam;
|
||||
if (id && id !== loadedItemId) {
|
||||
console.log("[AutoPlay] $effect triggered: loading new item", id, "(was:", loadedItemId, ") restart:", restart);
|
||||
autoPlayLog.debug("$effect triggered: loading new item", id, "(was:", loadedItemId, ") restart:", restart);
|
||||
// restart=true (advancing to next episode) forces start-from-beginning,
|
||||
// bypassing the resume-progress check.
|
||||
loadAndPlay(id, restart ? 0 : undefined, restart);
|
||||
@@ -128,16 +133,16 @@
|
||||
let retrievedProgressSeconds: number | null = null;
|
||||
|
||||
try {
|
||||
console.log("loadAndPlay: Loading item", id);
|
||||
log.debug("loadAndPlay: Loading item", id);
|
||||
// Load item details
|
||||
const item = await library.loadItem(id);
|
||||
console.log("loadAndPlay: Loaded item", item.name, "kind:", item.kind);
|
||||
log.debug("loadAndPlay: Loaded item", item.name, "kind:", item.kind);
|
||||
currentMedia = item;
|
||||
|
||||
// Check if this is a non-playable collection type that should be viewed in library instead
|
||||
const collectionKinds: MediaKind[] = ["album", "artist", "series", "season", "folder", "playlist", "channel"];
|
||||
if (item.kind && collectionKinds.includes(item.kind)) {
|
||||
console.log("loadAndPlay: Redirecting collection type to library:", item.kind);
|
||||
log.debug("loadAndPlay: Redirecting collection type to library:", item.kind);
|
||||
goto(`/library/${id}`);
|
||||
return;
|
||||
}
|
||||
@@ -162,7 +167,7 @@
|
||||
forceRestart,
|
||||
})
|
||||
) {
|
||||
console.log("loadAndPlay: Track already playing, showing UI without restarting");
|
||||
log.debug("loadAndPlay: Track already playing, showing UI without restarting");
|
||||
isPlaying = true;
|
||||
loading = false;
|
||||
// hasNext/hasPrevious come from the event-driven queue store.
|
||||
@@ -175,7 +180,7 @@
|
||||
try {
|
||||
await commands.playerStop();
|
||||
queue.clear();
|
||||
console.log("loadAndPlay: Stopped audio backend for video playback");
|
||||
log.debug("loadAndPlay: Stopped audio backend for video playback");
|
||||
} catch (e) {
|
||||
// Ignore - player may not have been playing
|
||||
}
|
||||
@@ -185,43 +190,43 @@
|
||||
// When forceRestart is set (advancing to a next episode) we always start
|
||||
// from the beginning, skipping the resume check and resume dialog.
|
||||
const userId = auth.getUserId();
|
||||
console.log("Resume check - userId:", userId, "itemId:", id, "startPosition:", startPosition, "forceRestart:", forceRestart);
|
||||
log.debug("Resume check - userId:", userId, "itemId:", id, "startPosition:", startPosition, "forceRestart:", forceRestart);
|
||||
|
||||
// Live streams have no fixed position - never resume.
|
||||
if (!startPosition && !forceRestart && userId && !isLive) {
|
||||
try {
|
||||
const progress = await commands.storageGetPlaybackProgress(userId, id);
|
||||
console.log("Resume check - retrieved progress:", progress);
|
||||
log.debug("Resume check - retrieved progress:", progress);
|
||||
|
||||
if (progress && progress.positionMs > 0 && item.durationMs) {
|
||||
const positionSeconds = progress.positionMs / 1000;
|
||||
const totalSeconds = item.durationMs / 1000;
|
||||
const progressPercent = (positionSeconds / totalSeconds) * 100;
|
||||
|
||||
console.log("Resume check - positionSeconds:", positionSeconds, "totalSeconds:", totalSeconds, "progressPercent:", progressPercent);
|
||||
log.debug("Resume check - positionSeconds:", positionSeconds, "totalSeconds:", totalSeconds, "progressPercent:", progressPercent);
|
||||
|
||||
// Store for later use regardless of whether dialog is shown
|
||||
retrievedProgressSeconds = positionSeconds;
|
||||
|
||||
// Show resume dialog if watched > 30 seconds and < 90% complete
|
||||
if (positionSeconds > 30 && progressPercent < 90) {
|
||||
console.log("Resume check - SHOWING RESUME DIALOG");
|
||||
log.debug("Resume check - SHOWING RESUME DIALOG");
|
||||
savedProgress = { positionSeconds, progressPercent };
|
||||
showResumeDialog = true;
|
||||
loading = false;
|
||||
return; // Wait for user decision
|
||||
} else {
|
||||
console.log("Resume check - NOT showing dialog. Position > 30?", positionSeconds > 30, "Progress < 90?", progressPercent < 90);
|
||||
log.debug("Resume check - NOT showing dialog. Position > 30?", positionSeconds > 30, "Progress < 90?", progressPercent < 90);
|
||||
}
|
||||
} else {
|
||||
console.log("Resume check - No valid progress found. Has progress?", !!progress, "Has position?", progress?.positionMs, "Has runtime?", !!item.durationMs);
|
||||
log.debug("Resume check - No valid progress found. Has progress?", !!progress, "Has position?", progress?.positionMs, "Has runtime?", !!item.durationMs);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to check saved progress:", e);
|
||||
log.error("Failed to check saved progress:", e);
|
||||
// Continue with normal playback
|
||||
}
|
||||
} else {
|
||||
console.log("Resume check - Skipped. Reason:", !userId ? "No userId" : "Has startPosition");
|
||||
log.debug("Resume check - Skipped. Reason:", !userId ? "No userId" : "Has startPosition");
|
||||
}
|
||||
|
||||
// Check if this item is downloaded locally
|
||||
@@ -232,7 +237,7 @@
|
||||
|
||||
if (localDownload) {
|
||||
// Use local file for playback
|
||||
console.log("loadAndPlay: Found local download, using offline playback:", localDownload.filePath);
|
||||
log.debug("loadAndPlay: Found local download, using offline playback:", localDownload.filePath);
|
||||
isOfflinePlayback = true;
|
||||
|
||||
// Get the storage path and resolve the file's location. A completed
|
||||
@@ -241,7 +246,7 @@
|
||||
// TRACES: UR-071 | DR-133
|
||||
const storagePath = await commands.storageGetPath();
|
||||
const fullPath = downloadedFilePath(storagePath, localDownload.filePath);
|
||||
console.log("loadAndPlay: Full local path:", fullPath);
|
||||
log.debug("loadAndPlay: Full local path:", fullPath);
|
||||
|
||||
// Serve the file over the loopback media server rather than the asset
|
||||
// protocol: the asset protocol answers a range-less request with the
|
||||
@@ -249,7 +254,7 @@
|
||||
// the URL (it holds the port and the per-session token).
|
||||
// TRACES: UR-071 | DR-137
|
||||
const localUrl = await commands.mediaLocalUrl(fullPath);
|
||||
console.log("loadAndPlay: Local media URL resolved");
|
||||
log.debug("loadAndPlay: Local media URL resolved");
|
||||
|
||||
if (isVideo) {
|
||||
// Local video files don't need transcoding and support native seeking
|
||||
@@ -260,7 +265,7 @@
|
||||
videoInitialPosition = effectivePosition;
|
||||
} else {
|
||||
// Local audio playback via MPV backend
|
||||
console.log("loadAndPlay: Using MPV backend for offline audio");
|
||||
log.debug("loadAndPlay: Using MPV backend for offline audio");
|
||||
// Use player_play_tracks - backend fetches all metadata from single ID
|
||||
const repo = auth.getRepository();
|
||||
const repositoryHandle = repo.getHandle();
|
||||
@@ -286,9 +291,9 @@
|
||||
if (isLive) {
|
||||
// Live TV channels must be "opened" before streaming; the server returns
|
||||
// a ready-to-play HLS transcoding URL. No resume, no seek, no progress.
|
||||
console.log("loadAndPlay: Opening live stream for channel:", id);
|
||||
log.debug("loadAndPlay: Opening live stream for channel:", id);
|
||||
const liveInfo = await repo.openLiveStream(id);
|
||||
console.log("loadAndPlay: Live stream URL:", liveInfo.streamUrl);
|
||||
log.debug("loadAndPlay: Live stream URL:", liveInfo.streamUrl);
|
||||
mediaSourceId = liveInfo.mediaSourceId;
|
||||
streamUrl = liveInfo.streamUrl;
|
||||
videoNeedsTranscoding = true;
|
||||
@@ -298,13 +303,13 @@
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("loadAndPlay: Getting playback info");
|
||||
log.debug("loadAndPlay: Getting playback info");
|
||||
const playbackInfo = await repo.getPlaybackInfo(id);
|
||||
console.log("loadAndPlay: Got playback info, mediaSourceId:", playbackInfo.mediaSourceId);
|
||||
log.debug("loadAndPlay: Got playback info, mediaSourceId:", playbackInfo.mediaSourceId);
|
||||
|
||||
if (isVideo) {
|
||||
// Playback API now detects HEVC/10-bit and returns transcoded URL when needed
|
||||
console.log("loadAndPlay: Using video stream, directPlay:", playbackInfo.directPlay, "needsTranscoding:", playbackInfo.needsTranscoding);
|
||||
log.debug("loadAndPlay: Using video stream, directPlay:", playbackInfo.directPlay, "needsTranscoding:", playbackInfo.needsTranscoding);
|
||||
mediaSourceId = playbackInfo.mediaSourceId;
|
||||
|
||||
// Prefer a completed download over streaming. Audio has done this
|
||||
@@ -328,7 +333,7 @@
|
||||
|
||||
streamUrl = source.url;
|
||||
videoNeedsTranscoding = source.needsTranscoding;
|
||||
console.log(
|
||||
log.debug(
|
||||
source.isLocal
|
||||
? "loadAndPlay: Playing downloaded file from disk"
|
||||
: `loadAndPlay: Using stream URL: ${streamUrl}`
|
||||
@@ -347,17 +352,17 @@
|
||||
const effectivePosition = startPosition ?? retrievedProgressSeconds ?? 0;
|
||||
videoInitialPosition = effectivePosition > 0 ? effectivePosition : 0;
|
||||
if (videoInitialPosition > 0) {
|
||||
console.log("loadAndPlay: Will seek to position after load:", videoInitialPosition);
|
||||
log.debug("loadAndPlay: Will seek to position after load:", videoInitialPosition);
|
||||
}
|
||||
} else {
|
||||
// For audio, use MPV backend
|
||||
console.log("loadAndPlay: Using MPV backend for audio");
|
||||
log.debug("loadAndPlay: Using MPV backend for audio");
|
||||
|
||||
// Check if we have a queue parameter (e.g., queue=parent:albumId)
|
||||
const queueParamValue = queueParam;
|
||||
if (queueParamValue?.startsWith("parent:")) {
|
||||
const parentId = queueParamValue.substring(7); // Remove "parent:" prefix
|
||||
console.log("loadAndPlay: Loading queue from parent:", parentId);
|
||||
log.debug("loadAndPlay: Loading queue from parent:", parentId);
|
||||
|
||||
// Fetch all tracks from the parent (album/playlist)
|
||||
const result = await repo.getItems(parentId, {
|
||||
@@ -372,16 +377,16 @@
|
||||
const startIndex = audioTracks.findIndex(t => t.id === id);
|
||||
const actualStartIndex = startIndex >= 0 ? startIndex : 0;
|
||||
|
||||
console.log("loadAndPlay: Building queue with", audioTracks.length, "tracks, startIndex:", actualStartIndex);
|
||||
log.debug("loadAndPlay: Building queue with", audioTracks.length, "tracks, startIndex:", actualStartIndex);
|
||||
|
||||
// Build queue items with stream URLs
|
||||
// Add error handling and logging for each track
|
||||
const queueItems = await Promise.all(audioTracks.map(async (t, idx) => {
|
||||
try {
|
||||
console.log(`loadAndPlay: Fetching stream URL for track ${idx + 1}/${audioTracks.length}: ${t.name}`);
|
||||
log.debug(`loadAndPlay: Fetching stream URL for track ${idx + 1}/${audioTracks.length}: ${t.name}`);
|
||||
const trackStreamUrl = await repo.getAudioStreamUrl(t.id);
|
||||
if (!trackStreamUrl) {
|
||||
console.error(`loadAndPlay: Empty stream URL for track: ${t.name}`);
|
||||
log.error(`loadAndPlay: Empty stream URL for track: ${t.name}`);
|
||||
throw new Error(`Failed to get stream URL for ${t.name}`);
|
||||
}
|
||||
return {
|
||||
@@ -398,7 +403,7 @@
|
||||
jellyfinItemId: t.id,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(`loadAndPlay: Failed to build queue item for track ${t.name}:`, e);
|
||||
log.error(`loadAndPlay: Failed to build queue item for track ${t.name}:`, e);
|
||||
throw e; // Re-throw to fail fast and show error to user
|
||||
}
|
||||
}));
|
||||
@@ -411,10 +416,10 @@
|
||||
} as unknown as PlayQueueRequest);
|
||||
|
||||
// Queue will auto-update from Rust backend event
|
||||
console.log("loadAndPlay: Successfully set up queue with", audioTracks.length, "tracks");
|
||||
log.debug("loadAndPlay: Successfully set up queue with", audioTracks.length, "tracks");
|
||||
} else {
|
||||
// Fallback to single item playback
|
||||
console.log("loadAndPlay: No audio tracks found in parent, falling back to single item");
|
||||
log.debug("loadAndPlay: No audio tracks found in parent, falling back to single item");
|
||||
// Use player_play_tracks - backend fetches all metadata from single ID
|
||||
const repo = auth.getRepository();
|
||||
const repositoryHandle = repo.getHandle();
|
||||
@@ -430,7 +435,7 @@
|
||||
});
|
||||
|
||||
// Queue will auto-update from Rust backend event
|
||||
console.log("loadAndPlay: Set queue with single item:", item.name);
|
||||
log.debug("loadAndPlay: Set queue with single item:", item.name);
|
||||
}
|
||||
} else {
|
||||
// No queue parameter - single item playback
|
||||
@@ -449,7 +454,7 @@
|
||||
});
|
||||
|
||||
// Queue will auto-update from Rust backend event
|
||||
console.log("loadAndPlay: Set queue with single item:", item.name);
|
||||
log.debug("loadAndPlay: Set queue with single item:", item.name);
|
||||
}
|
||||
|
||||
// Seek to start position if provided
|
||||
@@ -463,14 +468,14 @@
|
||||
loading = false;
|
||||
|
||||
// Fetch next episode for video episodes (for skip button)
|
||||
console.log("[NextEpisode] Post-load check: isVideo=", isVideo, "currentMedia=", currentMedia?.kind, currentMedia?.name);
|
||||
nextEpisodeLog.debug("Post-load check: isVideo=", isVideo, "currentMedia=", currentMedia?.kind, currentMedia?.name);
|
||||
if (isVideo && currentMedia) {
|
||||
fetchNextEpisode(currentMedia);
|
||||
} else {
|
||||
console.log("[NextEpisode] Skipped fetchNextEpisode - isVideo:", isVideo, "currentMedia:", !!currentMedia);
|
||||
nextEpisodeLog.debug("Skipped fetchNextEpisode - isVideo:", isVideo, "currentMedia:", !!currentMedia);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("loadAndPlay error:", e);
|
||||
log.error("loadAndPlay error:", e);
|
||||
// Show detailed error including the full error object
|
||||
if (e instanceof Error) {
|
||||
error = `${e.name}: ${e.message}`;
|
||||
@@ -599,21 +604,21 @@
|
||||
// and check for next episodes. HTML5 video plays independently of the Rust
|
||||
// backend queue, so the backend needs these to know what just finished.
|
||||
const mediaId = currentMedia?.id ?? null;
|
||||
console.log("[AutoPlay] Video ended. currentMedia:", mediaId, currentMedia?.name, "itemId (URL):", itemId);
|
||||
autoPlayLog.debug("Video ended. currentMedia:", mediaId, currentMedia?.name, "itemId (URL):", itemId);
|
||||
try {
|
||||
const repo = auth.getRepository();
|
||||
const repoHandle = repo.getHandle();
|
||||
await commands.playerOnPlaybackEnded(mediaId, repoHandle);
|
||||
} catch (e) {
|
||||
console.error("[AutoPlay] Failed to handle playback ended:", e);
|
||||
autoPlayLog.error("Failed to handle playback ended:", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchNextEpisode(media: MediaItem) {
|
||||
nextEpisode = null;
|
||||
console.log("[NextEpisode] fetchNextEpisode called:", { kind: media.kind, seriesId: media.seriesId, seasonId: media.seasonId, indexNumber: media.indexNumber, id: media.id, name: media.name });
|
||||
nextEpisodeLog.debug("fetchNextEpisode called:", { kind: media.kind, seriesId: media.seriesId, seasonId: media.seasonId, indexNumber: media.indexNumber, id: media.id, name: media.name });
|
||||
if (media.kind !== "episode" || !media.seasonId || media.indexNumber == null) {
|
||||
console.log("[NextEpisode] Skipping - not an episode or missing seasonId/indexNumber");
|
||||
nextEpisodeLog.debug("Skipping - not an episode or missing seasonId/indexNumber");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -621,18 +626,18 @@
|
||||
// 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.kind === "episode");
|
||||
console.log("[NextEpisode] Season has", episodes.length, "episodes, current index:", media.indexNumber);
|
||||
nextEpisodeLog.debug("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);
|
||||
nextEpisodeLog.debug("Set nextEpisode:", nextEpisode.name, "index:", nextEpisode.indexNumber);
|
||||
} else {
|
||||
console.log("[NextEpisode] No next episode in season (current position:", currentIdx, "of", episodes.length, ")");
|
||||
nextEpisodeLog.debug("No next episode in season (current position:", currentIdx, "of", episodes.length, ")");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[NextEpisode] Failed to fetch next episode:", e);
|
||||
nextEpisodeLog.error("Failed to fetch next episode:", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user