mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Load KefinTweaks scripts which don't require login/admin before users login
This commit is contained in:
@@ -348,6 +348,11 @@
|
||||
*/
|
||||
async function verifyRecentlyAddedInLibraryConfig(config) {
|
||||
try {
|
||||
if (!window.ApiClient || !window.ApiClient._loggedIn) {
|
||||
WARN('User not logged in, skipping recently-added verification');
|
||||
return config;
|
||||
}
|
||||
|
||||
if (!window.dataHelper || !window.dataHelper.getLibraries) {
|
||||
WARN('dataHelper.getLibraries not available, skipping recently-added verification');
|
||||
return config;
|
||||
@@ -2179,7 +2184,7 @@
|
||||
<div style="display: grid; gap: 0.75em;">
|
||||
<!-- Parent Item Dropdown -->
|
||||
${buildSelect(`query-${queryIndex}-parentItemType`, [
|
||||
{ value: '', label: 'Select a Parent...' },
|
||||
{ value: '', label: 'Select a Parent... (optional)' },
|
||||
{ value: 'Collection', label: 'Collection' },
|
||||
{ value: 'Playlist', label: 'Playlist' },
|
||||
{ value: 'Generic Parent', label: 'Generic Parent' }
|
||||
|
||||
+67
-32
@@ -19,37 +19,42 @@
|
||||
return "Pending Install"; // Fallback
|
||||
}
|
||||
|
||||
// Match version patterns: @commitHash, @latest, @main, or @v0.3.3
|
||||
// Note: check for hash first to avoid partial numeric matches (e.g. hash starting with digits)
|
||||
const versionMatch = root.match(/@([a-f0-9]{7,}|latest|main|v?[\d.]+)/i);
|
||||
|
||||
if (versionMatch) {
|
||||
const version = versionMatch[1];
|
||||
// Match version patterns: @commitHash, @latest, @main, @experimental, or @v0.3.3
|
||||
// Note: check for hash first to avoid partial numeric matches (e.g. hash starting with digits)
|
||||
const versionMatch = root.match(/@([a-f0-9]{7,}|latest|main|experimental|v?[\d.]+)/i);
|
||||
|
||||
// Handle version tags (v0.3.3 -> 0.3.3)
|
||||
if (version.startsWith('v') && /^\d+\.\d+\.\d+/.test(version.substring(1))) {
|
||||
return version.substring(1); // Remove 'v' prefix
|
||||
if (versionMatch) {
|
||||
const version = versionMatch[1];
|
||||
|
||||
// Handle version tags (v0.3.3 -> 0.3.3)
|
||||
if (version.startsWith('v') && /^\d+\.\d+\.\d+/.test(version.substring(1))) {
|
||||
return version.substring(1); // Remove 'v' prefix
|
||||
}
|
||||
|
||||
// Handle @main -> "development"
|
||||
if (version.toLowerCase() === 'main') {
|
||||
return 'development';
|
||||
}
|
||||
|
||||
// Handle @experimental -> "experimental"
|
||||
if (version.toLowerCase() === 'experimental') {
|
||||
return 'experimental';
|
||||
}
|
||||
|
||||
// Handle @latest -> "latest"
|
||||
if (version.toLowerCase() === 'latest') {
|
||||
return 'latest';
|
||||
}
|
||||
|
||||
// Handle commit hash -> show as "Dev (#hash)"
|
||||
if (/^[a-f0-9]{7,}$/i.test(version)) {
|
||||
return `Dev (#${version.substring(0, 7)})`;
|
||||
}
|
||||
|
||||
// Return as-is for other patterns
|
||||
return version;
|
||||
}
|
||||
|
||||
// Handle @main -> "Dev"
|
||||
if (version.toLowerCase() === 'main') {
|
||||
return 'development';
|
||||
}
|
||||
|
||||
// Handle @latest -> "latest"
|
||||
if (version.toLowerCase() === 'latest') {
|
||||
return 'latest';
|
||||
}
|
||||
|
||||
// Handle commit hash -> show as "Dev (#hash)"
|
||||
if (/^[a-f0-9]{7,}$/i.test(version)) {
|
||||
return `Dev (#${version.substring(0, 7)})`;
|
||||
}
|
||||
|
||||
// Return as-is for other patterns
|
||||
return version;
|
||||
}
|
||||
|
||||
// No version found in URL, this is a custom install
|
||||
return "Custom Install";
|
||||
}
|
||||
@@ -75,6 +80,8 @@
|
||||
seriesInfo: true, // Add series and season information to details pages
|
||||
collections: true, // Collection sorting functionality
|
||||
skinManager: true, // Skin selection and management
|
||||
thumbnailScrubber: false, // Trickplay thumbnail scrub on hover (bottom 20px of video cards)
|
||||
|
||||
// Note: Core functionality scripts (utils, cardBuilder, localStorageCache, modal)
|
||||
// are automatically enabled when needed by other scripts
|
||||
|
||||
@@ -285,7 +292,7 @@
|
||||
name: 'homeScreen',
|
||||
script: 'homeScreen3.js',
|
||||
css: 'homeScreen.css',
|
||||
dependencies: ['cardBuilder', 'localStorageCache', 'utils', 'homeScreenConfig2', 'homeScreen-configuration', 'peopleCache', 'studiosCache', 'moviesCache', 'indexedDBCache', 'homeScreenConfigCommunity', 'dataHelper', 'apiHelper', 'websocketHelper', 'homeScreen-migration', 'homeScreen-user-configuration'],
|
||||
dependencies: ['cardBuilder', 'localStorageCache', 'utils', 'homeScreenConfig2', 'homeScreen-configuration', 'peopleCache', 'studiosCache', 'moviesCache', 'indexedDBCache', 'homeScreenConfigCommunity', 'dataHelper', 'apiHelper', 'homeScreen-migration', 'homeScreen-user-configuration'],
|
||||
priority: true, // Load immediately after dependencies to reduce UI disruption
|
||||
description: 'Adds custom home screen sections'
|
||||
},
|
||||
@@ -331,6 +338,13 @@
|
||||
dependencies: [],
|
||||
description: 'Fixes the dashboard button to redirect to the home page when the back button is clicked and there is no history to go back to'
|
||||
},
|
||||
{
|
||||
name: 'thumbnailScrubber',
|
||||
script: 'thumbnailScrubber.js',
|
||||
css: null,
|
||||
dependencies: [],
|
||||
description: 'Shows trickplay thumbnail preview when hovering in the bottom 20px of a video card for 2+ seconds'
|
||||
},
|
||||
{
|
||||
name: 'infiniteScroll',
|
||||
script: 'infiniteScroll.js',
|
||||
@@ -509,11 +523,12 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
// Resolve @latest or @main to actual version/commit hash
|
||||
// Resolve @latest, @main, or @experimental to actual version/commit hash (so user always loads latest from that ref)
|
||||
async function resolveRootVersion(root) {
|
||||
// Check if root contains @latest or @main
|
||||
// Check if root contains @latest, @main, or @experimental
|
||||
const latestMatch = root.match(/@latest(\/|$)/);
|
||||
const mainMatch = root.match(/@main(\/|$)/);
|
||||
const experimentalMatch = root.match(/@experimental(\/|$)/);
|
||||
|
||||
if (latestMatch) {
|
||||
// Fetch the latest release version number
|
||||
@@ -556,6 +571,26 @@
|
||||
console.warn('[KefinTweaks Injector] Error fetching commit hash:', error);
|
||||
return root;
|
||||
}
|
||||
} else if (experimentalMatch) {
|
||||
// Fetch the latest commit hash from the experimental branch
|
||||
try {
|
||||
const response = await fetch('https://api.github.com/repos/ranaldsgift/KefinTweaks/commits/experimental');
|
||||
if (response.ok) {
|
||||
const commit = await response.json();
|
||||
if (commit && commit.sha) {
|
||||
return root.replace('@experimental', `@${commit.sha}`);
|
||||
} else {
|
||||
console.warn('[KefinTweaks Injector] Could not fetch experimental commit hash, using @experimental');
|
||||
return root;
|
||||
}
|
||||
} else {
|
||||
console.warn('[KefinTweaks Injector] Failed to fetch experimental commit hash, using @experimental');
|
||||
return root;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[KefinTweaks Injector] Error fetching experimental commit hash:', error);
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
// No resolution needed
|
||||
@@ -575,7 +610,7 @@
|
||||
// Ensure root ends with /
|
||||
let root = kefinTweaksRoot.endsWith('/') ? kefinTweaksRoot : kefinTweaksRoot + '/';
|
||||
|
||||
// Resolve @latest or @main if needed (with caching)
|
||||
// Resolve @latest, @main, or @experimental if needed (with caching)
|
||||
if (resolvedRootCache === null) {
|
||||
root = await resolveRootVersion(root);
|
||||
resolvedRootCache = root;
|
||||
|
||||
@@ -1329,6 +1329,9 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
|
||||
const maxRetries = 100; // 10 seconds (100 * 100ms)
|
||||
|
||||
try {
|
||||
// Check if there is a valid config with a root url already, and load the injector if so
|
||||
checkAndLoadInjector();
|
||||
|
||||
// Check if ApiClient is available and user is logged in
|
||||
if (!window.ApiClient || !window.ApiClient._loggedIn) {
|
||||
if (retryCount < maxRetries) {
|
||||
@@ -1342,9 +1345,6 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a valid config with a root url already, and load the injector if so
|
||||
checkAndLoadInjector();
|
||||
|
||||
// Check if user is admin
|
||||
const userIsAdmin = await isAdmin();
|
||||
if (!userIsAdmin) {
|
||||
|
||||
+33
-6
@@ -13,6 +13,28 @@
|
||||
throw new Error('ApiClient is not available');
|
||||
}
|
||||
}
|
||||
|
||||
function ensureLoggedIn() {
|
||||
if (typeof ApiClient === 'undefined' || !ApiClient) {
|
||||
throw new Error('ApiClient is not available');
|
||||
}
|
||||
if (!ApiClient._loggedIn) {
|
||||
throw new Error('User is not logged in');
|
||||
}
|
||||
}
|
||||
|
||||
// Run this on a separate thread to avoid blocking the main thread with requestIdleCallback
|
||||
async function waitForLogin() {
|
||||
return new Promise((resolve) => {
|
||||
requestIdleCallback(() => {
|
||||
if (window.ApiClient && window.ApiClient._loggedIn) {
|
||||
resolve(true);
|
||||
} else {
|
||||
setTimeout(() => waitForLogin(), 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* API Helper functions for Jellyfin operations
|
||||
@@ -20,6 +42,7 @@
|
||||
const userHelper = {
|
||||
getUserDisplayPreferences: async function() {
|
||||
ensureApiClient();
|
||||
ensureLoggedIn();
|
||||
|
||||
let cachedDisplayPreferences = null;
|
||||
|
||||
@@ -63,13 +86,16 @@
|
||||
return { promise: userDisplayPreferencesPromise, cached: cachedDisplayPreferences };
|
||||
},
|
||||
useEpisodeImages: async function() {
|
||||
const { promise, cached } = await this.getUserDisplayPreferences();
|
||||
const userDisplayPreferences = await promise;
|
||||
if (!userDisplayPreferences) {
|
||||
LOG('No user display preferences found');
|
||||
try {
|
||||
ensureApiClient();
|
||||
ensureLoggedIn();
|
||||
const { promise, cached } = await this.getUserDisplayPreferences();
|
||||
const userDisplayPreferences = await promise;
|
||||
return userDisplayPreferences.CustomPrefs?.useEpisodeImagesInNextUpAndResume === 'true';
|
||||
} catch (error) {
|
||||
WARN('Failed to load user display preferences for useEpisodeImages:', error);
|
||||
return false;
|
||||
}
|
||||
return userDisplayPreferences.CustomPrefs?.useEpisodeImagesInNextUpAndResume === 'true';
|
||||
},
|
||||
updateCustomPrefsByKey: async function(key, value) {
|
||||
const { promise, cached } = await this.getUserDisplayPreferences();
|
||||
@@ -96,7 +122,8 @@
|
||||
body: JSON.stringify(prefs)
|
||||
});
|
||||
return response.ok;
|
||||
}
|
||||
},
|
||||
waitForLogin: waitForLogin
|
||||
};
|
||||
|
||||
// TODO -- Update this whenever the user display preferences are updated
|
||||
|
||||
@@ -4616,11 +4616,13 @@ In the Custom Tabs plugin, add a new tab with the following HTML content:
|
||||
}
|
||||
|
||||
// Initialize monitoring to remove watched items from watchlist (playback + manual)
|
||||
function initializePlaybackMonitoring() {
|
||||
async function initializePlaybackMonitoring() {
|
||||
if (playbackMonitorInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
await window.userHelper.waitForLogin();
|
||||
|
||||
const maxRetries = 10;
|
||||
let retries = 0;
|
||||
// Use WebSocket to listen for UserDataChanged messages instead of intercepting fetch
|
||||
|
||||
Reference in New Issue
Block a user