From 27b6898be60850325e72668c97aae7cf62001bc7 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Thu, 4 May 2017 22:29:59 -0700 Subject: [PATCH 01/16] Revert "use mouse wheel scroll to increase/decrease speed" (#211) --- inject.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/inject.js b/inject.js index fd75f3c..054541f 100644 --- a/inject.js +++ b/inject.js @@ -125,13 +125,6 @@ chrome.extension.sendMessage({}, function(response) { `; shadow.innerHTML = shadowTemplate; - shadow.querySelector('#controller').addEventListener('wheel', (e) => { - runAction(e.wheelDelta > 0 ? 'faster' : 'slower', document); - e.preventDefault(); - e.stopPropagation(); - }); - - shadow.querySelector('.draggable').addEventListener('mousedown', (e) => { runAction(e.target.dataset['action'], document); }); From 427a19fb7473f2ee781f7457473955a5b628c748 Mon Sep 17 00:00:00 2001 From: canarslan12 Date: Wed, 24 May 2017 18:56:08 +0300 Subject: [PATCH 02/16] suggestion #216 - Reset use fastSpeed initially (#218) --- inject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inject.js b/inject.js index 054541f..cbc2ff9 100644 --- a/inject.js +++ b/inject.js @@ -56,7 +56,7 @@ chrome.extension.sendMessage({}, function(response) { this.id = Math.random().toString(36).substr(2, 9); if (!tc.settings.rememberSpeed) { tc.settings.speed = 1.0; - tc.settings.resetSpeed = 1.0; + tc.settings.resetSpeed = tc.settings.fastSpeed; } this.initializeControls(); From d6f4c3415abd18e99e574dd98dd402810ec50bb1 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Sun, 23 Apr 2017 10:21:24 -0700 Subject: [PATCH 03/16] bump to 0.4.7 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 4320baf..e0a8994 100755 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Video Speed Controller", "short_name": "videospeed", - "version": "0.4.6", + "version": "0.4.7", "manifest_version": 2, "description": "Speed up, slow down, advance and rewind any HTML5 video with quick shortcuts.", "homepage_url": "https://github.com/igrigorik/videospeed", From 735785fd06ba306d34d0a6c3ca7e5224aeee95a4 Mon Sep 17 00:00:00 2001 From: canarslan12 Date: Wed, 24 May 2017 13:37:07 +0300 Subject: [PATCH 04/16] #217 - Reverting Preferred Speed --- inject.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/inject.js b/inject.js index cbc2ff9..9c4d120 100644 --- a/inject.js +++ b/inject.js @@ -334,8 +334,14 @@ chrome.extension.sendMessage({}, function(response) { }); } + var oldSpeed = 1.0; function playVideoAtFastSpeed(video) { - video.playbackRate = tc.settings.fastSpeed; + if(video.playbackRate == tc.settings.fastSpeed) { + video.playbackRate = oldSpeed; + } else { + oldSpeed = video.playbackRate; + video.playbackRate = tc.settings.fastSpeed; + } } function handleDrag(video, controller) { From 0f5f6c3aabe366b11bcfdf4f518357922872592e Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Thu, 25 May 2017 20:46:54 -0400 Subject: [PATCH 05/16] refactor "reset speed" functionality --- inject.js | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/inject.js b/inject.js index 9c4d120..5c8e699 100644 --- a/inject.js +++ b/inject.js @@ -312,13 +312,7 @@ chrome.extension.sendMessage({}, function(response) { var s = Math.max(v.playbackRate - tc.settings.speedStep, 0.0625); v.playbackRate = Number(s.toFixed(2)); } else if (action === 'reset') { - if(v.playbackRate === 1.0) { - v.playbackRate = tc.settings.resetSpeed; - } else { - tc.settings.resetSpeed = v.playbackRate; - chrome.storage.sync.set({'resetSpeed': v.playbackRate}); - v.playbackRate = 1.0; - } + resetSpeed(v, 1.0); } else if (action === 'close') { v.classList.add('vsc-cancelled'); controller.remove(); @@ -328,19 +322,19 @@ chrome.extension.sendMessage({}, function(response) { } else if (action === 'drag') { handleDrag(v, controller); } else if (action === 'fast') { - playVideoAtFastSpeed(v); + resetSpeed(v, tc.settings.fastSpeed); } } }); } - var oldSpeed = 1.0; - function playVideoAtFastSpeed(video) { - if(video.playbackRate == tc.settings.fastSpeed) { - video.playbackRate = oldSpeed; + function resetSpeed(v, target) { + if (v.playbackRate === target) { + v.playbackRate = tc.settings.resetSpeed; } else { - oldSpeed = video.playbackRate; - video.playbackRate = tc.settings.fastSpeed; + tc.settings.resetSpeed = v.playbackRate; + chrome.storage.sync.set({'resetSpeed': v.playbackRate}); + v.playbackRate = target; } } From c157f0e8a5d60a5227feb972bc5e66d9dcfd874a Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Mon, 29 May 2017 18:22:38 -0700 Subject: [PATCH 06/16] fix escaping in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7552190..c18eee3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **TL;DR: faster playback translates to quick progress, better engagement, and retention.** -Average adult reads prose text at [250 to 300 words per minute](http://www.paperbecause.com/PIOP/files/f7/f7bb6bc5-2c4a-466f-9ae7-b483a2c0dca4.pdf) (wpm). By contrast, the average rate of speech for English speakers is ~150 wpm, with slide presentations often closer to 100 wpm. As a result, when given the choice, many viewers [speed up video playback to ~1.3~1.5 its recorded rate](http://research.microsoft.com/en-us/um/redmond/groups/coet/compression/chi99/paper.pdf) to compensate for the difference. +Average adult reads prose text at [250 to 300 words per minute](http://www.paperbecause.com/PIOP/files/f7/f7bb6bc5-2c4a-466f-9ae7-b483a2c0dca4.pdf) (wpm). By contrast, the average rate of speech for English speakers is ~150 wpm, with slide presentations often closer to 100 wpm. As a result, when given the choice, many viewers [speed up video playback to ~1.3\~1.5 its recorded rate](http://research.microsoft.com/en-us/um/redmond/groups/coet/compression/chi99/paper.pdf) to compensate for the difference. Many viewers report that [accelerated viewing keeps their attention longer](http://www.enounce.com/docs/BYUPaper020319.pdf): faster delivery keeps the viewer more engaged with the content. In fact, with a little training many end up watching videos at 2x+ the recorded speed. Some studies report that after being exposed to accelerated playback, [listeners become uncomfortable](http://xenia.media.mit.edu/~barons/html/avios92.html#beasleyalteredspeech) if they are forced to return to normal rate of presentation. From f060863459528562c0ae1267ca6de63137b5649b Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Mon, 29 May 2017 18:25:19 -0700 Subject: [PATCH 07/16] remove outdated content --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c18eee3..db1d7ae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # The science of accelerated playback -**TL;DR: faster playback translates to quick progress, better engagement, and retention.** +**TL;DR: faster playback translates to better engagement and retention.** Average adult reads prose text at [250 to 300 words per minute](http://www.paperbecause.com/PIOP/files/f7/f7bb6bc5-2c4a-466f-9ae7-b483a2c0dca4.pdf) (wpm). By contrast, the average rate of speech for English speakers is ~150 wpm, with slide presentations often closer to 100 wpm. As a result, when given the choice, many viewers [speed up video playback to ~1.3\~1.5 its recorded rate](http://research.microsoft.com/en-us/um/redmond/groups/coet/compression/chi99/paper.pdf) to compensate for the difference. @@ -24,11 +24,7 @@ Once the extension is installed simply navigate to any page that offers HTML5 vi * **X** - advance video by 10 seconds. * **V** - show/hide the controller. -Note that you can customize these shortcuts in the extension settings page. Also, a few tips for enabling and forcing HTML5 video: - - * YouTube: make sure you [enable the HTML5 opt-in experiment](http://www.youtube.com/html5). - * If you're adventurous, try disabling the Flash plugin in Chrome in chrome://plugins/ - * If viewing a video on Wistia, right click to switch to HTML5 video, refresh the page, and the controls will appear. +_Note: you can customize these shortcut keys in the extension settings page._ ### FAQ From 65ca4e7bcbcce85dac3f502bccbc5ab6602595f5 Mon Sep 17 00:00:00 2001 From: Sergey Orlov Date: Fri, 2 Jun 2017 17:36:42 +0300 Subject: [PATCH 08/16] Fix link to media.mit.edu article (#224) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db1d7ae..0402c9f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Average adult reads prose text at [250 to 300 words per minute](http://www.paperbecause.com/PIOP/files/f7/f7bb6bc5-2c4a-466f-9ae7-b483a2c0dca4.pdf) (wpm). By contrast, the average rate of speech for English speakers is ~150 wpm, with slide presentations often closer to 100 wpm. As a result, when given the choice, many viewers [speed up video playback to ~1.3\~1.5 its recorded rate](http://research.microsoft.com/en-us/um/redmond/groups/coet/compression/chi99/paper.pdf) to compensate for the difference. -Many viewers report that [accelerated viewing keeps their attention longer](http://www.enounce.com/docs/BYUPaper020319.pdf): faster delivery keeps the viewer more engaged with the content. In fact, with a little training many end up watching videos at 2x+ the recorded speed. Some studies report that after being exposed to accelerated playback, [listeners become uncomfortable](http://xenia.media.mit.edu/~barons/html/avios92.html#beasleyalteredspeech) if they are forced to return to normal rate of presentation. +Many viewers report that [accelerated viewing keeps their attention longer](http://www.enounce.com/docs/BYUPaper020319.pdf): faster delivery keeps the viewer more engaged with the content. In fact, with a little training many end up watching videos at 2x+ the recorded speed. Some studies report that after being exposed to accelerated playback, [listeners become uncomfortable](http://alumni.media.mit.edu/~barons/html/avios92.html#beasleyalteredspeech) if they are forced to return to normal rate of presentation. ## Faster HTML5 Video From 704b3b42c5de9e74bf3947ddfc757841b1b0a560 Mon Sep 17 00:00:00 2001 From: Can Arslan Date: Sun, 25 Jun 2017 22:15:51 +0300 Subject: [PATCH 09/16] Not updating speed correctly #214 (#220) I tested for several times with/without throttling in different videos and nothing effected/no console error and fixed issue. --- inject.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/inject.js b/inject.js index 5c8e699..549f86d 100644 --- a/inject.js +++ b/inject.js @@ -65,9 +65,6 @@ chrome.extension.sendMessage({}, function(response) { }); target.addEventListener('ratechange', function(event) { - if (target.readyState === 0) { - return; - } var speed = this.getSpeed(); this.speedIndicator.textContent = speed; tc.settings.speed = speed; From 7a790d449ee92909f23f047e51add5a8aa3b33b1 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Sun, 25 Jun 2017 13:09:10 -0700 Subject: [PATCH 10/16] custom rules to offset controller on Google Photos Closes #215. --- inject.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/inject.css b/inject.css index d11b58d..e975871 100644 --- a/inject.css +++ b/inject.css @@ -29,6 +29,18 @@ top: 40px; } +/* Google Photos player */ +/* Inline preview doesn't have any additional hooks, relying on Aria label */ +a[aria-label^="Video"] .vsc-controller { + position: relative; + top: 35px; +} +/* Google Photos full-screen view */ +#player .html5-video-container .vsc-controller { + position: relative; + top: 50px; +} + /* Netflix player */ #netflix-player:not(.player-cinema-mode) .vsc-controller { position: relative; From 07f43acf2e4004b11ea66d91fc4cfa3faad1a70d Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Sun, 25 Jun 2017 13:36:39 -0700 Subject: [PATCH 11/16] exclude new meet.google.com I wish we could speed up real-time.. alas, perhaps as part of HTML6. --- manifest.json | 1 + 1 file changed, 1 insertion(+) diff --git a/manifest.json b/manifest.json index e0a8994..5042dea 100755 --- a/manifest.json +++ b/manifest.json @@ -26,6 +26,7 @@ "exclude_matches": [ "https://plus.google.com/hangouts/*", "https://hangouts.google.com/hangouts/*", + "https://meet.google.com/*", "https://teamtreehouse.com/*", "http://www.hitbox.tv/*" ], From 7ea778d3ec08d2fc890447d25f2b0af550336602 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Mon, 26 Jun 2017 18:34:03 +0200 Subject: [PATCH 12/16] special-case inject prototype for FB and amazon Some sites inject overlays over their videos to intercept clicks and provide own on-screen controls, etc. Unfortunately this makes the VC controls inaccessible and without any generic workaround... well, short of relying on keyboard shortcuts. This is an experiment for special-casing FB and Amazon - FB we modify stacking context of the parent - Amazon we inject the controller one level higher, above the overlay The gotcha here is that this type of behavior is not uncommon, and special-casing each and every origin like this is not long-term sustainable. If this sticks.. we'll have to be very selective about which sites we enable this for. Closes #210 Closes #134 --- inject.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/inject.js b/inject.js index 549f86d..8e1a2ab 100644 --- a/inject.js +++ b/inject.js @@ -136,12 +136,26 @@ chrome.extension.sendMessage({}, function(response) { var fragment = document.createDocumentFragment(); fragment.appendChild(wrapper); - // Note: when triggered via a MutationRecord, it's possible that the - // target is not the immediate parent. This appends the controller as - // the first element of the target, which may not be the parent. - this.parent.insertBefore(fragment, this.parent.firstChild); this.video.classList.add('vsc-initialized'); this.video.dataset['vscid'] = this.id; + + switch (location.hostname) { + case 'www.amazon.com': + // insert before parent to bypass overlay + this.parent.parentElement.insertBefore(fragment, this.parent); + break; + + case 'www.facebook.com': + // set stacking context to same as parent's parent. + // + default fallthrough + this.parent.style.zIndex = 'auto'; + + default: + // Note: when triggered via a MutationRecord, it's possible that the + // target is not the immediate parent. This appends the controller as + // the first element of the target, which may not be the parent. + this.parent.insertBefore(fragment, this.parent.firstChild); + } } } From 2b06fa79822d351cdc1709166cdf41f8cf6a3222 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Sun, 2 Jul 2017 11:01:51 +0200 Subject: [PATCH 13/16] bump to 0.4.8 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 5042dea..9d3127b 100755 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "Video Speed Controller", "short_name": "videospeed", - "version": "0.4.7", + "version": "0.4.8", "manifest_version": 2, "description": "Speed up, slow down, advance and rewind any HTML5 video with quick shortcuts.", "homepage_url": "https://github.com/igrigorik/videospeed", From 212616da727ffea691d7a8044d75391238a3faba Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Mon, 3 Jul 2017 09:26:00 +0200 Subject: [PATCH 14/16] refine/scope down Google Photos CSS selector Current iteration also matched YouTube. Closes #234. --- inject.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inject.css b/inject.css index e975871..935e7fe 100644 --- a/inject.css +++ b/inject.css @@ -36,7 +36,7 @@ a[aria-label^="Video"] .vsc-controller { top: 35px; } /* Google Photos full-screen view */ -#player .html5-video-container .vsc-controller { +#player:not(.ytd-watch) .html5-video-container .vsc-controller { position: relative; top: 50px; } From 18455d521fbc66e33b87f0964966b262c214de84 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Mon, 3 Jul 2017 09:17:51 +0200 Subject: [PATCH 15/16] move controller check into initialization --- inject.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/inject.js b/inject.js index 8e1a2ab..d3d27a1 100644 --- a/inject.js +++ b/inject.js @@ -50,6 +50,10 @@ chrome.extension.sendMessage({}, function(response) { function defineVideoController() { tc.videoController = function(target, parent) { + if (target.dataset['vscid']) { + return; + } + this.video = target; this.parent = target.parentElement || parent; this.document = target.ownerDocument; @@ -244,9 +248,7 @@ chrome.extension.sendMessage({}, function(response) { function checkForVideo(node, parent, added) { if (node.nodeName === 'VIDEO') { if (added) { - if (!node.dataset['vscid']) { - new tc.videoController(node, parent); - } + new tc.videoController(node, parent); } else { if (node.classList.contains('vsc-initialized')) { let id = node.dataset['vscid']; From 5472786b19ab5048042965f66975af361e8946e7 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Tue, 4 Jul 2017 23:38:15 +0200 Subject: [PATCH 16/16] add logic and check for init-once closes #230, kudos to @xftroxgpx for the detective work and patch. --- inject.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/inject.js b/inject.js index d3d27a1..7c5dac3 100644 --- a/inject.js +++ b/inject.js @@ -195,6 +195,13 @@ chrome.extension.sendMessage({}, function(response) { } function initializeNow(document) { + // in theory, this should only run once, in practice.. + // that's not guaranteed, hence we enforce own init-once. + if (document.body.classList.contains('vsc-initialized')) { + return; + } + document.body.classList.add('vsc-initialized'); + if (document === window.document) { defineVideoController(); } else {