yt_dlp/extractor/
generic.rs1use std::path::PathBuf;
7use std::time::Duration;
8
9use async_trait::async_trait;
10
11use crate::error::Result;
12use crate::extractor::{ExtractorBase, VideoExtractor};
13use crate::model::Video;
14use crate::model::playlist::Playlist;
15
16#[derive(Debug, Clone)]
21pub struct Generic {
22 executable_path: PathBuf,
23 extractor_name: Option<String>,
24 args: Vec<String>,
25 timeout: Duration,
26}
27
28crate::extractor::impl_extractor_config!(Generic);
29
30impl Generic {
31 pub fn new(executable_path: PathBuf) -> Self {
41 tracing::debug!(
42 executable = ?executable_path,
43 "⚙️ Creating new Generic extractor"
44 );
45
46 Self {
47 executable_path,
48 extractor_name: None,
49 args: Vec::new(),
50 timeout: crate::client::DEFAULT_TIMEOUT,
51 }
52 }
53
54 pub fn for_extractor(executable_path: PathBuf, name: String) -> Self {
65 tracing::debug!(
66 executable = ?executable_path,
67 extractor_name = name,
68 "⚙️ Creating Generic extractor for specific extractor"
69 );
70
71 Self {
72 executable_path,
73 extractor_name: Some(name),
74 args: Vec::new(),
75 timeout: crate::client::DEFAULT_TIMEOUT,
76 }
77 }
78
79 pub fn with_extractor_args(&mut self, extractor: &str, args: &str) -> &mut Self {
98 tracing::debug!(
99 extractor = extractor,
100 args = args,
101 "⚙️ Adding extractor-specific arguments"
102 );
103
104 self.args.push(format!("--extractor-args={}:{}", extractor, args));
105 self
106 }
107
108 pub fn with_credentials(&mut self, username: &str, password: &str) -> &mut Self {
131 tracing::debug!(
132 has_password = !password.is_empty(),
133 "⚙️ Adding credentials for authentication"
134 );
135 tracing::warn!(
136 "Credentials passed as CLI arguments are visible in process listings — consider using netrc or cookies instead"
137 );
138
139 self.args.push(format!("--username={}", username));
140 self.args.push(format!("--password={}", password));
141 self
142 }
143}
144
145#[async_trait]
146impl ExtractorBase for Generic {
147 fn executable_path(&self) -> PathBuf {
148 self.executable_path.clone()
149 }
150
151 fn timeout(&self) -> Duration {
152 self.timeout
153 }
154
155 fn build_base_args(&self) -> Vec<String> {
156 let mut args = vec!["--no-progress".to_string(), "--dump-single-json".to_string()];
157 args.extend(self.args.clone());
158 args
159 }
160}
161
162#[async_trait]
163impl VideoExtractor for Generic {
164 async fn fetch_video(&self, url: &str) -> Result<Video> {
165 tracing::debug!(
166 url = url,
167 extractor_name = ?self.extractor_name,
168 arg_count = self.args.len(),
169 "📡 Fetching video with Generic extractor"
170 );
171 self.log_and_fetch_video(url, "Generic").await
172 }
173
174 async fn fetch_playlist(&self, url: &str) -> Result<Playlist> {
175 tracing::debug!(
176 url = url,
177 extractor_name = ?self.extractor_name,
178 arg_count = self.args.len(),
179 "📡 Fetching playlist with Generic extractor"
180 );
181 self.log_and_fetch_playlist(url, "Generic").await
182 }
183
184 fn name(&self) -> crate::extractor::ExtractorName {
185 crate::extractor::ExtractorName::Generic(self.extractor_name.clone())
186 }
187
188 fn supports_url(&self, _url: &str) -> bool {
189 true
191 }
192}