superlevels-chrome-extension
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSuperLevels 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- Open Chrome →
chrome://extensions/ - Enable Developer mode (top-right toggle)
- Click Load unpacked → select the folder
superlevels - 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- 打开Chrome →
chrome://extensions/ - 开启开发者模式(右上角开关)
- 点击加载已解压的扩展程序 → 选择文件夹
superlevels - 🚀图标会出现在你的工具栏中
无需构建步骤——纯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 animationsuperlevels/
├── 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 exclusively — no external storage:
chrome.storage.localjavascript
// 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.localjavascript
// 保存设置
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 reloadjavascript
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
故障排查
| Problem | Fix |
|---|---|
| Extension not appearing | Check Developer mode is on, reload at |
| Content script not running | Verify |
| Storage not persisting | Use |
| Music Recognizer needs |
| GDPR dismisser breaking a site | Toggle it off per-domain via popup; the site may use a non-standard framework |
| Dark mode looks wrong on images | Ensure the double-invert rule targets |
| Add the target URL's origin to |
| MV3 service worker sleeping | Move persistent state to |
| 问题 | 解决方法 |
|---|---|
| 扩展未显示 | 检查开发者模式已开启,在 |
| 内容脚本未运行 | 验证 |
| 存储未持久化 | 使用 |
| 音乐识别器需要在manifest中添加 |
| GDPR关闭器导致网站异常 | 通过弹窗按域名关闭该功能;该网站可能使用了非标准框架 |
| 深色模式下图片显示异常 | 确保双重反转规则覆盖 |
| 在manifest的 |
| MV3服务工作线程休眠 | 将持久化状态移至 |
Security Audit
安全审计
To audit before using:
bash
undefined使用前可进行审计:
bash
undefinedClone 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`。