recycleactor commited on
Commit
1feb804
·
verified ·
1 Parent(s): 6e039bb

Upload soundcloud.rs

Browse files
Files changed (1) hide show
  1. src/soundcloud.rs +68 -11
src/soundcloud.rs CHANGED
@@ -134,10 +134,49 @@ pub async fn download(Query(params): Query<DownloadParams>) -> impl IntoResponse
134
  let quality = params.quality.as_deref().unwrap_or("best");
135
 
136
  // Формируем аргументы для yt-dlp
 
137
  let format_arg = match quality {
138
- "256" => "bestaudio[abr<=256]",
139
- "128" => "bestaudio[abr<=128]",
140
- _ => "bestaudio",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  };
142
 
143
  // Скачиваем во временный файл БЕЗ конвертации - оригинальный формат
@@ -146,15 +185,19 @@ pub async fn download(Query(params): Query<DownloadParams>) -> impl IntoResponse
146
  .unwrap()
147
  .as_nanos());
148
 
 
 
 
149
  let output = match Command::new("yt-dlp")
150
  .args([
151
  "--quiet",
152
  "--no-warnings",
153
  "-f", format_arg,
154
- "-o", &temp_file,
 
155
  &params.url,
156
  ])
157
- .stdout(Stdio::null())
158
  .stderr(Stdio::piped())
159
  .output()
160
  .await
@@ -172,15 +215,22 @@ pub async fn download(Query(params): Query<DownloadParams>) -> impl IntoResponse
172
  return (StatusCode::INTERNAL_SERVER_ERROR, "Download failed").into_response();
173
  }
174
 
175
- // Находим скачанный файл (yt-dlp добавит расширение автоматически)
 
 
 
 
 
 
176
  let actual_file = if tokio::fs::metadata(&temp_file).await.is_ok() {
177
  temp_file.clone()
178
  } else {
179
- // Пробуем найти с расширением
180
  let mut found = None;
181
- for ext in &["m4a", "opus", "webm", "mp3", "aac"] {
182
  let path = format!("{}.{}", temp_file, ext);
183
  if tokio::fs::metadata(&path).await.is_ok() {
 
184
  found = Some(path);
185
  break;
186
  }
@@ -188,7 +238,7 @@ pub async fn download(Query(params): Query<DownloadParams>) -> impl IntoResponse
188
  match found {
189
  Some(p) => p,
190
  None => {
191
- tracing::error!("Could not find downloaded file");
192
  return (StatusCode::INTERNAL_SERVER_ERROR, "File not found").into_response();
193
  }
194
  }
@@ -293,14 +343,21 @@ pub async fn download(Query(params): Query<DownloadParams>) -> impl IntoResponse
293
 
294
  tracing::info!("Sending SoundCloud file: {} ({} bytes, {})", filename_safe, final_data.len(), final_content_type);
295
 
296
- axum::response::Response::builder()
297
  .status(200)
298
  .header("Content-Type", final_content_type)
299
  .header("Content-Length", final_data.len().to_string())
300
  .header("Content-Disposition", format!("inline; filename=\"{}\"", filename_safe))
301
  .header("Accept-Ranges", "bytes")
302
  .header("Access-Control-Allow-Origin", "*")
303
- .header("Cache-Control", "public, max-age=31536000")
 
 
 
 
 
 
 
304
  .body(axum::body::Body::from(final_data))
305
  .unwrap()
306
  .into_response()
 
134
  let quality = params.quality.as_deref().unwrap_or("best");
135
 
136
  // Формируем аргументы для yt-dlp
137
+ // Приоритизируем M4A/AAC (256kbps для Go+), затем MP3
138
  let format_arg = match quality {
139
+ "256" => "bestaudio[ext=m4a]/bestaudio[ext=aac]/bestaudio[abr<=256]/bestaudio",
140
+ "128" => "bestaudio[abr<=128]/bestaudio",
141
+ _ => "bestaudio[ext=m4a]/bestaudio[ext=aac]/bestaudio", // Приоритет M4A/AAC
142
+ };
143
+
144
+ tracing::info!("Using format selector: {}", format_arg);
145
+
146
+ // Сначала получаем информацию о доступных форматах для отладки
147
+ if let Ok(info_output) = Command::new("yt-dlp")
148
+ .args([
149
+ "--quiet",
150
+ "-F", // Показать все доступные форматы
151
+ &params.url,
152
+ ])
153
+ .output()
154
+ .await
155
+ {
156
+ let formats_info = String::from_utf8_lossy(&info_output.stdout);
157
+ tracing::info!("Available formats:\n{}", formats_info);
158
+ }
159
+
160
+ // Получаем URL thumbnail'а
161
+ let thumbnail_url = if let Ok(thumb_output) = Command::new("yt-dlp")
162
+ .args([
163
+ "--quiet",
164
+ "--no-warnings",
165
+ "--print", "%(thumbnail)s",
166
+ &params.url,
167
+ ])
168
+ .output()
169
+ .await
170
+ {
171
+ let thumb = String::from_utf8_lossy(&thumb_output.stdout).trim().to_string();
172
+ if !thumb.is_empty() && thumb.starts_with("http") {
173
+ tracing::info!("Found thumbnail: {}", thumb);
174
+ Some(thumb)
175
+ } else {
176
+ None
177
+ }
178
+ } else {
179
+ None
180
  };
181
 
182
  // Скачиваем во временный файл БЕЗ конвертации - оригинальный формат
 
185
  .unwrap()
186
  .as_nanos());
187
 
188
+ // Добавляем расширение .%(ext)s чтобы yt-dlp сам определил правильное расширение
189
+ let output_template = format!("{}.%(ext)s", temp_file);
190
+
191
  let output = match Command::new("yt-dlp")
192
  .args([
193
  "--quiet",
194
  "--no-warnings",
195
  "-f", format_arg,
196
+ "-o", &output_template,
197
+ "--no-post-overwrites", // Не перезаписываем после обработки
198
  &params.url,
199
  ])
200
+ .stdout(Stdio::piped())
201
  .stderr(Stdio::piped())
202
  .output()
203
  .await
 
215
  return (StatusCode::INTERNAL_SERVER_ERROR, "Download failed").into_response();
216
  }
217
 
218
+ // Логируем stdout чтобы увидеть что скачал yt-dlp
219
+ let stdout = String::from_utf8_lossy(&output.stdout);
220
+ if !stdout.is_empty() {
221
+ tracing::info!("yt-dlp stdout: {}", stdout);
222
+ }
223
+
224
+ // Находим скачанный файл (yt-dlp добавил расширение через .%(ext)s)
225
  let actual_file = if tokio::fs::metadata(&temp_file).await.is_ok() {
226
  temp_file.clone()
227
  } else {
228
+ // Пробуем найти с расширением - ВАЖНО: сначала ищем M4A/AAC, потом остальные
229
  let mut found = None;
230
+ for ext in &["m4a", "aac", "opus", "webm", "mp3"] {
231
  let path = format!("{}.{}", temp_file, ext);
232
  if tokio::fs::metadata(&path).await.is_ok() {
233
+ tracing::info!("Found downloaded file with extension: {}", ext);
234
  found = Some(path);
235
  break;
236
  }
 
238
  match found {
239
  Some(p) => p,
240
  None => {
241
+ tracing::error!("Could not find downloaded file with any extension");
242
  return (StatusCode::INTERNAL_SERVER_ERROR, "File not found").into_response();
243
  }
244
  }
 
343
 
344
  tracing::info!("Sending SoundCloud file: {} ({} bytes, {})", filename_safe, final_data.len(), final_content_type);
345
 
346
+ let mut response = axum::response::Response::builder()
347
  .status(200)
348
  .header("Content-Type", final_content_type)
349
  .header("Content-Length", final_data.len().to_string())
350
  .header("Content-Disposition", format!("inline; filename=\"{}\"", filename_safe))
351
  .header("Accept-Ranges", "bytes")
352
  .header("Access-Control-Allow-Origin", "*")
353
+ .header("Cache-Control", "public, max-age=31536000");
354
+
355
+ // Добавляем URL thumbnail'а в заголовок если есть
356
+ if let Some(thumb_url) = thumbnail_url {
357
+ response = response.header("X-Thumbnail-Url", thumb_url);
358
+ }
359
+
360
+ response
361
  .body(axum::body::Body::from(final_data))
362
  .unwrap()
363
  .into_response()