Repository navigation
Releases: dlushu/MediaBridge
Release list
1.9.6
发布说明摘自 CHANGELOG.md 的 1.9.6 一节。
修复
- 封面地址形态判错:整库封面刷 501(1.9.5 引入的回归)。出图那一跳(
Items/{Id}/Images/{type})
把以/开头的地址一律当成"面板自己的中继地址"、补上本机实例 origin,而 tmdb 这类元数据插件
给的封面是图床自己的相对路径(poster_path,如/1CIa….jpg),本该按该域声明的imageBase
拼成https://image.tmdb.org/t/p/w500/…。结果是 302 出了http://实例:8092/1CIa….jpg——
面板自己都不提供这个地址(501),而客户端(实测 Rex)只会在自己的/api/emby/前缀下发请求,
把它改写成/api/emby/1CIa….jpg后同样 501,日志里就是成片的✘ emby 未实现 GET /api/emby/….jpg
(实测那台面板 210/210 条图片 302 全是这种形态)。
现在把"封面地址的形态"收敛成三形态 + 一处判据(ADR-0079):
完整 URL / 面板代取前缀(/api/emby/img/…)/ 图床相对路径;判据只在core/image-url.js一处、
只认那个前缀,写入侧(imageUrlOf)把图床相对路径按imageBase拼成完整地址,出图那一跳遇到
第三种形态如实 404、绝不再补本机 origin(客户端对"没图"有兜底,对"错地址"只会放大成 501)。
旧 tag / 旧索引里的相对路径会变成 404(不出图、也不再刷 501)——按"缓存不是数据"的口径不做迁移,
客户端下次取条目元数据即为新地址。客户端无需改动。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.9.5
发布说明摘自 CHANGELOG.md 的 1.9.5 一节。
新增
- 日志页新增「导出日志」与「系统自检」:导出日志下载带系统运行环境信息(面板版本 / Node 版本 / 平台 / 内存 / 模块清单)的完整日志文本;系统自检检查数据目录可写性、内存状态、模块加载状态、图片索引数据库可写性、缓存数据库目录等关键项。
- 源插件可声明「直绑元数据域条目 Id」(契约
binds):此前因站点搜索精度太差、按名搜必然命中 0
而一直拿不到版本的条目(典型 Pornhub),现在由源插件在plugin.json里声明认领某个元数据域,
面板把该域条目的 entryId 直接交给插件取线路,跳过按名搜索。面板口径:先直绑、拿到可用线路即
不再按名搜;直绑失败自动回落到原有的按名搜(判据 / 分数线 / 条数一律不变),两者只对同一站点
二选一、不双算。要求插件版本已声明binds并(重新)安装或更新,面板才能在运行时看到它;
插件不声明则一切照旧。契约写在插件开发套件仓的contract-source.md,依据见
ADR-0076。 - 需要 Referer 的图床封面可以走「图片代取」:插件把这类封面写成根相对地址
/api/emby/img/{host}/{path}(意思就是"这张图请面板代取"),面板在出图那一跳补一道签名,
客户端照Items/{id}/Images/Primary的 302 取图时,由面板带上 Referer / User-Agent 去取 ——
此前「不带 Referer 一律 403」的那批图床封面恒定空白,现在出得来。插件的头(mbh)与面板签名
(mbm)都在地址里、都被签名保护,这个端点不是开放代理。要求插件版本支持这一形态
(给根相对地址即可;给绝对 http(s) 地址仍照旧由客户端直连)。
变更
- 公告与登录后弹窗增加 Telegram 交流群入口,移除公告正文中的维护说明。
- HLS 清单里的分片地址改走面板自己的「域名端点」(
/api/agg/hls/{host}/{path},
Emby 实例端口上是/api/emby/hls/{host}/{path}):原来是?seg=&sid=的子地址 ——
那串鉴权头存在面板内存里、分片地址只带一个sid,于是面板一重启,发出去的整份清单就全废(410),
只能等客户端重取清单。现在插件给的Referer/User-Agent与面板签名一起编进分片地址本身
(mbh/mbm),面板按 host + 路径拼回上游地址、单连接去取:重启不再让已发出去的清单失效,
也省掉那张内存表。客户端无需改动(清单还是清单,只是里面每个地址换了形态)。
修复
- Emby 图片 404 兜底:面板重启后图片索引清空,客户端仍缓存旧条目 Id 时,主图(Primary)请求会尝试从上游取一次条目信息并重建索引,避免持续 404。仅限 Primary 类型,避免批量背景图打爆上游。
- Emby 字幕内容端点认下
Stream.subrip/Stream.webvtt:面板给版本里的字幕流申报的Codec
是 Emby 内部名(SRT 记作subrip、VTT 记作webvtt),客户端据此拼出…/Subtitles/{Index}/Stream.subrip
回来,而端点此前只认Stream.srt/Stream.vtt→ 一律 501(日志记未实现;实测 SenPlayer
的 SRT 轨连吃 501,同批 ASS 轨走Stream.ass正常)。现放宽到srt/subrip/ass/ssa/vtt/webvtt
并归一,SRT / VTT 轨恢复可取。客户端无需改动;契约行见 docs/emby-compat.md「十」#23 的 23-6。 - 要鉴权头的线路(
playVia: proxy)不再「先探一发再重下」,段级分片也不再走切块:中继此前对每一发
都先探一发Range: bytes=0-1023拿总长、随即掐掉,再按块切、多路重下,而且要按序吐块 ——
第 1 块没读满,后面十几路即使下完也一个字节都发不出去。那套是按大文件设计的(网盘 CDN 按 Range
形态限速,开放式bytes=0-只有0.1MB/s),但 HLS 是逐分片取,分片为此白付「探测往返 + 重下 +2.8MB 的分片仍进切块档,每片都下到一半被播放器掐掉(日志对得上:开始写「共 2930168 字节」、
等整块」,而一块慢 / 走重试时整条流就是硬停顿。同一部片子(1080p)实测:分片经面板首字节
1089 / 1133 / 875ms,直连带 Referer 只要 302 / 291 / 311ms;上了第一版修复(只直搬 ≤512KB 的那档)后,
清单里 1.1
结束时只「搬了 0.5MB」,一部片子清单被重取了 3 次)。
现在按对象大小分流:8MB 以内(HLS 分片正在这一档)单连接边下边发 —— 不探、不切、不重下,
慢也是连续地慢,没有按序停顿(一片 2.8MB 从十几发上游请求降到 1 发);更大的才分块并发,
而且第一发当流式前缀先吐、后面的块并发续上(不再掐掉重拉,客户端从第 0 字节起就有数据)。
两档发的都是有界 Range,不会撞回开放式 Range 的限速。另外,中继那行「结束」日志现在写成
搬了 X / 共 Y,搬少了会写明"客户端提前断开" —— 就是这次排查时对不上的那种日志。
客户端无需改动;依据见 ADR-0077 与
ADR-0078。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.9.4
发布说明摘自 CHANGELOG.md 的 1.9.4 一节。
变更
- 集名里的
.iso现在认作容器:parseEpisodeMeta的容器清单补iso(光盘原盘镜像,
老片合集常见)。此前.iso播放项的container解析为空、标准文件名还会兜底拼成.mkv;
现在MediaSource.Container/ 版本文件名如实标iso。客户端无需改动(能不能播 ISO
由客户端自己决定,面板如实透传)。 - 聚合搜索「这条的版本」弹窗的字幕轨显示来源:每条字幕轨多标一个字幕插件名(面板自用 API
/api/agg/detail的subtitles[]新增source),装多个字幕插件时能看出这条轨从哪来。
对 Emby 客户端零影响(source只走面板自用 API,emby 层不读它)。同时修掉长文件名撑破弹窗
的老问题(字幕轨名字是文件名,含长哈希 / 无空格长串时不再溢出,改为折行)。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.9.3
发布说明摘自 CHANGELOG.md 的 1.9.3 一节。
新增
- agg 流端点增加带后缀的别名
/api/agg/stream.m3u8:有些播放器 / 客户端按 URL 后缀识别容器,
缺后缀就把面板这条 HLS 出口当普通文件拒掉。新路径与/api/agg/stream同一个 handler、
同一套凭证与搬运语义,只是路由落在带.m3u8的形状上;面板内部改写出的签名子地址仍走原路径
(见 ADR-0075)。- 面向面板之外的客户端(出口插件 / FW / Rex widget 等);面板 Web 与 Emby 客户端不受影响。
契约行见 docs/develop.md 的聚合层接口表。
- 面向面板之外的客户端(出口插件 / FW / Rex widget 等);面板 Web 与 Emby 客户端不受影响。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.9.2
发布说明摘自 CHANGELOG.md 的 1.9.2 一节。
变更
- 聚合搜索「这条的版本」弹窗显示字幕:面板聚合层新增字幕编排 —— 打开「这条的版本」时,
为一个播放目标问一次字幕插件(tracks),把字幕轨列在弹窗里。此前字幕只在 Emby 客户端可见。
字幕插件转接处由 emby 层迁到聚合层,web 与 Emby 共用同一处字幕来源
(见 ADR-0073)。- 面板自用 API
/api/agg/detail响应新增subtitles([{lang, format, label?}];
内部ref凭据不在 HTTP 出口下发)。契约行见 docs/develop.md。 - 对 Emby 客户端无任何可见变化 —— 字幕轨形状、字幕内容端点、鉴权口径、
MediaSourceId载荷
均与上一版一致(客户端无需改动)。
- 面板自用 API
修复
- 字幕地址自带 token,修客户端取字幕 401:字幕流的
DeliveryUrl此前是裸相对路径、不带 token,
而客户端(实测 Streama/1.0.55 android)把它原样发出、不自己追加 token → 面板判「没带 token」→
字幕一律 401(拉流因DirectStreamUrl本就埋了api_key所以正常)。现在字幕地址与DirectStreamUrl
同口径,末尾自带本请求的 access token(…/Stream.{Format}?api_key=…,见
ADR-0074)。- 影响端点:详情与播放信息里字幕流的
DeliveryUrl(多一个api_key);字幕内容端点本身、
鉴权口径、MediaSourceId载荷、Path/DirectStreamUrl均不变。客户端无需改动。
逐条见 emby-realdevice #23 的 23-5(未复测)。
- 影响端点:详情与播放信息里字幕流的
- 插件动作失败回执保留真因:插件动作抛异常时,面板除
code/message外一并带回异常的
cause(error.cause = { code?, message? })。Nodefetch()失败时message恒为一句
fetch failed,真因(如 DNS 的ENOTFOUND、端口非法的bad port)在cause—— 此前会被压成
通用的PLUGIN_ERROR: fetch failed(runner.js 动作异常回执)。
影响面:POST /api/plugins/:type/:id/call及其下游(如 Emby 字幕端点)现在能看到更具体的失败原因;
成功路径与既有code/message字段不变(兼容追加,见插件契约 devkitplugin-contract.md第十节)。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.9.1
发布说明摘自 CHANGELOG.md 的 1.9.1 一节。
新增
-
品牌图标(详见 ADR-0069):
新增品牌图形资产,落地到浏览器标签页与 Emby 默认头像;界面内(顶栏、日志)仍只有文字。public/logo.png(512×512 透明底)作为浏览器标签页图标(favicon),
public/index.html与public/login.html各加一条<link rel="icon">;README 顶部也引用这张图。server/modules/emby/assets/default-avatar.png换成同一张品牌图(仍是 606×606 透明底,
Emby 默认头像口径不变)。- 对客户端的影响:浏览器标签页多一个图标;Emby 默认头像换图 —— 尺寸与
tag口径不变
(tag仍是文件内容 md5),客户端会因内容变化重新拉一次头像。不涉及任何 Emby 端点契约。
-
「关于」页内嵌公告(详见 ADR-0068):
「设置 → 关于」页新增一张公告卡,内容取自仓库里的notice.html—— 交流群地址、贡献者名单
这类内容与代码分开维护,改仓库里那个文件即生效,不需要重新发版。- 新增端点:
GET /api/panel/notice→{html, url, error?}(带 5 分钟缓存)。
html默认取自https://raw.githubusercontent.com/<repo>/main/notice.html,经取源候选
(APP_MIRRORS,与面板更新、插件库共用,见 ADR-0067)。 - 新增环境变量
PANEL_NOTICE_URL可覆盖取回地址(显式给出时不套镜像前缀);置off/none/-
关闭这张卡。 - 内容为空或取不到 → 整张卡不显示;内容以隔离的内嵌 frame 渲染,不执行脚本、样式与面板隔离。
- 对客户端的影响:仅面板「关于」页多一张卡;不涉及 Emby 端点。
⚠️ 走第三方代理时取回的内容可能与仓库原文不同,故按不可信内容渲染(不跑脚本)。
- 新增端点:
-
字幕插件(第五类插件)与 Emby 标准字幕端点(契约变更记录见 docs/emby-compat.md;
插件侧契约见插件仓库media-bridge-plugins/docs/plugin-contract.md「七、字幕插件的动作」):
面板新增第五类插件subtitle,并落地 Emby 标准的字幕取用端点。- 新增端点:
GET /api/emby/Videos/{ItemId}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}
(含带StartPositionTicks的变体)——{Format}∈srt/ass/ssa/vtt。面板从版本 Id 载荷里
取出该轨的ref,交给字幕插件的fetch动作取回内容后回字节
(Content-Type优先取插件给的,没给才按Format兜底)。 - 详情 / 播放信息里挂字幕轨:条目详情、
PlaybackInfo的MediaSources[].MediaStreams[]
追加Type:'Subtitle'的流(Index/Codec/Language/DisplayTitle/DeliveryUrl等),
轨来自字幕插件tracks动作的申报。版本 Id 载荷由{r, v?}扩为{r, v?, s?}
(s= 流序号 → 字幕 ref 的映射;无字幕则不写,载荷与旧版完全一致)。 - 影响哪些端点:
GET /api/emby/Users/{UserId}/Items/{ItemId}(详情)、
POST /api/emby/Items/{ItemId}/PlaybackInfo,以及上面新增的字幕内容端点。 - 对客户端的影响:装并启用字幕插件后,版本会多出字幕轨、客户端可选中取用;没装字幕插件
则一切与从前完全一样(不出字幕轨、载荷不变)。字幕插件是软依赖 —— 没装 / 没在跑 /
tracks失败都只降级(不出字幕轨、记一行日志),不破坏详情本身。 - 真机对照见 docs/emby-realdevice/23-subtitles.md(未复测:
本仓库内没有真机样本,落地依据是 Emby 官方端点形状 + 插件契约,不是抓包)。
- 新增端点:
-
取源候选:内置公共 gh 代理,国内默认直连(详见 ADR-0067):
- 改的是什么:从 GitHub 取东西时,默认先试内置公共 gh 代理(
https://gh-proxy.com、
https://ghfast.top),失败再退到官方直连;单次请求 20 秒超时。面板更新与插件库共用这一套:- 应用代码(查最新版本 + 下版本包 + 下校验);插件库(取清单
index.json+ 取插件包)。
- 应用代码(查最新版本 + 下版本包 + 下校验);插件库(取清单
- 新增环境变量
APP_MIRRORS(逗号分隔、有序)可覆盖;置off/none/-只走官方。 - 影响哪些端点:面板侧「版本与更新」、容器首启的取源,以及
GET /api/plugins/library的
sourceUrl与插件安装取包(不涉及 Emby 端点)。 - 对客户端的影响:国内部署无需再手工找代理即可取源(含插件库);原来只有显式
PLUGIN_*_URL
才能指定源,现在留空即走候选、失败自动降级;在意校验的用户可关掉镜像。 ⚠️ 安全口径:走第三方代理时包体与其校验值(应用代码.sha256、插件 md5)同源,校验
只防传输损坏、不防代理替换(有意接受的取舍,见 ADR-0067);要真实校验就把
APP_SOURCE_URL(或PLUGIN_INDEX_URL/PLUGIN_SOURCE_URL)指向自己信任的镜像。- 引导脚本在
docker/(不入库),本次同改;需重推镜像才对新容器生效。
- 改的是什么:从 GitHub 取东西时,默认先试内置公共 gh 代理(
变更
-
品牌净化:对外 DTO 的自家字段与不透明 Id 前缀去掉
catpaw(契约变更记录见
docs/emby-compat.md):- 改的是什么:
ProviderIds.Catpaw→ProviderIds.MediaBridge;非标准字段
CatpawSource→MediaBridgeSource(其LineFilter子对象同改);版本 / 媒体源 Id 前缀
catpaw:→mbp:(catpawSourceId/parseCatpawSourceId→mbpSourceId/parseMbpSourceId);
媒体库(Views)Id 前缀catpawhome_→mbphome_;PresentationUniqueKey前缀p-catpaw-→p-mbp-。
另:面板自述GET /api/meta的service由catpaw-panel改为mbp-panel;登录 cookie 名
catpaw_panel→mbp_panel;备份包 manifest 的service同步改为mbp-panel(旧备份包不再接受还原)。 - 影响哪些端点:
GET /api/emby/Users/{UserId}/Items/{ItemId}(详情)、POST /api/emby/Items/{ItemId}/PlaybackInfo、
拉流 / 下载 / 字幕各端点里出现的版本 Id,以及GET /Users/{UserId}/Views(库 Id)。 - 对客户端的影响:改的全是不透明标识或面板自用字段(客户端只当字符串、或直接忽略),
客户端无需改动;但客户端若缓存了旧的库 Id / 版本 Id,换版后对不上会取不到内容,清一次客户端缓存 /
重新拉库列表即可。服务端数据无迁移:这些前缀都是运行时现算、不落库(emby.db五表无任何
catpaw列),故不注册迁移任务、数据版本不动。 - 真机对照见 docs/emby-realdevice/04 /
10 / 23(未复测)。 - 同时清掉面板自身文案 / 注释 / 示例里点名具体源的写法(设置项提示、聚合层注释、
develop.md的
source示例、package.json关键词、CONTRIBUTING.md术语表),面板不点名任何源、也不假设源的形态。
这些不进契约、对客户端无影响。
- 改的是什么:
-
仓库与镜像改名,统一到
MediaBridge/mediabridge:- GitHub 仓库
dlushu/media-bridge-panel→dlushu/MediaBridge:自更新取 Release 的默认仓库路径
(APP_REPO)随之改为dlushu/MediaBridge,package.json的repository.url与 README 同步更新。
旧地址由 GitHub 重定向仍可访问,已装环境无需改动。 - Docker Hub 镜像
dlushu/media-bridge-panel→dlushu/mediabridge(Docker Hub 名称须小写,
故用mediabridge)。旧镜像名不再更新,用旧名的部署需把docker run/ compose 里的镜像名换成
dlushu/mediabridge后再拉取。数据卷名media_bridge-data、容器名、发布资产名
media-bridge-panel-<版本>.tar.gz、备份文件名等均未变,改名不影响已有数据。
- GitHub 仓库
-
登录态有效期可调,且改为「滑动过期」(语义与取舍见 ADR-0064):
面板会话的有效期不再写死 30 天,可在「面板设置 → 安全」页按「数值 + 单位(分钟 / 小时 / 天)」调整,
默认 15 分钟、最大 30 天。语义由"到点强制退出"改为空闲计时 —— 从最后一次操作起算,
一直在用就自动顺延,只有空闲满这一时长才需要重新登录(会话在用到有效期的 1/4 时自动续签)。
密码 / 登录接口的响应形状不变,iat字段对前端不可见(会话是 HttpOnly cookie)。 -
登录改为独立页面
/login.html:未登录访问面板会跳到该页,登录后跳回原地址。
「记住密码」有两条路:① 浏览器 / 密码管理器的表单记忆(真实<form>+ 命名输入框 +autocomplete);
② 页上的**「记住密码」勾选框** —— 勾选且登录成功后,密码经 Base64 混淆存进本机浏览器存储
(localStorage),下次打开登录页自动预填,取消勾选即清除。混淆不是加密(防随手翻看、防不了懂行的人),
默认不勾,请按设备信任程度取舍。 -
开源协议由 MIT 改为 AGPL-3.0。
修复
-
测速汇总行口径写错:
成功 N(含 M 个无结果)里 M 其实不在 N 里
(计数是三桶互斥:有结果 / 无结果 / 失败),M > N 时读来矛盾。按业务口径
「无结果 = 站活着、不算失败」改为成功 N+M(其中 M 个无结果),数字对得上总数。
只改日志措辞,okCount/emptyCount的 API 口径不变。 -
开机时首页插件行清单空打一轮
NOT_READY:启动顺序是拉起插件进程后立刻预热行清单,
但插件握手是异步的——还没就绪的插件(日志里两行✘ …插件还没就绪)纯属启动竞态。
现在预热先等插件就绪(轮询running,起不来 / 崩了 / 超时就跳过)再拉行清单,
这两行噪音日志消除,预热一次到位;拿不到的老兜底(快照过期自动重刷)不变。 -
老内核 / 网络盘环境缓存库连环报错(GitHub issue #3,
disk I/O error→no such table: line_cache):- 根因一:缓存库(线路结果 / 图片索引)开 WAL 需要共享内存,CentOS 7 老内核 overlayfs、
NFS / SMB 卷上拿不到,PRAGMA journal_mode = WAL直接抛disk I/O error。 - 根因二(面板 bug):
cachedb.open()先把句柄赋给模块级变量、后跑 pragma 与建表,
pragma 一抛错就留下半初始化句柄——之后所有访问报no such table,完全掩盖真实原因。 - 改的是什么(ADR-0072):
open()原子化(全部初始化成功才登记句柄,失败关库重抛);WAL 起不来时打一条✘级日志
并降级 DELETE journal 继续跑——缓存是可丢数据,不该为它让整个功能不可用。 - 对用户的影响:老内核 / 网络盘环境面板照常可用(丢一点缓存读写并发收益,无感);
卷本身坏掉(盘满 / 断连)时报的是真实原因,不再是误导性的no such table。
- 根因一:缓存库(线路结果 / 图片索引)开 WAL 需要共享内存,CentOS 7 老内核 overlayfs、
-
「日志」页的「仅错误」过滤抓不到业务失败行:面板约定失败行打
✘前缀,但调用点走的
是console.log(级别是log)——logbus只按console方法分级,导致这些行进不了
「仅错误」、也不标红。现在按行首符号归级(✘→error、⚠️→warn),几十处调用点不用改;
标红样式(CSS 早已备好)随之生效。 -
HamHub 点播时反复失败(等几秒才起播):HamHub 把面板下发的根相对拉流地址
(/videos/{id}/stream.hls?…)按 origin 解析(RFC 3986:根相对替换整个 path),把/emby丢掉,
打的是http://<主机>:<实例端口>/videos/…—— 撞上实例端口的 404 守卫,反复退避重试(抓包里
/videos/…404 四次、改用/emby/videos/…才 200)。- 改的是什么:实例端口的路径归一化多认一条 —— 不以
/api/开头的路径一律当作 Emby 根路径
(真机 Emby 本就把端点挂在根路径,见 ADR-0065)。 - 影响哪些端点:实例端口上的全部 Emby 端点(重点:直连拉流
videos/{ItemId}/stream、
Items/{ItemId}/Stream、下载、字幕内容)。面板端口(面板 UI 所在)不变。 - 对客户端的影响:更宽容、客户端无需改动 —— 按 origin 解析(HamHub)与字符串拼接(AfuseKt)
两种行为都能命中;下发的地址一字未改;面板自用端点(accounts/instances等)仍照旧拒绝。 - 真机对照见 docs/emby-realdevice/12-direct-stream.md 的 12-6(未复测)。
- 改的是什么:实例端口的路径归一化多认一条 —— 不以
-
Yamby 打不开带字幕轨条目的播放页:字幕流(
MediaStreams[]里Type:'Subtitle')缺
IsDefault/IsForced字段,Yamby 把IsDefault当必填,整条PlaybackInfo反序列化直接抛
SerializationException。已补IsDefault:false/IsForced:false(外挂字幕本就不是默认/强制轨,
与真机一致)。其余客户端不受影响(它们读不到该字段时按false处理)。真机对照见
docs/emby-realdevice/23-subtitles.md 的 23-4(未复测)。 -
DirectStreamUrl容器后缀:hls映射为m3u8(曾为对齐真机去掉后缀,实测回归后恢复)(契约变更记录见
docs/emby-compat.md;决策见 ADR-0071,
取代 ADR-0070):- 改的是什么:
MediaSources[].DirectStreamUrl保持带后缀形态
/videos/{ItemId}/stream.{容器}?…,但不照抄Container字段:hls→stream.m3u8
(hls是 DTO 容器枚举值、不是播放器认得的扩展名;ExoPlayer 系按后缀推断类型只认.m3u8,
真机的 HLS 拉流地址本就是*.m3u8),其余容器原样拼(stream.mkv/stream.mp4)。 - 来龙去脉:本发布周期内曾按真机形态(予初Emby 4.9.5.0 的
DirectStreamUrl是裸stream)
去掉过后缀(ADR-0070),实测打断了一批靠 URL 后缀判类型的客户端(如 CapyPlayer/1.1.6:
面板清单中继正常回 200,客户端却把 m3u8 文本当普通文件嗅探,报
UnrecognizedInputFormatException)—— 恢复后缀,能播优先于真机形态对齐。详见
docs/emby-realdevice/11-items-playbackinfo.md 的 11-5(未复测)。 - 影响哪些端点:仅 `PO...
- 改的是什么:
1.9.0
发布说明摘自 CHANGELOG.md 的 1.9.0 一节。
变更
-
Emby 版本行标题位改由聚合层供给(契约变更记录见 docs/emby-compat.md):
版本行的标题位(MediaSources[].Name与视频流DisplayTitle)不再由 emby 层自己拼,
改为直接读聚合层写好的versionLabel,出口插件(FW/Rex)读同一个字段 —— 规则只实现一次。- 改的是什么:标题位格式不变(仍是
[体积] 站点标签 · 线路flag [· 变体标注] [· 项标注]),
拼装从 emby 层下沉到聚合层;emby 层不留旧拼装兜底。聚合层同步给详情站条目补上sourceName。 - 影响哪些端点:
POST /api/emby/Items/{ItemId}/PlaybackInfo、
GET /api/emby/Users/{UserId}/Items/{ItemId}(详情)的MediaSources。 - 对客户端的影响:多源命中时标题多出源名前缀(形如
源名 站点标签 · 线路)——
此前聚合层详情站条目不带sourceName,这条「多源前置源名」实际从未生效;现生效,属新可见文本。
单源场景标题不变。客户端无需改动(只当显示名读)。agg 详情缓存 key 版本号随之升级
(aggdetail4→aggdetail5)。 - 决策见 ADR-0063(与
ADR-0043 同一模式)。
- 改的是什么:标题位格式不变(仍是
-
Emby「接下来看」端点改为对外恒空(契约变更记录见 docs/emby-compat.md):
GET /api/emby/Shows/NextUp保留端点、不删路由、不加开关,但响应恒为
200 {Items:[], TotalRecordCount:0}。- 改的是什么:客户端首页的「继续观看」(
Items/Resume)与「接下来看」(Shows/NextUp)
在常规顺序观看下常指向同一集、两行重复;现让Shows/NextUp不再出数据,藏掉那一行。
算「该看哪一集」的实现留着但暂不调用(恢复时改回即可)。鉴权口径不变(无 token → 401)。 - 影响哪些端点:仅
GET /api/emby/Shows/NextUp(含带SeriesId的请求)。
Items/Resume、Items?Filters=IsPlayed等不受影响。 - 对客户端的影响:只认
Shows/NextUp渲染「接下来看」那一行的客户端将不再显示该行;
「继续观看」仍由Resume提供。客户端无需改动(它本就该容忍空列表)。 - 决策见 ADR-0060(取代 ADR-0023 的
Shows/NextUp那一格)。
- 改的是什么:客户端首页的「继续观看」(
-
Emby 播放地址由绝对 URL 改为相对路径(AfuseKt 起播 404)
(契约变更记录见 docs/emby-compat.md):- 改的是什么:
DirectStreamUrl(PlaybackInfo)与MediaSources[].Path(详情 /PlaybackInfo)
此前给绝对 URL({proto}://{host}/api/emby/…),现改为相对路径
(/videos/…?…&Static=true、/Items/…),对齐真机形态。连带去掉
getItem/getPlaybackInfo/buildMediaSource的host/proto参数与protoOf工具函数。 - 影响哪些端点:
POST /api/emby/Items/{ItemId}/PlaybackInfo、
GET /api/emby/Users/{UserId}/Items/{ItemId}(详情)。 - 对客户端的影响:AfuseKt/3.2.0 起播恢复。此前它把面板给的绝对地址当相对路径再拼在
自己的 base(已含/emby)之后,得到双重拼接的畸形地址 → 实例端口 404;改为相对后两种 base
都能命中。走官方协议的客户端无需改动。 - 决策见 ADR-0062;真机逐条见
docs/emby-realdevice/11-items-playbackinfo.md(未复测)。
- 改的是什么:
新增
-
Emby 收藏功能(契约变更记录见 docs/emby-compat.md):新增写端点
POST|DELETE /api/emby/Users/{UserId}/FavoriteItems/{ItemId},并让读取类端点出真收藏数据。- 改的是什么:面板新增收藏存储 ——
favorite表(一行 = 账号 + 条目 + 收藏时的列表元数据快照,
随emby.db持久化,属用户数据、不随缓存清理,SCHEMA_VERSION4→5)。收藏动作时快照、读侧 0 上游请求。 - 影响哪些端点:
POST|DELETE …/FavoriteItems/{ItemId}(此前落 501 通配 → 现 200 +UserItemDataDto,
IsFavorite真值;无 token → 401,Id 认不出 / 反查失败 → 204 不写库);
GET …/Items?Filters=IsFavorite(此前恒空 → 现读favorite表、快照重建出真实条目);
UserData.IsFavorite全链路(列表 / 详情 / 季集)由恒false→ 按收藏库查出的真值。 - 对客户端的影响:客户端无需改动。收藏 / 取消收藏由「未实现」转为可用,首页「收藏」入口由空列表转为真实集合;
可收藏条目类型对齐真机(电影 / 剧 / 季 / 集全认)。 - 决策见 ADR-0058;真机逐条见
docs/emby-realdevice/21-favorite-items.md(未复测,待端到端复核)。
- 改的是什么:面板新增收藏存储 ——
-
片源认证:插件认准的候选,面板直接采信:聚合层新增一条候选行级的认证标 ——
片源插件在search返回的候选上写vod_exact: true,表示「这一条已认准、就是目标作品」,
面板见到就把它的分数直接记 1、不再判名字(其余流转一律不变:仍受分数线与条数上限约束,
只因分最高排在最前、优先取详情)。这解决番号片的老问题:番号查询的名字相似度会被
三四十字的长标题稀释、导致正确候选被名字闸门拒掉;而番号站自己按番号精确过滤过,
「这条对不对」它比面板更清楚。契约在插件仓库
media-bridge-plugins(docs/plugin-contract.md第五节),
本仓库只是消费方。missav 片源先行适配(番号精确过滤后的候选带vod_exact)。
决策见 ADR-0059。 -
Emby 认领旧版播放上报族
Users/{UserId}/PlayingItems/*(HamHub Android 进度一条未落)
(契约变更记录见 docs/emby-compat.md):面板此前只实现新版族
POST /api/emby/Sessions/Playing[/Progress|/Stopped];抓包发现 HamHub Android/1.0.0 走的是
Emby 旧版族POST|DELETE /api/emby/Users/{UserId}/PlayingItems/{ItemId}[/Progress]
(ItemId在路径、参数在 query、无 JSON body),此前全落 501 通配 → 播放进度一条没记、
Resume/IsPlayed拿不到真数据。现认领这一族的 3 条(开始 / 心跳 / 结束),
把 path / query 拼成现有recordPlayback认的形状,落库口径与新版族完全一致(含 204 空体)。- 影响哪些端点:新增
POST …/PlayingItems/{ItemId}、POST …/PlayingItems/{ItemId}/Progress、
DELETE …/PlayingItems/{ItemId}(此前落 501 通配)。 - 对客户端的影响:走旧版族的客户端进度由「一条不记」转为正常入库,无需改动。
- 已知限制:旧版族不带
RunTimeTicks⇒ 面板拿不到时长,只能按位置记、「看完」可能判不出。 - 真机逐条见 docs/emby-realdevice/22-users-userid-playingitems.md(未复测)。
- 影响哪些端点:新增
修复
-
Emby 条目不再回空串
PremiereDate/Overview(客户端FormatException: Invalid date format):
插件没给首播日期时,条目 DTO 上此前会出现"PremiereDate": "";客户端(如 Hills)对它做
DateTime.parse(value),parse('')直接抛FormatException、整条响应解码失败(列表整个打不开)。
真机拿不到就不含这个键(不是回空串)——现对齐:PremiereDate/Overview改为拿不到就不挂键
(口径同DateCreated/DateModified)。数组类字段仍先铺[],不变。- 影响哪些端点:一切补
baseItem的条目 DTO ——Items列表、Items/Latest、Items/Resume、
详情、季 / 集、相似等。 - 对客户端的影响:
PremiereDate/Overview由恒在(可能为空串)变为可能缺失;
对空串做类型转换的客户端不再崩,其余客户端无感(无需改动)。Etag哈希对undefined/''
同化,值不变、无缓存抖动。 - 决策见 ADR-0061(细化 ADR-0008);
真机逐条见 docs/emby-realdevice/06-users-userid-items-latest.md(未复测)。
- 影响哪些端点:一切补
-
Emby 登录不认小写
pw(HamHub Android 登不上):POST /api/emby/Users/AuthenticateByName的
请求体取值此前只认固定拼写(Username/username、Pw/Password/password),客户端发全小写
{"username":…,"pw":…}时密码被读成空串 → 401无效用户名或密码。请重试。。真机(.NET 反序列化)
字段名大小写不敏感 —— 实测 OkEmby / itsmygo 发Pw与pw均登录成功。现对齐真机:Username/Pw
(含兼容Password)不再区分大小写。响应结构与错误文案不变,客户端无需改动。
(契约变更记录见 docs/emby-compat.md;真机逐条见
docs/emby-realdevice/02-users-authenticatebyname.md) -
Emby 登录不认
Authorization头里的 appName:POST /api/emby/Users/AuthenticateByName
取 appName 时此前只读X-Emby-Authorization,客户端按官方文档把Client="…"放在Authorization里时
被误判「缺 appName」→ 400Value cannot be null. (Parameter 'appName')。真机两头都认 —— 实测
OkEmby / nyamedia / 予初Emby:只发任一头 → 200 登录成功,两头都缺 → 400 登不上。现对齐真机:
X-Emby-Authorization缺失时回退读Authorization。响应结构与错误文案不变,客户端无需改动。
日志里的客户端标记([Client/版本])同步改为两个头都看(此前只认前者,缺了就退到 UA)。 -
Emby 登录不认授权头里不写引号的
Client=(部分客户端登不上):POST /api/emby/Users/AuthenticateByName
解析 appName 时此前正则写死Key="值"、只认带引号的写法,客户端发Emby Client=SomeApp, …(省引号)
就取不到 appName → 400。真机对引号可选 —— 实测 nyamedia 4.8.0.62:Emby Client="Filmly"与
Emby Client=Filmly均 200 登录成功。现对齐真机:Client=/Device=/DeviceId=/Version=的
值引号可省(日志的客户端标记同一口径;从授权头取Token=的路径一并放宽)。响应结构与错误文案不变,客户端无需改动。
(契约变更记录见 docs/emby-compat.md;真机逐条见
docs/emby-realdevice/02-users-authenticatebyname.md) -
Emby 登录不认 query 里的 appName(Filmly / 网易爆米花登不上):
POST /api/emby/Users/AuthenticateByName
取 appName 时此前只看授权头。抓包发现 Filmly 把客户端名放在 query(?X-Emby-Client=网易爆米花 Android),
授权头里只有Device/DeviceId/Version、没有Client=,于是被误判「缺 appName」→ 400
Value cannot be null. (Parameter 'appName')。真机对同一形状的请求实测(nyamedia 4.8.0.62):头无Client=- query 带
X-Emby-Client→ 200 登录成功;头无Client=+ 无 query → 400。现对齐真机:头里取不到Client=
时回退读 queryX-Emby-Client(参数名大小写不敏感)。响应结构与错误文案不变,客户端无需改动。
(契约变更记录见 docs/emby-compat.md;真机逐条见
docs/emby-realdevice/02-users-authenticatebyname.md)
- query 带
-
Emby 路径大小写写错就落 501(AfuseKt 登不上):
core/router.js的路径匹配此前字面段大小写敏感,
客户端把/api/emby/Users/AuthenticateByName写成全小写authenticatebyname就落ANY /api/emby/*rest
通配 → 501。真机(.NET 路由)大小写不敏感,故这类客户端在真机能登、在面板 501(实测 AfuseKt/3.2.0
就把登录路径写成全小写)。现对齐真机:字面段大小写不敏感比对(:param/*wildcard的取值照原样给)。
影响面为全局(所有走该路由器的路径,含面板自身/api/*):此前大小写写错会 404 / 501 的路径现在都能命中;
方法与段数约束不变(段数不齐仍 404、方法不符仍 405)。此前正确大小写的请求行为不变,客户端无需改动。
同轮删除冗余的Videos重复注册(现一条认下大小写两种),端点集合不变。
(契约变更记录见 docs/emby-compat.md;真机逐条见
[docs/emby-realdevice/02-users-authenticatebyname.md](https://github.com/dlushu/media-bridge-panel/blob/main/docs...
1.8.4
发布说明摘自 CHANGELOG.md 的 1.8.4 一节。
变更
- Emby 客户端协议继续按真机对齐(逐条对照与取样见 docs/emby-compat.md 的「十、真机对照记录」):
Users/{UserId}不再核对 UserId 与 token 是否同一人:实测真机不校验,只要有有效 token,
UserId 换成任意合法值照样回数据。Views也同步放宽(authorize(req)不再比对 userId)。Items/Items/Latest收紧守卫:无 token 一律 401(原来部分空查询分支会「照常回空」);
userId 与Views同口径放宽。两条端点的推荐/收藏/已看/搜索等分支形状逐一对过真机样本。Views补齐字段:ParentId给占位值"2";ChildCount优先用该行已知的真实条数
(首页插件记过就有),没记过时回退1。
- 用户头像改用部署者提供的品牌图标:
GET /api/emby/Users/{UserId}/Images/{type}不再回按UserId
派生的纯色 PNG,改为统一回server/modules/emby/assets/default-avatar.png(606×606 透明底,所有用户
共用一张)。User.PrimaryImageTag/SessionInfo.UserPrimaryImageTag= 该文件内容的 md5
(32 位 hex,与真机同形状)—— 换图标文件即自动失效客户端图片缓存,无需手动改版本号。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.8.3
发布说明摘自 CHANGELOG.md 的 1.8.3 一节。
修复
- HTTPS 反代下绝对地址退成
http://:MediaSources[].Path与DirectStreamUrl只用请求的Host
拼绝对 URL,而Host头里没有协议 —— 面板挂在 HTTPS 反代后面时仍一律吐http://,
客户端可能降级到 80 端口、或被浏览器的混合内容策略拦掉。现先读反代写入的X-Forwarded-Proto、
缺省才回退http(口径与聚合层的originOf一致)。实测:带X-Forwarded-Proto: https时两条地址均为
https://,不带头时仍为http://。
变更
- 登录与握手响应按真机样本对齐(逐条对照见 docs/emby-compat.md 的「十、真机对照记录」):
System/Info/Public只回真机那 5 个字段:补LocalAddresses/RemoteAddresses(空数组),
删LocalAddress/ProductName/OperatingSystem/StartupWizardCompleted。User(UserDto)补Prefix/DateCreated/PrimaryImageTag/PrimaryImageAspectRatio,
删真机没有的HasConfiguredEasyPassword/EnableAutoLogin;Configuration取真机 15 键
(SubtitleMode: Smart),Policy取真机 44 键(非管理员、IsHidden、下载与转码全 false 等)。SessionInfo从 8 键补到真机 20 键(PlayState/RemoteEndPoint/Protocol/InternalDeviceId/
SupportedCommands/UserPrimaryImageTag等)。
- 登录与取用户的错误体改为纯文本(真机如此):缺
X-Emby-Authorization→ 400
Value cannot be null. (Parameter 'appName');用户名或密码不对 → 401无效用户名或密码。请重试。
(不区分哪一个不匹配,避免暴露用户名是否存在);Users/{id}认不出 → 404 纯文本。 - 新增用户头像端点
GET /api/emby/Users/{UserId}/Images/{type}(豁免 AccessToken,与条目图片同理):
只认Primary,回一张按UserId派生的稳定纯色 PNG(160×160,Node 内置 zlib 生成,不引三方库)。
User.PrimaryImageTag现在有值,客户端登录后会来拉这张图,不给就是破图。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。
1.8.2
发布说明摘自 CHANGELOG.md 的 1.8.2 一节。
修复
- 302 跳转地址被二次编码:面板给
Location头编码时用了encodeURI,它会连%一起转义
(%3D→%253D),把源直链里已有的签名编坏 —— 上游校验不过直接 400,表现为「播放/取图莫名失败」。
改用new URL(url).href做归一化:只补编 URL 不允许的字符(中文、空格等),已编码的%XX原样保留。
涉及播放取流(serveStream/ 中继 302)与图片跳转两条路。 E<数字>集名定位不到(插件catpaw-resolve→ 1.0.12):花卷等源把每集写成
[1.4GB]E161.mp4【XIANNI2026】(字母E+ 集号),集名解析器此前不认这种前缀式写法,
该线路「源里明明有、却定位不到这一集」,版本列表里看不到它。现支持E<数字>前缀集号
(只认前面不是字母的E,HEVC/MPEG4这类词里的 E 不受影响)。
变更
- 中继首块自适应:探测式请求(
bytes=0-,或无 Range 从头全量)的前 4 块用 256KB,
小块更早吐字节、起播更快,也少浪费在飞数据(播放器常读几百 KB 就 seek);整片重试次数 1 → 2。 - 新建模板「续接补位」默认
0→8(ADR-0027 的兜底档):
新建模板不再默认「不补打」—— 前 8 条命中一条能用的都没拿到时,按分数继续往下试最多 8 条。
已保存的模板不受影响(盘上存着的值优先;填0仍是不补打)。
面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。