Skip to main content

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 {}