mirror of
https://github.com/SoPat712/videospeed.git
synced 2026-04-26 22:23:09 -04:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
fad0c49e65
|
|||
|
66075fb6f3
|
|||
|
bf4025dcb4
|
|||
|
76a7b933bb
|
|||
|
1cd533fc5c
|
|||
|
8c5bd68d39
|
|||
|
9c257af446
|
|||
|
64a9b85587
|
|||
|
edd997037a
|
|||
|
f85a1f9f29
|
|||
|
97366b76b6
|
|||
|
8269875bb1
|
@@ -1939,14 +1939,20 @@ function defineVideoController() {
|
|||||||
if (subtitleNudgeIndicator) {
|
if (subtitleNudgeIndicator) {
|
||||||
updateSubtitleNudgeIndicator(this.video);
|
updateSubtitleNudgeIndicator(this.video);
|
||||||
}
|
}
|
||||||
|
function blurAfterPointerTap(target, e) {
|
||||||
|
if (!target || typeof target.blur !== "function") return;
|
||||||
|
var pt = e.pointerType;
|
||||||
|
if (pt === "mouse" || pt === "touch" || (!pt && e.detail > 0)) {
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
target.blur();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
dragHandle.addEventListener(
|
dragHandle.addEventListener(
|
||||||
"mousedown",
|
"mousedown",
|
||||||
(e) => {
|
(e) => {
|
||||||
runAction(
|
var dragAction = dragHandle.dataset.action;
|
||||||
e.target.dataset["action"],
|
runAction(dragAction, getKeyBindings(dragAction, "value"), e);
|
||||||
getKeyBindings(e.target.dataset["action"], "value"),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
@@ -1955,11 +1961,9 @@ function defineVideoController() {
|
|||||||
button.addEventListener(
|
button.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
(e) => {
|
(e) => {
|
||||||
runAction(
|
var action = button.dataset.action;
|
||||||
e.target.dataset["action"],
|
runAction(action, getKeyBindings(action), e);
|
||||||
getKeyBindings(e.target.dataset["action"]),
|
blurAfterPointerTap(button, e);
|
||||||
e
|
|
||||||
);
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
@@ -1974,6 +1978,7 @@ function defineVideoController() {
|
|||||||
var newState = !isSubtitleNudgeEnabledForVideo(video);
|
var newState = !isSubtitleNudgeEnabledForVideo(video);
|
||||||
setSubtitleNudgeEnabledForVideo(video, newState);
|
setSubtitleNudgeEnabledForVideo(video, newState);
|
||||||
}
|
}
|
||||||
|
blurAfterPointerTap(subtitleNudgeIndicator, e);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
@@ -2667,6 +2672,7 @@ function runAction(action, value, e) {
|
|||||||
"mark",
|
"mark",
|
||||||
"jump",
|
"jump",
|
||||||
"drag",
|
"drag",
|
||||||
|
"nudge",
|
||||||
"toggleSubtitleNudge",
|
"toggleSubtitleNudge",
|
||||||
"display"
|
"display"
|
||||||
];
|
];
|
||||||
@@ -2782,6 +2788,12 @@ function runAction(action, value, e) {
|
|||||||
case "toggleSubtitleNudge":
|
case "toggleSubtitleNudge":
|
||||||
setSubtitleNudgeEnabledForVideo(v, subtitleNudgeToggleValue);
|
setSubtitleNudgeEnabledForVideo(v, subtitleNudgeToggleValue);
|
||||||
break;
|
break;
|
||||||
|
case "nudge":
|
||||||
|
setSubtitleNudgeEnabledForVideo(
|
||||||
|
v,
|
||||||
|
!isSubtitleNudgeEnabledForVideo(v)
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
log("runAction End", 5);
|
log("runAction End", 5);
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Speeder",
|
"name": "Speeder",
|
||||||
"short_name": "Speeder",
|
"short_name": "Speeder",
|
||||||
"version": "5.1.0",
|
"version": "5.1.3",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts (New and improved version of \"Video Speed Controller\")",
|
"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",
|
"homepage_url": "https://github.com/SoPat712/speeder",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
],
|
],
|
||||||
"options_ui": {
|
"options_ui": {
|
||||||
"page": "options.html",
|
"page": "options.html",
|
||||||
"open_in_tab": false
|
"open_in_tab": true
|
||||||
},
|
},
|
||||||
"browser_action": {
|
"browser_action": {
|
||||||
"default_icon": {
|
"default_icon": {
|
||||||
|
|||||||
@@ -873,13 +873,6 @@ button.lucide-result-tile.lucide-picked {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#faq hr {
|
|
||||||
height: 1px;
|
|
||||||
margin: 0 0 14px;
|
|
||||||
border: 0;
|
|
||||||
background: var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.support-footer {
|
.support-footer {
|
||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
|
|||||||
+5
-8
@@ -272,11 +272,6 @@
|
|||||||
</label>
|
</label>
|
||||||
<input id="hideWithControlsTimer" type="text" placeholder="2" />
|
<input id="hideWithControlsTimer" type="text" placeholder="2" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row row-checkbox">
|
|
||||||
<label for="showPopupControlBar">Show popup control bar</label>
|
|
||||||
<input id="showPopupControlBar" type="checkbox" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="defaults-divider"></div>
|
<div class="defaults-divider"></div>
|
||||||
<h4 class="defaults-sub-heading">Subtitle sync</h4>
|
<h4 class="defaults-sub-heading">Subtitle sync</h4>
|
||||||
|
|
||||||
@@ -350,7 +345,11 @@
|
|||||||
Configure which buttons appear in the browser popup control bar.
|
Configure which buttons appear in the browser popup control bar.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row row-checkbox">
|
||||||
|
<label for="showPopupControlBar">Show popup control bar</label>
|
||||||
|
<input id="showPopupControlBar" type="checkbox" />
|
||||||
|
</div>
|
||||||
|
<div class="row row-checkbox">
|
||||||
<label for="popupMatchHoverControls">Match hover controls</label>
|
<label for="popupMatchHoverControls">Match hover controls</label>
|
||||||
<input id="popupMatchHoverControls" type="checkbox" />
|
<input id="popupMatchHoverControls" type="checkbox" />
|
||||||
</div>
|
</div>
|
||||||
@@ -678,8 +677,6 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="faq" class="settings-card info-card">
|
<section id="faq" class="settings-card info-card">
|
||||||
<hr />
|
|
||||||
|
|
||||||
<h4>Extension controls not appearing?</h4>
|
<h4>Extension controls not appearing?</h4>
|
||||||
<p>
|
<p>
|
||||||
This extension only works with HTML5 audio and video. If the
|
This extension only works with HTML5 audio and video. If the
|
||||||
|
|||||||
+45
-8
@@ -147,6 +147,19 @@ var controllerButtonDefs = {
|
|||||||
mark: { icon: "\u2691", name: "Set marker" },
|
mark: { icon: "\u2691", name: "Set marker" },
|
||||||
jump: { icon: "\u21E5", name: "Jump to marker" }
|
jump: { icon: "\u21E5", name: "Jump to marker" }
|
||||||
};
|
};
|
||||||
|
var popupExcludedButtonIds = new Set(["settings"]);
|
||||||
|
|
||||||
|
function sanitizePopupButtonOrder(buttonIds) {
|
||||||
|
if (!Array.isArray(buttonIds)) return [];
|
||||||
|
var seen = new Set();
|
||||||
|
return buttonIds.filter(function (id) {
|
||||||
|
if (!controllerButtonDefs[id] || popupExcludedButtonIds.has(id) || seen.has(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen.add(id);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** Cached custom Lucide SVGs (mirrors chrome.storage.local customButtonIcons). */
|
/** Cached custom Lucide SVGs (mirrors chrome.storage.local customButtonIcons). */
|
||||||
var customButtonIconsLive = {};
|
var customButtonIconsLive = {};
|
||||||
@@ -713,7 +726,7 @@ function save_options() {
|
|||||||
document.getElementById("showPopupControlBar").checked;
|
document.getElementById("showPopupControlBar").checked;
|
||||||
settings.popupMatchHoverControls =
|
settings.popupMatchHoverControls =
|
||||||
document.getElementById("popupMatchHoverControls").checked;
|
document.getElementById("popupMatchHoverControls").checked;
|
||||||
settings.popupControllerButtons = getPopupControlBarOrder();
|
settings.popupControllerButtons = sanitizePopupButtonOrder(getPopupControlBarOrder());
|
||||||
|
|
||||||
// Collect site rules
|
// Collect site rules
|
||||||
settings.siteRules = [];
|
settings.siteRules = [];
|
||||||
@@ -802,7 +815,9 @@ function save_options() {
|
|||||||
ruleEl.querySelector(".site-showPopupControlBar").checked;
|
ruleEl.querySelector(".site-showPopupControlBar").checked;
|
||||||
var popupActiveZone = ruleEl.querySelector(".site-popup-cb-active");
|
var popupActiveZone = ruleEl.querySelector(".site-popup-cb-active");
|
||||||
if (popupActiveZone) {
|
if (popupActiveZone) {
|
||||||
rule.popupControllerButtons = readControlBarOrder(popupActiveZone);
|
rule.popupControllerButtons = sanitizePopupButtonOrder(
|
||||||
|
readControlBarOrder(popupActiveZone)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1071,7 +1086,10 @@ function createSiteRule(rule) {
|
|||||||
populateControlBarZones(
|
populateControlBarZones(
|
||||||
sitePopupActive,
|
sitePopupActive,
|
||||||
sitePopupAvailable,
|
sitePopupAvailable,
|
||||||
rule.popupControllerButtons
|
sanitizePopupButtonOrder(rule.popupControllerButtons),
|
||||||
|
function (id) {
|
||||||
|
return !popupExcludedButtonIds.has(id);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
sitePopupActive &&
|
sitePopupActive &&
|
||||||
@@ -1081,7 +1099,10 @@ function createSiteRule(rule) {
|
|||||||
populateControlBarZones(
|
populateControlBarZones(
|
||||||
sitePopupActive,
|
sitePopupActive,
|
||||||
sitePopupAvailable,
|
sitePopupAvailable,
|
||||||
getPopupControlBarOrder()
|
getPopupControlBarOrder(),
|
||||||
|
function (id) {
|
||||||
|
return !popupExcludedButtonIds.has(id);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1139,16 +1160,23 @@ function createControlBarBlock(buttonId) {
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateControlBarZones(activeZone, availableZone, activeIds) {
|
function populateControlBarZones(activeZone, availableZone, activeIds, allowButtonId) {
|
||||||
activeZone.innerHTML = "";
|
activeZone.innerHTML = "";
|
||||||
availableZone.innerHTML = "";
|
availableZone.innerHTML = "";
|
||||||
|
|
||||||
|
var allowed = function (id) {
|
||||||
|
if (!controllerButtonDefs[id]) return false;
|
||||||
|
return typeof allowButtonId === "function" ? Boolean(allowButtonId(id)) : true;
|
||||||
|
};
|
||||||
|
|
||||||
activeIds.forEach(function (id) {
|
activeIds.forEach(function (id) {
|
||||||
|
if (!allowed(id)) return;
|
||||||
var block = createControlBarBlock(id);
|
var block = createControlBarBlock(id);
|
||||||
if (block) activeZone.appendChild(block);
|
if (block) activeZone.appendChild(block);
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.keys(controllerButtonDefs).forEach(function (id) {
|
Object.keys(controllerButtonDefs).forEach(function (id) {
|
||||||
|
if (!allowed(id)) return;
|
||||||
if (!activeIds.includes(id)) {
|
if (!activeIds.includes(id)) {
|
||||||
var block = createControlBarBlock(id);
|
var block = createControlBarBlock(id);
|
||||||
if (block) availableZone.appendChild(block);
|
if (block) availableZone.appendChild(block);
|
||||||
@@ -1176,15 +1204,21 @@ function getControlBarOrder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function populatePopupControlBarEditor(activeIds) {
|
function populatePopupControlBarEditor(activeIds) {
|
||||||
|
var popupActiveIds = sanitizePopupButtonOrder(activeIds);
|
||||||
populateControlBarZones(
|
populateControlBarZones(
|
||||||
document.getElementById("popupControlBarActive"),
|
document.getElementById("popupControlBarActive"),
|
||||||
document.getElementById("popupControlBarAvailable"),
|
document.getElementById("popupControlBarAvailable"),
|
||||||
activeIds
|
popupActiveIds,
|
||||||
|
function (id) {
|
||||||
|
return !popupExcludedButtonIds.has(id);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPopupControlBarOrder() {
|
function getPopupControlBarOrder() {
|
||||||
return readControlBarOrder(document.getElementById("popupControlBarActive"));
|
return sanitizePopupButtonOrder(
|
||||||
|
readControlBarOrder(document.getElementById("popupControlBarActive"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePopupEditorDisabledState() {
|
function updatePopupEditorDisabledState() {
|
||||||
@@ -1771,7 +1805,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
populateControlBarZones(
|
populateControlBarZones(
|
||||||
popupActiveZone,
|
popupActiveZone,
|
||||||
popupAvailableZone,
|
popupAvailableZone,
|
||||||
getPopupControlBarOrder()
|
getPopupControlBarOrder(),
|
||||||
|
function (id) {
|
||||||
|
return !popupExcludedButtonIds.has(id);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
display: { label: "", className: "hideButton" },
|
display: { label: "", className: "hideButton" },
|
||||||
reset: { label: "", className: "" },
|
reset: { label: "", className: "" },
|
||||||
fast: { label: "", className: "" },
|
fast: { label: "", className: "" },
|
||||||
|
nudge: { label: "", className: "" },
|
||||||
settings: { label: "", className: "" },
|
settings: { label: "", className: "" },
|
||||||
pause: { label: "", className: "" },
|
pause: { label: "", className: "" },
|
||||||
muted: { label: "", className: "" },
|
muted: { label: "", className: "" },
|
||||||
@@ -18,6 +19,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var defaultButtons = ["rewind", "slower", "faster", "advance", "display"];
|
var defaultButtons = ["rewind", "slower", "faster", "advance", "display"];
|
||||||
|
var popupExcludedButtonIds = new Set(["settings"]);
|
||||||
var storageDefaults = {
|
var storageDefaults = {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
showPopupControlBar: true,
|
showPopupControlBar: true,
|
||||||
@@ -64,25 +66,37 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolvePopupButtons(storage, siteRule) {
|
function resolvePopupButtons(storage, siteRule) {
|
||||||
|
function sanitize(buttons) {
|
||||||
|
if (!Array.isArray(buttons)) return [];
|
||||||
|
var seen = new Set();
|
||||||
|
return buttons.filter(function (id) {
|
||||||
|
if (!controllerButtonDefs[id] || popupExcludedButtonIds.has(id) || seen.has(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen.add(id);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (siteRule && Array.isArray(siteRule.popupControllerButtons)) {
|
if (siteRule && Array.isArray(siteRule.popupControllerButtons)) {
|
||||||
return siteRule.popupControllerButtons;
|
return sanitize(siteRule.popupControllerButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storage.popupMatchHoverControls) {
|
if (storage.popupMatchHoverControls) {
|
||||||
if (siteRule && Array.isArray(siteRule.controllerButtons)) {
|
if (siteRule && Array.isArray(siteRule.controllerButtons)) {
|
||||||
return siteRule.controllerButtons;
|
return sanitize(siteRule.controllerButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(storage.controllerButtons)) {
|
if (Array.isArray(storage.controllerButtons)) {
|
||||||
return storage.controllerButtons;
|
return sanitize(storage.controllerButtons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(storage.popupControllerButtons)) {
|
if (Array.isArray(storage.popupControllerButtons)) {
|
||||||
return storage.popupControllerButtons;
|
return sanitize(storage.popupControllerButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultButtons;
|
return sanitize(defaultButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setControlBarVisible(visible) {
|
function setControlBarVisible(visible) {
|
||||||
@@ -209,7 +223,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
var customMap = customIconsMap || {};
|
var customMap = customIconsMap || {};
|
||||||
|
|
||||||
buttons.forEach(function (btnId) {
|
buttons.forEach(function (btnId) {
|
||||||
if (btnId === "nudge") return;
|
|
||||||
var def = controllerButtonDefs[btnId];
|
var def = controllerButtonDefs[btnId];
|
||||||
if (!def) return;
|
if (!def) return;
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -10,8 +10,11 @@
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Show extra buttons on hover or keyboard :focus-visible only. Plain :focus-within
|
||||||
|
after a mouse click kept #controls visible while hover-only rules (e.g. draggable
|
||||||
|
margin) turned off when the pointer left the bar. */
|
||||||
#controller:hover #controls,
|
#controller:hover #controls,
|
||||||
#controller:focus-within #controls,
|
#controller:focus-within:has(:focus-visible) #controls,
|
||||||
:host(:hover) #controls {
|
:host(:hover) #controls {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|||||||
Reference in New Issue
Block a user