Files
StudyDiary/02-学习笔记/NAS媒体刮削TMDB接口访问问题完整排查+落地文档.md

14 KiB
Raw Permalink Blame History

NAS媒体刮削TMDB接口访问问题完整排查+落地文档

NAS 媒体刮削 TMDB 接口访问问题完整排查 + 落地文档

文档来源:本次全部对话记录整理,包含:故障现象、完整排错过程、根因分析、两套可落地解决方案、配置模板、验证命令、故障清单 环境:MacOS Clash Verge Rev、群晖 NAS(Mihomo+Hysteria2 正常)、飞牛 fnOS(Docker 部署 MoviePilot、tinyMediaManager)

目录

  1. 故障现象汇总

  2. 前期网络排错全过程(curl、TLS、Hysteria2 排查)

  3. 根因分析

  4. 方案一【主方案|推荐日常使用】飞牛容器复用群晖 Mihomo 代理

  5. 方案二【备用兜底方案】Cloudflare Worker TMDB 中转(鉴权 + 缓存,无需代理)

  6. 两套方案切换规则

  7. 统一故障排查清单

  8. 附录:测试命令、参考脚本


1. 故障现象汇总

1.1 网络侧现象

  1. MacOS 客户端:Clash Verge Rev(Mihomo 内核),Hysteria2 节点,访问api.themoviedb.org正常,TMDB 接口可访问。

  2. 群晖 NAS:部署 Mihomo,同一份 config.yaml、相同内核版本,Hysteria2 节点正常,MoviePilot、TinyMediaManager 媒体刮削,TMDB 接口调用全部正常。

  3. 飞牛 fnOS:

    • 飞牛系统无系统级全局代理;

    • 飞牛 Docker 内部署 Mihomo,订阅同样 Hysteria2 节点,节点列表加载成功,但所有 Hysteria2 节点 TLS 握手失败,SSL_ERROR_SYSCALL;

    • 在飞牛上部署 MoviePilot、tinyMediaManager,调用 TMDB API 接口全部超时失败,无法刮削媒体元数据。

测试现象:curl 访问https://api.themoviedb.org,TLS 握手卡在 Client Hello 后直接断开,报错:curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL。

1.2 测试过程关键现象

  1. 裸网直接访问api.themoviedb.org:443:TCP 能建立连接,TLS 握手中断,SNI 被网络拦截。

  2. 使用本地 SOCKS5 代理(7890),未使用--socks5-hostname:本地解析域名,拿到污染 IP,握手失败;使用--socks5-hostname,域名交由代理远端解析。

  3. Hysteria2 依赖 UDP QUIC 协议;飞牛 fnOS 的 OVS 虚拟交换机 + 家庭路由器会拦截 UDP 出站,导致 HY2 QUIC 握手超时。

  4. 飞牛 Docker 容器不会自动继承宿主机的代理,容器内程序(MoviePilot/TMM)不会自动走宿主机 Mihomo。


2. 前期网络排错全过程记录

2.1 基础 curl 裸网测试

# 测试80端口HTTP
curl -v api.themoviedb.org
# HTTPS裸网测试,TLS握手失败
curl -v https://api.themoviedb.org

现象:TCP 连接成功,发送 TLS Client Hello 之后直接断开,报错 SSL_ERROR_SYSCALL。

尝试指定 TLS 版本--tls-max 1.2,依旧握手失败。

2.2 SOCKS 代理测试(本地 7890 端口)

# 错误:本地解析域名
curl -v --socks5 127.0.0.1:7890 https://api.themoviedb.org
# 正确:远端域名解析(socks5h)
curl -v --socks5-hostname 127.0.0.1:7890 https://api.themoviedb.org
# 验证代理出口IP
curl -v --socks5-hostname 127.0.0.1:7890 https://ifconfig.me

结论:--socks5 是本地解析域名,容易拿到污染 IP;--socks5-hostname 将域名解析交给远端代理服务器,规避 DNS 污染。

2.3 协议选型评估:mieru /anytls/hysteria2

协议 特点 本次环境适配性
Hysteria2 QUIC/UDP,速度好;强依赖 UDP 出站 Mac / 群晖正常;飞牛 fnOS 受 OVS、路由器 UDP 拦截,无法稳定运行
AnyTLS TCP 隧道,不依赖 UDP;存在内层 TLS1.3 报文被篡改风险 UDP 不通场景备选,稳定性弱于 HY2
Mieru TCP 隧道,抗干扰;同样 TCP 底层,TLS1.3 握手存在概率异常 备选

结论:飞牛环境不适合本地部署 Hysteria2,放弃在飞牛本机跑代理。

2.4 Mihomo 日志排查方法(飞牛 Docker)

  1. 修改 Mihomo 配置,开启 debug 日志
log-level: debug
external-controller: 127.0.0.1:9090
  1. 查看容器实时日志
# 查看容器名
docker ps | grep mihomo
# 实时跟踪日志
docker logs -f --tail 100 mihomo
# 导出日志到文件
docker logs mihomo > mihomo-debug.log
  1. 关键词识别
  • quic: connection timed out → UDP 出站被拦截(本次核心问题)

  • unsupported proxy type: hysteria2 → Mihomo 内核版本过低

  • tls: certificate verify failed → 需要skip-cert-verify: true

验证连通性(飞牛容器内 curl 测试)

docker exec -it moviepilot curl -v --socks5-hostname 群晖IP:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDBKEY

3. 根因分析

  1. 飞牛 fnOS 自带 OVS 虚拟交换机,会拦截 UDP 数据包;家庭路由器 / 光猫也会限制 UDP 出站,Hysteria2(QUIC/UDP)无法正常建立隧道。

  2. 飞牛 Docker 容器隔离:容器内程序不会自动复用宿主机代理,MoviePilot、TMM 裸网访问 TMDB,遭遇 DNS 污染 + SNI 阻断。

  3. Mac、群晖网络环境 UDP 不受限,所以同样配置、同样节点可以正常工作。

最终方案思路:不再在飞牛部署 Mihomo 代理,采用双冗余架构: ✅ 主方案:飞牛容器内 MoviePilot/TMM 直接复用群晖 Mihomo 的 SOCKS5 代理 ✅ 备用方案:CF Worker 中转 TMDB API,完全不需要代理,群晖 / 代理故障时兜底刮削。


4. 方案一【主方案|推荐日常使用】飞牛容器复用群晖 Mihomo 代理

4.1 群晖 Mihomo 前置配置(必须)

群晖 Mihomo config.yaml 关键配置,允许局域网访问

mixed-port: 7890
allow-lan: true
listen-address: 0.0.0.0
ipv6: false

要求:群晖防火墙放行 7890 端口;飞牛与群晖在同一局域网,无跨 VLAN 隔离。

4.2 MoviePilot docker-compose.yml(飞牛 fnOS)

修改:192.168.1.100 替换为群晖内网 IP;修改 volume 路径为飞牛实际路径

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
      # socks5h = 远端域名解析,规避DNS污染
      - PROXY_HOST=socks5h://192.168.1.100:7890
      # Github资源加速,解决插件下载失败
      - GITHUB_PROXY=https://mirror.ghproxy.com/
    network_mode: bridge

MoviePilot WebUI 配置

  • TMDB 地址保持官方默认,PROXY_HOST 已由环境变量注入,无需重复填写

  • 填入你的 TMDB API Key

启动命令:docker-compose up -d

4.3 TinyMediaManager (TMM) docker-compose.yml(飞牛 fnOS)

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

TMM WebUI 代理配置(推荐优先使用网页内配置,比环境变量更稳定)

  • Proxy type: SOCKS5

  • Host:群晖内网 IP

  • Port:7890

  • ✅ 勾选:Resolve hostnames remotely(远端域名解析,等价 socks5h)

4.4 连通验证命令

docker exec -it moviepilot curl -v --socks5-hostname 192.168.1.100:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDB密钥

返回 JSON 代表链路正常。


5. 方案二【备用兜底方案】Cloudflare Worker TMDB 中转(鉴权 + 缓存,无需代理)

适用场景:群晖关机、代理节点失效、UDP 链路彻底不可用。仅接管 TMDB 接口,Github、豆瓣等其他外网 API 仍然需要代理。 免费限制:CF Worker 免费版每日 10 万次请求,日常刮削完全够用。

5.1 主中转 Worker 脚本(鉴权 + 缓存)

登录 Cloudflare 后台 → Workers & Pages → 创建 Worker,清空原有代码粘贴下面代码

export default {
  async fetch(request, env) {
    // ========== 自定义你的访问密钥,自行修改 ==========
    const ACCESS_SECRET = "自定义随机密钥";
    // 缓存有效期,单位秒:3600=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;
    }
    // POST等其他请求直接透传,不缓存
    return await fetch(newReq);
  }
}

保存部署,得到 worker 域名,示例 tmdb-proxy.xxx.workers.dev

5.2 缓存清理三种方案

  1. 单影片临时绕过缓存(最简单) 请求地址末尾追加:&_nocache=随机数字 示例: https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=xxx&_nocache=20260925

  2. 全局一键清空全部缓存(批量重刷媒体库) 修改 Worker 代码任意一行,重新部署;CF 所有边缘节点缓存自动全部失效。

  3. 精准单条缓存删除(进阶 Purge Worker) 新建独立 Worker(tmdb-purge),粘贴下面代码,密钥和主 Worker 保持一致

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 });
    }
    // 替换为你的主worker域名
    const cacheUrl = new URL(`https://tmdb-proxy.xxx.workers.dev${targetPath}`);
    const cacheReq = new Request(cacheUrl);
    const cache = caches.default;
    await cache.delete(cacheReq);
    return new Response(`Purged: ${cacheUrl.toString()}`);
  }
}

调用示例:

curl -v -H "X-Tmdb-Secret: 自定义随机密钥" "https://tmdb-purge.xxx.workers.dev/?path=/3/movie/550?api_key=你的TMDBKEY"

5.3 MoviePilot 切换 CF Worker 配置

  1. 清空 PROXY_HOST(关闭代理)

  2. TMDB API 地址:https://tmdb-proxy.xxx.workers.dev/3

  3. 自定义请求头添加一行: X-Tmdb-Secret: 自定义随机密钥

  4. 保留原有 TMDB API Key

5.4 TMM 切换 CF Worker 配置

  1. TMDB API URL 替换为 worker 地址 https://tmdb-proxy.xxx.workers.dev/3

  2. Custom HTTP Headers 添加:X-Tmdb-Secret: 自定义随机密钥

  3. 关闭 TMM 内部代理设置

5.5 curl 测试命令

curl -v -H "X-Tmdb-Secret: 自定义随机密钥" "https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=你的TMDBKEY"

返回 JSON 即为正常。


6. 两套方案切换规则

方案 适用场景 优点 缺点
复用群晖 Mihomo(主方案) 日常长期使用,群晖保持开机 全覆盖 TMDB/Github/ 豆瓣,无额度限制,速度稳定 依赖群晖在线,群晖关机则刮削失效
CF Worker 中转(备用) 群晖关机、代理节点故障、UDP 被拦截 零代理依赖,不受 UDP/OVS 限制,自带缓存加速 仅 TMDB 接口生效,CF 免费版有每日额度上限

使用策略:日常使用主方案;代理故障 / 群晖关机,临时切换到 CF Worker 兜底刮削。


7. 统一故障排查清单

  1. ❌ 容器内不要填写127.0.0.1作为代理地址,容器内 [127.0.0.1](127.0.0.1) 指向容器自身,必须填写群晖内网 IP。

  2. ✅ 群晖 Mihomo 必须开启allow-lan: true,监听地址0.0.0.0,否则飞牛无法访问 7890 端口。

  3. ✅ 飞牛环境关闭 IPv6,规避 TLS 握手异常。

  4. ❌ 放弃飞牛本地部署 Hysteria2,OVS + 路由器 UDP 拦截属于硬限制。

  5. ✅ MoviePilot/TMM 优先使用软件原生内置代理配置,优于ALL_PROXY环境变量。

  6. 测试链路优先使用--socks5-hostname,远端解析域名,规避 DNS 污染。

  7. 代理测试失败优先查看 Mihomo debug 日志,定位是 UDP 超时、证书错误还是鉴权错误。


8. 附录:常用命令汇总

# 查看docker容器
docker ps | grep mihomo
docker ps | grep moviepilot
# 实时查看mihomo日志
docker logs -f --tail 100 mihomo
# 进入moviepilot容器curl测试代理连通
docker exec -it moviepilot curl -v --socks5-hostname 群晖IP:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDBKEY
# 测试CF Worker中转
curl -v -H "X-Tmdb-Secret: 自定义密钥" "https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=你的TMDBKEY"

如果你想要,我可以再输出 Markdown 纯文本版本(不带任何 canvas 标签,直接复制到 Typora/Obsidian/ 语雀保存)。你要 Markdown 版本吗?

(注:部分内容可能由 AI 生成)