diff --git a/src/scripts/ytContent.tsx b/src/scripts/ytContent.tsx index 12cdb2a..be7631c 100644 --- a/src/scripts/ytContent.tsx +++ b/src/scripts/ytContent.tsx @@ -18,7 +18,7 @@ interface Target time: number | null } -export function WatchOnLbryButton({ targetPlatform, lbryPathname, time }: WatchOnLbryButtonParameters) +function WatchOnLbryButton({ targetPlatform, lbryPathname, time }: WatchOnLbryButtonParameters) { if (!lbryPathname || !targetPlatform) return null @@ -61,7 +61,8 @@ async function redirectTo({ lbryPathname, platfrom, time }: Target) if (time) url.searchParams.set('t', time.toFixed(0)) - findVideoElement().then((videoElement) => { + findVideoElement().then((videoElement) => + { videoElement.addEventListener('play', () => videoElement.pause(), { once: true }) videoElement.pause() }) @@ -70,7 +71,7 @@ async function redirectTo({ lbryPathname, platfrom, time }: Target) { if (document.hidden) await new Promise((resolve) => document.addEventListener('visibilitychange', resolve, { once: true })) open(url, '_blank') - if (window.history.length === 1) window.close(); + if (window.history.length === 1) window.close() else window.history.back() } location.replace(url.toString()) @@ -79,15 +80,16 @@ async function redirectTo({ lbryPathname, platfrom, time }: Target) /** Returns a mount point for the button */ async function findButtonMountPoint(): Promise { + const id = 'watch-on-lbry-button-container' let mountBefore: HTMLDivElement | null = null const sourcePlatform = getSourcePlatfromSettingsFromHostname(new URL(location.href).hostname) if (!sourcePlatform) throw new Error(`Unknown source of: ${location.href}`) - const exits: HTMLDivElement | null = document.querySelector('#watch-on-yt-button-container') - if (exits) return exits; + const exits: HTMLDivElement | null = document.querySelector(`#${id}`) + if (exits) return exits while (!(mountBefore = document.querySelector(sourcePlatform.htmlQueries.mountButtonBefore))) await sleep(200) - + const div = document.createElement('div') - div.id = 'watch-on-yt-button-container' + div.id = id div.style.display = 'flex' div.style.alignItems = 'center' mountBefore.parentElement?.insertBefore(div, mountBefore) @@ -100,25 +102,28 @@ async function findVideoElement() const sourcePlatform = getSourcePlatfromSettingsFromHostname(new URL(location.href).hostname) if (!sourcePlatform) throw new Error(`Unknown source of: ${location.href}`) let videoElement: HTMLVideoElement | null = null - while (!(videoElement = document.querySelector(sourcePlatform.htmlQueries.videoPlayer))) await sleep(200) - return videoElement } -window.addEventListener('load', async () => +// We should get this from background, so the caching works and we don't get errors in the future if yt decides to impliment CORS +async function requestLbryPathname(videoId: string) +{ + return await new Promise((resolve) => chrome.runtime.sendMessage({ videoId }, resolve)) +} + +// Start +(async () => { const settings = await getExtensionSettingsAsync() - let target: Target | null = null - - const [buttonMountPoint, videoElement] = await Promise.all([findButtonMountPoint(), findVideoElement()]) + let updater: (() => Promise) // Listen Settings Change chrome.storage.onChanged.addListener(async (changes, areaName) => { if (areaName !== 'local') return Object.assign(settings, Object.fromEntries(Object.entries(changes).map(([key, change]) => [key, change.newValue]))) - await updateByURL(new URL(location.href)) + if (changes.redirect) await onModeChange() }) /* @@ -126,41 +131,55 @@ window.addEventListener('load', async () => * history.pushState changes from a content script */ // Listen URL Change - chrome.runtime.onMessage.addListener(onUrlChange) + chrome.runtime.onMessage.addListener(() => updater()) - // We should get this from background, so the caching works and we don't get errors in the future if yt decides to impliment CORS - async function requestLbryPathname(videoId: string) + async function getTargetByURL(url: URL) { - return await new Promise((resolve) => chrome.runtime.sendMessage({ videoId }, resolve)) - } - - function getVideoTime(url: URL) - { - return settings.redirect ? - (url.searchParams.has('t') ? parseYouTubeURLTimeString(url.searchParams.get('t')!) : null) : - (videoElement.currentTime > 3 && videoElement.currentTime < videoElement.duration - 1 ? videoElement.currentTime : null) - } - - async function updateByURL(url: URL) - { - if (url.pathname !== '/watch') return + if (url.pathname !== '/watch') return null const videoId = url.searchParams.get('v') const lbryPathname = videoId && await requestLbryPathname(videoId) - if (lbryPathname) target = { lbryPathname, platfrom: targetPlatformSettings[settings.targetPlatform], time: getVideoTime(url) } - else target = null + const target: Target | null = lbryPathname ? { lbryPathname, platfrom: targetPlatformSettings[settings.targetPlatform], time: null } : null - if (settings.redirect) target && redirectTo(target) - else updateButton(buttonMountPoint, target) + return target } - videoElement.addEventListener('timeupdate', - () => target && updateButton(buttonMountPoint, Object.assign(target, { time: getVideoTime(new URL(location.href)) }))) - - async function onUrlChange() + let removeVideoTimeUpdateListener: (() => void) | null = null + async function onModeChange() { - await updateByURL(new URL(location.href)) + let target: Target | null = null + if (settings.redirect) + updater = async () => + { + const url = new URL(location.href) + target = await getTargetByURL(url) + if (!target) return + target.time = url.searchParams.has('t') ? parseYouTubeURLTimeString(url.searchParams.get('t')!) : null + redirectTo(target) + } + else + { + const mountPoint = await findButtonMountPoint() + const videoElement = await findVideoElement() + + const getTime = () => videoElement.currentTime > 3 && videoElement.currentTime < videoElement.duration - 1 ? videoElement.currentTime : null + + const onTimeUpdate = () => target && updateButton(mountPoint, Object.assign(target, { time: getTime() })) + removeVideoTimeUpdateListener?.call(null) + videoElement.addEventListener('timeupdate', onTimeUpdate) + removeVideoTimeUpdateListener = () => videoElement.removeEventListener('timeupdate', onTimeUpdate) + + updater = async () => + { + const url = new URL(location.href) + target = await getTargetByURL(url) + if (target) target.time = getTime() + updateButton(mountPoint, target) + } + } + + await updater() } - await updateByURL(new URL(location.href)) -}) \ No newline at end of file + await onModeChange() +})() \ No newline at end of file