From 9b8f9dfbaec462bef29c12064efa8bd5202c4fc0 Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Sun, 1 Mar 2020 21:42:23 -0600 Subject: [PATCH 1/8] Added ratechange blocklist to fix #72 #521 and #584 --- inject.js | 93 ++++++++++++++++++++++++++++++++++++++++----------- manifest.json | 3 +- options.html | 24 ++++++++++--- options.js | 30 +++++++++++++++-- 4 files changed, 122 insertions(+), 28 deletions(-) diff --git a/inject.js b/inject.js index d059564..04816af 100644 --- a/inject.js +++ b/inject.js @@ -18,7 +18,12 @@ var tc = { vine.co imgur.com teams.microsoft.com - `.replace(regStrip, "") + `.replace(regStrip, ""), + blacklistrc: `\ + twitch.tv + pluralsight.com + teamtreehouse.com + `.replace(regStrip, "") } }; @@ -80,7 +85,8 @@ chrome.storage.sync.get(tc.settings, function(storage) { startHidden: tc.settings.startHidden, enabled: tc.settings.enabled, controllerOpacity: tc.settings.controllerOpacity, - blacklist: tc.settings.blacklist.replace(regStrip, "") + blacklist: tc.settings.blacklist.replace(regStrip, ""), + blacklistrc: tc.settings.blacklistrc.replace(regStrip, "") }); } tc.settings.lastSpeed = Number(storage.lastSpeed); @@ -91,6 +97,7 @@ chrome.storage.sync.get(tc.settings, function(storage) { tc.settings.startHidden = Boolean(storage.startHidden); tc.settings.controllerOpacity = Number(storage.controllerOpacity); tc.settings.blacklist = String(storage.blacklist); + tc.settings.blacklistrc = String(storage.blacklistrc); // ensure that there is a "display" binding (for upgrades from versions that had it as a separate binding) if (tc.settings.keyBindings.filter(x => x.action == "display").length == 0) { @@ -306,13 +313,13 @@ function defineVideoController() { }; } -function initializeWhenReady(document) { - escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; - function escapeStringRegExp(str) { - return str.replace(escapeStringRegExp.matchOperatorsRe, "\\$&"); - } +function escapeStringRegExp(str) { + matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; + return str.replace(matchOperatorsRe, "\\$&"); +} - var blacklisted = false; +function isBlacklisted() { + blacklisted = false; tc.settings.blacklist.split("\n").forEach(match => { match = match.replace(regStrip, ""); if (match.length == 0) { @@ -334,9 +341,46 @@ function initializeWhenReady(document) { return; } }); + return blacklisted; +} - if (blacklisted) return; +function isRateChangeBlocked() { + blockRateChange = false; + tc.settings.blacklistrc.split("\n").forEach(match => { + match = match.replace(regStrip, ""); + if (match.length == 0) { + return; + } + if (match.startsWith("/")) { + try { + var regexp = new RegExp(match); + } catch (err) { + return; + } + } else { + var regexp = new RegExp(escapeStringRegExp(match)); + } + if (regexp.test(location.href)) { + blockRateChange = true; + return; + } + }); + return blockRateChange; +} +function initializeWhenReady(document) { + if (isBlacklisted()) { + return; + } + if (isRateChangeBlocked()) { + document.body.addEventListener( + "ratechange", + function(event) { + event.stopImmediatePropagation(); + }, + true + ); + } window.onload = () => { initializeNow(window.document); }; @@ -502,8 +546,10 @@ function initializeNow(document) { }); break; case "attributes": - if (mutation.target.attributes["aria-hidden"] && - mutation.target.attributes["aria-hidden"].value == "false") { + if ( + mutation.target.attributes["aria-hidden"] && + mutation.target.attributes["aria-hidden"].value == "false" + ) { var flattenedNodes = getShadow(document.body); var node = flattenedNodes.filter(x => x.tagName == "VIDEO")[0]; if (node) { @@ -551,6 +597,13 @@ function initializeNow(document) { }); } +function setSpeed(controller, video, speed) { + var speedvalue = speed.toFixed(2); + video.playbackRate = Number(speedvalue); + var speedIndicator = controller.shadowRoot.querySelector("span"); + speedIndicator.textContent = speedvalue; +} + function runAction(action, document, value, e) { if (tc.settings.audioBoolean) { var mediaTags = getShadow(document.body).filter(x => { @@ -592,14 +645,14 @@ function runAction(action, document, value, e) { (v.playbackRate < 0.1 ? 0.0 : v.playbackRate) + value, 16 ); - v.playbackRate = Number(s.toFixed(2)); + setSpeed(controller, v, s); } else if (action === "slower") { // Video min rate is 0.0625: // https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/media/html_media_element.cc?gsn=kMinRate&l=165 var s = Math.max(v.playbackRate - value, 0.07); - v.playbackRate = Number(s.toFixed(2)); + setSpeed(controller, v, s); } else if (action === "reset") { - resetSpeed(v, 1.0); + resetSpeed(v, controller, 1.0); } else if (action === "display") { controller.classList.add("vsc-manual"); controller.classList.toggle("vsc-hidden"); @@ -622,7 +675,7 @@ function runAction(action, document, value, e) { } else if (action === "drag") { handleDrag(v, controller, e); } else if (action === "fast") { - resetSpeed(v, value); + resetSpeed(v, controller, value); } else if (action === "pause") { pause(v); } else if (action === "muted") { @@ -644,21 +697,21 @@ function pause(v) { } } -function resetSpeed(v, target) { +function resetSpeed(v, controller, target) { if (v.playbackRate === target) { if (v.playbackRate === getKeyBindings("reset")) { // resetSpeed if (target !== 1.0) { - v.playbackRate = 1.0; + setSpeed(controller, v, 1.0); } else { - v.playbackRate = getKeyBindings("fast"); // fastSpeed + setSpeed(controller, v, getKeyBindings("fast")); // fastSpeed } } else { - v.playbackRate = getKeyBindings("reset"); // resetSpeed + setSpeed(controller, v, getKeyBindings("reset")); // resetSpeed } } else { setKeyBindings("reset", v.playbackRate); // resetSpeed - v.playbackRate = target; + setSpeed(controller, v, target); } } diff --git a/manifest.json b/manifest.json index 021f792..f489342 100755 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Video Speed Controller", "short_name": "videospeed", - "version": "0.6.0", + "version": "0.6.1", "manifest_version": 2, "description": "Speed up, slow down, advance and rewind any HTML5 video with quick shortcuts.", "homepage_url": "https://github.com/igrigorik/videospeed", @@ -29,7 +29,6 @@ "https://plus.google.com/hangouts/*", "https://hangouts.google.com/*", "https://meet.google.com/*", - "https://teamtreehouse.com/*", "http://www.hitbox.tv/*" ], "css": ["inject.css"], diff --git a/options.html b/options.html index 36c9f3c..2ab49bc 100644 --- a/options.html +++ b/options.html @@ -160,14 +160,30 @@ >Blacklisted sites on which extension is disabled
(one per line)

- Regex is supported. Be sure + + Regex is supported. Be sure it is in "//g" format.
- ie: /(.+)youtube\.com(\/*)$/gi
+ ie: /(.+)youtube\.com(\/*)$/gi +
+
+ + +
diff --git a/options.js b/options.js index 865195f..657b8ad 100644 --- a/options.js +++ b/options.js @@ -23,6 +23,11 @@ var tcDefaults = { vine.co imgur.com teams.microsoft.com + `.replace(regStrip, ""), + blacklistrc: `\ + twitch.tv + pluralsight.com + teamtreehouse.com `.replace(regStrip, "") }; @@ -191,7 +196,25 @@ function validate() { var regexp = new RegExp(match); } catch (err) { status.textContent = - "Error: Invalid Regex: " + match + ". Unable to save"; + "Error: Invalid blacklist regex: " + match + ". Unable to save"; + valid = false; + return; + } + } + }); + document + .getElementById("blacklistrc") + .value.split("\n") + .forEach(match => { + match = match.replace(regStrip, ""); + if (match.startsWith("/")) { + try { + var regexp = new RegExp(match); + } catch (err) { + status.textContent = + "Error: Invalid ratechange blacklist regex: " + + match + + ". Unable to save"; valid = false; return; } @@ -216,6 +239,7 @@ function save_options() { var startHidden = document.getElementById("startHidden").checked; var controllerOpacity = document.getElementById("controllerOpacity").value; var blacklist = document.getElementById("blacklist").value; + var blacklistrc = document.getElementById("blacklistrc").value; chrome.storage.sync.remove([ "resetSpeed", @@ -238,7 +262,8 @@ function save_options() { startHidden: startHidden, controllerOpacity: controllerOpacity, keyBindings: keyBindings, - blacklist: blacklist.replace(regStrip, "") + blacklist: blacklist.replace(regStrip, ""), + blacklistrc: blacklistrc.replace(regStrip, "") }, function() { // Update status to let user know options were saved. @@ -261,6 +286,7 @@ function restore_options() { document.getElementById("controllerOpacity").value = storage.controllerOpacity; document.getElementById("blacklist").value = storage.blacklist; + document.getElementById("blacklistrc").value = storage.blacklistrc; // ensure that there is a "display" binding for upgrades from versions that had it as a separate binding if (storage.keyBindings.filter(x => x.action == "display").length == 0) { From dde52368a23cc7c4fb429acf63b31b44faf76ba7 Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Tue, 3 Mar 2020 22:33:19 -0600 Subject: [PATCH 2/8] Far better fix now utilizes a short cooldown window after issuing a speed change command --- inject.js | 58 ++++++++++++++++++---------------------------------- options.html | 16 --------------- options.js | 28 +------------------------ 3 files changed, 21 insertions(+), 81 deletions(-) diff --git a/inject.js b/inject.js index 04816af..be775b6 100644 --- a/inject.js +++ b/inject.js @@ -18,11 +18,6 @@ var tc = { vine.co imgur.com teams.microsoft.com - `.replace(regStrip, ""), - blacklistrc: `\ - twitch.tv - pluralsight.com - teamtreehouse.com `.replace(regStrip, "") } }; @@ -85,8 +80,7 @@ chrome.storage.sync.get(tc.settings, function(storage) { startHidden: tc.settings.startHidden, enabled: tc.settings.enabled, controllerOpacity: tc.settings.controllerOpacity, - blacklist: tc.settings.blacklist.replace(regStrip, ""), - blacklistrc: tc.settings.blacklistrc.replace(regStrip, "") + blacklist: tc.settings.blacklist.replace(regStrip, "") }); } tc.settings.lastSpeed = Number(storage.lastSpeed); @@ -97,7 +91,6 @@ chrome.storage.sync.get(tc.settings, function(storage) { tc.settings.startHidden = Boolean(storage.startHidden); tc.settings.controllerOpacity = Number(storage.controllerOpacity); tc.settings.blacklist = String(storage.blacklist); - tc.settings.blacklistrc = String(storage.blacklistrc); // ensure that there is a "display" binding (for upgrades from versions that had it as a separate binding) if (tc.settings.keyBindings.filter(x => x.action == "display").length == 0) { @@ -344,43 +337,31 @@ function isBlacklisted() { return blacklisted; } -function isRateChangeBlocked() { - blockRateChange = false; - tc.settings.blacklistrc.split("\n").forEach(match => { - match = match.replace(regStrip, ""); - if (match.length == 0) { - return; - } - if (match.startsWith("/")) { - try { - var regexp = new RegExp(match); - } catch (err) { - return; - } - } else { - var regexp = new RegExp(escapeStringRegExp(match)); - } - if (regexp.test(location.href)) { - blockRateChange = true; - return; - } - }); - return blockRateChange; +var coolDown = false; +function refreshCoolDown() { + if (coolDown) { + clearTimeout(coolDown); + } + coolDown = setTimeout(function() { + coolDown = false; + }, 1000); } function initializeWhenReady(document) { if (isBlacklisted()) { return; } - if (isRateChangeBlocked()) { - document.body.addEventListener( - "ratechange", - function(event) { + document.body.addEventListener( + "ratechange", + function(event) { + if (coolDown) { + refreshCoolDown(); + console.log("Speed event propagation blocked"); event.stopImmediatePropagation(); - }, - true - ); - } + } + }, + true + ); window.onload = () => { initializeNow(window.document); }; @@ -602,6 +583,7 @@ function setSpeed(controller, video, speed) { video.playbackRate = Number(speedvalue); var speedIndicator = controller.shadowRoot.querySelector("span"); speedIndicator.textContent = speedvalue; + refreshCoolDown(); } function runAction(action, document, value, e) { diff --git a/options.html b/options.html index 2ab49bc..eb979bb 100644 --- a/options.html +++ b/options.html @@ -168,22 +168,6 @@ -
- - -
diff --git a/options.js b/options.js index 657b8ad..cc1acab 100644 --- a/options.js +++ b/options.js @@ -23,11 +23,6 @@ var tcDefaults = { vine.co imgur.com teams.microsoft.com - `.replace(regStrip, ""), - blacklistrc: `\ - twitch.tv - pluralsight.com - teamtreehouse.com `.replace(regStrip, "") }; @@ -202,24 +197,6 @@ function validate() { } } }); - document - .getElementById("blacklistrc") - .value.split("\n") - .forEach(match => { - match = match.replace(regStrip, ""); - if (match.startsWith("/")) { - try { - var regexp = new RegExp(match); - } catch (err) { - status.textContent = - "Error: Invalid ratechange blacklist regex: " + - match + - ". Unable to save"; - valid = false; - return; - } - } - }); return valid; } @@ -239,7 +216,6 @@ function save_options() { var startHidden = document.getElementById("startHidden").checked; var controllerOpacity = document.getElementById("controllerOpacity").value; var blacklist = document.getElementById("blacklist").value; - var blacklistrc = document.getElementById("blacklistrc").value; chrome.storage.sync.remove([ "resetSpeed", @@ -262,8 +238,7 @@ function save_options() { startHidden: startHidden, controllerOpacity: controllerOpacity, keyBindings: keyBindings, - blacklist: blacklist.replace(regStrip, ""), - blacklistrc: blacklistrc.replace(regStrip, "") + blacklist: blacklist.replace(regStrip, "") }, function() { // Update status to let user know options were saved. @@ -286,7 +261,6 @@ function restore_options() { document.getElementById("controllerOpacity").value = storage.controllerOpacity; document.getElementById("blacklist").value = storage.blacklist; - document.getElementById("blacklistrc").value = storage.blacklistrc; // ensure that there is a "display" binding for upgrades from versions that had it as a separate binding if (storage.keyBindings.filter(x => x.action == "display").length == 0) { From 00781ceaa3124089fbababc1548376561fd614b1 Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Thu, 5 Mar 2020 19:08:30 -0600 Subject: [PATCH 3/8] Moved logic in rate change event listener into its own function to be triggered by setSpeed() --- inject.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/inject.js b/inject.js index be775b6..e1d989e 100644 --- a/inject.js +++ b/inject.js @@ -171,16 +171,7 @@ function defineVideoController() { // Ignore ratechange events on unitialized videos. // 0 == No information is available about the media resource. if (event.target.readyState > 0) { - var speed = this.getSpeed(); - this.speedIndicator.textContent = speed; - tc.settings.speeds[this.video.currentSrc] = speed; - tc.settings.lastSpeed = speed; - this.speed = speed; - chrome.storage.sync.set({ lastSpeed: speed }, function() { - console.log("Speed setting saved: " + speed); - }); - // show the controller for 1000ms if it's hidden. - runAction("blink", document, null, null); + rateChanged(this); } }.bind(this)) ); @@ -586,6 +577,19 @@ function setSpeed(controller, video, speed) { refreshCoolDown(); } +function rateChanged(controller) { + var speed = parseFloat(controller.video.playbackRate).toFixed(2); + controller.speedIndicator.textContent = speed; + tc.settings.speeds[controller.video.currentSrc] = speed; + tc.settings.lastSpeed = speed; + controller.speed = speed; + chrome.storage.sync.set({ lastSpeed: speed }, function() { + console.log("Speed setting saved: " + speed); + }); + // show the controller for 1000ms if it's hidden. + runAction("blink", document, null, null); +} + function runAction(action, document, value, e) { if (tc.settings.audioBoolean) { var mediaTags = getShadow(document.body).filter(x => { From 588a04fe581bc1b9f27a9e831c20317bfd460a05 Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Fri, 6 Mar 2020 18:26:04 -0600 Subject: [PATCH 4/8] Added node_modules to .gitignore - We may or may not use later, but no harm in adding --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 03c6b3a..4686867 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ local # IntelliJ IDEA .idea/ +node_modules From 73d5673031d4c2edf3915bcf041f290931fe521c Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Fri, 6 Mar 2020 19:59:04 -0600 Subject: [PATCH 5/8] Fixed issue preventing last speed from being properly stored --- inject.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/inject.js b/inject.js index e1d989e..6ec1154 100644 --- a/inject.js +++ b/inject.js @@ -171,7 +171,7 @@ function defineVideoController() { // Ignore ratechange events on unitialized videos. // 0 == No information is available about the media resource. if (event.target.readyState > 0) { - rateChanged(this); + rateChanged(this.div); } }.bind(this)) ); @@ -346,7 +346,6 @@ function initializeWhenReady(document) { "ratechange", function(event) { if (coolDown) { - refreshCoolDown(); console.log("Speed event propagation blocked"); event.stopImmediatePropagation(); } @@ -572,17 +571,19 @@ function initializeNow(document) { function setSpeed(controller, video, speed) { var speedvalue = speed.toFixed(2); video.playbackRate = Number(speedvalue); - var speedIndicator = controller.shadowRoot.querySelector("span"); - speedIndicator.textContent = speedvalue; refreshCoolDown(); + rateChanged(controller); } function rateChanged(controller) { - var speed = parseFloat(controller.video.playbackRate).toFixed(2); - controller.speedIndicator.textContent = speed; - tc.settings.speeds[controller.video.currentSrc] = speed; + var speedIndicator = controller.shadowRoot.querySelector("span"); + var video = controller.parentElement.querySelector("video"); + var src = video.currentSrc; + var speed = video.playbackRate.toFixed(2); + + speedIndicator.textContent = speed; + tc.settings.speeds[src] = speed; tc.settings.lastSpeed = speed; - controller.speed = speed; chrome.storage.sync.set({ lastSpeed: speed }, function() { console.log("Speed setting saved: " + speed); }); From ff3ea3113bf784abe08196c32db8809ca8337b4a Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Fri, 6 Mar 2020 22:44:01 -0600 Subject: [PATCH 6/8] Added logging function and logging entries Moved all on ratechange logic to document level listener Removed dead .getSpeed method Fixed bug causing controller to sometimes initialize with NaN --- inject.js | 148 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 39 deletions(-) diff --git a/inject.js b/inject.js index 6ec1154..3c7c308 100644 --- a/inject.js +++ b/inject.js @@ -18,10 +18,41 @@ var tc = { vine.co imgur.com teams.microsoft.com - `.replace(regStrip, "") + `.replace(regStrip, ""), + defaultLogLevel: 4, + logLevel: 3 } }; +/* Log levels (depends on caller specifying the correct level) + 1 - none + 2 - error + 3 - warning + 4 - info + 5 - debug + 6 - debug high verbosity + stack trace on each message +*/ +function log(message, level) { + verbosity = tc.settings.logLevel; + if (typeof level === "undefined") { + level = tc.settings.defaultLogLevel; + } + if (verbosity >= level) { + if (level === 2) { + console.log("ERROR:" + message); + } else if (level === 3) { + console.log("WARNING:" + message); + } else if (level === 4) { + console.log("INFO:" + message); + } else if (level === 5) { + console.log("DEBUG:" + message); + } else if (level === 6) { + console.log("DEBUG (VERBOSE):" + message); + console.trace(); + } + } +} + chrome.storage.sync.get(tc.settings, function(storage) { tc.settings.keyBindings = storage.keyBindings; // Array if (storage.keyBindings.length == 0) { @@ -132,47 +163,54 @@ function defineVideoController() { this.id = Math.random() .toString(36) .substr(2, 9); - - // settings.speeds[] ensures that same source used across video tags (e.g. fullscreen on YT) retains speed setting - // this.speed is a controller level variable that retains speed setting across source switches (e.g. video quality, playlist change) - this.speed = 1.0; - + storedSpeed = tc.settings.speeds[target.currentSrc]; if (!tc.settings.rememberSpeed) { - if (!tc.settings.speeds[target.currentSrc]) { - tc.settings.speeds[target.currentSrc] = this.speed; + if (!storedSpeed) { + log( + "Overwriting stored speed to 1.0 due to rememberSpeed being disabled", + 5 + ); + storedSpeed = 1.0; } setKeyBindings("reset", getKeyBindings("fast")); // resetSpeed = fastSpeed } else { - tc.settings.speeds[target.currentSrc] = tc.settings.lastSpeed; + log("Recalling stored speed due to rememberSpeed being enabled", 5); + storedSpeed = tc.settings.lastSpeed; } - target.playbackRate = tc.settings.speeds[target.currentSrc]; + log("Explicitly setting playbackRate to: " + storedSpeed, 5); + target.playbackRate = storedSpeed; this.div = this.initializeControls(); target.addEventListener( "play", (this.handlePlay = function(event) { + storedSpeed = tc.settings.speeds[event.target.currentSrc]; if (!tc.settings.rememberSpeed) { - if (!tc.settings.speeds[target.currentSrc]) { - tc.settings.speeds[target.currentSrc] = this.speed; + if (!storedSpeed) { + log( + "Overwriting stored speed to 1.0 (rememberSpeed not enabled)", + 4 + ); + storedSpeed = 1.0; } + // resetSpeed isn't really a reset, it's a toggle + log("Setting reset keybinding to fast", 5); setKeyBindings("reset", getKeyBindings("fast")); // resetSpeed = fastSpeed } else { - tc.settings.speeds[target.currentSrc] = tc.settings.lastSpeed; - } - target.playbackRate = tc.settings.speeds[target.currentSrc]; - }.bind(this)) - ); - - target.addEventListener( - "ratechange", - (this.handleRatechange = function(event) { - // Ignore ratechange events on unitialized videos. - // 0 == No information is available about the media resource. - if (event.target.readyState > 0) { - rateChanged(this.div); + log( + "Storing lastSpeed into tc.settings.speeds (rememberSpeed enabled)", + 5 + ); + storedSpeed = tc.settings.lastSpeed; } + // TODO: Check if explicitly setting the playback rate to 1.0 is + // necessary when rememberSpeed is disabled (this may accidentally + // override a website's intentional initial speed setting interfering + // with the site's default behavior) + log("Explicitly setting playbackRate to: " + storedSpeed, 4); + event.target.playbackRate = storedSpeed; }.bind(this)) ); @@ -200,26 +238,22 @@ function defineVideoController() { }); }; - tc.videoController.prototype.getSpeed = function() { - return parseFloat(this.video.playbackRate).toFixed(2); - }; - tc.videoController.prototype.remove = function() { this.div.remove(); this.video.removeEventListener("play", this.handlePlay); - this.video.removeEventListener("ratechange", this.handleRatechange); delete this.video.dataset["vscid"]; delete this.video.vsc; }; tc.videoController.prototype.initializeControls = function() { + log("initializeControls Begin", 5); var document = this.document; - var speed = parseFloat(tc.settings.speeds[this.video.currentSrc]).toFixed( - 2 - ), + var speed = this.video.playbackRate.toFixed(2), top = Math.max(this.video.offsetTop, 0) + "px", left = Math.max(this.video.offsetLeft, 0) + "px"; + log("Speed variable set to: " + speed, 5); + var wrapper = document.createElement("div"); wrapper.classList.add("vsc-controller"); wrapper.dataset["vscid"] = this.id; @@ -330,23 +364,28 @@ function isBlacklisted() { var coolDown = false; function refreshCoolDown() { + log("Begin refreshCoolDown", 5); if (coolDown) { clearTimeout(coolDown); } coolDown = setTimeout(function() { coolDown = false; }, 1000); + log("End refreshCoolDown", 5); } function initializeWhenReady(document) { + log("Begin initializeWhenReady", 5); if (isBlacklisted()) { return; } document.body.addEventListener( "ratechange", function(event) { + controller = event.target.parentElement.querySelector(".vsc-controller"); + rateChanged(controller); if (coolDown) { - console.log("Speed event propagation blocked"); + log("Speed event propagation blocked", 4); event.stopImmediatePropagation(); } }, @@ -366,6 +405,7 @@ function initializeWhenReady(document) { }; } } + log("End initializeWhenReady", 5); } function inIframe() { try { @@ -403,12 +443,14 @@ function getController(id) { } function initializeNow(document) { + log("Begin initializeNow", 5); if (!tc.settings.enabled) return; // enforce init-once due to redundant callers if (!document.body || document.body.classList.contains("vsc-initialized")) { return; } document.body.classList.add("vsc-initialized"); + log("initializeNow: vsc-initialized added to document body", 5); if (document === window.document) { defineVideoController(); @@ -429,6 +471,7 @@ function initializeNow(document) { "keydown", function(event) { var keyCode = event.keyCode; + log("Processing keydown event: " + keyCode, 6); // Ignore if following modifier is active. if ( @@ -440,6 +483,7 @@ function initializeNow(document) { event.getModifierState("Hyper") || event.getModifierState("OS") ) { + log("Keydown event ignored due to active modifier: " + keyCode, 5); return; } @@ -566,13 +610,16 @@ function initializeNow(document) { } initializeWhenReady(childDocument); }); + log("End initializeNow", 5); } function setSpeed(controller, video, speed) { + log("setSpeed started: " + speed, 5); var speedvalue = speed.toFixed(2); video.playbackRate = Number(speedvalue); refreshCoolDown(); rateChanged(controller); + log("setSpeed finished: " + speed, 5); } function rateChanged(controller) { @@ -581,17 +628,23 @@ function rateChanged(controller) { var src = video.currentSrc; var speed = video.playbackRate.toFixed(2); + log("Playback rate changed to " + speed, 4); + + log("Updating controller with new speed", 5); speedIndicator.textContent = speed; tc.settings.speeds[src] = speed; + log("Storing lastSpeed in settings for the rememberSpeed feature", 5); tc.settings.lastSpeed = speed; + log("Syncing chrome settings for lastSpeed", 5); chrome.storage.sync.set({ lastSpeed: speed }, function() { - console.log("Speed setting saved: " + speed); + log("Speed setting saved: " + speed, 5); }); // show the controller for 1000ms if it's hidden. runAction("blink", document, null, null); } function runAction(action, document, value, e) { + log("runAction Begin", 5); if (tc.settings.audioBoolean) { var mediaTags = getShadow(document.body).filter(x => { return x.tagName == "AUDIO" || x.tagName == "VIDEO"; @@ -622,10 +675,13 @@ function runAction(action, document, value, e) { if (!v.classList.contains("vsc-cancelled")) { if (action === "rewind") { + log("Rewind", 5); v.currentTime -= value; } else if (action === "advance") { + log("Fast forward", 5); v.currentTime += value; } else if (action === "faster") { + log("Increase speed", 5); // Maximum playback speed in Chrome is set to 16: // https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/media/html_media_element.cc?gsn=kMinRate&l=166 var s = Math.min( @@ -634,16 +690,20 @@ function runAction(action, document, value, e) { ); setSpeed(controller, v, s); } else if (action === "slower") { + log("Decrease speed", 5); // Video min rate is 0.0625: // https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/media/html_media_element.cc?gsn=kMinRate&l=165 var s = Math.max(v.playbackRate - value, 0.07); setSpeed(controller, v, s); } else if (action === "reset") { + log("Reset speed", 5); resetSpeed(v, controller, 1.0); } else if (action === "display") { + log("Showing controller", 5); controller.classList.add("vsc-manual"); controller.classList.toggle("vsc-hidden"); } else if (action === "blink") { + log("Showing controller momentarily", 5); // if vsc is hidden, show it briefly to give the use visual feedback that the action is excuted. if ( controller.classList.contains("vsc-hidden") || @@ -674,12 +734,15 @@ function runAction(action, document, value, e) { } } }); + log("runAction End", 5); } function pause(v) { if (v.paused) { + log("Resuming video", 5); v.play(); } else { + log("Pausing video", 5); v.pause(); } } @@ -687,17 +750,20 @@ function pause(v) { function resetSpeed(v, controller, target) { if (v.playbackRate === target) { if (v.playbackRate === getKeyBindings("reset")) { - // resetSpeed if (target !== 1.0) { + log("Resetting playback speed to 1.0", 4); setSpeed(controller, v, 1.0); } else { - setSpeed(controller, v, getKeyBindings("fast")); // fastSpeed + log('Toggling playback speed to "fast" speed', 4); + setSpeed(controller, v, getKeyBindings("fast")); } } else { - setSpeed(controller, v, getKeyBindings("reset")); // resetSpeed + log('Toggling playback speed to "reset" speed', 4); + setSpeed(controller, v, getKeyBindings("reset")); } } else { - setKeyBindings("reset", v.playbackRate); // resetSpeed + log('Toggling playback speed to "reset" speed', 4); + setKeyBindings("reset", v.playbackRate); setSpeed(controller, v, target); } } @@ -707,10 +773,12 @@ function muted(v, value) { } function setMark(v) { + log("Adding marker", 5); v.vsc.mark = v.currentTime; } function jumpToMark(v) { + log("Recalling marker", 5); if (v.vsc.mark && typeof v.vsc.mark === "number") { v.currentTime = v.vsc.mark; } @@ -763,6 +831,7 @@ function handleDrag(video, controller, e) { var timer; var animation = false; function showController(controller) { + log("Showing controller", 4); controller.classList.add("vcs-show"); if (animation) clearTimeout(timer); @@ -771,5 +840,6 @@ function showController(controller) { timer = setTimeout(function() { controller.classList.remove("vcs-show"); animation = false; + log("Hiding controller", 5); }, 2000); } From c32eec1bb2e25c01cbc209d0380beab6cbe7029b Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Sat, 7 Mar 2020 18:23:55 -0600 Subject: [PATCH 7/8] Moved ratechange listener into its own function Placed call for adding listener after call to document ready/disabled check Placed setupListener within try/catch block --- inject.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/inject.js b/inject.js index 3c7c308..15ecb5f 100644 --- a/inject.js +++ b/inject.js @@ -374,11 +374,7 @@ function refreshCoolDown() { log("End refreshCoolDown", 5); } -function initializeWhenReady(document) { - log("Begin initializeWhenReady", 5); - if (isBlacklisted()) { - return; - } +function setupListener() { document.body.addEventListener( "ratechange", function(event) { @@ -391,6 +387,13 @@ function initializeWhenReady(document) { }, true ); +} + +function initializeWhenReady(document) { + log("Begin initializeWhenReady", 5); + if (isBlacklisted()) { + return; + } window.onload = () => { initializeNow(window.document); }; @@ -449,6 +452,11 @@ function initializeNow(document) { if (!document.body || document.body.classList.contains("vsc-initialized")) { return; } + try { + setupListener(); + } catch { + // no operation + } document.body.classList.add("vsc-initialized"); log("initializeNow: vsc-initialized added to document body", 5); From b4f6bcc292583a8658131578c328ef36519d7b96 Mon Sep 17 00:00:00 2001 From: Chad Bailey Date: Sun, 8 Mar 2020 19:19:56 -0500 Subject: [PATCH 8/8] Removed redundant rateChanged() function --- inject.js | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/inject.js b/inject.js index 15ecb5f..fd7d166 100644 --- a/inject.js +++ b/inject.js @@ -378,12 +378,31 @@ function setupListener() { document.body.addEventListener( "ratechange", function(event) { - controller = event.target.parentElement.querySelector(".vsc-controller"); - rateChanged(controller); if (coolDown) { log("Speed event propagation blocked", 4); event.stopImmediatePropagation(); } + var controller = event.target.parentElement.querySelector( + ".vsc-controller" + ); + var speedIndicator = controller.shadowRoot.querySelector("span"); + var video = controller.parentElement.querySelector("video"); + var src = video.currentSrc; + var speed = video.playbackRate.toFixed(2); + + log("Playback rate changed to " + speed, 4); + + log("Updating controller with new speed", 5); + speedIndicator.textContent = speed; + tc.settings.speeds[src] = speed; + log("Storing lastSpeed in settings for the rememberSpeed feature", 5); + tc.settings.lastSpeed = speed; + log("Syncing chrome settings for lastSpeed", 5); + chrome.storage.sync.set({ lastSpeed: speed }, function() { + log("Speed setting saved: " + speed, 5); + }); + // show the controller for 1000ms if it's hidden. + runAction("blink", document, null, null); }, true ); @@ -626,31 +645,9 @@ function setSpeed(controller, video, speed) { var speedvalue = speed.toFixed(2); video.playbackRate = Number(speedvalue); refreshCoolDown(); - rateChanged(controller); log("setSpeed finished: " + speed, 5); } -function rateChanged(controller) { - var speedIndicator = controller.shadowRoot.querySelector("span"); - var video = controller.parentElement.querySelector("video"); - var src = video.currentSrc; - var speed = video.playbackRate.toFixed(2); - - log("Playback rate changed to " + speed, 4); - - log("Updating controller with new speed", 5); - speedIndicator.textContent = speed; - tc.settings.speeds[src] = speed; - log("Storing lastSpeed in settings for the rememberSpeed feature", 5); - tc.settings.lastSpeed = speed; - log("Syncing chrome settings for lastSpeed", 5); - chrome.storage.sync.set({ lastSpeed: speed }, function() { - log("Speed setting saved: " + speed, 5); - }); - // show the controller for 1000ms if it's hidden. - runAction("blink", document, null, null); -} - function runAction(action, document, value, e) { log("runAction Begin", 5); if (tc.settings.audioBoolean) {