Skip to content

feat(jellyfin): 支持 Jellyfin Intro Skipper 及原生 MediaSegments 片头片尾跳过 - #3246

Open
XYenon wants to merge 7 commits into
open-ani:mainfrom
XYenon:feat/jellyfin-intro-skipper
Open

feat(jellyfin): 支持 Jellyfin Intro Skipper 及原生 MediaSegments 片头片尾跳过#3246
XYenon wants to merge 7 commits into
open-ani:mainfrom
XYenon:feat/jellyfin-intro-skipper

Conversation

@XYenon

@XYenon XYenon commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

背景与目的 (Why)

此前播放 Jellyfin / Emby 数据源视频时,由于未提取媒体服务器中的视频章节/时间戳信息,导致无法识别片头片尾 (OP/ED),也无法自动或手动跳过 OP/ED。

本 PR 增加了对 Jellyfin 10.10+ 原生 MediaSegments API 以及经典 Intro Skipper 插件的兼容支持,使得播放 Jellyfin 媒体源时能够自动读取并应用 OP/ED 标注。


变更内容 (What)

  1. 数据模型拓展 (datasource/api)

    • MediaExtraFiles 中新增 MediaChapter 数据结构(包含 name, durationMillis, offsetMillis)及 chapters: List<MediaChapter> 属性。
  2. Jellyfin 数据源解析 (datasource/jellyfin)

    • 修改 BaseJellyfinMediaSource
      • 请求剧集详情时添加 fields=MediaStreams,Chapters
      • 实现三级回退的章节/片头获取策略 fetchChaptersAndSegments:
        1. Jellyfin 10.10+ 原生 MediaSegments API (GET /MediaSegments/{itemId}):解析 Intro / Outro / Recap / Preview / Commercial 标记。
        2. Intro Skipper 插件 API (GET /Episode/{itemId}/IntroTimestamps):解析 IntroStartIntroEnd 时间戳。
        3. Item 内嵌章节:解析视频自带的 Item.Chapters
  3. 播放器与 ViewModel 集成与优先级 (app/shared)

    • 更新 EpisodeViewModel:提取选中媒体的 extraFiles.chapters,合并至 combinedChaptersFlow。调整优先级策略为:Jellyfin 章节数据 c 存在时优先采用 (a + c),未提供时回退使用在线 AutoSkip 规则 (a + b)
    • 更新 PlayerSkipOpEdState:增加按章节名称关键字(OP, ED, Intro, Outro, Opening, Ending)自动识别跳过逻辑。
    • 修复 EpisodeVideo 中跳过按钮与 opEdSkipDuration 的状态响应绑定。
  4. 单元测试 (commonTest)

    • 新增 PlayerSkipOpEdStateTest 验证按名称匹配 OP 章节。
    • 新增 BaseJellyfinMediaSourceTest 验证 Jellyfin DTO 的反序列化。

测试验证情况 (Verification)

  • ./gradlew :datasource:jellyfin:desktopTest 单元测试通过 (3/3 passed)
  • ./gradlew :app:shared:desktopTest --tests "*PlayerSkipOpEdStateTest*" 单元测试通过
  • ./gradlew :datasource:jellyfin:assemble :datasource:datasource-api:assemble 编译构建成功

@XYenon
XYenon force-pushed the feat/jellyfin-intro-skipper branch 3 times, most recently from 572e542 to 1510a90 Compare July 29, 2026 16:09
@XYenon
XYenon marked this pull request as ready for review July 29, 2026 16:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1510a901ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/shared/src/commonMain/kotlin/ui/subject/episode/EpisodeViewModel.kt Outdated
Comment thread app/shared/src/commonMain/kotlin/ui/subject/episode/video/PlayerSkipOpEdState.kt Outdated
Comment thread datasource/jellyfin/src/commonMain/kotlin/BaseJellyfinMediaSource.kt Outdated
@XYenon

XYenon commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: b1bc621d43

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@XYenon
XYenon force-pushed the feat/jellyfin-intro-skipper branch 2 times, most recently from 8a85e08 to 9503dae Compare August 2, 2026 15:21
@Him188

Him188 commented Aug 9, 2026

Copy link
Copy Markdown
Member

请不要找 codex review, 他的 review 基本没有参考价值(

@XYenon
XYenon requested a review from Him188 August 12, 2026 08:58
Comment thread app/shared/src/commonMain/kotlin/ui/subject/episode/EpisodeVideo.kt Outdated
@StageGuard

Copy link
Copy Markdown
Member

merge main please

@XYenon
XYenon requested a review from StageGuard August 18, 2026 08:25

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

逻辑过于复杂,需要重新设计,我想一下

XYenon and others added 7 commits August 27, 2026 02:25
为什么修改:Jellyfin/Emby 数据源此前未提取视频片头片尾 (OP/ED) 章节信息,导致在播放 Jellyfin 媒体源时无法自动或一键跳过 OP/ED。

做了什么:
1. 数据模型层:MediaExtraFiles 中新增 MediaChapter 及 chapters 列表定义。
2. Jellyfin 数据源:BaseJellyfinMediaSource 在请求 getItem/getEpisodes 时添加 fields=MediaStreams,Chapters 字段,并依次支持 Jellyfin 10.10+ 原生 /MediaSegments/{itemId} API、Intro Skipper 插件 /Episode/{itemId}/IntroTimestamps API 及 Item 嵌入章节,将其解析为 MediaChapter 列表。
3. 播放器及 UI:EpisodeViewModel 支持将选定媒体的 extraFiles.chapters 合并至 combinedChaptersFlow 中;PlayerSkipOpEdState 支持按章节名称 (OP/ED/Intro/Outro 等) 自动识别并跳过。
4. 单元测试:新增 PlayerSkipOpEdStateTest 及 BaseJellyfinMediaSourceTest DTO 反序列化单元测试。

测试情况:
- ./gradlew :datasource:jellyfin:desktopTest ✅ BUILD SUCCESSFUL (3/3 passed)
- ./gradlew :app:shared:desktopTest --tests "*PlayerSkipOpEdStateTest*" ✅ BUILD SUCCESSFUL

Co-authored-by: XYenon <register@xyenon.bid>
1. 延迟章节 API 请求 (P1):在 fetch() 匹配流程中先执行 matches(query) 过滤,仅对筛选留下的目标剧集延迟发起 fetchChaptersAndSegments() 网络请求,避免对全季剧集进行串行请求。

2. 正向精确匹配 OP/ED 标记 (P2):MediaSegments API 请求时添加 includeSegmentTypes=Intro,Outro 限制,且仅保留 Intro/Outro 类型;在 PlayerSkipOpEdState 中改用正向名称匹配 (isOpEdName),支持 op, ed, intro, outro, opening, ending, 片头, 片尾, 片头曲, 片尾曲 等正向标记。

Co-authored-by: XYenon <register@xyenon.bid>
Amp-Thread-ID: https://ampcode.com/threads/T-019fb10d-dd57-74de-9c02-2c8c943031c8
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: XYenon <register@xyenon.bid>
@XYenon
XYenon force-pushed the feat/jellyfin-intro-skipper branch from d53682e to 0fd7525 Compare August 27, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants