Update resolution of kefinTweaksUrl for KefinTweaks-Injector JS Injector script

This commit is contained in:
HighImKevin committed 2026-09-15 05:56:24 -04:00
1 parent d6ad82cba9
commit 1b77c6f0f7
4 files changed
+123 -40

No files matched your search

+3 -1
View File
@@ -1190,7 +1190,9 @@
console.log('[KefinTweaks Injector] Jellyfin major version:', majorVersion ?? 'unknown');
const config = window.KefinTweaksConfig || {};
const root = Loader.normalizeRoot(config.kefinTweaksRoot || '');
const root = Loader.getResolvedKefinRoot
? Loader.getResolvedKefinRoot(config)
: Loader.normalizeRoot(config.kefinTweaksRoot || '');
try {
const plan = Loader.buildLoadPlan(config, majorVersion, {
+28 -5
View File
@@ -205,7 +205,8 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
let injectorScriptContent = null;
try {
const rootRaw = config.kefinTweaksRoot || '';
const root = rootRaw.endsWith('/') ? rootRaw : rootRaw + '/';
const resolvedRaw = config.kefinTweaksRootResolved || rootRaw;
const root = resolvedRaw.endsWith('/') ? resolvedRaw : resolvedRaw + '/';
if (root && root !== '/') {
await loadKefinTweaksLoaderFromRoot(root);
const Loader = window.KefinTweaksLoader;
@@ -217,8 +218,11 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
} catch (e) {
console.warn('[KefinTweaks Installer] Could not resolve Jellyfin major for injector bake:', e);
}
const planRoot = Loader.getResolvedKefinRoot
? Loader.getResolvedKefinRoot(config)
: root;
const plan = Loader.buildLoadPlan(config, major, {
root,
root: planRoot,
configOnly: config.enabled === false
});
injectorScriptContent = Loader.buildInjectorScript(plan);
@@ -334,8 +338,20 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
}
try {
const root = rootRaw.endsWith('/') ? rootRaw : rootRaw + '/';
await loadKefinTweaksLoaderFromRoot(root);
const normalize = (r) => {
if (!r || typeof r !== 'string') return '';
return r.endsWith('/') ? r : r + '/';
};
const expected = normalize(await resolveRootVersion(rootRaw));
const current = normalize(config.kefinTweaksRootResolved || '');
if (!current || current !== expected) {
config.kefinTweaksRootResolved = expected;
console.log('[KefinTweaks Installer] Updated kefinTweaksRootResolved:', current || '(none)', '->', expected);
}
const loadRoot = normalize(config.kefinTweaksRootResolved || rootRaw);
await loadKefinTweaksLoaderFromRoot(loadRoot);
const Loader = window.KefinTweaksLoader;
if (!Loader) {
return { ok: false, reason: 'KefinTweaksLoader unavailable' };
@@ -349,8 +365,9 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
console.warn('[KefinTweaks Installer] Could not resolve Jellyfin major for auto-create:', e);
}
const resolvedRoot = Loader.getResolvedKefinRoot(config);
const plan = Loader.buildLoadPlan(config, major, {
root,
root: resolvedRoot,
configOnly: config.enabled === false
});
const injectorScriptContent = Loader.buildInjectorScript(plan);
@@ -898,6 +915,10 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
}
const kefinTweaksRoot = buildKefinTweaksRootUrl(sourceType, source);
const kefinTweaksRootResolvedRaw = await resolveRootVersion(kefinTweaksRoot);
const kefinTweaksRootResolved = kefinTweaksRootResolvedRaw.endsWith('/')
? kefinTweaksRootResolvedRaw
: kefinTweaksRootResolvedRaw + '/';
// Load default config from the selected root
let defaultConfig;
@@ -908,6 +929,7 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
// Create minimal config if loading fails
defaultConfig = {
kefinTweaksRoot: kefinTweaksRoot,
kefinTweaksRootResolved: kefinTweaksRootResolved,
enabled: true,
scripts: {},
exclusiveElsewhere: {},
@@ -929,6 +951,7 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
kefinTweaksRoot: kefinTweaksRoot,
...(currentConfig || {}),
kefinTweaksRoot: kefinTweaksRoot, // Ensure root is updated
kefinTweaksRootResolved: kefinTweaksRootResolved,
enabled: enabledState // Update enabled state
};
+84 -30
View File
@@ -641,6 +641,14 @@
return root.endsWith('/') ? root : root + '/';
}
/**
* Prefer kefinTweaksRootResolved (commit SHA / verified URL); fall back to symbolic kefinTweaksRoot.
*/
function getResolvedKefinRoot(config) {
const cfg = config || {};
return normalizeRoot(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || '');
}
function resolveAssetUrl(root, relativePath) {
if (!relativePath) return null;
if (/^https?:\/\//i.test(relativePath)) return relativePath;
@@ -677,26 +685,29 @@
function expandScriptToAssets(scriptDef, root, urlSuffix, thirdParty) {
const assets = [];
const suffix = urlSuffix || '';
const pushRel = (kind, relativePath, name) => {
if (!relativePath) return;
if (/^https?:\/\//i.test(relativePath)) {
assets.push({ kind: kind, url: relativePath, name: name });
return;
}
const url = resolveAssetUrl(root, relativePath);
if (!url) return;
assets.push({
kind: kind,
url: url + suffix,
path: relativePath,
name: name
});
};
for (const tpName of scriptDef.thirdParty || []) {
const tp = thirdParty[tpName];
if (!tp) continue;
(tp.css || []).forEach((css) => {
const url = resolveAssetUrl(root, css);
if (url) assets.push({ kind: 'css', url: url + (/^https?:/i.test(css) ? '' : suffix), name: tpName });
});
(tp.js || []).forEach((js) => {
const url = resolveAssetUrl(root, js);
if (url) assets.push({ kind: 'js', url: url + (/^https?:/i.test(js) ? '' : suffix), name: tpName });
});
}
if (scriptDef.css) {
const url = resolveAssetUrl(root, scriptDef.css);
if (url) assets.push({ kind: 'css', url: url + suffix, name: scriptDef.name });
}
if (scriptDef.script) {
const url = resolveAssetUrl(root, scriptDef.script);
if (url) assets.push({ kind: 'js', url: url + suffix, name: scriptDef.name });
(tp.css || []).forEach((css) => pushRel('css', css, tpName));
(tp.js || []).forEach((js) => pushRel('js', js, tpName));
}
if (scriptDef.css) pushRel('css', scriptDef.css, scriptDef.name);
if (scriptDef.script) pushRel('js', scriptDef.script, scriptDef.name);
return assets;
}
@@ -742,7 +753,11 @@
function buildLoadPlan(config, majorVersion, options) {
options = options || {};
const root = normalizeRoot(options.root || (config && config.kefinTweaksRoot) || '');
const root = normalizeRoot(
options.root
|| getResolvedKefinRoot(config)
|| ''
);
if (!root) throw new Error('kefinTweaksRoot is required to build load plan');
const urlSuffix = options.urlSuffix || '';
const byName = definitionsByName();
@@ -764,7 +779,7 @@
const seen = new Set();
const pushAssets = (list) => {
list.forEach((a) => {
const key = a.kind + '|' + a.url;
const key = a.kind + '|' + (a.url || a.path || '');
if (seen.has(key)) return;
seen.add(key);
assets.push(a);
@@ -778,8 +793,18 @@
});
pushAssets([
{ kind: 'css', url: resolveAssetUrl(root, CONFIGURATION_FILES.css) + urlSuffix, name: 'configuration' },
{ kind: 'js', url: resolveAssetUrl(root, CONFIGURATION_FILES.script) + urlSuffix, name: 'configuration' }
{
kind: 'css',
url: resolveAssetUrl(root, CONFIGURATION_FILES.css) + urlSuffix,
path: CONFIGURATION_FILES.css,
name: 'configuration'
},
{
kind: 'js',
url: resolveAssetUrl(root, CONFIGURATION_FILES.script) + urlSuffix,
path: CONFIGURATION_FILES.script,
name: 'configuration'
}
]);
const stamp = [
@@ -907,7 +932,22 @@
}
function buildInjectorScript(loadPlan) {
const assetsJson = JSON.stringify(loadPlan.assets || []);
// Bake relative paths (and absolute http urls); join with resolved root at runtime
const bakeAssets = (loadPlan.assets || []).map((a) => {
if (!a) return null;
if (a.url && /^https?:\/\//i.test(a.url) && !a.path) {
return { kind: a.kind, url: a.url, name: a.name };
}
if (a.path) {
return { kind: a.kind, path: a.path, name: a.name };
}
if (a.url) {
return { kind: a.kind, url: a.url, name: a.name };
}
return null;
}).filter(Boolean);
const assetsJson = JSON.stringify(bakeAssets);
const defsJson = JSON.stringify(loadPlan.definitions || SCRIPT_DEFINITIONS);
const stamp = loadPlan.stamp || '';
const stampJson = JSON.stringify(stamp);
@@ -916,11 +956,22 @@
'// kefinTweaksInjectorStamp=' + stamp,
'(function () {',
' if (window.KefinTweaksScriptsPreloaded) return;',
' var root = (window.KefinTweaksConfig && window.KefinTweaksConfig.kefinTweaksRoot) || \'\';',
' var isExperimental = /@experimental(\\/|$)/i.test(String(root));',
' var isOfficialCdn = /cdn\\.jsdelivr\\.net\\/gh\\/ranaldsgift\\/KefinTweaks@/i.test(String(root));',
' if (!String(root).trim()) return;',
' var cfg = window.KefinTweaksConfig || {};',
' if (cfg.enabled !== true) return;',
' var symbolicRoot = cfg.kefinTweaksRoot || \'\';',
' var isExperimental = /@experimental(\\/|$)/i.test(String(symbolicRoot));',
' var isOfficialCdn = /cdn\\.jsdelivr\\.net\\/gh\\/ranaldsgift\\/KefinTweaks@/i.test(String(symbolicRoot));',
' if (!String(symbolicRoot).trim()) return;',
' if (!isExperimental && isOfficialCdn) return;',
' var resolvedRoot = String(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || \'\').trim();',
' if (!resolvedRoot) return;',
' if (resolvedRoot.charAt(resolvedRoot.length - 1) !== \'/\') resolvedRoot += \'/\';',
' function joinAssetUrl(relativePath) {',
' if (!relativePath) return null;',
' if (/^https?:\\/\\//i.test(relativePath)) return relativePath;',
' var base = resolvedRoot + \'scripts/\';',
' try { return new URL(relativePath, base).href; } catch (e) { return base + relativePath; }',
' }',
' window.KefinTweaksScriptsPreloaded = true;',
' window.KefinTweaksInjectorStamp = ' + stampJson + ';',
' var SCRIPT_DEFINITIONS_BAKED = ' + defsJson + ';',
@@ -972,18 +1023,20 @@
' var assets = ' + assetsJson + ';',
' for (var i = 0; i < assets.length; i++) {',
' var a = assets[i];',
' if (!a || !a.url) continue;',
' if (!a) continue;',
' var href = a.url || joinAssetUrl(a.path);',
' if (!href) continue;',
' if (a.kind === \'css\') {',
' if (document.querySelector(\'link[href="\' + a.url + \'"]\')) continue;',
' if (document.querySelector(\'link[href="\' + href + \'"]\')) continue;',
' var l = document.createElement(\'link\');',
' l.rel = \'stylesheet\';',
' l.type = \'text/css\';',
' l.href = a.url;',
' l.href = href;',
' document.head.appendChild(l);',
' } else {',
' if (document.querySelector(\'script[src="\' + a.url + \'"]\')) continue;',
' if (document.querySelector(\'script[src="\' + href + \'"]\')) continue;',
' var s = document.createElement(\'script\');',
' s.src = a.url;',
' s.src = href;',
' s.async = false;',
' document.head.appendChild(s);',
' }',
@@ -1183,6 +1236,7 @@
isScriptCompatible: isScriptCompatible,
mergeEnabledScripts: mergeEnabledScripts,
normalizeRoot: normalizeRoot,
getResolvedKefinRoot: getResolvedKefinRoot,
resolveAssetUrl: resolveAssetUrl,
buildLoadPlan: buildLoadPlan,
buildInjectorScript: buildInjectorScript,
+8 -4
View File
@@ -2213,9 +2213,10 @@ window.KefinTweaksConfig = ${JSON.stringify(configToSave, null, 2)};`;
// Build / refresh KefinTweaks-injector preload entry (same POST)
let injectorScriptContent = null;
try {
const root = (configToSave.kefinTweaksRoot || '').endsWith('/')
? configToSave.kefinTweaksRoot
: (configToSave.kefinTweaksRoot || '') + '/';
const resolvedOrSymbolic = configToSave.kefinTweaksRootResolved || configToSave.kefinTweaksRoot || '';
const root = resolvedOrSymbolic.endsWith('/')
? resolvedOrSymbolic
: resolvedOrSymbolic + '/';
if (root && root !== '/') {
if (!window.KefinTweaksLoader) {
await new Promise((resolve, reject) => {
@@ -2237,8 +2238,11 @@ window.KefinTweaksConfig = ${JSON.stringify(configToSave, null, 2)};`;
if (Loader) {
Loader.ensureKefinTweaksApi(Loader.SCRIPT_DEFINITIONS);
const major = await window.KefinTweaks.getJellyfinMajorVersion();
const planRoot = Loader.getResolvedKefinRoot
? Loader.getResolvedKefinRoot(configToSave)
: root;
const plan = Loader.buildLoadPlan(configToSave, major, {
root,
root: planRoot,
configOnly: configToSave.enabled === false
});
injectorScriptContent = Loader.buildInjectorScript(plan);