diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..26c8e89 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,53 @@ +# Dependencies +node_modules/ +.pnpm-store/ + +# Build outputs +.next/ +out/ +dist/ +build/ + +# Cache directories +.cache/ +.parcel-cache/ + +# Environment files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Log files +*.log +logs/ + +# Editor directories and files +.vscode/ +.idea/ +*.swp +*.swo + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# PWA Service Worker files (auto-generated) +public/sw.js +public/workbox-*.js + +# Generated files +src/lib/runtime.ts +manifest.json + +# Test coverage +coverage/ + +# Storybook build outputs +storybook-static/ diff --git a/README.md b/README.md index ef07ab7..50e4326 100644 --- a/README.md +++ b/README.md @@ -188,12 +188,17 @@ 1. **Fork** 本仓库到你的 GitHub 账户。 2. 登陆 [Cloudflare](https://cloudflare.com),点击 **计算(Workers)-> Workers 和 Pages**,点击创建 3. 选择 Pages,导入现有的 Git 存储库,选择 Fork 后的仓库 -4. 构建命令填写 **pnpm install --frozen-lockfile && pnpm run pages:build**,预设框架为无,构建输出目录为 `.vercel/output/static` +4. 构建命令填写 **npm install && npm run pages:build**,预设框架为无,构建输出目录为 `.vercel/output/static` 5. 保持默认设置完成首次部署。进入设置,将兼容性标志设置为 `nodejs_compat` 6. 首次部署完成后进入设置,新增 PASSWORD 密钥(变量和机密下),而后重试部署。 7. 如需自定义 `config.json`,请直接修改 Fork 后仓库中该文件。 8. 每次 Push 到 `main` 分支将自动触发重新构建。 +**⚠️ 重要提示:** +- 确保您的仓库中有 `pnpm-lock.yaml` 文件 +- 如果构建失败,可以尝试使用 **pnpm install --frozen-lockfile && pnpm run pages:build** +- Cloudflare Pages 环境变量建议设置为"加密"类型以提高安全性 + #### D1 支持 0. 完成普通部署并成功访问 @@ -226,6 +231,20 @@ docker run -d \ 访问 `http://服务器IP:3000` 即可使用。(需要在服务器控制台开放 3000 端口) +**⚠️ Windows 用户注意事项:** +```bash +# 如果在 Windows 上使用 Docker Desktop,建议先创建配置目录 +mkdir katelyatv-config + +# 然后使用绝对路径挂载(避免路径问题) +docker run -d \ + --name katelyatv \ + -p 3000:3000 \ + --env PASSWORD=your_secure_password \ + --restart unless-stopped \ + ghcr.io/katelya77/katelyatv:latest +``` + #### 2. 带自定义配置的部署 ```bash @@ -434,20 +453,42 @@ mkdir katelyatv && cd katelyatv # 2. 创建 docker-compose.yml 文件(复制上面的内容) nano docker-compose.yml -# 3. 启动所有服务 +# 3. 检查配置文件语法 +docker compose config + +# 4. 启动所有服务 docker compose up -d -# 4. 查看服务状态 +# 5. 查看服务状态 docker compose ps -# 5. 查看启动日志 +# 6. 查看启动日志 docker compose logs -f -# 6. 首次访问 http://your-server:3000 +# 7. 等待服务完全启动(通常需要 30-60 秒) +# 检查健康状态 +docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" + +# 8. 首次访问 http://your-server:3000 # 使用管理员账号 admin / admin_super_secure_password 登录 # 然后访问 /admin 进行管理员配置 ``` +**🔍 部署验证步骤:** + +```bash +# 验证 Redis 连接 +docker compose exec katelyatv-redis redis-cli ping +# 应该返回 "PONG" + +# 验证 KatelyaTV 服务 +curl -I http://localhost:3000 +# 应该返回 HTTP 200 状态码 + +# 查看服务启动顺序 +docker compose logs --timestamps | grep "Ready in" +``` + ### 🔄 管理与维护 ```bash @@ -482,6 +523,51 @@ docker compose down -v --remove-orphans 4. **资源监控**:定期检查容器资源使用情况,必要时调整配置 5. **日志管理**:配置日志轮转,避免日志文件过大 +### 🛠️ 常见部署问题排查 + +**问题 1:容器启动失败** +```bash +# 检查容器状态 +docker compose ps + +# 查看详细错误日志 +docker compose logs katelyatv + +# 常见原因:端口被占用、环境变量配置错误、镜像拉取失败 +``` + +**问题 2:Redis 连接失败** +```bash +# 检查 Redis 容器状态 +docker compose exec katelyatv-redis redis-cli ping + +# 检查网络连通性 +docker compose exec katelyatv ping katelyatv-redis + +# 验证环境变量 +docker compose exec katelyatv env | grep REDIS +``` + +**问题 3:Upstash Redis 连接问题** +```bash +# 验证 Upstash 配置 +curl -H "Authorization: Bearer YOUR_TOKEN" YOUR_UPSTASH_URL/ping + +# 检查环境变量格式 +echo $UPSTASH_URL # 应该是 https://xxx.upstash.io +echo $UPSTASH_TOKEN # 应该是长字符串令牌 +``` + +**问题 4:Cloudflare D1 初始化失败** +- 确保在 D1 控制台中正确执行了所有 SQL 语句 +- 检查数据库绑定名称是否为 `DB` +- 验证环境变量 `NEXT_PUBLIC_STORAGE_TYPE=d1` + +**问题 5:Vercel 部署问题** +- 检查环境变量是否正确设置 +- 确保 `config.json` 文件格式正确 +- 查看 Vercel 部署日志中的错误信息 + ## 🔄 自动同步最近更改 建议在 fork 的仓库中启用本仓库自带的 GitHub Actions 自动同步功能(见 `.github/workflows/sync.yml`)。 @@ -490,6 +576,8 @@ docker compose down -v --remove-orphans ## ⚙️ 环境变量 +### 📋 变量说明表 + | 变量 | 说明 | 可选值 | 默认值 | | --------------------------- | ----------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | USERNAME | redis 部署时的管理员账号 | 任意字符串 | (空) | @@ -505,6 +593,21 @@ docker compose down -v --remove-orphans | NEXT_PUBLIC_IMAGE_PROXY | 默认的浏览器端图片代理 | url prefix | (空) | | NEXT_PUBLIC_DOUBAN_PROXY | 默认的浏览器端豆瓣数据代理 | url prefix | (空) | +### 🔧 配置验证 + +**部署后可通过以下方式验证环境变量是否生效:** + +1. **访问服务状态页**:`http://your-domain/api/server-config` +2. **检查管理员面板**:使用管理员账号登录后访问 `/admin` +3. **查看容器日志**: + ```bash + # Docker 单容器 + docker logs katelyatv + + # Docker Compose + docker compose logs katelyatv + ``` + ## 📋 配置说明 所有可自定义项集中在根目录的 `config.json` 中: diff --git a/public/sw.js b/public/sw.js index ebb990a..eae7cb8 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,s={};const c=(c,n)=>(c=new URL(c+".js",n).href,s[c]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=c,e.onload=s,document.head.appendChild(e)}else e=c,importScripts(c),s()}).then(()=>{let e=s[c];if(!e)throw new Error(`Module ${c} didn’t register its module`);return e}));self.define=(n,a)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let t={};const o=e=>c(e,i),u={module:{uri:i},exports:t,require:o};s[i]=Promise.all(n.map(e=>u[e]||o(e))).then(e=>(a(...e),t))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"720e1c5b3ccb46ee5b17b83529c6c9ce"},{url:"/_next/static/chunks/110-242994b03aacf58a.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/154-de4a84fd5b2e0100.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/29-0844689411ca7d55.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/459-e3682af48de73c26.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/51b697cb-f464f3017ac1ea30.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/63-87ec1ced0bf21584.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/682-28f3765b3c021599.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/900-fb094d8873768e88.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/967-217cdcb80ae3beeb.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/_not-found/page-ac328df06cf68f14.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/admin/page-d0def26e413c060d.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/douban/page-2d0023184aa37aff.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/layout-bd0bfbfdb401e15f.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/login/page-fcbddca77bc41b81.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/page-1c3dfeac6b19d4e5.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/play/page-7cd4f72b453741ca.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/search/page-2e4f55fe3c431d81.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/app/warning/page-11cba4cf9332a238.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/c72274ce-06682d6fc8197e6d.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/da9543df-bf6da1a431d8604f.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/framework-6e06c675866dc992.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/main-2fabec0df3918ea4.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/main-app-dbd320e104e1a5dc.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/pages/_app-792b631a362c29e1.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/pages/_error-9fde6601392a2a99.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-17170f1d90853b2d.js",revision:"owcChvMBPcqUgysujuf1h"},{url:"/_next/static/css/23100062f5d4aac0.css",revision:"23100062f5d4aac0"},{url:"/_next/static/css/275ed64cc4367444.css",revision:"275ed64cc4367444"},{url:"/_next/static/css/992fe66234716999.css",revision:"992fe66234716999"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/_next/static/owcChvMBPcqUgysujuf1h/_buildManifest.js",revision:"046380ae5bc74b46b6d5eac3eed65355"},{url:"/_next/static/owcChvMBPcqUgysujuf1h/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/favicon.ico",revision:"c5de6e56c5664adda146825f75ea6ecf"},{url:"/icons/icon-192x192.png",revision:"4a56c090828a1ad254c903c7aec0389d"},{url:"/icons/icon-256x256.png",revision:"f6409eb1a001f754121e3a8281c0319c"},{url:"/icons/icon-384x384.png",revision:"f6efc3e357b9ffdf4e0d8c14b2ed0ac1"},{url:"/icons/icon-512x512.png",revision:"9c008cbbeb6a576fe07bb1284a83f4d2"},{url:"/logo.png",revision:"40de611b143c47c6291c7bdad2c959ca"},{url:"/manifest.json",revision:"7bd3dabc1cfbfe40f09577efca223d31"},{url:"/robots.txt",revision:"e2b2cd8514443456bc6fb9d77b3b1f3e"},{url:"/screenshot1.png",revision:"10572bfcea54dc93ac4c5f7c9057fc98"},{url:"/screenshot2.png",revision:"f815a8990973a221899976867365c239"},{url:"/screenshot3.png",revision:"49709e96345dfeeab1d8083821d4b44e"},{url:"/screenshot4.png",revision:"a76c751e41e37556048a487e4f8b8b1c"},{url:"/wechat.jpg",revision:"d0f601311802667cd6ca5a37dc69bfa7"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:c,state:n})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")}); +if(!self.define){let e,s={};const a=(a,n)=>(a=new URL(a+".js",n).href,s[a]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()}).then(()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e}));self.define=(n,c)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let t={};const r=e=>a(e,i),o={module:{uri:i},exports:t,require:r};s[i]=Promise.all(n.map(e=>o[e]||r(e))).then(e=>(c(...e),t))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"95803b57e88eef065d7509dd2a83fba2"},{url:"/_next/static/J7ayQg7mNrFOgKQuAh0h0/_buildManifest.js",revision:"046380ae5bc74b46b6d5eac3eed65355"},{url:"/_next/static/J7ayQg7mNrFOgKQuAh0h0/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/110-1617e84e1c4bea87.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/154-de4a84fd5b2e0100.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/29-0844689411ca7d55.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/459-e3682af48de73c26.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/51b697cb-f464f3017ac1ea30.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/63-87ec1ced0bf21584.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/682-28f3765b3c021599.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/900-fb094d8873768e88.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/967-217cdcb80ae3beeb.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/_not-found/page-ac328df06cf68f14.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/admin/page-d0def26e413c060d.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/douban/page-2d0023184aa37aff.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/layout-bd0bfbfdb401e15f.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/login/page-fcbddca77bc41b81.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/page-1c3dfeac6b19d4e5.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/play/page-7cd4f72b453741ca.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/search/page-2e4f55fe3c431d81.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/app/warning/page-11cba4cf9332a238.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/c72274ce-06682d6fc8197e6d.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/da9543df-bf6da1a431d8604f.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/framework-6e06c675866dc992.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/main-2fabec0df3918ea4.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/main-app-dbd320e104e1a5dc.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/pages/_app-792b631a362c29e1.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/pages/_error-9fde6601392a2a99.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-17170f1d90853b2d.js",revision:"J7ayQg7mNrFOgKQuAh0h0"},{url:"/_next/static/css/0578cc219b4d0116.css",revision:"0578cc219b4d0116"},{url:"/_next/static/css/23100062f5d4aac0.css",revision:"23100062f5d4aac0"},{url:"/_next/static/css/275ed64cc4367444.css",revision:"275ed64cc4367444"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/favicon.ico",revision:"c5de6e56c5664adda146825f75ea6ecf"},{url:"/icons/icon-192x192.png",revision:"4a56c090828a1ad254c903c7aec0389d"},{url:"/icons/icon-256x256.png",revision:"f6409eb1a001f754121e3a8281c0319c"},{url:"/icons/icon-384x384.png",revision:"f6efc3e357b9ffdf4e0d8c14b2ed0ac1"},{url:"/icons/icon-512x512.png",revision:"9c008cbbeb6a576fe07bb1284a83f4d2"},{url:"/logo.png",revision:"40de611b143c47c6291c7bdad2c959ca"},{url:"/manifest.json",revision:"7bd3dabc1cfbfe40f09577efca223d31"},{url:"/robots.txt",revision:"e2b2cd8514443456bc6fb9d77b3b1f3e"},{url:"/screenshot1.png",revision:"10572bfcea54dc93ac4c5f7c9057fc98"},{url:"/screenshot2.png",revision:"f815a8990973a221899976867365c239"},{url:"/screenshot3.png",revision:"49709e96345dfeeab1d8083821d4b44e"},{url:"/screenshot4.png",revision:"a76c751e41e37556048a487e4f8b8b1c"},{url:"/wechat.jpg",revision:"d0f601311802667cd6ca5a37dc69bfa7"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:a,state:n})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")}); diff --git a/scripts/version-manager.js b/scripts/version-manager.js index b63f1a5..8ddd885 100644 --- a/scripts/version-manager.js +++ b/scripts/version-manager.js @@ -1,5 +1,7 @@ #!/usr/bin/env node +/* eslint-disable @typescript-eslint/no-var-requires, no-console, unused-imports/no-unused-vars */ + /** * MoonTV 版本管理脚本 * 用于自动化版本号更新、CHANGELOG 生成和发布管理 @@ -13,7 +15,7 @@ const { execSync } = require('child_process'); const PACKAGE_JSON = path.join(__dirname, '../package.json'); const VERSION_TXT = path.join(__dirname, '../VERSION.txt'); const CHANGELOG_MD = path.join(__dirname, '../CHANGELOG.md'); -const README_MD = path.join(__dirname, '../README.md'); +const _README_MD = path.join(__dirname, '../README.md'); // 版本类型 const VERSION_TYPES = { diff --git a/src/components/PageLayout.tsx b/src/components/PageLayout.tsx index 85113e4..cb5c932 100644 --- a/src/components/PageLayout.tsx +++ b/src/components/PageLayout.tsx @@ -163,65 +163,62 @@ const TopNavbar = ({ activePath = '/' }: { activePath?: string }) => { const PageLayout = ({ children, activePath = '/' }: PageLayoutProps) => { return ( -
+
{/* 移动端头部 */} - {/* 桌面端顶部导航栏 - 保持固定在顶部 */} + {/* 桌面端顶部导航栏 - 直接放在最外层,确保 sticky 生效 */}
- {/* 主要布局容器 - 确保可滚动 */} -
- {/* 主内容区域 */} -
- {/* 桌面端左上角返回按钮 */} - {['/play'].includes(activePath) && ( -
- -
- )} + {/* 主内容区域 - 移除 overflow-auto,让整个页面可滚动 */} +
+ {/* 桌面端左上角返回按钮 */} + {['/play'].includes(activePath) && ( +
+ +
+ )} - {/* 主内容容器 - 为播放页面使用特殊布局(83.33%宽度),其他页面使用默认布局(66.67%宽度) */} -
- {/* 使用flex布局实现宽度控制 */} -
- {/* 左侧留白区域 - 播放页面占8.33%,其他页面占16.67% */} -
+ {/* 主内容容器 - 为播放页面使用特殊布局(83.33%宽度),其他页面使用默认布局(66.67%宽度) */} +
+ {/* 使用flex布局实现宽度控制 */} +
+ {/* 左侧留白区域 - 播放页面占8.33%,其他页面占16.67% */} +
- {/* 主内容区 - 播放页面占83.33%,其他页面占66.67% */} + {/* 主内容区 - 播放页面占83.33%,其他页面占66.67% */} +
-
- {children} -
+ {children}
- - {/* 右侧留白区域 - 播放页面占8.33%,其他页面占16.67% */} -
-
-
+ + {/* 右侧留白区域 - 播放页面占8.33%,其他页面占16.67% */} +
+
+
{/* 移动端底部导航 */}