mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-03-11 03:49:07 +00:00
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:
@@ -211,23 +211,15 @@
|
|||||||
// ----- OAuth flow (handlers for PlexAuthButton events) -----
|
// ----- OAuth flow (handlers for PlexAuthButton events) -----
|
||||||
async function handleAuthSuccess(authToken: string) {
|
async function handleAuthSuccess(authToken: string) {
|
||||||
try {
|
try {
|
||||||
console.log(
|
|
||||||
"[PlexSettings] Auth success! Token received:",
|
|
||||||
authToken.substring(0, 10) + "..."
|
|
||||||
);
|
|
||||||
setPlexAuthCookie(authToken);
|
setPlexAuthCookie(authToken);
|
||||||
console.log("[PlexSettings] Fetching user data...");
|
|
||||||
const userData = await fetchPlexUserData(authToken);
|
const userData = await fetchPlexUserData(authToken);
|
||||||
if (userData) {
|
if (userData) {
|
||||||
console.log("[PlexSettings] User data received:", userData.username);
|
|
||||||
plexUserData.value = userData;
|
plexUserData.value = userData;
|
||||||
plexUsername.value = userData.username;
|
plexUsername.value = userData.username;
|
||||||
isPlexConnected.value = true;
|
isPlexConnected.value = true;
|
||||||
}
|
}
|
||||||
console.log("[PlexSettings] Linking Plex account to backend...");
|
|
||||||
const { success, message } = await linkPlexAccount(authToken);
|
const { success, message } = await linkPlexAccount(authToken);
|
||||||
if (success) {
|
if (success) {
|
||||||
console.log("[PlexSettings] ✅ Account linked successfully");
|
|
||||||
emit("reload");
|
emit("reload");
|
||||||
await fetchPlexLibraries(authToken);
|
await fetchPlexLibraries(authToken);
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
@@ -236,7 +228,6 @@
|
|||||||
message: message || "Successfully connected your Plex account"
|
message: message || "Successfully connected your Plex account"
|
||||||
} as IErrorMessage);
|
} as IErrorMessage);
|
||||||
} else {
|
} else {
|
||||||
console.error("[PlexSettings] ❌ Account linking failed:", message);
|
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
type: ErrorMessageTypes.Error,
|
type: ErrorMessageTypes.Error,
|
||||||
title: "Authentication failed",
|
title: "Authentication failed",
|
||||||
@@ -254,7 +245,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleAuthError(errorMessage: string) {
|
function handleAuthError(errorMessage: string) {
|
||||||
console.error("[PlexSettings] Auth error:", errorMessage);
|
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
type: ErrorMessageTypes.Error,
|
type: ErrorMessageTypes.Error,
|
||||||
title: "Authentication failed",
|
title: "Authentication failed",
|
||||||
|
|||||||
@@ -9,10 +9,6 @@ export function usePlexAuth() {
|
|||||||
// Generate a PIN for Plex OAuth
|
// Generate a PIN for Plex OAuth
|
||||||
async function generatePlexPin() {
|
async function generatePlexPin() {
|
||||||
try {
|
try {
|
||||||
console.log(
|
|
||||||
"[PlexAuth] Generating PIN with CLIENT_IDENTIFIER:",
|
|
||||||
CLIENT_IDENTIFIER
|
|
||||||
);
|
|
||||||
const response = await fetch("https://plex.tv/api/v2/pins?strong=true", {
|
const response = await fetch("https://plex.tv/api/v2/pins?strong=true", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -24,10 +20,6 @@ export function usePlexAuth() {
|
|||||||
|
|
||||||
if (!response.ok) throw new Error("Failed to generate PIN");
|
if (!response.ok) throw new Error("Failed to generate PIN");
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log("[PlexAuth] PIN generated successfully:", {
|
|
||||||
id: data.id,
|
|
||||||
code: data.code
|
|
||||||
});
|
|
||||||
return { id: data.id, code: data.code };
|
return { id: data.id, code: data.code };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[PlexAuth] Error generating PIN:", error);
|
console.error("[PlexAuth] Error generating PIN:", error);
|
||||||
@@ -48,17 +40,8 @@ export function usePlexAuth() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) return null;
|
||||||
console.log("[PlexAuth] PIN check response not OK:", response.status);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.authToken) {
|
|
||||||
console.log(
|
|
||||||
"[PlexAuth] ✅ Auth token received:",
|
|
||||||
data.authToken.substring(0, 10) + "..."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return data.authToken;
|
return data.authToken;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[PlexAuth] Error checking PIN:", error);
|
console.error("[PlexAuth] Error checking PIN:", error);
|
||||||
@@ -82,13 +65,9 @@ export function usePlexAuth() {
|
|||||||
pinCode: string,
|
pinCode: string,
|
||||||
onSuccess: (token: string) => void
|
onSuccess: (token: string) => void
|
||||||
) {
|
) {
|
||||||
console.log("[PlexAuth] Starting polling for PIN:", pinId);
|
|
||||||
pollInterval.value = window.setInterval(async () => {
|
pollInterval.value = window.setInterval(async () => {
|
||||||
const authToken = await checkPin(pinId, pinCode);
|
const authToken = await checkPin(pinId, pinCode);
|
||||||
if (authToken) {
|
if (authToken) {
|
||||||
console.log(
|
|
||||||
"[PlexAuth] 🎉 Authentication successful! Calling onSuccess callback"
|
|
||||||
);
|
|
||||||
stopPolling();
|
stopPolling();
|
||||||
if (plexPopup.value && !plexPopup.value.closed) {
|
if (plexPopup.value && !plexPopup.value.closed) {
|
||||||
plexPopup.value.close();
|
plexPopup.value.close();
|
||||||
@@ -108,20 +87,9 @@ export function usePlexAuth() {
|
|||||||
|
|
||||||
// Set cookie
|
// Set cookie
|
||||||
function setPlexAuthCookie(authToken: string) {
|
function setPlexAuthCookie(authToken: string) {
|
||||||
console.log(
|
|
||||||
"[PlexAuth] Setting cookie for token:",
|
|
||||||
authToken.substring(0, 10) + "..."
|
|
||||||
);
|
|
||||||
const expires = new Date();
|
const expires = new Date();
|
||||||
expires.setDate(expires.getDate() + 30);
|
expires.setDate(expires.getDate() + 30);
|
||||||
const cookieString = `plex_auth_token=${authToken}; path=/; expires=${expires.toUTCString()}; SameSite=Strict`;
|
document.cookie = `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"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cookie
|
// Get cookie
|
||||||
@@ -139,7 +107,6 @@ export function usePlexAuth() {
|
|||||||
onSuccess: (token: string) => void,
|
onSuccess: (token: string) => void,
|
||||||
onError: (msg: string) => void
|
onError: (msg: string) => void
|
||||||
) {
|
) {
|
||||||
console.log("[PlexAuth] openAuthPopup called");
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
const width = 600;
|
const width = 600;
|
||||||
@@ -154,12 +121,10 @@ export function usePlexAuth() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!plexPopup.value) {
|
if (!plexPopup.value) {
|
||||||
console.error("[PlexAuth] Popup blocked!");
|
|
||||||
onError("Please allow popups for this site to authenticate with Plex");
|
onError("Please allow popups for this site to authenticate with Plex");
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("[PlexAuth] Popup opened successfully");
|
|
||||||
|
|
||||||
// Add loading screen
|
// Add loading screen
|
||||||
if (plexPopup.value.document) {
|
if (plexPopup.value.document) {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { ref } from "vue";
|
|
||||||
import { usePlexApi } from "./usePlexApi";
|
|
||||||
import {
|
import {
|
||||||
processLibraryItem,
|
processLibraryItem,
|
||||||
calculateGenreStats,
|
calculateGenreStats,
|
||||||
@@ -7,88 +5,133 @@ import {
|
|||||||
} from "@/utils/plexHelpers";
|
} from "@/utils/plexHelpers";
|
||||||
|
|
||||||
export function usePlexLibraries() {
|
export function usePlexLibraries() {
|
||||||
const { plexServerUrl, fetchLibrarySections, fetchLibraryDetails } =
|
async function loadLibraries(
|
||||||
usePlexApi();
|
sections: any[],
|
||||||
|
authToken: string,
|
||||||
const loading = ref(false);
|
serverUrl: string,
|
||||||
const libraryStats = ref({
|
username: string,
|
||||||
movies: 0,
|
fetchLibraryDetailsFn: any
|
||||||
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;
|
|
||||||
|
|
||||||
// Reset stats
|
// 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 {
|
try {
|
||||||
const sections = await fetchLibrarySections(authToken);
|
|
||||||
|
|
||||||
for (const section of sections) {
|
for (const section of sections) {
|
||||||
const type = section.type;
|
const type = section.type;
|
||||||
const key = section.key;
|
const key = section.key;
|
||||||
|
|
||||||
if (type === "movie") {
|
if (type === "movie") {
|
||||||
await processLibrarySection(authToken, key, "movies");
|
await processLibrarySection(
|
||||||
|
authToken,
|
||||||
|
serverUrl,
|
||||||
|
key,
|
||||||
|
"movies",
|
||||||
|
stats,
|
||||||
|
details,
|
||||||
|
fetchLibraryDetailsFn
|
||||||
|
);
|
||||||
} else if (type === "show") {
|
} else if (type === "show") {
|
||||||
await processLibrarySection(authToken, key, "shows");
|
await processLibrarySection(
|
||||||
|
authToken,
|
||||||
|
serverUrl,
|
||||||
|
key,
|
||||||
|
"shows",
|
||||||
|
stats,
|
||||||
|
details,
|
||||||
|
fetchLibraryDetailsFn
|
||||||
|
);
|
||||||
} else if (type === "artist") {
|
} 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) {
|
} catch (error) {
|
||||||
console.error("[PlexLibraries] Error loading libraries:", error);
|
console.error("[PlexLibraries] Error loading libraries:", error);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processLibrarySection(
|
async function processLibrarySection(
|
||||||
authToken: string,
|
authToken: string,
|
||||||
|
serverUrl: string,
|
||||||
sectionKey: string,
|
sectionKey: string,
|
||||||
libraryType: string
|
libraryType: string,
|
||||||
|
stats: any,
|
||||||
|
details: any,
|
||||||
|
fetchLibraryDetailsFn: any
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const data = await fetchLibraryDetails(authToken, sectionKey);
|
const data = await fetchLibraryDetailsFn(
|
||||||
|
authToken,
|
||||||
|
serverUrl,
|
||||||
|
sectionKey
|
||||||
|
);
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
const totalCount = data.all.MediaContainer?.size || 0;
|
const totalCount = data.all.MediaContainer?.size || 0;
|
||||||
|
|
||||||
// Update stats
|
// Update stats
|
||||||
if (libraryType === "movies") {
|
if (libraryType === "movies") {
|
||||||
libraryStats.value.movies += totalCount;
|
stats.movies += totalCount;
|
||||||
} else if (libraryType === "shows") {
|
} else if (libraryType === "shows") {
|
||||||
libraryStats.value.shows += totalCount;
|
stats.shows += totalCount;
|
||||||
} else if (libraryType === "music") {
|
} else if (libraryType === "music") {
|
||||||
libraryStats.value.music += totalCount;
|
stats.music += totalCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process recently added items
|
// Process recently added items
|
||||||
const recentItems = data.recentMetadata
|
const recentItems = data.recentMetadata
|
||||||
.slice(0, 5)
|
.slice(0, 5)
|
||||||
.map((item: any) =>
|
.map((item: any) =>
|
||||||
processLibraryItem(item, libraryType, authToken, plexServerUrl.value)
|
processLibraryItem(item, libraryType, authToken, serverUrl)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculate stats
|
// Calculate stats
|
||||||
@@ -96,7 +139,7 @@ export function usePlexLibraries() {
|
|||||||
const durations = calculateDuration(data.metadata, libraryType);
|
const durations = calculateDuration(data.metadata, libraryType);
|
||||||
|
|
||||||
// Update library details
|
// Update library details
|
||||||
libraryDetails.value[libraryType] = {
|
details[libraryType] = {
|
||||||
total: totalCount,
|
total: totalCount,
|
||||||
recentlyAdded: recentItems,
|
recentlyAdded: recentItems,
|
||||||
genres,
|
genres,
|
||||||
@@ -112,9 +155,6 @@ export function usePlexLibraries() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loading,
|
|
||||||
libraryStats,
|
|
||||||
libraryDetails,
|
|
||||||
loadLibraries
|
loadLibraries
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user