Compare commits

..

49 Commits

Author SHA1 Message Date
joshpatra a2b041e225 v5.1.8.0-beta.1 2026-04-07 14:33:07 -04:00
joshpatra 4f87aadfd7 Bump version to 5.1.8.0 2026-04-07 14:32:21 -04:00
joshpatra 8456111bf0 fix: correct AMO URL and lucide spec object key 2026-04-07 14:31:45 -04:00
joshpatra 6efe92a036 Refine site rule toggle and override UI 2026-04-07 14:31:41 -04:00
joshpatra 0cb13905ff Fix subtitle nudge site gating 2026-04-07 14:31:39 -04:00
joshpatra f32d1b3f71 Accept raw settings backups during import 2026-04-07 14:31:36 -04:00
joshpatra e6c56bcecb Allow zero controller opacity in settings 2026-04-07 14:31:34 -04:00
joshpatra a7a0aafd68 Add Vitest suite and fix wrapped local import restore 2026-04-07 14:31:27 -04:00
joshpatra 3cf1a4acd1 style(inject): normalize formatting 2026-04-04 16:14:56 -04:00
joshpatra a9956831c4 refactor(shortcuts): switch shortcut bindings to event.code 2026-04-04 13:33:11 -04:00
joshpatra 25d3acf576 v5.1.7.0-beta.1 2026-04-02 22:34:00 -04:00
joshpatra 7b8b4324af Bump version to 5.1.7.0 2026-04-02 22:33:59 -04:00
joshpatra 8b9e4bea1d fix: refresh site rules on DOM video changes 2026-04-02 21:16:37 -04:00
joshpatra 8c94cc2088 fix: clarify site rule auto-hide copy 2026-04-02 21:08:15 -04:00
joshpatra 19d3af02a2 refactor: store settings as sparse diffs 2026-04-02 21:07:31 -04:00
joshpatra 306e0e3ea0 Exclude Lucide cache from backups 2026-04-02 20:47:32 -04:00
joshpatra 1536c13c3e v5.1.6-beta.1 2026-04-02 18:20:49 -04:00
joshpatra 6bd319c8cc Bump version to 5.1.6 2026-04-02 18:20:48 -04:00
joshpatra 3aee8c8f9a fix: errors from web-ext 2026-04-02 18:20:33 -04:00
joshpatra 939ee08466 v5.1.4-beta.1 2026-04-02 14:17:18 -04:00
joshpatra 5a175c3cf8 Bump version to 5.1.4 2026-04-02 14:17:17 -04:00
joshpatra 805e5a82e5 fix: unicode reset glyph fallback in extension popup 2026-04-02 14:16:53 -04:00
joshpatra df34b1fee9 feat: Lucide subtitle nudge on/off targets and dual preview in options 2026-04-02 14:16:46 -04:00
joshpatra 0741c6e535 feat: custom Lucide icons for subtitle nudge on/off in inject 2026-04-02 14:16:40 -04:00
joshpatra fad0c49e65 v5.1.3-beta.1 2026-04-02 13:56:22 -04:00
joshpatra 66075fb6f3 Bump version to 5.1.3 2026-04-02 13:56:21 -04:00
joshpatra bf4025dcb4 fix: settings update 2026-04-02 13:54:01 -04:00
joshpatra 76a7b933bb v5.1.2-beta.1 2026-04-02 13:52:04 -04:00
joshpatra 1cd533fc5c Bump version to 5.1.2 2026-04-02 13:52:02 -04:00
joshpatra 8c5bd68d39 fix: popup control bar section layout in options 2026-04-02 13:44:03 -04:00
joshpatra 9c257af446 feat: omit settings from popup control bar 2026-04-02 13:43:56 -04:00
joshpatra 64a9b85587 fix: control bar icon clicks, hover/focus-within, nudge action 2026-04-02 13:43:43 -04:00
joshpatra edd997037a v5.1.1-beta.1 2026-04-02 13:11:47 -04:00
joshpatra f85a1f9f29 Bump version to 5.1.1 2026-04-02 13:11:46 -04:00
joshpatra 97366b76b6 chore: open options in tab 2026-04-02 13:09:09 -04:00
joshpatra 8269875bb1 fix: removed divider 2026-04-02 13:01:14 -04:00
joshpatra e34ec17f33 v5.1.0-beta.1 2026-04-02 12:53:10 -04:00
joshpatra 8d3905b654 Bump version to 5.1.0 2026-04-02 12:53:09 -04:00
joshpatra 7fd8a931d8 deploy: squash beta→main for stable; beta script pushes dev then pulls 2026-04-02 12:52:27 -04:00
joshpatra 17319c1e25 Re-run site rules on DOM media attach; extract refreshAllControllerGeometry 2026-04-02 12:52:27 -04:00
joshpatra 841c1a246e fix: nudge flash layout, Lucide icons, hover bar spacing 2026-04-02 12:52:27 -04:00
joshpatra ed0f63e8bc feat: user-customizable Lucide controller button icons 2026-04-02 12:52:27 -04:00
joshpatra 53f66f1eeb v5.0.4-beta.1 2026-04-01 16:31:49 -04:00
joshpatra f106ab490a Bump version to 5.0.4 2026-04-01 16:31:48 -04:00
joshpatra 5a38121e09 refactor: scripts update 2026-04-01 16:31:29 -04:00
joshpatra 36ed922b5c Add interactive deploy scripts for beta and AMO stable releases 2026-04-01 16:29:19 -04:00
joshpatra 3275d1f322 v5.0.2-beta.1 2026-04-01 16:24:24 -04:00
joshpatra f6d706f096 chore: version bump, deployment update 2026-04-01 16:21:44 -04:00
joshpatra 04292a8018 refactor: update settings, feat: change reset speed indicator to show speed it changes to/from 2026-04-01 16:18:36 -04:00
7 changed files with 37 additions and 165 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"kiroAgent.configureMCP": "Disabled"
}
+2 -2
View File
@@ -33,7 +33,7 @@ last point to listen to it a few more times.
![Player](https://cloud.githubusercontent.com/assets/2400185/24076745/5723e6ae-0c41-11e7-820c-1d8e814a2888.png)
#### *Install [Chrome](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk) or [Firefox](https://addons.mozilla.org/en-us/firefox/addon/speeder/) Extension*
#### *Install [Chrome](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk) or [Firefox](https://addons.mozilla.org/en-us/firefox/addon/videospeed/) Extension*
\*\* Once the extension is installed simply navigate to any page that offers
HTML5 video ([example](https://www.youtube.com/watch?v=E9FxNzv1Tr8)), and you'll
@@ -56,7 +56,7 @@ shortcuts with different values, which will allow you to quickly toggle between
your most commonly used speeds. To add a new shortcut, open extension settings
and click "Add New".
<img width="1760" height="1330" alt="image" src="https://github.com/user-attachments/assets/32e814dd-93ea-4943-8ec9-3eca735447ac" />
![settings Add New shortcut](https://user-images.githubusercontent.com/121805/50726471-50242200-1172-11e9-902f-0e5958387617.jpg)
Some sites may assign other functionality to one of the assigned shortcut keys —
these collisions are inevitable, unfortunately. As a workaround, the extension
+3 -56
View File
@@ -130,14 +130,11 @@ var controllerButtonDefs = {
display: { label: "", className: "hideButton" },
reset: { label: "\u21BB", className: "" },
fast: { label: "", className: "" },
nudge: { label: "", className: "" },
settings: { label: "", className: "" },
pause: { label: "", className: "" },
muted: { label: "", className: "" },
louder: { label: "", className: "" },
softer: { label: "", className: "" },
mark: { label: "", className: "" },
jump: { label: "", className: "" },
settings: { label: "", className: "" }
jump: { label: "", className: "" }
};
function createDefaultBinding(action, code, value) {
@@ -2589,8 +2586,6 @@ function runAction(action, value, e) {
"advance",
"faster",
"slower",
"louder",
"softer",
"reset",
"fast",
"move",
@@ -2713,12 +2708,6 @@ function runAction(action, value, e) {
case "muted":
muted(v);
break;
case "louder":
volumeUp(v, Number.isFinite(numValue) ? numValue : 0.1);
break;
case "softer":
volumeDown(v, Number.isFinite(numValue) ? numValue : 0.1);
break;
case "mark":
setMark(v);
break;
@@ -2783,49 +2772,7 @@ function resetSpeed(v, target, isFastKey = false) {
}
function muted(v) {
var nextMuted = !v.muted;
v.muted = nextMuted;
if (!isOnYouTube()) return;
var ytApi = getYouTubePlayerApi(v);
if (!ytApi) return;
if (nextMuted && typeof ytApi.mute === "function") ytApi.mute();
if (!nextMuted && typeof ytApi.unMute === "function") ytApi.unMute();
}
function getYouTubePlayerApi(video) {
if (!isOnYouTube()) return null;
var playerEl =
(video && video.closest ? video.closest(".html5-video-player") : null) ||
document.getElementById("movie_player") ||
document.querySelector(".html5-video-player");
if (!playerEl) return null;
return playerEl.wrappedJSObject || playerEl;
}
function syncYouTubePlayerVolume(video, volume) {
var ytApi = getYouTubePlayerApi(video);
if (!ytApi || typeof ytApi.setVolume !== "function") return;
ytApi.setVolume(Math.round(volume * 100));
if (volume > 0 && typeof ytApi.unMute === "function") {
ytApi.unMute();
}
}
function setVideoVolume(video, targetVolume) {
var nextVolume = Math.max(0, Math.min(1, Number(targetVolume.toFixed(2))));
video.volume = nextVolume;
if (nextVolume > 0 && video.muted) {
video.muted = false;
}
syncYouTubePlayerVolume(video, nextVolume);
}
function volumeUp(v, value) {
setVideoVolume(v, v.volume + value);
}
function volumeDown(v, value) {
setVideoVolume(v, v.volume - value);
v.muted = !v.muted;
}
function setMark(v) {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "Speeder",
"short_name": "Speeder",
"version": "5.2.1",
"version": "5.1.8.0",
"manifest_version": 2,
"description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts (New and improved version of \"Video Speed Controller\")",
"homepage_url": "https://github.com/SoPat712/speeder",
+26 -98
View File
@@ -74,13 +74,11 @@ var controllerButtonDefs = {
reset: { icon: "\u21BB", name: "Reset speed" },
fast: { icon: "\u2605", name: "Preferred speed" },
nudge: { icon: "\u2713", name: "Subtitle nudge" },
pause: { icon: "\u23EF", name: "Play / Pause" },
muted: { icon: "M", name: "Mute / Unmute" },
louder: { icon: "+", name: "Increase volume" },
softer: { icon: "\u2212", name: "Decrease volume" },
mark: { icon: "\u2691", name: "Set marker" },
jump: { icon: "\u21E5", name: "Jump to marker" },
settings: { icon: "\u2699", name: "Settings" },
pause: { icon: "\u23EF", name: "Pause / Play" },
muted: { icon: "M", name: "Mute / Unmute" },
mark: { icon: "\u2691", name: "Set marker" },
jump: { icon: "\u21E5", name: "Jump to marker" }
};
var popupExcludedButtonIds = new Set(["settings"]);
@@ -223,17 +221,14 @@ const actionLabels = {
advance: "Advance",
reset: "Reset speed",
fast: "Preferred speed",
toggleSubtitleNudge: "Toggle subtitle nudge",
pause: "Play / Pause",
muted: "Mute / Unmute",
louder: "Increase volume",
softer: "Decrease volume",
muted: "Mute",
pause: "Pause",
mark: "Set marker",
jump: "Jump to marker"
jump: "Jump to marker",
toggleSubtitleNudge: "Toggle subtitle nudge"
};
const speedBindingActions = ["slower", "faster", "fast", "softer", "louder"];
const requiredShortcutActions = new Set(["display", "slower", "faster"]);
const speedBindingActions = ["slower", "faster", "fast"];
function formatSpeedBindingDisplay(action, value) {
if (!speedBindingActions.includes(action)) {
@@ -246,30 +241,6 @@ function formatSpeedBindingDisplay(action, value) {
return n.toFixed(2);
}
function getDefaultShortcutValue(action) {
if (action === "louder" || action === "softer") {
return 0.1;
}
var defaultBinding = tcDefaults.keyBindings.find(function (binding) {
return binding.action === action;
});
if (defaultBinding && Number.isFinite(Number(defaultBinding.value))) {
return Number(defaultBinding.value);
}
return 0;
}
function resolveShortcutValue(action, value) {
if (value === undefined || value === null) {
return getDefaultShortcutValue(action);
}
var numericValue = Number(value);
if (Number.isFinite(numericValue)) {
return numericValue;
}
return 0;
}
const customActionsNoValues = [
"reset",
"display",
@@ -609,10 +580,7 @@ function add_shortcut(action, value) {
valueInput.value = "N/A";
valueInput.disabled = true;
} else {
valueInput.value = formatSpeedBindingDisplay(
action,
resolveShortcutValue(action, value)
);
valueInput.value = formatSpeedBindingDisplay(action, value || 0);
}
var removeButton = document.createElement("button");
@@ -639,25 +607,9 @@ function createKeyBindings(item) {
var binding = normalizeStoredBinding(input.vscBinding);
if (!binding) {
if (requiredShortcutActions.has(action)) {
return {
valid: false,
message:
"Error: Shortcut for " +
(actionLabels[action] || action) +
" cannot be empty. Unable to save"
};
}
binding = createDisabledBinding();
}
if (binding.disabled === true && requiredShortcutActions.has(action)) {
return {
valid: false,
message:
"Error: Shortcut for " +
(actionLabels[action] || action) +
" cannot be empty. Unable to save"
message: "Error: Shortcut for " + action + " is invalid. Unable to save"
};
}
@@ -876,43 +828,24 @@ function save_options() {
if (ruleEl.querySelector(".override-shortcuts").checked) {
var shortcuts = [];
ruleEl.querySelectorAll(".site-shortcuts-container .customs").forEach((shortcutRow) => {
if (saveError) return;
var action = shortcutRow.dataset.action;
var keyInput = shortcutRow.querySelector(".customKey");
var valueInput = shortcutRow.querySelector(".customValue");
var forceCheckbox = shortcutRow.querySelector(".customForce");
var binding = normalizeStoredBinding(keyInput.vscBinding);
if (!binding) {
if (requiredShortcutActions.has(action)) {
saveError =
"Error: Site rule shortcut for " +
(actionLabels[action] || action) +
" cannot be empty. Unable to save";
return;
}
binding = createDisabledBinding();
if (binding) {
shortcuts.push({
action: action,
code: binding.code,
disabled: binding.disabled === true,
value: customActionsNoValues.includes(action)
? 0
: Number(valueInput.value),
force: forceCheckbox ? forceCheckbox.checked : false
});
}
if (binding.disabled === true && requiredShortcutActions.has(action)) {
saveError =
"Error: Site rule shortcut for " +
(actionLabels[action] || action) +
" cannot be empty. Unable to save";
return;
}
shortcuts.push({
action: action,
code: binding.code,
disabled: binding.disabled === true,
value: customActionsNoValues.includes(action)
? 0
: Number(valueInput.value),
force: forceCheckbox ? forceCheckbox.checked : false
});
});
if (saveError) return;
if (shortcuts.length > 0) rule.shortcuts = shortcuts;
}
@@ -958,13 +891,11 @@ function addSiteRuleShortcut(container, action, binding, value, force) {
advance: "Advance",
reset: "Reset speed",
fast: "Preferred speed",
toggleSubtitleNudge: "Toggle subtitle nudge",
pause: "Play / Pause",
muted: "Mute / Unmute",
louder: "Increase volume",
softer: "Decrease volume",
muted: "Mute",
pause: "Pause",
mark: "Set marker",
jump: "Jump to marker"
jump: "Jump to marker",
toggleSubtitleNudge: "Toggle subtitle nudge"
};
var actionLabelText = actionLabels[action] || action;
if (action === "toggleSubtitleNudge") {
@@ -992,10 +923,7 @@ function addSiteRuleShortcut(container, action, binding, value, force) {
valueInput.value = "N/A";
valueInput.disabled = true;
} else {
valueInput.value = formatSpeedBindingDisplay(
action,
resolveShortcutValue(action, value)
);
valueInput.value = formatSpeedBindingDisplay(action, value || 0);
}
var forceLabel = document.createElement("label");
+2 -4
View File
@@ -14,13 +14,11 @@ document.addEventListener("DOMContentLoaded", function () {
reset: { label: "\u21BB", className: "" },
fast: { label: "", className: "" },
nudge: { label: "", className: "" },
settings: { label: "", className: "" },
pause: { label: "", className: "" },
muted: { label: "", className: "" },
louder: { label: "", className: "" },
softer: { label: "", className: "" },
mark: { label: "", className: "" },
jump: { label: "", className: "" },
settings: { label: "", className: "" }
jump: { label: "", className: "" }
};
var defaultButtons = ["rewind", "slower", "faster", "advance", "display"];
-4
View File
@@ -16,10 +16,6 @@ var vscUiIconPaths = {
slower: '<line x1="5" y1="12" x2="19" y2="12"/>',
faster:
'<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>',
softer:
'<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><line x1="16" y1="12" x2="22" y2="12"/>',
louder:
'<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><line x1="17" y1="9" x2="17" y2="15"/><line x1="14" y1="12" x2="20" y2="12"/>',
moreHorizontal:
'<circle cx="6" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="18" cy="12" r="1.5"/>',
chevronUp: '<path d="m18 15-6-6-6 6"/>',