sanzhiniao

把 某TV 的 DRM 直播流解密后,以标准 HLS 格式提供给任意播放器(VLC / IINA / mpv / PotPlayer 等)。

Docker 一条命令

不带代理

docker run -d --name sanzhiniao --restart=always -p 15678:15678 iptvtop/sanzhiniao

带 HTTP 代理(环境变量方式)

docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  -e UTV_PROXY=http://host.docker.internal:7890 iptvtop/sanzhiniao

带 HTTP 代理(命令行参数方式)

docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  iptvtop/sanzhiniao --proxy http://192.168.1.10:7890

带 SOCKS5 代理

docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  -e UTV_PROXY=socks5://host.docker.internal:1080 iptvtop/sanzhiniao
docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  iptvtop/sanzhiniao --proxy socks5://192.168.1.10:1080
host.docker.internal 是 Docker Desktop / 新版 Docker Engine 里指向宿主机的地址,Mac 与 Windows 通用。

代理需要认证怎么办

如果代理服务器开启了账号密码认证,直接使用上面的命令会报错:

{
  "error": "https://m-epg.cmishow.com:1443/...: Provided proxy credentials are incorrect"
}

意思是代理返回了 401/407(Proxy Authentication Required),要求在代理地址里带上用户名密码。

带认证的 HTTP 代理:

docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  iptvtop/sanzhiniao --proxy http://用户名:密码@192.168.1.10:7890

带认证的 SOCKS5 代理:

docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  iptvtop/sanzhiniao --proxy socks5://用户名:密码@192.168.1.10:1080

环境变量写法同理:

docker run -d --name sanzhiniao --restart=always -p 15678:15678 \
  -e UTV_PROXY=http://用户名:密码@192.168.1.10:7890 iptvtop/sanzhiniao

注意事项:

  • 用户名或密码里有 @、:、/、% 等特殊字符时,需要做 URL 编码,例如 @ → %40、: → %3A、/ → %2F、% → %25。
  • 先确认代理是否真的开了认证:在宿主机执行 curl -x http://192.168.1.10:7890 -I https://m-epg.cmishow.com:1443/,如果返回 407 Proxy Authentication Required,就是代理要求认证;如果 curl 能通而容器报错,多半是容器访问不到该代理地址。
  • Clash / mihomo 默认的 mixed 端口(如 7890)一般不要求认证;如果你自己加了 authentication: [user:pass] 配置,就必须用带凭据的写法。

docker-compose

services:
  sanzhiniao:
    image: iptvtop/sanzhiniao:latest
    container_name: sanzhiniao
    restart: always
    ports:
      - "15678:15678"
    environment:
      # 留空 = 直连;按需改成你的代理地址
      UTV_PROXY: ""
      # UTV_PROXY: "http://host.docker.internal:7890"
      # UTV_PROXY: "socks5://host.docker.internal:1080"
      # 代理需要认证时:
      # UTV_PROXY: "http://用户名:密码@host.docker.internal:7890"
    # 需要更多启动参数时用 command 覆盖(会替换默认 CMD):
    # command: ["--proxy", "socks5://host.docker.internal:1080", "--channel-cache", "600"]

启动:

docker compose up -d

使用

启动后打开:

http://<主机IP>:15678/playlist.m3u

播放器里添加这个地址即可。也可以单独播放某个频道:

http://<主机IP>:15678/play/<频道ID>.m3u8

频道 ID 可以从 /playlist.m3u 里的播放地址看到。

启动参数

参数默认值说明
--host0.0.0.0监听地址(容器内必须用 0.0.0.0)
--port15678监听端口
--groups本地,migu要输出的频道分组,逗号分隔
--proxy无代理地址,支持 http://、socks4://、socks4a://、socks5://
--api-modeautoauto / adb / direct;容器内无 adb,实际等效 direct
--channel-cache600频道列表 / 详情 / playurl 链接缓存秒数
--playlist-cache0上游 m3u8 内容缓存秒数(0 = 每次实时拉取)

环境变量:

变量说明
UTV_PROXY等效 --proxy,未显式传 --proxy 时生效

缓存策略

  • 频道列表、频道详情、playurl 链接:内存缓存 600s
  • 上游 m3u8 内容:默认不缓存,每次 /play 实时拉取
  • 分片 URL 映射:保留 MEDIA-SEQUENCE - 20 之后的滑动窗口,不缓存 ts 内容
  • 重启后缓存清空

代理域名清单(Clash / Surge 规则用)

服务端(容器内)实际发起请求的域名只有两类,走 UTV_PROXY 指定的代理:

域名用途协议
m-epg.cmishow.com频道列表 / 详情 / 播放地址 APIHTTPS(端口 1443)
gslb.cdn.hk.chinamobile.comm3u8 与 TS 分片HTTP

Clash 规则(把这两条放到代理策略前面):

rules:
  - DOMAIN-SUFFIX,cmishow.com,PROXY
  - DOMAIN-SUFFIX,cdn.hk.chinamobile.com,PROXY

播放器侧还会直接访问以下资源(不经过容器,由你的播放器请求;如播放器也走 Clash,可一并加规则):

域名用途
epg.zsdc.eu.org节目单 EPG(播放列表 x-tvg-url)
cdn.jsdelivr.net固定头部的注意事项 logo 与占位媒体流
pic-hwcdn.utvlive.top频道 logo

Clash 规则示例:

rules:
  # 服务端流量(容器内代理)
  - DOMAIN-SUFFIX,cmishow.com,PROXY
  - DOMAIN-SUFFIX,cdn.hk.chinamobile.com,PROXY
  # 播放器侧资源(按需)
  - DOMAIN,epg.zsdc.eu.org,DIRECT
  - DOMAIN-SUFFIX,jsdelivr.net,DIRECT
  - DOMAIN-SUFFIX,utvlive.top,DIRECT
  - MATCH,PROXY
说明:CDN 的 m3u8/ts 是明文 HTTP,如果你的 Clash 开了“仅代理加密流量”之类的规则,需要确保 cdn.hk.chinamobile.com 也命中代理或直连策略,视你的网络环境选择。

标签: none