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
This commit is contained in:
Kevin Raoofi 2020-10-13 03:31:41 -04:00
parent 468c04ba62
commit 48f88da6aa
8 changed files with 132 additions and 107 deletions

15
src/common/settings.ts Normal file
View file

@ -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<K extends Array<keyof LbrySettings>>(...keys: K): Promise<Pick<LbrySettings, K[number]>> {
return new Promise(resolve => chrome.storage.local.get(keys, o => resolve(o as any)));
}

View file

@ -13,8 +13,7 @@
],
"background": {
"scripts": [
"scripts/runtimeOnStartup.js",
"scripts/storageOnChanged.js",
"scripts/storageSetup.js",
"scripts/tabOnUpdated.js"
],
"persistent": false

View file

@ -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);

View file

@ -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" });
});

View file

@ -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<keyof LbrySettings>);
// 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);

View file

@ -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) {
}

View file

@ -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) {
}

View file

@ -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');