diff --git a/SB.js b/SB.js index 98388ab3..aeb524dc 100644 --- a/SB.js +++ b/SB.js @@ -159,7 +159,8 @@ SB.defaults = { "hideInfoButtonPlayerControls": false, "hideDeleteButtonPlayerControls": false, "hideDiscordLaunches": 0, - "hideDiscordLink": false + "hideDiscordLink": false, + "invidiousInstances": ["invidio.us", "invidiou.sh", "invidious.snopyta.org"] } // Reset config diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 0248d1d5..3dca55b5 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -370,10 +370,7 @@ "message": "Reset Invidious Instance List" }, "resetInvidiousInstanceAlert": { - "message": "You are about to reset the Invidious instance list?" - }, - "noInstancesAdded": { - "message": "No extra instances added yet" + "message": "You are about to reset the Invidious instance list" }, "currentInstances": { "message": "Current Instances:" diff --git a/background.js b/background.js index f8d65d01..06e7c8f6 100644 --- a/background.js +++ b/background.js @@ -44,6 +44,9 @@ chrome.runtime.onMessage.addListener(async function (request, sender, callback) iconUrl: "./icons/LogoSponsorBlocker256px.png" }); case "registerContentScript": + let oldRegistration = contentScriptRegistrations[request.id]; + if (oldRegistration) oldRegistration.unregister(); + browser.contentScripts.register({ allFrames: request.allFrames, js: request.js, diff --git a/content.js b/content.js index a482f27c..9b2d472d 100644 --- a/content.js +++ b/content.js @@ -75,78 +75,78 @@ var popupInitialised = false; chrome.runtime.onMessage.addListener(messageListener); function messageListener(request, sender, sendResponse) { - //messages from popup script - switch(request.message){ - case "update": - videoIDChange(getYouTubeVideoID(document.URL)); - break; - case "sponsorStart": - sponsorMessageStarted(sendResponse); + //messages from popup script + switch(request.message){ + case "update": + videoIDChange(getYouTubeVideoID(document.URL)); + break; + case "sponsorStart": + sponsorMessageStarted(sendResponse); - break; - case "sponsorDataChanged": - updateSponsorTimesSubmitting(); + break; + case "sponsorDataChanged": + updateSponsorTimesSubmitting(); - break; - case "isInfoFound": - //send the sponsor times along with if it's found - sendResponse({ - found: sponsorDataFound, - sponsorTimes: sponsorTimes, - hiddenSponsorTimes: hiddenSponsorTimes, - UUIDs: UUIDs - }); + break; + case "isInfoFound": + //send the sponsor times along with if it's found + sendResponse({ + found: sponsorDataFound, + sponsorTimes: sponsorTimes, + hiddenSponsorTimes: hiddenSponsorTimes, + UUIDs: UUIDs + }); - if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) { - //the popup should be closed now that another is opening - closeInfoMenu(); - } + if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) { + //the popup should be closed now that another is opening + closeInfoMenu(); + } - popupInitialised = true; - break; - case "getVideoID": - sendResponse({ - videoID: sponsorVideoID - }); + popupInitialised = true; + break; + case "getVideoID": + sendResponse({ + videoID: sponsorVideoID + }); - break; - case "getVideoDuration": - sendResponse({ - duration: v.duration - }); + break; + case "getVideoDuration": + sendResponse({ + duration: v.duration + }); - break; - case "skipToTime": - v.currentTime = request.time; - return - case "getCurrentTime": - sendResponse({ - currentTime: v.currentTime - }); + break; + case "skipToTime": + v.currentTime = request.time; + return + case "getCurrentTime": + sendResponse({ + currentTime: v.currentTime + }); - break; - case "getChannelURL": - sendResponse({ - channelURL: channelURL - }); + break; + case "getChannelURL": + sendResponse({ + channelURL: channelURL + }); - break; - case "isChannelWhitelisted": - sendResponse({ - value: channelWhitelisted - }); + break; + case "isChannelWhitelisted": + sendResponse({ + value: channelWhitelisted + }); - break; - case "whitelistChange": - channelWhitelisted = request.value; - sponsorsLookup(sponsorVideoID); + break; + case "whitelistChange": + channelWhitelisted = request.value; + sponsorsLookup(sponsorVideoID); - break; - case "changeStartSponsorButton": - changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible); + break; + case "changeStartSponsorButton": + changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible); - break; - } + break; + } } /** @@ -154,7 +154,7 @@ function messageListener(request, sender, sendResponse) { * * @param {String} changes */ -function configUpdateListener(changes) { +function contentConfigUpdateListener(changes) { for (const key in changes) { switch(key) { case "hideVideoPlayerControls": @@ -166,8 +166,8 @@ function configUpdateListener(changes) { } } -if (!SB.configListeners.includes(configUpdateListener)) { - SB.configListeners.push(configUpdateListener); +if (!SB.configListeners.includes(contentConfigUpdateListener)) { + SB.configListeners.push(contentConfigUpdateListener); } //check for hotkey pressed diff --git a/manifest.json b/manifest.json index 073befc2..57548cc5 100644 --- a/manifest.json +++ b/manifest.json @@ -14,7 +14,7 @@ "all_frames": true, "js": [ "config.js", - "SB.js", + "SB.js", "utils/previewBar.js", "utils/skipNotice.js", "utils.js", @@ -58,9 +58,9 @@ }, "background": { "scripts":[ + "config.js", "SB.js", "utils.js", - "config.js", "background.js" ], "persistent": false @@ -76,11 +76,5 @@ "page": "options/options.html", "open_in_tab": true }, - "manifest_version": 2, - "browser_specific_settings": { - "gecko": { - "id": "sponsorBlocker@ajay.app", - "strict_min_version": "57.0" - } - } + "manifest_version": 2 } diff --git a/options/options.js b/options/options.js index d4ffe4a2..10abfe7a 100644 --- a/options/options.js +++ b/options/options.js @@ -1,14 +1,12 @@ window.addEventListener('DOMContentLoaded', init); -var invidiousInstancesRegex = []; -for (const url of supportedInvidiousInstances) { - invidiousInstancesRegex.push("https://*." + url + "/*"); - invidiousInstancesRegex.push("http://*." + url + "/*"); -} - async function init() { localizeHtmlPage(); + if (!SB.configListeners.includes(optionsConfigUpdateListener)) { + SB.configListeners.push(optionsConfigUpdateListener); + } + await wait(() => SB.config !== undefined); // Set all of the toggle options to the correct option @@ -55,6 +53,13 @@ async function init() { let button = optionsElements[i].querySelector(".trigger-button"); 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; case "keybind-change": let keybindButton = optionsElements[i].querySelector(".trigger-button"); @@ -62,22 +67,7 @@ async function init() { break; case "display": - let displayOption = optionsElements[i].getAttribute("sync-option") - 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; + updateDisplayElement(optionsElements[i]) } } @@ -85,6 +75,87 @@ async function init() { 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 * @@ -96,7 +167,7 @@ function invidiousInit(checkbox, option) { if (isFirefox()) permissions = []; chrome.permissions.contains({ - origins: invidiousInstancesRegex, + origins: getInvidiousInstancesRegex(), permissions: permissions }, function (result) { if (result != checkbox.checked) { @@ -120,12 +191,13 @@ function invidiousOnClick(checkbox, option) { if (isFirefox()) permissions = []; chrome.permissions.request({ - origins: invidiousInstancesRegex, + origins: getInvidiousInstancesRegex(), permissions: permissions }, async function (granted) { if (granted) { let js = [ "config.js", + "SB.js", "utils/previewBar.js", "utils/skipNotice.js", "utils.js", @@ -154,12 +226,12 @@ function invidiousOnClick(checkbox, option) { allFrames: true, js: firefoxJS, css: firefoxCSS, - matches: invidiousInstancesRegex + matches: getInvidiousInstancesRegex() }); } else { chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() { let conditions = []; - for (const regex of invidiousInstancesRegex) { + for (const regex of getInvidiousInstancesRegex()) { conditions.push(new chrome.declarativeContent.PageStateMatcher({ pageUrl: { urlMatches: regex } })); @@ -196,7 +268,7 @@ function invidiousOnClick(checkbox, option) { } chrome.permissions.remove({ - origins: invidiousInstancesRegex + origins: getInvidiousInstancesRegex() }); } } @@ -271,40 +343,7 @@ function activateTextChange(element) { // See if anything extra must be done switch (option) { 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"); - return; } @@ -321,3 +360,13 @@ function activateTextChange(element) { 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; +} \ No newline at end of file diff --git a/utils.js b/utils.js index 99e45906..4fdea008 100644 --- a/utils.js +++ b/utils.js @@ -1,5 +1,4 @@ var onInvidious = false; -var supportedInvidiousInstances = ["invidio.us", "invidiou.sh", "invidious.snopyta.org"]; // Function that can be used to wait for a condition before returning async function wait(condition, timeout = 5000, check = 100) { @@ -23,7 +22,7 @@ async function wait(condition, timeout = 5000, check = 100) { function getYouTubeVideoID(url) { // 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 let urlObject = null; @@ -35,9 +34,14 @@ function getYouTubeVideoID(url) { } //Check if valid hostname - if (supportedInvidiousInstances.includes(urlObject.host)) { + if (SB.config && SB.config.invidiousInstances.includes(urlObject.host)) { onInvidious = true; } 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 }