superlevels-chrome-extension

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SuperLevels Chrome Extension

SuperLevels Chrome扩展

Skill by ara.so — Daily 2026 Skills collection.
SuperLevels is an open-source Chrome extension that consolidates 12+ browser tools into one auditable, privacy-respecting package. Features include tab cleaning, cookie editing, dark mode, JS toggle, GDPR consent dismissal, live CSS editing, YouTube unhooking, music recognition, Picture-in-Picture, and JSON formatting — all stored locally with zero telemetry.
来自ara.so的技能工具 — 2026每日技能合集。
SuperLevels是一款开源Chrome扩展,将12款以上浏览器工具整合到一个可审计、注重隐私的包中。功能包括标签页清理、Cookie编辑、深色模式、JS开关、GDPR同意弹窗关闭、实时CSS编辑、YouTube解绑、音乐识别、画中画以及JSON格式化——所有数据均本地存储,无任何遥测。

Installation (Developer Mode)

安装(开发者模式)

bash
git clone https://github.com/levelsio/superlevels.git
cd superlevels
  1. Open Chrome →
    chrome://extensions/
  2. Enable Developer mode (top-right toggle)
  3. Click Load unpacked → select the
    superlevels
    folder
  4. The 🚀 icon appears in your toolbar
No build step required — pure JavaScript, loads directly.
bash
git clone https://github.com/levelsio/superlevels.git
cd superlevels
  1. 打开Chrome →
    chrome://extensions/
  2. 开启开发者模式(右上角开关)
  3. 点击加载已解压的扩展程序 → 选择
    superlevels
    文件夹
  4. 🚀图标会出现在你的工具栏中
无需构建步骤——纯JavaScript,直接加载。

Project Structure

项目结构

superlevels/
├── manifest.json          # Extension manifest (permissions, content scripts)
├── popup.html             # Main popup UI
├── popup.js               # Popup logic and feature coordination
├── background.js          # Service worker (tab events, redirects, storage)
├── content.js             # Injected into pages (dark mode, CSS, GDPR, etc.)
├── features/              # Individual feature modules (if separated)
├── icons/                 # Extension icons
└── demo.gif               # Demo animation
superlevels/
├── manifest.json          # 扩展清单(权限、内容脚本)
├── popup.html             # 主弹窗UI
├── popup.js               # 弹窗逻辑与功能协调
├── background.js          # 服务工作线程(标签页事件、重定向、存储)
├── content.js             # 注入页面的脚本(深色模式、CSS、GDPR等)
├── features/              # 独立功能模块(如有拆分)
├── icons/                 # 扩展图标
└── demo.gif               # 演示动画

manifest.json Key Patterns

manifest.json核心配置

json
{
  "manifest_version": 3,
  "name": "SuperLevels",
  "version": "1.0",
  "permissions": [
    "tabs",
    "cookies",
    "storage",
    "scripting",
    "webNavigation",
    "activeTab"
  ],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icons/icon48.png"
  }
}
json
{
  "manifest_version": 3,
  "name": "SuperLevels",
  "version": "1.0",
  "permissions": [
    "tabs",
    "cookies",
    "storage",
    "scripting",
    "webNavigation",
    "activeTab"
  ],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icons/icon48.png"
  }
}

Storage Pattern (All Features)

存储模式(全功能通用)

SuperLevels uses
chrome.storage.local
exclusively — no external storage:
javascript
// Save a setting
async function saveSetting(key, value) {
  await chrome.storage.local.set({ [key]: value });
}

// Load a setting with default
async function loadSetting(key, defaultValue) {
  const result = await chrome.storage.local.get([key]);
  return result[key] !== undefined ? result[key] : defaultValue;
}

// Per-domain settings pattern
async function saveDomainSetting(feature, domain, value) {
  const storageKey = `${feature}_${domain}`;
  await chrome.storage.local.set({ [storageKey]: value });
}

async function loadDomainSetting(feature, domain, defaultValue) {
  const storageKey = `${feature}_${domain}`;
  const result = await chrome.storage.local.get([storageKey]);
  return result[storageKey] !== undefined ? result[storageKey] : defaultValue;
}
SuperLevels仅使用
chrome.storage.local
——无外部存储:
javascript
// 保存设置
async function saveSetting(key, value) {
  await chrome.storage.local.set({ [key]: value });
}

// 加载带默认值的设置
async function loadSetting(key, defaultValue) {
  const result = await chrome.storage.local.get([key]);
  return result[key] !== undefined ? result[key] : defaultValue;
}

// 按域名存储设置的模式
async function saveDomainSetting(feature, domain, value) {
  const storageKey = `${feature}_${domain}`;
  await chrome.storage.local.set({ [storageKey]: value });
}

async function loadDomainSetting(feature, domain, defaultValue) {
  const storageKey = `${feature}_${domain}`;
  const result = await chrome.storage.local.get([storageKey]);
  return result[storageKey] !== undefined ? result[storageKey] : defaultValue;
}

Feature: Tab Cleaner

功能:标签页清理器

javascript
// background.js — track tab activity
const tabLastActive = {};

chrome.tabs.onActivated.addListener(({ tabId }) => {
  tabLastActive[tabId] = Date.now();
});

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
  if (changeInfo.status === 'complete') {
    tabLastActive[tabId] = Date.now();
  }
});

async function cleanInactiveTabs() {
  const settings = await chrome.storage.local.get(['tabTimeout', 'excludedHosts']);
  const timeoutMs = (settings.tabTimeout || 5) * 60 * 1000;
  const excludedHosts = settings.excludedHosts || [];

  const tabs = await chrome.tabs.query({});
  const now = Date.now();

  for (const tab of tabs) {
    if (tab.active || tab.pinned) continue;

    const tabHost = new URL(tab.url).hostname;
    if (excludedHosts.some(h => tabHost.includes(h))) continue;

    const lastActive = tabLastActive[tab.id] || tab.lastAccessed || 0;
    if (now - lastActive > timeoutMs) {
      // Save to recently closed before removing
      await saveRecentlyClosed(tab);
      chrome.tabs.remove(tab.id);
    }
  }
}

async function saveRecentlyClosed(tab) {
  const { recentlyClosed = [] } = await chrome.storage.local.get(['recentlyClosed']);
  recentlyClosed.unshift({ url: tab.url, title: tab.title, closedAt: Date.now() });
  const trimmed = recentlyClosed.slice(0, 20); // keep last 20
  await chrome.storage.local.set({ recentlyClosed: trimmed });
}

// Run cleaner on interval
setInterval(cleanInactiveTabs, 60 * 1000);
javascript
// background.js — 追踪标签页活动
const tabLastActive = {};

chrome.tabs.onActivated.addListener(({ tabId }) => {
  tabLastActive[tabId] = Date.now();
});

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
  if (changeInfo.status === 'complete') {
    tabLastActive[tabId] = Date.now();
  }
});

async function cleanInactiveTabs() {
  const settings = await chrome.storage.local.get(['tabTimeout', 'excludedHosts']);
  const timeoutMs = (settings.tabTimeout || 5) * 60 * 1000;
  const excludedHosts = settings.excludedHosts || [];

  const tabs = await chrome.tabs.query({});
  const now = Date.now();

  for (const tab of tabs) {
    if (tab.active || tab.pinned) continue;

    const tabHost = new URL(tab.url).hostname;
    if (excludedHosts.some(h => tabHost.includes(h))) continue;

    const lastActive = tabLastActive[tab.id] || tab.lastAccessed || 0;
    if (now - lastActive > timeoutMs) {
      // 删除前保存到最近关闭列表
      await saveRecentlyClosed(tab);
      chrome.tabs.remove(tab.id);
    }
  }
}

async function saveRecentlyClosed(tab) {
  const { recentlyClosed = [] } = await chrome.storage.local.get(['recentlyClosed']);
  recentlyClosed.unshift({ url: tab.url, title: tab.title, closedAt: Date.now() });
  const trimmed = recentlyClosed.slice(0, 20); // 保留最近20条
  await chrome.storage.local.set({ recentlyClosed: trimmed });
}

// 定时运行清理器
setInterval(cleanInactiveTabs, 60 * 1000);

Feature: Dark Mode (Content Script)

功能:深色模式(内容脚本)

javascript
// content.js — dark mode via CSS filter
function applyDarkMode(brightness = 90) {
  let style = document.getElementById('superlevels-darkmode');
  if (!style) {
    style = document.createElement('style');
    style.id = 'superlevels-darkmode';
    document.head.appendChild(style);
  }
  style.textContent = `
    html {
      filter: invert(1) hue-rotate(180deg) brightness(${brightness}%) !important;
    }
    img, video, canvas, iframe, svg, picture {
      filter: invert(1) hue-rotate(180deg) !important;
    }
  `;
}

function removeDarkMode() {
  const style = document.getElementById('superlevels-darkmode');
  if (style) style.remove();
}

// Listen for messages from popup
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.action === 'setDarkMode') {
    if (msg.enabled) {
      applyDarkMode(msg.brightness || 90);
    } else {
      removeDarkMode();
    }
    sendResponse({ ok: true });
  }
});

// Auto-apply on load if enabled for this domain
(async () => {
  const domain = location.hostname;
  const { [`darkmode_${domain}`]: enabled, [`darkmode_brightness_${domain}`]: brightness }
    = await chrome.storage.local.get([`darkmode_${domain}`, `darkmode_brightness_${domain}`]);
  if (enabled) applyDarkMode(brightness || 90);
})();
javascript
// content.js — 通过CSS滤镜实现深色模式
function applyDarkMode(brightness = 90) {
  let style = document.getElementById('superlevels-darkmode');
  if (!style) {
    style = document.createElement('style');
    style.id = 'superlevels-darkmode';
    document.head.appendChild(style);
  }
  style.textContent = `
    html {
      filter: invert(1) hue-rotate(180deg) brightness(${brightness}%) !important;
    }
    img, video, canvas, iframe, svg, picture {
      filter: invert(1) hue-rotate(180deg) !important;
    }
  `;
}

function removeDarkMode() {
  const style = document.getElementById('superlevels-darkmode');
  if (style) style.remove();
}

// 监听来自弹窗的消息
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.action === 'setDarkMode') {
    if (msg.enabled) {
      applyDarkMode(msg.brightness || 90);
    } else {
      removeDarkMode();
    }
    sendResponse({ ok: true });
  }
});

// 页面加载时如果当前域名已启用则自动应用
(async () => {
  const domain = location.hostname;
  const { [`darkmode_${domain}`]: enabled, [`darkmode_brightness_${domain}`]: brightness }
    = await chrome.storage.local.get([`darkmode_${domain}`, `darkmode_brightness_${domain}`]);
  if (enabled) applyDarkMode(brightness || 90);
})();

Feature: Live CSS Editor

功能:实时CSS编辑器

javascript
// content.js — inject and update custom CSS
function applyCustomCSS(css) {
  let style = document.getElementById('superlevels-custom-css');
  if (!style) {
    style = document.createElement('style');
    style.id = 'superlevels-custom-css';
    document.head.appendChild(style);
  }
  style.textContent = css;
}

// popup.js — save and send CSS as user types
const cssTextarea = document.getElementById('css-editor');
const domain = new URL((await chrome.tabs.query({ active: true, currentWindow: true }))[0].url).hostname;

cssTextarea.addEventListener('input', async () => {
  const css = cssTextarea.value;
  await chrome.storage.local.set({ [`css_${domain}`]: css });

  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: (css) => {
      let style = document.getElementById('superlevels-custom-css');
      if (!style) {
        style = document.createElement('style');
        style.id = 'superlevels-custom-css';
        document.head.appendChild(style);
      }
      style.textContent = css;
    },
    args: [css]
  });
});

// Handle Tab key for indentation
cssTextarea.addEventListener('keydown', (e) => {
  if (e.key === 'Tab') {
    e.preventDefault();
    const start = cssTextarea.selectionStart;
    const end = cssTextarea.selectionEnd;
    cssTextarea.value = cssTextarea.value.substring(0, start) + '  ' + cssTextarea.value.substring(end);
    cssTextarea.selectionStart = cssTextarea.selectionEnd = start + 2;
  }
});
javascript
// content.js — 注入并更新自定义CSS
function applyCustomCSS(css) {
  let style = document.getElementById('superlevels-custom-css');
  if (!style) {
    style = document.createElement('style');
    style.id = 'superlevels-custom-css';
    document.head.appendChild(style);
  }
  style.textContent = css;
}

// popup.js — 用户输入时保存并发送CSS
const cssTextarea = document.getElementById('css-editor');
const domain = new URL((await chrome.tabs.query({ active: true, currentWindow: true }))[0].url).hostname;

cssTextarea.addEventListener('input', async () => {
  const css = cssTextarea.value;
  await chrome.storage.local.set({ [`css_${domain}`]: css });

  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: (css) => {
      let style = document.getElementById('superlevels-custom-css');
      if (!style) {
        style = document.createElement('style');
        style.id = 'superlevels-custom-css';
        document.head.appendChild(style);
      }
      style.textContent = css;
    },
    args: [css]
  });
});

// 处理Tab键缩进
cssTextarea.addEventListener('keydown', (e) => {
  if (e.key === 'Tab') {
    e.preventDefault();
    const start = cssTextarea.selectionStart;
    const end = cssTextarea.selectionEnd;
    cssTextarea.value = cssTextarea.value.substring(0, start) + '  ' + cssTextarea.value.substring(end);
    cssTextarea.selectionStart = cssTextarea.selectionEnd = start + 2;
  }
});

Feature: Music Recognizer (ACRCloud)

功能:音乐识别器(ACRCloud)

Requires your own ACRCloud API credentials — sign up free at https://www.acrcloud.com/sign-up/
javascript
// popup.js — capture tab audio and identify
async function recognizeMusic() {
  const settings = await chrome.storage.local.get(['acrcloud_host', 'acrcloud_key', 'acrcloud_secret']);

  if (!settings.acrcloud_host || !settings.acrcloud_key || !settings.acrcloud_secret) {
    showError('Add your ACRCloud API credentials in settings first.');
    return;
  }

  // Capture audio from current tab (10 seconds)
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  const stream = await chrome.tabCapture.capture({ audio: true, video: false });

  const audioContext = new AudioContext();
  const source = audioContext.createMediaStreamSource(stream);
  const processor = audioContext.createScriptProcessor(4096, 1, 1);
  const chunks = [];

  processor.onaudioprocess = (e) => {
    chunks.push(new Float32Array(e.inputBuffer.getChannelData(0)));
  };

  source.connect(processor);
  processor.connect(audioContext.destination);

  await new Promise(resolve => setTimeout(resolve, 10000)); // record 10s

  stream.getTracks().forEach(t => t.stop());
  processor.disconnect();

  // Convert to WAV and send to ACRCloud
  const wavBlob = float32ArrayToWav(chunks, audioContext.sampleRate);
  const result = await queryACRCloud(wavBlob, settings);

  // Save to history
  if (result?.metadata?.music?.[0]) {
    const song = result.metadata.music[0];
    const { recognitionHistory = [] } = await chrome.storage.local.get(['recognitionHistory']);
    recognitionHistory.unshift({
      title: song.title,
      artist: song.artists?.[0]?.name,
      album: song.album?.name,
      recognizedAt: Date.now()
    });
    await chrome.storage.local.set({ recognitionHistory: recognitionHistory.slice(0, 50) });
  }
}

async function queryACRCloud(audioBlob, { acrcloud_host, acrcloud_key, acrcloud_secret }) {
  const timestamp = Math.floor(Date.now() / 1000);
  const stringToSign = `POST\n/v1/identify\n${acrcloud_key}\naudio\n1\n${timestamp}`;

  // HMAC-SHA1 signature (use SubtleCrypto)
  const encoder = new TextEncoder();
  const keyData = encoder.encode(acrcloud_secret);
  const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']);
  const signature = btoa(String.fromCharCode(...new Uint8Array(
    await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(stringToSign))
  )));

  const formData = new FormData();
  formData.append('sample', audioBlob, 'sample.wav');
  formData.append('access_key', acrcloud_key);
  formData.append('data_type', 'audio');
  formData.append('signature_version', '1');
  formData.append('signature', signature);
  formData.append('sample_bytes', audioBlob.size);
  formData.append('timestamp', timestamp);

  const response = await fetch(`https://${acrcloud_host}/v1/identify`, {
    method: 'POST',
    body: formData
  });
  return response.json();
}
需要你自己的ACRCloud API凭证——在https://www.acrcloud.com/sign-up/免费注册获取
javascript
// popup.js — 捕获标签页音频并识别
async function recognizeMusic() {
  const settings = await chrome.storage.local.get(['acrcloud_host', 'acrcloud_key', 'acrcloud_secret']);

  if (!settings.acrcloud_host || !settings.acrcloud_key || !settings.acrcloud_secret) {
    showError('请先在设置中添加你的ACRCloud API凭证。');
    return;
  }

  // 捕获当前标签页音频(10秒)
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  const stream = await chrome.tabCapture.capture({ audio: true, video: false });

  const audioContext = new AudioContext();
  const source = audioContext.createMediaStreamSource(stream);
  const processor = audioContext.createScriptProcessor(4096, 1, 1);
  const chunks = [];

  processor.onaudioprocess = (e) => {
    chunks.push(new Float32Array(e.inputBuffer.getChannelData(0)));
  };

  source.connect(processor);
  processor.connect(audioContext.destination);

  await new Promise(resolve => setTimeout(resolve, 10000)); // 录制10秒

  stream.getTracks().forEach(t => t.stop());
  processor.disconnect();

  // 转换为WAV并发送到ACRCloud
  const wavBlob = float32ArrayToWav(chunks, audioContext.sampleRate);
  const result = await queryACRCloud(wavBlob, settings);

  // 保存到历史记录
  if (result?.metadata?.music?.[0]) {
    const song = result.metadata.music[0];
    const { recognitionHistory = [] } = await chrome.storage.local.get(['recognitionHistory']);
    recognitionHistory.unshift({
      title: song.title,
      artist: song.artists?.[0]?.name,
      album: song.album?.name,
      recognizedAt: Date.now()
    });
    await chrome.storage.local.set({ recognitionHistory: recognitionHistory.slice(0, 50) });
  }
}

async function queryACRCloud(audioBlob, { acrcloud_host, acrcloud_key, acrcloud_secret }) {
  const timestamp = Math.floor(Date.now() / 1000);
  const stringToSign = `POST\n/v1/identify\n${acrcloud_key}\naudio\n1\n${timestamp}`;

  // HMAC-SHA1签名(使用SubtleCrypto)
  const encoder = new TextEncoder();
  const keyData = encoder.encode(acrcloud_secret);
  const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']);
  const signature = btoa(String.fromCharCode(...new Uint8Array(
    await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(stringToSign))
  )));

  const formData = new FormData();
  formData.append('sample', audioBlob, 'sample.wav');
  formData.append('access_key', acrcloud_key);
  formData.append('data_type', 'audio');
  formData.append('signature_version', '1');
  formData.append('signature', signature);
  formData.append('sample_bytes', audioBlob.size);
  formData.append('timestamp', timestamp);

  const response = await fetch(`https://${acrcloud_host}/v1/identify`, {
    method: 'POST',
    body: formData
  });
  return response.json();
}

Adding a New Feature

添加新功能

Follow this pattern to add a feature:
javascript
// 1. Add toggle in popup.html
// <div class="feature" id="my-feature">
//   <label>My Feature</label>
//   <input type="checkbox" id="my-feature-toggle">
// </div>

// 2. popup.js — wire up the toggle
const myFeatureToggle = document.getElementById('my-feature-toggle');
const domain = await getCurrentDomain();

// Load saved state
myFeatureToggle.checked = await loadDomainSetting('myfeature', domain, false);

myFeatureToggle.addEventListener('change', async () => {
  const enabled = myFeatureToggle.checked;
  await saveDomainSetting('myfeature', domain, enabled);

  // Send message to content script
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.tabs.sendMessage(tab.id, { action: 'setMyFeature', enabled });
});

// 3. content.js — handle the message
chrome.runtime.onMessage.addListener((msg) => {
  if (msg.action === 'setMyFeature') {
    if (msg.enabled) enableMyFeature();
    else disableMyFeature();
  }
});

// 4. Auto-apply on page load
(async () => {
  const domain = location.hostname;
  const enabled = await loadDomainSetting('myfeature', domain, false);
  if (enabled) enableMyFeature();
})();
遵循以下模式添加功能:
javascript
// 1. 在popup.html中添加开关
// <div class="feature" id="my-feature">
//   <label>我的功能</label>
//   <input type="checkbox" id="my-feature-toggle">
// </div>

// 2. popup.js — 绑定开关事件
const myFeatureToggle = document.getElementById('my-feature-toggle');
const domain = await getCurrentDomain();

// 加载已保存的状态
myFeatureToggle.checked = await loadDomainSetting('myfeature', domain, false);

myFeatureToggle.addEventListener('change', async () => {
  const enabled = myFeatureToggle.checked;
  await saveDomainSetting('myfeature', domain, enabled);

  // 发送消息到内容脚本
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.tabs.sendMessage(tab.id, { action: 'setMyFeature', enabled });
});

// 3. content.js — 处理消息
chrome.runtime.onMessage.addListener((msg) => {
  if (msg.action === 'setMyFeature') {
    if (msg.enabled) enableMyFeature();
    else disableMyFeature();
  }
});

// 4. 页面加载时自动应用
(async () => {
  const domain = location.hostname;
  const enabled = await loadDomainSetting('myfeature', domain, false);
  if (enabled) enableMyFeature();
})();

Feature: GDPR Consent Banner Dismisser

功能:GDPR同意弹窗关闭器

javascript
// content.js — auto-dismiss consent banners
const GDPR_SELECTORS = [
  // OneTrust
  '#onetrust-accept-btn-handler',
  '.onetrust-accept-btn-handler',
  // CookieBot
  '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll',
  // Didomi
  '#didomi-notice-agree-button',
  // Quantcast
  '.qc-cmp2-summary-buttons button:last-child',
  // Generic
  '[id*="cookie"] [id*="accept"]',
  '[class*="cookie-consent"] button',
  '[aria-label*="Accept cookies"]',
  '[aria-label*="accept all"]',
];

const GDPR_HIDE_SELECTORS = [
  '#onetrust-consent-sdk',
  '.cookiebot-widget',
  '#didomi-host',
  '.qc-cmp2-container',
  '[class*="cookie-banner"]',
  '[id*="cookie-banner"]',
  '[class*="gdpr-banner"]',
];

function dismissGDPRBanners() {
  // Click accept buttons
  for (const selector of GDPR_SELECTORS) {
    const btn = document.querySelector(selector);
    if (btn) { btn.click(); break; }
  }

  // Hide banner containers
  for (const selector of GDPR_HIDE_SELECTORS) {
    const el = document.querySelector(selector);
    if (el) el.style.setProperty('display', 'none', 'important');
  }
}

// Run on load and watch for dynamically injected banners
dismissGDPRBanners();
const observer = new MutationObserver(dismissGDPRBanners);
observer.observe(document.body, { childList: true, subtree: true });
javascript
// content.js — 自动关闭同意弹窗
const GDPR_SELECTORS = [
  // OneTrust
  '#onetrust-accept-btn-handler',
  '.onetrust-accept-btn-handler',
  // CookieBot
  '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll',
  // Didomi
  '#didomi-notice-agree-button',
  // Quantcast
  '.qc-cmp2-summary-buttons button:last-child',
  // 通用选择器
  '[id*="cookie"] [id*="accept"]',
  '[class*="cookie-consent"] button',
  '[aria-label*="Accept cookies"]',
  '[aria-label*="accept all"]',
];

const GDPR_HIDE_SELECTORS = [
  '#onetrust-consent-sdk',
  '.cookiebot-widget',
  '#didomi-host',
  '.qc-cmp2-container',
  '[class*="cookie-banner"]',
  '[id*="cookie-banner"]',
  '[class*="gdpr-banner"]',
];

function dismissGDPRBanners() {
  // 点击同意按钮
  for (const selector of GDPR_SELECTORS) {
    const btn = document.querySelector(selector);
    if (btn) { btn.click(); break; }
  }

  // 隐藏弹窗容器
  for (const selector of GDPR_HIDE_SELECTORS) {
    const el = document.querySelector(selector);
    if (el) el.style.setProperty('display', 'none', 'important');
  }
}

// 页面加载时运行,并监听动态注入的弹窗
dismissGDPRBanners();
const observer = new MutationObserver(dismissGDPRBanners);
observer.observe(document.body, { childList: true, subtree: true });

Common Patterns

通用模式

Get Current Tab Domain

获取当前标签页域名

javascript
async function getCurrentDomain() {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  try {
    return new URL(tab.url).hostname;
  } catch {
    return null;
  }
}
javascript
async function getCurrentDomain() {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  try {
    return new URL(tab.url).hostname;
  } catch {
    return null;
  }
}

Send Message to Content Script

发送消息到内容脚本

javascript
async function sendToContentScript(action, data = {}) {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  try {
    return await chrome.tabs.sendMessage(tab.id, { action, ...data });
  } catch (e) {
    // Content script not yet loaded — inject it
    await chrome.scripting.executeScript({
      target: { tabId: tab.id },
      files: ['content.js']
    });
    return chrome.tabs.sendMessage(tab.id, { action, ...data });
  }
}
javascript
async function sendToContentScript(action, data = {}) {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  try {
    return await chrome.tabs.sendMessage(tab.id, { action, ...data });
  } catch (e) {
    // 内容脚本尚未加载 — 注入脚本
    await chrome.scripting.executeScript({
      target: { tabId: tab.id },
      files: ['content.js']
    });
    return chrome.tabs.sendMessage(tab.id, { action, ...data });
  }
}

Reload Tab After Permission Change

权限变更后重新加载标签页

javascript
async function applyAndReload(settingKey, value) {
  await chrome.storage.local.set({ [settingKey]: value });
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.tabs.reload(tab.id);
}
// Used by JS Toggle, since disabling JS requires a content settings reload
javascript
async function applyAndReload(settingKey, value) {
  await chrome.storage.local.set({ [settingKey]: value });
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.tabs.reload(tab.id);
}
// 用于JS开关,因为禁用JS需要重新加载内容设置

Troubleshooting

故障排查

ProblemFix
Extension not appearingCheck Developer mode is on, reload at
chrome://extensions/
Content script not runningVerify
manifest.json
matches
includes the site's URL pattern
Storage not persistingUse
chrome.storage.local
not
localStorage
(unavailable in service workers)
chrome.tabCapture
fails
Music Recognizer needs
tabCapture
permission in manifest and only works on HTTP/HTTPS pages
GDPR dismisser breaking a siteToggle it off per-domain via popup; the site may use a non-standard framework
Dark mode looks wrong on imagesEnsure the double-invert rule targets
img, video, canvas, iframe, svg, picture
chrome.scripting
blocked
Add the target URL's origin to
host_permissions
in manifest
MV3 service worker sleepingMove persistent state to
chrome.storage
not in-memory variables
问题解决方法
扩展未显示检查开发者模式已开启,在
chrome://extensions/
页面重新加载
内容脚本未运行验证
manifest.json
中的
matches
包含该网站的URL模式
存储未持久化使用
chrome.storage.local
而非
localStorage
(服务工作线程中不可用)
chrome.tabCapture
失败
音乐识别器需要在manifest中添加
tabCapture
权限,且仅在HTTP/HTTPS页面生效
GDPR关闭器导致网站异常通过弹窗按域名关闭该功能;该网站可能使用了非标准框架
深色模式下图片显示异常确保双重反转规则覆盖
img, video, canvas, iframe, svg, picture
chrome.scripting
被阻止
在manifest的
host_permissions
中添加目标URL的源
MV3服务工作线程休眠将持久化状态移至
chrome.storage
而非内存变量

Security Audit

安全审计

To audit before using:
bash
undefined
使用前可进行审计:
bash
undefined

Clone and inspect

克隆并检查

Ask your AI tool:

询问你的AI工具:

"Analyze this Chrome extension for security vulnerabilities,

"分析这款Chrome扩展的安全漏洞、恶意软件、间谍软件、数据泄露及可疑行为"

malware, spyware, data exfiltration, and suspicious behavior"


Key things to verify: no `fetch`/`XMLHttpRequest` to unexpected hosts, no `eval()` usage, no external scripts loaded, all storage is `chrome.storage.local` only.

需要验证的关键点:无向未知主机发送`fetch`/`XMLHttpRequest`请求,无`eval()`使用,无加载外部脚本,所有存储仅使用`chrome.storage.local`。