Subtitle settings: global [subtitles] config + per-channel overrides
Adds full subtitle control (backend + desktop UI; web UI follows). ## Model - New [subtitles] config section: enabled / auto_generated / embed / format / langs. Sensible defaults (subs on, auto on, no embed/convert, all langs). - DownloadOptions gains per-channel Option overrides: subtitles_enabled, subtitles_auto, subtitles_embed, subtitle_format (subtitle_langs already existed). None = defer to global. ## Resolver - Downloader gains subtitle_defaults (the global section) + a single apply_subtitle_flags() that merges global + per-channel and emits the yt-dlp flags (--write-subs / --write-auto-subs / --sub-langs / --convert-subs / --embed-subs). Disabled = emit nothing. - Replaces the hardcoded --write-subs --write-auto-subs at the main download + repair builders. Moved the --sub-langs emission out of DownloadOptions::apply into the resolver so global + override merge in one place. ## Desktop UI - Settings screen: "Subtitles (global defaults)" section. - Channel-options dialog: tri-state (Default/On/Off) combos for each override + a convert-format field. ## Wiring - subtitle_defaults seeded at Downloader construction (app + web) and refreshed on settings save (desktop). 4 resolver tests cover global defaults, disabled, global format/embed/ langs, and per-channel override-wins. 84 pass. Web UI rows are the remaining piece (next commit). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
1e95102ec8
commit
0814ba0c3b
5 changed files with 282 additions and 23 deletions
|
|
@ -67,6 +67,24 @@ pub struct DownloadOptions {
|
|||
#[serde(default)]
|
||||
pub subtitle_langs: Vec<String>,
|
||||
|
||||
/// Per-channel subtitle overrides. Each `None` falls back to the
|
||||
/// global `[subtitles]` config. Resolved in [`crate::downloader`]'s
|
||||
/// subtitle-flag builder, not here, because `apply()` doesn't have
|
||||
/// the global config in scope.
|
||||
///
|
||||
/// - `subtitles_enabled`: master on/off for this channel.
|
||||
/// - `subtitles_auto`: include auto-generated captions.
|
||||
/// - `subtitles_embed`: embed into the container.
|
||||
/// - `subtitle_format`: convert to this format (empty string = native).
|
||||
#[serde(default)]
|
||||
pub subtitles_enabled: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub subtitles_auto: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub subtitles_embed: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub subtitle_format: Option<String>,
|
||||
|
||||
/// Raw passthrough — every entry is appended as a separate argument to
|
||||
/// yt-dlp. Lets users access any flag we haven't exposed yet. Equivalent
|
||||
/// to Tartube's `extra_cmd_string`.
|
||||
|
|
@ -131,9 +149,10 @@ impl DownloadOptions {
|
|||
cmd.arg("--match-filter").arg(filter);
|
||||
}
|
||||
}
|
||||
if !self.subtitle_langs.is_empty() {
|
||||
cmd.arg("--sub-langs").arg(self.subtitle_langs.join(","));
|
||||
}
|
||||
// Subtitle flags (langs / write / auto / embed / convert) are
|
||||
// emitted by the downloader's subtitle resolver, which merges
|
||||
// these per-channel overrides with the global [subtitles] config.
|
||||
// apply() handles everything else.
|
||||
for arg in &self.extra_args {
|
||||
if !arg.is_empty() {
|
||||
cmd.arg(arg);
|
||||
|
|
@ -189,17 +208,9 @@ mod tests {
|
|||
assert_eq!(args, vec!["--limit-rate", "500K"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtitle_langs_join_with_commas() {
|
||||
let mut cmd = Command::new("yt-dlp");
|
||||
DownloadOptions {
|
||||
subtitle_langs: vec!["en".into(), "ja".into(), "es".into()],
|
||||
..Default::default()
|
||||
}
|
||||
.apply(&mut cmd);
|
||||
let args: Vec<String> = cmd.get_args().map(|a| a.to_string_lossy().into_owned()).collect();
|
||||
assert_eq!(args, vec!["--sub-langs", "en,ja,es"]);
|
||||
}
|
||||
// Subtitle-flag emission moved to the downloader's resolver (it merges
|
||||
// these per-channel langs with the global [subtitles] config). The
|
||||
// resolver's behavior is tested in downloader.rs.
|
||||
|
||||
#[test]
|
||||
fn skip_auth_check_emits_extractor_arg() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue