Skip to main content

yt_dlp/stats/
snapshot.rs

1use std::time::Duration;
2
3use crate::download::DownloadPriority;
4
5/// Aggregate snapshot of all statistics collected by the [`super::StatisticsTracker`].
6///
7/// Obtained by calling [`super::StatisticsTracker::snapshot`]. All fields are
8/// computed at the moment of the call; subsequent mutations to the tracker are not
9/// reflected in an already-obtained snapshot.
10#[derive(Debug, Clone, serde::Serialize)]
11pub struct GlobalSnapshot {
12    /// Download-level aggregate statistics.
13    pub downloads: DownloadStats,
14    /// Metadata fetch (video/playlist) aggregate statistics.
15    pub fetches: FetchStats,
16    /// Post-processing aggregate statistics.
17    pub post_processing: PostProcessStats,
18    /// Playlist-level aggregate statistics.
19    pub playlists: PlaylistStats,
20    /// Number of downloads currently in progress. Equivalent to `active_downloads.len()`.
21    pub active_count: usize,
22    /// Live state of every download currently in progress, ordered by download ID.
23    pub active_downloads: Vec<ActiveDownloadSnapshot>,
24    /// Bounded window of the most recently completed downloads.
25    pub recent_downloads: Vec<DownloadSnapshot>,
26}
27
28/// Aggregate counters and derived metrics for all download operations.
29#[derive(Debug, Clone, serde::Serialize)]
30pub struct DownloadStats {
31    /// Total number of downloads that were enqueued.
32    pub attempted: u64,
33    /// Completed downloads.
34    pub completed: u64,
35    /// Downloads that ended with an error.
36    pub failed: u64,
37    /// Downloads that were canceled.
38    pub canceled: u64,
39    /// Downloads currently waiting in the queue.
40    pub queued: u64,
41    /// Sum of bytes transferred across all completed downloads.
42    pub total_bytes: u64,
43    /// Total number of retry attempts across all downloads.
44    pub total_retries: u64,
45    /// Cumulative wall-clock time spent downloading (completed downloads only).
46    pub total_duration: Duration,
47    /// Average duration per completed download, or `None` if no downloads finished yet.
48    pub avg_duration: Option<Duration>,
49    /// Average throughput in bytes per second, or `None` if no data transferred.
50    pub avg_speed_bytes_per_sec: Option<f64>,
51    /// Highest per-download peak speed observed, in bytes per second.
52    pub peak_speed_bytes_per_sec: f64,
53    /// Ratio of completed to terminal downloads, or `None` if no terminal downloads.
54    pub success_rate: Option<f64>,
55}
56
57/// Live state of a single download that is currently in progress.
58#[derive(Debug, Clone, serde::Serialize)]
59pub struct ActiveDownloadSnapshot {
60    /// Internal download identifier.
61    pub download_id: u64,
62    /// URL being downloaded.
63    pub url: String,
64    /// Priority at which the download was queued.
65    pub priority: DownloadPriority,
66    /// Number of bytes received so far.
67    pub downloaded_bytes: u64,
68    /// Expected total size in bytes. `0` means the size is not yet known.
69    pub total_bytes: u64,
70    /// Download progress as a fraction in `[0.0, 1.0]`, or `None` if `total_bytes` is 0.
71    pub progress: Option<f64>,
72    /// Peak speed observed so far during this download, in bytes per second.
73    pub peak_speed_bytes_per_sec: f64,
74    /// Time elapsed since the download started transferring data.
75    /// `None` if the download is still waiting in the queue.
76    pub elapsed: Option<Duration>,
77    /// Total time elapsed since the download was enqueued (queue wait + transfer time).
78    pub time_since_queued: Duration,
79}
80
81/// Snapshot of a single completed (terminal) download.
82#[derive(Debug, Clone, serde::Serialize)]
83pub struct DownloadSnapshot {
84    /// Internal download identifier.
85    pub download_id: u64,
86    /// Original URL that was downloaded.
87    pub url: String,
88    /// Priority at which the download was queued.
89    pub priority: DownloadPriority,
90    /// Terminal outcome of this download.
91    pub outcome: DownloadOutcomeSnapshot,
92    /// Bytes transferred.
93    pub bytes: u64,
94    /// Wall-clock download duration, or `None` if it was canceled before starting.
95    pub duration: Option<Duration>,
96    /// Time spent waiting in the queue before the download started.
97    pub queue_wait: Option<Duration>,
98    /// Peak speed observed during this download, in bytes per second.
99    pub peak_speed_bytes_per_sec: f64,
100    /// Number of retry attempts for this download.
101    pub retry_count: u32,
102}
103
104/// Terminal outcome of a single completed download.
105#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde::Serialize)]
106pub enum DownloadOutcomeSnapshot {
107    /// Download finished successfully.
108    Completed,
109    /// Download ended with an error.
110    Failed,
111    /// Download was canceled by the user.
112    Canceled,
113}
114
115/// Aggregate statistics for metadata fetch operations (video and playlist).
116#[derive(Debug, Clone, serde::Serialize)]
117pub struct FetchStats {
118    /// Total number of fetch calls made.
119    pub attempted: u64,
120    /// Fetches that returned a result.
121    pub succeeded: u64,
122    /// Fetches that returned an error.
123    pub failed: u64,
124    /// Average duration of successful fetches, or `None` if none succeeded.
125    pub avg_duration: Option<Duration>,
126    /// Ratio of successful to total fetches, or `None` if no fetches attempted.
127    pub success_rate: Option<f64>,
128}
129
130/// Aggregate statistics for post-processing operations.
131#[derive(Debug, Clone, serde::Serialize)]
132pub struct PostProcessStats {
133    /// Number of post-processing operations started.
134    pub attempted: u64,
135    /// Operations that completed successfully.
136    pub succeeded: u64,
137    /// Operations that failed.
138    pub failed: u64,
139    /// Average duration of successful operations, or `None` if none succeeded.
140    pub avg_duration: Option<Duration>,
141    /// Ratio of succeeded to attempted, or `None` if no operations ran.
142    pub success_rate: Option<f64>,
143}
144
145/// Aggregate statistics for playlist-level operations.
146#[derive(Debug, Clone, serde::Serialize)]
147pub struct PlaylistStats {
148    /// Number of playlists whose metadata was successfully fetched.
149    pub playlists_fetched: u64,
150    /// Number of playlist metadata fetch failures.
151    pub playlists_fetch_failed: u64,
152    /// Number of individual playlist items that downloaded successfully.
153    pub items_successful: u64,
154    /// Number of individual playlist items that failed.
155    pub items_failed: u64,
156    /// Ratio of successful items to total items, or `None` if no items attempted.
157    pub item_success_rate: Option<f64>,
158}
159
160impl std::fmt::Display for GlobalSnapshot {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        write!(
163            f,
164            "GlobalSnapshot(active={}, downloads={}, fetches={}, playlists={})",
165            self.active_count, self.downloads, self.fetches, self.playlists
166        )
167    }
168}
169
170impl std::fmt::Display for DownloadStats {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        write!(
173            f,
174            "DownloadStats(attempted={}, completed={}, failed={})",
175            self.attempted, self.completed, self.failed
176        )
177    }
178}
179
180impl std::fmt::Display for ActiveDownloadSnapshot {
181    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182        write!(
183            f,
184            "ActiveDownloadSnapshot(id={}, downloaded={}, total={})",
185            self.download_id, self.downloaded_bytes, self.total_bytes
186        )
187    }
188}
189
190impl std::fmt::Display for DownloadSnapshot {
191    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192        write!(
193            f,
194            "DownloadSnapshot(id={}, outcome={}, bytes={})",
195            self.download_id, self.outcome, self.bytes
196        )
197    }
198}
199
200impl std::fmt::Display for DownloadOutcomeSnapshot {
201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202        match self {
203            Self::Completed => f.write_str("Completed"),
204            Self::Failed => f.write_str("Failed"),
205            Self::Canceled => f.write_str("Canceled"),
206        }
207    }
208}
209
210impl std::fmt::Display for FetchStats {
211    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212        write!(
213            f,
214            "FetchStats(attempted={}, succeeded={}, failed={})",
215            self.attempted, self.succeeded, self.failed
216        )
217    }
218}
219
220impl std::fmt::Display for PostProcessStats {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        write!(
223            f,
224            "PostProcessStats(attempted={}, succeeded={}, failed={})",
225            self.attempted, self.succeeded, self.failed
226        )
227    }
228}
229
230impl std::fmt::Display for PlaylistStats {
231    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232        write!(
233            f,
234            "PlaylistStats(fetched={}, items_ok={}, items_failed={})",
235            self.playlists_fetched, self.items_successful, self.items_failed
236        )
237    }
238}