mirror of
https://github.com/LBRYFoundation/Watch-on-LBRY.git
synced 2025-08-23 17:47:26 +00:00
🍣 Refactor
This commit is contained in:
parent
4cdcc4c9a4
commit
719ff06caf
3 changed files with 69 additions and 85 deletions
|
@ -6,8 +6,7 @@ export interface ExtensionSettings {
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: ExtensionSettings = { redirect: true, targetPlatform: 'odysee', urlResolver: 'lbryInc' };
|
export const DEFAULT_SETTINGS: ExtensionSettings = { redirect: true, targetPlatform: 'odysee', urlResolver: 'lbryInc' };
|
||||||
|
|
||||||
export function getExtensionSettingsAsync(): Promise<ExtensionSettings>
|
export function getExtensionSettingsAsync(): Promise<ExtensionSettings> {
|
||||||
{
|
|
||||||
return new Promise(resolve => chrome.storage.local.get(o => resolve(o as any)));
|
return new Promise(resolve => chrome.storage.local.get(o => resolve(o as any)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
135
src/common/yt.ts
135
src/common/yt.ts
|
@ -17,6 +17,11 @@ interface YtExportedJsonSubscription {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface YtIdResolverDescriptor {
|
||||||
|
id: string
|
||||||
|
type: 'channel' | 'video'
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param file to load
|
* @param file to load
|
||||||
* @returns a promise with the file as a string
|
* @returns a promise with the file as a string
|
||||||
|
@ -33,9 +38,57 @@ export function getFileContent(file: File): Promise<string> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface YtIdResolverDescriptor {
|
export const ytService = (() => {
|
||||||
id: string
|
/**
|
||||||
type: 'channel' | 'video'
|
* 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 = (() =>
|
const URLResolverCache = (() =>
|
||||||
|
@ -98,80 +151,12 @@ const URLResolverCache = (() =>
|
||||||
return { put, get }
|
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
|
* @param descriptorsWithIndex YT resource IDs to check
|
||||||
* @returns a promise with the list of channels that were found on lbry
|
* @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}))
|
const descriptorsWithIndex: (YtIdResolverDescriptor & { index: number })[] = descriptors.map((descriptor, index) => ({...descriptor, index}))
|
||||||
descriptors = null as any
|
descriptors = null as any
|
||||||
const results: (string | null)[] = []
|
const results: (string | null)[] = []
|
||||||
|
@ -196,7 +181,7 @@ export const ytService = {
|
||||||
{
|
{
|
||||||
const descriptorsGroupedByType: Record<YtIdResolverDescriptor['type'], typeof descriptorsWithIndex | null> = groupBy(descriptorChunk, (descriptor) => descriptor.type) as any;
|
const descriptorsGroupedByType: Record<YtIdResolverDescriptor['type'], typeof descriptorsWithIndex | null> = groupBy(descriptorChunk, (descriptor) => descriptor.type) as any;
|
||||||
|
|
||||||
const { urlResolver: urlResolverSettingName } = await getExtensionSettingsAsync('urlResolver')
|
const { urlResolver: urlResolverSettingName } = await getExtensionSettingsAsync()
|
||||||
const urlResolverSetting = ytUrlResolversSettings[urlResolverSettingName]
|
const urlResolverSetting = ytUrlResolversSettings[urlResolverSettingName]
|
||||||
|
|
||||||
const url = new URL(`https://${urlResolverSetting.hostname}`);
|
const url = new URL(`https://${urlResolverSetting.hostname}`);
|
||||||
|
@ -289,4 +274,6 @@ export const ytService = {
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return { readCsv, readJson, readOpml, resolveById }
|
||||||
|
})()
|
||||||
|
|
|
@ -155,12 +155,7 @@ function redirectTo({ targetPlatform, lbryPathname }: UpdateContext): void {
|
||||||
location.replace(url.toString());
|
location.replace(url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', async () =>
|
||||||
|
|
||||||
findButtonMountPoint().then(() => updateButton(ctxCache))
|
|
||||||
findVideoElement().then(() => updateButton(ctxCache))
|
|
||||||
|
|
||||||
async function onPageLoad()
|
|
||||||
{
|
{
|
||||||
// Listen History.pushState
|
// Listen History.pushState
|
||||||
{
|
{
|
||||||
|
@ -193,4 +188,7 @@ async function onPageLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateByURL(new URL(location.href))
|
await updateByURL(new URL(location.href))
|
||||||
}
|
|
||||||
|
findButtonMountPoint().then(() => updateButton(ctxCache))
|
||||||
|
findVideoElement().then(() => updateButton(ctxCache))
|
||||||
|
})
|
Loading…
Add table
Reference in a new issue