Fix: Restore library stats functionality and remove debug logging

- 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
This commit is contained in:
2026-02-27 17:58:38 +01:00
parent 15b6c571d0
commit 5e73b73783
3 changed files with 93 additions and 98 deletions

View File

@@ -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",

View File

@@ -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) {

View File

@@ -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<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 }
});
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
};
}