yt_dlp/metadata/mod.rs
1//! Metadata management module for downloaded files.
2//!
3//! This module provides functionality to add metadata to downloaded files,
4//! such as title, artist, album, genre, technical information, and thumbnails.
5//!
6//! ## Supported Formats
7//!
8//! - **MP3**: Title, artist, comment, genre (from tags), release year
9//! - **M4A**: Title, artist, comment, genre (from tags), release year
10//! - **MP4**: All basic metadata, plus technical information (resolution, FPS, video codec, video bitrate, audio codec, audio bitrate, audio channels, sample rate)
11//! - **WebM**: All basic metadata (via Matroska format), plus technical information as with MP4
12//! - **FLAC**: Title, artist, album, genre, date, description (via Vorbis comments through lofty), thumbnail embedding
13//! - **OGG/Opus**: Title, artist, album, genre, date, description (via Vorbis comments through lofty)
14//! - **WAV**: Title, artist, album, genre (via RIFF INFO through lofty)
15//! - **AAC**: Title, artist, album, genre, date (via ID3v2 through lofty)
16//! - **AIFF**: Title, artist, album, genre, date (via ID3v2 through lofty)
17//! - **AVI/TS/FLV**: Basic metadata via FFmpeg fallback
18//!
19//! ## Intelligent Metadata Management
20//!
21//! The system intelligently manages metadata application:
22//!
23//! - **Standalone files** (audio or audio+video): Metadata applied immediately during download
24//! - **Separate streams** (to be combined later): NO metadata applied to avoid redundant work
25//! - **Combined files**: Complete metadata applied to final file, including info from both streams
26
27use std::path::PathBuf;
28
29use crate::error::Result;
30
31pub mod api;
32pub mod base;
33pub mod chapters;
34pub mod postprocess;
35pub mod writers;
36
37// Re-export the trait
38pub use base::BaseMetadata;
39
40/// Playlist metadata information for embedding in video files.
41#[derive(Debug, Clone)]
42pub struct PlaylistMetadata {
43 /// The playlist title/name
44 pub title: String,
45 /// The playlist ID
46 pub id: String,
47 /// The track number/index in the playlist (1-based)
48 pub index: usize,
49 /// Total number of tracks in the playlist (optional)
50 pub total: Option<usize>,
51}
52
53/// Metadata manager for handling file metadata.
54///
55/// This manager provides methods to add metadata and thumbnails to downloaded files
56/// in various formats (MP3, M4A, MP4, WebM, MKV, etc.).
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct MetadataManager {
59 /// Path to ffmpeg executable
60 ffmpeg_path: PathBuf,
61}
62
63impl MetadataManager {
64 /// Create a new MetadataManager with default ffmpeg path.
65 ///
66 /// The default ffmpeg path is "ffmpeg" unless overridden by the `FFMPEG_PATH`
67 /// environment variable.
68 ///
69 /// # Returns
70 ///
71 /// A new MetadataManager instance
72 pub fn new() -> Self {
73 let ffmpeg_path = Self::default_ffmpeg_path();
74
75 tracing::debug!(
76 ffmpeg_path = ?ffmpeg_path,
77 "⚙️ Creating new MetadataManager"
78 );
79
80 Self { ffmpeg_path }
81 }
82
83 /// Create a new MetadataManager with custom ffmpeg path.
84 ///
85 /// # Arguments
86 ///
87 /// * `ffmpeg_path` - Path to the ffmpeg executable
88 ///
89 /// # Returns
90 ///
91 /// A new MetadataManager instance with custom ffmpeg path
92 pub fn with_ffmpeg_path(ffmpeg_path: impl Into<PathBuf>) -> Self {
93 let ffmpeg_path = ffmpeg_path.into();
94
95 tracing::debug!(
96 ffmpeg_path = ?ffmpeg_path,
97 "⚙️ Creating MetadataManager with custom ffmpeg path"
98 );
99
100 Self { ffmpeg_path }
101 }
102
103 /// Get the default ffmpeg path.
104 ///
105 /// Can be overridden via the `FFMPEG_PATH` environment variable.
106 ///
107 /// # Returns
108 ///
109 /// PathBuf to the ffmpeg executable
110 pub(crate) fn default_ffmpeg_path() -> PathBuf {
111 std::env::var("FFMPEG_PATH")
112 .map(|path| {
113 tracing::debug!(
114 ffmpeg_path = %path,
115 "⚙️ Using ffmpeg path from FFMPEG_PATH environment variable"
116 );
117 PathBuf::from(path)
118 })
119 .unwrap_or_else(|_| {
120 tracing::debug!("⚙️ Using default ffmpeg path");
121 PathBuf::from("ffmpeg")
122 })
123 }
124
125 /// Get the file extension from a path.
126 ///
127 /// Delegates to [`crate::utils::fs::try_extension`].
128 pub(crate) fn get_file_extension(file_path: impl Into<PathBuf>) -> Result<String> {
129 crate::utils::fs::try_extension(&file_path.into())
130 }
131
132 /// Create a temporary output path for metadata processing.
133 ///
134 /// Delegates to [`crate::utils::fs::create_temp_path`].
135 pub(crate) fn create_temp_output_path(
136 file_path: impl Into<PathBuf>,
137 file_format: &str,
138 ) -> crate::error::Result<PathBuf> {
139 Ok(crate::utils::fs::create_temp_path(&file_path.into(), file_format))
140 }
141}
142
143impl Default for MetadataManager {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149impl BaseMetadata for MetadataManager {}