mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Don't load next up from server if we can infer it from the DOM
This commit is contained in:
@@ -7,9 +7,10 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.detailSection:has(.series-episodes-section) {
|
||||
#itemDetailPage[data-series-episodes-item-id] .detailSection {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.series-episodes-section {
|
||||
padding-left: 0 !important;
|
||||
margin: 0 !important;
|
||||
|
||||
+71
-11
@@ -337,6 +337,54 @@
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer Next Up episode from the native .nextUpSection card title (S#:E#).
|
||||
* @param {HTMLElement} activePage
|
||||
* @returns {Object|null}
|
||||
*/
|
||||
function inferNextUpFromDom(activePage) {
|
||||
if (!activePage) return null;
|
||||
|
||||
const card = activePage.querySelector('.nextUpSection .itemsContainer .card');
|
||||
if (!card) return null;
|
||||
|
||||
const titleLink = card.querySelector('.cardText-first a[title]');
|
||||
if (!titleLink) return null;
|
||||
|
||||
const title = titleLink.getAttribute('title') || '';
|
||||
const match = title.match(/S(\d+)\s*:\s*E(\d+)/i);
|
||||
if (!match) return null;
|
||||
|
||||
const season = parseInt(match[1], 10);
|
||||
const episode = parseInt(match[2], 10);
|
||||
if (!Number.isFinite(season) || !Number.isFinite(episode)) return null;
|
||||
|
||||
let id = null;
|
||||
const href = titleLink.getAttribute('href') || '';
|
||||
const idMatch = href.match(/[?&]id=([^&]+)/i);
|
||||
if (idMatch) {
|
||||
try {
|
||||
id = decodeURIComponent(idMatch[1]);
|
||||
} catch (_) {
|
||||
id = idMatch[1];
|
||||
}
|
||||
}
|
||||
if (!id) {
|
||||
id = card.getAttribute('data-id') || card.dataset?.id || null;
|
||||
}
|
||||
|
||||
const nameRemainder = title.replace(/S\d+\s*:\s*E\d+\s*-?\s*/i, '').trim();
|
||||
|
||||
LOG(`Inferred Next Up from DOM: S${season}:E${episode}${id ? ` (${id})` : ''}`);
|
||||
return {
|
||||
ParentIndexNumber: season,
|
||||
IndexNumber: episode,
|
||||
Id: id,
|
||||
SeasonId: null,
|
||||
Name: nameRemainder || title
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the Next Up episode for a given series
|
||||
* @param {string} seriesId - The series ID
|
||||
@@ -507,14 +555,24 @@
|
||||
}
|
||||
|
||||
function performEpisodeScroll(scrollerContainer, targetCard, targetEpisodeNumber) {
|
||||
const scrollerPadding = parseInt(window.getComputedStyle(scrollerContainer).paddingLeft, 10) || 0;
|
||||
const translateX = targetCard.offsetLeft - scrollerPadding;
|
||||
window.cardBuilder.setScrollerPosition(scrollerContainer, translateX, false);
|
||||
const itemsContainer = scrollerContainer.querySelector('.itemsContainer') || scrollerContainer;
|
||||
const cards = Array.from(itemsContainer.querySelectorAll(
|
||||
':scope > .card:not(.card-layout-dummy):not(.skeleton-card)'
|
||||
));
|
||||
const index = cards.indexOf(targetCard);
|
||||
if (index < 0) {
|
||||
WARN(`Target episode card not in scroller card list S${targetEpisodeNumber.season}:E${targetEpisodeNumber.episode}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.cardBuilder?.scrollToCardIndex) {
|
||||
window.cardBuilder.scrollToCardIndex(scrollerContainer, index, { animate: false });
|
||||
}
|
||||
|
||||
const scrollButtons = scrollerContainer.closest('.emby-scroller-container')?.querySelector('.emby-scrollbuttons');
|
||||
if (scrollButtons) {
|
||||
const leftButton = scrollButtons.querySelector('button[data-direction="left"]');
|
||||
if (leftButton) {
|
||||
if (leftButton && index > 0) {
|
||||
leftButton.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
@@ -748,8 +806,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Get NextUp episode
|
||||
let targetEpisode = await fetchNextUpEpisode(seriesId);
|
||||
// Prefer Next Up from native DOM (already painted); API only if missing
|
||||
const pageForUi = document.querySelector('.libraryPage:not(.hide)') || activePage;
|
||||
let targetEpisode = inferNextUpFromDom(pageForUi);
|
||||
if (!targetEpisode) {
|
||||
targetEpisode = await fetchNextUpEpisode(seriesId);
|
||||
}
|
||||
let targetEpisodeNumber = null;
|
||||
|
||||
// Determine target season
|
||||
@@ -788,7 +850,6 @@
|
||||
|
||||
// Extract NextUp header text
|
||||
let nextUpHeaderText = 'Next Up';
|
||||
const pageForUi = document.querySelector('.libraryPage:not(.hide)') || activePage;
|
||||
const nextUpSection = pageForUi.querySelector('.nextUpSection');
|
||||
if (nextUpSection) {
|
||||
const nextUpHeader = nextUpSection.querySelector('.sectionTitle, h2, h3');
|
||||
@@ -801,6 +862,8 @@
|
||||
// Render episodes section
|
||||
await renderEpisodesSection(seriesId, seasons, targetEpisode, nextUpHeaderText);
|
||||
|
||||
const childrenCollapsible = activePage.querySelector('.detailSection #listChildrenCollapsible');
|
||||
|
||||
// Hide season container if option is enabled and there's only one season
|
||||
if (hideSingleSeasonContainer && isSingleSeason && childrenCollapsible) {
|
||||
childrenCollapsible.style.display = 'none';
|
||||
@@ -894,10 +957,7 @@
|
||||
|
||||
LOG(`Found series: ${item.Id} (${item.Name})`);
|
||||
|
||||
// Small delay to ensure page is ready (Emby may still be swapping pages)
|
||||
setTimeout(async () => {
|
||||
await processSeriesPage(item);
|
||||
}, 100);
|
||||
await processSeriesPage(item);
|
||||
},
|
||||
{
|
||||
pages: ['details']
|
||||
|
||||
Reference in New Issue
Block a user