diff --git a/src/scripts/tabOnUpdated.ts b/src/scripts/tabOnUpdated.ts index 4570d1a..e73fe73 100644 --- a/src/scripts/tabOnUpdated.ts +++ b/src/scripts/tabOnUpdated.ts @@ -1,5 +1,36 @@ -import { appRedirectUrl } from '../common/lbry-url'; -import { getSettingsAsync } from '../common/settings'; +import { appRedirectUrl, parseProtocolUrl } from '../common/lbry-url'; +import { getSettingsAsync, LbrySettings } from '../common/settings'; +import { YTDescriptor, ytService } from '../common/yt'; +export interface UpdateContext { + descriptor: YTDescriptor + /** LBRY URL fragment */ + url: string + enabled: boolean + redirect: LbrySettings['redirect'] +} + +async function resolveYT(descriptor: YTDescriptor) { + const lbryProtocolUrl: string | null = await ytService.resolveById(descriptor).then(a => a[0]); + const segments = parseProtocolUrl(lbryProtocolUrl || '', { encode: true }); + if (segments.length === 0) return; + return segments.join('/'); +} + +const urlCache: Record = {}; + +async function ctxFromURL(url: string): Promise { + if (!url || !(url.startsWith('https://www.youtube.com/watch?v=') || url.startsWith('https://www.youtube.com/channel/'))) return; + url = new URL(url).href; + const { enabled, redirect } = await getSettingsAsync('enabled', 'redirect'); + const descriptor = ytService.getId(url); + if (!descriptor) return; // couldn't get the ID, so we're done + + const res = url in urlCache ? urlCache[url] : await resolveYT(descriptor); + urlCache[url] = res; + if (!res) return; // couldn't find it on lbry, so we're done + + return { descriptor, url: res, enabled, redirect }; +} // handles lbry.tv -> lbry app redirect chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, { url: tabUrl }) => { @@ -21,9 +52,16 @@ chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, { url: tabUrl }) => }); }); +chrome.runtime.onMessage.addListener(({ url }: { url: string }, sender, sendResponse) => { + ctxFromURL(url).then(ctx => { + sendResponse(ctx); + }) + return true; +}) + // relay youtube link changes to the content script chrome.tabs.onUpdated.addListener((tabId, changeInfo, { url }) => { - if (!changeInfo.url || !url || - !(url.startsWith('https://www.youtube.com/watch?v=') || url.startsWith('https://www.youtube.com/channel/'))) return; - chrome.tabs.sendMessage(tabId, { url }); + if (!changeInfo.url || !url || !(url.startsWith('https://www.youtube.com/watch?v=') || url.startsWith('https://www.youtube.com/channel/'))) return; + + ctxFromURL(url).then(ctx => chrome.tabs.sendMessage(tabId, ctx)); }); diff --git a/src/scripts/ytContent.tsx b/src/scripts/ytContent.tsx index 2496c03..522fea3 100644 --- a/src/scripts/ytContent.tsx +++ b/src/scripts/ytContent.tsx @@ -1,8 +1,9 @@ import { h, JSX, render } from 'preact'; import { parseProtocolUrl } from '../common/lbry-url'; -import { getSettingsAsync, LbrySettings, redirectDomains } from '../common/settings'; +import { LbrySettings, redirectDomains } from '../common/settings'; import { YTDescriptor, ytService } from '../common/yt'; +import { UpdateContext } from './tabOnUpdated'; interface UpdaterOptions { /** invoked if a redirect should be performed */ @@ -11,14 +12,6 @@ interface UpdaterOptions { onURL?(ctx: UpdateContext): void } -interface UpdateContext { - descriptor: YTDescriptor - /** LBRY URL fragment */ - url: string - enabled: boolean - redirect: LbrySettings['redirect'] -} - interface ButtonSettings { text: string icon: string @@ -49,16 +42,9 @@ async function resolveYT(descriptor: YTDescriptor) { } /** Compute the URL and determine whether or not a redirect should be performed. Delegates the redirect to callbacks. */ -async function handleURLChange(url: URL | Location, { onRedirect, onURL }: UpdaterOptions): Promise { - const { enabled, redirect } = await getSettingsAsync('enabled', 'redirect'); - const descriptor = ytService.getId(url.href); - if (!descriptor) return; // couldn't get the ID, so we're done - const res = await resolveYT(descriptor); - if (!res) return; // couldn't find it on lbry, so we're done - - const ctx = { descriptor, url: res, enabled, redirect }; +async function handleURLChange(ctx: UpdateContext, { onRedirect, onURL }: UpdaterOptions): Promise { if (onURL) onURL(ctx); - if (enabled && onRedirect) onRedirect(ctx); + if (ctx.enabled && onRedirect) onRedirect(ctx); } /** Returns a mount point for the button */ @@ -105,7 +91,7 @@ function WatchOnLbryButton({ redirect = 'app', url }: { redirect?: LbrySettings[ const mountPointPromise = findMountPoint(); -const handle = (url: URL | Location) => handleURLChange(url, { +const handle = (ctx: UpdateContext) => handleURLChange(ctx, { async onURL({ descriptor: { type }, url, redirect }) { const mountPoint = await mountPointPromise; if (type !== 'video' || !mountPoint) return; @@ -119,19 +105,19 @@ const handle = (url: URL | Location) => handleURLChange(url, { }); // handle the location on load of the page -handle(location); +chrome.runtime.sendMessage({ url: location.href }, async (ctx: UpdateContext) => handle(ctx)); /* * Gets messages from background script which relays tab update events. This is because there's no sensible way to detect * history.pushState changes from a content script */ -chrome.runtime.onMessage.addListener(async (req: { url: string }) => { +chrome.runtime.onMessage.addListener(async (ctx: UpdateContext) => { mountPointPromise.then(mountPoint => mountPoint && render(, mountPoint)) - if (!req.url) return; - handle(new URL(req.url)); + if (!ctx.url) return; + handle(ctx); }); chrome.storage.onChanged.addListener((changes, areaName) => { if (areaName !== 'local' || !changes.redirect) return; - handle(new URL(location.href)); + chrome.runtime.sendMessage({ url: location.href }, async (ctx: UpdateContext) => handle(ctx)); });