# NAS(群晖\+飞牛)MoviePilot/TMM TMDB刮削 终极稳定技术方案 ## 一、问题背景与核心故障根源 ### 1\.1 设备环境差异 - **群晖NAS**:Mihomo代理正常、Hysteria2节点正常、UDP链路通畅、全局代理生效,MoviePilot/TMM刮削全部正常。 - **飞牛fnOS**:无系统全局代理、OVS虚拟交换机拦截UDP、Hysteria2(QUIC/UDP)链路大面积失效,导致所有TMDB API请求超时/握手失败,媒体刮削完全不可用。 ### 1\.2 核心技术故障定论 本次故障**不是节点、密钥、TLS版本、DNS污染问题**,是环境硬限制: - TMDB CloudFront 强制仅支持 **TLS1\.3**; - 传统TCP隧道(Vmess/Vless/AnyTLS/Mieru)存在内层TLS1\.3报文损坏缺陷; - 唯一稳定的Hysteria2(QUIC/UDP)协议,被飞牛fnOS OVS/路由器UDP拦截; - 飞牛Docker容器**不会自动继承宿主机代理**,裸网访问TMDB必然失败。 **结论**:飞牛无法本地稳定运行HY2代理,放弃飞牛本地代理,采用「双方案冗余架构」解决刮削问题。 ## 二、整体架构设计(双冗余方案) **主方案(长期日常使用)**:飞牛容器复用群晖Mihomo代理(全接口覆盖) **备方案(断代理兜底)**:Cloudflare Worker带鉴权\+缓存TMDB中转(无需任何代理、纯裸网可用) 两套方案可随时切换,彻底解决飞牛TMDB刮削不稳定问题。 ## 三、主方案:飞牛复用群晖Mihomo代理(推荐默认启用) ### 3\.1 前置必备条件(必须配置) 群晖Mihomo **config\.yaml** 核心配置(允许局域网访问): ```yaml mixed-port: 7890 allow-lan: true listen-address: 0.0.0.0 ipv6: false ``` 群晖防火墙放行 **7890端口**,飞牛与群晖处于同一局域网、无跨VLAN隔离。 ### 3\.2 MoviePilot 完整部署配置 飞牛docker\-compose\.yml,直接复用群晖SOCKS5代理,自动解决TMDB/Github/豆瓣全部外网请求。 ```yaml version: "3.8" services: moviepilot: image: jxxghp/moviepilot:latest container_name: moviepilot restart: unless-stopped ports: - "3000:3000" volumes: - /volume1/moviepilot:/app/config environment: - TZ=Asia/Shanghai # 核心代理配置:远端解析域名,规避DNS污染 - PROXY_HOST=socks5h://192.168.1.100:7890 # Github加速,解决插件/资源下载失败 - GITHUB_PROXY=https://mirror.ghproxy.com/ network_mode: bridge ``` ⚠️ 替换:`192.168.1.100` 为你的**群晖真实内网IP**,目录按需修改。 ### 3\.3 MoviePilot 网页端配置 - 无需修改TMDB接口地址,保持官方默认 - PROXY\_HOST已由环境变量注入,无需重复填写 - 正常填写TMDB API Key即可 ### 3\.4 TinyMediaManager\(TMM\) 部署配置 ```yaml version: "3.8" services: tinymediamanager: image: tinymediamanager/tinymediamanager:latest container_name: tinymediamanager restart: unless-stopped ports: - "4000:4000" volumes: - /volume1/tmm:/config environment: - TZ=Asia/Shanghai - ALL_PROXY=socks5h://192.168.1.100:7890 - NO_PROXY=127.0.0.1,localhost,192.168.0.0/16 network_mode: bridge ``` ### 3\.5 TMM 网页端代理配置(优先推荐) - Proxy type: SOCKS5 - Host: 群晖内网IP - Port: 7890 - 开启:Resolve hostnames remotely(远端域名解析,等价socks5h) ### 3\.6 连通性验证命令(飞牛SSH执行) ```bash docker exec -it moviepilot curl -v --socks5-hostname 192.168.1.100:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDB密钥 ``` 返回JSON即为代理通路正常。 ## 四、备方案:CF Worker 鉴权\+缓存 TMDB 中转(无代理兜底) **适用场景**:群晖关机、代理节点故障、飞牛UDP彻底不通,**零代理依赖**完成TMDB刮削。 **核心优势**:TCP链路传输、不受UDP/OVS限制、带密码防盗刷、自带缓存提速、节省TMDB/CF额度。 ### 4\.1 主中转Worker代码(鉴权\+缓存) 新建Worker,清空默认代码,粘贴如下完整版: ```javascript export default { async fetch(request, env) { // 自定义你的访问密钥 const ACCESS_SECRET = "自定义随机密钥"; // 缓存有效期1小时,可改为600(10分钟)/86400(24小时) const CACHE_TTL = 3600; const auth = request.headers.get("X-Tmdb-Secret"); if (!auth || auth !== ACCESS_SECRET) { return new Response("Access Denied", { status: 403 }); } const targetHost = "api.themoviedb.org"; const url = new URL(request.url); url.hostname = targetHost; const newReq = new Request(url, request); newReq.headers.set("Host", targetHost); // GET请求缓存加速 if (request.method === "GET") { const cacheKey = new Request(newReq.url, newReq); const cache = caches.default; let response = await cache.match(cacheKey); if (!response) { response = await fetch(newReq); response = new Response(response.body, response); response.headers.set("Cache-Control", `s-maxage=${CACHE_TTL}`); await cache.put(cacheKey, response.clone()); } return response; } return await fetch(newReq); } } ``` ### 4\.2 缓存清理方案(三种方式) #### 方式1:临时绕过缓存(单影片刷新,最简单) 链接后追加参数:`&_nocache=随机数字` #### 方式2:全局一键清缓存(批量重刷库) 修改任意一行Worker代码并重新部署,CF边缘节点缓存**全部自动清空**。 #### 方式3:精准单条缓存删除(进阶) 单独部署purge清理Worker,支持指定路径删除缓存(文档末尾附代码)。 ### 4\.3 MoviePilot 切换Worker配置 - 清空 **PROXY\_HOST**(关闭代理) - TMDB API地址:`https://你的worker域名.workers.dev/3` - 自定义请求头新增:`X-Tmdb-Secret: 你的自定义密钥` - 保留原有TMDB Key ### 4\.4 TMM 切换Worker配置 - TMDB API URL 替换为Worker地址 - Custom HTTP Headers 添加 `X-Tmdb-Secret: 你的密钥` - 关闭软件内代理设置 ### 4\.5 缓存清理Purge Worker代码(精准删除单条缓存) ```javascript export default { async fetch(request, env) { const ACCESS_SECRET = "和主Worker一致的密钥"; const auth = request.headers.get("X-Tmdb-Secret"); if (!auth || auth !== ACCESS_SECRET) { return new Response("Access Denied", { status: 403 }); } const url = new URL(request.url); const targetPath = url.searchParams.get("path"); if (!targetPath) { return new Response("Missing ?path=/3/movie/550", { status: 400 }); } const cacheUrl = new URL(`https://你的主worker域名.workers.dev${targetPath}`); const cacheReq = new Request(cacheUrl); const cache = caches.default; await cache.delete(cacheReq); return new Response(`Purged: ${cacheUrl.toString()}`); } } ``` ## 五、两套方案取舍标准 |方案|适用场景|优点|缺点| |---|---|---|---| |群晖代理复用(主)|日常长期使用、群晖开机|全覆盖(TMDB/Github/豆瓣)、无额度限制、速度稳定|依赖群晖在线| |CF Worker中转(备)|群晖关机、代理故障、UDP拦截|零代理依赖、抗网络污染、自带缓存加速|仅覆盖TMDB、有每日免费额度| ## 六、通用排坑清单(飞牛专属) 1. **禁止使用127\.0\.0\.1**:容器内回环地址指向自身,必须填写群晖内网IP 2. **必须开启allow\-lan: true**:群晖Mihomo禁止仅监听127\.0\.0\.1 3. **飞牛关闭IPv6**:规避隧道TLS1\.3握手异常 4. **放弃飞牛本地HY2**:fnOS OVS\+路由器UDP拦截为硬故障,无法修复 5. **优先软件内置代理**:MoviePilot/TMM原生代理优于系统环境变量代理 ## 七、最终落地规范 - 日常默认:**群晖Mihomo代理复用方案** - 故障兜底:**CF Worker鉴权缓存中转方案** - 永久废弃:飞牛本地Hysteria2代理、TCP隧道(AnyTLS/Mieru/Vmess) > (注:部分内容可能由 AI 生成)