Skip to content

Releases: dlushu/MediaBridge

1.9.6

Choose a tag to compare

@github-actions github-actions released this 14 Oct 17:51

发布说明摘自 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

Choose a tag to compare

@github-actions github-actions released this 14 Oct 16:13

发布说明摘自 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 是逐分片取,分片为此白付「探测往返 + 重下 +
    等整块」,而一块慢 / 走重试时整条流就是硬停顿。同一部片子(1080p)实测:分片经面板首字节
    1089 / 1133 / 875ms,直连带 Referer 只要 302 / 291 / 311ms;上了第一版修复(只直搬 ≤512KB 的那档)后,
    清单里 1.1
    2.8MB 的分片仍进切块档,每片都下到一半被播放器掐掉(日志对得上:开始写「共 2930168 字节」、
    结束时只「搬了 0.5MB」,一部片子清单被重取了 3 次)。
    现在按对象大小分流:8MB 以内(HLS 分片正在这一档)单连接边下边发 —— 不探、不切、不重下,
    慢也是连续地慢,没有按序停顿(一片 2.8MB 从十几发上游请求降到 1 发);更大的才分块并发,
    而且第一发当流式前缀先吐、后面的块并发续上(不再掐掉重拉,客户端从第 0 字节起就有数据)。
    两档发的都是有界 Range,不会撞回开放式 Range 的限速。另外,中继那行「结束」日志现在写成
    搬了 X / 共 Y,搬少了会写明"客户端提前断开" —— 就是这次排查时对不上的那种日志。
    客户端无需改动;依据见 ADR-0077 与
    ADR-0078。

面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。

1.9.4

Choose a tag to compare

@github-actions github-actions released this 09 Oct 17:23

发布说明摘自 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

Choose a tag to compare

@github-actions github-actions released this 09 Oct 07:29

发布说明摘自 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 的聚合层接口表。

面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。

1.9.2

Choose a tag to compare

@github-actions github-actions released this 09 Oct 07:02

发布说明摘自 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 载荷
      均与上一版一致(客户端无需改动)。

修复

  • 字幕地址自带 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? })。Node fetch() 失败时 message 恒为一句
    fetch failed,真因(如 DNS 的 ENOTFOUND、端口非法的 bad port)在 cause —— 此前会被压成
    通用的 PLUGIN_ERROR: fetch failed(runner.js 动作异常回执)。
    影响面:POST /api/plugins/:type/:id/call 及其下游(如 Emby 字幕端点)现在能看到更具体的失败原因;
    成功路径与既有 code / message 字段不变(兼容追加,见插件契约 devkit plugin-contract.md 第十节)。

面板「设置 → 版本与更新」里可以手动更新到这个版本;它只安装正式 Release 的资产并校验 sha256。

1.9.1

Choose a tag to compare

@github-actions github-actions released this 09 Oct 03:46

发布说明摘自 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/(不入库),本次同改;需重推镜像才对新容器生效。

变更

  • 品牌净化:对外 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、备份文件名等均未变,改名不影响已有数据。
  • 登录态有效期可调,且改为「滑动过期」(语义与取舍见 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。
  • 「日志」页的「仅错误」过滤抓不到业务失败行:面板约定失败行打 ✘ 前缀,但调用点走的
    是 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...
Read more

1.9.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 15:44

发布说明摘自 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_VERSION 4→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」→ 400 Value 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=
      时回退读 query X-Emby-Client(参数名大小写不敏感)。响应结构与错误文案不变,客户端无需改动。
      (契约变更记录见 docs/emby-compat.md;真机逐条见
      docs/emby-realdevice/02-users-authenticatebyname.md)
  • 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...

Read more

1.8.4

Choose a tag to compare

@github-actions github-actions released this 06 Oct 00:32

发布说明摘自 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

Choose a tag to compare

@github-actions github-actions released this 05 Oct 15:55

发布说明摘自 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

Choose a tag to compare

@github-actions github-actions released this 05 Oct 04:52

发布说明摘自 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。