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}