const GOOGLE_DRIVE_HOST = 'drive.google.com'; const GOOGLE_DRIVE_PLAYER_HOST = 'youtube.googleapis.com'; export const GOOGLE_DRIVE_PLAYER_ORIGIN_PATTERN = 'https://youtube.googleapis.com/*'; export const GOOGLE_DRIVE_PLAYER_ACCESS_REQUIRED = 'google_drive_player_access_required'; export const GOOGLE_DRIVE_PLAYER_AMBIGUOUS = 'google_drive_player_ambiguous'; export function isGoogleDriveUrl(value) { try { return new URL(value).hostname.toLowerCase() === GOOGLE_DRIVE_HOST; } catch { return false; } } export function inspectMediaFrame() { const videos = Array.from(document.querySelectorAll('video')); const drivePlayerIframes = Array.from(document.querySelectorAll('iframe')).filter((frame) => { try { const url = new URL(frame.src); if (url.hostname.toLowerCase() !== 'youtube.googleapis.com') return false; const origin = url.searchParams.get('origin') || url.searchParams.get('post_message_origin'); return origin === 'https://drive.google.com'; } catch { return false; } }); let bestVideoScore = 0; for (const video of videos) { const width = video.videoWidth || video.offsetWidth || 0; const height = video.videoHeight || video.offsetHeight || 0; const duration = Number.isFinite(video.duration) ? video.duration : 0; bestVideoScore = Math.max(bestVideoScore, (width * height) + (duration * 100)); } return { href: window.location.href, videoCount: videos.length, videoScore: bestVideoScore, frameArea: Math.max(0, window.innerWidth) * Math.max(0, window.innerHeight), drivePlayerIframeCount: drivePlayerIframes.length, parentFrameVisible: window.__koalaParentFrameVisibility?.visible ?? null, parentFrameArea: window.__koalaParentFrameVisibility?.area ?? null }; } export function installParentFrameVisibilityProbe(token) { const handler = (event) => { if (event.source !== window.parent || event.data?.type !== 'KOALASYNC_FRAME_VISIBILITY' || event.data?.token !== token) { return; } window.__koalaParentFrameVisibility = { visible: event.data.visible === true, area: Number.isFinite(event.data.area) ? event.data.area : 0 }; window.removeEventListener('message', handler); }; window.addEventListener('message', handler); } export async function dispatchParentFrameVisibilityProbe(token) { let count = 0; for (const frame of document.querySelectorAll('iframe')) { try { const url = new URL(frame.src); const origin = url.searchParams.get('origin') || url.searchParams.get('post_message_origin'); if (url.hostname.toLowerCase() !== 'youtube.googleapis.com' || origin !== 'https://drive.google.com') { continue; } const rect = frame.getBoundingClientRect(); const style = window.getComputedStyle(frame); const area = Math.max(0, rect.width) * Math.max(0, rect.height); const intersectsViewport = rect.bottom > 0 && rect.right > 0 && rect.top < window.innerHeight && rect.left < window.innerWidth; const browserReportsVisible = typeof frame.checkVisibility === 'function' ? frame.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }) : true; const visible = area > 0 && intersectsViewport && browserReportsVisible && style.display !== 'none' && style.visibility !== 'hidden' && Number(style.opacity) !== 0; frame.contentWindow?.postMessage({ type: 'KOALASYNC_FRAME_VISIBILITY', token, visible, area }, 'https://youtube.googleapis.com'); count++; } catch { // Ignore unrelated or not-yet-initialized frames. } } await new Promise(resolve => setTimeout(resolve, 100)); return count; } function isGoogleDrivePlayerFrameUrl(value) { try { const url = new URL(value); if (url.hostname.toLowerCase() !== GOOGLE_DRIVE_PLAYER_HOST || url.pathname !== '/embed/') { return false; } const origin = url.searchParams.get('origin') || url.searchParams.get('post_message_origin'); return origin === 'https://drive.google.com'; } catch { return false; } } function createGoogleDrivePlayerAccessError() { const error = new Error('Google Drive player frame access is required'); error.code = GOOGLE_DRIVE_PLAYER_ACCESS_REQUIRED; error.originPattern = GOOGLE_DRIVE_PLAYER_ORIGIN_PATTERN; return error; } function createGoogleDrivePlayerAmbiguousError() { const error = new Error('Google Drive player frame could not be identified safely'); error.code = GOOGLE_DRIVE_PLAYER_AMBIGUOUS; return error; } export function selectGoogleDrivePlayerFrame(injectionResults) { let candidates = (Array.isArray(injectionResults) ? injectionResults : []) .filter(entry => Number.isInteger(entry?.frameId) && entry?.result) .filter(entry => isGoogleDrivePlayerFrameUrl(entry.result.href)); if (candidates.length > 1) { const confirmedVisible = candidates.filter(entry => entry.result.parentFrameVisible === true); if (confirmedVisible.length > 0) { candidates = confirmedVisible; } else { const notConfirmedHidden = candidates.filter(entry => entry.result.parentFrameVisible !== false ); if (notConfirmedHidden.length !== 1) return null; candidates = notConfirmedHidden; } } candidates.sort((left, right) => { const visibilityRank = result => result.parentFrameVisible === true ? 2 : result.parentFrameVisible === false ? 0 : 1; const leftVisible = visibilityRank(left.result); const rightVisible = visibilityRank(right.result); if (leftVisible !== rightVisible) return rightVisible - leftVisible; const leftParentArea = Number.isFinite(left.result.parentFrameArea) ? left.result.parentFrameArea : left.result.frameArea; const rightParentArea = Number.isFinite(right.result.parentFrameArea) ? right.result.parentFrameArea : right.result.frameArea; if (leftParentArea !== rightParentArea) return rightParentArea - leftParentArea; const leftHasVideo = left.result.videoCount > 0 ? 1 : 0; const rightHasVideo = right.result.videoCount > 0 ? 1 : 0; if (leftHasVideo !== rightHasVideo) return rightHasVideo - leftHasVideo; if (left.result.videoScore !== right.result.videoScore) { return right.result.videoScore - left.result.videoScore; } return right.result.frameArea - left.result.frameArea; }); return candidates[0] || null; } export async function resolveMediaScriptTarget(chromeApi, tabId, tabUrl, { attempts = 8, retryDelayMs = 200 } = {}) { const topFrameTarget = { tabId }; if (!isGoogleDriveUrl(tabUrl)) return topFrameTarget; let fallbackFrame = null; let drivePlayerIframeDetected = false; let ambiguousPlayerFramesDetected = false; for (let attempt = 0; attempt < attempts; attempt++) { let results; try { results = await chromeApi.scripting.executeScript({ target: { tabId, allFrames: true }, func: inspectMediaFrame }); } catch { let topFrameResult = null; try { const topResults = await chromeApi.scripting.executeScript({ target: { tabId }, func: inspectMediaFrame }); topFrameResult = Array.isArray(topResults) ? topResults[0]?.result : null; } catch { // The generic injection path below remains the final source of truth. } if (topFrameResult?.drivePlayerIframeCount > 0) { throw createGoogleDrivePlayerAccessError(); } return topFrameTarget; } const topFrame = results.find(entry => entry?.frameId === 0); if (topFrame?.result?.drivePlayerIframeCount > 0) { drivePlayerIframeDetected = true; } const playerFrameCount = results.filter(entry => isGoogleDrivePlayerFrameUrl(entry?.result?.href) ).length; if (playerFrameCount > 1) { const token = `${tabId}:${attempt}:${Date.now()}:${Math.random()}`; try { await chromeApi.scripting.executeScript({ target: { tabId, allFrames: true }, func: installParentFrameVisibilityProbe, args: [token] }); await chromeApi.scripting.executeScript({ target: { tabId }, func: dispatchParentFrameVisibilityProbe, args: [token] }); results = await chromeApi.scripting.executeScript({ target: { tabId, allFrames: true }, func: inspectMediaFrame }); } catch { // Ambiguous frames are retried below; never guess a stale player. } } const selectedFrame = selectGoogleDrivePlayerFrame(results); if (!selectedFrame && playerFrameCount > 1) { ambiguousPlayerFramesDetected = true; } if (selectedFrame?.result?.videoCount > 0) { return { tabId, frameIds: [selectedFrame.frameId] }; } if (selectedFrame) fallbackFrame = selectedFrame; if (attempt < attempts - 1) { await new Promise(resolve => setTimeout(resolve, retryDelayMs)); } } if (!fallbackFrame && ambiguousPlayerFramesDetected) { throw createGoogleDrivePlayerAmbiguousError(); } if (!fallbackFrame && drivePlayerIframeDetected) { throw createGoogleDrivePlayerAccessError(); } return fallbackFrame ? { tabId, frameIds: [fallbackFrame.frameId] } : topFrameTarget; }