disable-autogain-control-extension icon indicating copy to clipboard operation
disable-autogain-control-extension copied to clipboard

Switch to Manifest v3 for Chrome

Open AlexWayfer opened this issue 1 year ago • 1 comments

image

image

AlexWayfer avatar Aug 06 '24 18:08 AlexWayfer

ChatGPT suggests the following v3 manifest ;-)

{
    "name": "Disable Automatic Gain Control",
    "version": "1.3",
    "description": "Disables the automatic microphone gain control enabled by web applications like Google Meet and Hangouts.",
    "manifest_version": 3,
    "background": {
        "service_worker": "background.js"
    },
    "content_scripts": [
      {
        "matches": ["<all_urls>"],
        "js": ["installDisableAutogain.js"]
      }
    ],
    "web_accessible_resources": [
        {
            "resources": ["disableAutogain.js"],
            "matches": ["<all_urls>"]
        }
    ],
    "action": {},
    "permissions": [
        "activeTab",
        "contextMenus"
    ],
    "host_permissions": [
        "http://*/",
        "https://*/"
    ]
}

And the following background.js changes:

// Show context menu that allows enabling/disabling on a per-domain basis.
chrome.action.onClicked.addListener((tab) => {
    const { origin } = new URL(tab.url);
    chrome.permissions.contains({
        origins: [origin + "/*"],
    }, (hasPermission) => {
        if (hasPermission) {
            chrome.permissions.remove({
                origins: [origin + "/*"]
            }, () => chrome.tabs.reload(tab.id));
        } else {
            chrome.permissions.request({
                origins: [origin + "/*"]
            }, () => chrome.tabs.reload(tab.id));
        }
    });
});

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    injectScriptIfNecessary(tab);
});

/**
 * @param {chrome.tabs.Tab} tab 
 */
function injectScriptIfNecessary(tab) {
    if (tab.status !== "loading" || !tab.url) {
        return;
    }

    try {
        const { origin, protocol } = new URL(tab.url);
        if (protocol !== "https:" && protocol !== "http:") {
            return;
        }
        chrome.permissions.contains({
            origins: [origin + "/*"]
        }, (hasPermission) => {
            if (hasPermission) {
                // Note: ExecuteScript is not available in Manifest v3. 
                // You need to use content_scripts in the manifest instead of this line.
                chrome.scripting.executeScript({
                    target: {tabId: tab.id, allFrames: true},
                    files: ["installDisableAutogain.js"]
                });
            }
            chrome.action.setTitle({
                title: hasPermission
                    ? "Disable Automatic Gain Control"
                    : "Enable Automatic Gain Control",
                tabId: tab.id,
            });
            chrome.action.setBadgeText({
                text: hasPermission ? "On" : "",
                tabId: tab.id,
            });
        });
    } catch (e) {
        console.error("Failed to inject script", e);
    }
}

function showUsage() {
    chrome.tabs.create({
        url: chrome.runtime.getURL("usage.html")
    });
}

function showUpgradeNotice() {
    chrome.tabs.create({
        url: chrome.runtime.getURL("upgradeFromV1.0.html")
    });
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (typeof message === "object" && message["type"] === "enable-meet-hangouts") {
        chrome.permissions.request({
            origins: [
                "https://meet.google.com/*",
                "https://hangouts.google.com/*"
            ]
        }, (granted) => {
            sendResponse(granted);
        });
        return true;
    }
});

chrome.contextMenus.create({
    title: "Usage",
    contexts: ["action"],
    onclick: () => {
        showUsage();
    }
});

chrome.runtime.onInstalled.addListener(({ reason, previousVersion }) => {
    if (reason === "update" && previousVersion === "1.0") {
        showUpgradeNotice();
    } else if (reason === "install") {
        showUsage();
    }
});

But I have absolutely no idea if it will work just like this -- just passing this along to see if it can help get this fixed smoothly...

dot-i avatar Oct 06 '24 12:10 dot-i

@AlexWayfer @dot-i - I forked the repo and updated it for manifest-v3. It works as far as I've been using it, but i haven't done extensive functional testing.

Currently submitting it to the chrome webstore, but if you wanted to pull it down and load it directly, here's the repo. https://github.com/stratten/disable-autogain-control-extension

stratten avatar Aug 02 '25 16:08 stratten

@AlexWayfer @dot-i - I forked the repo and updated it for manifest-v3. It works as far as I've been using it, but i haven't done extensive functional testing.

Currently submitting it to the chrome webstore, but if you wanted to pull it down and load it directly, here's the repo. https://github.com/stratten/disable-autogain-control-extension

@stratten thank you for your work on this! Your fork does indeed look like an usable alternative for d.a.g.c. I heard of your fork by a friend and I also plan to test it in chromium in the following days.

You told that you wanted to submit that one to the chrome web store. Do you already have new status updates on it how it keeps going or is it still waiting for the approval from Google?

dtdan-03 avatar Sep 23 '25 17:09 dtdan-03

@dtdan-03 - yeah, it was approved! And so far no one has reported any issues.

https://chromewebstore.google.com/detail/disable-automatic-gain-co/dfjdfadcciciboknnahlhgonamhfgmhp

stratten avatar Sep 24 '25 12:09 stratten

@dot-i / @dtdan-03 - this is a quick breakdown of the core adjustments that were required:

  • Migrated extension from Manifest V2 to V3
  • Updated background script for MV3 service worker model
  • Fixed permission handling and runtime errors

Key Updates:

  1. manifest.json → Manifest V3 migration
  • Set MV3, moved to service worker, updated APIs, defined icons, corrected host permissions
{
  "manifest_version": 3,
  "background": { "service_worker": "background.js" },
  "action": {},
  "web_accessible_resources": [
    { "resources": ["disableAutogain.js"], "matches": ["<all_urls>"] }
  ],
  "icons": {
    "16": "images/icon16.png",
    "32": "images/icon32.png",
    "48": "images/icon48.png",
    "128": "images/icon128.png"
  },
  "permissions": ["activeTab", "contextMenus", "scripting"],
  "optional_host_permissions": ["http://*/", "https://*/"]
}
  1. background.js → MV2 APIs replaced with MV3 equivalents
  • browserAction → action
  • tabs.executeScript → scripting.executeScript
  • extension.getURL → runtime.getURL
  • Added protocol guard to avoid invalid schemes
  • Moved context menu creation into onInstalled to avoid duplicate IDs

Action click: add protocol guard and dynamic per-origin permission toggle

chrome.action.onClicked.addListener(tab => {
  const { origin, protocol } = new URL(tab.url);
  if (protocol !== "https:" && protocol !== "http:") {
    return; // prevents chrome-extension:// and other invalid schemes
  }
  chrome.permissions.contains({ origins: [origin + "/*"] }, hasPermission => {
    if (hasPermission) {
      chrome.permissions.remove({ origins: [origin + "/*"] }, () => chrome.tabs.reload(tab.id));
    } else {
      chrome.permissions.request({ origins: [origin + "/*"] }, () => chrome.tabs.reload(tab.id));
    }
  });
});

Inject the installer script when allowed

chrome.scripting.executeScript({
  target: { tabId: tab.id, allFrames: true },
  files: ["installDisableAutogain.js"]
});

Update title and badge

chrome.action.setTitle({ title: hasPermission ? "Disable Automatic Gain Control" : "Enable Automatic Gain Control", tabId: tab.id });
chrome.action.setBadgeText({ text: hasPermission ? "On" : "", tabId: tab.id });

runtime URL getters

chrome.runtime.getURL("usage.html");
chrome.runtime.getURL("upgradeFromV1.0.html");

Context menu: create once on install/enable, listen globally for clicks

chrome.runtime.onInstalled.addListener(({ reason, previousVersion }) => {
  chrome.contextMenus.create({ title: "Usage", contexts: ["action"], id: "usage-menu" });
  if (reason === "update" && previousVersion === "1.0") { showUpgradeNotice(); }
  else if (reason === "install") { showUsage(); }
});

chrome.contextMenus.onClicked.addListener(info => {
  if (info.menuItemId === "usage-menu") { showUsage(); }
});

Errors Resolved:

  • Unsupported manifest version → Upgraded to MV3 (service_worker, action, web_accessible_resources changes)
  • Permission 'http://*/' is unknown → Use optional_host_permissions (not optional_permissions)
  • Invalid scheme for origin (chrome-extension://...) → Added protocol guard in action click handler and in injector
  • You cannot remove required permissions → Made host permissions optional so they can be added/removed per-origin
  • Cannot create item with duplicate id usage-menu → Create context menu in onInstalled only

stratten avatar Sep 24 '25 12:09 stratten