mirror of
https://github.com/SoPat712/videospeed.git
synced 2025-08-21 18:08:46 -04:00
Compare commits
6 Commits
v1.0.0
...
c3166cf347
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c3166cf347 | ||
![]() |
77a25c4f1e | ||
![]() |
3fee61d2b6 | ||
![]() |
b7684aad09 | ||
![]() |
43dc8b773b | ||
![]() |
2d8a4fc25f |
@@ -1,3 +1,7 @@
|
|||||||
|
[](https://addons.mozilla.org/en-US/firefox/addon/video-speed-controller-v1/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The science of accelerated playback
|
# The science of accelerated playback
|
||||||
|
|
||||||
**TL;DR: faster playback translates to better engagement and retention.**
|
**TL;DR: faster playback translates to better engagement and retention.**
|
||||||
@@ -74,10 +78,10 @@ You can try manually disabling Flash from the browser.
|
|||||||
[`igrigorik/videospeed`](https://github.com/igrigorik/videospeed) repository
|
[`igrigorik/videospeed`](https://github.com/igrigorik/videospeed) repository
|
||||||
is a port of [`igrigorik`](https://github.com/igrigorik)'s videospeed Chrome
|
is a port of [`igrigorik`](https://github.com/igrigorik)'s videospeed Chrome
|
||||||
add-on for Firefox. This fork modifies the Chrome add-on code so that it works
|
add-on for Firefox. This fork modifies the Chrome add-on code so that it works
|
||||||
in Firefox. This repo is the code behind the [Firefox Extension](https://addons.mozilla.org/en-us/firefox/addon/videospeed/)
|
in Firefox. This repo is the code behind the [Firefox Extension](https://addons.mozilla.org/en-US/firefox/addon/video-speed-controller-v1/)
|
||||||
whereas the [`igrigorik/videospeed`](https://github.com/igrigorik/videospeed)
|
whereas the [`igrigorik/videospeed`](https://github.com/igrigorik/videospeed)
|
||||||
repository contains the code behind the [Chrome Extension](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk).
|
repository contains the code behind the [Chrome Extension](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk).
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
(MIT License) - Copyright (c) 2014 Ilya Grigorik
|
(MIT License) - Copyright (c) 2025 Josh Patra
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "Video Speed Controller",
|
"name": "Video Speed Controller",
|
||||||
"short_name": "videospeed",
|
"short_name": "videospeed",
|
||||||
"version": "0.6.3.3",
|
"version": "1.1.2",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts",
|
"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": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "{7be2ba16-0f1e-4d93-9ebc-5164397477a9}"
|
"id": "{ed860648-f54f-4dc9-9a0d-501aec4313f5}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
|
64
options.html
64
options.html
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Video Speed Controller: Options</title>
|
<title>Video Speed Controller: Options</title>
|
||||||
@@ -148,8 +148,13 @@
|
|||||||
<input id="rememberSpeed" type="checkbox" />
|
<input id="rememberSpeed" type="checkbox" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="forceLastSavedSpeed">Force last saved speed<br />
|
<label for="forceLastSavedSpeed"
|
||||||
<em>Useful for video players that override the speeds set by VideoSpeed</em></label>
|
>Force last saved speed<br />
|
||||||
|
<em
|
||||||
|
>Useful for video players that override the speeds set by
|
||||||
|
VideoSpeed</em
|
||||||
|
></label
|
||||||
|
>
|
||||||
<input id="forceLastSavedSpeed" type="checkbox" />
|
<input id="forceLastSavedSpeed" type="checkbox" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -175,6 +180,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="nudgeSettings">
|
||||||
|
<h3>Subtitle Nudge Settings (Experimental - YouTube Only)</h3>
|
||||||
|
<div class="row">
|
||||||
|
<label for="enableSubtitleNudge"
|
||||||
|
>Enable Subtitle Nudge <br /><em
|
||||||
|
>Periodically 'nudges' video speed by a tiny amount to help keep
|
||||||
|
subtitles in sync on some sites (e.g. YouTube).</em
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<input id="enableSubtitleNudge" type="checkbox" />
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label for="subtitleNudgeInterval"
|
||||||
|
>Nudge Interval (milliseconds) <br /><em
|
||||||
|
>How often to nudge (e.g., 25-1000). Smaller values are more
|
||||||
|
frequent. Default: 25.</em
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="subtitleNudgeInterval"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
placeholder="25"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label for="subtitleNudgeAmount"
|
||||||
|
>Nudge Amount (decimal) <br /><em
|
||||||
|
>How much to change speed by (e.g., 0.001). Very small values
|
||||||
|
recommended. Default: 0.001.</em
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="subtitleNudgeAmount"
|
||||||
|
type="text"
|
||||||
|
value=""
|
||||||
|
placeholder="0.001"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<button id="save">Save</button>
|
<button id="save">Save</button>
|
||||||
<button id="restore">Restore Defaults</button>
|
<button id="restore">Restore Defaults</button>
|
||||||
<button id="experimental">Show Experimental Features</button>
|
<button id="experimental">Show Experimental Features</button>
|
||||||
@@ -186,12 +232,12 @@
|
|||||||
|
|
||||||
<h4>Extension controls not appearing?</h4>
|
<h4>Extension controls not appearing?</h4>
|
||||||
<p>
|
<p>
|
||||||
This extension is only compatible with HTML5 audio and video. If you don't
|
This extension is only compatible with HTML5 audio and video. If you
|
||||||
see the controls showing up, chances are you are viewing a Flash content.
|
don't see the controls showing up, chances are you are viewing a Flash
|
||||||
If you want to confirm, try right-clicking on the content and inspect the
|
content. If you want to confirm, try right-clicking on the content and
|
||||||
menu: if it mentions flash, then that's the issue. That said, <b>most sites
|
inspect the menu: if it mentions flash, then that's the issue. That
|
||||||
will fallback to HTML5</b> if they detect that Flash is not available. You
|
said, <b>most sites will fallback to HTML5</b> if they detect that Flash
|
||||||
can try manually disabling Flash from the browser.
|
is not available. You can try manually disabling Flash from the browser.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
264
options.js
264
options.js
@@ -22,13 +22,17 @@ var tcDefaults = {
|
|||||||
twitter.com
|
twitter.com
|
||||||
imgur.com
|
imgur.com
|
||||||
teams.microsoft.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 = {
|
var keyCodeAliases = {
|
||||||
0: "null",
|
/* ... same as your original ... */ 0: "null",
|
||||||
null: "null",
|
null: "null",
|
||||||
undefined: "null",
|
undefined: "null",
|
||||||
32: "Space",
|
32: "Space",
|
||||||
@@ -76,83 +80,53 @@ var keyCodeAliases = {
|
|||||||
222: "'",
|
222: "'",
|
||||||
59: ";",
|
59: ";",
|
||||||
61: "+",
|
61: "+",
|
||||||
173: "-",
|
173: "-"
|
||||||
};
|
};
|
||||||
|
|
||||||
function recordKeyPress(e) {
|
function recordKeyPress(e) {
|
||||||
|
/* ... same as your original ... */
|
||||||
if (
|
if (
|
||||||
(e.keyCode >= 48 && e.keyCode <= 57) || // Numbers 0-9
|
(e.keyCode >= 48 && e.keyCode <= 57) ||
|
||||||
(e.keyCode >= 65 && e.keyCode <= 90) || // Letters A-Z
|
(e.keyCode >= 65 && e.keyCode <= 90) ||
|
||||||
keyCodeAliases[e.keyCode] // Other character keys
|
keyCodeAliases[e.keyCode]
|
||||||
) {
|
) {
|
||||||
e.target.value =
|
e.target.value =
|
||||||
keyCodeAliases[e.keyCode] || String.fromCharCode(e.keyCode);
|
keyCodeAliases[e.keyCode] || String.fromCharCode(e.keyCode);
|
||||||
e.target.keyCode = e.keyCode;
|
e.target.keyCode = e.keyCode;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
} else if (e.keyCode === 8) {
|
} else if (e.keyCode === 8) {
|
||||||
// Clear input when backspace pressed
|
|
||||||
e.target.value = "";
|
e.target.value = "";
|
||||||
} else if (e.keyCode === 27) {
|
} else if (e.keyCode === 27) {
|
||||||
// When esc clicked, clear input
|
|
||||||
e.target.value = "null";
|
e.target.value = "null";
|
||||||
e.target.keyCode = null;
|
e.target.keyCode = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputFilterNumbersOnly(e) {
|
function inputFilterNumbersOnly(e) {
|
||||||
|
/* ... same as your original ... */
|
||||||
var char = String.fromCharCode(e.keyCode);
|
var char = String.fromCharCode(e.keyCode);
|
||||||
if (!/[\d\.]$/.test(char) || !/^\d+(\.\d*)?$/.test(e.target.value + char)) {
|
if (!/[\d\.]$/.test(char) || !/^\d+(\.\d*)?$/.test(e.target.value + char)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputFocus(e) {
|
function inputFocus(e) {
|
||||||
e.target.value = "";
|
/* ... same as your original ... */ e.target.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputBlur(e) {
|
function inputBlur(e) {
|
||||||
e.target.value =
|
/* ... same as your original ... */ e.target.value =
|
||||||
keyCodeAliases[e.target.keyCode] || String.fromCharCode(e.target.keyCode);
|
keyCodeAliases[e.target.keyCode] || String.fromCharCode(e.target.keyCode);
|
||||||
}
|
}
|
||||||
|
// function updateShortcutInputText(inputId, keyCode) { /* ... same as your original ... */ } // Not directly used in provided options.js logic flow
|
||||||
function updateShortcutInputText(inputId, keyCode) {
|
|
||||||
document.getElementById(inputId).value =
|
|
||||||
keyCodeAliases[keyCode] || String.fromCharCode(keyCode);
|
|
||||||
document.getElementById(inputId).keyCode = keyCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCustomShortcutInputText(inputItem, keyCode) {
|
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;
|
inputItem.keyCode = keyCode;
|
||||||
}
|
}
|
||||||
|
var customActionsNoValues = ["pause", "muted", "mark", "jump", "display"]; // Original
|
||||||
// List of custom actions for which customValue should be disabled
|
|
||||||
var customActionsNoValues = ["pause", "muted", "mark", "jump", "display"];
|
|
||||||
|
|
||||||
function add_shortcut() {
|
function add_shortcut() {
|
||||||
var html = `<select class="customDo">
|
/* ... same as your original ... */
|
||||||
<option value="slower">Decrease speed</option>
|
var html = `<select class="customDo"><option value="slower">Decrease speed</option><option value="faster">Increase speed</option><option value="rewind">Rewind</option><option value="advance">Advance</option><option value="reset">Reset speed</option><option value="fast">Preferred speed</option><option value="muted">Mute</option><option value="pause">Pause</option><option value="mark">Set marker</option><option value="jump">Jump to marker</option><option value="display">Show/hide controller</option></select><input class="customKey" type="text" placeholder="press a key"/><input class="customValue" type="text" placeholder="value (0.10)"/><select class="customForce"><option value="false">Do not disable website key bindings</option><option value="true">Disable website key bindings</option></select><button class="removeParent">X</button>`;
|
||||||
<option value="faster">Increase speed</option>
|
|
||||||
<option value="rewind">Rewind</option>
|
|
||||||
<option value="advance">Advance</option>
|
|
||||||
<option value="reset">Reset speed</option>
|
|
||||||
<option value="fast">Preferred speed</option>
|
|
||||||
<option value="muted">Mute</option>
|
|
||||||
<option value="pause">Pause</option>
|
|
||||||
<option value="mark">Set marker</option>
|
|
||||||
<option value="jump">Jump to marker</option>
|
|
||||||
<option value="display">Show/hide controller</option>
|
|
||||||
</select>
|
|
||||||
<input class="customKey" type="text" placeholder="press a key"/>
|
|
||||||
<input class="customValue" type="text" placeholder="value (0.10)"/>
|
|
||||||
<select class="customForce">
|
|
||||||
<option value="false">Do not disable website key bindings</option>
|
|
||||||
<option value="true">Disable website key bindings</option>
|
|
||||||
</select>
|
|
||||||
<button class="removeParent">X</button>`;
|
|
||||||
var div = document.createElement("div");
|
var div = document.createElement("div");
|
||||||
div.setAttribute("class", "row customs");
|
div.setAttribute("class", "row customs");
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
@@ -162,14 +136,13 @@ function add_shortcut() {
|
|||||||
customs_element.children[customs_element.childElementCount - 1]
|
customs_element.children[customs_element.childElementCount - 1]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createKeyBindings(item) {
|
function createKeyBindings(item) {
|
||||||
|
/* ... same as your original ... */
|
||||||
const action = item.querySelector(".customDo").value;
|
const action = item.querySelector(".customDo").value;
|
||||||
const key = item.querySelector(".customKey").keyCode;
|
const key = item.querySelector(".customKey").keyCode;
|
||||||
const value = Number(item.querySelector(".customValue").value);
|
const value = Number(item.querySelector(".customValue").value);
|
||||||
const force = item.querySelector(".customForce").value;
|
const force = item.querySelector(".customForce").value;
|
||||||
const predefined = !!item.id; //item.id ? true : false;
|
const predefined = !!item.id;
|
||||||
|
|
||||||
keyBindings.push({
|
keyBindings.push({
|
||||||
action: action,
|
action: action,
|
||||||
key: key,
|
key: key,
|
||||||
@@ -178,9 +151,8 @@ function createKeyBindings(item) {
|
|||||||
predefined: predefined
|
predefined: predefined
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates settings before saving
|
|
||||||
function validate() {
|
function validate() {
|
||||||
|
/* ... same as your original ... */
|
||||||
var valid = true;
|
var valid = true;
|
||||||
var status = document.getElementById("status");
|
var status = document.getElementById("status");
|
||||||
document
|
document
|
||||||
@@ -190,7 +162,7 @@ function validate() {
|
|||||||
match = match.replace(regStrip, "");
|
match = match.replace(regStrip, "");
|
||||||
if (match.startsWith("/")) {
|
if (match.startsWith("/")) {
|
||||||
try {
|
try {
|
||||||
var regexp = new RegExp(match);
|
new RegExp(match);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
status.textContent =
|
status.textContent =
|
||||||
"Error: Invalid blacklist regex: " + match + ". Unable to save";
|
"Error: Invalid blacklist regex: " + match + ". Unable to save";
|
||||||
@@ -202,24 +174,45 @@ function validate() {
|
|||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves options to chrome.storage
|
// MODIFIED: save_options to include nudge settings
|
||||||
function save_options() {
|
function save_options() {
|
||||||
if (validate() === false) {
|
if (validate() === false) return;
|
||||||
return;
|
|
||||||
}
|
keyBindings = []; // Reset global keyBindings before populating from DOM
|
||||||
keyBindings = [];
|
|
||||||
Array.from(document.querySelectorAll(".customs")).forEach((item) =>
|
Array.from(document.querySelectorAll(".customs")).forEach((item) =>
|
||||||
createKeyBindings(item)
|
createKeyBindings(item)
|
||||||
); // Remove added shortcuts
|
);
|
||||||
|
|
||||||
var rememberSpeed = document.getElementById("rememberSpeed").checked;
|
var s = {}; // Object to hold all settings to be saved
|
||||||
var forceLastSavedSpeed = document.getElementById("forceLastSavedSpeed").checked;
|
s.rememberSpeed = document.getElementById("rememberSpeed").checked;
|
||||||
var audioBoolean = document.getElementById("audioBoolean").checked;
|
s.forceLastSavedSpeed = document.getElementById(
|
||||||
var enabled = document.getElementById("enabled").checked;
|
"forceLastSavedSpeed"
|
||||||
var startHidden = document.getElementById("startHidden").checked;
|
).checked;
|
||||||
var controllerOpacity = document.getElementById("controllerOpacity").value;
|
s.audioBoolean = document.getElementById("audioBoolean").checked;
|
||||||
var blacklist = document.getElementById("blacklist").value;
|
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([
|
chrome.storage.sync.remove([
|
||||||
"resetSpeed",
|
"resetSpeed",
|
||||||
"speedStep",
|
"speedStep",
|
||||||
@@ -233,33 +226,22 @@ function save_options() {
|
|||||||
"advanceKeyCode",
|
"advanceKeyCode",
|
||||||
"fastKeyCode"
|
"fastKeyCode"
|
||||||
]);
|
]);
|
||||||
chrome.storage.sync.set(
|
|
||||||
{
|
chrome.storage.sync.set(s, function () {
|
||||||
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");
|
var status = document.getElementById("status");
|
||||||
status.textContent = "Options saved";
|
status.textContent = "Options saved";
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
status.textContent = "";
|
status.textContent = "";
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restores options from chrome.storage
|
// MODIFIED: restore_options to include nudge settings
|
||||||
function restore_options() {
|
function restore_options() {
|
||||||
chrome.storage.sync.get(tcDefaults, function (storage) {
|
chrome.storage.sync.get(tcDefaults, function (storage) {
|
||||||
document.getElementById("rememberSpeed").checked = storage.rememberSpeed;
|
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("audioBoolean").checked = storage.audioBoolean;
|
||||||
document.getElementById("enabled").checked = storage.enabled;
|
document.getElementById("enabled").checked = storage.enabled;
|
||||||
document.getElementById("startHidden").checked = storage.startHidden;
|
document.getElementById("startHidden").checked = storage.startHidden;
|
||||||
@@ -267,65 +249,86 @@ function restore_options() {
|
|||||||
storage.controllerOpacity;
|
storage.controllerOpacity;
|
||||||
document.getElementById("blacklist").value = storage.blacklist;
|
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) {
|
if (storage.keyBindings.filter((x) => x.action == "display").length == 0) {
|
||||||
storage.keyBindings.push({
|
storage.keyBindings.push({
|
||||||
action: "display",
|
action: "display",
|
||||||
value: 0,
|
value: 0,
|
||||||
force: false,
|
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) {
|
for (let i in storage.keyBindings) {
|
||||||
var item = storage.keyBindings[i];
|
var item = storage.keyBindings[i];
|
||||||
if (item.predefined) {
|
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") {
|
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"])) {
|
||||||
if (customActionsNoValues.includes(item["action"]))
|
const el = document.querySelector(
|
||||||
document.querySelector(
|
|
||||||
"#" + item["action"] + " .customValue"
|
"#" + item["action"] + " .customValue"
|
||||||
).disabled = true;
|
|
||||||
|
|
||||||
updateCustomShortcutInputText(
|
|
||||||
document.querySelector("#" + item["action"] + " .customKey"),
|
|
||||||
item["key"]
|
|
||||||
);
|
);
|
||||||
document.querySelector("#" + item["action"] + " .customValue").value =
|
if (el) el.disabled = true;
|
||||||
item["value"];
|
}
|
||||||
document.querySelector("#" + item["action"] + " .customForce").value =
|
const keyEl = document.querySelector(
|
||||||
item["force"];
|
"#" + item["action"] + " .customKey"
|
||||||
|
);
|
||||||
|
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 {
|
} else {
|
||||||
// new ones
|
// Non-predefined, dynamically added shortcuts
|
||||||
add_shortcut();
|
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"];
|
dom.querySelector(".customDo").value = item["action"];
|
||||||
|
if (customActionsNoValues.includes(item["action"])) {
|
||||||
if (customActionsNoValues.includes(item["action"]))
|
|
||||||
dom.querySelector(".customValue").disabled = true;
|
dom.querySelector(".customValue").disabled = true;
|
||||||
|
}
|
||||||
updateCustomShortcutInputText(
|
updateCustomShortcutInputText(
|
||||||
dom.querySelector(".customKey"),
|
dom.querySelector(".customKey"),
|
||||||
item["key"]
|
item["key"]
|
||||||
);
|
);
|
||||||
dom.querySelector(".customValue").value = item["value"];
|
dom.querySelector(".customValue").value = item["value"];
|
||||||
dom.querySelector(".customForce").value = item["force"];
|
dom.querySelector(".customForce").value = String(item["force"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function restore_defaults() {
|
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 () {
|
chrome.storage.sync.set(tcDefaults, function () {
|
||||||
restore_options();
|
restore_options(); // This will populate based on tcDefaults
|
||||||
document
|
|
||||||
.querySelectorAll(".removeParent")
|
|
||||||
.forEach((button) => button.click()); // Remove added shortcuts
|
|
||||||
// Update status to let user know options were saved.
|
|
||||||
var status = document.getElementById("status");
|
var status = document.getElementById("status");
|
||||||
status.textContent = "Default options restored";
|
status.textContent = "Default options restored";
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@@ -335,14 +338,15 @@ function restore_defaults() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show_experimental() {
|
function show_experimental() {
|
||||||
|
/* ... same as your original ... */
|
||||||
document
|
document
|
||||||
.querySelectorAll(".customForce")
|
.querySelectorAll(".customForce")
|
||||||
.forEach((item) => (item.style.display = "inline-block"));
|
.forEach((item) => (item.style.display = "inline-block"));
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
/* ... same as your original event listeners setup ... */
|
||||||
restore_options();
|
restore_options();
|
||||||
|
|
||||||
document.getElementById("save").addEventListener("click", save_options);
|
document.getElementById("save").addEventListener("click", save_options);
|
||||||
document.getElementById("add").addEventListener("click", add_shortcut);
|
document.getElementById("add").addEventListener("click", add_shortcut);
|
||||||
document
|
document
|
||||||
@@ -353,34 +357,32 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
.addEventListener("click", show_experimental);
|
.addEventListener("click", show_experimental);
|
||||||
|
|
||||||
function eventCaller(event, className, funcName) {
|
function eventCaller(event, className, funcName) {
|
||||||
if (!event.target.classList || !event.target.classList.contains(className)) {
|
if (!event.target.classList || !event.target.classList.contains(className))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
funcName(event);
|
funcName(event);
|
||||||
}
|
}
|
||||||
|
document.addEventListener("keypress", (event) =>
|
||||||
document.addEventListener("keypress", (event) => {
|
eventCaller(event, "customValue", inputFilterNumbersOnly)
|
||||||
eventCaller(event, "customValue", inputFilterNumbersOnly);
|
);
|
||||||
});
|
document.addEventListener("focus", (event) =>
|
||||||
document.addEventListener("focus", (event) => {
|
eventCaller(event, "customKey", inputFocus)
|
||||||
eventCaller(event, "customKey", inputFocus);
|
);
|
||||||
});
|
document.addEventListener("blur", (event) =>
|
||||||
document.addEventListener("blur", (event) => {
|
eventCaller(event, "customKey", inputBlur)
|
||||||
eventCaller(event, "customKey", inputBlur);
|
);
|
||||||
});
|
document.addEventListener("keydown", (event) =>
|
||||||
document.addEventListener("keydown", (event) => {
|
eventCaller(event, "customKey", recordKeyPress)
|
||||||
eventCaller(event, "customKey", recordKeyPress);
|
);
|
||||||
});
|
document.addEventListener("click", (event) =>
|
||||||
document.addEventListener("click", (event) => {
|
|
||||||
eventCaller(event, "removeParent", function () {
|
eventCaller(event, "removeParent", function () {
|
||||||
event.target.parentNode.remove();
|
event.target.parentNode.remove();
|
||||||
});
|
})
|
||||||
});
|
);
|
||||||
document.addEventListener("change", (event) => {
|
document.addEventListener("change", (event) => {
|
||||||
eventCaller(event, "customDo", function () {
|
eventCaller(event, "customDo", function () {
|
||||||
if (customActionsNoValues.includes(event.target.value)) {
|
if (customActionsNoValues.includes(event.target.value)) {
|
||||||
event.target.nextElementSibling.nextElementSibling.disabled = true;
|
event.target.nextElementSibling.nextElementSibling.disabled = true;
|
||||||
event.target.nextElementSibling.nextElementSibling.value = 0;
|
event.target.nextElementSibling.nextElementSibling.value = 0; // Or "" if placeholder is preferred
|
||||||
} else {
|
} else {
|
||||||
event.target.nextElementSibling.nextElementSibling.disabled = false;
|
event.target.nextElementSibling.nextElementSibling.disabled = false;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user