Post

LibreTV:被我归档半年后,又捡回来的影视聚合站

本文由 AIGC 辅助生成

去年在 Linux.do 论坛冲浪的时候,看到有佬友在分享各种采集站的接口资源——就是那些提供影视数据的 API。其实很久之前我就想自己搭一个影视站了,但那时候手头没有服务器,愿望就一直搁着。看到这些免费接口,又赶上 Cloudflare Pages、Vercel 这类平台把”白嫖部署”变得毫无门槛,一个念头冒出来:能不能做一个自己随便部署的个人影视站?

那段时间正好是 AI coding 工具爆发的时候,Linux.do 的佬友们也非常活跃地分享着各种 AI 资源。于是我找来几个现有的同类项目挨个试,总觉得差点意思,最后干脆在其中一个的基础上动手改,改着改着就成了 LibreTV。当时的噱头很简单:“一分钟部署影视站”。

后面就是一段很愉快的开源经历:项目不断迭代,评论区、issue 区一直有网友提供意见、反馈 bug、交流玩法。再后来,社区里一些大佬开发出了 MoonTV 等一堆更好用的衍生项目——人家确实做得更好。加上那阵子我在忙申请学校、准备 APS、考雅思,精力实在顾不过来,就把项目归档了。归档的时候它已经有了 20k+ forks、13k+ stars,也算体面地退场了。

今年 9 月,看到 OpenAI 给开源项目 maintainer 发半年 Pro 的赞助,说实话非常心动,就把 LibreTV 解除归档,准备刷刷活跃度去申请开发者赞助。既然要捡回来,干脆顺手用 Next.js 重构了一遍,现在应该比之前好用不少。更妙的是,如今国产 AI coding agent 层出不穷,qoder、zcode、codebuddy……我天天都能领到鸡蛋(token),总之下课了闲着没事的时候,就开着 agent 修修改改几个陈年老项目,倒是乐趣无穷。

扯完了背景,下面对着现在的版本,把功能和我们部署的事一次讲清楚。


它是怎么工作的

LibreTV 本身不存任何视频,也不提供任何内容。它更像一个”搜索引擎 + 播放器”的组合:

你输入片名后,服务端会同时去请求一批采集站的 API(就是开头说的那类资源站接口),把返回的结果按片名聚合。比如搜”流浪地球”,出来 8 部相关影片、15 条结果,每个结果上会标”3 源”或者”2 源”——意思是这个片在几个采集站有货。同名影片会合并成一张卡片,展开之后每个源列一行,可以直接挑一个播:

聚合搜索结果,同名影片合并并标注来源数

这个”跨源聚合”是我觉得它做得最贴心的地方。同一个片在不同源的清晰度、集数、加载速度差别很大,传统做法是你自己挨个试,而 LibreTV 直接把它们排在一起,还带换源测速——播放卡了就换个源,进度还保留着。

点进播放页是 ArtPlayer + hls.js 的组合,常见的 HLS 直链基本都能吃。播放器支持倍速、快捷键(空格暂停、F 全屏、Alt+左右切集数)、自动连播,移动端还有长按 3 倍速。播放进度和历史存在浏览器本地的 IndexedDB 里,精确到秒,下次打开点一下就能续播——这也是它整个服务无状态、部署起来极省心的原因。

播放页,正在播放流浪地球

除了点播,它还带一个 /live 页面,填个 M3U 订阅就能看 IPTV 直播,支持按分组浏览频道、EPG 节目单,直播流走它自己的长连接代理转发。首页推荐源也可以在豆瓣、Bangumi 新番和影视榜单之间切换,都是服务端直连加缓存,不用配 key。

打开首页时会先要一次访问密码——这是它强制带的访问验证,用来自防红防扫描、防止被有些人举报版权违规,也算是一道简单的门禁:

访问验证


部署:Docker Compose 五分钟搞定

项目推荐用 Docker 部署,官方镜像在 ghcr.io 上,拉下来就能用。整个服务无状态(观看历史在浏览器、配置在 localStorage),不需要挂载任何卷。

1
2
3
4
5
mkdir libretv && cd libretv

# 创建 compose 文件(内容见下)后,设置访问密码并启动
echo "PASSWORD=你的密码" > .env
docker compose pull && docker compose up -d

docker-compose.yml 最简就这么几行:

1
2
3
4
5
6
7
8
9
services:
  libretv:
    image: ghcr.io/librespark/libretv:latest
    container_name: libretv
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - PASSWORD=${PASSWORD:?请在 .env 中设置 PASSWORD}

起来之后访问 http://服务器IP:8080,输入你设的密码就完事了。

几个值得配的环境变量

上面的最小配置已经能用,但有几个可选项建议按需加上:

  • PROXY_SECRET:代理/会话的签名密钥。多实例部署或者后面挂了别的服务,建议显式设置(openssl rand -hex 32 生成一个)。
  • DEFAULT_SOURCES:预置采集站,JSON 数组。部署给自己人用的话,把自己验证过可用的源写进去,用户端默认勾选,省得每个人自己找源。
  • DEFAULT_LIVE_SOURCES:预置直播源(M3U 订阅地址),同样支持带 EPG 节目单。想看 IPTV 的话这个必配。
  • DEFAULT_SUBSCRIPTIONS:订阅一个远程的源列表 JSON,一次下发点播源 + 直播源,源更新了改远端一份文件就行。
  • 60S_API_BASE:影视榜单推荐用的 60s API 实例地址,官方公共实例有限流,自部署一个更稳。
  • LIVE_ALLOW_PRIVATE=1:直播源在内网时必须开这个,否则会被 SSRF 防护拦掉(我之前那篇内网邮件服务器的场景就用得上)。

搜索行为也有几个可调的:SEARCH_MAX_PAGES 控制每个源最多抓几页,SEARCH_SOURCE_TIMEOUT_MS 是单个源的总超时。默认值对个人用足够了,源加得多再考虑调。

反向代理与 HTTPS

直接裸 HTTP + IP 也能用,但既然是长期挂着的站,还是建议套个域名加反代。我自己用 1Panel 里的 OpenResty 反代到 127.0.0.1:8080,再加一份证书就完事了,具体步骤和之前那篇邮件服务器里的反代部分差不多。

有一个细节值得说:LibreTV 的 Cookie Secure 策略是按请求协议自动推导的——HTTPS 访问自动加 Secure,HTTP 则不加,所以本地调试和线上 HTTPS 之间不需要手动切换。真遇到特殊场景也可以用 COOKIE_SECURE 强制指定。

另外别忘了它有个登录门,公网上记得把密码设复杂一点;不想暴露公网的话,放进内网 + 防火墙白名单即可。

不想用 Docker

它是个标准的 Next.js 15 项目(App Router + TypeScript + Tailwind),Node 22 环境下源码跑起来也很直接:

1
2
3
4
5
git clone https://github.com/LibreSpark/LibreTV.git
cd LibreTV
npm install
npm run build
PASSWORD=你的密码 npm start   # 默认监听 8080

不过没有 Docker 那么省心,进程守护、开机自启都得自己料理,服务器上我还是更推荐容器。(当然你也可以试试 Vercel、Cloudflare Pages、Edgeone、Netlify 和 Render,毕竟我不知道 LibreTV 符不符合人家平台规则)


最后

这次重构之后,代码结构比老版本清晰挺多,Next.js 的服务端路由也把之前一堆散落的函数调用收敛得体面了些。仓库在这:LibreSpark/LibreTV,AGPL-3.0 开源;文档在官网 wiki,部署、配置、数据源、直播都有单独的页面;README 里还挂着一个演示站,想先体验再部署的可以直接去看。

欢迎来提 issue 和 PR——毕竟赞助申请的活跃度指标还指着它(笑)。也再次感谢 Linux.do 的佬友们,独乐乐不如众乐乐。

照例提醒一句:LibreTV 只是聚合搜索和播放的工具,视频内容全部来自第三方采集站,版权状况它管不了也不背锅,自己部署自己心里要有数。

本文由 AIGC 辅助生成。

This post is licensed under CC BY 4.0 by the author.