把多个数据源聚合成一份可以直接交给播放客户端的媒体源: 来源与站点由插件提供,面板负责跨来源搜索、合并线路,对外提供 Emby 兼容接口。
- 来源由插件提供 —— 面板不点名任何插件,也不假设插件内部怎么工作:来源、站点、播放地址 都由插件按约定申报,面板只按动作名取用,不关心插件背后的地址与端口。
- 聚合搜索 —— 一个关键字并发查询多个来源的多个站点,对片名做规范化清洗后按权重打分匹配, 命中与未命中都可查看(含分数与原因)。
- 版本合并 —— 同一部作品在多处的线路,在客户端里表现为多个可选的「版本」,点哪条播哪条。
- Emby 兼容 —— 客户端把面板当作一台 Emby 服务器使用(握手、登录、媒体库、搜索、详情、图片、播放、字幕均已实现)。
- 零依赖 —— 只使用 Node 内置模块(含内置
node:sqlite),没有第三方包,没有构建步骤。
本项目不内置、不分发任何来源或内容。各项来源由用户自行配置,其可用性与合法性由用户判断。
镜像发布在 Docker Hub:dlushu/mediabridge,同时提供 linux/amd64 与 linux/arm64。
# 8088 面板本身(Emby 客户端**不**连它,连的是下面那组实例端口)
# 8090-8100 面板要用的端口段:**Emby 实例从这里起依次 +1**(每台各占一个)
# 装不下就把范围往后加(例如再补一段 -p 8101-8110:8101-8110)
docker run -d --name media-bridge-panel --init --restart unless-stopped \
-p 8088:8088 -p 8090-8100:8090-8100 \
-v media_bridge-data:/data \
-e TZ=Asia/Shanghai \
dlushu/mediabridge:latest等价的 compose 文件:
services:
media-bridge-panel:
image: dlushu/mediabridge:latest
container_name: media-bridge-panel
restart: unless-stopped
init: true
ports:
- "8088:8088" # 面板本身(Emby 客户端不连它)
- "8090-8100:8090-8100" # Emby 实例端口:各自从 8090 起依次 +1
volumes:
- media_bridge-data:/data
environment:
TZ: Asia/Shanghai
APP_REPO: dlushu/MediaBridge
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes:
media_bridge-data:
name: media_bridge-data启动后打开 http://<主机地址>:8088。
镜像里没有应用代码:容器首次启动时会从 GitHub Release 取一份装到数据卷的
/data/app/<版本>/下再运行。默认先经内置的公共 gh 代理取(APP_MIRRORS,见下),取不到再退到官方直连。 之后升级不需要重建容器:在「面板设置 → 关于 → 版本与更新」里手动更新,应用进程会自己重启到新版本。
运行数据与已安装的应用代码都在具名卷
media_bridge-data里(来源、站点勾选、Emby 账号、面板密码、 配置、应用代码)。备份该卷即可完整迁移。不要执行docker compose down -v:-v会一并删除数据卷。
node --version # 需要 ≥ 22.13(内置 sqlite 从该版本起无需开启实验开关)
npm start默认监听 0.0.0.0:8088,运行数据写入项目内的 data/。
| 变量 | 默认 | 说明 |
|---|---|---|
WEB_PORT |
8088 |
面板端口(页面与面板接口)。Emby 客户端不连它,连的是各 Emby 实例的端口 |
WEB_HOST |
0.0.0.0 |
监听地址 |
DATA_DIR |
项目内 data/(镜像内为 /data) |
运行数据目录;应用代码装在它下面的 app/ |
TZ |
跟随系统 | 日志时间(建议 Asia/Shanghai) |
APP_REPO |
dlushu/MediaBridge |
从哪个仓库取应用代码(换成分支/私有镜像源时用) |
APP_VERSION |
未设置 | 固定运行的版本;留空 = 用已装版本,磁盘上没有则取最新 Release |
APP_SOURCE_URL |
未设置 | 版本包地址模板,占位符 {repo} {version} {tag} {name};支持 http(s):// 与本地路径 |
APP_CHECKSUM_URL |
未设置 | .sha256 校验文件地址模板(占位符同上);留空 = 在版本包地址后加 .sha256 |
APP_MIRRORS |
https://gh-proxy.com,https://ghfast.top |
取源镜像前缀(逗号分隔、有序):面板更新与插件库共用,先逐个试这些公共 gh 代理,再退到官方直连。留空 = 用内置默认;置 off / none / - 只走官方直连。显式设了 APP_SOURCE_URL / PLUGIN_INDEX_URL / PLUGIN_SOURCE_URL 时,对应那条不套镜像前缀 |
PLUGIN_REPO |
dlushu/media-bridge-plugins |
插件库仓库(owner/repo)—— 插件从它取清单与包(面板本身不带插件,见 ADR-0035) |
PLUGIN_INDEX_URL |
未设置 | 插件清单地址;留空 = 走 APP_MIRRORS 候选(含镜像),最后兜到上面那个仓库 main 分支根目录的 index.json;设了就是唯一地址、不再套镜像 |
PLUGIN_SOURCE_URL |
未设置 | 插件包地址模板,占位符 {repo} {path} {type} {id} {version};留空 = 走 APP_MIRRORS 候选(含镜像);设了就是唯一地址、不再套镜像;支持 http(s):// 与本地路径 |
PANEL_NOTICE_URL |
未设置 | 「关于」页内嵌公告的取回地址(见 ADR-0068);留空 = 取本仓库 main 分支根目录的 notice.html(走 APP_MIRRORS 候选)。设了就是唯一地址、不再套镜像;置 off / none / - 关闭这张卡 |
例:想自己指定 gh 代理(或换掉内置的),按先后顺序填 APP_MIRRORS;只走官方直连就关掉它:
-e APP_MIRRORS=https://gh-proxy.com,https://your-mirror.example # 逐个试,最后自动退到 github.com
-e APP_MIRRORS=off # 不走任何镜像,只连官方关于校验:走第三方代理时,包体与其校验值(应用代码的
.sha256、插件的 md5)都经代理之手, 校验只能挡住传输损坏,挡不住代理替换(详见 ADR-0067)。
- 登录面板 —— 默认密码
123456;进入后先到「面板设置 → 安全」修改密码。 - 装插件(必做,面板本身不带插件)—— 在侧栏「插件 → 插件库」装所需的插件;装时可勾
「装完就启用」,网络不通时也能在「插件 → 管理」页上传本地
.tar.gz手装。 插件分五类,详见插件分类。 - 配置插件 —— 侧栏按类型分栏,点开某个插件就是它自带的设置页;它要什么就在那儿填 —— 取数凭据、账号、站点地址等,各插件各不相同,一律存在插件自己那儿。
- 配一套模板 —— 在「聚合设置 → 模板」新建(或选中)一套模板,按来源页签勾选参与聚合的站点, 保存后再到「聚合设置 → 域 → 模板」把哪个元数据域用哪套模板指过去;没指的域,其内容搜不到。 匹配策略与线路过滤详见匹配与线路过滤。
- 接入客户端 —— 在「Emby → 实例」页新增实例,在「Emby → 账号」页新建账号,然后在 Emby 客户端「添加服务器」里填该实例的连接地址。详见接入客户端。
不接入客户端也可以先在网页上验证效果:「聚合搜索」搜索片名,结果里每条的「这条的版本」 展示的就是客户端点开该条目时会拿到的东西。
左侧是一棵树:一栏一个父节点(点一下收起 / 展开这一栏),栏里的页挂在它下面。
聚合设置
├ 模板 建 / 删 / 改模板 —— 站点集合 + 打分过滤参数 + 超时与并发;站点按来源分页签勾选
├ 聚合搜索 多来源并发搜索(带打分),每条可查看「这条的版本」
└ 域 → 模板 哪个元数据域用哪套模板
Emby
├ 实例 每台服务器一份:名称 / 端口 / 首页插件 / 连接地址(客户端连的就是这里)
└ 账号 按实例分(先选实例);客户端里显示的服务器名 = 该实例的名称
插件
├ 插件库 从插件仓库里挑插件装 / 更新(面板本身不带插件)
└ 管理 已装的:装 / 卸 / 启停 / 重启 / 动作调用 / 日志;也可上传本地 .tar.gz 手装
元数据 已启用的元数据插件各占一个子项,点开内嵌打开它自己的设置页
片源 已启用的片源插件各占一个子项
首页 已启用的首页插件各占一个子项
输出 已启用的输出插件各占一个子项
字幕 已启用的字幕插件各占一个子项
面板设置
├ 概览 运行环境、面板重启、退出登录
├ 设置 缓存设置、站点测速
├ 备份与还原 导出 / 还原整份数据
├ 安全 修改面板密码、登录态有效期
├ 关于 版本与更新、关于
└ 日志 面板进程的实时日志
「元数据 / 片源 / 首页 / 输出 / 字幕」五栏的子项现算:装好并启用的插件才出现在侧栏,栏里一个插件都没有时整栏不显示。一个包可同时具备多个类型,于是会同时出现在对应的每一栏里。
- 元数据插件 —— 条目详情从哪来。
- 片源插件 —— 去哪儿找片。
- 首页插件 —— 客户端首页那些媒体库行。
- 输出插件 —— 把面板已有的首页 / 聚合能力再转给外部客户端。
- 字幕插件 —— 给版本挂字幕轨、供客户端取用。
一个包可同时具备多个类型,每个类型各带自己那份设置页,于是同一插件会同时出现在侧栏对应的多栏里。
装法:「插件 → 插件库」挑装,可勾「装完就启用」;网络不通时在「插件 → 管理」页上传本地 .tar.gz。
插件仓库地址可用 PLUGIN_REPO / PLUGIN_INDEX_URL / PLUGIN_SOURCE_URL 更换(见环境变量表)。
在「聚合设置 → 模板」的「编辑」卡片里那一排参数:
- 打分设置:分数线(填
0表示不按分数线筛选)、「最多留几条命中」(希望得到几条可用的结果, 不足时按分数继续向后尝试)、「匹配到底」(忽略条数上限,直到凑够或名单结束)。 - 线路过滤:一个正则,只有匹配的线路名才会进入客户端看到的版本列表。
- 新增实例:「Emby → 实例」页点「新增实例」,端口留空即可,后端从
8090起依次 +1。 - 连接地址:在 Emby 客户端「添加服务器」里填该实例的端口(每行给出的就是连接地址)。
填主机就行:客户端自己会补
/emby,实例监听两种前缀都收;哪个客户端连不上,就改成http://<面板地址>:8090/api/emby再试。面板端口8088不再提供客户端协议端点 (只留System/Info/Public垫片),填它会连不上。 - 账号:需先在「Emby → 账号」页(先选实例)中新建。
- 服务器名:客户端内显示的服务器名默认为实例名,可在「Emby → 实例」页的编辑弹窗里改。
- 全新安装不自动建实例:面板装好后「Emby → 实例」是空的,需自行添加一台;
从老版本升级上来的会沿用老的
emby.db生成一条default,不受影响。
面板只列出「可用」的线路:有线路,且定位到了请求的那一集。核对方法:「聚合搜索」搜索片名 → 点击某条的「这条的版本」,可以看到每个来源取回几条线路、哪条定位到了该集;这份内容与客户端拿到的相同。 常见原因是来源里确实没有该集(例如来源只更新到第 210 集),或排在候选前列的条目没有可用线路 —— 后者可在「聚合设置 → 模板」的参数里调大「最多留几条命中」,或启用「匹配到底」。
客户端的关键字走面板自身的搜索;面板里搜不到即确实没有。若网页「聚合搜索」能搜到而客户端搜不到, 通常是「聚合设置 → 模板」里这套模板没勾这个站点,或「片源」栏里那个插件的实例没在运行 (启停在该插件自己的设置页)。
面板对播放一律以 302 跳转到插件提供的直链,不代理流量,因此跳转后的地址必须能被客户端访问
(局域网内通常没有问题)。
面板侧日志若已正常回 200(清单)或 302(直链),说明地址已经交给客户端。
后续失败通常是客户端自身的媒体解析器/嗅探器判不出类型(例如 URL 不带 .m3u8 后缀时
ExoPlayer 系把它当普通文件嗅探)或客户端本身不支持该容器。这类问题取决于具体客户端,
面板只能确保下发的地址与类型标识正确。详情见 ADR-0071。
| 端口 | 用途 |
|---|---|
8088 |
面板本体(页面与面板接口),有密码保护;只额外提供 System/Info/Public 垫片,不是 Emby 客户端要连的端口 |
8090 起 |
Emby 实例端口:新建实例时端口留空,就从 8090 起依次 +1(被占了继续往后找)。Emby 客户端连的是这里,用 Emby 账号鉴权(与面板密码是两套) |
Emby 实例端口要发布给需要连接的客户端(建议一次发布 -p 8090-8100,不够再往后加);
某个插件若自己还需要额外端口,按其说明另行发布。需要外网访问时,只发布 8088 与相应实例端口,
并置于反向代理与 HTTPS 之后。更多细节见 SECURITY.md。
- Docker 部署:数据与应用代码都在具名卷
media_bridge-data内 (docker volume inspect media_bridge-data可查看实际路径),其中应用代码在<卷>/app/<版本>/。 - 备份:面板「面板设置 → 备份与还原 → 导出备份」会打出一个 zip,含整份数据
(设置、模板、插件、Emby 账号与播放进度),不含缓存与应用代码;也可以直接备份上述卷。
⚠️ 备份里含账号密码哈希与插件凭证,请当作私密文件保管。 - 升级:「面板设置 → 关于 → 版本与更新」→ 检查更新 → 更新到新版本。 面板会下载、校验并安装新版本,随后自己重启(容器不停,几秒后页面恢复)。 更新采用完整替换:新版本启动成功后,旧版本目录会被自动清掉,磁盘上只留当前这一版 (决策见 ADR-0021)。
- 回退:本地不留旧版本,所以回退 = 把
APP_VERSION指向要回到的版本再重启容器 —— 引导脚本发现该版本不在磁盘上会重新下载(前提是那个 Release 还在、且这台机器能访问到)。 - 镜像只在"引导逻辑"变化时才需要更新:
docker pull dlushu/mediabridge:latest后重建容器。
- 客户端内显示的服务器名 = 该实例的名称:在面板「Emby → 实例」页里编辑该实例。
- 面板自身的名称:
server/core/branding.js与public/core/branding.js(两处成对)。
- 文档地图:docs/index.md
- 架构与依赖方向:ARCHITECTURE.md
- 设计决策记录:docs/adr/
- 贡献流程与书写规范:CONTRIBUTING.md
- 变更记录:CHANGELOG.md
- 安全策略:SECURITY.md
提交前请运行 npm run check(语法检查与文风检查)。
仓库只包含应用源码;容器定义与镜像构建脚本不属于项目源码,由维护者另行维护。 分发有两条路:Docker Hub 上的运行时镜像(见上文),以及 GitHub Release 上的版本包 —— 容器启动与面板更新装的都是后者,由
.github/workflows/release.yml在推送v<版本>标签时产出。
