fix: detect videos inside same-origin player iframes

Sites like jkanime.net render the real <video> inside a first-party
iframe, so the top document had zero video elements and the content
script reported "NO VIDEO ELEMENT".

findVideo() now descends into reachable frame documents, the
MutationObserver registers those documents too (frame mutations never
bubble to the parent), and frame load events re-trigger the scan so a
late-loading player is still picked up. Debug reports count videos
across frames and expose an "In Iframe" flag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
KoalaDev
2026-08-14 06:36:07 +02:00
parent 48d6c1dc0b
commit 809301b641
3 changed files with 130 additions and 5 deletions
+46
View File
@@ -71,6 +71,52 @@ assert.strictEqual(
'findVideo should score Shadow DOM videos together with light DOM videos'
);
// Same-origin player iframe (jkanime.net): the top document has no <video>,
// the real player lives inside the frame document.
const framedPlayer = makeVideo('framed-player', 1280, 720, { muted: false, duration: 1400 });
const frameDocument = {
querySelectorAll(selector) {
if (selector === 'video') return [framedPlayer];
return [];
}
};
const playerFrame = { contentDocument: frameDocument };
const framedTopDocument = {
querySelectorAll(selector) {
if (selector === 'video') return [];
if (selector === 'iframe, frame') return [playerFrame];
return [];
}
};
assert.strictEqual(
findVideo(framedTopDocument),
framedPlayer,
'findVideo should descend into same-origin player iframes'
);
// A cross-origin frame throws on contentDocument and must not break the scan.
const crossOriginFrame = {
get contentDocument() { throw new Error('blocked by same-origin policy'); }
};
const crossOriginTopDocument = {
querySelectorAll(selector) {
if (selector === 'video') return [lightPreview];
if (selector === 'iframe, frame') return [crossOriginFrame];
return [];
}
};
assert.strictEqual(
findVideo(crossOriginTopDocument),
lightPreview,
'findVideo should skip unreachable cross-origin frames'
);
function makeDocument(nodes = []) {
return {
querySelectorAll() { return nodes; }