From 933babb4e65f7cbef1a15635b9a81ba52a259c96 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 17 Feb 2020 11:32:00 -0500 Subject: [PATCH 01/16] Added mobile YouTube site to the whitelist. --- src/content.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content.ts b/src/content.ts index 8ebc3121..2241639f 100644 --- a/src/content.ts +++ b/src/content.ts @@ -499,7 +499,7 @@ function getYouTubeVideoID(url: string) { // Check if valid hostname if (Config.config && Config.config.invidiousInstances.includes(urlObject.host)) { onInvidious = true; - } else if (!["www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) { + } else if (!["m.youtube.com", "www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) { if (!Config.config) { // Call this later, in case this is an Invidious tab utils.wait(() => Config.config !== null).then(() => videoIDChange(getYouTubeVideoID(url))); From 219a7ba8c34fe84c29bd3e05dbc56d103c48765f Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 17 Feb 2020 15:10:50 -0500 Subject: [PATCH 02/16] Added preview bar to mobile --- src/content.ts | 130 ++++++++++++++++++++++++-------- src/js-components/previewBar.ts | 18 ++++- 2 files changed, 111 insertions(+), 37 deletions(-) diff --git a/src/content.ts b/src/content.ts index 2241639f..c856b6b1 100644 --- a/src/content.ts +++ b/src/content.ts @@ -30,6 +30,7 @@ var sponsorSkipped = []; var video: HTMLVideoElement; var onInvidious; +var onMobileYouTube; //the video id of the last preview bar update var lastPreviewBarUpdate; @@ -47,7 +48,7 @@ var title; var channelWhitelisted = false; // create preview bar -var previewBar = null; +var previewBar: PreviewBar = null; // When not null, a sponsor is currently being previewed and auto skip should be enabled. // This is set to a timeout function when that happens that will reset it after 3 seconds. @@ -255,7 +256,7 @@ async function videoIDChange(id) { sponsorVideoID = id; resetValues(); - + //id is not valid if (!id) return; @@ -278,26 +279,19 @@ async function videoIDChange(id) { channelIDPromise.then(() => channelIDPromise.isFulfilled = true).catch(() => channelIDPromise.isRejected = true); //setup the preview bar - if (previewBar == null) { - //create it - utils.wait(getControls).then(result => { - const progressElementSelectors = [ - // For YouTube - "ytp-progress-bar-container", - "no-model cue-range-markers", - // For Invidious/VideoJS - "vjs-progress-holder" - ]; + if (previewBar === null) { + if (onMobileYouTube) { + // Mobile YouTube workaround + const observer = new MutationObserver(handleMobileControlsMutations); - for (const selector of progressElementSelectors) { - const el = document.getElementsByClassName(selector); - - if (el && el.length && el[0]) { - previewBar = new PreviewBar(el[0]); - break; - } - } - }); + observer.observe(document.getElementById("player-control-container"), { + attributes: true, + childList: true, + subtree: true + }); + } else { + utils.wait(getControls).then(createPreviewBar); + } } //warn them if they had unsubmitted times @@ -361,6 +355,56 @@ async function videoIDChange(id) { } } +function handleMobileControlsMutations(): void { + let mobileYouTubeSelector = ".progress-bar-background"; + + if (previewBar !== null) { + if (document.body.contains(previewBar.container)) { + updatePreviewBarPositionMobile(document.getElementsByClassName(mobileYouTubeSelector)[0]); + + return; + } else { + // The container does not exist anymore, remove that old preview bar + previewBar.remove(); + previewBar = null; + } + } + + // Create the preview bar if needed (the function hasn't returned yet) + createPreviewBar(); +} + +/** + * Creates a preview bar on the video + */ +function createPreviewBar(): void { + if (previewBar !== null) return; + + const progressElementSelectors = [ + // For mobile YouTube + ".progress-bar-background", + // 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.querySelectorAll(selector); + + if (el && el.length && el[0]) { + console.log(selector) + + previewBar = new PreviewBar(el[0], onMobileYouTube); + + updatePreviewBar(); + + break; + } + } +} + function sponsorsLookup(id: string, channelIDPromise?) { video = document.querySelector('video') // Youtube video player @@ -499,6 +543,8 @@ function getYouTubeVideoID(url: string) { // Check if valid hostname if (Config.config && Config.config.invidiousInstances.includes(urlObject.host)) { onInvidious = true; + } else if (urlObject.host === "m.youtube.com") { + onMobileYouTube = true; } else if (!["m.youtube.com", "www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) { if (!Config.config) { // Call this later, in case this is an Invidious tab @@ -572,6 +618,15 @@ function getChannelID() { channelWhitelisted = false; } +/** + * This function is required on mobile YouTube and will keep getting called whenever the preview bar disapears + */ +async function updatePreviewBarPositionMobile(parent: Element) { + if (document.getElementById("previewbar") === null) { + previewBar.updatePosition(parent); + } +} + function updatePreviewBar() { let localSponsorTimes = sponsorTimes; if (localSponsorTimes == null) localSponsorTimes = []; @@ -750,16 +805,25 @@ function createButton(baseID, title, callback, imageName, isDraggable=false) { controls.prepend(newButton); } -function getControls() { - let controls = document.getElementsByClassName("ytp-right-controls"); +function getControls(): HTMLElement | boolean { + let controlsSelectors = [ + // YouTube + ".ytp-right-controls", + // Mobile YouTube + "#player-control-overlay", + // Invidious/videojs video element's controls element + ".vjs-control-bar" + ] - 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]; + for (const controlsSelector of controlsSelectors) { + let controls = document.querySelectorAll(controlsSelector); + + if (controls && controls.length > 0) { + return controls[controls.length - 1]; + } } + + return false; }; //adds all the player controls buttons @@ -782,7 +846,7 @@ async function updateVisibilityOfPlayerControlsButton() { await createButtons(); - if (Config.config.hideVideoPlayerControls || onInvidious) { + if (Config.config.hideVideoPlayerControls || onInvidious || onMobileYouTube) { document.getElementById("startSponsorButton").style.display = "none"; document.getElementById("submitButton").style.display = "none"; } else { @@ -790,13 +854,13 @@ async function updateVisibilityOfPlayerControlsButton() { } //don't show the info button on embeds - if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) { + if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious || onMobileYouTube) { document.getElementById("infoButton").style.display = "none"; } else { document.getElementById("infoButton").style.removeProperty("display"); } - if (Config.config.hideDeleteButtonPlayerControls || onInvidious) { + if (Config.config.hideDeleteButtonPlayerControls || onInvidious || onMobileYouTube) { document.getElementById("deleteButton").style.display = "none"; } } @@ -848,7 +912,7 @@ async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) { await utils.wait(isSubmitButtonLoaded); //if it isn't visible, there is no data - let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none" + let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious || onMobileYouTube)) ? "unset" : "none" document.getElementById("deleteButton").style.display = shouldHide; if (showStartSponsor) { diff --git a/src/js-components/previewBar.ts b/src/js-components/previewBar.ts index a70659b5..febeaa25 100644 --- a/src/js-components/previewBar.ts +++ b/src/js-components/previewBar.ts @@ -23,18 +23,28 @@ let barTypes = { class PreviewBar { container: HTMLUListElement; parent: any; + onMobileYouTube: boolean; - constructor(parent) { + constructor(parent, onMobileYouTube) { this.container = document.createElement('ul'); this.container.id = 'previewbar'; this.parent = parent; - this.updatePosition(); + this.onMobileYouTube = onMobileYouTube; + + this.updatePosition(parent); } - updatePosition() { + updatePosition(parent) { //below the seek bar // this.parent.insertAdjacentElement("afterEnd", this.container); + + this.parent = parent; + + if (this.onMobileYouTube) { + parent.style.backgroundColor = "rgba(255, 255, 255, 0.3)"; + parent.style.opacity = "1"; + } //on the seek bar this.parent.insertAdjacentElement("afterBegin", this.container); @@ -70,7 +80,7 @@ class PreviewBar { bar.setAttribute('data-vs-segment-type', types[i]); bar.style.backgroundColor = barTypes[types[i]].color; - bar.style.opacity = barTypes[types[i]].opacity; + if (!this.onMobileYouTube) bar.style.opacity = barTypes[types[i]].opacity; bar.style.width = width + '%'; bar.style.left = (timestamps[i][0] / duration * 100) + "%"; bar.style.position = "absolute" From af7ba31c2f03818a8b0a6ebf05e8b8ddc374cedd Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 14:40:40 -0500 Subject: [PATCH 03/16] Remove logging. --- src/content.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/content.ts b/src/content.ts index c856b6b1..0b56dc50 100644 --- a/src/content.ts +++ b/src/content.ts @@ -394,8 +394,6 @@ function createPreviewBar(): void { const el = document.querySelectorAll(selector); if (el && el.length && el[0]) { - console.log(selector) - previewBar = new PreviewBar(el[0], onMobileYouTube); updatePreviewBar(); From aeabf806ac5cb8e07d763d723ae20d942ce8132d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 15:03:55 -0500 Subject: [PATCH 04/16] Added duration change listener check to prevent mid-video zero second skips. Sometimes the video gets reset to zero seconds for a few milliseconds, this should not trigger a skip. Resolves https://github.com/ajayyy/SponsorBlock/issues/183 --- src/content.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/content.ts b/src/content.ts index 0b56dc50..3277691e 100644 --- a/src/content.ts +++ b/src/content.ts @@ -37,6 +37,8 @@ var lastPreviewBarUpdate; //whether the duration listener listening for the duration changes of the video has been setup yet var durationListenerSetUp = false; +// Timestamp of the last duration change +var lastDurationChange = 0; //the channel this video is about var channelURL; @@ -403,8 +405,17 @@ function createPreviewBar(): void { } } -function sponsorsLookup(id: string, channelIDPromise?) { +/** + * Triggered every time the video duration changes. + * This happens when the resolution changes or at random time to clear memory. + */ +function durationChangeListener() { + lastDurationChange = Date.now(); + updatePreviewBar(); +} + +function sponsorsLookup(id: string, channelIDPromise?) { video = document.querySelector('video') // Youtube video player //there is no video here if (video == null) { @@ -416,7 +427,7 @@ function sponsorsLookup(id: string, channelIDPromise?) { durationListenerSetUp = true; //wait until it is loaded - video.addEventListener('durationchange', updatePreviewBar); + video.addEventListener('durationchange', durationChangeListener); } if (channelIDPromise !== undefined) { @@ -671,6 +682,9 @@ function sponsorCheck() { return; } + // Don't skip right after duration change (the time resets to zero) 400ms + if (Date.now() - lastDurationChange < 400000 && lastTime > 1) return; + let skipHappened = false; if (sponsorTimes != null) { From cd58f6bc73ef115e8d42b60b6d5d9e1c067a6e7a Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 15:57:40 -0500 Subject: [PATCH 05/16] Skip notice improvement. --- src/content.ts | 3 ++- src/js-components/skipNotice.ts | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/content.ts b/src/content.ts index 3277691e..fe12251f 100644 --- a/src/content.ts +++ b/src/content.ts @@ -95,7 +95,8 @@ var skipNoticeContentContainer = () => ({ v: video, reskipSponsorTime, hiddenSponsorTimes, - updatePreviewBar + updatePreviewBar, + onMobileYouTube }); //get messages from the background script and the popup diff --git a/src/js-components/skipNotice.ts b/src/js-components/skipNotice.ts index b3e9c944..3b740327 100644 --- a/src/js-components/skipNotice.ts +++ b/src/js-components/skipNotice.ts @@ -56,6 +56,9 @@ class SkipNotice { noticeElement.classList.add("sponsorSkipObject"); noticeElement.classList.add("sponsorSkipNotice"); noticeElement.style.zIndex = String(50 + amountOfPreviousNotices); + if (contentContainer().onMobileYouTube) { + noticeElement.style.bottom = "3em"; + } //add mouse enter and leave listeners noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this)); @@ -173,7 +176,8 @@ class SkipNotice { noticeElement.appendChild(secondRow); //get reference node - let referenceNode = document.getElementById("movie_player") || document.querySelector("#player-container .video-js"); + let referenceNode = document.getElementById("player-container-id") + || document.getElementById("movie_player") || document.querySelector("#player-container .video-js"); if (referenceNode == null) { //for embeds let player = document.getElementById("player"); From 5b2a0feccff7299ea5cc3dfd54ddc2c60fa72ce9 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 18:29:02 -0500 Subject: [PATCH 06/16] Switched to new skipping mechanic --- src/content.ts | 162 ++++++++++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/src/content.ts b/src/content.ts index fe12251f..e13bd07c 100644 --- a/src/content.ts +++ b/src/content.ts @@ -15,11 +15,17 @@ utils.wait(() => Config.config !== null, 5000, 10).then(addCSS); var sponsorDataFound = false; var previousVideoID = null; //the actual sponsorTimes if loaded and UUIDs associated with them -var sponsorTimes = null; +var sponsorTimes: number[][] = null; var UUIDs = []; //what video id are these sponsors for var sponsorVideoID = null; +// Skips are scheduled to ensure precision. +// Skips are rescheduled every seeked event. +// Skips are canceled every seeking event +var currentSkipSchedule: NodeJS.Timeout = null; +var seekListenerSetUp = false + //these are sponsors that have been downvoted var hiddenSponsorTimes = []; @@ -416,6 +422,39 @@ function durationChangeListener() { updatePreviewBar(); } +function cancelSponsorSchedule(): void { + if (currentSkipSchedule !== null) { + clearTimeout(currentSkipSchedule); + } +} + +/** + * + * @param currentTime Optional if you don't want to use the actual current time + */ +function startSponsorSchedule(currentTime?: number): void { + cancelSponsorSchedule(); + + if (Config.config.disableSkipping) return; + + if (currentTime === undefined) currentTime = video.currentTime; + + let skipInfo = getNextSkipIndex(currentTime); + + let skipStartTime = skipInfo.array[skipInfo.index][0]; + let timeUntilSponsor = skipStartTime - currentTime; + + currentSkipSchedule = setTimeout(() => { + if (video.currentTime >= skipStartTime) { + skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice); + + startSponsorSchedule(); + } else { + startSponsorSchedule(); + } + }, timeUntilSponsor * 1000 * (1 / video.playbackRate)); +} + function sponsorsLookup(id: string, channelIDPromise?) { video = document.querySelector('video') // Youtube video player //there is no video here @@ -431,6 +470,16 @@ function sponsorsLookup(id: string, channelIDPromise?) { video.addEventListener('durationchange', durationChangeListener); } + if (!seekListenerSetUp && !Config.config.disableSkipping) { + seekListenerSetUp = true; + + video.addEventListener('seeked', () => startSponsorSchedule()); + video.addEventListener('play', () => startSponsorSchedule()); + video.addEventListener('ratechange', () => startSponsorSchedule()); + video.addEventListener('seeking', cancelSponsorSchedule); + video.addEventListener('pause', cancelSponsorSchedule); + } + if (channelIDPromise !== undefined) { if (channelIDPromise.isFulfilled) { whitelistCheck(); @@ -481,6 +530,19 @@ function sponsorsLookup(id: string, channelIDPromise?) { UUIDs = smallUUIDs; } + // See if there are any zero second sponsors + let zeroSecondSponsor = false; + for (const time of sponsorTimes) { + if (time[0] <= 0) { + zeroSecondSponsor = true; + break; + } + } + + if (zeroSecondSponsor) { + startSponsorSchedule(0); + } + // Reset skip save sponsorSkipped = []; @@ -528,13 +590,6 @@ function sponsorsLookup(id: string, channelIDPromise?) { sponsorLookupRetries++; } }); - - //add the event to run on the videos "ontimeupdate" - if (!Config.config.disableSkipping) { - video.ontimeupdate = function () { - sponsorCheck(); - }; - } } function getYouTubeVideoID(url: string) { @@ -673,76 +728,45 @@ function whitelistCheck() { } } -//video skipping -function sponsorCheck() { - if (Config.config.disableSkipping) { - // Make sure this isn't called again - video.ontimeupdate = null; - return; - } else if (channelWhitelisted) { - return; - } +/** + * Returns info about the next upcoming sponsor skip + */ +function getNextSkipIndex(currentTime: number): {array: number[][], index: number, openNotice: boolean} { + let sponsorStartTimes = getStartTimes(sponsorTimes); + let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, currentTime, true); - // Don't skip right after duration change (the time resets to zero) 400ms - if (Date.now() - lastDurationChange < 400000 && lastTime > 1) return; + let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime)); - let skipHappened = false; + // TOOD: support preview sponsors - if (sponsorTimes != null) { - //see if any sponsor start time was just passed - for (let i = 0; i < sponsorTimes.length; i++) { - //if something was skipped - if (checkSponsorTime(sponsorTimes, i, true)) { - skipHappened = true; - break; - } - } - } - - if (!skipHappened) { - //check for the "preview" sponsors (currently edited by this user) - for (let i = 0; i < sponsorTimesSubmitting.length; i++) { - //must be a finished sponsor and be valid - if (sponsorTimesSubmitting[i].length > 1 && sponsorTimesSubmitting[i][1] > sponsorTimesSubmitting[i][0]) { - checkSponsorTime(sponsorTimesSubmitting, i, false); - } - } - } - - //don't keep track until they are loaded in - if (sponsorTimes !== null || sponsorTimesSubmitting.length > 0) { - lastTime = video.currentTime; - } + return { + array: sponsorTimes, + index: minSponsorTimeIndex, + openNotice: true + }; } -function checkSponsorTime(sponsorTimes, index, openNotice): boolean { - //this means part of the video was just skipped - if (Math.abs(video.currentTime - lastTime) > 1 && lastTime != -1) { - //make lastTime as if the video was playing normally - lastTime = video.currentTime - 0.0001; +/** + * Gets just the start times from a sponsor times array. + * Optionally specify a minimum + * + * @param sponsorTimes + * @param minimum + * @param hideHiddenSponsors + */ +function getStartTimes(sponsorTimes: number[][], minimum?: number, hideHiddenSponsors: boolean = false): number[] { + let startTimes: number[] = []; + + for (let i = 0; i < sponsorTimes.length; i++) { + if ((minimum === undefined || sponsorTimes[i][0] >= minimum) && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) { + startTimes.push(sponsorTimes[i][0]); + } } - if (checkIfTimeToSkip(video.currentTime, sponsorTimes[index][0], sponsorTimes[index][1]) && !hiddenSponsorTimes.includes(index)) { - //skip it - skipToTime(video, index, sponsorTimes, openNotice); - - //something was skipped - return true; - } - - return false; + return startTimes; } -function checkIfTimeToSkip(currentVideoTime, startTime, endTime) { - //If the sponsor time is in between these times, skip it - //Checks if the last time skipped to is not too close to now, to make sure not to get too many - // sponsor times in a row (from one troll) - //the last term makes 0 second start times possible only if the video is not setup to start at a different time from zero - return (Math.abs(currentVideoTime - startTime) < 3 && startTime >= lastTime && startTime <= currentVideoTime) || - (lastTime == -1 && startTime == 0 && currentVideoTime < endTime) -} - -//skip fromt he start time to the end time for a certain index sponsor time +//skip from fhe start time to the end time for a certain index sponsor time function skipToTime(v, index, sponsorTimes, openNotice) { if (!Config.config.disableAutoSkip || previewResetter !== null) { v.currentTime = sponsorTimes[index][1]; From b681f5abd976306b08d312d70fb9c3057e39573f Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 18:43:45 -0500 Subject: [PATCH 07/16] Added support for preview sponsors in new skipping method. --- src/content.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/content.ts b/src/content.ts index e13bd07c..8d06bb66 100644 --- a/src/content.ts +++ b/src/content.ts @@ -435,7 +435,7 @@ function cancelSponsorSchedule(): void { function startSponsorSchedule(currentTime?: number): void { cancelSponsorSchedule(); - if (Config.config.disableSkipping) return; + if (Config.config.disableSkipping || sponsorTimes === null) return; if (currentTime === undefined) currentTime = video.currentTime; @@ -737,13 +737,24 @@ function getNextSkipIndex(currentTime: number): {array: number[][], index: numbe let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime)); - // TOOD: support preview sponsors + let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting); + let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, currentTime, false); - return { - array: sponsorTimes, - index: minSponsorTimeIndex, - openNotice: true - }; + let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime)); + + if (minPreviewSponsorTimeIndex == -1 || sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) { + return { + array: sponsorTimes, + index: minSponsorTimeIndex, + openNotice: true + }; + } else { + return { + array: sponsorTimesSubmitting, + index: minPreviewSponsorTimeIndex, + openNotice: false + }; + } } /** From 6cd2d4cf83ce0f471242002b7a1ece1fd35fbbaf Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 18:44:06 -0500 Subject: [PATCH 08/16] Added back whitelist support --- src/content.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/content.ts b/src/content.ts index 8d06bb66..07ff57f8 100644 --- a/src/content.ts +++ b/src/content.ts @@ -435,17 +435,19 @@ function cancelSponsorSchedule(): void { function startSponsorSchedule(currentTime?: number): void { cancelSponsorSchedule(); - if (Config.config.disableSkipping || sponsorTimes === null) return; + if (sponsorTimes === null || Config.config.disableSkipping || channelWhitelisted){ + return; + } if (currentTime === undefined) currentTime = video.currentTime; let skipInfo = getNextSkipIndex(currentTime); - let skipStartTime = skipInfo.array[skipInfo.index][0]; - let timeUntilSponsor = skipStartTime - currentTime; + let skipTime = skipInfo.array[skipInfo.index]; + let timeUntilSponsor = skipTime[0] - currentTime; currentSkipSchedule = setTimeout(() => { - if (video.currentTime >= skipStartTime) { + if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) { skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice); startSponsorSchedule(); From d58cd639c7460f879c697cc65e8dd66efd57cb79 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 18:45:33 -0500 Subject: [PATCH 09/16] Added zero second preview sponsors. --- src/content.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/content.ts b/src/content.ts index 07ff57f8..2c5a413e 100644 --- a/src/content.ts +++ b/src/content.ts @@ -540,6 +540,14 @@ function sponsorsLookup(id: string, channelIDPromise?) { break; } } + if (!zeroSecondSponsor) { + for (const time of sponsorTimesSubmitting) { + if (time[0] <= 0) { + zeroSecondSponsor = true; + break; + } + } + } if (zeroSecondSponsor) { startSponsorSchedule(0); From 186938216639493c5dbede4d437d146761f5c946 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 19:03:34 -0500 Subject: [PATCH 10/16] Fixed popup issues. --- src/content.ts | 3 +++ src/popup.ts | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/content.ts b/src/content.ts index 2c5a413e..d3ecfa99 100644 --- a/src/content.ts +++ b/src/content.ts @@ -953,6 +953,9 @@ function updateSponsorTimesSubmitting() { sponsorTimesSubmitting = sponsorTimes; updatePreviewBar(); + + // Restart skipping schedule + startSponsorSchedule(); } } }); diff --git a/src/popup.ts b/src/popup.ts index c61a0a5d..c29f486a 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -719,17 +719,8 @@ async function runThePopup(messageListener?: MessageListener) { sponsorTimes.splice(index, 1); //save this - Config.config.sponsorTimes.set(currentVideoID, sponsorTimes); - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - {message: "sponsorDataChanged"} - ); - }); - + Config.config.sponsorTimes.set(currentVideoID, sponsorTimes); + //update display displaySponsorTimes(); @@ -750,6 +741,16 @@ async function runThePopup(messageListener?: MessageListener) { //hide submission section document.getElementById("submissionSection").style.display = "none"; } + + messageHandler.query({ + active: true, + currentWindow: true + }, tabs => { + messageHandler.sendMessage( + tabs[0].id, + {message: "sponsorDataChanged"} + ); + }); } function clearTimes() { From 1b25ea7f959d0cc9619f5bb940e76d16255a1efd Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 18 Feb 2020 19:29:20 -0500 Subject: [PATCH 11/16] Shrunk notice on mobile --- src/js-components/skipNotice.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js-components/skipNotice.ts b/src/js-components/skipNotice.ts index 3b740327..9918eec7 100644 --- a/src/js-components/skipNotice.ts +++ b/src/js-components/skipNotice.ts @@ -57,7 +57,8 @@ class SkipNotice { noticeElement.classList.add("sponsorSkipNotice"); noticeElement.style.zIndex = String(50 + amountOfPreviousNotices); if (contentContainer().onMobileYouTube) { - noticeElement.style.bottom = "3em"; + noticeElement.style.bottom = "4em"; + noticeElement.style.zoom = "0.8"; } //add mouse enter and leave listeners From 7dc8a9924748d6e04243be2b3e18d8a141bd6f70 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 19 Feb 2020 00:00:22 -0500 Subject: [PATCH 12/16] Added button support to mobile. --- src/content.ts | 84 +++++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/src/content.ts b/src/content.ts index d3ecfa99..fa3169d7 100644 --- a/src/content.ts +++ b/src/content.ts @@ -357,7 +357,8 @@ async function videoIDChange(id) { } } }); - }); + }); + //see if video controls buttons should be added if (!onInvidious) { updateVisibilityOfPlayerControlsButton(); @@ -366,7 +367,19 @@ async function videoIDChange(id) { function handleMobileControlsMutations(): void { let mobileYouTubeSelector = ".progress-bar-background"; - + + updateVisibilityOfPlayerControlsButton().then((createdButtons) => { + if (createdButtons) { + if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].length >= 2) { + changeStartSponsorButton(true, true); + } else if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].length < 2) { + changeStartSponsorButton(false, true); + } else { + changeStartSponsorButton(true, false); + } + } + }); + if (previewBar !== null) { if (document.body.contains(previewBar.container)) { updatePreviewBarPositionMobile(document.getElementsByClassName(mobileYouTubeSelector)[0]); @@ -696,7 +709,7 @@ function getChannelID() { /** * This function is required on mobile YouTube and will keep getting called whenever the preview bar disapears */ -async function updatePreviewBarPositionMobile(parent: Element) { +function updatePreviewBarPositionMobile(parent: Element) { if (document.getElementById("previewbar") === null) { previewBar.updatePosition(parent); } @@ -838,14 +851,20 @@ function reskipSponsorTime(UUID) { } } -function createButton(baseID, title, callback, imageName, isDraggable=false) { - if (document.getElementById(baseID + "Button") != null) return; +function createButton(baseID, title, callback, imageName, isDraggable=false): boolean { + if (document.getElementById(baseID + "Button") != null) return false; // Button HTML let newButton = document.createElement("button"); newButton.draggable = isDraggable; newButton.id = baseID + "Button"; - newButton.className = "ytp-button playerButton"; + newButton.classList.add("playerButton"); + if (!onMobileYouTube) { + newButton.classList.add("ytp-button"); + } else { + newButton.classList.add("icon-button"); + newButton.style.padding = "0"; + } newButton.setAttribute("title", chrome.i18n.getMessage(title)); newButton.addEventListener("click", callback); @@ -861,6 +880,8 @@ function createButton(baseID, title, callback, imageName, isDraggable=false) { // Add the button to player controls.prepend(newButton); + + return true; } function getControls(): HTMLElement | boolean { @@ -868,7 +889,7 @@ function getControls(): HTMLElement | boolean { // YouTube ".ytp-right-controls", // Mobile YouTube - "#player-control-overlay", + ".player-controls-top", // Invidious/videojs video element's controls element ".vjs-control-bar" ] @@ -885,26 +906,31 @@ function getControls(): HTMLElement | boolean { }; //adds all the player controls buttons -async function createButtons() { +async function createButtons(): Promise { let result = await utils.wait(getControls).catch(); //set global controls variable controls = result; - // Add button if does not already exist in html - createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png"); - createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png") - createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png"); - createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png"); -} -//adds or removes the player controls button to what it should be -async function updateVisibilityOfPlayerControlsButton() { - //not on a proper video yet - if (!sponsorVideoID) return; + let createdButton = false; - await createButtons(); - - if (Config.config.hideVideoPlayerControls || onInvidious || onMobileYouTube) { + // Add button if does not already exist in html + createdButton = createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png") || createdButton; + createdButton = createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png") || createdButton; + createdButton = createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png") || createdButton; + createdButton = createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png") || createdButton; + + return createdButton; +} + +//adds or removes the player controls button to what it should be +async function updateVisibilityOfPlayerControlsButton(): Promise { + //not on a proper video yet + if (!sponsorVideoID) return false; + + let createdButtons = await createButtons(); + + if (Config.config.hideVideoPlayerControls || onInvidious) { document.getElementById("startSponsorButton").style.display = "none"; document.getElementById("submitButton").style.display = "none"; } else { @@ -912,15 +938,17 @@ async function updateVisibilityOfPlayerControlsButton() { } //don't show the info button on embeds - if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious || onMobileYouTube) { + if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) { document.getElementById("infoButton").style.display = "none"; } else { document.getElementById("infoButton").style.removeProperty("display"); } - if (Config.config.hideDeleteButtonPlayerControls || onInvidious || onMobileYouTube) { + if (Config.config.hideDeleteButtonPlayerControls || onInvidious) { document.getElementById("deleteButton").style.display = "none"; } + + return createdButtons; } function startSponsorClicked() { @@ -961,19 +989,11 @@ function updateSponsorTimesSubmitting() { }); } -//is the submit button on the player loaded yet -function isSubmitButtonLoaded() { - return document.getElementById("submitButton") !== null; -} - async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) { if(!sponsorVideoID) return false; - //make sure submit button is loaded - await utils.wait(isSubmitButtonLoaded); - //if it isn't visible, there is no data - let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious || onMobileYouTube)) ? "unset" : "none" + let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none" document.getElementById("deleteButton").style.display = shouldHide; if (showStartSponsor) { From 2039bfa0818c2e4ab49c301f1db577ee0a6547d6 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 19 Feb 2020 00:10:05 -0500 Subject: [PATCH 13/16] Made buttons on mobile not close the menu. --- src/content.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/content.ts b/src/content.ts index fa3169d7..2965d0dd 100644 --- a/src/content.ts +++ b/src/content.ts @@ -866,7 +866,12 @@ function createButton(baseID, title, callback, imageName, isDraggable=false): bo newButton.style.padding = "0"; } newButton.setAttribute("title", chrome.i18n.getMessage(title)); - newButton.addEventListener("click", callback); + newButton.addEventListener("click", (event: Event) => { + callback(); + + // Prevents the contols from closing when clicked + if (onMobileYouTube) event.stopPropagation(); + }); // Image HTML let newButtonImage = document.createElement("img"); From 2e212e6d10152b6fae5e6b7ff92a7626dfda5c86 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 19 Feb 2020 00:14:08 -0500 Subject: [PATCH 14/16] Improved mobile preview bar --- src/js-components/previewBar.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js-components/previewBar.ts b/src/js-components/previewBar.ts index febeaa25..f1812aa2 100644 --- a/src/js-components/previewBar.ts +++ b/src/js-components/previewBar.ts @@ -44,6 +44,8 @@ class PreviewBar { if (this.onMobileYouTube) { parent.style.backgroundColor = "rgba(255, 255, 255, 0.3)"; parent.style.opacity = "1"; + + this.container.style.transform = "none"; } //on the seek bar From 20e90bbc346c071caa1c113afab1b2db01988d64 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 19 Feb 2020 00:54:30 -0500 Subject: [PATCH 15/16] Fixed schedule not updating when new sponsors arrive --- src/content.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content.ts b/src/content.ts index 2965d0dd..6433c905 100644 --- a/src/content.ts +++ b/src/content.ts @@ -564,6 +564,8 @@ function sponsorsLookup(id: string, channelIDPromise?) { if (zeroSecondSponsor) { startSponsorSchedule(0); + } else { + startSponsorSchedule(); } // Reset skip save From 50862e3c035180ee1b056ba9fcd281fcaeb24aef Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 19 Feb 2020 11:25:14 -0500 Subject: [PATCH 16/16] Increased version number --- manifest/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest/manifest.json b/manifest/manifest.json index 7de46a8c..2645d1c0 100644 --- a/manifest/manifest.json +++ b/manifest/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_fullName__", "short_name": "__MSG_Name__", - "version": "1.2.13", + "version": "1.2.14", "default_locale": "en", "description": "__MSG_Description__", "content_scripts": [{