Blog

给个人站加一个影视板块

nextjsmoontvplusdeploymentinfra

给个人站加一个影视板块

本站在 /tv 路径下集成了一个完整的影视搜索和播放系统,基于 MoonTVPlus 二次开发。

架构概览

整个 TV 板块是独立运行的 Next.js 应用,通过主站的 proxy 路由嵌入:

用户访问 /tv
  → 主站 iframe(src="/tv-proxy")
    → 主站 rewrite /api/ → /tv-proxy/api/
      → proxy route (/tv-proxy/[[...path]]/route.ts)
        → http://localhost:3002 (MoonTVPlus)

这样设计的理由:MoonTVPlus 自身的 /api/* 路径在主站下会冲突,通过 rewrite 把所有 TV 相关的 API 请求转发到 MoonTVPlus 的实际端口。

项目结构

D:\MyWeb\
├── moontv\              ← MoonTVPlus (Next.js 14, 端口 3002)
│   ├── src\             ← 源码
│   ├── .env.local       ← 环境变量
│   └── .data\moontv.db  ← SQLite 数据库
├── infinite-canvas\     ← 主站 (Next.js 16, 端口 3000)
│   ├── next.config.ts   ← rewrite 和 redirect 规则
│   └── src\app\tv\      ← TV iframe 页面
└── danmu_api\           ← 弹幕服务 (端口 9321)

集成要点

1. Rewrite 规则

主站的 next.config.ts 配置了 24 条 rewrite 规则,覆盖 MoonTVPlus 的所有 API 路径:

rewrites: [
  { source: "/api/login", destination: "/tv-proxy/api/login" },
  { source: "/api/search/:path", destination: "/tv-proxy/api/search/:path" },
  { source: "/api/danmaku/:path", destination: "/tv-proxy/api/danmaku/:path" },
  { source: "/api/image-proxy", destination: "/tv-proxy/api/image-proxy" },
  // ... 共 24 条
]

2. Proxy Route

主站新增一个 catch-all 路由来处理代理转发:

/tv-proxy/[[...path]]/route.ts

收到请求后直接 fetch 到 MoonTVPlus 的对应路径,把响应透传给浏览器。

3. iframe 页面

/tv 页面是一个简单的 iframe,指向 /tv-proxy。iframe 的好处是两个应用完全隔离——MoonTVPlus 的样式、路由、状态都不会影响主站。

视频源配置

MoonTVPlus 本身是空壳,不内置任何视频源。通过环境变量订阅 LunaTV 的配置:

CONFIG_SUBSCRIPTION_URL=https://pz.v88.qzz.io?format=2&source=jingjian

这个订阅地址 Base58 编码了 61 个视频源(普通 + 成人),通过管理后台拉取后,所有源就可以搜索了。源数据每日更新。

源有了之后还需要根据实际测速调整权重。用了几部热门电影测试后,把表现最好的源(红牛资源、豪华资源、速播资源)权重调高,被墙或不可用的源(爱奇艺)排除掉。

弹幕服务

MoonTVPlus 的弹幕功能依赖独立的弹幕 API 后端。内置的 Netlify 服务在国内被墙,所以自建了一个:

git clone https://github.com/huangxd-/danmu_api.git
cd danmu_api && npm install

服务启动后在 http://localhost:9321,从腾讯视频、爱奇艺、B站等国内平台实时获取弹幕数据。集成到 start-server.bat 里随网站一起启动。

几个坑

登录重定向:MoonTVPlus 的 basePath 是 /tv-proxy,登录后默认跳转到 /(主站根目录)。需要修改源码中的重定向逻辑,从当前路径推导正确的 basePath。

图片代理:视频源的封面图来自各种 CDN(tu.iqiyizyimg.compps.vodfeiss.com 等),很多在国内无法直接访问。通过 MoonTVPlus 的 /api/image-proxy 路由做服务器中转,所有外部图片走服务器代理加载。

PWA 图标:MoonTVPlus 的 manifest.json 引用 /icons/icon-192x192.png,但文件只存在于 MoonTVPlus 的 public/ 目录下。需要在主站加一条 rewrite 把 /icons/* 代理过去。

弹幕中间件拦截/api/image-proxy 请求会被 MoonTVPlus 的 auth middleware 拦截返回 401,需要把这个路径加到 middleware 的 skip list 里。

Windows 启动脚本.bat 文件必须用 CRLF 换行符,否则 cmd.exe 闪退。这是个花了一小时才发现的坑。

启动流程

现在的启动顺序是:

1. 清理端口(3000、3002、9321)
2. 启动弹幕服务 danmu_api
3. 启动 MoonTVPlus(端口 3002)
4. 启动主站(端口 3000)
5. 启动 frpc 内网穿透

全部集成在一个 start-server.bat 里一键启动。