Skip to content

Auto-pause silently fails after the MV3 service worker goes inactive (previous_tab resets to -1) #20

Description

@vicmaela-stack

Version: 1.13.0 · Chrome · Windows 11

Summary

Auto-pause on tab switch works only intermittently. It fails whenever Chrome has suspended the MV3 service worker, which happens after roughly 30 seconds without extension activity.

Root cause

previous_tab is module-level state in the service worker:

let previous_tab = -1;

MV3 terminates the worker when idle and discards that state. On wake it is back to -1, so the guard in tabs.onActivated skips the pause entirely:

if (options.autopause && previous_tab !== -1) {

refresh_settings() does restore it, but it is invoked without await at module scope and suspends at its first await. The tabs.onActivated listener that woke the worker therefore runs before the restore finishes and observes previous_tab === -1.

This is most likely to hit in the extension's primary use case: watching a video generates no extension events, so the worker is almost always suspended by the time the user switches tabs. That makes the failure look random to users.

Steps to reproduce

  1. Enable auto-pause and auto-resume.
  2. Start a video in tab A.
  3. Let it play for ~60 seconds without touching the browser, so the service worker is suspended (shows as "inactive" on chrome://extensions).
  4. Switch to tab B.

Expected: the video in tab A pauses.
Actual: it keeps playing. Performing the same switch immediately after any extension activity works correctly.

Suggested fix

Mirror previous_tab and previous_window into chrome.storage.session, which survives worker suspension and is cleared on browser restart, and have the listeners wait for initialization:

const settingsReady = refresh_settings();

env.tabs.onActivated.addListener(async function (info) {
  await settingsReady;
  // ...
});

with refresh_settings() reading the stored values before falling back to the existing tabs.query logic.

Minor, unrelated

registerContentScripts runs again on every worker wake, but the registration itself persists, so it rejects with Duplicate script ID 'video_auto_pause'. Guarding with getRegisteredContentScripts (or a try/catch) removes the unhandled rejection.

I have both changes running locally and can share the exact diff if that is useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions