news 2026/9/30 2:19:42

Seal:基于 yt-dlp 的 Android 视频与音频下载器——核心功能架构与实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Seal:基于 yt-dlp 的 Android 视频与音频下载器——核心功能架构与实战指南
  • 移动开发
  • 音视频

【免费下载链接】Seal

🦭 Video/Audio Downloader for Android, based on yt-dlp

项目地址:https://gitcode.com/gh_mirrors/se/Seal
点击查看免费下载

Seal 是一款面向 Android 的免费开源视频/音频下载应用,以 yt-dlp(阿塞拜疆语版 README,与 README.md 内容同源)为骨架,结合app/src/main/java/com/junkfood/seal/下的真实源码实现,系统讲解 Seal 的核心特性、底层调用链、下载参数细节与安装获取方式,帮助你理解其"yt-dlp 引擎 + 原生 Android 封装"的整体架构。

项目概览:为 yt-dlp 打造的原生 Android 前端

Seal 的定位十分明确:它是 yt-dlp 的GUI 前端(README 原文:Seal is a simple GUI of yt-dlp, based on youtubedl-android),本身并不实现站点解析逻辑,而是把 yt-dlp 的解析与下载能力完整封装进 Android 应用。技术底座由三部分构成:

  • yt-dlp:解析支持站点并执行下载的核心 CLI 工具;
  • youtubedl-android:将 yt-dlp 二进制与 JNI 绑定移植到 Android 的库(README 中列出的dvd亦为其配套项目);
  • 原生 Kotlin + Jetpack Compose:应用本体 UI 与业务逻辑。

这些依赖可以在 gradle/libs.versions.toml 中直接确认:youtubedl-android-library、youtubedl-android-ffmpeg、youtubedl-android-aria2c(版本 0.17.3),以及 Room 2.6.1、Koin 4.0.0、MMKV 1.3.12、Coil、kotlinx-serialization 等配套组件;settings.gradle.kts 则表明项目由app与color(Monet 动态取色库)两个模块组成。

应用启动时(App.kt),会在后台依次完成YoutubeDL.init、FFmpeg.init、Aria2c.init三个原生库的初始化,并在首次启动时把内置 WebView 的 Cookie 导出为 yt-dlp 可读的 Netscape 格式文件——这为后面讲解的"登录态下载"铺平了道路。

核心特性总览

README 开列的功能清单是本文的主体骨架,现将其逐项映射到源码实现,便于后续深入:

README 特性对应源码模块底层机制
从 yt-dlp 支持的平台下载视频/音频DownloadUtil.ktYoutubeDLRequest 组装 yt-dlp 参数并执行
为提取的音频嵌入元数据与封面addOptionsForAudioDownloads-x+--embed-metadata/--embed-thumbnail(依赖 mutagen 能力)
一键下载播放列表全部视频getPlaylistOrVideoInfo--flat-playlist/--playlist-items
使用内置 aria2c 作为外部下载器enableAria2c--downloader libaria2c.so
为下载的视频嵌入字幕addOptionsForVideoDownloads--write-subs/--embed-subs
用模板执行自定义 yt-dlp 命令CommandTemplate.kt--config-locations注入模板文件
应用内管理下载与自定义模板DownloaderV2.kt任务状态机 + Room 持久化
Material Design 3 动态配色 UITheme.kt 等DynamicColors + Monet 调色板
MAD:纯 Kotlin、单 Activity、无 FragmentMainActivity.ktCompose 可组合目的地路由

下面逐一展开。

下载引擎:多平台视频/音频抓取

DownloadUtil(DownloadUtil.kt)是整个下载能力的核心门面。它把所有 yt-dlp 参数封装为 Kotlin 对象,再通过YoutubeDL.getInstance().execute(...)提交给原生进程执行。

信息获取阶段

当用户粘贴链接后,应用先调用fetchVideoInfoFromUrl(DownloadUtil.kt#L140-L187)拉取视频元数据,其组装的关键参数包括:

  • -o %(title).200B:以标题作为临时输出名(BASENAME常量,截断 200 字符);
  • --dump-single-json:以 JSON 形式输出单视频完整信息;
  • --no-playlist:默认只解析当前视频;
  • -R 1与--socket-timeout 5:限制重试次数并设置网络超时;
  • 可选的-x(音频提取)、-S(格式排序)、--restrict-filenames(限制文件名字符集)等,取决于用户偏好;
  • 若目标在播放列表内且指定了索引,则改用--playlist-items <index>配合--dump-json。

返回的 JSON 被反序列化为 VideoInfo.kt 中定义的VideoInfo(含 title、duration、formats、thumbnail、subtitles、chapters、vcodec/acodec 等数十个字段),Format数据类还提供isAudioOnly()、containsVideo()等判定方法,供 UI 层区分"纯音频格式"与"视频格式"。

实际下载阶段

downloadVideo(DownloadUtil.kt#L660-L825)依据VideoInfo.vcodec == "none"判断走音频链路还是视频链路,并追加一整套参数:--no-mtime(不恢复文件时间戳)、--restrict-filenames、--proxy、-4(强制 IPv4)、-r <rate>K(限速)、-P(指定输出目录与临时目录)、-o(自定义输出模板)等。下载完成后还会通过MediaScannerConnection.scanFile通知系统媒体库,并把记录写入下载历史数据库。

音频提取与元数据/封面嵌入

README 明确列出:"将元数据和视频缩略图嵌入到 mutagen 支持的提取音频文件中"。这在源码中的落地是addOptionsForAudioDownloads(DownloadUtil.kt#L559-L626),核心参数为:

  • -x:仅提取音频;
  • --audio-format mp3|m4a:需要时转换容器格式;
  • --embed-metadata与--embed-thumbnail:把标题、艺术家、封面嵌入音频(底层依赖 mutagen 对音频标签的写入能力);
  • --convert-thumbnails jpg:统一封面编码;
  • --parse-metadata系列:把%(release_year,upload_date)s映射为meta_date、播放列表场景下把%(album,playlist,title)s映射为meta_album、%(track_number,playlist_index)d映射为meta_track,从而在批量下载时也能写全专辑/曲目信息;
  • 可选的封面裁剪:通过写入--ppa "ffmpeg: -c:v mjpeg -vf crop=..."配置裁剪正方形封面(CROP_ARTWORK_COMMAND)。

音频的输出命名同样支持模板,例如按章节拆分时使用chapter:%(title)/%(section_number)d - %(section_title).200B%(ext)s,或按 Clip 区间命名为%(title).200B [%(section_start)d-%(section_end)d]%(ext)s(见 DownloadUtil.kt#L62-L81)。

播放列表一键批量下载

对播放列表链接,getPlaylistOrVideoInfo(DownloadUtil.kt#L87-L126)以--flat-playlist模式快速枚举条目,并解析 JSON 判断返回PlaylistResult还是单视频VideoInfo。进入下载时,若downloadPlaylist开启,则通过--playlist-items <index>精确指定当前要下载的条目;配合subdirectoryPlaylistTitle选项,输出路径会追加%(playlist)s/前缀,实现"按播放列表标题分子目录存放"(PLAYLIST_TITLE_SUBDIRECTORY_PREFIX)。

aria2c 外部下载器

README 提到"将内置 aria2c 作为所有下载的外部下载器"。源码中enableAria2c(DownloadUtil.kt#L433-L434)只需一行核心参数:

this.addOption("--downloader", "libaria2c.so")

即以libaria2c.so作为 yt-dlp 的外部下载器进程。当未启用 aria2c 且设置了concurrentFragments > 1时,会退化为 yt-dlp 内置的--concurrent-fragments N(默认并发片段数为 8,见 PreferenceUtil.kt)。

字幕下载、转换与嵌入

字幕处理是下载偏好中的一组独立开关(downloadSubtitle、embedSubtitle、autoSubtitle等),对应参数组合为:

  • --write-subs:下载手动字幕;--write-auto-subs:下载自动生成字幕(可加--extractor-args "youtube:skip=translated_subs"跳过翻译字幕);
  • --sub-langs <lang>:限定语言,默认值为en.*,.*-orig;
  • --embed-subs:把字幕嵌入视频文件;保留原始字幕文件则叠加--write-subs;
  • --convert-subs ass|srt|vtt|lrc:按需转换字幕格式(对应CONVERT_ASS/LRC/SRT/VTT常量);
  • 当"下载字幕 + 嵌入字幕"或用户显式开启时,会追加--remux-video mkv与--merge-output-format mkv(mergeToMkv逻辑),因为 MKV 容器对字幕嵌入兼容性最好。

自定义 yt-dlp 命令模板

这是 README 中"用模板执行自定义 yt-dlp 命令"的实现。模板在数据库中是一张简单的表(CommandTemplate.kt):

@Entity @Serializable data class CommandTemplate( @PrimaryKey(autoGenerate = true) val id: Int, val name: String, val template: String, )

即每个模板 = 名称 + 一段 yt-dlp 参数文本。首次运行时若模板表为空,应用会自动写入一个示例模板--no-mtime -S "ext"(TEMPLATE_EXAMPLE,见 PreferenceUtil.kt#L181)。

执行模板时(executeCustomCommandTask,DownloadUtil.kt#L876-L914),应用会把模板内容写入临时配置文件,然后通过--config-locations <文件路径>注入 yt-dlp,并自动拼接--newline(逐行输出便于进度解析)、--downloader libaria2c.so、--download-archive(归档去重)、--restrict-filenames与 Cookie 参数。用户可将 URL 按换行/空格分隔批量执行,命令同样走任务队列并展示进度通知。

应用内下载任务管理:状态机与前台服务

README 承诺"应用内管理下载与自定义命令模板"。新一代下载管理由DownloaderV2Impl(DownloaderV2.kt)实现,其核心是一个任务状态机(Task.kt#L58-L119):

  • Idle→FetchingInfo→ReadyWithInfo→Running→Completed
  • 任何阶段可被用户打断为Canceled,出错进入Error,二者都保留action(FetchInfo / Download)以便一键重启。

调度器doYourWork(DownloaderV2.kt#L219-L236)维护MAX_CONCURRENCY = 3的并发上限,按状态优先级排序取出下一个任务:ReadyWithInfo直接进入下载,Idle则先抓取信息,CustomCommand类型任务则跳过信息抓取直接执行。

配套机制还包括:

  • 前台服务保活:任务开始/结束通过snapshotFlow驱动App.startService()/App.stopService()(DownloaderV2.kt#L101-L121),前台通知由 DownloadService.kt 承载;
  • 崩溃恢复:任务列表以 JSON 序列化备份到 MMKV(TASK_LIST键),应用重启时enqueueFromBackup会把中断中的任务重置为Canceled状态,等待用户手动重启;
  • 取消机制:cancelImpl通过YoutubeDL.destroyProcessById(taskId)直接销毁对应原生进程,再取消协程 Job。

Material Design 3 与 MAD 架构

README 最后两项特性强调 UI 采用Material Design 3 风格 + 动态颜色主题,架构遵循MAD(Modern Android Development):纯 Kotlin 编写 UI 与逻辑,单 Activity、无 Fragment、仅可组合目的地。

  • MainActivity.kt 是唯一的 Activity,onCreate中直接setContent { ... AppEntry(...) },并通过onNewIntent处理外部分享/打开链接(ACTION_VIEW/ACTION_SEND),自动弹出下载对话框;
  • 主题模块(theme/)提供SealTheme与深浅色、高对比度适配;
  • 动态取色通过DynamicColors.applyToActivitiesIfAvailable(App.kt#L84)与独立的color模块(Monet 实现)完成,支持 TonalSpot、Spritz、FruitSalad、Vibrant、Monochrome 五种调色板风格(paletteStyles,见 PreferenceUtil.kt#L188-L201)。

下图为应用的核心主界面,即输入链接、解析视频信息并发起下载的入口:

下载前参数配置弹窗则负责格式选择、字幕开关与播放列表选项:

安装与获取方式

README 的下载章节给出两条渠道,并强调:对大多数设备,推荐安装 arm64-v8a 版本的 APK:

  • GitHub Releases:获取最新稳定版;也可以安装预发布(pre-release)版本,帮助项目测试新功能与变更;
  • F-Droid:同步提供稳定版发布。

从仓库结构看,应用支持多种 ABI 构建(App.kt#L217 的崩溃报告中会输出Supported ABIs),arm64-v8a 对应绝大多数现代安卓手机。需要说明:本文所引用的安装渠道为 README 原文所述事实,具体下载请以对应平台页面为准。

参与贡献、翻译与社区

README 对社区参与有明确约定:

  • 贡献欢迎:可通过 Hosted Weblate 平台参与 Seal 的多语言翻译(仓库translations/目录下已包含阿塞拜疆语、简体中文、繁体中文、阿拉伯语、俄语等 20 余种语言的 README 译本,app/src/main/res/values-*下更有完整的 UI 字符串翻译);
  • 提交前指引:提交 Bug 报告、功能请求或改进建议前,应先阅读 CONTRIBUTING.md 了解规范与指引;
  • 社区渠道:项目维护有 Telegram 频道与 Matrix 空间用于讨论、公告与发布通知。

许可证与商标条款

项目采用GPLv3许可证(LICENSE),README 额外给出了一条重要的商标式限制条款:

除按 GPLv3 许可证授权的源码之外,禁止任何其他方以 "Seal" 的名义使用其作为下载器应用,该限制同样适用于 Seal 的衍生项目(衍生项目包括但不限于 fork 与非官方构建)。

这意味着:第三方可以依据 GPLv3 修改和分发源码,但不能使用 Seal 的名称来包装发布下载器应用。

致谢与依赖底座

README 的 Credits 章节披露了项目的技术渊源:Seal 基于youtubedl-android构建 yt-dlp 的 GUI,部分 UI 设计与代码借鉴自Read You与Music You两个开源项目,并使用了dvd、Material color utilities与Monet等组件(color模块即 Monet 的仓库内实现)。这些依赖共同构成了 Seal "下载引擎移植 + 现代 Android UI" 的双层结构,也解释了为何它能在保持 yt-dlp 全部能力的同时,提供流畅的 Material 3 原生体验。

小结

通过 README 与源码的对照可以看到,Seal 的价值在于把 yt-dlp 的庞大参数体系收敛成一套直观的 Android 图形界面:信息抓取、格式选择、音频提取、播放列表、字幕、aria2c 加速、自定义命令模板与任务恢复机制,全部围绕DownloadUtil与DownloaderV2两个核心模块组织。对于希望研究"如何把 CLI 下载工具封装为现代 Android 应用"的开发者,DownloadUtil.kt 与 DownloaderV2.kt 是两份值得精读的参考实现。

  • 移动开发
  • 音视频

【免费下载链接】Seal

🦭 Video/Audio Downloader for Android, based on yt-dlp

项目地址:https://gitcode.com/gh_mirrors/se/Seal
点击查看免费下载

相关推荐

上一篇:终极指南:如何用QKeyMapper实现Windows键鼠手柄专业映射
下一篇:WaveTools终极指南:一键解锁《鸣潮》120FPS高帧率体验

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 2:17:47

局域网试题及答案:网工基础自测题库与eNSP实战验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 2:17:43

wiliwili 完整指南:手柄用户的多平台第三方B站客户端

wiliwili 完整指南&#xff1a;手柄用户的多平台第三方B站客户端 【免费下载链接】wiliwili 第三方B站客户端&#xff0c;目前可以运行在PC全平台、PSVita、PS4 、Xbox 和 Nintendo Switch上 项目地址: https://gitcode.com/GitHub_Trending/wi/wiliwili 打开游戏机&…

作者头像 李华
网站建设 2026/9/30 2:13:33

HPC集群架构选型与落地实践:从Cluster到IB网络的完整解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华