Implement cached duration fallback and simulate keyboard events fallback for Disney+ seeks when controls are hidden

This commit is contained in:
Timo
2026-07-02 13:27:53 +02:00
parent 71fa6e7315
commit bea0f6925c
2 changed files with 37 additions and 2 deletions
+36 -2
View File
@@ -59,6 +59,7 @@
// --- SHARED_EVENTS_INJECT_END ---
// Suppresses native event reporting after a programmatic action.
// Each entry is a per-type timer (key = 'playing'|'paused'|'seek').
@@ -218,10 +219,31 @@
const now = Number(node.getAttribute?.('aria-valuenow') ?? node.value);
const max = Number(node.getAttribute?.('aria-valuemax') ?? node.max);
if (Number.isFinite(now) && Number.isFinite(max) && max >= 60 && now >= 0 && now <= max + 5) {
considerTimeline({ current: now, duration: max }, 'aria-value', 300);
considerTimeline({ current: now, duration: max }, 'aria-value', 300);
}
for (const attr of ['aria-valuetext', 'aria-label', 'title', 'data-testid', 'data-test']) {
const parsed = parseTimelineText(node.getAttribute?.(attr));
considerTimeline(parsed, attr, 200);
}
const text = String(node.textContent || '').trim();
if (text && text.length < 200) {
const parsed = parseTimelineText(text);
considerTimeline(parsed, 'text', 100);
textParts.push(text);
}
}
considerTimeline(parseTimelineText(textParts.join(' ')), 'combined-text', 25);
lastDisneyPlusTimelineCandidates = candidates
.sort((a, b) => b.score - a.score)
.slice(0, 8)
.map(({ source, current, duration }) => ({ source, current, duration }));
for (const attr of ['aria-valuetext', 'aria-label', 'title', 'data-testid', 'data-test']) {
return best;
}
function getElementLabel(el) {
return [
el.getAttribute?.('aria-label'),
el.getAttribute?.('title'),
@@ -233,6 +255,7 @@
function getDisneyPlusSeekButtonLabels() {
if (!isDisneyPlusHost() || typeof document === 'undefined') return [];
return Array.from(document.querySelectorAll('button,[role="button"]'))
.map(getElementLabel)
.filter(Boolean)
.slice(0, 20);
@@ -251,6 +274,17 @@
const matchesDirection = backward ? backRe.test(label) : forwardRe.test(label);
return matchesDirection && timeRe.test(label);
}) || candidates.find(btn => {
const label = getElementLabel(btn);
return backward ? backRe.test(label) : forwardRe.test(label);
});
if (button && typeof button.click === 'function') {
const clicks = Math.max(1, Math.min(12, Math.round(Math.abs(delta) / 10)));
for (let i = 0; i < clicks; i++) {
setTimeout(() => button.click(), i * 60);
}
return true;
}
// Fallback: Simulate ArrowLeft / ArrowRight keyboard events
const clicks = Math.max(1, Math.min(12, Math.round(Math.abs(delta) / 10)));
+1
View File
@@ -91,6 +91,7 @@ function makeNode(attrs = {}, textContent = '') {
function loadTimelineFns(hostname, document = makeDocument()) {
return Function('window', 'document', [
'let lastDisneyPlusTimelineCandidates = [];',
'let lastKnownDisneyPlusDuration = 0;',
extractFunction('hostMatchesUrl', source),
extractFunction('matchesPlayerUrls', source),
extractFunction('isDisneyPlusHost', source),