From 719ff06caf2cc461fa3f7ff0c2288c28a9c069f7 Mon Sep 17 00:00:00 2001 From: Shiba <44804845+DeepDoge@users.noreply.github.com> Date: Sun, 9 Jan 2022 18:54:28 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=A3=20Refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/settings.ts | 3 +- src/common/yt.ts | 139 +++++++++++++++++--------------------- src/scripts/ytContent.tsx | 12 ++-- 3 files changed, 69 insertions(+), 85 deletions(-) diff --git a/src/common/settings.ts b/src/common/settings.ts index c5908c8..de9065a 100644 --- a/src/common/settings.ts +++ b/src/common/settings.ts @@ -6,8 +6,7 @@ export interface ExtensionSettings { export const DEFAULT_SETTINGS: ExtensionSettings = { redirect: true, targetPlatform: 'odysee', urlResolver: 'lbryInc' }; -export function getExtensionSettingsAsync(): Promise -{ +export function getExtensionSettingsAsync(): Promise { return new Promise(resolve => chrome.storage.local.get(o => resolve(o as any))); } diff --git a/src/common/yt.ts b/src/common/yt.ts index 6d255e2..a0277ea 100644 --- a/src/common/yt.ts +++ b/src/common/yt.ts @@ -17,6 +17,11 @@ interface YtExportedJsonSubscription { }; } +export interface YtIdResolverDescriptor { + id: string + type: 'channel' | 'video' +} + /** * @param file to load * @returns a promise with the file as a string @@ -33,10 +38,58 @@ export function getFileContent(file: File): Promise { }); } -export interface YtIdResolverDescriptor { - id: string - type: 'channel' | 'video' -} +export const ytService = (() => { + /** + * Extracts the channelID from a YT URL. + * + * Handles these two types of YT URLs: + * * /feeds/videos.xml?channel_id=* + * * /channel/* + */ + function getChannelId(channelURL: string) { + const match = channelURL.match(/channel\/([^\s?]*)/); + return match ? match[1] : new URL(channelURL).searchParams.get('channel_id'); + } + + /** + * Reads the array of YT channels from an OPML file + * + * @param opmlContents an opml file as as tring + * @returns the channel IDs + */ + function readOpml(opmlContents: string): string[] { + const opml = new DOMParser().parseFromString(opmlContents, 'application/xml'); + opmlContents = '' + return Array.from(opml.querySelectorAll('outline > outline')) + .map(outline => outline.getAttribute('xmlUrl')) + .filter((url): url is string => !!url) + .map(url => getChannelId(url)) + .filter((url): url is string => !!url); // we don't want it if it's empty + } + + /** + * Reads an array of YT channel IDs from the YT subscriptions JSON file + * + * @param jsonContents a JSON file as a string + * @returns the channel IDs + */ + function readJson(jsonContents: string): string[] { + const subscriptions: YtExportedJsonSubscription[] = JSON.parse(jsonContents); + jsonContents = '' + return subscriptions.map(sub => sub.snippet.resourceId.channelId); + } + + /** + * Reads an array of YT channel IDs from the YT subscriptions CSV file + * + * @param csvContent a CSV file as a string + * @returns the channel IDs + */ + function readCsv(csvContent: string): string[] { + const rows = csvContent.split('\n') + csvContent = '' + return rows.slice(1).map((row) => row.substring(0, row.indexOf(','))) + } const URLResolverCache = (() => { @@ -98,80 +151,12 @@ const URLResolverCache = (() => return { put, get } })() -export const ytService = { - /** - * Reads the array of YT channels from an OPML file - * - * @param opmlContents an opml file as as tring - * @returns the channel IDs - */ - readOpml(opmlContents: string): string[] { - const opml = new DOMParser().parseFromString(opmlContents, 'application/xml'); - opmlContents = '' - return Array.from(opml.querySelectorAll('outline > outline')) - .map(outline => outline.getAttribute('xmlUrl')) - .filter((url): url is string => !!url) - .map(url => ytService.getChannelId(url)) - .filter((url): url is string => !!url); // we don't want it if it's empty - }, - - /** - * Reads an array of YT channel IDs from the YT subscriptions JSON file - * - * @param jsonContents a JSON file as a string - * @returns the channel IDs - */ - readJson(jsonContents: string): string[] { - const subscriptions: YtExportedJsonSubscription[] = JSON.parse(jsonContents); - jsonContents = '' - return subscriptions.map(sub => sub.snippet.resourceId.channelId); - }, - - /** - * Reads an array of YT channel IDs from the YT subscriptions CSV file - * - * @param csvContent a CSV file as a string - * @returns the channel IDs - */ - readCsv(csvContent: string): string[] { - const rows = csvContent.split('\n') - csvContent = '' - return rows.slice(1).map((row) => row.substring(0, row.indexOf(','))) - }, - - /** - * Extracts the channelID from a YT URL. - * - * Handles these two types of YT URLs: - * * /feeds/videos.xml?channel_id=* - * * /channel/* - */ - getChannelId(channelURL: string) { - const match = channelURL.match(/channel\/([^\s?]*)/); - return match ? match[1] : new URL(channelURL).searchParams.get('channel_id'); - }, - - /** Extracts the video ID from a YT URL */ - getVideoId(url: string) { - const regex = /watch\/?\?.*v=([^\s&]*)/; - const match = url.match(regex); - return match ? match[1] : null; // match[1] is the videoId - }, - - getId(url: string): YtIdResolverDescriptor | null { - const videoId = ytService.getVideoId(url); - if (videoId) return { id: videoId, type: 'video' }; - const channelId = ytService.getChannelId(url); - if (channelId) return { id: channelId, type: 'channel' }; - return null; - }, - /** * @param descriptorsWithIndex YT resource IDs to check * @returns a promise with the list of channels that were found on lbry */ - async resolveById(descriptors: YtIdResolverDescriptor[], progressCallback?: (progress: number) => void): Promise<(string | null)[]> { + async function resolveById(descriptors: YtIdResolverDescriptor[], progressCallback?: (progress: number) => void): Promise<(string | null)[]> { const descriptorsWithIndex: (YtIdResolverDescriptor & { index: number })[] = descriptors.map((descriptor, index) => ({...descriptor, index})) descriptors = null as any const results: (string | null)[] = [] @@ -196,7 +181,7 @@ export const ytService = { { const descriptorsGroupedByType: Record = groupBy(descriptorChunk, (descriptor) => descriptor.type) as any; - const { urlResolver: urlResolverSettingName } = await getExtensionSettingsAsync('urlResolver') + const { urlResolver: urlResolverSettingName } = await getExtensionSettingsAsync() const urlResolverSetting = ytUrlResolversSettings[urlResolverSettingName] const url = new URL(`https://${urlResolverSetting.hostname}`); @@ -288,5 +273,7 @@ export const ytService = { })); return results - } -} + } + + return { readCsv, readJson, readOpml, resolveById } +})() diff --git a/src/scripts/ytContent.tsx b/src/scripts/ytContent.tsx index f1fd9b1..6fb60c3 100644 --- a/src/scripts/ytContent.tsx +++ b/src/scripts/ytContent.tsx @@ -155,12 +155,7 @@ function redirectTo({ targetPlatform, lbryPathname }: UpdateContext): void { location.replace(url.toString()); } - - -findButtonMountPoint().then(() => updateButton(ctxCache)) -findVideoElement().then(() => updateButton(ctxCache)) - -async function onPageLoad() +window.addEventListener('load', async () => { // Listen History.pushState { @@ -193,4 +188,7 @@ async function onPageLoad() } await updateByURL(new URL(location.href)) -} \ No newline at end of file + + findButtonMountPoint().then(() => updateButton(ctxCache)) + findVideoElement().then(() => updateButton(ctxCache)) +}) \ No newline at end of file