【免费下载链接】unyo-app
🐙 Anime streaming and Manga reader desktop app without ads.
Unyo 是一款免费的桌面端 Anime 流媒体与 Manga 阅读器,它内置了"自动跳过片头片尾"功能:播放番剧时,应用会调用 AniSkip API 获取该集的开篇(OP)与片尾(ED)时间区间,让播放器按钮在关键时刻显示 Skip Opening / Skip Ending,点击即可一键跳过。本文将带你完整看懂这套功能的原理:从 API 数据结构、请求时机,到播放器跳过逻辑与个性化设置。
功能初体验:播放器上的"聪明"跳过按钮 🎬
在 Unyo 中打开任意一集动画,播放器右下角的进度条旁会有一个深色按钮,它的文字会随播放进度实时变化:
| 当前所处区间 | 按钮显示 |
|---|---|
| 正在播放片头(OP 区间内) | Skip Opening |
| 正在播放片尾(ED 区间内) | Skip Ending |
| 普通剧情段落 | + 85s(手动快进) |
这个看似简单的按钮,背后其实是"数据查询 + 状态管理 + 播放控制"三者协作的结果。
数据基础:AniSkip API 返回了什么?
Unyo 的片头片尾时间数据来自 AniSkip 开放 API,其基础地址定义在配置文件 lib/config/config.dart 中(aniskiBaseEndpoint指向api.aniskip.com)。
Unyo 实际请求的完整路径形如:
/v2/skip-times/{malId}/{episode}?types=op&types=ed&episodeLength=1500参数含义很直白:
- malId:作品在 MyAnimeList 中的 ID,来自 Anime 实体 的
idMal字段 - episode:当前集数(播放器内部索引
playlistIndex + 1) - types=op&types=ed:同时请求片头与片尾区间
- episodeLength:以秒为单位的单集时长,用于服务端精确匹配
返回的 JSON 由 AniskipTimesEntity 建模,核心结构如下:
{ "found": true, "results": [ { "skipType": "op", "skipId": "xxxxxx", "episodeLength": 1500.0, "interval": { "startTime": 35.2, "endTime": 182.7 } } ] }其中interval.startTime/interval.endTime就是"这一段剧情从第几秒开始、到第几秒结束"。skipType为op表示片头,ed表示片尾——这是整个跳过逻辑的判断依据。
核心流程拆解:从开播到跳过只需四步
所有关键逻辑集中在 lib/application/cubits/video_cubit.dart 中,整个链路可拆成四步:
第 1 步:开播后延迟 1 秒发起查询
当新一集视频初始化完成后,Unyo 并不立即请求 API,而是延迟 1 秒再触发,见 _initVideoMetadata:
Future.delayed(const Duration(seconds: 1), () => _getAniskipSkipTimes(state.selectedAnime, videoInfo));第 2 步:构造请求,并优雅兜底
_getAniskipSkipTimes 负责发起请求。有个值得注意的细节:episodeLength参数取自作品的duration字段(分钟制)并换算为秒;如果时长数据缺失(为 0),则回退为 24 分钟(24 * 60秒),保证请求总能发出:
double formattedDuration = selectedAnime.duration > 0 ? selectedAnime.duration * 60 : 24 * 60;第 3 步:筛选结果,写入播放状态
拿到响应后,代码按skipType过滤出片头与片尾两条记录,分别写入 VideoState 的openingSkipTimes和endingSkipTimes字段。若查询失败(HTTP 状态码大于 299 或数据状态码异常),仅记录日志并静默退出——跳过功能不可用不会阻断正常播放。
第 4 步:根据播放进度实时判断区间
播放时,UI 通过 getSkipTimeText 拿到当前按钮文案。判断公式很简单:
当前播放秒数 > 区间起点 且 当前播放秒数 < 区间终点 ⇒ 正处于该区间
命中 OP 显示Skip Opening,命中 ED 显示Skip Ending,都未命中则显示+ 85s。
跳过逻辑详解:精准 Seek + 手动快进兜底 ⏩
点击按钮后触发 performSkipActin(源码中方法名即如此拼写),执行策略分三级:
- 处于 OP 区间:直接
seekTo跳转到interval.endTime,即片头结束那一秒 - 处于 ED 区间:同样
seekTo到片尾结束点 - 其他情况:调用
forward快进用户设定的手动跳过时长
按钮本身的渲染位于 unyo_video_controls.dart,它每次构建时都实时读取 Cubit 状态,因此文案能随播放进度动态刷新,无需额外轮询。
个性化设置:自动跳过与手动跳过时间
在设置页的Player分类下(见 settings_screen.dart),用户可以微调这套跳过体验:
- Skip opening automatically:开启后片头可自动跳过(数据可用时)
- Skip ending automatically:片尾自动跳过开关
- Default manual skip time:手动快进时长滑杆,范围 60 ~ 120 秒,默认 85 秒,对应 Settings 模型 中的
manualSkipTime字段(即按钮上的+ 85s)
设置项通过 SettingsCubit 写入本地用户设置,下次播放立即生效。
关键源码文件清单
| 文件 | 职责 |
|---|---|
| lib/application/cubits/video_cubit.dart | API 查询、区间判断、跳过执行的核心逻辑 |
| lib/core/services/api/dto/aniskip/aniskip_times_entity.dart | AniSkip 响应数据模型 |
| lib/config/config.dart | API 基础地址配置 |
| lib/application/states/video_state.dart | 片头/片尾区间状态存储 |
| lib/presentation/widgets/styled/unyo_video_controls.dart | 跳过按钮 UI |
| lib/presentation/screens/settings_screen.dart | Player 设置项 |
小结
Unyo 的自动跳过片头片尾功能,本质上是一个典型的"外部数据增强本地体验"案例:用 AniSkip API 的interval区间数据驱动按钮文案与 Seek 行为,再用手动快进作为无数据时的兜底。整个实现仅涉及一次轻量 HTTP 请求和纯内存状态判断,无轮询、无复杂依赖——这正是桌面端流媒体应用提升观剧效率的务实做法。如果你想为自己的播放器加入类似功能,Unyo 的这份四步实现链路完全可以作为参考模板。
【免费下载链接】unyo-app
🐙 Anime streaming and Manga reader desktop app without ads.
相关推荐
AniBaka 智能跳过片头片尾教程:OP/ED 标注、应用到全集与 AniSkip 数据源揭秘
AniBaka 智能跳过片头片尾教程:OP/ED 标注、应用到全集与 AniSkip 数据源揭秘 追番最怕两件事:每集都要手动拖进度条,跳完片尾结果彩蛋被剪掉了
Intro Skipper终极指南:让Jellyfin自动跳过片头片尾
Intro Skipper终极指南:让Jellyfin自动跳过片头片尾 每次追剧都要手动跳过重复的片头片尾?Intro Skipper为你解决这个烦恼!这款基于
音视频后端swift-doc与Swift Package Manager的完美结合实践:快速生成专业Swift文档
swift doc与Swift Package Manager的完美结合实践:快速生成专业Swift文档 swift doc是一款强大的Swift项目文档生成工
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考