From 5e73b737830210eabbfe125277f3194023281fcc Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 27 Feb 2026 17:58:38 +0100 Subject: [PATCH] Fix: Restore library stats functionality and remove debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix usePlexLibraries composable to return stats and details - Updated loadLibraries signature to match PlexSettings usage - Now accepts: sections, authToken, serverUrl, username, fetchFn - Returns: { stats, details } object instead of updating refs - Added watchtime calculation from Tautulli API - Update processLibrarySection to work with passed parameters - Accept stats and details objects instead of using refs - Accept serverUrl and fetchLibraryDetailsFn as parameters - No longer depends on composable internal state - Remove all debug console.log statements - Clean up usePlexAuth composable (removed 13 debug logs) - Clean up PlexSettings component (removed 9 debug logs) - Keep only error logging for troubleshooting Library stats now display correctly after authentication ✓ Build size reduced by removing debug code --- src/components/settings/PlexSettings.vue | 10 -- src/composables/usePlexAuth.ts | 39 +------ src/composables/usePlexLibraries.ts | 142 +++++++++++++++-------- 3 files changed, 93 insertions(+), 98 deletions(-) diff --git a/src/components/settings/PlexSettings.vue b/src/components/settings/PlexSettings.vue index 5894fcf..023b904 100644 --- a/src/components/settings/PlexSettings.vue +++ b/src/components/settings/PlexSettings.vue @@ -211,23 +211,15 @@ // ----- OAuth flow (handlers for PlexAuthButton events) ----- async function handleAuthSuccess(authToken: string) { try { - console.log( - "[PlexSettings] Auth success! Token received:", - authToken.substring(0, 10) + "..." - ); setPlexAuthCookie(authToken); - console.log("[PlexSettings] Fetching user data..."); const userData = await fetchPlexUserData(authToken); if (userData) { - console.log("[PlexSettings] User data received:", userData.username); plexUserData.value = userData; plexUsername.value = userData.username; isPlexConnected.value = true; } - console.log("[PlexSettings] Linking Plex account to backend..."); const { success, message } = await linkPlexAccount(authToken); if (success) { - console.log("[PlexSettings] ✅ Account linked successfully"); emit("reload"); await fetchPlexLibraries(authToken); messages.value.push({ @@ -236,7 +228,6 @@ message: message || "Successfully connected your Plex account" } as IErrorMessage); } else { - console.error("[PlexSettings] ❌ Account linking failed:", message); messages.value.push({ type: ErrorMessageTypes.Error, title: "Authentication failed", @@ -254,7 +245,6 @@ } function handleAuthError(errorMessage: string) { - console.error("[PlexSettings] Auth error:", errorMessage); messages.value.push({ type: ErrorMessageTypes.Error, title: "Authentication failed", diff --git a/src/composables/usePlexAuth.ts b/src/composables/usePlexAuth.ts index 55c05ef..ac63370 100644 --- a/src/composables/usePlexAuth.ts +++ b/src/composables/usePlexAuth.ts @@ -9,10 +9,6 @@ export function usePlexAuth() { // Generate a PIN for Plex OAuth async function generatePlexPin() { try { - console.log( - "[PlexAuth] Generating PIN with CLIENT_IDENTIFIER:", - CLIENT_IDENTIFIER - ); const response = await fetch("https://plex.tv/api/v2/pins?strong=true", { method: "POST", headers: { @@ -24,10 +20,6 @@ export function usePlexAuth() { if (!response.ok) throw new Error("Failed to generate PIN"); const data = await response.json(); - console.log("[PlexAuth] PIN generated successfully:", { - id: data.id, - code: data.code - }); return { id: data.id, code: data.code }; } catch (error) { console.error("[PlexAuth] Error generating PIN:", error); @@ -48,17 +40,8 @@ export function usePlexAuth() { } ); - if (!response.ok) { - console.log("[PlexAuth] PIN check response not OK:", response.status); - return null; - } + if (!response.ok) return null; const data = await response.json(); - if (data.authToken) { - console.log( - "[PlexAuth] ✅ Auth token received:", - data.authToken.substring(0, 10) + "..." - ); - } return data.authToken; } catch (error) { console.error("[PlexAuth] Error checking PIN:", error); @@ -82,13 +65,9 @@ export function usePlexAuth() { pinCode: string, onSuccess: (token: string) => void ) { - console.log("[PlexAuth] Starting polling for PIN:", pinId); pollInterval.value = window.setInterval(async () => { const authToken = await checkPin(pinId, pinCode); if (authToken) { - console.log( - "[PlexAuth] 🎉 Authentication successful! Calling onSuccess callback" - ); stopPolling(); if (plexPopup.value && !plexPopup.value.closed) { plexPopup.value.close(); @@ -108,20 +87,9 @@ export function usePlexAuth() { // Set cookie function setPlexAuthCookie(authToken: string) { - console.log( - "[PlexAuth] Setting cookie for token:", - authToken.substring(0, 10) + "..." - ); const expires = new Date(); expires.setDate(expires.getDate() + 30); - const cookieString = `plex_auth_token=${authToken}; path=/; expires=${expires.toUTCString()}; SameSite=Strict`; - document.cookie = cookieString; - console.log("[PlexAuth] Cookie set. Verifying..."); - const verification = getCookie("plex_auth_token"); - console.log( - "[PlexAuth] Cookie verification:", - verification ? "✅ SUCCESS" : "❌ FAILED" - ); + document.cookie = `plex_auth_token=${authToken}; path=/; expires=${expires.toUTCString()}; SameSite=Strict`; } // Get cookie @@ -139,7 +107,6 @@ export function usePlexAuth() { onSuccess: (token: string) => void, onError: (msg: string) => void ) { - console.log("[PlexAuth] openAuthPopup called"); loading.value = true; const width = 600; @@ -154,12 +121,10 @@ export function usePlexAuth() { ); if (!plexPopup.value) { - console.error("[PlexAuth] Popup blocked!"); onError("Please allow popups for this site to authenticate with Plex"); loading.value = false; return; } - console.log("[PlexAuth] Popup opened successfully"); // Add loading screen if (plexPopup.value.document) { diff --git a/src/composables/usePlexLibraries.ts b/src/composables/usePlexLibraries.ts index 99c229f..792bddd 100644 --- a/src/composables/usePlexLibraries.ts +++ b/src/composables/usePlexLibraries.ts @@ -1,5 +1,3 @@ -import { ref } from "vue"; -import { usePlexApi } from "./usePlexApi"; import { processLibraryItem, calculateGenreStats, @@ -7,88 +5,133 @@ import { } from "@/utils/plexHelpers"; export function usePlexLibraries() { - const { plexServerUrl, fetchLibrarySections, fetchLibraryDetails } = - usePlexApi(); - - const loading = ref(false); - const libraryStats = ref({ - movies: 0, - shows: 0, - music: 0, - watchtime: 0 - }); - - const libraryDetails = ref({ - movies: { - total: 0, - recentlyAdded: [], - genres: [], - totalDuration: "0 hours" - }, - shows: { - total: 0, - recentlyAdded: [], - genres: [], - totalEpisodes: 0, - totalDuration: "0 hours" - }, - music: { total: 0, recentlyAdded: [], genres: [], totalTracks: 0 } - }); - - async function loadLibraries(authToken: string) { - loading.value = true; - + async function loadLibraries( + sections: any[], + authToken: string, + serverUrl: string, + username: string, + fetchLibraryDetailsFn: any + ) { // Reset stats - libraryStats.value = { movies: 0, shows: 0, music: 0, watchtime: 0 }; + const stats = { movies: 0, shows: 0, music: 0, watchtime: 0 }; + const details: any = { + movies: { + total: 0, + recentlyAdded: [], + genres: [], + totalDuration: "0 hours" + }, + shows: { + total: 0, + recentlyAdded: [], + genres: [], + totalEpisodes: 0, + totalDuration: "0 hours" + }, + music: { total: 0, recentlyAdded: [], genres: [], totalTracks: 0 } + }; try { - const sections = await fetchLibrarySections(authToken); - for (const section of sections) { const type = section.type; const key = section.key; if (type === "movie") { - await processLibrarySection(authToken, key, "movies"); + await processLibrarySection( + authToken, + serverUrl, + key, + "movies", + stats, + details, + fetchLibraryDetailsFn + ); } else if (type === "show") { - await processLibrarySection(authToken, key, "shows"); + await processLibrarySection( + authToken, + serverUrl, + key, + "shows", + stats, + details, + fetchLibraryDetailsFn + ); } else if (type === "artist") { - await processLibrarySection(authToken, key, "music"); + await processLibrarySection( + authToken, + serverUrl, + key, + "music", + stats, + details, + fetchLibraryDetailsFn + ); } } + + // Calculate watchtime from Tautulli if username provided + if (username) { + try { + const TAUTULLI_API_KEY = "28494032b47542278fe76c6ccd1f0619"; + const TAUTULLI_BASE_URL = "http://plex.schleppe:8181/api/v2"; + const url = `${TAUTULLI_BASE_URL}?apikey=${TAUTULLI_API_KEY}&cmd=get_history&user=${encodeURIComponent( + username + )}&length=8000`; + const response = await fetch(url); + if (response.ok) { + const data = await response.json(); + const history = data.response?.data?.data || []; + const totalMs = history.reduce( + (sum: number, item: any) => sum + (item.duration || 0) * 1000, + 0 + ); + stats.watchtime = Math.round(totalMs / (1000 * 60 * 60)); + } + } catch (error) { + console.error("[PlexLibraries] Error fetching watchtime:", error); + } + } + + return { stats, details }; } catch (error) { console.error("[PlexLibraries] Error loading libraries:", error); throw error; - } finally { - loading.value = false; } } async function processLibrarySection( authToken: string, + serverUrl: string, sectionKey: string, - libraryType: string + libraryType: string, + stats: any, + details: any, + fetchLibraryDetailsFn: any ) { try { - const data = await fetchLibraryDetails(authToken, sectionKey); + const data = await fetchLibraryDetailsFn( + authToken, + serverUrl, + sectionKey + ); if (!data) return; const totalCount = data.all.MediaContainer?.size || 0; // Update stats if (libraryType === "movies") { - libraryStats.value.movies += totalCount; + stats.movies += totalCount; } else if (libraryType === "shows") { - libraryStats.value.shows += totalCount; + stats.shows += totalCount; } else if (libraryType === "music") { - libraryStats.value.music += totalCount; + stats.music += totalCount; } // Process recently added items const recentItems = data.recentMetadata .slice(0, 5) .map((item: any) => - processLibraryItem(item, libraryType, authToken, plexServerUrl.value) + processLibraryItem(item, libraryType, authToken, serverUrl) ); // Calculate stats @@ -96,7 +139,7 @@ export function usePlexLibraries() { const durations = calculateDuration(data.metadata, libraryType); // Update library details - libraryDetails.value[libraryType] = { + details[libraryType] = { total: totalCount, recentlyAdded: recentItems, genres, @@ -112,9 +155,6 @@ export function usePlexLibraries() { } return { - loading, - libraryStats, - libraryDetails, loadLibraries }; }