mirror of
				https://github.com/SoPat712/videospeed.git
				synced 2025-10-30 18:34:02 -04:00 
			
		
		
		
	
							
								
								
									
										46
									
								
								inject.js
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								inject.js
									
									
									
									
									
								
							| @@ -8,8 +8,11 @@ chrome.extension.sendMessage({}, function(response) { | |||||||
|         this.video = target; |         this.video = target; | ||||||
|         this.initializeControls(); |         this.initializeControls(); | ||||||
|  |  | ||||||
|         chrome.storage.sync.get('speed', function(storage) { |         chrome.storage.sync.get({ | ||||||
|           var speed = storage.speed ? storage.speed : '1.00'; |           speed: '1.00', | ||||||
|  |           rememberSpeed: false | ||||||
|  |         }, function(storage) { | ||||||
|  |           var speed = storage.rememberSpeed ? storage.speed : '1.00'; | ||||||
|           target.playbackRate = speed; |           target.playbackRate = speed; | ||||||
|           this.speedIndicator.textContent = speed; |           this.speedIndicator.textContent = speed; | ||||||
|         }.bind(this)); |         }.bind(this)); | ||||||
| @@ -92,18 +95,24 @@ chrome.extension.sendMessage({}, function(response) { | |||||||
|         videoTags.forEach(function(v) { |         videoTags.forEach(function(v) { | ||||||
|           if (!v.paused && !v.classList.contains("vc-cancelled")) { |           if (!v.paused && !v.classList.contains("vc-cancelled")) { | ||||||
|             if (action === 'rewind') { |             if (action === 'rewind') { | ||||||
|               v.playbackRate -= 0.10; |               v.playbackRate = Math.max(v.playbackRate - speedStep, 0.00); | ||||||
|               v.currentTime -= 10; |               v.currentTime -= rewindTime; | ||||||
|             } else if (action === 'faster') { v.playbackRate += 0.10 } |             } else if (action === 'faster') {  | ||||||
|               else if (action === 'slower') { v.playbackRate = Math.max(v.playbackRate - 0.10, 0.00) } |                 v.playbackRate += speedStep } | ||||||
|  |               else if (action === 'slower') {  | ||||||
|  |                   v.playbackRate = Math.max(v.playbackRate - speedStep, 0.00); } | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       document.addEventListener('keydown', function(event) { |       document.addEventListener('keypress', function(event) { | ||||||
|         if      (event.keyCode == 65) { runAction('rewind') } // A |          | ||||||
|         else if (event.keyCode == 68) { runAction('faster') } // D |         // if lowercase letter pressed, check for uppercase key code | ||||||
|         else if (event.keyCode == 83) { runAction('slower') } // S |         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; |         return false; | ||||||
|       }, true); |       }, true); | ||||||
| @@ -120,6 +129,23 @@ chrome.extension.sendMessage({}, function(response) { | |||||||
|       videoTags.forEach(function(video) { |       videoTags.forEach(function(video) { | ||||||
|         var control = new tc.videoController(video); |         var control = new tc.videoController(video); | ||||||
|       }); |       }); | ||||||
|  |          | ||||||
|  |       var speedStep, rewindTime, rewindKeyCode, slowerKeyCode, fasterKeyCode; | ||||||
|  |        | ||||||
|  |       chrome.storage.sync.get({  | ||||||
|  |         speedStep:        0.1, // default 0.10x | ||||||
|  |         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); |   }, 10); | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "HTML5 Video Playback Speed Controller", |   "name": "HTML5 Video Playback Speed Controller", | ||||||
|   "version": "0.1.2", |   "version": "0.1.3", | ||||||
|   "manifest_version": 2, |   "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.", |   "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", |   "homepage_url": "https://github.com/igrigorik/videospeed", | ||||||
| @@ -10,6 +10,7 @@ | |||||||
|     "128": "icons/icon128.png" |     "128": "icons/icon128.png" | ||||||
|   }, |   }, | ||||||
|   "permissions": [ "activeTab", "storage" ], |   "permissions": [ "activeTab", "storage" ], | ||||||
|  |   "options_page": "options.html", | ||||||
|   "content_scripts": [{ |   "content_scripts": [{ | ||||||
|       "all_frames": true, |       "all_frames": true, | ||||||
|       "matches": [ "http://*/*", "https://*/*"], |       "matches": [ "http://*/*", "https://*/*"], | ||||||
|   | |||||||
							
								
								
									
										94
									
								
								options.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								options.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | 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 { | ||||||
|  | 	-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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | input[type="text"] { | ||||||
|  |     width: 75px; | ||||||
|  |     text-align: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .row { | ||||||
|  |     margin: 5px 0px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | label { | ||||||
|  |     display: inline-block; | ||||||
|  |     width: 170px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | label[for=rememberSpeed] { | ||||||
|  |   width: 200px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #status { | ||||||
|  |     color: #9D9D9D; | ||||||
|  |     display: inline-block; | ||||||
|  |     margin-left: 50px; | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								options.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								options.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  | 	<head> | ||||||
|  | 		<title>HTML5 Video Playback Speed Controller Options</title> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="options.css" />	 | ||||||
|  | 	</head> | ||||||
|  | 	<body> | ||||||
|  | 		<header> | ||||||
|  | 			<h1>HTML5 Video Playback Speed Controller</h1> | ||||||
|  | 		</header> | ||||||
|  |          | ||||||
|  |         <section> | ||||||
|  |             <h3>Shortcuts</h3> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <label for="rewindKeyInput">Rewind</label> | ||||||
|  |                 <input id="rewindKeyInput" placeholder="press a key" type="text" value=""/> | ||||||
|  |             </div> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <label for="slowerKeyInput">Slow Down</label> | ||||||
|  |                 <input id="slowerKeyInput" placeholder="press a key" type="text" value=""/> | ||||||
|  |             </div> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <label for="fasterKeyInput">Speed Up</label> | ||||||
|  |                 <input id="fasterKeyInput" placeholder="press a key" type="text" value=""/> | ||||||
|  |             </div> | ||||||
|  |         </section> | ||||||
|  |        | ||||||
|  |         <section> | ||||||
|  | 			<h3>Others</h3> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <label for="rewindTime">Rewind Time (s)</label>  | ||||||
|  |                 <input id="rewindTime" type="text" value=""/>  | ||||||
|  |             </div> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <label for="speedStep">Speed Change Step</label> | ||||||
|  |                 <input id="speedStep" type="text" value=""/> | ||||||
|  |             </div> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <label for="rememberSpeed">Remember Playback Speed</label> | ||||||
|  |                 <input id="rememberSpeed" type="checkbox"/> | ||||||
|  |             </div> | ||||||
|  |         </section> | ||||||
|  | 		 | ||||||
|  |         <button id="save">Save</button>  <button id="restore">Restore Defaults</button> | ||||||
|  |         <div id="status"></div> | ||||||
|  |          | ||||||
|  | 	</body> | ||||||
|  |     <script type="text/javascript" src="options.js"></script> | ||||||
|  | </html> | ||||||
							
								
								
									
										120
									
								
								options.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								options.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | |||||||
|  | function recordKeyPress(e) { | ||||||
|  |   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 = String.fromCharCode(e.target.keyCode).toUpperCase(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | function updateShortcutInputText(inputId, keyCode) { | ||||||
|  |   document.getElementById(inputId).value = String.fromCharCode(keyCode).toUpperCase(); | ||||||
|  |   document.getElementById(inputId).keyCode = keyCode; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Saves options to chrome.storage | ||||||
|  | function save_options() { | ||||||
|  |   | ||||||
|  |   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; | ||||||
|  |   var rememberSpeed = document.getElementById('rememberSpeed').checked; | ||||||
|  |    | ||||||
|  |   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; | ||||||
|  |  | ||||||
|  |   chrome.storage.sync.set({ | ||||||
|  |     speedStep:      speedStep, | ||||||
|  |     rewindTime:     rewindTime, | ||||||
|  |     rewindKeyCode:  rewindKeyCode, | ||||||
|  |     slowerKeyCode:  slowerKeyCode, | ||||||
|  |     fasterKeyCode:  fasterKeyCode, | ||||||
|  |     rememberSpeed: rememberSpeed | ||||||
|  |   }, 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.1, | ||||||
|  |     rewindTime: 10, | ||||||
|  |     rewindKeyCode: 65, | ||||||
|  |     slowerKeyCode: 83, | ||||||
|  |     fasterKeyCode: 68, | ||||||
|  |     rememberSpeed: false | ||||||
|  |   }, 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; | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function restore_defaults() { | ||||||
|  |    | ||||||
|  |   chrome.storage.sync.set({ | ||||||
|  |     speedStep: 0.1, | ||||||
|  |     rewindTime: 10, | ||||||
|  |     rewindKeyCode: 65, | ||||||
|  |     slowerKeyCode: 83, | ||||||
|  |     fasterKeyCode: 68, | ||||||
|  |     rememberSpeed: false | ||||||
|  |   }, 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'); | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  |   document.getElementById(inputId).addEventListener('keypress', recordKeyPress); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Ilya Grigorik
					Ilya Grigorik