Jellyfin 12.0 正式发布:数据库重构、版本号去 10 与升级红线清单

开源媒体服务器 Jellyfin 在 9 月 8 日发布 12.0 稳定版。这次版本做了三件事:把媒体库数据库的性能重构落地、把图书和漫画支持收进服务器核心、把版本号从 10.x 时代切换到新编号。公告同时用整段篇幅列出了升级前置条件,数据库 schema 变更加首次启动数据重写,让这次升级成为近几个版本里操作风险最高的一次。

Jellyfin GitHub 仓库

从 10.11 到 12.0:版本号里少掉的"10"

这次发布最直观的变化写在版本号里。按旧命名规则,本次版本应该是 10.12.0,官方直接去掉了前缀"10.",发布为 12.0.0。10.11.x 成为使用旧编号的最后一个分支。

原因在官方公告里写得很具体:10.11.0 重写了整个媒体库数据库,按任何合理标准都是一次大版本升级,但"10."这个前缀从项目分叉以来从未变过,真正承载版本含义的数字被挤到了中间位置,让大版本升级看起来像小版本更新,用户按小版本的预期升级,踩到的却是大版本的坑。社区在 1 月提出、5 月确认了这个反馈,最终决定让第一位数字在大版本时真正移动。

对所有解析 Jellyfin 版本号的程序(客户端、监控脚本、部署流水线、容器镜像 tag 固定),这是升级前需要检查的一件事。

数据库重构:播放列表从"一整个列表"到"一行一条"

10.11.0 重建了媒体库数据库的结构,12.0 在此基础上兑现性能。公告里讲得最透彻的例子是播放列表的存储方式。

旧实现里,播放列表的全部内容作为一个整体列表存在播放列表自身内部,数据库无法"看进"这个列表。统计条目数、计算观看进度、翻页展示,任何操作都要先加载整个播放列表再解开;编辑同理,增删一项意味着把整个列表写回数据库。列表越长,每次操作的成本越高。

12.0 把播放列表中的每一项拆成独立的数据行。数据库可以直接数行数、返回一页、增删单项而不触碰其余部分。合集(collections)和 boxsets 之前用同样的存储方式,一并修复。伴随的改进还有:批量删除大量条目不再中途失败;Continue Watching、Next Up、重看标记、音乐 Latest Media、艺人查询、文件夹观看计数都变快;重量级数据库维护不再与媒体库扫描同时运行,两者不再争抢资源。

官方同时说明:这轮优化针对的是读取媒体库的路径,扫描器本身不是这次的目标,扫描速度只作为副作用略有提升。

需要手动控制迁移时机的服务器现在可以用 --mode MigrateSystem 参数:执行数据库升级后退出,不启动其余服务,把首次启动的迁移拆成可计划的步骤。

剧集多版本与图书漫画入核心

alternate versions(同一内容的多个版本分组)此前是电影专属功能,12.0 扩展到剧集:广播版与加长版、1080p 与 4K 副本可以像电影一样分组,观看进度跟随实际观看的版本。这个功能正是升级后必须全库重扫的原因:修复版本链接的存储方式后,自动归组的版本要从磁盘文件重建。

图书和漫画的支持从插件搬进服务器核心:

  • 直接读取 EPUB 的 OPF、漫画的 ComicInfo 文件和 ComicBookInfo 注释,无需插件
  • 为 EPUB 和全部支持的漫画归档格式生成海报,有声书支持外挂封面
  • 从文件名解析书名、序号、年份、系列,漫画解析卷号和章节号
  • 从漫画归档和 PDF 提取页数,从有声书提取章节
  • Bookshelf 插件废弃,拆分为 GoogleBooks 和 ComicVine 两个 provider,新增 OpenLibrary 插件
  • Web 端新增现代图书库布局、统一的全屏阅读界面、PDF 滑动翻页,iOS 有声书支持后台播放

推荐与搜索也开放了插件扩展:每个媒体库可以选择自己的相似内容来源,服务器内置 ListenBrainz 作为音乐推荐源,让"相似艺人"建议来自真实收听数据;搜索结果可以由插件补充,不再需要 fork 整个项目。

安全修复与破坏性变更

12.0 包含一批安全修复:封堵特制请求读取服务目录之外文件的路径、阻止未登录状态下重新运行安装向导、拒绝文件名不安全的插件包、在更多位置应用家长控制、修复 Web 客户端的跨站脚本问题。

破坏性变更集中在客户端和插件开发者一侧:

  • 服务器升级到 .NET 10,插件接口多处变更,旧插件必须重新编译
  • 已弃用的授权机制默认禁用
  • GetItems 变为异步,带筛选时自动应用 recursive 参数,同一查询可能返回与 10.11 不同的结果
  • 删除了五个早已废弃的路由;QuickConnect 的 GET 形式移除,只保留 POST
  • Swashbuckle 更新到 v10,OpenAPI 文档结构变化,自动生成的 SDK 需要重新生成
  • 旧式 /emby/ 与 /mediabrowser/ 兼容路径移除,多年未更新的客户端将无法连接服务器

原计划在本次版本移除的内置 TLS/SSL 支持推迟到未来版本,官方建议不变:对外网暴露的实例放在反向代理后面。

升级红线:动数据库之前的五件事

官方公告把 TL;DR 整段留给了升级警告:本次发布改写数据库 schema 并在首次启动时重写数据,没有备份就没有退路。

#检查项具体要求
1备份停止服务后对数据目录和配置目录做完整手动备份,这是唯一回退手段
2版本门槛必须已在 10.10.7 或任意 10.11.x;更旧的版本先升 10.10.7 再升 12.0
3用户名用户名改为大小写不敏感,仅大小写不同的两个账户会让迁移直接失败,升级前先改名
4插件先移除全部第三方插件;10.11 构建的插件无法在 12.0 加载,等作者更新;官方插件已适配
5首次扫描升级后必须执行全库扫描;自动归组的多版本会被清空重建;首次扫描明显变慢属预期,迁移运行中不要停止服务

两条来自实际反馈的补充:升级后 Web 界面异常先强制刷新(Ctrl+Shift+R)或清浏览器缓存,过期缓存资源是这类问题的首要原因;首次扫描后部分电影会短暂显示为"新添加",属于迁移修正旧数据的正常现象。

社区实测:迁移时长与性能

发布讨论区里,一位 40TB 媒体库的用户从 10.10.7 直接升级到 12.0:迁移只用了几分钟,全库重扫把此前消失的部分条目带了回来,之后一切正常。另一位报告迁移 10 分钟、重扫 30 分钟、补齐 trickplay 预览图几分钟。两人的共同结论是 12.0 的浏览性能优于 10.10 和 10.11,包括第三方客户端内的表现。

10.11.0 发布时的性能问题曾让部分用户回退到 10.10.7。本次版本经历了 7 个 RC 才转正,从 6 月 22 日的 RC1 到 9 月 1 日的 RC7,历时两个半月。讨论区一位长期停在 10.10.7 的用户升级后表示这回不用再回去了。

仓库页显示 Jellyfin 主仓库星标 57k,贡献者 1k。

与 Plex 的差距,社区怎么说

Jellyfin 是 Emby 在 2018 年转向闭源后的社区分支,与 Plex 的对比是每个版本讨论区的固定节目。12.0 的讨论串里,Plex 用户的正面评价集中在退路:终身会员用户把 Jellyfin 视作 Plex 做出下一个用户敌对动作时的落点,这个预期本身就在影响 Plex 的产品决策。反对的声音同样具体:客户端生态仍是 Plex 的强项,Plexamp 在音乐场景没有对手,非技术家庭成员的使用体验差距是很多迁移推迟的实际原因;Jellyfin 的字幕体验(尤其 Android 客户端投屏 Chromecast 场景)被反复点名。两条路线各自的适配成本在讨论区都有第一手描述,迁移决策前可以完整读一遍。

12.0 的升级清单长,但条条有对应的技术原因:schema 变更决定了备份是唯一退路,用户名大小写规则决定了迁移可能失败,多版本重建决定了必须重扫。官方公告原文与完整 changelog 在 jellyfin.org 与 GitHub Releases 页面,升级前读一遍 TL;DR 一节,比事后恢复数据库便宜得多。