feat: expand shortcuts and improve YouTube navigation

This commit is contained in:
joshpatra committed 2026-07-26 10:19:11 -04:00
1 parent 04f1414118
commit a2d7f0d9d6
11 files changed
+224 -81

No files matched your search

+48 -1
View File
@@ -320,6 +320,7 @@ describe("inject.js media/controller lifecycle regressions", () => {
src: "blob:https://www.youtube.com/hover-preview",
mountRect: makeRect(0, 0, 320, 180)
});
preview.mount.id = "inline-preview-player";
document.dispatchEvent(
new MouseEvent("mousemove", { bubbles: true, clientX: 100, clientY: 90 })
);
@@ -333,6 +334,10 @@ describe("inject.js media/controller lifecycle regressions", () => {
src: "blob:https://www.youtube.com/main-player",
mountRect: makeRect(0, 0, 1280, 720)
});
main.mount.id = "movie_player";
document.dispatchEvent(
new MouseEvent("mousemove", { bubbles: true, clientX: 100, clientY: 90 })
);
document.dispatchEvent(
new KeyboardEvent("keydown", {
bubbles: true,
@@ -342,11 +347,53 @@ describe("inject.js media/controller lifecycle regressions", () => {
})
);
expect(window.tc.lastPointerPosition).toBeNull();
expect(window.tc.lastPointerPosition).not.toBeNull();
expect(preview.video.playbackRate).toBe(1);
expect(main.video.playbackRate).toBe(1.1);
});
it("captures SPA shortcuts before later page handlers and distinguishes Shift", async () => {
vi.useFakeTimers();
bootInject({
syncGetDelayMs: 25,
syncData: {
keyBindings: [
{ action: "advance", code: "KeyX", value: 10 },
{ action: "advance", code: "KeyX", shiftKey: true, value: 3 }
]
}
});
expect(window.vscKeydownListenerAttached).toBe(true);
window.addEventListener(
"keydown",
(event) => event.stopImmediatePropagation(),
true
);
await vi.advanceTimersByTimeAsync(25);
await settleLifecycle();
const { video } = createControlledVideo();
video.currentTime = 50;
video.dispatchEvent(
new KeyboardEvent("keydown", {
bubbles: true,
code: "KeyX",
key: "x"
})
);
video.dispatchEvent(
new KeyboardEvent("keydown", {
bubbles: true,
code: "KeyX",
key: "X",
shiftKey: true
})
);
expect(video.currentTime).toBe(63);
});
it("skips ambient loops by default and includes them when explicitly enabled", async () => {
bootInject();
await settleLifecycle();
+42
View File
@@ -106,6 +106,48 @@ describe("options page", () => {
expect(chrome.storage.sync.set).not.toHaveBeenCalled();
});
it("adds and restores duplicate actions with Shift bindings", async () => {
const chrome = await setupOptions();
const selector = document.getElementById("addShortcutSelector");
expect(selector.querySelector('option[value="rewind"]')).not.toBeNull();
selector.value = "rewind";
selector.dispatchEvent(new window.Event("change", { bubbles: true }));
const duplicate = document.querySelector(
'.shortcut-row.customs[data-action="rewind"]'
);
duplicate.querySelector(".customKey").dispatchEvent(
new window.KeyboardEvent("keydown", {
key: "Z",
code: "KeyZ",
shiftKey: true,
bubbles: true
})
);
duplicate.querySelector(".customValue").value = "3";
globalThis.save_options();
expect(
chrome.storage.sync.__state.keyBindings.filter(
(binding) => binding.action === "rewind"
)
).toEqual([
expect.objectContaining({ value: 10, shiftKey: false }),
expect.objectContaining({ value: 3, shiftKey: true })
]);
globalThis.restore_options();
await flushAsyncWork();
expect(
document.querySelectorAll('.shortcut-row[data-action="rewind"]')
).toHaveLength(2);
expect(
document.querySelector(
'.shortcut-row.customs[data-action="rewind"] .customKey'
).value
).toBe("Shift+Z");
});
it("shows a more-menu trigger for collapsed site rules and a collapse trigger when open", async () => {
await setupOptions({ sync: { siteRules: [] } });
+16
View File
@@ -67,6 +67,22 @@ describe("options.js", () => {
expect(chrome.storage.sync.set).not.toHaveBeenCalled();
});
it("automatically saves changed settings", async () => {
const chrome = bootOptions({ syncData: { rememberSpeed: false } });
await flushAsyncWork(3);
vi.useFakeTimers();
chrome.storage.sync.set.mockClear();
const rememberSpeed = document.getElementById("rememberSpeed");
rememberSpeed.checked = true;
rememberSpeed.dispatchEvent(new Event("change", { bubbles: true }));
expect(chrome.storage.sync.set).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(300);
expect(chrome.storage.sync._dump().rememberSpeed).toBe(true);
});
it("does not partially save options when a required site shortcut is invalid", async () => {
const chrome = bootOptions({ syncData: { rememberSpeed: false } });
await flushAsyncWork(3);
+2 -2
View File
@@ -244,7 +244,7 @@ describe("canonical settings storage", () => {
forceLastSavedSpeed: "true",
controllerOpacity: 3,
subtitleNudgeInterval: -5,
preferredSpeed: 50
preferredSpeed: 500
}
]
});
@@ -257,7 +257,7 @@ describe("canonical settings storage", () => {
expect(rule.forceLastSavedSpeed).toBe(true);
expect(rule.controllerOpacity).toBe(1);
expect(rule.subtitleNudgeInterval).toBe(250);
expect(rule.preferredSpeed).toBe(16);
expect(rule.preferredSpeed).toBe(100);
});
it("falls back for null and blank numeric settings instead of coercing zero", () => {
+5
View File
@@ -158,6 +158,11 @@ describe("shared helpers", () => {
"NumpadAdd"
);
expect(keyBindingUtils.getLegacyKeyCode({ key: 65 })).toBe(65);
expect(keyBindingUtils.getActionValueError("fast", 0.01)).toBeNull();
expect(keyBindingUtils.getActionValueError("fast", 100)).toBeNull();
expect(keyBindingUtils.getActionValueError("fast", 0.009)).toContain(
"between 0.01 and 100"
);
});
it("builds and parses import/export payloads", () => {