diff --git a/.gitea/workflows/workflow.yaml b/.gitea/workflows/workflow.yaml index 774bb95..96be952 100644 --- a/.gitea/workflows/workflow.yaml +++ b/.gitea/workflows/workflow.yaml @@ -2,13 +2,13 @@ name: 构建扩展程序 on: push: - branches: [ main ] + branches: [ main, dev ] pull_request: - branches: [ main ] + branches: [ main, dev ] jobs: - build: - name: 构建扩展程序 + build-for-chrome: + name: 构建 Chrome 扩展程序 runs-on: ubuntu-latest steps: @@ -24,31 +24,64 @@ jobs: run: npm install - name: 构建扩展程序 - run: npm run build + run: npm run build:chrome - name: 将构建结果压缩成 ZIP run: |- cd dist - zip -r ../extension-${{ gitea.sha }}.zip ./* + zip -r ../msrmod-chrome.zip ./* cd .. - name: 上传构建工件 uses: actions/upload-artifact@v3 with: - name: extension-${{ gitea.sha }} - path: extension-${{ gitea.sha }}.zip + name: chrome-extension + path: msrmod-chrome.zip - publish: + build-for-firefox: + name: 构建 Firefox 附加组件 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + name: 检出代码 + + - name: 设置 Node.js + uses: actions/setup-node@v3 + with: + node-version: '22' + + - name: 安装依赖 + run: npm install + + - name: 构建扩展程序 + run: npm run build:firefox + + - name: 将构建结果压缩成 ZIP + run: |- + cd dist + zip -r ../msrmod-firefox.zip ./* + cd .. + + - name: 上传构建工件 + uses: actions/upload-artifact@v3 + with: + name: firefox-addon + path: msrmod-firefox.zip + + publish-to-chrome-webstore: name: 发布至 Chrome 应用商店 runs-on: ubuntu-latest - needs: build - if: github.ref == 'refs/heads/main' + needs: build-for-chrome + # 仅在 main 分支上执行发布 + if: gitea.ref == 'refs/heads/main' steps: - name: 下载构建工件 uses: actions/download-artifact@v3 with: - name: extension-${{ gitea.sha }} + name: chrome-extension + path: ./ - name: 设置 Node.js uses: actions/setup-node@v3 @@ -62,8 +95,45 @@ jobs: - name: 上传扩展程序到 Chrome Web Store run: |- chrome-webstore-upload upload \ - --source extension-${{ gitea.sha }}.zip \ + --source msrmod-chrome.zip \ --extension-id kphoaomopljjiofeaigjmbagmbdaamhh \ --client-id ${{ secrets.CI_GOOGLE_CLIENT_ID }} \ --client-secret ${{ secrets.CI_GOOGLE_CLIENT_SECRET }} \ - --refresh-token ${{ secrets.CI_GOOGLE_REFRESH_TOKEN }} \ No newline at end of file + --refresh-token ${{ secrets.CI_GOOGLE_REFRESH_TOKEN }} + + publish-to-firefox-addons: + name: 发布至 Firefox 附加组件库 + runs-on: ubuntu-latest + needs: build-for-firefox + # 仅在 main 分支上执行发布 + if: gitea.ref == 'refs/heads/main' + + steps: + - name: 下载构建工件 + uses: actions/download-artifact@v3 + with: + name: firefox-addon + path: ./ + + - name: 解压工件 + run: |- + unzip msrmod-firefox.zip -d ./dist + + - name: 设置 Node.js + uses: actions/setup-node@v3 + with: + node-version: "22" + + - name: 安装 web-ext 工具 + run: |- + npm install -g web-ext + + - name: 上传附加组件到 Firefox Add-ons + run: |- + web-ext sign \ + --source-dir . \ + --artifacts-dir dist \ + --api-key ${{ secrets.FIREFOX_API_KEY }} \ + --api-secret ${{ secrets.FIREFOX_API_SECRET }} + + \ No newline at end of file diff --git a/README.md b/README.md index 57778cf..158914c 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,14 @@ MSR Mod 是一款用于「塞壬唱片」官网(monster-siren.hypergryph.com)的替代前端(alternate frontend)。安装后访问塞壬官网可自动重定向至扩展(可在偏好设置中关闭),为其提供更现代的用户界面以及强大的音乐播放队列、星标和歌单等管理功能。 +## 开发 & 打包 +- 安装 Node 与 npm(在 22 版本测试通过) +- Clone 本项目至本地 +- `npm run dev:refresh` 以刷新开发用 `dist` 文件夹 +- `npm i` 并进行 `npm run dev` 以开启 Chromium 适用的测试前端 +- 在 Chromium 浏览器中加载 `dist` 文件夹 +- 使用 `npm run build:chrome` 或 `npm run build:firefox` 构建对应浏览器版本的扩展程序或附加组件 + ## 隐私协议 & 版权声明 MSR Mod 仅与特定的服务器进行交互,譬如由鹰角网络设立的后端服务器及媒体资源服务器等。同时,您在 MSR Mod 中的部分行为(包括星标、建立歌单等)可根据情况提交至 MSR Mod 的服务器。这些数据将根据您的特定偏好设置公开或隐藏。MSR Mod 不会主动将您的数据汇报给任何第三方,也将利用行业标准保护您的个人信息不被泄露。 diff --git a/package.json b/package.json index 0e3a2e2..e680d0f 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,17 @@ "type": "module", "scripts": { "dev": "vite", - "build": "npm run prebuild && vue-tsc -b && vite build && cp -r public/* dist/", + "build": "echo 'No platform specified, will build for Chromium.' && npm run build-chrome", + "build:chrome": "npm run prebuild:chrome && vue-tsc -b && vite build && cp -r public/* dist/", + "build:firefox": "npm run prebuild:firefox && vue-tsc -b && vite build && cp -r public/* dist/", "dev:refresh": "vue-tsc -b && vite build && cp -r public/* dist/", "build:watch": "vite build --watch", "preview": "vite preview", "lint": "biome format --write .", "quality-check": "biome ci", "qc": "npm run quality-check", - "prebuild": "node scripts/prebuild.js" + "prebuild:chrome": "node scripts/prebuild-chrome.js", + "prebuild:firefox": "node scripts/prebuild-firefox.js" }, "dependencies": { "@tailwindcss/vite": "^4.1.7", diff --git a/scripts/prebuild.js b/scripts/prebuild-chrome.js similarity index 100% rename from scripts/prebuild.js rename to scripts/prebuild-chrome.js diff --git a/scripts/prebuild-firefox.js b/scripts/prebuild-firefox.js new file mode 100644 index 0000000..8d9fe33 --- /dev/null +++ b/scripts/prebuild-firefox.js @@ -0,0 +1,80 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +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(); + } + + // 移除 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; + } + + // 添加 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'); +} + +// 处理 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'); +} + +// 执行处理 +try { + 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