1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::path::PathBuf;
4
5use crate::platforms::Platform;
6use tokio_util::sync::CancellationToken;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct MediaInfo {
10 pub title: String,
11 pub author: String,
12 pub platform: String,
13 pub duration_seconds: Option<f64>,
14 pub thumbnail_url: Option<String>,
15 pub available_qualities: Vec<VideoQuality>,
16 pub media_type: MediaType,
17 pub file_size_bytes: Option<u64>,
18}
19
20impl MediaInfo {
21 pub fn get_closest_quality(&self, wanted_quality: &str) -> Option<&VideoQuality> {
22 if self.available_qualities.is_empty() {
23 return None;
24 }
25 if wanted_quality == "best" || wanted_quality == "highest" {
26 return self.available_qualities.first();
27 }
28
29 let target_height = match wanted_quality
30 .to_lowercase()
31 .trim_end_matches('p')
32 .parse::<u32>()
33 {
34 Ok(h) => h,
35 Err(_) => return self.available_qualities.first(),
36 };
37
38 let mut closest = &self.available_qualities[0];
39 let mut min_diff = (closest.height as i32 - target_height as i32).abs() as u32;
40
41 for q in &self.available_qualities {
42 let diff = (q.height as i32 - target_height as i32).abs() as u32;
43 if diff < min_diff {
44 min_diff = diff;
45 closest = q;
46 }
47 }
48
49 Some(closest)
50 }
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
54pub enum MediaType {
55 Video,
56 Audio,
57 Photo,
58 Gif,
59 Carousel,
60 Playlist,
61 Course,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct VideoQuality {
66 pub label: String,
67 pub width: u32,
68 pub height: u32,
69 pub url: String,
70 pub format: String,
71 #[serde(default)]
72 pub filesize_bytes: Option<u64>,
73}
74
75#[derive(Clone)]
76pub struct DownloadOptions {
77 pub quality: Option<String>,
78 pub output_dir: PathBuf,
79 pub filename_template: Option<String>,
80 pub download_subtitles: bool,
81 pub include_auto_subtitles: bool,
82 pub download_mode: Option<String>,
83 pub format_id: Option<String>,
84 pub referer: Option<String>,
85 pub extra_headers: Option<HashMap<String, String>>,
86 pub page_url: Option<String>,
87 pub user_agent: Option<String>,
88 pub cancel_token: CancellationToken,
89 pub concurrent_fragments: u32,
90 pub ytdlp_path: Option<PathBuf>,
91 pub torrent_listen_port: Option<u16>,
92 pub torrent_id_slot: Option<std::sync::Arc<tokio::sync::Mutex<Option<usize>>>>,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct FormatInfo {
97 pub format_id: String,
98 pub ext: String,
99 pub resolution: Option<String>,
100 pub width: Option<u32>,
101 pub height: Option<u32>,
102 pub fps: Option<f64>,
103 pub vcodec: Option<String>,
104 pub acodec: Option<String>,
105 pub filesize: Option<u64>,
106 pub tbr: Option<f64>,
107 pub has_video: bool,
108 pub has_audio: bool,
109 pub format_note: Option<String>,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct DownloadResult {
114 pub file_path: PathBuf,
115 pub file_size_bytes: u64,
116 pub duration_seconds: f64,
117 #[serde(default)]
119 pub torrent_id: Option<usize>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct MediaItem {
124 pub url: String,
125 pub media_type: MediaType,
126 pub thumbnail_url: Option<String>,
127 pub width: Option<u32>,
128 pub height: Option<u32>,
129 pub duration_seconds: Option<f64>,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct GenericDownloadResult {
134 pub platform: Platform,
135 pub title: String,
136 pub author: String,
137 pub files: Vec<DownloadedFile>,
138 pub total_bytes: u64,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct DownloadedFile {
143 pub path: PathBuf,
144 pub media_type: MediaType,
145 pub size_bytes: u64,
146}