diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..415eb0a --- /dev/null +++ b/.env.example @@ -0,0 +1,14 @@ +# Debug Configuration +# Set DEBUG environment variable to control debug output +# Examples: +# DEBUG=msr:* # Enable all MSR debug output +# DEBUG=msr:player # Enable only player debug +# DEBUG=msr:store,msr:api # Enable store and API debug +# DEBUG=* # Enable all debug output (including libraries) +# DEBUG= # Disable all debug output + +# Development (default: enable all msr:* debug) +VITE_DEBUG=msr:* + +# Production (default: disabled) +# VITE_DEBUG= \ No newline at end of file diff --git a/public/background.js b/public/background.js index 4b009eb..24e582b 100644 --- a/public/background.js +++ b/public/background.js @@ -1,7 +1,7 @@ -console.log("aaaa") +console.log('aaaa') // 兼容 Chrome 和 Firefox -const browserAPI = typeof browser !== 'undefined' ? browser : chrome; +const browserAPI = typeof browser !== 'undefined' ? browser : chrome browserAPI.webRequest.onBeforeRequest.addListener( async (details) => { @@ -16,12 +16,18 @@ browserAPI.webRequest.onBeforeRequest.addListener( console.log('recived request for fontset api, redirecting to index.html') const pref = await browserAPI.storage.sync.get('preferences') - if (pref === undefined || pref.preferences === undefined || pref.preferences.autoRedirect === undefined || pref.preferences.autoRedirect === true) { - const isChrome = typeof browserAPI.runtime.getBrowserInfo === 'undefined'; + if ( + pref === undefined || + pref.preferences === undefined || + pref.preferences.autoRedirect === undefined || + pref.preferences.autoRedirect === true + ) { + const isChrome = typeof browserAPI.runtime.getBrowserInfo === 'undefined' if (isChrome) { if ( - details.url === 'https://monster-siren.hypergryph.com/manifest.json' && + details.url === + 'https://monster-siren.hypergryph.com/manifest.json' && details.type === 'other' && details.frameId === 0 ) { @@ -32,17 +38,24 @@ browserAPI.webRequest.onBeforeRequest.addListener( } } else { // Firefox: 直接在当前标签页导航 - browserAPI.tabs.update(details.tabId, { url: browserAPI.runtime.getURL('index.html') }) + browserAPI.tabs.update(details.tabId, { + url: browserAPI.runtime.getURL('index.html'), + }) } } }, - { urls: ['https://monster-siren.hypergryph.com/api/fontset', 'https://monster-siren.hypergryph.com/manifest.json'] }, + { + urls: [ + 'https://monster-siren.hypergryph.com/api/fontset', + 'https://monster-siren.hypergryph.com/manifest.json', + ], + }, ) // 兼容新旧版本的 API -const actionAPI = browserAPI.action || browserAPI.browserAction; +const actionAPI = browserAPI.action || browserAPI.browserAction if (actionAPI) { actionAPI.onClicked.addListener(() => { browserAPI.tabs.create({ url: browserAPI.runtime.getURL('index.html') }) }) -} \ No newline at end of file +} diff --git a/public/manifest.json b/public/manifest.json index 0211d94..dc21205 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -5,12 +5,8 @@ "description": "塞壬唱片(Monster Siren Records)官网的替代前端。", "content_scripts": [ { - "matches": [ - "https://monster-siren.hypergryph.com/" - ], - "js": [ - "content.js" - ], + "matches": ["https://monster-siren.hypergryph.com/"], + "js": ["content.js"], "run_at": "document_end" } ], @@ -36,13 +32,9 @@ "background": { "service_worker": "background.js" }, - "permissions": [ - "tabs", - "webRequest", - "storage" - ], + "permissions": ["tabs", "webRequest", "storage"], "content_security_policy": { "extension_pages": "default-src 'self'; script-src 'self' http://localhost:5173; style-src 'self' 'unsafe-inline'; connect-src 'self' ws://localhost:5173 https://monster-siren.hypergryph.com https://web.hycdn.cn https://res01.hycdn.cn; img-src 'self' https://web.hycdn.cn; media-src 'self' https://res01.hycdn.cn;", "sandbox": "sandbox" } -} \ No newline at end of file +} diff --git a/scripts/prebuild-chrome.js b/scripts/prebuild-chrome.js index fe5a3a3..02f0b2f 100644 --- a/scripts/prebuild-chrome.js +++ b/scripts/prebuild-chrome.js @@ -1,61 +1,65 @@ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) // 处理 manifest.json function processManifest() { - const manifestPath = path.join(__dirname, '../public/manifest.json'); - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); - - // 移除本地调试相关的配置 - if (manifest.host_permissions) { - manifest.host_permissions = manifest.host_permissions.filter( - permission => !permission.includes('localhost') - ); - } - - if (manifest.content_security_policy && manifest.content_security_policy.extension_pages) { - // 移除 CSP 中的本地开发相关配置 - manifest.content_security_policy.extension_pages = manifest.content_security_policy.extension_pages - .replace(/script-src 'self' http:\/\/localhost:5173;\s*/g, '') - .replace(/\s*http:\/\/localhost:5173\s*/g, ' ') - .replace(/\s*ws:\/\/localhost:5173\s*/g, ' ') - .replace(/;\s+/g, '; ') // 标准化分号后的空格 - .replace(/\s+/g, ' ') // 合并多个空格为一个 - .trim(); - } - - fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); - console.log('✅ Manifest.json processed'); + const manifestPath = path.join(__dirname, '../public/manifest.json') + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) + + // 移除本地调试相关的配置 + if (manifest.host_permissions) { + manifest.host_permissions = manifest.host_permissions.filter( + (permission) => !permission.includes('localhost'), + ) + } + + if ( + manifest.content_security_policy && + manifest.content_security_policy.extension_pages + ) { + // 移除 CSP 中的本地开发相关配置 + manifest.content_security_policy.extension_pages = + manifest.content_security_policy.extension_pages + .replace(/script-src 'self' http:\/\/localhost:5173;\s*/g, '') + .replace(/\s*http:\/\/localhost:5173\s*/g, ' ') + .replace(/\s*ws:\/\/localhost:5173\s*/g, ' ') + .replace(/;\s+/g, '; ') // 标准化分号后的空格 + .replace(/\s+/g, ' ') // 合并多个空格为一个 + .trim() + } + + fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)) + console.log('✅ Manifest.json processed') } // 处理 index.html function processIndexHtml() { - const indexPath = path.join(__dirname, '../index.html'); - let content = fs.readFileSync(indexPath, 'utf8'); - - // 替换脚本地址 - content = content.replace( - /src="[^"]*\/src\/main\.ts"/g, - 'src="./src/main.ts"' - ); - - // 移除 crossorigin 属性 - content = content.replace(/\s+crossorigin/g, ''); - - fs.writeFileSync(indexPath, content); - console.log('✅ Index.html processed'); + const indexPath = path.join(__dirname, '../index.html') + let content = fs.readFileSync(indexPath, 'utf8') + + // 替换脚本地址 + content = content.replace( + /src="[^"]*\/src\/main\.ts"/g, + 'src="./src/main.ts"', + ) + + // 移除 crossorigin 属性 + content = content.replace(/\s+crossorigin/g, '') + + fs.writeFileSync(indexPath, content) + console.log('✅ Index.html processed') } // 执行处理 try { - processManifest(); - processIndexHtml(); - console.log('🎉 Build preparation completed!'); + processManifest() + processIndexHtml() + console.log('🎉 Build preparation completed!') } catch (error) { - console.error('❌ Error during build preparation:', error); - process.exit(1); -} \ No newline at end of file + console.error('❌ Error during build preparation:', error) + process.exit(1) +} diff --git a/scripts/prebuild-firefox.js b/scripts/prebuild-firefox.js index 8d9fe33..0beddff 100644 --- a/scripts/prebuild-firefox.js +++ b/scripts/prebuild-firefox.js @@ -1,80 +1,87 @@ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) // 处理 manifest.json function processManifest() { - const manifestPath = path.join(__dirname, '../public/manifest.json'); - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + const manifestPath = path.join(__dirname, '../public/manifest.json') + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) - // 移除本地调试相关的配置 - if (manifest.host_permissions) { - manifest.host_permissions = manifest.host_permissions.filter( - permission => !permission.includes('localhost') - ); - } + // 移除本地调试相关的配置 + if (manifest.host_permissions) { + manifest.host_permissions = manifest.host_permissions.filter( + (permission) => !permission.includes('localhost'), + ) + } - if (manifest.content_security_policy && manifest.content_security_policy.extension_pages) { - // 移除 CSP 中的本地开发相关配置 - manifest.content_security_policy.extension_pages = manifest.content_security_policy.extension_pages - .replace(/script-src 'self' http:\/\/localhost:5173;\s*/g, '') - .replace(/\s*http:\/\/localhost:5173\s*/g, ' ') - .replace(/\s*ws:\/\/localhost:5173\s*/g, ' ') - .replace(/;\s+/g, '; ') // 标准化分号后的空格 - .replace(/\s+/g, ' ') // 合并多个空格为一个 - .trim(); - } + if ( + manifest.content_security_policy && + manifest.content_security_policy.extension_pages + ) { + // 移除 CSP 中的本地开发相关配置 + manifest.content_security_policy.extension_pages = + manifest.content_security_policy.extension_pages + .replace(/script-src 'self' http:\/\/localhost:5173;\s*/g, '') + .replace(/\s*http:\/\/localhost:5173\s*/g, ' ') + .replace(/\s*ws:\/\/localhost:5173\s*/g, ' ') + .replace(/;\s+/g, '; ') // 标准化分号后的空格 + .replace(/\s+/g, ' ') // 合并多个空格为一个 + .trim() + } - // 移除 CSP 中的 sandbox 配置(Firefox 不支持) - if (manifest.content_security_policy && manifest.content_security_policy.sandbox) { - delete manifest.content_security_policy.sandbox; - } + // 移除 CSP 中的 sandbox 配置(Firefox 不支持) + if ( + manifest.content_security_policy && + manifest.content_security_policy.sandbox + ) { + delete manifest.content_security_policy.sandbox + } - // 移除 background.service_worker,替换为 background.scripts - if (manifest.background && manifest.background.service_worker) { - manifest.background.scripts = [manifest.background.service_worker]; - delete manifest.background.service_worker; - } + // 移除 background.service_worker,替换为 background.scripts + if (manifest.background && manifest.background.service_worker) { + manifest.background.scripts = [manifest.background.service_worker] + delete manifest.background.service_worker + } - // 添加 firefox 特有配置 - manifest.browser_specific_settings = { - gecko: { - id: 'msr-mod@firefox-addon.astrian.moe', - strict_min_version: '115.0', - } - }; + // 添加 firefox 特有配置 + manifest.browser_specific_settings = { + gecko: { + id: 'msr-mod@firefox-addon.astrian.moe', + strict_min_version: '115.0', + }, + } - fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); - console.log('✅ Manifest.json processed'); + fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)) + console.log('✅ Manifest.json processed') } // 处理 index.html function processIndexHtml() { - const indexPath = path.join(__dirname, '../index.html'); - let content = fs.readFileSync(indexPath, 'utf8'); + const indexPath = path.join(__dirname, '../index.html') + let content = fs.readFileSync(indexPath, 'utf8') - // 替换脚本地址 - content = content.replace( - /src="[^"]*\/src\/main\.ts"/g, - 'src="./src/main.ts"' - ); + // 替换脚本地址 + content = content.replace( + /src="[^"]*\/src\/main\.ts"/g, + 'src="./src/main.ts"', + ) - // 移除 crossorigin 属性 - content = content.replace(/\s+crossorigin/g, ''); + // 移除 crossorigin 属性 + content = content.replace(/\s+crossorigin/g, '') - fs.writeFileSync(indexPath, content); - console.log('✅ Index.html processed'); + fs.writeFileSync(indexPath, content) + console.log('✅ Index.html processed') } // 执行处理 try { - processManifest(); - processIndexHtml(); - console.log('🎉 Build preparation completed!'); + processManifest() + processIndexHtml() + console.log('🎉 Build preparation completed!') } catch (error) { - console.error('❌ Error during build preparation:', error); - process.exit(1); -} \ No newline at end of file + console.error('❌ Error during build preparation:', error) + process.exit(1) +} diff --git a/scripts/prebuild-safari.js b/scripts/prebuild-safari.js index 930e720..6efe7cc 100644 --- a/scripts/prebuild-safari.js +++ b/scripts/prebuild-safari.js @@ -1,55 +1,59 @@ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) // 处理 manifest.json for Safari function processManifest() { - const manifestPath = path.join(__dirname, '../public/manifest.json'); - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + const manifestPath = path.join(__dirname, '../public/manifest.json') + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) - // 移除本地调试相关的配置 - if (manifest.host_permissions) { - manifest.host_permissions = manifest.host_permissions.filter( - permission => !permission.includes('localhost') - ); - } + // 移除本地调试相关的配置 + if (manifest.host_permissions) { + manifest.host_permissions = manifest.host_permissions.filter( + (permission) => !permission.includes('localhost'), + ) + } - if (manifest.content_security_policy && manifest.content_security_policy.extension_pages) { - // 移除 CSP 中的本地开发相关配置 - manifest.content_security_policy.extension_pages = manifest.content_security_policy.extension_pages - .replace(/script-src 'self' http:\/\/localhost:5173;\s*/g, '') - .replace(/\s*http:\/\/localhost:5173\s*/g, ' ') - .replace(/\s*ws:\/\/localhost:5173\s*/g, ' ') - .replace(/;\s+/g, '; ') // 标准化分号后的空格 - .replace(/\s+/g, ' ') // 合并多个空格为一个 - .trim(); - } + if ( + manifest.content_security_policy && + manifest.content_security_policy.extension_pages + ) { + // 移除 CSP 中的本地开发相关配置 + manifest.content_security_policy.extension_pages = + manifest.content_security_policy.extension_pages + .replace(/script-src 'self' http:\/\/localhost:5173;\s*/g, '') + .replace(/\s*http:\/\/localhost:5173\s*/g, ' ') + .replace(/\s*ws:\/\/localhost:5173\s*/g, ' ') + .replace(/;\s+/g, '; ') // 标准化分号后的空格 + .replace(/\s+/g, ' ') // 合并多个空格为一个 + .trim() + } - // Safari 特殊处理:添加 appShell.html 到 content scripts 匹配 - if (manifest.content_scripts && manifest.content_scripts[0]) { - // 添加 appShell.html 的匹配规则 - const existingMatches = manifest.content_scripts[0].matches; - if (!existingMatches.includes("https://monster-siren.hypergryph.com/")) { - existingMatches.push("https://monster-siren.hypergryph.com/"); - } - } + // Safari 特殊处理:添加 appShell.html 到 content scripts 匹配 + if (manifest.content_scripts && manifest.content_scripts[0]) { + // 添加 appShell.html 的匹配规则 + const existingMatches = manifest.content_scripts[0].matches + if (!existingMatches.includes('https://monster-siren.hypergryph.com/')) { + existingMatches.push('https://monster-siren.hypergryph.com/') + } + } - // Safari 特殊处理:使用 background.page 而不是 service_worker - if (manifest.background && manifest.background.service_worker) { - // Safari 扩展在 Manifest V3 中必须使用 persistent: false - // 但为了调试,我们暂时设为 true 来确保页面加载 - manifest.background = { - page: "background.html", - persistent: true - }; - } + // Safari 特殊处理:使用 background.page 而不是 service_worker + if (manifest.background && manifest.background.service_worker) { + // Safari 扩展在 Manifest V3 中必须使用 persistent: false + // 但为了调试,我们暂时设为 true 来确保页面加载 + manifest.background = { + page: 'background.html', + persistent: true, + } + } - // 创建 background.html 文件用于 Safari - const backgroundHtmlPath = path.join(__dirname, '../public/background.html'); - const backgroundHtmlContent = ` + // 创建 background.html 文件用于 Safari + const backgroundHtmlPath = path.join(__dirname, '../public/background.html') + const backgroundHtmlContent = `
@@ -102,19 +106,19 @@ function processManifest() { log('=== After background.js script tag ==='); -`; - fs.writeFileSync(backgroundHtmlPath, backgroundHtmlContent); +