diff --git a/background.js b/background.js index 06e7c8f6..f6d1d533 100644 --- a/background.js +++ b/background.js @@ -1,6 +1,15 @@ +isBackgroundScript = true; + // Used only on Firefox, which does not support non persistent background pages. var contentScriptRegistrations = {}; +// Register content script if needed +if (isFirefox()) { + wait(() => SB.config !== undefined).then(function() { + if (SB.config.supportInvidious) setupExtraSiteContentScripts(); + }); +} + chrome.tabs.onUpdated.addListener(function(tabId) { chrome.tabs.sendMessage(tabId, { message: 'update', @@ -44,16 +53,7 @@ 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, - css: request.css, - matches: request.matches - }).then(() => void (contentScriptRegistrations[request.id] = registration)); - + registerFirefoxContentScript(request); return false; case "unregisterContentScript": contentScriptRegistrations[request.id].unregister(); @@ -81,6 +81,24 @@ chrome.runtime.onInstalled.addListener(function (object) { }, 1500); }); +/** + * Only works on Firefox. + * Firefox requires that it be applied after every extension restart. + * + * @param {JSON} options + */ +function registerFirefoxContentScript(options) { + let oldRegistration = contentScriptRegistrations[options.id]; + if (oldRegistration) oldRegistration.unregister(); + + browser.contentScripts.register({ + allFrames: options.allFrames, + js: options.js, + css: options.css, + matches: options.matches + }).then(() => void (contentScriptRegistrations[options.id] = registration)); +} + //gets the sponsor times from memory function getSponsorTimes(videoID, callback) { let sponsorTimes = []; diff --git a/manifest.json b/manifest.json index 57548cc5..d2aac68b 100644 --- a/manifest.json +++ b/manifest.json @@ -76,5 +76,10 @@ "page": "options/options.html", "open_in_tab": true }, - "manifest_version": 2 + "manifest_version": 2, + "browser_specific_settings": { + "gecko": { + "id": "sponsorBlocker@ajay.app" + } + } } diff --git a/options/options.js b/options/options.js index 82e398d1..837cfe18 100644 --- a/options/options.js +++ b/options/options.js @@ -185,75 +185,10 @@ function invidiousInit(checkbox, option) { */ function invidiousOnClick(checkbox, option) { if (checkbox.checked) { - // Request permission - let permissions = ["declarativeContent"]; - if (isFirefox()) permissions = []; - - chrome.permissions.request({ - origins: getInvidiousInstancesRegex(), - permissions: permissions - }, async function (granted) { - if (granted) { - let js = [ - "config.js", - "SB.js", - "utils/previewBar.js", - "utils/skipNotice.js", - "utils.js", - "content.js", - "popup.js" - ]; - let css = [ - "content.css", - "./libs/Source+Sans+Pro.css", - "popup.css" - ]; - - if (isFirefox()) { - let firefoxJS = []; - for (const file of js) { - firefoxJS.push({file}); - } - let firefoxCSS = []; - for (const file of css) { - firefoxCSS.push({file}); - } - - chrome.runtime.sendMessage({ - message: "registerContentScript", - id: "invidious", - allFrames: true, - js: firefoxJS, - css: firefoxCSS, - matches: getInvidiousInstancesRegex() - }); - } else { - chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() { - let conditions = []; - for (const regex of getInvidiousInstancesRegex()) { - conditions.push(new chrome.declarativeContent.PageStateMatcher({ - pageUrl: { urlMatches: regex } - })); - } - // Add page rule - let rule = { - id: "invidious", - conditions, - actions: [new chrome.declarativeContent.RequestContentScript({ - allFrames: true, - js, - css - })] - }; - - chrome.declarativeContent.onPageChanged.addRules([rule]); - }); - } - } else { + setupExtraSitePermissions(function (granted) { + if (!granted) { SB.config[option] = false; checkbox.checked = false; - - chrome.declarativeContent.onPageChanged.removeRules(["invidious"]); } }); } else { @@ -358,14 +293,4 @@ 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 4fdea008..0b7ca6ad 100644 --- a/utils.js +++ b/utils.js @@ -1,3 +1,4 @@ +var isBackgroundScript = false; var onInvidious = false; // Function that can be used to wait for a condition before returning @@ -60,6 +61,119 @@ function getYouTubeVideoID(url) { return false; } +/** + * Asks for the optional permissions required for all extra sites. + * It also starts the content script registrations. + * + * For now, it is just SB.config.invidiousInstances. + * + * @param {CallableFunction} callback + */ +function setupExtraSitePermissions(callback) { + // Request permission + let permissions = ["declarativeContent"]; + if (isFirefox()) permissions = []; + + chrome.permissions.request({ + origins: getInvidiousInstancesRegex(), + permissions: permissions + }, async function (granted) { + if (granted) { + setupExtraSiteContentScripts(); + } else { + if (isFirefox()) { + if (isBackgroundScript) { + if (contentScriptRegistrations[request.id]) { + contentScriptRegistrations[request.id].unregister(); + delete contentScriptRegistrations[request.id]; + } + } else { + chrome.runtime.sendMessage({ + message: "unregisterContentScript", + id: "invidious" + }); + } + } else { + chrome.declarativeContent.onPageChanged.removeRules(["invidious"]); + } + } + + callback(granted); + }); +} + +/** + * Registers the content scripts for the extra sites. + * Will use a different method depending on the browser. + * This is called by setupExtraSitePermissions(). + * + * For now, it is just SB.config.invidiousInstances. + */ +function setupExtraSiteContentScripts() { + let js = [ + "config.js", + "SB.js", + "utils/previewBar.js", + "utils/skipNotice.js", + "utils.js", + "content.js", + "popup.js" + ]; + let css = [ + "content.css", + "./libs/Source+Sans+Pro.css", + "popup.css" + ]; + + if (isFirefox()) { + let firefoxJS = []; + for (const file of js) { + firefoxJS.push({file}); + } + let firefoxCSS = []; + for (const file of css) { + firefoxCSS.push({file}); + } + + let registration = { + message: "registerContentScript", + id: "invidious", + allFrames: true, + js: firefoxJS, + css: firefoxCSS, + matches: getInvidiousInstancesRegex() + }; + + if (isBackgroundScript) { + registerFirefoxContentScript(registration); + } else { + chrome.runtime.sendMessage(registration); + } + } else { + chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() { + let conditions = []; + for (const regex of getInvidiousInstancesRegex()) { + conditions.push(new chrome.declarativeContent.PageStateMatcher({ + pageUrl: { urlMatches: regex } + })); + } + + // Add page rule + let rule = { + id: "invidious", + conditions, + actions: [new chrome.declarativeContent.RequestContentScript({ + allFrames: true, + js, + css + })] + }; + + chrome.declarativeContent.onPageChanged.addRules([rule]); + }); + } +} + function localizeHtmlPage() { //Localize by replacing __MSG_***__ meta tags var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children; @@ -83,6 +197,19 @@ function getLocalizedMessage(text) { } } +/** + * @returns {String[]} Invidious Instances in regex form + */ +function getInvidiousInstancesRegex() { + var invidiousInstancesRegex = []; + for (const url of SB.config.invidiousInstances) { + invidiousInstancesRegex.push("https://*." + url + "/*"); + invidiousInstancesRegex.push("http://*." + url + "/*"); + } + + return invidiousInstancesRegex; +} + function generateUserID(length = 36) { let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let result = "";