Close popup automatically after a successful save

This commit is contained in:
Justin Oro
2026-09-02 16:53:22 -07:00
parent b2082d0624
commit 646a106e93
4 changed files with 39 additions and 1 deletions
+3 -1
View File
@@ -26,6 +26,8 @@ A small Chrome extension that automatically clicks "Skip Intro" and "Skip Credit
Changing the Plex URL takes effect on your next page load — refresh your Plex tab after saving a new one. Toggle and delay changes apply immediately, no refresh needed. Changing the Plex URL takes effect on your next page load — refresh your Plex tab after saving a new one. Toggle and delay changes apply immediately, no refresh needed.
Clicking **Save** closes the popup automatically shortly after confirming the save, so you don't have to click elsewhere to dismiss it. If something's wrong with what you entered (like a blank or invalid custom URL), the popup shows an error and stays open instead.
## How it works ## How it works
The extension's content script runs on every page but only activates once the page's hostname matches your configured Plex URL. From there it uses a `MutationObserver` to watch the page for any `<button>` or `[role="button"]` element whose visible text contains "skip intro" or "skip credit" (case-insensitive, so it still matches if Plex appends a countdown like "Skip Intro 0:05"). When a match appears and is actually visible, it schedules a click — immediately if its delay is 0, or after the configured delay otherwise. Right before a delayed click actually fires, it re-checks that the button is still present, visible, still says "Skip Intro"/"Skip Credits", and that its toggle is still on — so turning a toggle off, or Plex removing the button, cancels a pending click instead of firing it late. A short cooldown per element stops a single button from being double-clicked in one burst, but still allows a later click if Plex reuses the same button element for the next episode. The extension's content script runs on every page but only activates once the page's hostname matches your configured Plex URL. From there it uses a `MutationObserver` to watch the page for any `<button>` or `[role="button"]` element whose visible text contains "skip intro" or "skip credit" (case-insensitive, so it still matches if Plex appends a countdown like "Skip Intro 0:05"). When a match appears and is actually visible, it schedules a click — immediately if its delay is 0, or after the configured delay otherwise. Right before a delayed click actually fires, it re-checks that the button is still present, visible, still says "Skip Intro"/"Skip Credits", and that its toggle is still on — so turning a toggle off, or Plex removing the button, cancels a pending click instead of firing it late. A short cooldown per element stops a single button from being double-clicked in one burst, but still allows a later click if Plex reuses the same button element for the next episode.
@@ -41,7 +43,7 @@ npm install
npm test npm test
``` ```
The suite covers: clicking Skip Intro/Skip Credits, ignoring non-Plex pages, respecting the on/off toggles, matching a custom server URL, reacting to buttons added dynamically after page load, ignoring unrelated buttons, handling countdown suffixes in the button text, not clicking hidden buttons, correctly re-clicking a reused button after its cooldown, delayed clicks (including cancellation when a toggle turns off or the button disappears mid-delay), and the settings popup's save/validation/load behavior for both the URL and the delay sliders. The suite covers: clicking Skip Intro/Skip Credits, ignoring non-Plex pages, respecting the on/off toggles, matching a custom server URL, reacting to buttons added dynamically after page load, ignoring unrelated buttons, handling countdown suffixes in the button text, not clicking hidden buttons, correctly re-clicking a reused button after its cooldown, delayed clicks (including cancellation when a toggle turns off or the button disappears mid-delay), and the settings popup's save/validation/load behavior for the URL, the delay sliders, and auto-close on save.
## Troubleshooting ## Troubleshooting
+3
View File
@@ -88,6 +88,9 @@ document.addEventListener("DOMContentLoaded", () => {
}, },
() => { () => {
showStatus("Saved", false); showStatus("Saved", false);
setTimeout(() => {
window.close();
}, 600);
} }
); );
}); });
+5
View File
@@ -74,6 +74,11 @@ function loadPopupScript({ initialSettings } = {}) {
); );
const savedCalls = []; const savedCalls = [];
window.__closeCalled = false;
window.close = () => {
window.__closeCalled = true;
};
window.chrome = { window.chrome = {
storage: { storage: {
sync: { sync: {
+28
View File
@@ -133,3 +133,31 @@ test("unchecking a toggle and saving persists it as false", async () => {
assert.strictEqual(savedCalls[0].skipCredits, false); assert.strictEqual(savedCalls[0].skipCredits, false);
assert.strictEqual(savedCalls[0].skipIntro, true); assert.strictEqual(savedCalls[0].skipIntro, true);
}); });
test("closes the popup shortly after a successful save", async () => {
const { window } = loadPopupScript();
await wait(20);
window.document.getElementById("saveBtn").click();
await wait(50);
assert.strictEqual(window.__closeCalled, false, "should not close instantly, so the Saved message is visible");
await wait(700);
assert.strictEqual(window.__closeCalled, true, "should close shortly after saving");
});
test("does not close the popup when the save is rejected for a blank custom URL", async () => {
const { window } = loadPopupScript();
await wait(20);
const urlPreset = window.document.getElementById("urlPreset");
urlPreset.value = "custom";
urlPreset.dispatchEvent(new window.Event("change"));
window.document.getElementById("customUrl").value = " ";
window.document.getElementById("saveBtn").click();
await wait(700);
assert.strictEqual(window.__closeCalled, false);
});