Format conversion pipeline (Tartube parity 1.7)
Post-download ffmpeg pass with three modes, global + per-channel. Closes the last real Tartube parity gap. ## Modes - remux-mp4: fast container change mkv→mp4 (stream-copy video, aac audio) - h264-mp4: re-encode to H.264/AAC at a configurable CRF + x264 preset - audio: extract to mp3 / m4a / opus / flac ## Design (separate ffmpeg pass) The main download adds `--print after_move:CONVERT_PATH:%(filepath)s` when conversion is active. poll() scans freshly-Done download jobs for those lines and enqueues a distinct ffmpeg transcode Job per finished file — so the UI shows transcoding as its own phase. On success the source is renamed to <name>.original.<ext> (keep_original) or deleted; the converted file lands next to it. Transcodes don't auto-retry and don't themselves convert (no infinite loop). ## Config New [convert] section (mode / crf / preset / audio_format / keep_original) + per-channel DownloadOptions.convert_mode override (None = defer to global, "off" = force-disable for that channel). ConvertSpec::resolve merges them; CRF 0→23, empty preset→medium, empty audio→mp3 defaults. ## UI Desktop + web: a "Format conversion (global defaults)" Settings section with mode-dependent rows (CRF/preset for h264, format for audio, keep- original toggle), and a per-channel Convert dropdown in the channel- options dialog. Verified: all three ffmpeg modes produce valid output on a real library file (remux instant, h264 CRF23 ~12s for a 3.4min clip, mp3 extraction); settings round-trip (global → config.toml [convert] → echo; per-channel override saves + reads back). 4 resolver tests; 95 pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
b58d393d98
commit
fd9063b5cb
6 changed files with 534 additions and 9 deletions
|
|
@ -22,6 +22,38 @@ pub struct Config {
|
|||
pub plex: PlexSection,
|
||||
#[serde(default)]
|
||||
pub subtitles: SubtitlesSection,
|
||||
#[serde(default)]
|
||||
pub convert: ConvertSection,
|
||||
}
|
||||
|
||||
/// `[convert]` table — global post-download format-conversion defaults.
|
||||
/// A separate ffmpeg pass runs after the download completes. Per-channel
|
||||
/// [`crate::download_options::DownloadOptions`] can override `mode`.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
pub struct ConvertSection {
|
||||
/// What to do after download. One of:
|
||||
/// - `""` / `"off"`: nothing (keep the downloaded mkv as-is).
|
||||
/// - `"remux-mp4"`: fast container change mkv→mp4, no re-encode.
|
||||
/// - `"h264-mp4"`: re-encode video to H.264/AAC mp4 at [`Self::crf`].
|
||||
/// - `"audio"`: extract audio to [`Self::audio_format`].
|
||||
#[serde(default)]
|
||||
pub mode: String,
|
||||
/// CRF for `h264-mp4` (0–51; lower = bigger/better). 23 is a sane
|
||||
/// default if left at 0.
|
||||
#[serde(default)]
|
||||
pub crf: u8,
|
||||
/// x264 preset for `h264-mp4` (ultrafast…veryslow). Empty = "medium".
|
||||
#[serde(default)]
|
||||
pub preset: String,
|
||||
/// Audio format for `audio` mode (mp3 / m4a / opus / flac). Empty =
|
||||
/// "mp3".
|
||||
#[serde(default)]
|
||||
pub audio_format: String,
|
||||
/// Keep the original downloaded file alongside the converted one
|
||||
/// (renamed to `<stem>.original.<ext>`). When false, the original is
|
||||
/// deleted after a successful convert.
|
||||
#[serde(default)]
|
||||
pub keep_original: bool,
|
||||
}
|
||||
|
||||
/// `[subtitles]` table — global subtitle download defaults. Per-channel
|
||||
|
|
@ -230,6 +262,7 @@ impl Config {
|
|||
web: WebSection::default(),
|
||||
plex: PlexSection::default(),
|
||||
subtitles: SubtitlesSection::default(),
|
||||
convert: ConvertSection::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue