From d3ab0a194e331ea84413901d4f4cb02f84fc44f7 Mon Sep 17 00:00:00 2001 From: Radu Filip Date: Fri, 15 Aug 2014 00:26:35 +0100 Subject: [PATCH 1/5] Added Options Page Added Options Page allowing user to customize shortcuts and other parameters --- inject.js | 39 ++++++++++++++---- manifest.json | 1 + options.css | 101 +++++++++++++++++++++++++++++++++++++++++++++++ options.html | 52 ++++++++++++++++++++++++ options.js | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+), 8 deletions(-) create mode 100644 options.css create mode 100644 options.html create mode 100644 options.js diff --git a/inject.js b/inject.js index 255d811..7f8d47f 100644 --- a/inject.js +++ b/inject.js @@ -92,18 +92,24 @@ chrome.extension.sendMessage({}, function(response) { videoTags.forEach(function(v) { if (!v.paused && !v.classList.contains("vc-cancelled")) { if (action === 'rewind') { - v.playbackRate -= 0.10; - v.currentTime -= 10; - } else if (action === 'faster') { v.playbackRate += 0.10 } - else if (action === 'slower') { v.playbackRate = Math.max(v.playbackRate - 0.10, 0.00) } + v.playbackRate -= speedStep; + v.currentTime -= rewindTime; + } else if (action === 'faster') { + v.playbackRate += speedStep } + else if (action === 'slower') { + v.playbackRate = Math.max(v.playbackRate - speedStep, 0.00) } } }); } - document.addEventListener('keydown', function(event) { - if (event.keyCode == 65) { runAction('rewind') } // A - else if (event.keyCode == 68) { runAction('faster') } // D - else if (event.keyCode == 83) { runAction('slower') } // S + document.addEventListener('keypress', function(event) { + + // if lowercase letter pressed, check for uppercase key code + var keyCode = String.fromCharCode(event.keyCode).toUpperCase().charCodeAt(); + + if (keyCode == rewindKeyCode) { runAction('rewind') } + else if (keyCode == fasterKeyCode) { runAction('faster') } + else if (keyCode == slowerKeyCode) { runAction('slower') } return false; }, true); @@ -120,6 +126,23 @@ chrome.extension.sendMessage({}, function(response) { videoTags.forEach(function(video) { var control = new tc.videoController(video); }); + + var speedStep, rewindTime, rewindKeyCode, slowerKeyCode, fasterKeyCode; + + chrome.storage.sync.get({ + speedStep: 0.25, // default 0.25x + rewindTime: 10, // default 10s + rewindKeyCode: 65, // default: A + slowerKeyCode: 83, // default: S + fasterKeyCode: 68 // default: D + }, + function(storage) { + speedStep = Number(storage.speedStep); + rewindTime = Number(storage.rewindTime); + rewindKeyCode = Number(storage.rewindKeyCode); + slowerKeyCode = Number(storage.slowerKeyCode); + fasterKeyCode = Number(storage.fasterKeyCode); + }); } }, 10); }); diff --git a/manifest.json b/manifest.json index 825f091..538b691 100755 --- a/manifest.json +++ b/manifest.json @@ -10,6 +10,7 @@ "128": "icons/icon128.png" }, "permissions": [ "activeTab", "storage" ], + "options_page": "options.html", "content_scripts": [{ "all_frames": true, "matches": [ "http://*/*", "https://*/*"], diff --git a/options.css b/options.css new file mode 100644 index 0000000..b0d8cb0 --- /dev/null +++ b/options.css @@ -0,0 +1,101 @@ +body { + margin: 0; + padding-left: 15px; + padding-top: 53px; + font-family: sans-serif; + font-size: 12px; + color: rgb(48, 57, 66); +} + +h1, h2, h3 { + font-weight: normal; + line-height: 1; + user-select: none; + cursor: default; +} +h1 { + font-size: 1.5em; + margin: 21px 0 13px; +} +h3 { + font-size: 1.2em; + margin-bottom: 0.8em; + color: black; +} +p { + margin: 0.65em 0; +} + +header { + position: fixed; + top: 0; + left: 15px; + right: 0; + border-bottom: 1px solid #EEE; + background: linear-gradient(white, white 40%, rgba(255, 255, 255, 0.92)); +} +header, section { + min-width: 600px; + max-width: 738px; +} +section { + padding-left: 18px; + margin-top: 8px; + margin-bottom: 24px; +} +section h3 { + margin-left: -18px; +} + +button, select { + -webkit-appearance: none; + position: relative; + + margin: 0 1px 0 0; + padding: 0 10px; + min-width: 4em; + min-height: 2em; + + background-image: linear-gradient(#EDEDED, #EDEDED 38%, #DEDEDE); + border: 1px solid rgba(0,0,0,0.25); + border-radius: 2px; + outline: none; + box-shadow: 0 1px 0 rgba(0,0,0,0.08), inset 0 1px 2px rgba(255,255,255,0.75); + color: #444; + text-shadow: 0 1px 0 rgb(240,240,240); + font: inherit; + + user-select: none; +} + +select { + padding-right: 20px; + + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAICAYAAAAbQcSUAAAAaUlEQVQoz2P4//8/A7UwdkEGhiggTsODo4g2LBEImJmZvwE1/UfHIHGQPNGGAbHCggULFrKxsf1ENgjEB4mD5EnxJoaByAZB5Yk3DNlAPj6+L8gGkWUYzMC3b982IRtEtmFQjaxYxDAwAGi4TwMYKNLfAAAAAElFTkSuQmCC'), linear-gradient(#EDEDED, #EDEDED 38%, #DEDEDE); + background-position: right center; + background-repeat: no-repeat; +} + +input[type="text"] { + width: 120px; +} + +.row { + margin: 5px 0px; +} + +label { + display: inline-block; + width: 150px; +} + +#rewindTime { + width: 69px; + text-align: center; +} + +#status { + color: #9D9D9D; + display: inline-block; + margin-left: 50px; +} \ No newline at end of file diff --git a/options.html b/options.html new file mode 100644 index 0000000..c51b7ad --- /dev/null +++ b/options.html @@ -0,0 +1,52 @@ + + + + HTML5 Video Playback Speed Controller Options + + + +
+

HTML5 Video Playback Speed Controller

+
+ +
+

Shortcuts

+
+ + +
+
+ + +
+
+ + +
+
+ +
+

Others

+
+ + +
+
+ + +
+
+ + +
+ + + + \ No newline at end of file diff --git a/options.js b/options.js new file mode 100644 index 0000000..9624fa1 --- /dev/null +++ b/options.js @@ -0,0 +1,107 @@ +function recordKeyPress(e) { + var normalizedKeyCode = String.fromCharCode(e.keyCode).toUpperCase().charCodeAt(); + e.target.value = getInputMsg(normalizedKeyCode); + e.target.keyCode = normalizedKeyCode; + + e.preventDefault(); + e.stopPropagation(); +}; + +function inputFocus(e) { + e.target.value = ""; +}; + +function inputBlur(e) { + e.target.value = getInputMsg(e.target.keyCode); +}; + +function updateShortcutInputText(inputId, keyCode) { + document.getElementById(inputId).value = getInputMsg(keyCode); + document.getElementById(inputId).keyCode = keyCode; +} + +function getInputMsg(keyCode) { + return "Shortcut set to " + String.fromCharCode(keyCode).toUpperCase(); +}; + +// Saves options to chrome.storage +function save_options() { + + var speedStep = Number(document.getElementById('speedStep').value); + var rewindTime = document.getElementById('rewindTime').value; + var rewindKeyCode = document.getElementById('rewindKeyInput').keyCode; + var slowerKeyCode = document.getElementById('slowerKeyInput').keyCode; + var fasterKeyCode = document.getElementById('fasterKeyInput').keyCode; + + rewindTime = isNaN(rewindTime) ? 10 : rewindTime; + rewindKeyCode = isNaN(rewindKeyCode) ? 65 : rewindKeyCode; + slowerKeyCode = isNaN(slowerKeyCode) ? 83 : slowerKeyCode; + fasterKeyCode = isNaN(fasterKeyCode) ? 68 : fasterKeyCode; + + chrome.storage.sync.set({ + speedStep: speedStep, + rewindTime: rewindTime, + rewindKeyCode: rewindKeyCode, + slowerKeyCode: slowerKeyCode, + fasterKeyCode: fasterKeyCode + }, function() { + // Update status to let user know options were saved. + var status = document.getElementById('status'); + status.textContent = 'Options saved'; + setTimeout(function() { + status.textContent = ''; + }, 1000); + }); +} + +// Restores options from chrome.storage +function restore_options() { + chrome.storage.sync.get({ + speedStep: 0.25, + rewindTime: 10, + rewindKeyCode: 65, + slowerKeyCode: 83, + fasterKeyCode: 68 + }, function(storage) { + document.getElementById('speedStep').value = storage.speedStep.toFixed(2); + document.getElementById('rewindTime').value = storage.rewindTime; + updateShortcutInputText('rewindKeyInput', storage.rewindKeyCode); + updateShortcutInputText('slowerKeyInput', storage.slowerKeyCode); + updateShortcutInputText('fasterKeyInput', storage.fasterKeyCode); + }); +} + +function restore_defaults() { + + chrome.storage.sync.set({ + speedStep: 0.25, + rewindTime: 10, + rewindKeyCode: 65, + slowerKeyCode: 83, + fasterKeyCode: 68 + }, function() { + restore_options(); + // Update status to let user know options were saved. + var status = document.getElementById('status'); + status.textContent = 'Default options restored'; + setTimeout(function() { + status.textContent = ''; + }, 1000); + }); + +} + +// Event Listeners +document.addEventListener('DOMContentLoaded', restore_options); +document.getElementById('save').addEventListener('click', save_options); +document.getElementById('restore').addEventListener('click', restore_defaults); + +initShortcutInput('rewindKeyInput'); +initShortcutInput('slowerKeyInput'); +initShortcutInput('fasterKeyInput'); + +function initShortcutInput(inputId) { + document.getElementById(inputId).addEventListener('focus', inputFocus); + document.getElementById(inputId).addEventListener('blur', inputBlur); + document.getElementById(inputId).addEventListener('keypress', recordKeyPress); +} From dfb86cd287ccbf0ea9f35099a5753b5028ceac6a Mon Sep 17 00:00:00 2001 From: Radu Filip Date: Sat, 16 Aug 2014 11:53:34 +0100 Subject: [PATCH 2/5] Options Page adjustments Implemented the adjustments suggested by Ilya: default values adjustments, input validation, UI --- inject.js | 2 +- manifest.json | 2 +- options.css | 19 ++++--------------- options.html | 15 ++++----------- options.js | 34 +++++++++++++++++++++------------- 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/inject.js b/inject.js index 7f8d47f..c616f51 100644 --- a/inject.js +++ b/inject.js @@ -130,7 +130,7 @@ chrome.extension.sendMessage({}, function(response) { var speedStep, rewindTime, rewindKeyCode, slowerKeyCode, fasterKeyCode; chrome.storage.sync.get({ - speedStep: 0.25, // default 0.25x + speedStep: 0.1, // default 0.10x rewindTime: 10, // default 10s rewindKeyCode: 65, // default: A slowerKeyCode: 83, // default: S diff --git a/manifest.json b/manifest.json index 538b691..f58bb91 100755 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "HTML5 Video Playback Speed Controller", - "version": "0.1.2", + "version": "0.1.3", "manifest_version": 2, "description": "Lean in and speed up your video learning with handy shortcuts to accelerate, slow-down, and rewind your video via your keyboard.", "homepage_url": "https://github.com/igrigorik/videospeed", diff --git a/options.css b/options.css index b0d8cb0..0486233 100644 --- a/options.css +++ b/options.css @@ -47,7 +47,7 @@ section h3 { margin-left: -18px; } -button, select { +button { -webkit-appearance: none; position: relative; @@ -56,7 +56,7 @@ button, select { min-width: 4em; min-height: 2em; - background-image: linear-gradient(#EDEDED, #EDEDED 38%, #DEDEDE); + background-image: linear-gradient(#EDEDED, #EDEDED 38%, #DEDEDE); border: 1px solid rgba(0,0,0,0.25); border-radius: 2px; outline: none; @@ -68,16 +68,10 @@ button, select { user-select: none; } -select { - padding-right: 20px; - - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAICAYAAAAbQcSUAAAAaUlEQVQoz2P4//8/A7UwdkEGhiggTsODo4g2LBEImJmZvwE1/UfHIHGQPNGGAbHCggULFrKxsf1ENgjEB4mD5EnxJoaByAZB5Yk3DNlAPj6+L8gGkWUYzMC3b982IRtEtmFQjaxYxDAwAGi4TwMYKNLfAAAAAElFTkSuQmCC'), linear-gradient(#EDEDED, #EDEDED 38%, #DEDEDE); - background-position: right center; - background-repeat: no-repeat; -} input[type="text"] { - width: 120px; + width: 75px; + text-align: center; } .row { @@ -89,11 +83,6 @@ label { width: 150px; } -#rewindTime { - width: 69px; - text-align: center; -} - #status { color: #9D9D9D; display: inline-block; diff --git a/options.html b/options.html index c51b7ad..fc62e61 100644 --- a/options.html +++ b/options.html @@ -13,15 +13,15 @@

Shortcuts

- +
- +
- +
@@ -33,14 +33,7 @@
- +
diff --git a/options.js b/options.js index 9624fa1..baaf108 100644 --- a/options.js +++ b/options.js @@ -1,39 +1,44 @@ function recordKeyPress(e) { - var normalizedKeyCode = String.fromCharCode(e.keyCode).toUpperCase().charCodeAt(); - e.target.value = getInputMsg(normalizedKeyCode); - e.target.keyCode = normalizedKeyCode; + var normalizedChar = String.fromCharCode(e.keyCode).toUpperCase(); + e.target.value = normalizedChar; + e.target.keyCode = normalizedChar.charCodeAt(); e.preventDefault(); e.stopPropagation(); }; +function inputFilterNumbersOnly(e) { + var char = String.fromCharCode(e.keyCode); + if (!/[\d\.]$/.test(char) || !/^\d+(\.\d*)?$/.test(e.target.value + char)) { + e.preventDefault(); + e.stopPropagation(); + } +}; + function inputFocus(e) { e.target.value = ""; }; function inputBlur(e) { - e.target.value = getInputMsg(e.target.keyCode); + e.target.value = String.fromCharCode(e.target.keyCode).toUpperCase(); }; function updateShortcutInputText(inputId, keyCode) { - document.getElementById(inputId).value = getInputMsg(keyCode); + document.getElementById(inputId).value = String.fromCharCode(keyCode).toUpperCase(); document.getElementById(inputId).keyCode = keyCode; } -function getInputMsg(keyCode) { - return "Shortcut set to " + String.fromCharCode(keyCode).toUpperCase(); -}; - // Saves options to chrome.storage function save_options() { - var speedStep = Number(document.getElementById('speedStep').value); + var speedStep = document.getElementById('speedStep').value; var rewindTime = document.getElementById('rewindTime').value; var rewindKeyCode = document.getElementById('rewindKeyInput').keyCode; var slowerKeyCode = document.getElementById('slowerKeyInput').keyCode; var fasterKeyCode = document.getElementById('fasterKeyInput').keyCode; - rewindTime = isNaN(rewindTime) ? 10 : rewindTime; + speedStep = isNaN(speedStep) ? 0.1 : Number(speedStep); + rewindTime = isNaN(rewindTime) ? 10 : Number(rewindTime); rewindKeyCode = isNaN(rewindKeyCode) ? 65 : rewindKeyCode; slowerKeyCode = isNaN(slowerKeyCode) ? 83 : slowerKeyCode; fasterKeyCode = isNaN(fasterKeyCode) ? 68 : fasterKeyCode; @@ -57,7 +62,7 @@ function save_options() { // Restores options from chrome.storage function restore_options() { chrome.storage.sync.get({ - speedStep: 0.25, + speedStep: 0.1, rewindTime: 10, rewindKeyCode: 65, slowerKeyCode: 83, @@ -74,7 +79,7 @@ function restore_options() { function restore_defaults() { chrome.storage.sync.set({ - speedStep: 0.25, + speedStep: 0.1, rewindTime: 10, rewindKeyCode: 65, slowerKeyCode: 83, @@ -100,6 +105,9 @@ initShortcutInput('rewindKeyInput'); initShortcutInput('slowerKeyInput'); initShortcutInput('fasterKeyInput'); +document.getElementById('rewindTime').addEventListener('keypress', inputFilterNumbersOnly); +document.getElementById('speedStep').addEventListener('keypress', inputFilterNumbersOnly); + function initShortcutInput(inputId) { document.getElementById(inputId).addEventListener('focus', inputFocus); document.getElementById(inputId).addEventListener('blur', inputBlur); From e366a3835570559f8d494b7c2814fe69cac69d30 Mon Sep 17 00:00:00 2001 From: Radu Filip Date: Sat, 16 Aug 2014 17:18:52 +0100 Subject: [PATCH 3/5] Added "Remember Playback Speed" option Option to control the use of the last video's playback speed for a newly loaded video --- inject.js | 7 +++++-- options.css | 6 +++++- options.html | 6 +++++- options.js | 8 ++++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/inject.js b/inject.js index c616f51..28e7230 100644 --- a/inject.js +++ b/inject.js @@ -8,8 +8,11 @@ chrome.extension.sendMessage({}, function(response) { this.video = target; this.initializeControls(); - chrome.storage.sync.get('speed', function(storage) { - var speed = storage.speed ? storage.speed : '1.00'; + chrome.storage.sync.get({ + speed: '1.00', + rememberSpeed: true + }, function(storage) { + var speed = storage.rememberSpeed ? storage.speed : '1.00'; target.playbackRate = speed; this.speedIndicator.textContent = speed; }.bind(this)); diff --git a/options.css b/options.css index 0486233..425bfed 100644 --- a/options.css +++ b/options.css @@ -80,7 +80,11 @@ input[type="text"] { label { display: inline-block; - width: 150px; + width: 170px; +} + +label[for=rememberSpeed] { + width: 200px; } #status { diff --git a/options.html b/options.html index fc62e61..b42e4a3 100644 --- a/options.html +++ b/options.html @@ -32,9 +32,13 @@
- +
+
+ + +
diff --git a/options.js b/options.js index baaf108..7eb6b28 100644 --- a/options.js +++ b/options.js @@ -36,6 +36,7 @@ function save_options() { var rewindKeyCode = document.getElementById('rewindKeyInput').keyCode; var slowerKeyCode = document.getElementById('slowerKeyInput').keyCode; var fasterKeyCode = document.getElementById('fasterKeyInput').keyCode; + var rememberSpeed = document.getElementById('rememberSpeed').checked; speedStep = isNaN(speedStep) ? 0.1 : Number(speedStep); rewindTime = isNaN(rewindTime) ? 10 : Number(rewindTime); @@ -48,7 +49,8 @@ function save_options() { rewindTime: rewindTime, rewindKeyCode: rewindKeyCode, slowerKeyCode: slowerKeyCode, - fasterKeyCode: fasterKeyCode + fasterKeyCode: fasterKeyCode, + rememberSpeed: rememberSpeed }, function() { // Update status to let user know options were saved. var status = document.getElementById('status'); @@ -66,13 +68,15 @@ function restore_options() { rewindTime: 10, rewindKeyCode: 65, slowerKeyCode: 83, - fasterKeyCode: 68 + fasterKeyCode: 68, + rememberSpeed: true }, function(storage) { document.getElementById('speedStep').value = storage.speedStep.toFixed(2); document.getElementById('rewindTime').value = storage.rewindTime; updateShortcutInputText('rewindKeyInput', storage.rewindKeyCode); updateShortcutInputText('slowerKeyInput', storage.slowerKeyCode); updateShortcutInputText('fasterKeyInput', storage.fasterKeyCode); + document.getElementById('rememberSpeed').checked = storage.rememberSpeed; }); } From 8dd9d26af722735e51bbab428397d7223c1de8a9 Mon Sep 17 00:00:00 2001 From: Radu Filip Date: Sat, 16 Aug 2014 17:55:29 +0100 Subject: [PATCH 4/5] Minor adjustments Changed the default value for Remember Playback Speed to 'false' --- inject.js | 2 +- options.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/inject.js b/inject.js index 28e7230..85225c1 100644 --- a/inject.js +++ b/inject.js @@ -10,7 +10,7 @@ chrome.extension.sendMessage({}, function(response) { chrome.storage.sync.get({ speed: '1.00', - rememberSpeed: true + rememberSpeed: false }, function(storage) { var speed = storage.rememberSpeed ? storage.speed : '1.00'; target.playbackRate = speed; diff --git a/options.js b/options.js index 7eb6b28..51ecf40 100644 --- a/options.js +++ b/options.js @@ -69,7 +69,7 @@ function restore_options() { rewindKeyCode: 65, slowerKeyCode: 83, fasterKeyCode: 68, - rememberSpeed: true + rememberSpeed: false }, function(storage) { document.getElementById('speedStep').value = storage.speedStep.toFixed(2); document.getElementById('rewindTime').value = storage.rewindTime; @@ -87,7 +87,8 @@ function restore_defaults() { rewindTime: 10, rewindKeyCode: 65, slowerKeyCode: 83, - fasterKeyCode: 68 + fasterKeyCode: 68, + rememberSpeed: false }, function() { restore_options(); // Update status to let user know options were saved. From 8240e35a021659a9b356264302a61abcf460e280 Mon Sep 17 00:00:00 2001 From: Radu Filip Date: Sun, 17 Aug 2014 01:09:43 +0100 Subject: [PATCH 5/5] Fixed negative playback speed on rewind --- inject.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inject.js b/inject.js index 85225c1..352cadf 100644 --- a/inject.js +++ b/inject.js @@ -95,12 +95,12 @@ chrome.extension.sendMessage({}, function(response) { videoTags.forEach(function(v) { if (!v.paused && !v.classList.contains("vc-cancelled")) { if (action === 'rewind') { - v.playbackRate -= speedStep; + v.playbackRate = Math.max(v.playbackRate - speedStep, 0.00); v.currentTime -= rewindTime; } else if (action === 'faster') { v.playbackRate += speedStep } else if (action === 'slower') { - v.playbackRate = Math.max(v.playbackRate - speedStep, 0.00) } + v.playbackRate = Math.max(v.playbackRate - speedStep, 0.00); } } }); }