Added detailed docstrings and comments to Python build and dev scripts, improving maintainability and clarity. Enhanced JavaScript files (background.js, content.js, popup.js, platform-detector.js, webext-compat.js) with module-level and function-level documentation. Standardized package naming in build.py and updated the GitHub Actions workflow for simplified, platform-agnostic publishing, removing platform selection input and automating release steps for Chrome, Edge, and Firefox. Improved code quality checks and test coverage in dev.py.
165 lines
4.7 KiB
JavaScript
165 lines
4.7 KiB
JavaScript
/**
|
|
* 平台特定的配置和检测
|
|
*
|
|
* 提供浏览器平台检测和特性识别功能:
|
|
* - 检测当前运行的浏览器类型和版本
|
|
* - 识别 Manifest 版本 (V2/V3)
|
|
* - 检测移动端环境
|
|
* - 识别开发版本
|
|
*/
|
|
|
|
/**
|
|
* 平台检测器
|
|
* 提供浏览器环境检测的核心功能
|
|
*/
|
|
const platformDetector = {
|
|
/**
|
|
* 检测当前浏览器平台
|
|
*
|
|
* @returns {Object} 平台检测结果
|
|
* @property {string} platform - 浏览器类型 (firefox/chrome/edge/opera/safari/unknown)
|
|
* @property {number} version - 浏览器主版本号
|
|
* @property {number} manifestVersion - Manifest 版本号
|
|
* @property {boolean} isMobile - 是否为移动端
|
|
* @property {boolean} isDevBuild - 是否为开发版本
|
|
*/
|
|
detect() {
|
|
const manifest =
|
|
typeof browser !== "undefined" && browser.runtime
|
|
? browser.runtime.getManifest()
|
|
: chrome.runtime.getManifest();
|
|
|
|
const ua = navigator.userAgent;
|
|
const extURL =
|
|
typeof browser !== "undefined" && browser.runtime
|
|
? browser.runtime.getURL("")
|
|
: chrome.runtime.getURL("");
|
|
|
|
let platform = "unknown";
|
|
let version = 0;
|
|
|
|
// 根据扩展 URL 前缀检测浏览器类型
|
|
if (extURL.startsWith("moz-extension://")) {
|
|
platform = "firefox";
|
|
const match = /Firefox\/(\d+)/.exec(ua);
|
|
version = match ? parseInt(match[1], 10) : 115;
|
|
} else if (extURL.startsWith("safari-web-extension://")) {
|
|
platform = "safari";
|
|
const match = /Version\/(\d+)/.exec(ua);
|
|
version = match ? parseInt(match[1], 10) : 15;
|
|
} else if (/\bEdg\/\b/.test(ua)) {
|
|
platform = "edge";
|
|
const match = /Edg\/(\d+)/.exec(ua);
|
|
version = match ? parseInt(match[1], 10) : 120;
|
|
} else if (/\bOPR\/\b/.test(ua)) {
|
|
platform = "opera";
|
|
const match = /OPR\/(\d+)/.exec(ua);
|
|
version = match ? parseInt(match[1], 10) : 120;
|
|
} else {
|
|
platform = "chrome";
|
|
const match = /Chrome\/(\d+)/.exec(ua);
|
|
version = match ? parseInt(match[1], 10) : 120;
|
|
}
|
|
|
|
return {
|
|
platform,
|
|
version,
|
|
manifestVersion: manifest.manifest_version,
|
|
isMobile: /\bMobile\b/.test(ua),
|
|
isDevBuild: /^\d+\.\d+\.\d+\D/.test(manifest.version),
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 获取平台特定的能力
|
|
*/
|
|
getCapabilities(platformInfo = null) {
|
|
const info = platformInfo || this.detect();
|
|
|
|
const capabilities = {
|
|
// 基础能力
|
|
downloads: true,
|
|
storage: true,
|
|
tabs: true,
|
|
|
|
// 高级能力
|
|
declarativeNetRequest: false,
|
|
offscreen: false,
|
|
scripting: false,
|
|
|
|
// 特殊能力
|
|
popupResize: true,
|
|
contextMenus: true,
|
|
notifications: true,
|
|
};
|
|
|
|
// Firefox 特定能力
|
|
if (info.platform === "firefox") {
|
|
capabilities.webRequest = true;
|
|
capabilities.contentSecurityPolicy = false; // 在 Manifest V2 中有限制
|
|
capabilities.popupResize = false; // Firefox 不支持动态调整弹窗大小
|
|
}
|
|
|
|
// Chrome/Chromium 特定能力
|
|
if (
|
|
info.platform === "chrome" ||
|
|
info.platform === "edge" ||
|
|
info.platform === "opera"
|
|
) {
|
|
if (info.manifestVersion === 3) {
|
|
capabilities.declarativeNetRequest = true;
|
|
capabilities.offscreen = info.version >= 109;
|
|
capabilities.scripting = true;
|
|
capabilities.webRequest = false; // MV3 中 webRequest 被限制
|
|
} else {
|
|
capabilities.webRequest = true;
|
|
}
|
|
}
|
|
|
|
// Safari 特定能力
|
|
if (info.platform === "safari") {
|
|
capabilities.notifications = false; // Safari 扩展通知支持有限
|
|
capabilities.contextMenus = false; // Safari 扩展上下文菜单支持有限
|
|
}
|
|
|
|
return capabilities;
|
|
},
|
|
|
|
/**
|
|
* 获取平台特定的限制
|
|
*/
|
|
getLimitations(platformInfo = null) {
|
|
const info = platformInfo || this.detect();
|
|
|
|
const limitations = {
|
|
maxStorageSize: Infinity,
|
|
maxDownloadConcurrency: 10,
|
|
requiresUserGesture: false,
|
|
contentScriptLimitations: [],
|
|
};
|
|
|
|
if (info.platform === "firefox") {
|
|
limitations.maxStorageSize = 5 * 1024 * 1024; // 5MB for local storage
|
|
limitations.contentScriptLimitations = [
|
|
"limited-eval", // eval() 受限
|
|
"no-dynamic-import", // 动态导入受限
|
|
];
|
|
}
|
|
|
|
if (info.platform === "safari") {
|
|
limitations.maxStorageSize = 10 * 1024 * 1024; // 10MB
|
|
limitations.requiresUserGesture = true; // 许多操作需要用户手势
|
|
limitations.maxDownloadConcurrency = 3; // 下载并发限制更严格
|
|
}
|
|
|
|
return limitations;
|
|
},
|
|
};
|
|
|
|
// 导出
|
|
if (typeof module !== "undefined" && module.exports) {
|
|
module.exports = { platformDetector };
|
|
} else {
|
|
window.platformDetector = platformDetector;
|
|
}
|