Fix Continue Watching and Next Up not appearing correctly

This commit is contained in:
HighImKevin
2026-09-10 09:20:29 -04:00
parent b21497a194
commit 773393ef3e
6 changed files with 92 additions and 216 deletions
+31 -137
View File
@@ -155,6 +155,30 @@
return flattened;
}
const CONTINUE_WATCHING_SECTION_IDS = new Set([
'continueWatching',
'nextUp',
'continueWatchingAndNextUp'
]);
/**
* Clear MERGE_NEXT_UP-era hidden flags so CW / Next Up / combined are independent sections.
*/
function normalizeContinueWatchingVisibility(config) {
if (!config) return;
const groupKeys = ['HOME_SECTION_GROUPS', 'SEASONAL_SECTION_GROUPS', 'DISCOVERY_SECTION_GROUPS', 'CUSTOM_SECTION_GROUPS'];
groupKeys.forEach((key) => {
(config[key] || []).forEach((group) => {
(group.sections || []).forEach((section) => {
if (section?.id && CONTINUE_WATCHING_SECTION_IDS.has(section.id)) {
section.hidden = false;
}
});
});
});
delete config.MERGE_NEXT_UP;
}
/**
* Collect discovery-enabled sections from custom groups, stamping pageNumber
* per group (1..N among discovery sections only, in group order).
@@ -927,10 +951,11 @@
CACHE: { ...defaults.CACHE, ...(existingConfig.CACHE || {}) },
SPOTLIGHT_SETTINGS: { ...defaults.SPOTLIGHT_SETTINGS, ...(existingConfig.SPOTLIGHT_SETTINGS || {}) },
HOME_SETTINGS: { ...defaults.HOME_SETTINGS, ...(existingConfig.HOME_SETTINGS || {}) },
USER_HOME_SCREEN_SETTINGS: { ...defaults.USER_HOME_SCREEN_SETTINGS, ...(existingConfig.USER_HOME_SCREEN_SETTINGS || {}) },
MERGE_NEXT_UP: existingConfig.MERGE_NEXT_UP ?? defaults.MERGE_NEXT_UP ?? false
USER_HOME_SCREEN_SETTINGS: { ...defaults.USER_HOME_SCREEN_SETTINGS, ...(existingConfig.USER_HOME_SCREEN_SETTINGS || {}) }
};
normalizeContinueWatchingVisibility(mergedConfig);
// Add ENABLED_NORMAL_SECTIONS and ENABLED_DISCOVERY_SECTIONS
// ENABLED_NORMAL_SECTIONS is all enabled sections from HOME_SECTION_GROUPS, SEASONAL_SECTION_GROUPS, and CUSTOM_SECTION_GROUPS that aren't discovery sections
// If they have a start/end date the current date must fall within that date range
@@ -1522,10 +1547,11 @@
USER_HOME_SCREEN_SETTINGS: {
...(savedHomeScreenConfig.USER_HOME_SCREEN_SETTINGS || {}),
...(config.USER_HOME_SCREEN_SETTINGS || {})
},
MERGE_NEXT_UP: config.MERGE_NEXT_UP !== undefined ? config.MERGE_NEXT_UP : (savedHomeScreenConfig.MERGE_NEXT_UP !== undefined ? savedHomeScreenConfig.MERGE_NEXT_UP : false)
}
};
normalizeContinueWatchingVisibility(mergedHomeScreenConfig);
// Empty values (= blank CustomPrefs segments) must not persist to JS Injector
omitEmptyPropsFromGroups(mergedHomeScreenConfig.HOME_SECTION_GROUPS);
omitEmptyPropsFromGroups(mergedHomeScreenConfig.SEASONAL_SECTION_GROUPS);
@@ -1760,33 +1786,9 @@
function buildSectionContentHTML(sectionType) {
// Always use currentConfig as source of truth
if (!currentConfig) return '<div class="listItemBodyText secondary">No configuration loaded.</div>';
const mergeNextUp = currentConfig.MERGE_NEXT_UP || false;
// Filter groups based on mergeNextUp setting
const getFilteredGroups = (groups) => {
if (mergeNextUp) {
// Filter out groups containing nextUp or continueWatching sections when merged
return groups.map(group => {
const filteredSections = (group.sections || []).filter(s =>
s.id !== 'nextUp' && s.id !== 'continueWatching'
);
return { ...group, sections: filteredSections };
}).filter(group => group.sections.length > 0);
} else {
// Filter out continueWatchingAndNextUp section
return groups.map(group => {
const filteredSections = (group.sections || []).filter(s =>
s.id !== 'continueWatchingAndNextUp'
);
return { ...group, sections: filteredSections };
}).filter(group => group.sections.length > 0);
}
};
switch (sectionType) {
case 'home': {
//const homeGroups = getFilteredGroups(currentConfig.HOME_SECTION_GROUPS || []);
const homeGroups = currentConfig.HOME_SECTION_GROUPS || [];
return `
@@ -2228,8 +2230,7 @@
CACHE: currentConfig?.CACHE,
SPOTLIGHT_SETTINGS: currentConfig?.SPOTLIGHT_SETTINGS,
HOME_SETTINGS: currentConfig?.HOME_SETTINGS,
USER_HOME_SCREEN_SETTINGS: currentConfig?.USER_HOME_SCREEN_SETTINGS,
MERGE_NEXT_UP: currentConfig?.MERGE_NEXT_UP
USER_HOME_SCREEN_SETTINGS: currentConfig?.USER_HOME_SCREEN_SETTINGS
};
}
@@ -2784,82 +2785,6 @@
// Attach initial section row listeners
attachSectionRowListeners(dialog);
// Merge Next Up toggle - update currentConfig immediately and refresh sections tab
// Use event delegation to prevent stacking listeners when switching tabs
/* dialog.addEventListener('click', async (e) => {
const btn = e.target.closest('#merge-next-up');
if (!btn) return;
currentConfig.MERGE_NEXT_UP = btn.checked;
// Hide continue watching and next up sections if merge next up is enabled
const continueWatchingGroup = currentConfig.HOME_SECTION_GROUPS.find(g => g.name === 'Continue Watching');
if (continueWatchingGroup) {
continueWatchingGroup.sections = continueWatchingGroup.sections.map(s => {
if (s.id === 'continueWatchingAndNextUp') {
s.enabled = currentConfig.MERGE_NEXT_UP;
s.hidden = !currentConfig.MERGE_NEXT_UP;
} else {
s.enabled = !currentConfig.MERGE_NEXT_UP;
s.hidden = currentConfig.MERGE_NEXT_UP;
}
return s;
});
// Update continueWatchingGroup in currentConfig
currentConfig.HOME_SECTION_GROUPS = currentConfig.HOME_SECTION_GROUPS.map(g => {
if (g.name === 'Continue Watching') {
return continueWatchingGroup;
}
return g;
});
}
await saveConfig(currentConfig);
refreshMainModal();
}); */
/* const mergeNextUpCheckbox = dialog.querySelector('#merge-next-up');
if (mergeNextUpCheckbox) {
mergeNextUpCheckbox.addEventListener('change', async () => {
currentConfig.MERGE_NEXT_UP = mergeNextUpCheckbox.checked;
// Hide continue watching and next up sections if merge next up is enabled
const continueWatchingGroup = currentConfig.HOME_SECTION_GROUPS.find(g => g.name === 'Continue Watching');
if (continueWatchingGroup) {
continueWatchingGroup.sections = continueWatchingGroup.sections.map(s => {
if (s.id === 'continueWatchingAndNextUp') {
s.enabled = currentConfig.MERGE_NEXT_UP;
s.hidden = !currentConfig.MERGE_NEXT_UP;
} else {
s.enabled = !currentConfig.MERGE_NEXT_UP;
s.hidden = currentConfig.MERGE_NEXT_UP;
}
return s;
});
// Update continueWatchingGroup in currentConfig
currentConfig.HOME_SECTION_GROUPS = currentConfig.HOME_SECTION_GROUPS.map(g => {
if (g.name === 'Continue Watching') {
return continueWatchingGroup;
}
return g;
});
}
await saveConfig(currentConfig);
// Refresh sections tab if it's currently visible
const sectionsTab = dialog.querySelector('#tab-sections');
if (sectionsTab && sectionsTab.style.display !== 'none') {
const contentContainer = dialog.querySelector('#section-content');
if (contentContainer) {
const activeNavBtn = dialog.querySelector('.section-type-nav-btn.active');
const activeType = activeNavBtn ? activeNavBtn.dataset.sectionType : 'home';
contentContainer.innerHTML = buildSectionContentHTML(activeType);
}
}
});
} */
// Group toggle-all buttons
// Use event delegation to prevent stacking listeners when switching tabs
@@ -3459,39 +3384,8 @@
const checkbox = document.getElementById(checkboxId);
if (checkbox) {
checkbox.checked = !checkbox.checked;
// Trigger change event for any listeners (like merge-next-up)
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
updateToggleSliderUI(btn, checkbox.checked);
if (checkboxId === 'merge-next-up') {
currentConfig.MERGE_NEXT_UP = checkbox.checked;
// Hide continue watching and next up sections if merge next up is enabled
const continueWatchingGroup = currentConfig.HOME_SECTION_GROUPS.find(g => g.name === 'Continue Watching');
if (continueWatchingGroup) {
continueWatchingGroup.sections = continueWatchingGroup.sections.map(s => {
if (s.id === 'continueWatchingAndNextUp') {
s.enabled = currentConfig.MERGE_NEXT_UP;
s.hidden = !currentConfig.MERGE_NEXT_UP;
} else {
s.enabled = !currentConfig.MERGE_NEXT_UP;
s.hidden = currentConfig.MERGE_NEXT_UP;
}
return s;
});
// Update continueWatchingGroup in currentConfig
currentConfig.HOME_SECTION_GROUPS = currentConfig.HOME_SECTION_GROUPS.map(g => {
if (g.name === 'Continue Watching') {
return continueWatchingGroup;
}
return g;
});
}
await saveConfig(currentConfig);
refreshMainModal();
}
}
} else {
// Fallback: just toggle the visual state
-1
View File
@@ -49,7 +49,6 @@
DISCOVERY_SECTION_GROUPS: JSON.parse(JSON.stringify(defaults.DISCOVERY_SECTION_GROUPS || [])),
CUSTOM_SECTION_GROUPS: [],
REMOVE_CONFLICTING_SECTIONS: legacyHomeScreen.removeConflictingSections !== false,
MERGE_NEXT_UP: false,
DISCOVERY_SETTINGS: JSON.parse(JSON.stringify(defaults.DISCOVERY_SETTINGS || {})),
SEASONAL_THEME_SETTINGS: JSON.parse(JSON.stringify(defaults.SEASONAL_THEME_SETTINGS || {}))
};
+57 -20
View File
@@ -1598,6 +1598,37 @@
}
}
/**
* Wait until admin homeScreen-configuration has registered getSections/getConfig.
* Injector loads deps in parallel, so prefs can open before that API exists.
*/
function waitForHomeScreenSectionsApi(timeoutMs = 15000, intervalMs = 100) {
return new Promise((resolve) => {
if (typeof window.KefinHomeScreen?.getSections === 'function'
&& typeof window.KefinHomeScreen?.getConfig === 'function') {
resolve(true);
return;
}
const start = Date.now();
const timer = setInterval(() => {
if (typeof window.KefinHomeScreen?.getSections === 'function'
&& typeof window.KefinHomeScreen?.getConfig === 'function') {
clearInterval(timer);
resolve(true);
return;
}
if (Date.now() - start >= timeoutMs) {
clearInterval(timer);
resolve(false);
}
}, intervalMs);
});
}
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Render user home sections editor
*/
@@ -1608,14 +1639,18 @@
}
try {
// Check dependencies
if (!window.KefinHomeScreen || !window.KefinHomeScreen.getSections) {
container.innerHTML = '<div class="listItemBodyText secondary">Loading home sections…</div>';
const apiReady = await waitForHomeScreenSectionsApi();
if (!apiReady) {
ERR('KefinHomeScreen.getSections not available');
container.innerHTML = '<div class="listItemBodyText secondary">Error loading editor. Please refresh the page.</div>';
return;
}
if (!window.KefinTweaksUI || !window.KefinTweaksUI.renderHomeSectionsOrderEditor) {
ERR('KefinTweaksUI.renderHomeSectionsOrderEditor not available');
container.innerHTML = '<div class="listItemBodyText secondary">Error loading editor. Please refresh the page.</div>';
return;
}
@@ -1624,7 +1659,7 @@
let allSections = (userConfig.sections || []).filter((s) => {
if (s.userConfigurable === false) return false;
if (s.type === 'discovery' || s.discoveryEnabled === true) return false;
// Keep hidden sections only when currently enabled (e.g. merge CW+Next Up)
// Keep hidden sections only when currently enabled
if (s.hidden === true && s.enabled === false) return false;
return true;
});
@@ -1802,26 +1837,28 @@
}
window.KefinTweaksUtils.onViewPage(async (view, element, hash) => {
// Check if we're on the mypreferenceshome page
LOG('Preferences home page detected');
const form = document.querySelector('.libraryPage:not(.hide) .homeScreenSettingsContainer > form');
if (form && form.firstChild) {
// Check if editor already rendered
if (form.querySelector('#kefin-user-home-sections-editor')) {
return;
}
// Create container for editor
const editorContainer = document.createElement('div');
editorContainer.id = 'kefin-user-home-sections-editor';
// Insert as last child of the form
form.appendChild(editorContainer);
// Render editor
await renderUserHomeSectionsEditor(editorContainer);
let form = null;
for (let attempt = 0; attempt < 20; attempt++) {
form = document.querySelector('.libraryPage:not(.hide) .homeScreenSettingsContainer > form');
if (form && form.firstChild) break;
await delay(150);
}
if (!form || !form.firstChild) {
WARN('Home settings form not ready');
return;
}
if (form.querySelector('#kefin-user-home-sections-editor')) {
return;
}
const editorContainer = document.createElement('div');
editorContainer.id = 'kefin-user-home-sections-editor';
form.appendChild(editorContainer);
await renderUserHomeSectionsEditor(editorContainer);
}, {
pages: ['mypreferenceshome', 'userpreferences']
});
+3 -1
View File
@@ -963,7 +963,9 @@
hideWatched: inferHideWatched(section),
hideName: section.hideName === true,
userEnabledByDefault: section.enabled !== false,
userConfigurable: section.hidden !== true,
userConfigurable: section.userConfigurable !== undefined
? section.userConfigurable !== false
: section.hidden !== true,
groupSelect: groupSelection.groupSelect,
groupNew: groupSelection.groupNew,
queries: (section.queries?.length ? section.queries : [createDefaultQuery()]).map(q => ({ ...q })),
-49
View File
@@ -737,32 +737,6 @@
});
}
// Handle MergeNextUp setting - check if continueWatchingAndNextUp should be enabled
const mergeNextUp = await getMergeNextUpSetting();
if (mergeNextUp) {
// Find and disable nextUp and continueWatching sections when merged
const nextUpIndex = merged.findIndex(s => s.id === 'nextUp');
const continueWatchingIndex = merged.findIndex(s => s.id === 'continueWatching');
if (nextUpIndex !== -1) {
merged[nextUpIndex].enabled = false;
}
if (continueWatchingIndex !== -1) {
merged[continueWatchingIndex].enabled = false;
}
// Enable the merged section
const mergedIndex = merged.findIndex(s => s.id === 'continueWatchingAndNextUp');
if (mergedIndex !== -1) {
merged[mergedIndex].enabled = true;
LOG('MergeNextUp enabled: Using continueWatchingAndNextUp section');
}
} else {
// Disable merged section if merge is not enabled
const mergedIndex = merged.findIndex(s => s.id === 'continueWatchingAndNextUp');
if (mergedIndex !== -1) {
merged[mergedIndex].enabled = false;
}
}
// Filter seasonal sections based on date
const filteredMerged = merged.filter(section => {
if (section.startDate && section.endDate) {
@@ -1135,7 +1109,6 @@
let performanceDuration;
const performanceTimes = [];
const mergeNextUp = await getMergeNextUpSetting();
for (const sectionConfig of sortedSections) {
const loopStartTime = performance.now();
@@ -1158,19 +1131,6 @@
continue;
}
// Check merge setting for continueWatchingAndNextUp
if (sectionConfig.id === 'continueWatchingAndNextUp' && !mergeNextUp) {
LOG(`Skipping continueWatchingAndNextUp: merge not enabled`);
continue;
}
// Skip individual sections when merge is enabled
if (mergeNextUp &&
(sectionConfig.id === 'continueWatching' || sectionConfig.id === 'nextUp')) {
LOG(`Skipping ${sectionConfig.id}: merge enabled, using continueWatchingAndNextUp`);
continue;
}
sectionPromises.push(loadSectionForRendering(sectionConfig));
const loopEndTime = performance.now();
@@ -1252,15 +1212,6 @@
return date.toLocaleDateString('en-US', options);
}
async function getMergeNextUpSetting() {
const config = await window.KefinHomeScreen.getConfig();
const mergeNextUp = config.MERGE_NEXT_UP;
if (mergeNextUp !== undefined) {
return mergeNextUp;
}
return false;
}
let _displayPreferencesPromise = null;
async function fetchDisplayPreferences() {
+1 -8
View File
@@ -75,7 +75,6 @@
name: 'Continue Watching',
jellyfinId: 'resume',
enabled: false,
hidden: false,
order: 10,
cardFormat: 'Thumb',
ttl: CACHE_CONFIG.FORCE_REFRESH_TTL,
@@ -99,7 +98,6 @@
name: 'Next Up',
jellyfinId: 'nextup',
enabled: false,
hidden: false,
order: 11,
cardFormat: 'Thumb',
ttl: CACHE_CONFIG.FORCE_REFRESH_TTL,
@@ -122,9 +120,8 @@
id: 'continueWatchingAndNextUp',
name: 'Continue Watching and Next Up',
jellyfinId: 'resume',
enabled: false, // Disabled by default - only used when merge setting is enabled
enabled: false,
order: 10,
hidden: true,
cardFormat: 'Thumb',
ttl: CACHE_CONFIG.FORCE_REFRESH_TTL,
sortBy: 'DatePlayed', // Used to sort merged results from both queries
@@ -161,7 +158,6 @@
name: 'Continue Listening',
jellyfinId: 'resumeaudio',
enabled: false,
hidden: false,
order: 10,
cardFormat: 'Square',
ttl: CACHE_CONFIG.FORCE_REFRESH_TTL,
@@ -185,7 +181,6 @@
name: 'Continue Reading',
jellyfinId: 'resumebook',
enabled: false,
hidden: false,
order: 10,
cardFormat: 'Poster',
ttl: CACHE_CONFIG.FORCE_REFRESH_TTL,
@@ -1542,7 +1537,6 @@
DISCOVERY_SECTION_GROUPS: KEFINTWEAKS_DISCOVERY_SECTION_GROUPS,
CUSTOM_SECTION_GROUPS: [], // Empty by default - user-created/imported sections
REMOVE_CONFLICTING_SECTIONS: true,
MERGE_NEXT_UP: false,
HOME_SETTINGS: HOME_SETTINGS,
USER_HOME_SCREEN_SETTINGS: USER_HOME_SCREEN_SETTINGS,
DISCOVERY_SETTINGS: DISCOVERY_SETTINGS,
@@ -1558,7 +1552,6 @@
DISCOVERY_SECTION_GROUPS: KEFINTWEAKS_DISCOVERY_SECTION_GROUPS, // modified by user configuration
CUSTOM_SECTION_GROUPS: [], // Empty by default - user-created/imported sections // modified by user configuration
REMOVE_CONFLICTING_SECTIONS: true,
MERGE_NEXT_UP: false,
HOME_SETTINGS: HOME_SETTINGS,
DISCOVERY_SETTINGS: DISCOVERY_SETTINGS,
SEASONAL_THEME_SETTINGS: SEASONAL_THEME_SETTINGS,