From 2f6ddeb5f1284ee6e4af2d82b4c717bff336cac4 Mon Sep 17 00:00:00 2001 From: afrmtbl Date: Thu, 5 Dec 2019 15:35:25 -0500 Subject: [PATCH 01/30] Initial Invidious support --- content.js | 52 +++++++++++++++++++++++++++++++++++++++------ manifest.json | 4 +++- utils.js | 10 ++++++++- utils/skipNotice.js | 4 ++-- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/content.js b/content.js index 228172de..5340fd04 100644 --- a/content.js +++ b/content.js @@ -59,9 +59,9 @@ var lastSponsorTimeSkippedUUID = null; var showingStartSponsor = true; //should the video controls buttons be added -var hideVideoPlayerControls = false; -var hideInfoButtonPlayerControls = false; -var hideDeleteButtonPlayerControls = false; +var hideVideoPlayerControls = onInvidious ? true : false; +var hideInfoButtonPlayerControls = onInvidious ? true : false; +var hideDeleteButtonPlayerControls = onInvidious ? true : false; //the sponsor times being prepared to be submitted var sponsorTimesSubmitting = []; @@ -294,8 +294,22 @@ function videoIDChange(id) { if (previewBar == null) { //create it wait(getControls).then(result => { - let progressBar = document.getElementsByClassName("ytp-progress-bar-container")[0] || document.getElementsByClassName("no-model cue-range-markers")[0]; - previewBar = new PreviewBar(progressBar); + const progressElementSelectors = [ + // For YouTube + "ytp-progress-bar-container", + "no-model cue-range-markers", + // For Invidious/VideoJS + "vjs-progress-holder" + ]; + + for (const selector of progressElementSelectors) { + const el = document.getElementsByClassName(selector); + + if (el && el.length && el[0]) { + previewBar = new PreviewBar(el[0]); + break; + } + } }); } @@ -460,6 +474,10 @@ function sponsorsLookup(id, channelIDPromise) { sponsorLookupRetries++; } + + if (channelWhitelisted) { + whitelistCheck(); + } }); //add the event to run on the videos "ontimeupdate" @@ -509,6 +527,13 @@ function getChannelID() { if (channelContainers.length != 0) { channelURLContainer = channelContainers[0].firstElementChild; } + else if (onInvidious) { + // Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers... + channelContainers = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a"); + if (channelContainers.length != 0) { + channelURLContainer = channelContainers; + } + } } if (channelURLContainer == null) { @@ -521,7 +546,12 @@ function getChannelID() { let currentTitle = ""; if (titleInfoContainer != null) { currentTitle = titleInfoContainer.firstElementChild.firstElementChild.querySelector(".title").firstElementChild.innerText; - } else { + } + else if (onInvidious) { + // Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers... + currentTitle = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a > div > span").textContent; + } + else { //old YouTube theme currentTitle = document.getElementById("eow-title").innerText; } @@ -721,7 +751,15 @@ function createButton(baseID, title, callback, imageName, isDraggable=false) { function getControls() { let controls = document.getElementsByClassName("ytp-right-controls"); - return (!controls || controls.length === 0) ? false : controls[controls.length - 1] + + if (!controls || controls.length === 0) { + // The invidious video element's controls element + controls = document.getElementsByClassName("vjs-control-bar"); + return (!controls || controls.length === 0) ? false : controls[controls.length - 1]; + } + else { + return controls[controls.length - 1]; + } }; //adds all the player controls buttons diff --git a/manifest.json b/manifest.json index e186cd0f..3e0815a9 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,9 @@ { "matches": [ "https://*.youtube.com/*", - "https://www.youtube-nocookie.com/embed/*" + "https://www.youtube-nocookie.com/embed/*", + "https://*.invidio.us/*" + "https://*.invidiou.sh/*" ], "all_frames": true, "js": [ diff --git a/utils.js b/utils.js index d9ce3a22..dceedeb8 100644 --- a/utils.js +++ b/utils.js @@ -1,3 +1,6 @@ +var onInvidious = false; +var supportedInvidiousInstances = ["invidio.us", "invidiou.sh"]; + // Function that can be used to wait for a condition before returning async function wait(condition, timeout = 5000, check = 100) { return await new Promise((resolve, reject) => { @@ -29,7 +32,12 @@ function getYouTubeVideoID(url) { } //Check if valid hostname - if(!["www.youtube.com","www.youtube-nocookie.com"].includes(urlObject.host)) return false; + if(!["www.youtube.com", "www.youtube-nocookie.com", ...supportedInvidiousInstances].includes(urlObject.host)) { + return false; + } + else if (supportedInvidiousInstances.includes(urlObject.host)) { + onInvidious = true; + } //Get ID from searchParam if ((urlObject.pathname == "/watch" || urlObject.pathname == "/watch/") && urlObject.searchParams.has("v")) { diff --git a/utils/skipNotice.js b/utils/skipNotice.js index c69e62d2..6102f121 100644 --- a/utils/skipNotice.js +++ b/utils/skipNotice.js @@ -166,7 +166,7 @@ class SkipNotice { noticeElement.appendChild(secondRow); //get reference node - let referenceNode = document.getElementById("movie_player"); + let referenceNode = document.getElementById("movie_player") || document.querySelector("#player-container .video-js"); if (referenceNode == null) { //for embeds let player = document.getElementById("player"); @@ -433,4 +433,4 @@ class SkipNotice { if (this.countdownInterval != -1) clearInterval(this.countdownInterval); } -} \ No newline at end of file +} From 6d442b9e804ff49f2966bc6f27fa9243a08a0a25 Mon Sep 17 00:00:00 2001 From: afrmtbl Date: Thu, 5 Dec 2019 15:48:26 -0500 Subject: [PATCH 02/30] Explain additional whitelist check --- content.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content.js b/content.js index 5340fd04..cf0ef27c 100644 --- a/content.js +++ b/content.js @@ -475,6 +475,10 @@ function sponsorsLookup(id, channelIDPromise) { sponsorLookupRetries++; } + // If the initial channel whitelist check finishes before + // the fetching of the sponsor times, then the sponsor times will be + // added again after the whitelist check clears them. Checking it here makes sure + // the whitelist will be applied (downside is `whitelistCheck()` gets called multiple times). if (channelWhitelisted) { whitelistCheck(); } From 5dc67a386c06e167d824e422dd15811fb7d0be9b Mon Sep 17 00:00:00 2001 From: afrmtbl Date: Thu, 5 Dec 2019 16:13:22 -0500 Subject: [PATCH 03/30] Fix manifest --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 3e0815a9..bd7734ae 100644 --- a/manifest.json +++ b/manifest.json @@ -9,7 +9,7 @@ "matches": [ "https://*.youtube.com/*", "https://www.youtube-nocookie.com/embed/*", - "https://*.invidio.us/*" + "https://*.invidio.us/*", "https://*.invidiou.sh/*" ], "all_frames": true, From 630b099fd6df9b59f6acf1228e3be8b812ce2b58 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 19 Dec 2019 00:36:35 -0500 Subject: [PATCH 04/30] Fixed formatting and removed whitelisting fix code. Whitelisting was now fixed in a different way. --- content.js | 20 ++++---------------- utils.js | 7 +++---- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/content.js b/content.js index cf0ef27c..424b476f 100644 --- a/content.js +++ b/content.js @@ -474,14 +474,6 @@ function sponsorsLookup(id, channelIDPromise) { sponsorLookupRetries++; } - - // If the initial channel whitelist check finishes before - // the fetching of the sponsor times, then the sponsor times will be - // added again after the whitelist check clears them. Checking it here makes sure - // the whitelist will be applied (downside is `whitelistCheck()` gets called multiple times). - if (channelWhitelisted) { - whitelistCheck(); - } }); //add the event to run on the videos "ontimeupdate" @@ -530,8 +522,7 @@ function getChannelID() { channelContainers = document.getElementsByClassName("yt-user-info"); if (channelContainers.length != 0) { channelURLContainer = channelContainers[0].firstElementChild; - } - else if (onInvidious) { + } else if (onInvidious) { // Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers... channelContainers = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a"); if (channelContainers.length != 0) { @@ -550,12 +541,10 @@ function getChannelID() { let currentTitle = ""; if (titleInfoContainer != null) { currentTitle = titleInfoContainer.firstElementChild.firstElementChild.querySelector(".title").firstElementChild.innerText; - } - else if (onInvidious) { + } else if (onInvidious) { // Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers... currentTitle = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a > div > span").textContent; - } - else { + } else { //old YouTube theme currentTitle = document.getElementById("eow-title").innerText; } @@ -760,8 +749,7 @@ function getControls() { // The invidious video element's controls element controls = document.getElementsByClassName("vjs-control-bar"); return (!controls || controls.length === 0) ? false : controls[controls.length - 1]; - } - else { + } else { return controls[controls.length - 1]; } }; diff --git a/utils.js b/utils.js index dceedeb8..4373d69c 100644 --- a/utils.js +++ b/utils.js @@ -32,11 +32,10 @@ function getYouTubeVideoID(url) { } //Check if valid hostname - if(!["www.youtube.com", "www.youtube-nocookie.com", ...supportedInvidiousInstances].includes(urlObject.host)) { - return false; - } - else if (supportedInvidiousInstances.includes(urlObject.host)) { + if (supportedInvidiousInstances.includes(urlObject.host)) { onInvidious = true; + } else if (!["www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) { + return false } //Get ID from searchParam From 45a64fcb03145c66dfd8e2a2cdfe939bc0322482 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 19 Dec 2019 00:38:55 -0500 Subject: [PATCH 05/30] Prevented upload button from appearing on invidious. It still appears if the video player controls are disabled. --- content.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content.js b/content.js index 424b476f..a1bdad71 100644 --- a/content.js +++ b/content.js @@ -756,6 +756,9 @@ function getControls() { //adds all the player controls buttons async function createButtons() { + // Don't add controls on Invidious yet + if (onInvidious) return; + let result = await wait(getControls).catch(); //set global controls variable From 547127367313b05dcb64ba9750953ebe3a3e6c0a Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 19 Dec 2019 00:48:26 -0500 Subject: [PATCH 06/30] Fixed getting channel ID for invidious. --- content.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content.js b/content.js index 6421f53f..0ddea4a9 100644 --- a/content.js +++ b/content.js @@ -518,17 +518,17 @@ function getChannelID() { if (channelNameContainer !== null) { channelURLContainer = channelNameContainer.querySelector("#container").querySelector("#text-container").querySelector("#text").firstElementChild; + } else if (onInvidious) { + // Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers... + channelContainers = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a"); + if (channelContainers.length != 0) { + channelURLContainer = channelContainers; + } } else { //old YouTube theme let channelContainers = document.getElementsByClassName("yt-user-info"); if (channelContainers.length != 0) { channelURLContainer = channelContainers[0].firstElementChild; - } else if (onInvidious) { - // Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers... - channelContainers = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a"); - if (channelContainers.length != 0) { - channelURLContainer = channelContainers; - } } } From 5b628ccbf94d2c9ca6074ae1a8790e925e9adb1d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 19 Dec 2019 00:56:52 -0500 Subject: [PATCH 07/30] Fixed submit button being shown at the wrong time. --- content.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/content.js b/content.js index 0ddea4a9..cbd1f788 100644 --- a/content.js +++ b/content.js @@ -757,9 +757,6 @@ function getControls() { //adds all the player controls buttons async function createButtons() { - // Don't add controls on Invidious yet - if (onInvidious) return; - let result = await wait(getControls).catch(); //set global controls variable @@ -845,7 +842,7 @@ async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) { document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png"); document.getElementById("startSponsorButton").setAttribute("title", chrome.i18n.getMessage("sponsorStart")); - if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !hideInfoButtonPlayerControls) { + if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !hideDeleteButtonPlayerControls) { document.getElementById("submitButton").style.display = "unset"; } else if (!uploadButtonVisible) { //disable submit button From 9fc846bd7ac54211553740d0632fde449e12b862 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 19 Dec 2019 01:03:09 -0500 Subject: [PATCH 08/30] Made sure the video player button options are ignored on Invidious. --- content.js | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/content.js b/content.js index cbd1f788..1e6441f6 100644 --- a/content.js +++ b/content.js @@ -59,9 +59,10 @@ var lastSponsorTimeSkippedUUID = null; var showingStartSponsor = true; //should the video controls buttons be added -var hideVideoPlayerControls = onInvidious ? true : false; -var hideInfoButtonPlayerControls = onInvidious ? true : false; -var hideDeleteButtonPlayerControls = onInvidious ? true : false; +//TODO: If invidious gets video controls, change the code where this is set from chrome.sync as well. +var hideVideoPlayerControls = onInvidious; +var hideInfoButtonPlayerControls = onInvidious; +var hideDeleteButtonPlayerControls = onInvidious; //the sponsor times being prepared to be submitted var sponsorTimesSubmitting = []; @@ -374,28 +375,29 @@ function videoIDChange(id) { }); //see if video controls buttons should be added - chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) { - if (result.hideVideoPlayerControls != undefined) { - hideVideoPlayerControls = result.hideVideoPlayerControls; - } - - updateVisibilityOfPlayerControlsButton(); - }); - chrome.storage.sync.get(["hideInfoButtonPlayerControls"], function(result) { - if (result.hideInfoButtonPlayerControls != undefined) { - hideInfoButtonPlayerControls = result.hideInfoButtonPlayerControls; - } - - updateVisibilityOfPlayerControlsButton(); - }); - chrome.storage.sync.get(["hideDeleteButtonPlayerControls"], function(result) { - if (result.hideDeleteButtonPlayerControls != undefined) { - hideDeleteButtonPlayerControls = result.hideDeleteButtonPlayerControls; - } - - updateVisibilityOfPlayerControlsButton(false); - }); - + if (!onInvidious) { + chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) { + if (result.hideVideoPlayerControls != undefined) { + hideVideoPlayerControls = result.hideVideoPlayerControls; + } + + updateVisibilityOfPlayerControlsButton(); + }); + chrome.storage.sync.get(["hideInfoButtonPlayerControls"], function(result) { + if (result.hideInfoButtonPlayerControls != undefined) { + hideInfoButtonPlayerControls = result.hideInfoButtonPlayerControls; + } + + updateVisibilityOfPlayerControlsButton(); + }); + chrome.storage.sync.get(["hideDeleteButtonPlayerControls"], function(result) { + if (result.hideDeleteButtonPlayerControls != undefined) { + hideDeleteButtonPlayerControls = result.hideDeleteButtonPlayerControls; + } + + updateVisibilityOfPlayerControlsButton(false); + }); + } } function sponsorsLookup(id, channelIDPromise) { @@ -842,7 +844,7 @@ async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) { document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png"); document.getElementById("startSponsorButton").setAttribute("title", chrome.i18n.getMessage("sponsorStart")); - if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !hideDeleteButtonPlayerControls) { + if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !hideVideoPlayerControls) { document.getElementById("submitButton").style.display = "unset"; } else if (!uploadButtonVisible) { //disable submit button From 433db26078643fbbe62c2cf51054c6d8a499dd33 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 30 Dec 2019 23:15:29 -0500 Subject: [PATCH 09/30] Added option to enable invidious support. --- _locales/en/messages.json | 6 ++++ manifest.json | 11 +++--- options/options.html | 18 +++++++++- options/options.js | 71 ++++++++++++++++++++++++++++++++++----- 4 files changed, 93 insertions(+), 13 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7ebbc3ab..e31a5741 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -344,5 +344,11 @@ }, "keybindCurrentlySet": { "message": ". It is currently set to:" + }, + "supportInvidious": { + "message": "Support Invidious" + }, + "supportInvidiousDescription": { + "message": "Invidious (invidio.us) is a third party YouTube client. To enable support, you must accept the extra permissions." } } diff --git a/manifest.json b/manifest.json index a287db2b..175ed2e9 100644 --- a/manifest.json +++ b/manifest.json @@ -8,9 +8,7 @@ { "matches": [ "https://*.youtube.com/*", - "https://www.youtube-nocookie.com/embed/*", - "https://*.invidio.us/*", - "https://*.invidiou.sh/*" + "https://www.youtube-nocookie.com/embed/*" ], "all_frames": true, "js": [ @@ -46,7 +44,12 @@ "permissions": [ "storage", "notifications", - "https://sponsor.ajay.app/*" + "https://sponsor.ajay.app/*", + "https://*.invidio.us/*" + ], + "optional_permissions": [ + "declarativeContent", + "https://*/*" ], "browser_action": { "default_title": "__MSG_Name__", diff --git a/options/options.html b/options/options.html index 45983d58..943c3c80 100644 --- a/options/options.html +++ b/options/options.html @@ -20,7 +20,23 @@

__MSG_Options__