|
1 | 1 | // ==UserScript== |
2 | 2 | // @name YouTube Speed Override |
3 | | -// @description Override the default youtube controls for > and < |
| 3 | +// @description Override the default youtube controls for > and < and show remaining time when Option key is held |
4 | 4 | // @author Glenn 'devalias' Grant (devalias.net) |
5 | 5 | // @homepageURL https://github.com/0xdevalias/userscripts |
6 | 6 | // @supportURL https://github.com/0xdevalias/userscripts/issues |
7 | 7 | // @downloadURL https://github.com/0xdevalias/userscripts/raw/main/userscripts/youtube-speed-override/youtube-speed-override.user.js |
8 | 8 | // @namespace https://www.devalias.net/ |
9 | | -// @version 1.5 |
| 9 | +// @version 1.6 |
10 | 10 | // @match https://www.youtube.com/* |
11 | 11 | // @grant GM_getValue |
12 | 12 | // @grant GM_setValue |
|
19 | 19 | 'use strict'; |
20 | 20 |
|
21 | 21 | const LOG_PREFIX = '[userscript::youtube-speed-override]'; |
| 22 | + |
22 | 23 | let DEBUG = GM_getValue('isDebugEnabled', false); |
| 24 | + let isAltKeyPressed = false; |
23 | 25 |
|
24 | 26 | function debugLog(...args) { |
25 | 27 | if (!DEBUG) return |
26 | 28 |
|
27 | | - console.log(LOG_PREFIX, ...args); |
| 29 | + console.log(LOG_PREFIX, ...args, { DEBUG, isAltKeyPressed }); |
28 | 30 | } |
29 | 31 |
|
30 | 32 | function registerOrUpdateDebugMenuItem() { |
|
86 | 88 | const videoTimeDisplayDurationSelector = |
87 | 89 | '#movie_player .ytp-chrome-bottom .ytp-left-controls .ytp-time-display .ytp-time-duration'; |
88 | 90 |
|
| 91 | + const durationSpan = await waitForElement('#movie_player .ytp-chrome-bottom .ytp-left-controls .ytp-time-display .ytp-time-duration'); |
| 92 | + |
89 | 93 | // HACK: Track this internally to prevent weird interactions with the default YouTube handler |
90 | 94 | // let videoPlaybackRate = video.playbackRate; |
91 | 95 |
|
|
204 | 208 |
|
205 | 209 | // Function to update the time display with the adjusted length |
206 | 210 | function updateAdjustedTimeDisplay() { |
207 | | - if (video.playbackRate === 1) return; |
| 211 | + if (!video.duration) return |
| 212 | + |
| 213 | + // const originalCurrentTime = formatDuration(video.currentTime); |
| 214 | + const originalDuration = formatDuration(video.duration); |
| 215 | + |
| 216 | + // If rate is 1x, only update if alt/option key is pressed, otherwise reset to default |
| 217 | + if (!isAltKeyPressed && video.playbackRate === 1) { |
| 218 | + // Avoid updating if it's already the same content (might prevent some mutation handlers from triggering?) |
| 219 | + if (durationSpan.innerText === originalDuration) return |
| 220 | + |
| 221 | + durationSpan.innerText = originalDuration |
| 222 | + return; |
| 223 | + } |
208 | 224 |
|
209 | | - const durationSpan = document.querySelector( |
210 | | - videoTimeDisplayDurationSelector, |
| 225 | + const adjustedCurrentTime = formatDuration( |
| 226 | + video.currentTime / video.playbackRate, |
| 227 | + ); |
| 228 | + const adjustedDuration = formatDuration( |
| 229 | + video.duration / video.playbackRate, |
211 | 230 | ); |
212 | 231 |
|
213 | | - if (durationSpan) { |
214 | | - // const originalCurrentTime = formatDuration(video.currentTime); |
215 | | - const adjustedCurrentTime = formatDuration( |
216 | | - video.currentTime / video.playbackRate, |
217 | | - ); |
218 | | - |
219 | | - const originaDuration = formatDuration(video.duration); |
220 | | - const adjustedDuration = formatDuration( |
221 | | - video.duration / video.playbackRate, |
222 | | - ); |
223 | | - durationSpan.innerText = `${originaDuration} (${adjustedCurrentTime} / ${adjustedDuration} adjusted for ${video.playbackRate}x playback rate)`; |
| 232 | + if (!isAltKeyPressed) { |
| 233 | + durationSpan.innerText = `${originalDuration} (${adjustedCurrentTime} / ${adjustedDuration} adjusted for ${video.playbackRate}x playback rate)`; |
| 234 | + } else { |
| 235 | + const remainingTime = video.duration - video.currentTime; |
| 236 | + const adjustedRemainingTime = formatDuration(remainingTime / video.playbackRate); |
| 237 | + const percentageComplete = ((video.currentTime / video.duration) * 100).toFixed(2); |
| 238 | + |
| 239 | + durationSpan.innerText = `${originalDuration} (${adjustedRemainingTime} remaining / ${percentageComplete}% complete; adjusted for ${video.playbackRate}x playback rate)`; |
224 | 240 | } |
225 | 241 | } |
226 | 242 |
|
227 | 243 | // Override the default controls for > and < |
228 | 244 | document.addEventListener( |
229 | 245 | 'keydown', |
230 | 246 | (e) => { |
| 247 | + debugLog(`keydown event: ${e.key}`) |
| 248 | + |
| 249 | + if (e.altKey) { |
| 250 | + isAltKeyPressed = true; |
| 251 | + } |
| 252 | + |
231 | 253 | // TODO: I think this still doesn't properly prevent the default YouTube code from running, so sometimes we increase by more than 0.25 |
232 | 254 | // This might be fixed since I added capture: true |
233 | 255 | if (e.key === '>') { |
|
273 | 295 | { capture: true }, |
274 | 296 | ); |
275 | 297 |
|
| 298 | + document.addEventListener( |
| 299 | + 'keyup', |
| 300 | + (e) => { |
| 301 | + debugLog(`keyup event: ${e.key}`) |
| 302 | + |
| 303 | + if (!e.altKey) { |
| 304 | + isAltKeyPressed = false; |
| 305 | + } |
| 306 | + }, |
| 307 | + { capture: true }, |
| 308 | + ); |
| 309 | + |
276 | 310 | video.addEventListener('ratechange', () => { |
277 | 311 | // When the video playbackRate changes, update the playback speed in the settings menu to match our custom override |
278 | 312 | updateSettingsMenu(); |
|
0 commit comments