mirror of
https://github.com/SoPat712/Speeder.git
synced 2026-10-08 19:05:02 -04:00
feat(controller): configure ambient video overlays
This commit is contained in:
8 files changed
+236
-16
No files matched your search
@@ -25,6 +25,7 @@ describe("import/export flows", () => {
|
||||
const settings = globalThis.vscGetSettingsDefaults();
|
||||
settings.siteRules[1].title = "My Shorts rule";
|
||||
settings.siteRules[1].shortcutTargetMode = "all";
|
||||
settings.siteRules[1].showAmbientLoopControls = true;
|
||||
|
||||
const exported = globalThis.normalizedSettingsForExport(
|
||||
globalThis.vscBuildStoredSettingsDiff(settings)
|
||||
@@ -33,6 +34,7 @@ describe("import/export flows", () => {
|
||||
|
||||
expect(restored.siteRules[1].title).toBe("My Shorts rule");
|
||||
expect(restored.siteRules[1].shortcutTargetMode).toBe("all");
|
||||
expect(restored.siteRules[1].showAmbientLoopControls).toBe(true);
|
||||
expect(exported.siteRules.map((rule) => rule.title)).toEqual([
|
||||
"YouTube videos",
|
||||
"My Shorts rule",
|
||||
|
||||
@@ -309,7 +309,7 @@ describe("inject.js media/controller lifecycle regressions", () => {
|
||||
expect(second.video.playbackRate).toBe(1.2);
|
||||
});
|
||||
|
||||
it("skips GIF-like ambient loops but accepts them if they become real players", async () => {
|
||||
it("skips ambient loops by default and includes them when explicitly enabled", async () => {
|
||||
bootInject();
|
||||
await settleLifecycle();
|
||||
|
||||
@@ -332,12 +332,71 @@ describe("inject.js media/controller lifecycle regressions", () => {
|
||||
expect(window.ensureController(video, mount)).toBeNull();
|
||||
expect(video.vsc).toBeUndefined();
|
||||
|
||||
video.loop = false;
|
||||
video.controls = true;
|
||||
window.tc.settings.showAmbientLoopControls = true;
|
||||
window.tc.siteRuleBase.showAmbientLoopControls = true;
|
||||
expect(window.ensureController(video, mount)).toBeTruthy();
|
||||
expect(video.vsc.div.isConnected).toBe(true);
|
||||
});
|
||||
|
||||
it("always includes a genuine player even when its video has an ambient-loop signature", async () => {
|
||||
bootInject();
|
||||
await settleLifecycle();
|
||||
|
||||
const player = document.createElement("media-player");
|
||||
const video = document.createElement("video");
|
||||
const playButton = document.createElement("button");
|
||||
const rect = makeRect(0, 0, 640, 360);
|
||||
playButton.setAttribute("aria-label", "Play");
|
||||
video.autoplay = true;
|
||||
video.defaultMuted = true;
|
||||
video.muted = true;
|
||||
video.loop = true;
|
||||
video.playsInline = true;
|
||||
video.src = "https://example.org/interactive-loop.mp4";
|
||||
player.append(video, playButton);
|
||||
document.body.appendChild(player);
|
||||
[player, video].forEach((element) => setRect(element, rect));
|
||||
setBoxMetrics(player, rect.width, rect.height);
|
||||
|
||||
expect(window.tc.settings.showAmbientLoopControls).toBe(false);
|
||||
expect(window.ensureController(video, player)).toBeTruthy();
|
||||
expect(video.vsc.div.isConnected).toBe(true);
|
||||
});
|
||||
|
||||
it("applies the ambient-loop setting from a matching site rule", async () => {
|
||||
bootInject({
|
||||
url: "https://news.example.org/story",
|
||||
syncData: {
|
||||
showAmbientLoopControls: false,
|
||||
siteRules: [
|
||||
{
|
||||
pattern: "news.example.org",
|
||||
enabled: true,
|
||||
showAmbientLoopControls: true
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
await settleLifecycle();
|
||||
|
||||
const mount = document.createElement("div");
|
||||
const video = document.createElement("video");
|
||||
const rect = makeRect(0, 0, 480, 270);
|
||||
video.autoplay = true;
|
||||
video.defaultMuted = true;
|
||||
video.muted = true;
|
||||
video.loop = true;
|
||||
video.playsInline = true;
|
||||
video.src = "https://news.example.org/card.mp4";
|
||||
mount.appendChild(video);
|
||||
document.body.appendChild(mount);
|
||||
[mount, video].forEach((element) => setRect(element, rect));
|
||||
setBoxMetrics(mount, rect.width, rect.height);
|
||||
|
||||
expect(window.ensureController(video, mount)).toBeTruthy();
|
||||
expect(window.tc.settings.showAmbientLoopControls).toBe(true);
|
||||
});
|
||||
|
||||
it("moves the host into an ancestor fullscreen subtree and restores it", async () => {
|
||||
bootInject();
|
||||
await settleLifecycle();
|
||||
@@ -610,6 +669,14 @@ describe("inject.js media/controller lifecycle regressions", () => {
|
||||
|
||||
controllerElement.dispatchEvent(new Event("pointerleave"));
|
||||
expect(wrapper.classList.contains("ytp-autohide")).toBe(true);
|
||||
|
||||
player.dispatchEvent(new MouseEvent("mousemove", { bubbles: true }));
|
||||
expect(wrapper.classList.contains("vsc-show")).toBe(true);
|
||||
player.classList.remove("ytp-autohide");
|
||||
player.classList.add("ytp-autohide");
|
||||
await settleLifecycle();
|
||||
expect(wrapper.classList.contains("ytp-autohide")).toBe(true);
|
||||
expect(wrapper.classList.contains("vsc-show")).toBe(true);
|
||||
});
|
||||
|
||||
it("suppresses a zero-size host and reveals it when the video becomes visible", async () => {
|
||||
|
||||
@@ -29,6 +29,7 @@ describe("options page", () => {
|
||||
manifestVersion: "5.1.7.0",
|
||||
sync: {
|
||||
rememberSpeed: true,
|
||||
showAmbientLoopControls: true,
|
||||
enabled: false,
|
||||
shortcutTargetMode: "all",
|
||||
subtitleNudgeEnabledByDefault: false,
|
||||
@@ -45,6 +46,7 @@ describe("options page", () => {
|
||||
enabled: true,
|
||||
shortcutTargetMode: "all",
|
||||
preferredSpeed: 2.4,
|
||||
showAmbientLoopControls: false,
|
||||
subtitleNudgeEnabledByDefault: false,
|
||||
showPopupControlBar: false,
|
||||
popupControllerButtons: ["advance", "settings", "advance"]
|
||||
@@ -55,6 +57,7 @@ describe("options page", () => {
|
||||
|
||||
expect(document.getElementById("app-version").textContent).toBe("5.1.7.0");
|
||||
expect(document.getElementById("rememberSpeed").checked).toBe(true);
|
||||
expect(document.getElementById("showAmbientLoopControls").checked).toBe(true);
|
||||
expect(document.getElementById("enabled").checked).toBe(false);
|
||||
expect(document.getElementById("shortcutTargetMode").value).toBe("all");
|
||||
expect(document.getElementById("subtitleNudgeEnabledByDefault").checked).toBe(
|
||||
@@ -72,6 +75,9 @@ describe("options page", () => {
|
||||
expect(document.querySelector(".site-rule .site-preferredSpeed").value).toBe(
|
||||
"2.4"
|
||||
);
|
||||
expect(
|
||||
document.querySelector(".site-rule .site-showAmbientLoopControls").checked
|
||||
).toBe(false);
|
||||
expect(
|
||||
document.querySelector(".site-rule .site-shortcutTargetMode").value
|
||||
).toBe("all");
|
||||
@@ -181,6 +187,7 @@ describe("options page", () => {
|
||||
const chrome = await setupOptions();
|
||||
|
||||
document.getElementById("rememberSpeed").checked = true;
|
||||
document.getElementById("showAmbientLoopControls").checked = true;
|
||||
document.getElementById("hideWithControlsTimer").value = "20";
|
||||
document.getElementById("controllerOpacity").value = "0";
|
||||
document.getElementById("controllerMarginTop").value = "250";
|
||||
@@ -204,6 +211,7 @@ describe("options page", () => {
|
||||
rule.querySelector(".site-pattern").value = "youtube.com";
|
||||
rule.querySelector(".override-playback").checked = true;
|
||||
rule.querySelector(".site-rememberSpeed").checked = true;
|
||||
rule.querySelector(".site-showAmbientLoopControls").checked = false;
|
||||
rule.querySelector(".site-preferredSpeed").value = "2.4";
|
||||
rule.querySelector(".override-shortcut-target").checked = true;
|
||||
rule.querySelector(".site-shortcutTargetMode").value = "all";
|
||||
@@ -231,6 +239,7 @@ describe("options page", () => {
|
||||
);
|
||||
|
||||
expect(savedSettings.rememberSpeed).toBe(true);
|
||||
expect(savedSettings.showAmbientLoopControls).toBe(true);
|
||||
expect(savedSettings.hideWithControlsTimer).toBe(15);
|
||||
expect(savedSettings.controllerOpacity).toBe(0);
|
||||
expect(savedSettings.controllerMarginTop).toBe(200);
|
||||
@@ -246,6 +255,7 @@ describe("options page", () => {
|
||||
title: "My YouTube rule",
|
||||
pattern: "youtube.com",
|
||||
rememberSpeed: true,
|
||||
showAmbientLoopControls: false,
|
||||
shortcutTargetMode: "all",
|
||||
preferredSpeed: 2.4,
|
||||
controllerOpacity: 0,
|
||||
|
||||
@@ -34,10 +34,36 @@ describe("canonical settings storage", () => {
|
||||
})
|
||||
);
|
||||
expect(settings.shortcutTargetMode).toBe("closest");
|
||||
expect(settings.showAmbientLoopControls).toBe(false);
|
||||
expect(settings.subtitleNudgeInterval).toBe(250);
|
||||
expect(settings.siteRules[0].enableSubtitleNudge).toBeUndefined();
|
||||
});
|
||||
|
||||
it("round-trips global and site-specific ambient-loop visibility", () => {
|
||||
const settings = window.vscExpandStoredSettings({
|
||||
showAmbientLoopControls: true,
|
||||
siteRules: [
|
||||
{
|
||||
pattern: "cnn.com",
|
||||
showAmbientLoopControls: false
|
||||
}
|
||||
]
|
||||
});
|
||||
const restored = window.vscExpandStoredSettings(
|
||||
window.vscBuildStoredSettingsDiff(settings)
|
||||
);
|
||||
|
||||
expect(restored.showAmbientLoopControls).toBe(true);
|
||||
expect(restored.siteRules).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
pattern: "cnn.com",
|
||||
showAmbientLoopControls: false
|
||||
})
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("round-trips global and site-specific shortcut targeting", () => {
|
||||
const settings = window.vscExpandStoredSettings({
|
||||
shortcutTargetMode: "all",
|
||||
|
||||
Reference in new issue
Block a user