From 48f88da6aa7c02f4a1266b0946cf9bca7e6aa241 Mon Sep 17 00:00:00 2001 From: Kevin Raoofi Date: Tue, 13 Oct 2020 03:31:41 -0400 Subject: [PATCH] Common settings module * settings module as single source of truth and provides utilities, defaults, constants, and typing * runtimeOnStartup and storageOnChanged were merged into storageSetup * storageSetup reworked to use settings for seamless additions * tabOnUpdated and YTtoLBRY updated to use settings for URL prefixes --- src/common/settings.ts | 15 ++++++ src/manifest.json | 3 +- src/scripts/runtimeOnStartup.js | 12 ----- src/scripts/storageOnChanged.js | 7 --- src/scripts/storageSetup.ts | 28 +++++++++++ src/scripts/tabOnUpdated.js | 83 --------------------------------- src/scripts/tabOnUpdated.ts | 83 +++++++++++++++++++++++++++++++++ src/tools/YTtoLBRY.js | 8 ++-- 8 files changed, 132 insertions(+), 107 deletions(-) create mode 100644 src/common/settings.ts delete mode 100644 src/scripts/runtimeOnStartup.js delete mode 100644 src/scripts/storageOnChanged.js create mode 100644 src/scripts/storageSetup.ts delete mode 100644 src/scripts/tabOnUpdated.js create mode 100644 src/scripts/tabOnUpdated.ts diff --git a/src/common/settings.ts b/src/common/settings.ts new file mode 100644 index 0000000..fb0ff86 --- /dev/null +++ b/src/common/settings.ts @@ -0,0 +1,15 @@ +export interface LbrySettings { + enabled: boolean + redirect: keyof typeof redirectDomains +} + +export const DEFAULT_SETTINGS: LbrySettings = { enabled: true, redirect: 'lbry.tv' }; + +export const redirectDomains = { + 'lbry.tv': { prefix: 'https://lbry.tv/', display: 'lbry.tv' }, + app: { prefix: 'lbry://', display: 'App' }, +}; + +export function getSettingsAsync>(...keys: K): Promise> { + return new Promise(resolve => chrome.storage.local.get(keys, o => resolve(o as any))); +} diff --git a/src/manifest.json b/src/manifest.json index 734dcd4..520644b 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -13,8 +13,7 @@ ], "background": { "scripts": [ - "scripts/runtimeOnStartup.js", - "scripts/storageOnChanged.js", + "scripts/storageSetup.js", "scripts/tabOnUpdated.js" ], "persistent": false diff --git a/src/scripts/runtimeOnStartup.js b/src/scripts/runtimeOnStartup.js deleted file mode 100644 index 9655e3b..0000000 --- a/src/scripts/runtimeOnStartup.js +++ /dev/null @@ -1,12 +0,0 @@ -const func = () => { - chrome.storage.local.get(['enabled', 'redirect'], ({ enabled, redirect }) => { - if (enabled === null || enabled === undefined) enabled = true; - if (!redirect) redirect = 'lbry.tv'; - chrome.storage.local.set({ enabled, redirect }); - // have to set this manually as the trigger doesn't work for `onInstalled` - chrome.browserAction.setBadgeText({ text: enabled ? 'ON' : 'OFF' }); - }); -}; - -chrome.runtime.onStartup.addListener(func); -chrome.runtime.onInstalled.addListener(func); diff --git a/src/scripts/storageOnChanged.js b/src/scripts/storageOnChanged.js deleted file mode 100644 index 2a1c909..0000000 --- a/src/scripts/storageOnChanged.js +++ /dev/null @@ -1,7 +0,0 @@ -chrome.storage.onChanged.addListener((changes, areaName) => { - if (areaName !== "local") return; - if (!changes.enabled) return; - const { newValue } = changes.enabled; - console.log(newValue); - chrome.browserAction.setBadgeText({ text: newValue ? "ON" : "OFF" }); -}); diff --git a/src/scripts/storageSetup.ts b/src/scripts/storageSetup.ts new file mode 100644 index 0000000..d637431 --- /dev/null +++ b/src/scripts/storageSetup.ts @@ -0,0 +1,28 @@ +import { DEFAULT_SETTINGS, LbrySettings, getSettingsAsync } from '../common/settings'; + +/** Reset settings to default value and update the browser badge text */ +async function initSettings() { + const settings = await getSettingsAsync(...Object.keys(DEFAULT_SETTINGS) as Array); + + // get all the values that aren't set and use them as a change set + const invalidEntries = (Object.entries(DEFAULT_SETTINGS) as Array<[keyof LbrySettings, LbrySettings[keyof LbrySettings]]>) + .filter(([k]) => settings[k] === null || settings[k] === undefined); + + // fix our local var and set it in storage for later + if (invalidEntries.length > 0) { + const changeSet = Object.fromEntries(invalidEntries); + Object.assign(settings, changeSet); + chrome.storage.local.set(changeSet); + } + + chrome.browserAction.setBadgeText({ text: settings.enabled ? 'ON' : 'OFF' }); +} + +chrome.storage.onChanged.addListener((changes, areaName) => { + if (areaName !== 'local' || !changes.enabled) return; + chrome.browserAction.setBadgeText({ text: changes.enabled.newValue ? 'ON' : 'OFF' }); +}); + + +chrome.runtime.onStartup.addListener(initSettings); +chrome.runtime.onInstalled.addListener(initSettings); diff --git a/src/scripts/tabOnUpdated.js b/src/scripts/tabOnUpdated.js deleted file mode 100644 index ab69b98..0000000 --- a/src/scripts/tabOnUpdated.js +++ /dev/null @@ -1,83 +0,0 @@ -chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - chrome.storage.local.get(async ({ enabled }) => { - if (!enabled) return; - if (!changeInfo.url) return; - if (tab.url.match(/\b(https:\/\/lbry.tv|lbry:\/\/)/g)) { - chrome.storage.local.get('redirect', ({redirect}) => { - var redirectTo; - if (redirect === "app") { - let isChannel = tab.url.match(/^(https|http):\/\/lbry.tv\/@([^?:$#@;/"<>%{}|^~[\]`])+?:[a-z0-9]{1,40}($|(?=\?))/g); - let isClaim = tab.url.match(/^(https|http):\/\/lbry.tv\/@([^?:$#@;/"<>%{}|^~[\]`])+?:[a-z0-9]{1,40}\/([^?:$#@;/"<>%{}|^~[\]`])+?:[a-z0-9]{1,40}($|(?=\?))/g); - - if (isChannel) { - redirectTo = `lbry://${tab.url.match(/@([^$#@;/"<>%{}|^~[\]`])+?(?=[#:])/g)[0]}#${tab.url.match(/#([a-z0-9]{40})|:[a-z0-9]($|(?=\?))/g)[0].substr(1)}`; - } else if (isClaim) { - redirectTo = `lbry://${tab.url.match(/@([^$#@;/"<>%{}|^~[\]`])+?(?=[#:])/g)}#${tab.url.match(/(#([a-z0-9]{40})|:[a-z0-9])(?=\/([^$#@;/"<>%{}|^~[\]`])+?(#([a-z0-9]{40})|:[a-z0-9])($|(?=\?)))/g)[0].substr(1)}${tab.url.match(/\/([^$#@;/"<>%{}|^~[\]`])+?(?=[#:])/g)[0]}#${tab.url.match(/(#([a-z0-9]{40})|:[a-z0-9])($|(?=\?))/g)[0].substr(1)}`; - } - } - - if (redirectTo) { - chrome.tabs.update(tabId, { url: redirectTo + "?src=watch-on-lbry" }); - if (redirect === "app") { - alert("Opened link in LBRY App!"); // Better for UX since sometimes LBRY App doesn't take focus, if that is fixed, this can be removed - - // Close tab if it lacks history and go back if it does - chrome.tabs.executeScript(tabId, { - code: ` - if (window.history.length === 1) { - window.close(); - } else { - window.history.back(); - }` - }); - } - } - }); - return; - } - const { id, type } = getId(tab.url); - if (!id) return; - - const url = `https://api.lbry.com/yt/resolve?${type}_ids=${id}`; - const response = await fetch(url, { headers: { 'Content-Type': 'application/json' } }); - const json = await response.json(); - console.log(json); - const title = json.data[`${type}s`][id]; - if (!title) return; - console.log(title); - - chrome.storage.local.get('redirect', ({ redirect }) => { - console.log(redirect); - let newUrl; - if (redirect === "lbry.tv") { - newUrl = `https://lbry.tv/${title.replace(/^lbry:\/\//, "").replace(/#/g, ":")}?src=watch-on-lbry`; - } else if (redirect === "app") { - newUrl = `lbry://${title.replace(/^lbry:\/\//, "")}`; - } - chrome.tabs.update(tabId, { url: newUrl }); - }); - }); -}); - -function getId(url) { - const videoId = getVideoId(url); - if (videoId) return { id: videoId, type: "video" }; - const channelId = getChannelId(url); - if (channelId) return { id: channelId, type: "channel" }; - return {}; // Equivalent of returning null -} - -function getVideoId(url) { - const regex = /watch\/?\?.*v=([^\s&]*)/; - const match = url.match(regex); - return match ? match[1] : null; // match[1] is the videoId -} - -function getChannelId(url) { - const regex = /channel\/([^\s?]*)/; - const match = url.match(regex); - return match ? match[1] : null; // match[1] is the channelId -} - -function getNewUrl(title) { -} diff --git a/src/scripts/tabOnUpdated.ts b/src/scripts/tabOnUpdated.ts new file mode 100644 index 0000000..4e02b68 --- /dev/null +++ b/src/scripts/tabOnUpdated.ts @@ -0,0 +1,83 @@ +import { getSettingsAsync, redirectDomains } from "../common/settings"; + +chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, { url: tabUrl }) => { + const { enabled, redirect } = await getSettingsAsync('enabled', 'redirect'); + const urlPrefix = redirectDomains[redirect].prefix; + + if (!enabled || !changeInfo.url || !tabUrl) return; + if (tabUrl.match(/\b(https:\/\/lbry.tv|lbry:\/\/)/g)) { + + var redirectTo; + if (redirect === "app") { + let isChannel = tabUrl.match(/^(https|http):\/\/lbry.tv\/@([^?:$#@;/"<>%{}|^~[\]`])+?:[a-z0-9]{1,40}($|(?=\?))/g); + let isClaim = tabUrl.match(/^(https|http):\/\/lbry.tv\/@([^?:$#@;/"<>%{}|^~[\]`])+?:[a-z0-9]{1,40}\/([^?:$#@;/"<>%{}|^~[\]`])+?:[a-z0-9]{1,40}($|(?=\?))/g); + + if (isChannel) { + redirectTo = `lbry://${tabUrl.match(/@([^$#@;/"<>%{}|^~[\]`])+?(?=[#:])/g)![0]}#${tabUrl.match(/#([a-z0-9]{40})|:[a-z0-9]($|(?=\?))/g)![0].substr(1)}`; + } else if (isClaim) { + redirectTo = `lbry://${tabUrl.match(/@([^$#@;/"<>%{}|^~[\]`])+?(?=[#:])/g)}#${tabUrl.match(/(#([a-z0-9]{40})|:[a-z0-9])(?=\/([^$#@;/"<>%{}|^~[\]`])+?(#([a-z0-9]{40})|:[a-z0-9])($|(?=\?)))/g)![0].substr(1)}${tabUrl.match(/\/([^$#@;/"<>%{}|^~[\]`])+?(?=[#:])/g)![0]}#${tabUrl.match(/(#([a-z0-9]{40})|:[a-z0-9])($|(?=\?))/g)![0].substr(1)}`; + } + } + + if (redirectTo) { + chrome.tabs.update(tabId, { url: redirectTo + "?src=watch-on-lbry" }); + if (redirect === "app") { + alert("Opened link in LBRY App!"); // Better for UX since sometimes LBRY App doesn't take focus, if that is fixed, this can be removed + + // Close tab if it lacks history and go back if it does + chrome.tabs.executeScript(tabId, { + code: ` + if (window.history.length === 1) { + window.close(); + } else { + window.history.back(); + }` + }); + } + } + return; + } + const { id, type } = getId(tabUrl); + if (!id) return; + + const url = `https://api.lbry.com/yt/resolve?${type}_ids=${id}`; + const response = await fetch(url, { headers: { 'Content-Type': 'application/json' } }); + const json = await response.json(); + console.log(json); + const title = json.data[`${type}s`][id]; + if (!title) return; + console.log(title); + + + console.log(redirect); + let newUrl; + if (redirect === "lbry.tv") { + newUrl = `${urlPrefix}${title.replace(/^lbry:\/\//, "").replace(/#/g, ":")}?src=watch-on-lbry`; + } else if (redirect === "app") { + newUrl = `lbry://${title.replace(/^lbry:\/\//, "")}`; + } + chrome.tabs.update(tabId, { url: newUrl }); +}); + +function getId(url) { + const videoId = getVideoId(url); + if (videoId) return { id: videoId, type: "video" }; + const channelId = getChannelId(url); + if (channelId) return { id: channelId, type: "channel" }; + return {}; // Equivalent of returning null +} + +function getVideoId(url) { + const regex = /watch\/?\?.*v=([^\s&]*)/; + const match = url.match(regex); + return match ? match[1] : null; // match[1] is the videoId +} + +function getChannelId(url) { + const regex = /channel\/([^\s?]*)/; + const match = url.match(regex); + return match ? match[1] : null; // match[1] is the channelId +} + +function getNewUrl(title) { +} diff --git a/src/tools/YTtoLBRY.js b/src/tools/YTtoLBRY.js index 72720ae..ea4c8f3 100644 --- a/src/tools/YTtoLBRY.js +++ b/src/tools/YTtoLBRY.js @@ -1,3 +1,5 @@ +import { redirectDomains } from '../common/settings' + console.log("YouTube To LBRY finder!"); var ytChannelsString = ""; var lbryChannelsString = ""; @@ -48,7 +50,7 @@ function lbryAPIrequest() { while (lbryChannelList.lastElementChild) { lbryChannelList.removeChild(lbryChannelList.lastElementChild); } - + chrome.storage.local.get('redirect', redirect => { validateChannels(toCheck, redirect.redirect, []); }); @@ -60,7 +62,7 @@ function validateChannels(channels, redirect, validatedChannels) { for (let i = 0; i < channels.length && i < requestSize; i++) { channelsString += `${channelsString.length > 0 ? ',' : ''}${channels[i]}` } - request = new XMLHttpRequest(); + request = new XMLHttpRequest(); request.open("GET", `https://api.lbry.com/yt/resolve?channel_ids={${channelsString}}`); request.send(); request.onload = () => { @@ -69,7 +71,7 @@ function validateChannels(channels, redirect, validatedChannels) { Object.keys(testChannels).map((testChannelKey) => { let testChannel = testChannels[testChannelKey]; if (testChannel != null) { - let link = `${redirect === "lbry.tv" ? "https://lbry.tv/" : "lbry://"}${testChannel}`; + let link = redirectDomains[redirect].prefix + testChannel; validatedChannels.push(link); let li = document.createElement('li'); let a = document.createElement('a');