From 2d8a4fc25f475d69d07869e7f178f4397caf0e51 Mon Sep 17 00:00:00 2001 From: Josh Patra <30350506+SoPat712@users.noreply.github.com> Date: Mon, 19 May 2025 12:54:35 -0400 Subject: [PATCH] add nudge to settings --- inject.js | 403 +++++++++++++++++++------------------------------ manifest.json | 6 +- options.html | 64 ++++++-- options.js | 278 +++++++++++++++++----------------- videospeed.xpi | Bin 0 -> 57329 bytes 5 files changed, 352 insertions(+), 399 deletions(-) create mode 100644 videospeed.xpi diff --git a/inject.js b/inject.js index f5b557d..201aec2 100644 --- a/inject.js +++ b/inject.js @@ -2,16 +2,15 @@ var regStrip = /^[\r\t\f\v ]+|[\r\t\f\v ]+$/gm; var tc = { settings: { - lastSpeed: 1.0, // default 1x - enabled: true, // default enabled - speeds: {}, // empty object to hold speed for each source - - displayKeyCode: 86, // default: V - rememberSpeed: false, // default: false - forceLastSavedSpeed: false, //default: false - audioBoolean: false, // default: false - startHidden: false, // default: false - controllerOpacity: 0.3, // default: 0.3 + lastSpeed: 1.0, + enabled: true, + speeds: {}, + displayKeyCode: 86, + rememberSpeed: false, + forceLastSavedSpeed: false, + audioBoolean: false, + startHidden: false, + controllerOpacity: 0.3, keyBindings: [], blacklist: `\ www.instagram.com @@ -27,30 +26,21 @@ var tc = { subtitleNudgeInterval: 25, subtitleNudgeAmount: 0.001 }, - - // Holds a reference to all of the AUDIO/VIDEO DOM elements we've attached to mediaElements: [], - isNudging: false // Flag for nudge operation (ADDED) + isNudging: false // ADDED: Flag for nudge operation }; -/* Log levels (depends on caller specifying the correct level) */ +/* Log levels */ function log(message, level) { verbosity = tc.settings.logLevel; - if (typeof level === "undefined") { - level = tc.settings.defaultLogLevel; - } + if (typeof level === "undefined") level = tc.settings.defaultLogLevel; if (verbosity >= level) { - // MODIFIED: Added [VSC] prefix for clarity let prefix = "[VSC] "; - if (level === 2) { - console.log(prefix + "ERROR: " + message); - } else if (level === 3) { - console.log(prefix + "WARNING: " + message); - } else if (level === 4) { - console.log(prefix + "INFO: " + message); - } else if (level === 5) { - console.log(prefix + "DEBUG: " + message); - } else if (level === 6) { + if (level === 2) console.log(prefix + "ERROR: " + message); + else if (level === 3) console.log(prefix + "WARNING: " + message); + else if (level === 4) console.log(prefix + "INFO: " + message); + else if (level === 5) console.log(prefix + "DEBUG: " + message); + else if (level === 6) { console.log(prefix + "DEBUG (VERBOSE): " + message); console.trace(); } @@ -58,7 +48,7 @@ function log(message, level) { } chrome.storage.sync.get(tc.settings, function (storage) { - // MODIFIED: Robust keyBinding initialization from storage or defaults. + // MODIFIED: Robust keyBinding initialization tc.settings.keyBindings = Array.isArray(storage.keyBindings) && storage.keyBindings.length > 0 && @@ -99,7 +89,7 @@ chrome.storage.sync.get(tc.settings, function (storage) { value: 1.0, force: false, predefined: true - }, // Default value for reset action is 1.0 + }, { action: "fast", key: Number(storage.fastKeyCode) || 71, @@ -117,7 +107,7 @@ chrome.storage.sync.get(tc.settings, function (storage) { log("Initializing/Updating keybindings in storage.", 4); chrome.storage.sync.set({ keyBindings: tc.settings.keyBindings, - version: "0.6.3.8" + version: "0.6.3.10" }); // Update version } @@ -132,16 +122,16 @@ chrome.storage.sync.get(tc.settings, function (storage) { tc.settings.controllerOpacity = Number(storage.controllerOpacity) || 0.3; tc.settings.blacklist = String(storage.blacklist || tc.settings.blacklist); - if (typeof storage.logLevel !== "undefined") { + if (typeof storage.logLevel !== "undefined") tc.settings.logLevel = Number(storage.logLevel); - } - // ADDED: Load nudge settings from storage + + // ADDED: Load nudge settings tc.settings.enableSubtitleNudge = typeof storage.enableSubtitleNudge !== "undefined" ? Boolean(storage.enableSubtitleNudge) : tc.settings.enableSubtitleNudge; tc.settings.subtitleNudgeInterval = - Number(storage.subtitleNudgeInterval) || 25; // Using 25ms as requested + Number(storage.subtitleNudgeInterval) || 25; tc.settings.subtitleNudgeAmount = Number(storage.subtitleNudgeAmount) || tc.settings.subtitleNudgeAmount; @@ -156,18 +146,18 @@ chrome.storage.sync.get(tc.settings, function (storage) { predefined: true }); } - initializeWhenReady(document); }); function getKeyBindings(action, what = "value") { - if (!tc.settings.keyBindings) return false; // ADDED: Guard against undefined keyBindings + // Original getKeyBindings + if (!tc.settings.keyBindings) return false; try { const binding = tc.settings.keyBindings.find( (item) => item.action === action ); if (binding) return binding[what]; - // Fallback defaults for safety + // Fallbacks from original if (what === "value") { if (action === "slower" || action === "faster") return 0.1; if (action === "rewind" || action === "advance") return 10; @@ -181,64 +171,42 @@ function getKeyBindings(action, what = "value") { } } -// Original setKeyBindings, used by original resetSpeed logic. +// Original setKeyBindings from your provided code (used by original resetSpeed) function setKeyBindings(action, value) { - if (!tc.settings.keyBindings) return; // ADDED: Guard + if (!tc.settings.keyBindings) return; const binding = tc.settings.keyBindings.find( (item) => item.action === action ); if (binding) { binding["value"] = value; - log( - `In-memory value for keyBinding '${action}' set to ${value} by original setKeyBindings func`, - 6 - ); } } function defineVideoController() { tc.videoController = function (target, parent) { - if (target.vsc) { - log(`VSC controller already exists for ${target.src || "video"}.`, 6); - return target.vsc; - } + if (target.vsc) return target.vsc; log(`Creating VSC controller for ${target.src || "video"}.`, 4); - tc.mediaElements.push(target); target.vsc = this; this.video = target; this.parent = parent || target.parentElement; - this.nudgeIntervalId = null; // ADDED: For the subtitle nudge feature + this.nudgeIntervalId = null; // ADDED for nudge - // Original logic for determining initial speed - let storedSpeed; + let storedSpeed; // Original logic if (!tc.settings.rememberSpeed) { storedSpeed = tc.settings.speeds[target.currentSrc]; - if (!storedSpeed) { - log( - "Overwriting stored speed to 1.0 due to rememberSpeed being disabled or no speed for src", - 5 - ); - storedSpeed = 1.0; - } - setKeyBindings("reset", getKeyBindings("fast")); // Original logic for 'R' key toggle state + if (!storedSpeed) storedSpeed = 1.0; + setKeyBindings("reset", getKeyBindings("fast")); } else { - log("Recalling stored speed due to rememberSpeed being enabled", 5); storedSpeed = tc.settings.speeds[target.currentSrc] || tc.settings.lastSpeed; } - if (tc.settings.forceLastSavedSpeed) { - storedSpeed = tc.settings.lastSpeed; - } + if (tc.settings.forceLastSavedSpeed) storedSpeed = tc.settings.lastSpeed; this.div = this.initializeControls(); if (Math.abs(target.playbackRate - storedSpeed) > 0.001) { - log( - `Video current rate ${target.playbackRate.toFixed(2)} differs from VSC target ${storedSpeed.toFixed(2)}. Setting speed (initial).`, - 4 - ); setSpeed(target, storedSpeed, true); // MODIFIED: Pass true for isInitialSet } else { if (this.speedIndicator) @@ -251,12 +219,11 @@ function defineVideoController() { } } - // Original mediaEventAction var mediaEventAction = function (event) { + // Original mediaEventAction const video = event.target; if (!video.vsc) return; - - let speedToSet = tc.settings.speeds[video.currentSrc]; // Use 'let' + let speedToSet = tc.settings.speeds[video.currentSrc]; if (!tc.settings.rememberSpeed) { if (!speedToSet) speedToSet = 1.0; setKeyBindings("reset", getKeyBindings("fast")); @@ -266,14 +233,9 @@ function defineVideoController() { if (tc.settings.forceLastSavedSpeed) speedToSet = tc.settings.lastSpeed; if (Math.abs(video.playbackRate - speedToSet) > 0.001) { - log( - `Media event '${event.type}': rate ${video.playbackRate.toFixed(2)} vs target ${speedToSet.toFixed(2)}. Setting.`, - 4 - ); setSpeed(video, speedToSet, false); // MODIFIED: isInitialSet is false } - - // ADDED: Manage nudge based on event type + // ADDED: Manage nudge if (event.type === "play") video.vsc.startSubtitleNudge(); else if (event.type === "pause" || event.type === "ended") video.vsc.stopSubtitleNudge(); @@ -286,32 +248,31 @@ function defineVideoController() { target.addEventListener( "pause", (this.handlePause = mediaEventAction.bind(this)) - ); // ADDED for nudge + ); // ADDED target.addEventListener( "ended", (this.handleEnded = mediaEventAction.bind(this)) - ); // ADDED for nudge + ); // ADDED target.addEventListener( "seeked", (this.handleSeek = mediaEventAction.bind(this)) ); var srcObserver = new MutationObserver((mutations) => { + // Original srcObserver mutations.forEach((mutation) => { if ( mutation.type === "attributes" && (mutation.attributeName === "src" || mutation.attributeName === "currentSrc") ) { - if (!this.div) return; // MODIFIED: Check if div exists - log(`Src changed to: ${mutation.target.currentSrc || "empty"}`, 4); - this.stopSubtitleNudge(); // ADDED: Stop nudge for old src - - if (!mutation.target.src && !mutation.target.currentSrc) { + if (!this.div) return; + this.stopSubtitleNudge(); // ADDED + if (!mutation.target.src && !mutation.target.currentSrc) this.div.classList.add("vsc-nosource"); - } else { + else { this.div.classList.remove("vsc-nosource"); - let newSrcSpeed = tc.settings.speeds[mutation.target.currentSrc]; // MODIFIED: Follow original logic + let newSrcSpeed = tc.settings.speeds[mutation.target.currentSrc]; if (!tc.settings.rememberSpeed) { if (!newSrcSpeed) newSrcSpeed = 1.0; } else { @@ -319,7 +280,6 @@ function defineVideoController() { } if (tc.settings.forceLastSavedSpeed) newSrcSpeed = tc.settings.lastSpeed; - setSpeed(mutation.target, newSrcSpeed, true); // MODIFIED: isInitialSet = true if (!mutation.target.paused && mutation.target.playbackRate !== 1.0) this.startSubtitleNudge(); // ADDED @@ -329,14 +289,13 @@ function defineVideoController() { }); srcObserver.observe(target, { attributeFilter: ["src", "currentSrc"] }); - // ADDED: Initial nudge check - if (!target.paused && target.playbackRate !== 1.0) { - this.startSubtitleNudge(); - } + if (!target.paused && target.playbackRate !== 1.0) + this.startSubtitleNudge(); // ADDED }; // --- Nudge Methods (ADDED) --- tc.videoController.prototype.startSubtitleNudge = function () { + if (!location.hostname.includes("youtube.com")) return; // ADDED: Nudge only on YouTube if ( !tc.settings.enableSubtitleNudge || this.nudgeIntervalId !== null || @@ -347,10 +306,7 @@ function defineVideoController() { this.stopSubtitleNudge(); return; } - log( - `Nudge: Starting for ${this.video.currentSrc || "video"} (Rate: ${this.video.playbackRate.toFixed(2)}) interval: ${tc.settings.subtitleNudgeInterval}ms.`, - 5 - ); + log(`Nudge: Starting interval: ${tc.settings.subtitleNudgeInterval}ms.`, 5); this.nudgeIntervalId = setInterval(() => { if ( !this.video || @@ -363,10 +319,8 @@ function defineVideoController() { } const currentRate = this.video.playbackRate; const nudgeAmount = tc.settings.subtitleNudgeAmount; - tc.isNudging = true; this.video.playbackRate = currentRate + nudgeAmount; - requestAnimationFrame(() => { if ( this.video && @@ -379,49 +333,43 @@ function defineVideoController() { }); }, tc.settings.subtitleNudgeInterval); }; - tc.videoController.prototype.stopSubtitleNudge = function () { if (this.nudgeIntervalId !== null) { - log( - `Nudge: Stopping for ${this.video ? this.video.currentSrc || "video" : "detached video"}`, - 5 - ); + log(`Nudge: Stopping.`, 5); clearInterval(this.nudgeIntervalId); this.nudgeIntervalId = null; } }; - // --- End Nudge Methods --- tc.videoController.prototype.remove = function () { + // Original remove this.stopSubtitleNudge(); // ADDED - // Original remove logic: if (this.div && this.div.parentNode) this.div.remove(); if (this.video) { this.video.removeEventListener("play", this.handlePlay); this.video.removeEventListener("pause", this.handlePause); // ADDED this.video.removeEventListener("ended", this.handleEnded); // ADDED - this.video.removeEventListener("seeked", this.handleSeek); // MODIFIED: was "seek" in original provided code + this.video.removeEventListener("seeked", this.handleSeek); // Original had "seek" delete this.video.vsc; } let idx = tc.mediaElements.indexOf(this.video); if (idx !== -1) tc.mediaElements.splice(idx, 1); }; - // Original initializeControls tc.videoController.prototype.initializeControls = function () { + // Original initializeControls log("initializeControls Begin", 5); const doc = this.video.ownerDocument; const speedForUI = this.video.playbackRate.toFixed(2); var top = Math.max(this.video.offsetTop, 0) + "px", left = Math.max(this.video.offsetLeft, 0) + "px"; - log("Speed variable for UI set to: " + speedForUI, 5); var wrapper = doc.createElement("div"); wrapper.classList.add("vsc-controller"); if (!this.video.src && !this.video.currentSrc) wrapper.classList.add("vsc-nosource"); if (tc.settings.startHidden) wrapper.classList.add("vsc-hidden"); var shadow = wrapper.attachShadow({ mode: "open" }); - var shadowTemplate = ` + shadow.innerHTML = `
${speedForUI} @@ -433,7 +381,6 @@ function defineVideoController() {
`; - shadow.innerHTML = shadowTemplate; this.speedIndicator = shadow.querySelector(".draggable"); // MODIFIED: Original was "span" // MODIFIED: Pass this.video as 4th arg to runAction @@ -450,8 +397,8 @@ function defineVideoController() { }, true ); - shadow.querySelectorAll("button").forEach((button) => { - button.addEventListener( + shadow.querySelectorAll("button").forEach((btn) => + btn.addEventListener( "click", (e) => { runAction( @@ -463,8 +410,8 @@ function defineVideoController() { e.stopPropagation(); }, true - ); - }); + ) + ); shadow .querySelector("#controller") .addEventListener("click", (e) => e.stopPropagation(), false); @@ -473,8 +420,8 @@ function defineVideoController() { .addEventListener("mousedown", (e) => e.stopPropagation(), false); var fragment = doc.createDocumentFragment(); fragment.appendChild(wrapper); - const parentEl = this.parent || this.video.parentElement; - if (!parentEl || !parentEl.parentNode) { + const pEl = this.parent || this.video.parentElement; + if (!pEl || !pEl.parentNode) { doc.body.appendChild(fragment); return wrapper; } @@ -483,38 +430,35 @@ function defineVideoController() { case location.hostname == "www.amazon.com": case location.hostname == "www.reddit.com": case /hbogo\./.test(location.hostname): - parentEl.parentElement.insertBefore(fragment, parentEl); + pEl.parentElement.insertBefore(fragment, pEl); break; case location.hostname == "www.facebook.com": let p = - parentEl.parentElement.parentElement.parentElement.parentElement + pEl.parentElement.parentElement.parentElement.parentElement .parentElement.parentElement.parentElement; if (p && p.firstChild) p.insertBefore(fragment, p.firstChild); - else if (parentEl.firstChild) - parentEl.insertBefore(fragment, parentEl.firstChild); - else parentEl.appendChild(fragment); + else if (pEl.firstChild) pEl.insertBefore(fragment, pEl.firstChild); + else pEl.appendChild(fragment); break; case location.hostname == "tv.apple.com": - const appleRoot = parentEl.getRootNode(); - const scrim = - appleRoot && appleRoot.querySelector - ? appleRoot.querySelector(".scrim") - : null; - if (scrim) scrim.prepend(fragment); - else parentEl.insertBefore(fragment, parentEl.firstChild); + const r = pEl.getRootNode(); + const s = r && r.querySelector ? r.querySelector(".scrim") : null; + if (s) s.prepend(fragment); + else pEl.insertBefore(fragment, pEl.firstChild); break; default: - parentEl.insertBefore(fragment, parentEl.firstChild); + pEl.insertBefore(fragment, pEl.firstChild); } return wrapper; }; } function escapeStringRegExp(str) { - const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; - return str.replace(matchOperatorsRe, "\\$&"); -} + const m = /[|\\{}()[\]^$+*?.]/g; + return str.replace(m, "\\$&"); +} // Original function isBlacklisted() { + /* ... same original logic (with robust regex) ... */ let blacklisted = false; const blacklistLines = tc.settings.blacklist ? tc.settings.blacklist.split("\n") @@ -539,18 +483,18 @@ function isBlacklisted() { return blacklisted; } -var coolDown = false; +var coolDown = false; // Original coolDown function refreshCoolDown() { + // Original refreshCoolDown log("Begin refreshCoolDown", 5); if (coolDown) clearTimeout(coolDown); coolDown = setTimeout(function () { coolDown = false; }, 1000); - // log("End refreshCoolDown", 6); // Original log level was 5 } function setupListener() { - if (document.vscRateListenerAttached) return; // MODIFIED: Ensure flag check + if (document.vscRateListenerAttached) return; // Original flag was vscRateChangeListenerAttached // MODIFIED: fromUserInput parameter added function updateSpeedFromEvent(video, fromUserInput = false) { @@ -565,12 +509,12 @@ function setupListener() { tc.settings.speeds[video.currentSrc || "unknown_src"] = speed; tc.settings.lastSpeed = speed; chrome.storage.sync.set({ lastSpeed: speed }, () => { - if (chrome.runtime.lastError) - log(`Error saving lastSpeed: ${chrome.runtime.lastError.message}`, 2); + /* error handling if needed */ }); // MODIFIED: Only "blink" (show controller) if change was from user input if (fromUserInput) { + // The original runAction("blink", null, null) implies value is taken from keybinding or default runAction("blink", getKeyBindings("blink", "value") || 1000, null, video); } @@ -586,7 +530,6 @@ function setupListener() { function (event) { // ADDED: Check tc.isNudging at the very start if (tc.isNudging) { - // log("Ratechange event during nudge, VSC UI/state update skipped. Allowing propagation for YT.", 6); return; } @@ -602,7 +545,7 @@ function setupListener() { return; const eventOrigin = event.detail && event.detail.origin; - let isFromUserInputForBlink = false; // MODIFIED: Flag to control blink + let isFromUserInputForBlink = false; if (tc.settings.forceLastSavedSpeed) { if (eventOrigin === "videoSpeed") { @@ -615,100 +558,60 @@ function setupListener() { video.playbackRate = detailSpeedNum; } } - isFromUserInputForBlink = event.detail.fromUserInput !== false; // Respect passed flag + // Use fromUserInput from event.detail if present (set by setSpeed) + isFromUserInputForBlink = event.detail.fromUserInput !== false; updateSpeedFromEvent(video, isFromUserInputForBlink); event.stopImmediatePropagation(); } else { if (Math.abs(video.playbackRate - tc.settings.lastSpeed) > 0.001) { - log( - `Ratechange (Force ON): Discrepancy. Video rate: ${video.playbackRate.toFixed(2)}, VSC wants: ${tc.settings.lastSpeed.toFixed(2)}. Forcing.`, - 3 - ); video.playbackRate = tc.settings.lastSpeed; event.stopImmediatePropagation(); - // The next ratechange will be from VSC forcing, consider that not direct user input for blink - // updateSpeedFromEvent will be called by that next event. } else { - updateSpeedFromEvent(video, false); // Not user input, just confirming forced speed + updateSpeedFromEvent(video, false); } } } else { // forceLastSavedSpeed is OFF - // Determine if it was a VSC-initiated user action (like S/D keys) - // The `setSpeed` function, when called by `runAction`, doesn't add a special origin detail - // when forceLastSavedSpeed is off. So, a native ratechange event fires. - // We assume if forceLastSavedSpeed is off, any rate change processed here - // that isn't a nudge IS significant enough to update UI state. - // The "blink" should happen if tc.settings.lastSpeed *changed* due to this event, - // implying it wasn't just a confirmation of existing speed. - const oldLastSpeed = tc.settings.lastSpeed; - updateSpeedFromEvent(video, false); // Initially assume not user-driven for blink - if ( - Math.abs(oldLastSpeed - tc.settings.lastSpeed) > 0.001 && - oldLastSpeed !== 1.0 && - tc.settings.lastSpeed !== 1.0 - ) { - // If lastSpeed actually changed due to this event, it was likely a user action via VSC - // or a significant external change. Trigger blink. - // Exception: don't blink if going to/from 1.0x as that's often a reset. - // This logic is imperfect for determining "user input" when not forcing. - // A cleaner way would be if setSpeed could flag the *next* native event. - // For now, this is a heuristic. - if (!tc.isNudging) { - // Double check not a nudge, though already filtered - runAction( - "blink", - getKeyBindings("blink", "value") || 1000, - null, - video - ); - } - } + // If setSpeed was called (which sets video.vscIsDirectSetByVSC) + // then it's a user-driven change (or initial set). + isFromUserInputForBlink = video.vscIsDirectSetByVSC === true; + if (video.hasOwnProperty("vscIsDirectSetByVSC")) + delete video.vscIsDirectSetByVSC; // Consume flag + + updateSpeedFromEvent(video, isFromUserInputForBlink); + // DO NOT stop propagation when forceLastSavedSpeed is OFF } }, true ); - document.vscRateChangeListenerAttached = true; // MODIFIED: Ensure flag is set + document.vscRateListenerAttached = true; // Original flag name } -// MODIFIED: More robust initialization flow with unique flags +// Original initializeWhenReady and initializeNow structure, with unique flags for re-entrancy checks var vscInitializedDocuments = new Set(); function initializeWhenReady(doc) { - if (doc.vscInitWhenReadyCalledFullUniqueFlag && doc.readyState !== "loading") - return; - doc.vscInitWhenReadyCalledFullUniqueFlag = true; - if (isBlacklisted()) { - return; - } + if (doc.vscInitWhenReadyUniqueFlag1 && doc.readyState !== "loading") return; + doc.vscInitWhenReadyUniqueFlag1 = true; + if (isBlacklisted()) return; log( - `initializeWhenReady for: ${doc.location ? doc.location.href : "iframe"}. ReadyState: ${doc.readyState}`, + `initializeWhenReady for: ${doc.location ? doc.location.href : "iframe"}. RS: ${doc.readyState}`, 5 ); - - if (doc === window.document && !window.vscPageLoadListenerFullUniqueFlag) { + if (doc === window.document && !window.vscPageLoadListenerUniqueFlag1) { window.addEventListener("load", () => initializeNow(window.document), { once: true }); - window.vscPageLoadListenerFullUniqueFlag = true; + window.vscPageLoadListenerUniqueFlag1 = true; } - if (doc.readyState === "complete") { - initializeNow(doc); - } else { - if (!doc.vscReadyStateListenerFullUniqueFlag) { - doc.addEventListener( - "readystatechange", - function onRSChange_VSC_Final_Unique_CB() { - if (doc.readyState === "complete") { - doc.removeEventListener( - "readystatechange", - onRSChange_VSC_Final_Unique_CB - ); - initializeNow(doc); - } - } - ); - doc.vscReadyStateListenerFullUniqueFlag = true; - } + if (doc.readyState === "complete") initializeNow(doc); + else if (!doc.vscReadyStateListenerUniqueFlag1) { + doc.addEventListener("readystatechange", function onRSChangeUnique1() { + if (doc.readyState === "complete") { + doc.removeEventListener("readystatechange", onRSChangeUnique1); + initializeNow(doc); + } + }); + doc.vscReadyStateListenerUniqueFlag1 = true; } } function inIframe() { @@ -719,6 +622,7 @@ function inIframe() { } } function getShadow(parent) { + /* ... original logic ... */ let result = []; function getChild(p) { if (p.firstElementChild) { @@ -742,7 +646,7 @@ function initializeNow(doc) { 4 ); if (!tc.settings.enabled) { - log("VSC is disabled.", 4); + log("VSC disabled.", 4); return; } if (!doc.body.classList.contains("vsc-initialized")) @@ -766,8 +670,8 @@ function initializeNow(doc) { docsForKeydown.add(window.top.document); } catch (e) {} docsForKeydown.forEach((lDoc) => { - if (!lDoc.vscKeydownListenerUniqueFlagB) { - // Different flag + if (!lDoc.vscKeydownListenerUniqueFlagC) { + // Unique flag name lDoc.addEventListener( "keydown", function (event) { @@ -807,11 +711,11 @@ function initializeNow(doc) { }, true ); - lDoc.vscKeydownListenerUniqueFlagB = true; + lDoc.vscKeydownListenerUniqueFlagC = true; } }); - if (!doc.vscMutationObserverUniqueFlagB) { - // Different flag + if (!doc.vscMutationObserverUniqueFlagC) { + // Unique flag name const obs = new MutationObserver((muts) => { if (typeof requestIdleCallback === "function") requestIdleCallback(() => processMutations(muts), { timeout: 1000 }); @@ -865,7 +769,7 @@ function initializeNow(doc) { attributes: true, attributeFilter: ["aria-hidden"] }); - doc.vscMutationObserverUniqueFlagB = true; + doc.vscMutationObserverUniqueFlagC = true; } const q = tc.settings.audioBoolean ? "video,audio" : "video"; doc.querySelectorAll(q).forEach((vid) => { @@ -879,7 +783,7 @@ function initializeNow(doc) { vscInitializedDocuments.add(doc); } -// MODIFIED setSpeed to accept `isInitialCall` and use it for `fromUserInput` +// MODIFIED setSpeed to accept `isInitialCall` and pass it for `fromUserInput` in custom event function setSpeed(video, speed, isInitialCall = false) { const numericSpeed = Number(speed); if (isNaN(numericSpeed) || numericSpeed <= 0 || numericSpeed > 16) return; @@ -904,23 +808,23 @@ function setSpeed(video, speed, isInitialCall = false) { ); } else { if (Math.abs(video.playbackRate - numericSpeed) > 0.001) { - // Before changing rate, set a flag that this is VSC initiated for non-forced mode - video.vscIsSettingRate = !isInitialCall; // True if user action, false if initial + // ADDED: Set a temporary flag on the video element itself before changing playbackRate + // This helps the native ratechange event handler determine if VSC initiated this change. + if (!isInitialCall) { + video.vscIsDirectlySettingRate = true; + } video.playbackRate = numericSpeed; - // Flag will be cleared by ratechange listener after processing } } - if (!isInitialCall) refreshCoolDown(); + if (!isInitialCall) refreshCoolDown(); // Original call if (video.vsc) { if (numericSpeed === 1.0 || video.paused) video.vsc.stopSubtitleNudge(); else video.vsc.startSubtitleNudge(); } } -// MODIFIED runAction to pass 4th arg `specificVideo` to some internal calls if needed. -// And pass `isInitialCall=false` to setSpeed calls. +// MODIFIED runAction for specificVideo targeting and passing `isInitialCall=false` to setSpeed function runAction(action, value, e, specificVideo = null) { - // ... (robust mediaTagsToProcess logic from previous correct version) ... var mediaTagsToProcess = []; if (specificVideo) mediaTagsToProcess = [specificVideo]; else if (e && e.target) { @@ -955,8 +859,9 @@ function runAction(action, value, e, specificVideo = null) { e && e.target && e.target.getRootNode && e.target.getRootNode().host ? e.target.getRootNode().host : null; - var originalActionForResetContext = actionBeingProcessedForReset_ctx; // Use a local context var - actionBeingProcessedForReset_ctx = action; + + // Store current action for original resetSpeed context (local to this runAction call) + const currentActionContext = action; mediaTagsToProcess.forEach(function (v) { if (!v || !v.vsc || !v.vsc.div || !v.vsc.speedIndicator) return; @@ -969,6 +874,7 @@ function runAction(action, value, e, specificVideo = null) { return; if (action === "blink" && specificVideo && v !== specificVideo) return; + // MODIFIED: showController only for explicit user-driven actions, not "blink" itself const userDrivenActionsThatShowController = [ "rewind", "advance", @@ -1008,12 +914,12 @@ function runAction(action, value, e, specificVideo = null) { case "slower": setSpeed(v, Math.max(v.playbackRate - numValue, 0.07), false); break; - // MODIFIED: Calls new resetSpeed directly + // MODIFIED: Passing currentActionContext to original resetSpeed case "reset": - resetSpeedSimple(v, 1.0); + resetSpeed(v, 1.0, currentActionContext); break; case "fast": - resetSpeedSimple(v, numValue); + resetSpeed(v, numValue, currentActionContext); break; case "display": controllerDiv.classList.add("vsc-manual"); @@ -1060,45 +966,44 @@ function runAction(action, value, e, specificVideo = null) { log(`Unknown action: ${action}`, 3); } }); - actionBeingProcessedForReset_ctx = originalActionForResetContext; } -var actionBeingProcessedForReset_ctx = null; // Context for original resetSpeed +// Removed global actionBeingProcessedForReset_global function pause(v) { if (v.paused) v.play().catch((e) => log(`Play err:${e.message}`, 2)); else v.pause(); } -// MODIFIED: New simpler resetSpeed function -function resetSpeedSimple(v, targetActionSpeed) { +// MODIFIED: Original resetSpeed function now takes currentActionContext +function resetSpeed(v, target, currentActionContext = null) { log( - `resetSpeedSimple: Video current: ${v.playbackRate.toFixed(2)}, Target for this action: ${targetActionSpeed.toFixed(2)}`, + `resetSpeed (original): Video current: ${v.playbackRate.toFixed(2)}, Target: ${target.toFixed(2)}, Context: ${currentActionContext}`, 4 ); - const fastPreferredSpeed = getKeyBindings("fast", "value") || 1.8; - if (targetActionSpeed === 1.0) { - // Action was "reset" (R key) - if (Math.abs(v.playbackRate - 1.0) < 0.01) { - setSpeed(v, fastPreferredSpeed, false); + if (Math.abs(v.playbackRate - target) < 0.01) { + // Using Math.abs for float comparison + // If current speed IS the target of THIS action + if (v.playbackRate === (getKeyBindings("reset", "value") || 1.0)) { + if (target !== 1.0) { + setSpeed(v, 1.0, false); + } else { + // Target is 1.0 and current is 1.0 (or what reset key last stored) -> go to fast + setSpeed(v, getKeyBindings("fast", "value"), false); + } } else { - setSpeed(v, 1.0, false); + // Current is target, but not what 'reset' binding value holds (e.g. G pressed, current is fast speed) + setSpeed(v, getKeyBindings("reset", "value") || 1.0, false); } } else { - // Action was "fast" (G key), targetActionSpeed is the preferred speed - if (Math.abs(v.playbackRate - targetActionSpeed) < 0.01) { - setSpeed(v, 1.0, false); - } else { - setSpeed(v, targetActionSpeed, false); + // Current speed is NOT the target of this action. Set to the target. + if (currentActionContext === "reset") { + // Only do this for 'reset' action context + setKeyBindings("reset", v.playbackRate); // Original call to store current rate } + setSpeed(v, target, false); } } -// Remove or comment out the old `resetSpeed` function that uses setKeyBindings and actionBeingProcessedForReset_global -/* -function resetSpeed(v, target) { // THIS IS THE OLD ONE TO BE REPLACED by resetSpeedSimple - // ... original complex logic ... -} -*/ function muted(v) { v.muted = !v.muted; @@ -1114,7 +1019,7 @@ function jumpToMark(v) { else log("No mark.", 4); } function handleDrag(video, e) { - /* ... same original ... */ + /* ... same original logic ... */ if (!video || !video.vsc || !video.vsc.div || !video.vsc.div.shadowRoot) return; const controller = video.vsc.div; @@ -1156,7 +1061,7 @@ function handleDrag(video, e) { } var timer = null; function showController(controller) { - /* ... same original ... */ + /* ... same original logic ... */ if (!controller || typeof controller.classList === "undefined") return; controller.classList.add("vcs-show"); if (timer) clearTimeout(timer); diff --git a/manifest.json b/manifest.json index 2987782..3203e1e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,13 +1,13 @@ { "name": "Video Speed Controller", "short_name": "videospeed", - "version": "0.6.3.3", + "version": "1.1.0", "manifest_version": 2, "description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts", - "homepage_url": "https://github.com/codebicycle/videospeed", + "homepage_url": "https://github.com/SoPat712/videospeed", "browser_specific_settings": { "gecko": { - "id": "{7be2ba16-0f1e-4d93-9ebc-5164397477a9}" + "id": "{ed860648-f54f-4dc9-9a0d-501aec4313f5}" } }, "icons": { diff --git a/options.html b/options.html index 242c326..22925f1 100644 --- a/options.html +++ b/options.html @@ -1,4 +1,4 @@ - + Video Speed Controller: Options @@ -148,8 +148,13 @@
- +
@@ -175,6 +180,47 @@
+
+

Subtitle Nudge Settings (Experimental - YouTube Only)

+
+ + +
+
+ + +
+
+ + +
+
+ @@ -186,12 +232,12 @@

Extension controls not appearing?

- This extension is only compatible with HTML5 audio and video. If you don't - see the controls showing up, chances are you are viewing a Flash content. - If you want to confirm, try right-clicking on the content and inspect the - menu: if it mentions flash, then that's the issue. That said, most sites - will fallback to HTML5 if they detect that Flash is not available. You - can try manually disabling Flash from the browser. + This extension is only compatible with HTML5 audio and video. If you + don't see the controls showing up, chances are you are viewing a Flash + content. If you want to confirm, try right-clicking on the content and + inspect the menu: if it mentions flash, then that's the issue. That + said, most sites will fallback to HTML5 if they detect that Flash + is not available. You can try manually disabling Flash from the browser.

diff --git a/options.js b/options.js index e1b8b95..d33d794 100644 --- a/options.js +++ b/options.js @@ -22,13 +22,17 @@ var tcDefaults = { twitter.com imgur.com teams.microsoft.com - `.replace(regStrip, "") + `.replace(regStrip, ""), + // ADDED: Nudge defaults + enableSubtitleNudge: true, + subtitleNudgeInterval: 25, + subtitleNudgeAmount: 0.001 }; -var keyBindings = []; +var keyBindings = []; // This is populated during save/restore var keyCodeAliases = { - 0: "null", + /* ... same as your original ... */ 0: "null", null: "null", undefined: "null", 32: "Space", @@ -74,85 +78,55 @@ var keyCodeAliases = { 220: "\\", 221: "]", 222: "'", - 59: ";", - 61: "+", - 173: "-", + 59: ";", + 61: "+", + 173: "-" }; function recordKeyPress(e) { + /* ... same as your original ... */ if ( - (e.keyCode >= 48 && e.keyCode <= 57) || // Numbers 0-9 - (e.keyCode >= 65 && e.keyCode <= 90) || // Letters A-Z - keyCodeAliases[e.keyCode] // Other character keys + (e.keyCode >= 48 && e.keyCode <= 57) || + (e.keyCode >= 65 && e.keyCode <= 90) || + keyCodeAliases[e.keyCode] ) { e.target.value = keyCodeAliases[e.keyCode] || String.fromCharCode(e.keyCode); e.target.keyCode = e.keyCode; - e.preventDefault(); e.stopPropagation(); } else if (e.keyCode === 8) { - // Clear input when backspace pressed e.target.value = ""; } else if (e.keyCode === 27) { - // When esc clicked, clear input e.target.value = "null"; e.target.keyCode = null; } } - function inputFilterNumbersOnly(e) { + /* ... same as your original ... */ 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 = ""; + /* ... same as your original ... */ e.target.value = ""; } - function inputBlur(e) { - e.target.value = + /* ... same as your original ... */ e.target.value = keyCodeAliases[e.target.keyCode] || String.fromCharCode(e.target.keyCode); } - -function updateShortcutInputText(inputId, keyCode) { - document.getElementById(inputId).value = - keyCodeAliases[keyCode] || String.fromCharCode(keyCode); - document.getElementById(inputId).keyCode = keyCode; -} - +// function updateShortcutInputText(inputId, keyCode) { /* ... same as your original ... */ } // Not directly used in provided options.js logic flow function updateCustomShortcutInputText(inputItem, keyCode) { - inputItem.value = keyCodeAliases[keyCode] || String.fromCharCode(keyCode); + /* ... same as your original ... */ inputItem.value = + keyCodeAliases[keyCode] || String.fromCharCode(keyCode); inputItem.keyCode = keyCode; } - -// List of custom actions for which customValue should be disabled -var customActionsNoValues = ["pause", "muted", "mark", "jump", "display"]; - +var customActionsNoValues = ["pause", "muted", "mark", "jump", "display"]; // Original function add_shortcut() { - var html = ` - - - - `; + /* ... same as your original ... */ + var html = ``; var div = document.createElement("div"); div.setAttribute("class", "row customs"); div.innerHTML = html; @@ -162,14 +136,13 @@ function add_shortcut() { customs_element.children[customs_element.childElementCount - 1] ); } - function createKeyBindings(item) { + /* ... same as your original ... */ const action = item.querySelector(".customDo").value; const key = item.querySelector(".customKey").keyCode; const value = Number(item.querySelector(".customValue").value); const force = item.querySelector(".customForce").value; - const predefined = !!item.id; //item.id ? true : false; - + const predefined = !!item.id; keyBindings.push({ action: action, key: key, @@ -178,9 +151,8 @@ function createKeyBindings(item) { predefined: predefined }); } - -// Validates settings before saving function validate() { + /* ... same as your original ... */ var valid = true; var status = document.getElementById("status"); document @@ -190,7 +162,7 @@ function validate() { match = match.replace(regStrip, ""); if (match.startsWith("/")) { try { - var regexp = new RegExp(match); + new RegExp(match); } catch (err) { status.textContent = "Error: Invalid blacklist regex: " + match + ". Unable to save"; @@ -202,24 +174,45 @@ function validate() { return valid; } -// Saves options to chrome.storage +// MODIFIED: save_options to include nudge settings function save_options() { - if (validate() === false) { - return; - } - keyBindings = []; + if (validate() === false) return; + + keyBindings = []; // Reset global keyBindings before populating from DOM Array.from(document.querySelectorAll(".customs")).forEach((item) => createKeyBindings(item) - ); // Remove added shortcuts + ); - var rememberSpeed = document.getElementById("rememberSpeed").checked; - var forceLastSavedSpeed = document.getElementById("forceLastSavedSpeed").checked; - var audioBoolean = document.getElementById("audioBoolean").checked; - var enabled = document.getElementById("enabled").checked; - var startHidden = document.getElementById("startHidden").checked; - var controllerOpacity = document.getElementById("controllerOpacity").value; - var blacklist = document.getElementById("blacklist").value; + var s = {}; // Object to hold all settings to be saved + s.rememberSpeed = document.getElementById("rememberSpeed").checked; + s.forceLastSavedSpeed = document.getElementById( + "forceLastSavedSpeed" + ).checked; + s.audioBoolean = document.getElementById("audioBoolean").checked; + s.enabled = document.getElementById("enabled").checked; + s.startHidden = document.getElementById("startHidden").checked; + s.controllerOpacity = document.getElementById("controllerOpacity").value; + s.blacklist = document + .getElementById("blacklist") + .value.replace(regStrip, ""); + s.keyBindings = keyBindings; // Use the populated global keyBindings + // ADDED: Save nudge settings + s.enableSubtitleNudge = document.getElementById( + "enableSubtitleNudge" + ).checked; + s.subtitleNudgeInterval = + parseInt(document.getElementById("subtitleNudgeInterval").value, 10) || + tcDefaults.subtitleNudgeInterval; + s.subtitleNudgeAmount = + parseFloat(document.getElementById("subtitleNudgeAmount").value) || + tcDefaults.subtitleNudgeAmount; + // Basic validation for nudge interval and amount + if (s.subtitleNudgeInterval < 10) s.subtitleNudgeInterval = 10; // Min 10ms + if (s.subtitleNudgeAmount <= 0 || s.subtitleNudgeAmount > 0.1) + s.subtitleNudgeAmount = tcDefaults.subtitleNudgeAmount; + + // Remove old flat settings (original logic) chrome.storage.sync.remove([ "resetSpeed", "speedStep", @@ -233,33 +226,22 @@ function save_options() { "advanceKeyCode", "fastKeyCode" ]); - chrome.storage.sync.set( - { - rememberSpeed: rememberSpeed, - forceLastSavedSpeed: forceLastSavedSpeed, - audioBoolean: audioBoolean, - enabled: enabled, - startHidden: startHidden, - controllerOpacity: controllerOpacity, - keyBindings: keyBindings, - blacklist: blacklist.replace(regStrip, "") - }, - function () { - // Update status to let user know options were saved. - var status = document.getElementById("status"); - status.textContent = "Options saved"; - setTimeout(function () { - status.textContent = ""; - }, 1000); - } - ); + + chrome.storage.sync.set(s, function () { + var status = document.getElementById("status"); + status.textContent = "Options saved"; + setTimeout(function () { + status.textContent = ""; + }, 1000); + }); } -// Restores options from chrome.storage +// MODIFIED: restore_options to include nudge settings function restore_options() { chrome.storage.sync.get(tcDefaults, function (storage) { document.getElementById("rememberSpeed").checked = storage.rememberSpeed; - document.getElementById("forceLastSavedSpeed").checked = storage.forceLastSavedSpeed; + document.getElementById("forceLastSavedSpeed").checked = + storage.forceLastSavedSpeed; document.getElementById("audioBoolean").checked = storage.audioBoolean; document.getElementById("enabled").checked = storage.enabled; document.getElementById("startHidden").checked = storage.startHidden; @@ -267,65 +249,86 @@ function restore_options() { storage.controllerOpacity; document.getElementById("blacklist").value = storage.blacklist; - // ensure that there is a "display" binding for upgrades from versions that had it as a separate binding + // ADDED: Restore nudge settings + document.getElementById("enableSubtitleNudge").checked = + storage.enableSubtitleNudge; + document.getElementById("subtitleNudgeInterval").value = + storage.subtitleNudgeInterval; + document.getElementById("subtitleNudgeAmount").value = + storage.subtitleNudgeAmount; + + // Original key binding restoration logic + if ( + !Array.isArray(storage.keyBindings) || + storage.keyBindings.length === 0 + ) { + // If keyBindings missing or not an array, use defaults from tcDefaults + storage.keyBindings = tcDefaults.keyBindings; + } if (storage.keyBindings.filter((x) => x.action == "display").length == 0) { storage.keyBindings.push({ action: "display", value: 0, force: false, - predefined: true + predefined: true, + key: storage.displayKeyCode || tcDefaults.displayKeyCode }); } + // Clear existing dynamic shortcuts before restoring (if any were added by mistake) + const dynamicShortcuts = document.querySelectorAll(".customs:not([id])"); + dynamicShortcuts.forEach((sc) => sc.remove()); + for (let i in storage.keyBindings) { var item = storage.keyBindings[i]; if (item.predefined) { - //do predefined ones because their value needed for overlay - // document.querySelector("#" + item["action"] + " .customDo").value = item["action"]; if (item["action"] == "display" && typeof item["key"] === "undefined") { - item["key"] = storage.displayKeyCode || tcDefaults.displayKeyCode; // V + item["key"] = storage.displayKeyCode || tcDefaults.displayKeyCode; } - - if (customActionsNoValues.includes(item["action"])) - document.querySelector( + if (customActionsNoValues.includes(item["action"])) { + const el = document.querySelector( "#" + item["action"] + " .customValue" - ).disabled = true; - - updateCustomShortcutInputText( - document.querySelector("#" + item["action"] + " .customKey"), - item["key"] + ); + if (el) el.disabled = true; + } + const keyEl = document.querySelector( + "#" + item["action"] + " .customKey" ); - document.querySelector("#" + item["action"] + " .customValue").value = - item["value"]; - document.querySelector("#" + item["action"] + " .customForce").value = - item["force"]; + const valEl = document.querySelector( + "#" + item["action"] + " .customValue" + ); + const forceEl = document.querySelector( + "#" + item["action"] + " .customForce" + ); + if (keyEl) updateCustomShortcutInputText(keyEl, item["key"]); + if (valEl) valEl.value = item["value"]; + if (forceEl) forceEl.value = String(item["force"]); // Ensure string for select value } else { - // new ones + // Non-predefined, dynamically added shortcuts add_shortcut(); - const dom = document.querySelector(".customs:last-of-type"); + const dom = document.querySelector(".customs:last-of-type"); // Gets the newly added one dom.querySelector(".customDo").value = item["action"]; - - if (customActionsNoValues.includes(item["action"])) + if (customActionsNoValues.includes(item["action"])) { dom.querySelector(".customValue").disabled = true; - + } updateCustomShortcutInputText( dom.querySelector(".customKey"), item["key"] ); dom.querySelector(".customValue").value = item["value"]; - dom.querySelector(".customForce").value = item["force"]; + dom.querySelector(".customForce").value = String(item["force"]); } } }); } function restore_defaults() { + /* ... same as your original, tcDefaults now includes nudge defaults ... */ + // Remove all dynamically added shortcuts first + document.querySelectorAll(".customs:not([id])").forEach((el) => el.remove()); + // Then set defaults and restore options, which will re-add predefined ones correctly chrome.storage.sync.set(tcDefaults, function () { - restore_options(); - document - .querySelectorAll(".removeParent") - .forEach((button) => button.click()); // Remove added shortcuts - // Update status to let user know options were saved. + restore_options(); // This will populate based on tcDefaults var status = document.getElementById("status"); status.textContent = "Default options restored"; setTimeout(function () { @@ -335,14 +338,15 @@ function restore_defaults() { } function show_experimental() { + /* ... same as your original ... */ document .querySelectorAll(".customForce") .forEach((item) => (item.style.display = "inline-block")); } document.addEventListener("DOMContentLoaded", function () { + /* ... same as your original event listeners setup ... */ restore_options(); - document.getElementById("save").addEventListener("click", save_options); document.getElementById("add").addEventListener("click", add_shortcut); document @@ -353,34 +357,32 @@ document.addEventListener("DOMContentLoaded", function () { .addEventListener("click", show_experimental); function eventCaller(event, className, funcName) { - if (!event.target.classList || !event.target.classList.contains(className)) { + if (!event.target.classList || !event.target.classList.contains(className)) return; - } funcName(event); } - - document.addEventListener("keypress", (event) => { - eventCaller(event, "customValue", inputFilterNumbersOnly); - }); - document.addEventListener("focus", (event) => { - eventCaller(event, "customKey", inputFocus); - }); - document.addEventListener("blur", (event) => { - eventCaller(event, "customKey", inputBlur); - }); - document.addEventListener("keydown", (event) => { - eventCaller(event, "customKey", recordKeyPress); - }); - document.addEventListener("click", (event) => { + document.addEventListener("keypress", (event) => + eventCaller(event, "customValue", inputFilterNumbersOnly) + ); + document.addEventListener("focus", (event) => + eventCaller(event, "customKey", inputFocus) + ); + document.addEventListener("blur", (event) => + eventCaller(event, "customKey", inputBlur) + ); + document.addEventListener("keydown", (event) => + eventCaller(event, "customKey", recordKeyPress) + ); + document.addEventListener("click", (event) => eventCaller(event, "removeParent", function () { event.target.parentNode.remove(); - }); - }); + }) + ); document.addEventListener("change", (event) => { eventCaller(event, "customDo", function () { if (customActionsNoValues.includes(event.target.value)) { event.target.nextElementSibling.nextElementSibling.disabled = true; - event.target.nextElementSibling.nextElementSibling.value = 0; + event.target.nextElementSibling.nextElementSibling.value = 0; // Or "" if placeholder is preferred } else { event.target.nextElementSibling.nextElementSibling.disabled = false; } diff --git a/videospeed.xpi b/videospeed.xpi new file mode 100644 index 0000000000000000000000000000000000000000..3a81ecbcc0bef31dec0a14b5610f04aca36a009a GIT binary patch literal 57329 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ℜ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 literal 0 HcmV?d00001