Merge branch 'master' into dev

# Conflicts:
#	inject.js
#	manifest.json
This commit is contained in:
codebicycle
2017-07-22 08:17:41 +03:00
4 changed files with 64 additions and 35 deletions

View File

@@ -1,10 +1,10 @@
# 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.
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
@@ -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

View File

@@ -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:not(.ytd-watch) .html5-video-container .vsc-controller {
position: relative;
top: 50px;
}
/* Netflix player */
#netflix-player:not(.player-cinema-mode) .vsc-controller {
position: relative;

View File

@@ -50,13 +50,17 @@ chrome.runtime.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;
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();
@@ -65,9 +69,6 @@ chrome.runtime.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;
@@ -103,6 +104,10 @@ chrome.runtime.sendMessage({}, function(response) {
wrapper.addEventListener('mousedown', prevent, false);
wrapper.addEventListener('click', prevent, false);
if (tc.settings.startHidden) {
wrapper.classList.add('vsc-hidden');
}
var styleElem = document.createElement('style')
var shadowCSS = chrome.runtime.getURL('shadow.css')
var textElem = document.createTextNode(`@import "${shadowCSS}";`)
@@ -169,12 +174,26 @@ chrome.runtime.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);
}
}
}
@@ -210,6 +229,13 @@ chrome.runtime.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 {
@@ -263,9 +289,7 @@ chrome.runtime.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'];
@@ -342,13 +366,7 @@ chrome.runtime.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.local.set({'resetSpeed': v.playbackRate});
v.playbackRate = 1.0;
}
resetSpeed(v, 1.0);
} else if (action === 'close') {
v.classList.add('vsc-cancelled');
controller.remove();
@@ -358,23 +376,25 @@ chrome.runtime.sendMessage({}, function(response) {
} else if (action === 'drag') {
handleDrag(v, controller);
} else if (action === 'fast') {
playVideoAtFastSpeed(v);
resetSpeed(v, tc.settings.fastSpeed);
}
}
});
}
function playVideoAtFastSpeed(video) {
video.playbackRate = tc.settings.fastSpeed;
function resetSpeed(v, target) {
if (v.playbackRate === target) {
v.playbackRate = tc.settings.resetSpeed;
} else {
tc.settings.resetSpeed = v.playbackRate;
chrome.storage.local.set({'resetSpeed': v.playbackRate});
v.playbackRate = target;
}
}
function handleDrag(video, controller) {
const parentElement = controller.parentElement,
boundRect = parentElement.getBoundingClientRect(),
shadowController = controller.querySelector('#controller'),
drag = shadowController.querySelector('.draggable'),
offsetLeft = boundRect.left + drag.offsetLeft + drag.offsetWidth,
offsetTop = boundRect.top + drag.offsetTop + drag.offsetHeight;
shadowController = controller.querySelector('#controller');
video.classList.add('vcs-dragging');
shadowController.classList.add('dragging');

View File

@@ -1,7 +1,7 @@
{
"name": "Video Speed Controller",
"short_name": "videospeed",
"version": "0.4.6.1",
"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/codebicycle/videospeed",
@@ -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/*"
],