diff --git a/src/background/utils/getAutoMedia.ts b/src/background/utils/getAutoMedia.ts index 316945ac..855ab43b 100644 --- a/src/background/utils/getAutoMedia.ts +++ b/src/background/utils/getAutoMedia.ts @@ -38,46 +38,16 @@ export async function clearClosed() { const tabIds = new Set(tabs.map((t) => t.id)) const clearKeys: string[] = [] for (let key in data) { - if (!key.startsWith("m:scope:")) return - if (tabIds.has(data[key]?.tabInfo.tabId)) return + if (!key.startsWith("m:scope:")) continue + if (tabIds.has(data[key]?.tabInfo.tabId)) continue clearKeys.push(key) } chrome.storage.session.remove(clearKeys) } -export async function getMediaData() { - const d = await getMediaDataWithScopes() - return { pinned: d.pinned, infos: flattenMediaInfos(d.scopes) } satisfies MediaData -} - -export async function getAutoMedia(tabInfo: TabInfo, videoOnly?: boolean) { - let [{ ignorePiP }, { infos, pinned }] = await Promise.all([fetchView({ ignorePiP: true }), getMediaData()]) - - infos = infos.filter((info) => info.readyState) - infos = videoOnly ? infos.filter((info) => info.videoSize) : infos - - const pinnedInfo = infos.find((info) => info.key === pinned?.key) - if (pinnedInfo && (await checkContentScript(pinnedInfo.tabInfo.tabId, pinnedInfo.tabInfo.frameId))) return pinnedInfo - - infos.sort((a, b) => b.creationTime - a.creationTime) - let pippedInfo = infos.find((info) => info.pipMode) || infos.find((info) => info.isDip) - if (pippedInfo && !(await checkContentScript(pippedInfo.tabInfo.tabId, pippedInfo.tabInfo.frameId))) { - pippedInfo = null - } - - if (!ignorePiP && pippedInfo) return pippedInfo - if (tabInfo) { - infos = infos.filter((info) => info.tabInfo.tabId === tabInfo.tabId) - } - - if (!infos.length) return pippedInfo || undefined - - const now = Date.now() - let peakIntersect = infos - .filter((v) => v.intersectionRatio != null) - .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]?.intersectionRatio - +function pickHighest(infos: FlatMediaInfo[], tabInfo: TabInfo, now: number, peakIntersect: number) { let highest: { info: FlatMediaInfo; score: number } + infos.forEach((info) => { let score = 0 @@ -114,5 +84,57 @@ export async function getAutoMedia(tabInfo: TabInfo, videoOnly?: boolean) { } }) - return highest?.info + return highest +} + +export async function getMediaData() { + const d = await getMediaDataWithScopes() + return { pinned: d.pinned, infos: flattenMediaInfos(d.scopes) } satisfies MediaData +} + +export async function getAutoMedia(tabInfo: TabInfo, videoOnly?: boolean) { + let [{ ignorePiP }, { infos, pinned }] = await Promise.all([fetchView({ ignorePiP: true }), getMediaData()]) + + infos = infos.filter((info) => info.readyState) + infos = videoOnly ? infos.filter((info) => info.videoSize) : infos + + const pinnedInfo = infos.find((info) => info.key === pinned?.key) + if (pinnedInfo && (await checkContentScript(pinnedInfo.tabInfo.tabId, pinnedInfo.tabInfo.frameId))) return pinnedInfo + + infos.sort((a, b) => b.creationTime - a.creationTime) + let pippedInfo = infos.find((info) => info.pipMode) || infos.find((info) => info.isDip) + if (pippedInfo && !(await checkContentScript(pippedInfo.tabInfo.tabId, pippedInfo.tabInfo.frameId))) { + pippedInfo = null + } + + if (!ignorePiP && pippedInfo) return pippedInfo + if (tabInfo) { + infos = infos.filter((info) => info.tabInfo.tabId === tabInfo.tabId) + } + + if (!infos.length) return pippedInfo || undefined + + const now = Date.now() + let peakIntersect = infos + .filter((v) => v.intersectionRatio != null) + .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]?.intersectionRatio + + let highest = pickHighest(infos, tabInfo, now, peakIntersect) + if (!highest) return undefined + + const isAlive = await checkContentScript(highest.info.tabInfo.tabId, highest.info.tabInfo.frameId) + if (isAlive) return highest.info + + const staleKey = `m:scope:${highest.info.tabInfo.tabId}:${highest.info.tabInfo.frameId}` + await chrome.storage.session.remove(staleKey) + + infos = infos.filter((info) => info.key !== highest.info.key) + if (!infos.length) return pippedInfo || undefined + + peakIntersect = infos + .filter((v) => v.intersectionRatio != null) + .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]?.intersectionRatio + highest = pickHighest(infos, tabInfo, Date.now(), peakIntersect) + + return highest?.info || pippedInfo || undefined } diff --git a/src/background/utils/processKeybinds.ts b/src/background/utils/processKeybinds.ts index 8a1379fc..45858dbd 100644 --- a/src/background/utils/processKeybinds.ts +++ b/src/background/utils/processKeybinds.ts @@ -953,16 +953,25 @@ function showIndicator(opts: IndicatorShowOpts, tabId: number, showAlt?: boolean let tempSpeedTimeoutId: number let mediaSped: FlatMediaInfo + +function sendTemporarySpeed(media: FlatMediaInfo, factor?: number) { + const payload = factor == null ? ({ type: "SET_TEMPORARY_SPEED" } as Messages) : ({ type: "SET_TEMPORARY_SPEED", factor } as Messages) + const frameIds = [media.tabInfo.frameId, 0].filter((v, i, arr) => v != null && arr.indexOf(v) === i) + + void (async () => { + for (const frameId of frameIds) { + if (!(await checkContentScript(media.tabInfo.tabId, frameId))) continue + + try { + await chrome.tabs.sendMessage(media.tabInfo.tabId, payload, { frameId }) + return + } catch {} + } + })() +} + function activateTemporarySpeed(media: FlatMediaInfo, factor: number, kbType?: KeybindType) { - console.log("SPEEDING") - chrome.tabs.sendMessage( - media.tabInfo.tabId, - { - type: "SET_TEMPORARY_SPEED", - factor, - } as Messages, - { frameId: media.tabInfo.frameId }, - ) + sendTemporarySpeed(media, factor) if (mediaSped && mediaSped.key !== media?.key) { releaseTemporarySpeed(mediaSped) } @@ -979,15 +988,8 @@ function activateTemporarySpeed(media: FlatMediaInfo, factor: number, kbType?: K } export function releaseTemporarySpeed(media?: FlatMediaInfo) { - console.log("RELEASING") media = media || mediaSped if (!media) return - chrome.tabs.sendMessage( - media.tabInfo.tabId, - { - type: "SET_TEMPORARY_SPEED", - } as Messages, - { frameId: media.tabInfo.frameId }, - ) + sendTemporarySpeed(media) mediaSped = null } diff --git a/src/utils/configUtils.ts b/src/utils/configUtils.ts index 6db1f995..41ff1460 100644 --- a/src/utils/configUtils.ts +++ b/src/utils/configUtils.ts @@ -20,6 +20,7 @@ import { import { clamp, isFirefox, round } from "./helper" import { compareHotkeys, Hotkey } from "./keys" import { fetchView, pushView } from "./state" +import { checkContentScript } from "./browserUtils" export function conformSpeed(speed: number, rounding = 2) { return clamp(0.07, 16, round(speed, rounding)) @@ -92,7 +93,19 @@ export function sendMediaEvent(event: MediaEvent, key: string, tabId: number, fr // realizeMediaEvent(key, event) } else { } - chrome.tabs.sendMessage(tabId, { type: "APPLY_MEDIA_EVENT", event, key }, frameId == null ? undefined : { frameId }) + + const frameIds = [frameId, 0].filter((v, i, arr) => v != null && arr.indexOf(v) === i) + + void (async () => { + for (const attemptFrameId of frameIds) { + if (!(await checkContentScript(tabId, attemptFrameId))) continue + + try { + await chrome.tabs.sendMessage(tabId, { type: "APPLY_MEDIA_EVENT", event, key }, { frameId: attemptFrameId }) + return + } catch {} + } + })() } export function sendMessageToConfigSync(msg: any, tabId: number, frameId?: number) {