mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Update skin configuration dependencies, and prevent admin skin[] from being clobbered
This commit is contained in:
@@ -6,12 +6,26 @@
|
||||
|
||||
const LOG = (...args) => console.log('[KefinTweaks SkinManager Config]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks SkinManager Config]', ...args);
|
||||
const WARN = (...args) => console.warn('[KefinTweaks SkinManager Config]', ...args);
|
||||
|
||||
const MODAL_ID = 'kefin-skinmanager-config';
|
||||
|
||||
// Store loaded config for use in listeners
|
||||
let currentLoadedConfig = null;
|
||||
|
||||
function hasDefaultSkinsCatalog() {
|
||||
const skins = window.KefinTweaksDefaultSkinsConfig?.skins;
|
||||
return Array.isArray(skins) && skins.length > 0;
|
||||
}
|
||||
|
||||
function notifySkinManagerConfig(message) {
|
||||
if (window.KefinTweaksToaster?.toast) {
|
||||
window.KefinTweaksToaster.toast(message);
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to build Jellyfin checkbox
|
||||
function buildJellyfinCheckbox(id, checked, label, dataAttributes = {}) {
|
||||
let className = 'emby-checkbox';
|
||||
@@ -298,6 +312,22 @@
|
||||
*/
|
||||
async function saveConfig(skinManagerConfig) {
|
||||
try {
|
||||
if (!hasDefaultSkinsCatalog()) {
|
||||
WARN('Refusing to save Skin Manager config: default skins catalog not loaded');
|
||||
notifySkinManagerConfig('Default skins are not loaded yet. Try again in a moment.');
|
||||
return false;
|
||||
}
|
||||
|
||||
const existingSkins = window.KefinTweaksConfig?.skins;
|
||||
const existingNonEmpty = Array.isArray(existingSkins) && existingSkins.length > 0;
|
||||
const nextSkins = skinManagerConfig?.skins;
|
||||
const nextEmpty = !Array.isArray(nextSkins) || nextSkins.length === 0;
|
||||
if (nextEmpty && existingNonEmpty) {
|
||||
WARN('Refusing to save Skin Manager config: would wipe non-empty skins array');
|
||||
notifySkinManagerConfig('Save blocked: collected skins list is empty but existing config has skins. Reload and try again.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!window.KefinTweaksConfig) {
|
||||
window.KefinTweaksConfig = {};
|
||||
}
|
||||
@@ -437,10 +467,17 @@
|
||||
|
||||
/**
|
||||
* Collect configuration from form
|
||||
* @returns {Object|null} Collected config, or null if unsafe to save
|
||||
*/
|
||||
function collectConfig() {
|
||||
if (!hasDefaultSkinsCatalog()) {
|
||||
WARN('Cannot collect Skin Manager config: default skins catalog not loaded');
|
||||
notifySkinManagerConfig('Default skins are not loaded yet. Try again in a moment.');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get default skin
|
||||
const defaultSkin = document.getElementById('defaultSkin')?.value || null;
|
||||
let defaultSkin = document.getElementById('defaultSkin')?.value || null;
|
||||
if (defaultSkin === '') {
|
||||
defaultSkin = null;
|
||||
}
|
||||
@@ -532,6 +569,14 @@
|
||||
// Add the current category's optional includes
|
||||
optionalIncludes.push(...currentCategoryOptionalIncludes);
|
||||
|
||||
const existingSkins = window.KefinTweaksConfig?.skins;
|
||||
const existingNonEmpty = Array.isArray(existingSkins) && existingSkins.length > 0;
|
||||
if (skins.length === 0 && existingNonEmpty) {
|
||||
WARN('Cannot collect Skin Manager config: would wipe non-empty skins array');
|
||||
notifySkinManagerConfig('Save blocked: collected skins list is empty but existing config has skins. Reload and try again.');
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
skins: skins,
|
||||
themes: themes,
|
||||
@@ -577,6 +622,11 @@
|
||||
*/
|
||||
async function openConfigModal() {
|
||||
try {
|
||||
if (!hasDefaultSkinsCatalog()) {
|
||||
notifySkinManagerConfig('Default skins are not loaded yet. Try again in a moment.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Load config
|
||||
const config = await loadConfig();
|
||||
|
||||
@@ -617,6 +667,7 @@
|
||||
if (saveBtn) {
|
||||
saveBtn.addEventListener('click', async () => {
|
||||
const skinManagerConfig = collectConfig();
|
||||
if (!skinManagerConfig) return;
|
||||
const success = await saveConfig(skinManagerConfig);
|
||||
if (success) {
|
||||
if (window.KefinTweaksToaster && window.KefinTweaksToaster.toast) {
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
name: 'skinManager-configuration',
|
||||
script: '../configuration/skinManager-configuration.js',
|
||||
css: null,
|
||||
dependencies: ['modal', 'toaster', 'utils'],
|
||||
dependencies: ['modal', 'toaster', 'utils', 'skinConfigLegacyDefaults', 'skinConfig'],
|
||||
description: 'Skin manager configuration for KefinTweaks'
|
||||
},
|
||||
{
|
||||
|
||||
+67
-61
@@ -408,6 +408,10 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy: strip exact default duplicates / old Jellypane URLs from admin skins and persist.
|
||||
// Disabled — can wipe enable/disable stubs. Keep helpers + body for possible restore.
|
||||
const RUN_LEGACY_SKIN_DEDUP_CLEANUP = false;
|
||||
|
||||
// Load and merge skin configurations
|
||||
async function loadSkinConfig() {
|
||||
// Load default skins from skinConfig.js (for merging)
|
||||
@@ -418,73 +422,75 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
|
||||
// Load admin-configured skins from window.KefinTweaksConfig (from JS Injector)
|
||||
let adminSkins = window.KefinTweaksConfig?.skins || [];
|
||||
|
||||
// Clean up admin skins: remove exact duplicates of legacy defaults and old Jellypane format
|
||||
const cleanedAdminSkins = [];
|
||||
const skinsToRemove = new Set();
|
||||
|
||||
adminSkins.forEach(adminSkin => {
|
||||
// Check for exact match with any legacy default skin (canonical comparison)
|
||||
const matchingLegacyDefault = legacyDefaults.find(legacySkin => {
|
||||
if (adminSkin.name !== legacySkin.name) {
|
||||
return false;
|
||||
|
||||
if (RUN_LEGACY_SKIN_DEDUP_CLEANUP) {
|
||||
// Clean up admin skins: remove exact duplicates of legacy defaults and old Jellypane format
|
||||
const cleanedAdminSkins = [];
|
||||
const skinsToRemove = new Set();
|
||||
|
||||
adminSkins.forEach(adminSkin => {
|
||||
// Check for exact match with any legacy default skin (canonical comparison)
|
||||
const matchingLegacyDefault = legacyDefaults.find(legacySkin => {
|
||||
if (adminSkin.name !== legacySkin.name) {
|
||||
return false;
|
||||
}
|
||||
const matches = skinsMatchExactly(adminSkin, legacySkin);
|
||||
if (!matches) {
|
||||
// Debug: Log why skins with same name don't match
|
||||
LOG(`[Skin Match Debug] Skin '${adminSkin.name}' found in both configs but URLs/colorSchemes differ. Admin: ${JSON.stringify({url: adminSkin.url, colorSchemes: adminSkin.colorSchemes})}, Legacy Default: ${JSON.stringify({url: legacySkin.url, colorSchemes: legacySkin.colorSchemes})}`);
|
||||
}
|
||||
return matches;
|
||||
});
|
||||
|
||||
if (matchingLegacyDefault) {
|
||||
// Exact match found - remove from admin config
|
||||
LOG(`Removing exact duplicate of legacy default skin '${adminSkin.name}' from admin config`);
|
||||
skinsToRemove.add(adminSkin.name);
|
||||
return; // Skip adding to cleanedAdminSkins
|
||||
}
|
||||
const matches = skinsMatchExactly(adminSkin, legacySkin);
|
||||
if (!matches) {
|
||||
// Debug: Log why skins with same name don't match
|
||||
LOG(`[Skin Match Debug] Skin '${adminSkin.name}' found in both configs but URLs/colorSchemes differ. Admin: ${JSON.stringify({url: adminSkin.url, colorSchemes: adminSkin.colorSchemes})}, Legacy Default: ${JSON.stringify({url: legacySkin.url, colorSchemes: legacySkin.colorSchemes})}`);
|
||||
|
||||
// Special case: Jellypane with old URL format
|
||||
if (isJellypaneWithOldUrlFormat(adminSkin)) {
|
||||
LOG(`Removing Jellypane with old URL format from admin config`);
|
||||
skinsToRemove.add(adminSkin.name);
|
||||
return; // Skip adding to cleanedAdminSkins
|
||||
}
|
||||
return matches;
|
||||
|
||||
// Keep this admin skin
|
||||
cleanedAdminSkins.push(adminSkin);
|
||||
});
|
||||
|
||||
if (matchingLegacyDefault) {
|
||||
// Exact match found - remove from admin config
|
||||
LOG(`Removing exact duplicate of legacy default skin '${adminSkin.name}' from admin config`);
|
||||
skinsToRemove.add(adminSkin.name);
|
||||
return; // Skip adding to cleanedAdminSkins
|
||||
}
|
||||
|
||||
// Special case: Jellypane with old URL format
|
||||
if (isJellypaneWithOldUrlFormat(adminSkin)) {
|
||||
LOG(`Removing Jellypane with old URL format from admin config`);
|
||||
skinsToRemove.add(adminSkin.name);
|
||||
return; // Skip adding to cleanedAdminSkins
|
||||
}
|
||||
|
||||
// Keep this admin skin
|
||||
cleanedAdminSkins.push(adminSkin);
|
||||
});
|
||||
|
||||
// If we removed any skins, create backup and save cleaned config
|
||||
if (skinsToRemove.size > 0 && window.KefinTweaksConfig) {
|
||||
// Create a deep copy of the original config for backup
|
||||
const originalConfig = JSON.parse(JSON.stringify(window.KefinTweaksConfig));
|
||||
|
||||
// Create backup before modifying
|
||||
const backupCreated = await createConfigBackup(originalConfig);
|
||||
if (!backupCreated) {
|
||||
WARN('Failed to create backup, but continuing with cleanup');
|
||||
}
|
||||
|
||||
// Update KefinTweaksConfig with cleaned skins
|
||||
window.KefinTweaksConfig.skins = cleanedAdminSkins;
|
||||
|
||||
// Save the cleaned config back to JS Injector
|
||||
if (window.KefinTweaksUtils && window.KefinTweaksUtils.saveConfigToJavaScriptInjector) {
|
||||
const saveSuccess = await window.KefinTweaksUtils.saveConfigToJavaScriptInjector(window.KefinTweaksConfig, { waitForLogin: false });
|
||||
if (saveSuccess) {
|
||||
LOG(`Successfully saved cleaned config (removed ${skinsToRemove.size} duplicate/old-format skin(s): ${Array.from(skinsToRemove).join(', ')})`);
|
||||
} else {
|
||||
WARN('Failed to save cleaned config to JS Injector');
|
||||
|
||||
// If we removed any skins, create backup and save cleaned config
|
||||
if (skinsToRemove.size > 0 && window.KefinTweaksConfig) {
|
||||
// Create a deep copy of the original config for backup
|
||||
const originalConfig = JSON.parse(JSON.stringify(window.KefinTweaksConfig));
|
||||
|
||||
// Create backup before modifying
|
||||
const backupCreated = await createConfigBackup(originalConfig);
|
||||
if (!backupCreated) {
|
||||
WARN('Failed to create backup, but continuing with cleanup');
|
||||
}
|
||||
} else {
|
||||
WARN('KefinTweaksUtils.saveConfigToJavaScriptInjector not available, cannot save cleaned config');
|
||||
|
||||
// Update KefinTweaksConfig with cleaned skins
|
||||
window.KefinTweaksConfig.skins = cleanedAdminSkins;
|
||||
|
||||
// Save the cleaned config back to JS Injector
|
||||
if (window.KefinTweaksUtils && window.KefinTweaksUtils.saveConfigToJavaScriptInjector) {
|
||||
const saveSuccess = await window.KefinTweaksUtils.saveConfigToJavaScriptInjector(window.KefinTweaksConfig, { waitForLogin: false });
|
||||
if (saveSuccess) {
|
||||
LOG(`Successfully saved cleaned config (removed ${skinsToRemove.size} duplicate/old-format skin(s): ${Array.from(skinsToRemove).join(', ')})`);
|
||||
} else {
|
||||
WARN('Failed to save cleaned config to JS Injector');
|
||||
}
|
||||
} else {
|
||||
WARN('KefinTweaksUtils.saveConfigToJavaScriptInjector not available, cannot save cleaned config');
|
||||
}
|
||||
|
||||
LOG(`Cleaned up ${skinsToRemove.size} duplicate/old-format skin(s) from admin config: ${Array.from(skinsToRemove).join(', ')}`);
|
||||
}
|
||||
|
||||
LOG(`Cleaned up ${skinsToRemove.size} duplicate/old-format skin(s) from admin config: ${Array.from(skinsToRemove).join(', ')}`);
|
||||
|
||||
adminSkins = cleanedAdminSkins;
|
||||
}
|
||||
|
||||
adminSkins = cleanedAdminSkins;
|
||||
|
||||
// Merge: Start with defaults, then override/add from admin config
|
||||
// Admin config takes precedence for duplicate names
|
||||
|
||||
Reference in New Issue
Block a user