Added support for any invidious instance.

This commit is contained in:
Ajay Ramachandran
2020-01-09 21:23:25 -05:00
parent 25436d9620
commit a20fa9871e
7 changed files with 189 additions and 141 deletions

3
SB.js
View File

@@ -159,7 +159,8 @@ SB.defaults = {
"hideInfoButtonPlayerControls": false, "hideInfoButtonPlayerControls": false,
"hideDeleteButtonPlayerControls": false, "hideDeleteButtonPlayerControls": false,
"hideDiscordLaunches": 0, "hideDiscordLaunches": 0,
"hideDiscordLink": false "hideDiscordLink": false,
"invidiousInstances": ["invidio.us", "invidiou.sh", "invidious.snopyta.org"]
} }
// Reset config // Reset config

View File

@@ -370,10 +370,7 @@
"message": "Reset Invidious Instance List" "message": "Reset Invidious Instance List"
}, },
"resetInvidiousInstanceAlert": { "resetInvidiousInstanceAlert": {
"message": "You are about to reset the Invidious instance list?" "message": "You are about to reset the Invidious instance list"
},
"noInstancesAdded": {
"message": "No extra instances added yet"
}, },
"currentInstances": { "currentInstances": {
"message": "Current Instances:" "message": "Current Instances:"

View File

@@ -44,6 +44,9 @@ chrome.runtime.onMessage.addListener(async function (request, sender, callback)
iconUrl: "./icons/LogoSponsorBlocker256px.png" iconUrl: "./icons/LogoSponsorBlocker256px.png"
}); });
case "registerContentScript": case "registerContentScript":
let oldRegistration = contentScriptRegistrations[request.id];
if (oldRegistration) oldRegistration.unregister();
browser.contentScripts.register({ browser.contentScripts.register({
allFrames: request.allFrames, allFrames: request.allFrames,
js: request.js, js: request.js,

View File

@@ -75,78 +75,78 @@ var popupInitialised = false;
chrome.runtime.onMessage.addListener(messageListener); chrome.runtime.onMessage.addListener(messageListener);
function messageListener(request, sender, sendResponse) { function messageListener(request, sender, sendResponse) {
//messages from popup script //messages from popup script
switch(request.message){ switch(request.message){
case "update": case "update":
videoIDChange(getYouTubeVideoID(document.URL)); videoIDChange(getYouTubeVideoID(document.URL));
break; break;
case "sponsorStart": case "sponsorStart":
sponsorMessageStarted(sendResponse); sponsorMessageStarted(sendResponse);
break; break;
case "sponsorDataChanged": case "sponsorDataChanged":
updateSponsorTimesSubmitting(); updateSponsorTimesSubmitting();
break; break;
case "isInfoFound": case "isInfoFound":
//send the sponsor times along with if it's found //send the sponsor times along with if it's found
sendResponse({ sendResponse({
found: sponsorDataFound, found: sponsorDataFound,
sponsorTimes: sponsorTimes, sponsorTimes: sponsorTimes,
hiddenSponsorTimes: hiddenSponsorTimes, hiddenSponsorTimes: hiddenSponsorTimes,
UUIDs: UUIDs UUIDs: UUIDs
}); });
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) { if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
//the popup should be closed now that another is opening //the popup should be closed now that another is opening
closeInfoMenu(); closeInfoMenu();
} }
popupInitialised = true; popupInitialised = true;
break; break;
case "getVideoID": case "getVideoID":
sendResponse({ sendResponse({
videoID: sponsorVideoID videoID: sponsorVideoID
}); });
break; break;
case "getVideoDuration": case "getVideoDuration":
sendResponse({ sendResponse({
duration: v.duration duration: v.duration
}); });
break; break;
case "skipToTime": case "skipToTime":
v.currentTime = request.time; v.currentTime = request.time;
return return
case "getCurrentTime": case "getCurrentTime":
sendResponse({ sendResponse({
currentTime: v.currentTime currentTime: v.currentTime
}); });
break; break;
case "getChannelURL": case "getChannelURL":
sendResponse({ sendResponse({
channelURL: channelURL channelURL: channelURL
}); });
break; break;
case "isChannelWhitelisted": case "isChannelWhitelisted":
sendResponse({ sendResponse({
value: channelWhitelisted value: channelWhitelisted
}); });
break; break;
case "whitelistChange": case "whitelistChange":
channelWhitelisted = request.value; channelWhitelisted = request.value;
sponsorsLookup(sponsorVideoID); sponsorsLookup(sponsorVideoID);
break; break;
case "changeStartSponsorButton": case "changeStartSponsorButton":
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible); changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
break; break;
} }
} }
/** /**
@@ -154,7 +154,7 @@ function messageListener(request, sender, sendResponse) {
* *
* @param {String} changes * @param {String} changes
*/ */
function configUpdateListener(changes) { function contentConfigUpdateListener(changes) {
for (const key in changes) { for (const key in changes) {
switch(key) { switch(key) {
case "hideVideoPlayerControls": case "hideVideoPlayerControls":
@@ -166,8 +166,8 @@ function configUpdateListener(changes) {
} }
} }
if (!SB.configListeners.includes(configUpdateListener)) { if (!SB.configListeners.includes(contentConfigUpdateListener)) {
SB.configListeners.push(configUpdateListener); SB.configListeners.push(contentConfigUpdateListener);
} }
//check for hotkey pressed //check for hotkey pressed

View File

@@ -14,7 +14,7 @@
"all_frames": true, "all_frames": true,
"js": [ "js": [
"config.js", "config.js",
"SB.js", "SB.js",
"utils/previewBar.js", "utils/previewBar.js",
"utils/skipNotice.js", "utils/skipNotice.js",
"utils.js", "utils.js",
@@ -58,9 +58,9 @@
}, },
"background": { "background": {
"scripts":[ "scripts":[
"config.js",
"SB.js", "SB.js",
"utils.js", "utils.js",
"config.js",
"background.js" "background.js"
], ],
"persistent": false "persistent": false
@@ -76,11 +76,5 @@
"page": "options/options.html", "page": "options/options.html",
"open_in_tab": true "open_in_tab": true
}, },
"manifest_version": 2, "manifest_version": 2
"browser_specific_settings": {
"gecko": {
"id": "sponsorBlocker@ajay.app",
"strict_min_version": "57.0"
}
}
} }

View File

@@ -1,14 +1,12 @@
window.addEventListener('DOMContentLoaded', init); window.addEventListener('DOMContentLoaded', init);
var invidiousInstancesRegex = [];
for (const url of supportedInvidiousInstances) {
invidiousInstancesRegex.push("https://*." + url + "/*");
invidiousInstancesRegex.push("http://*." + url + "/*");
}
async function init() { async function init() {
localizeHtmlPage(); localizeHtmlPage();
if (!SB.configListeners.includes(optionsConfigUpdateListener)) {
SB.configListeners.push(optionsConfigUpdateListener);
}
await wait(() => SB.config !== undefined); await wait(() => SB.config !== undefined);
// Set all of the toggle options to the correct option // Set all of the toggle options to the correct option
@@ -55,6 +53,13 @@ async function init() {
let button = optionsElements[i].querySelector(".trigger-button"); let button = optionsElements[i].querySelector(".trigger-button");
button.addEventListener("click", () => activateTextChange(optionsElements[i])); button.addEventListener("click", () => activateTextChange(optionsElements[i]));
let textChangeOption = optionsElements[i].getAttribute("sync-option");
// See if anything extra must be done
switch (textChangeOption) {
case "invidiousInstances":
invidiousInstanceAddInit(optionsElements[i], textChangeOption);
}
break; break;
case "keybind-change": case "keybind-change":
let keybindButton = optionsElements[i].querySelector(".trigger-button"); let keybindButton = optionsElements[i].querySelector(".trigger-button");
@@ -62,22 +67,7 @@ async function init() {
break; break;
case "display": case "display":
let displayOption = optionsElements[i].getAttribute("sync-option") updateDisplayElement(optionsElements[i])
let displayText = SB.config[displayOption];
optionsElements[i].innerText = displayText;
// See if anything extra must be run
switch (displayOption) {
case "invidiousInstances":
if (!displayText || displayText.length == 0) {
optionsElements[i].innerText = chrome.i18n.getMessage("noInstancesAdded");
} else {
optionsElements[i].innerText = displayText.join(', ');
}
break;
}
break;
} }
} }
@@ -85,6 +75,87 @@ async function init() {
optionsContainer.classList.add("animated"); optionsContainer.classList.add("animated");
} }
/**
* Called when the config is updated
*
* @param {String} element
*/
function optionsConfigUpdateListener(changes) {
let optionsContainer = document.getElementById("options");
let optionsElements = optionsContainer.querySelectorAll("*");
for (let i = 0; i < optionsElements.length; i++) {
switch (optionsElements[i].getAttribute("option-type")) {
case "display":
updateDisplayElement(optionsElements[i])
}
}
}
/**
* Will set display elements to the proper text
*
* @param {HTMLElement} element
*/
function updateDisplayElement(element) {
let displayOption = element.getAttribute("sync-option")
let displayText = SB.config[displayOption];
element.innerText = displayText;
// See if anything extra must be run
switch (displayOption) {
case "invidiousInstances":
element.innerText = displayText.join(', ');
break;
}
}
/**
* Initializes the option to add Invidious instances
*
* @param {HTMLElement} element
* @param {String} option
*/
function invidiousInstanceAddInit(element, option) {
let textBox = element.querySelector(".option-text-box");
let button = element.querySelector(".trigger-button");
let setButton = element.querySelector(".text-change-set");
setButton.addEventListener("click", async function(e) {
if (textBox.value == "" || textBox.value.includes("/") || textBox.value.includes("http") || textBox.value.includes(":")) {
alert(chrome.i18n.getMessage("addInvidiousInstanceError"));
} else {
// Add this
//TODO Make the call to invidiousOnClick support passing the straight extra values, plus make the get not needed
//OR merge the config PR and use that
let instanceList = SB.config[option];
if (!instanceList) instanceList = [];
instanceList.push(textBox.value);
SB.config[option] = instanceList;
let checkbox = document.querySelector("#support-invidious input");
checkbox.checked = true;
invidiousOnClick(checkbox, "supportInvidious");
textBox.value = "";
// Hide this section again
element.querySelector(".option-hidden-section").classList.add("hidden");
button.classList.remove("disabled");
}
});
let resetButton = element.querySelector(".invidious-instance-reset");
resetButton.addEventListener("click", function(e) {
if (confirm(chrome.i18n.getMessage("resetInvidiousInstanceAlert"))) {
SB.config[option] = SB.defaults[option];
}
});
}
/** /**
* Run when the invidious button is being initialized * Run when the invidious button is being initialized
* *
@@ -96,7 +167,7 @@ function invidiousInit(checkbox, option) {
if (isFirefox()) permissions = []; if (isFirefox()) permissions = [];
chrome.permissions.contains({ chrome.permissions.contains({
origins: invidiousInstancesRegex, origins: getInvidiousInstancesRegex(),
permissions: permissions permissions: permissions
}, function (result) { }, function (result) {
if (result != checkbox.checked) { if (result != checkbox.checked) {
@@ -120,12 +191,13 @@ function invidiousOnClick(checkbox, option) {
if (isFirefox()) permissions = []; if (isFirefox()) permissions = [];
chrome.permissions.request({ chrome.permissions.request({
origins: invidiousInstancesRegex, origins: getInvidiousInstancesRegex(),
permissions: permissions permissions: permissions
}, async function (granted) { }, async function (granted) {
if (granted) { if (granted) {
let js = [ let js = [
"config.js", "config.js",
"SB.js",
"utils/previewBar.js", "utils/previewBar.js",
"utils/skipNotice.js", "utils/skipNotice.js",
"utils.js", "utils.js",
@@ -154,12 +226,12 @@ function invidiousOnClick(checkbox, option) {
allFrames: true, allFrames: true,
js: firefoxJS, js: firefoxJS,
css: firefoxCSS, css: firefoxCSS,
matches: invidiousInstancesRegex matches: getInvidiousInstancesRegex()
}); });
} else { } else {
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() { chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() {
let conditions = []; let conditions = [];
for (const regex of invidiousInstancesRegex) { for (const regex of getInvidiousInstancesRegex()) {
conditions.push(new chrome.declarativeContent.PageStateMatcher({ conditions.push(new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlMatches: regex } pageUrl: { urlMatches: regex }
})); }));
@@ -196,7 +268,7 @@ function invidiousOnClick(checkbox, option) {
} }
chrome.permissions.remove({ chrome.permissions.remove({
origins: invidiousInstancesRegex origins: getInvidiousInstancesRegex()
}); });
} }
} }
@@ -271,40 +343,7 @@ function activateTextChange(element) {
// See if anything extra must be done // See if anything extra must be done
switch (option) { switch (option) {
case "invidiousInstances": case "invidiousInstances":
let setButton = element.querySelector(".text-change-set");
setButton.addEventListener("click", async function(e) {
if (textBox.value.includes("/") || textBox.value.includes("http") || textBox.value.includes(":")) {
alert(chrome.i18n.getMessage("addInvidiousInstanceError"));
} else {
// Add this
//TODO Make the call to invidiousOnClick support passing the straight extra values, plus make the get not needed
//OR merge the config PR and use that
if (!SB.config[option]) SB.config[option] = [];
SB.config[option].push(textBox.value);
let checkbox = document.querySelector("#support-invidious input");
checkbox.checked = true;
invidiousOnClick(checkbox, "supportInvidious");
textBox.value = "";
// Hide this section again
element.querySelector(".option-hidden-section").classList.add("hidden");
button.classList.remove("disabled");
}
});
let resetButton = element.querySelector(".invidious-instance-reset");
resetButton.addEventListener("click", function(e) {
if (confirm(chrome.i18n.getMessage("resetInvidiousInstanceAlert"))) {
SB.config[option] = [];
}
});
element.querySelector(".option-hidden-section").classList.remove("hidden"); element.querySelector(".option-hidden-section").classList.remove("hidden");
return; return;
} }
@@ -321,3 +360,13 @@ function activateTextChange(element) {
element.querySelector(".option-hidden-section").classList.remove("hidden"); element.querySelector(".option-hidden-section").classList.remove("hidden");
} }
function getInvidiousInstancesRegex() {
var invidiousInstancesRegex = [];
for (const url of SB.config.invidiousInstances) {
invidiousInstancesRegex.push("https://*." + url + "/*");
invidiousInstancesRegex.push("http://*." + url + "/*");
}
return invidiousInstancesRegex;
}

View File

@@ -1,5 +1,4 @@
var onInvidious = false; var onInvidious = false;
var supportedInvidiousInstances = ["invidio.us", "invidiou.sh", "invidious.snopyta.org"];
// Function that can be used to wait for a condition before returning // Function that can be used to wait for a condition before returning
async function wait(condition, timeout = 5000, check = 100) { async function wait(condition, timeout = 5000, check = 100) {
@@ -23,7 +22,7 @@ async function wait(condition, timeout = 5000, check = 100) {
function getYouTubeVideoID(url) { function getYouTubeVideoID(url) {
// For YouTube TV support // For YouTube TV support
if(document.URL.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", ""); if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", "");
//Attempt to parse url //Attempt to parse url
let urlObject = null; let urlObject = null;
@@ -35,9 +34,14 @@ function getYouTubeVideoID(url) {
} }
//Check if valid hostname //Check if valid hostname
if (supportedInvidiousInstances.includes(urlObject.host)) { if (SB.config && SB.config.invidiousInstances.includes(urlObject.host)) {
onInvidious = true; onInvidious = true;
} else if (!["www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) { } else if (!["www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) {
if (!SB.config) {
// Call this later, in case this is an Invidious tab
wait(() => SB.config !== undefined).then(() => videoIDChange(getYouTubeVideoID(url)));
}
return false return false
} }