Erfan commited on
Commit
0e4bd6e
·
1 Parent(s): ad6c7a2

fix: multiple format attempts per yt-dlp client + ytdl.ga API fallback

Browse files

- Fix 'Requested format not available' by trying 3 format strings per client
- Use bv*+ba/b (best video+audio merge) as primary format
- Add ytdl.ga and najemi.cz PHP API endpoints as fallback
- Prioritize yt-dlp (with cookies) then ytdl.ga then rest

Files changed (1) hide show
  1. bot/youtube.py +68 -23
bot/youtube.py CHANGED
@@ -170,35 +170,76 @@ def _has_cookies() -> bool:
170
 
171
  async def _try_ytdlp(url: str, quality: str = "audio"):
172
  if quality == "audio":
173
- fmt = "bestaudio"
 
 
 
 
174
  else:
175
- fmt = "best"
176
  clients = ["android_embedded", "android", "web", "tv", "ios", "web_creator", "music"]
177
  cookies = _has_cookies()
178
  for client in clients:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  try:
180
- _log(f"Trying yt-dlp client={client}{' (with cookies)' if cookies else ''}")
181
- opts = {
182
- "format": fmt,
183
- "outtmpl": os.path.join(DOWNLOAD_DIR, f"{uuid.uuid4()}.%(ext)s"),
184
- "quiet": True,
185
- "no_warnings": True,
186
- "extractor_args": {"youtube": {"player_client": [client]}},
187
- }
188
- if cookies:
189
- opts["cookiefile"] = COOKIES_FILE
190
- with yt_dlp.YoutubeDL(opts) as ydl:
191
- info = ydl.extract_info(url, download=True)
192
- file_path = ydl.prepare_filename(info)
193
- if os.path.exists(file_path):
194
- _log(f"SUCCESS via yt-dlp client={client}")
195
- return file_path, info.get("title", "video")
196
- found = _find_downloaded_file()
197
- if found:
198
- _log(f"SUCCESS via yt-dlp client={client}")
199
- return found, info.get("title", "video")
 
 
 
200
  except Exception as e:
201
- _log(f"yt-dlp client={client} failed: {e}")
202
  return None, None
203
 
204
 
@@ -229,6 +270,10 @@ async def download_yt(url: str, quality: str = "audio"):
229
  if result[0]:
230
  return result
231
 
 
 
 
 
232
  result = await _try_piped(url, quality)
233
  if result[0]:
234
  return result
 
170
 
171
  async def _try_ytdlp(url: str, quality: str = "audio"):
172
  if quality == "audio":
173
+ formats = ["bestaudio/best", "bestaudio", "worstaudio"]
174
+ elif quality == "1080p":
175
+ formats = ["bv*[height<=1080]+ba/b[height<=1080]", "bestvideo[height<=1080]+bestaudio/best[height<=1080]", "best[height<=1080]"]
176
+ elif quality == "720p":
177
+ formats = ["bv*[height<=720]+ba/b[height<=720]", "bestvideo[height<=720]+bestaudio/best[height<=720]", "best[height<=720]"]
178
  else:
179
+ formats = ["bv*+ba/b", "bestvideo+bestaudio/best", "best"]
180
  clients = ["android_embedded", "android", "web", "tv", "ios", "web_creator", "music"]
181
  cookies = _has_cookies()
182
  for client in clients:
183
+ for fmt in formats:
184
+ try:
185
+ _log(f"Trying yt-dlp client={client} fmt={fmt}{' (with cookies)' if cookies else ''}")
186
+ opts = {
187
+ "format": fmt,
188
+ "outtmpl": os.path.join(DOWNLOAD_DIR, f"{uuid.uuid4()}.%(ext)s"),
189
+ "quiet": True,
190
+ "no_warnings": True,
191
+ "extractor_args": {"youtube": {"player_client": [client]}},
192
+ }
193
+ if cookies:
194
+ opts["cookiefile"] = COOKIES_FILE
195
+ with yt_dlp.YoutubeDL(opts) as ydl:
196
+ info = ydl.extract_info(url, download=True)
197
+ file_path = ydl.prepare_filename(info)
198
+ if os.path.exists(file_path):
199
+ _log(f"SUCCESS via yt-dlp client={client} fmt={fmt}")
200
+ return file_path, info.get("title", "video")
201
+ found = _find_downloaded_file()
202
+ if found:
203
+ _log(f"SUCCESS via yt-dlp client={client} fmt={fmt}")
204
+ return found, info.get("title", "video")
205
+ except Exception as e:
206
+ _log(f"yt-dlp client={client} fmt={fmt} failed: {e}")
207
+ return None, None
208
+
209
+
210
+ async def _try_ytdlp_ga(url: str, quality: str = "audio"):
211
+ _log("Trying ytdl.ga API...")
212
+ endpoints = [
213
+ "https://ytdl.ga/handler.php",
214
+ "https://najemi.cz/ytdl/handler.php",
215
+ ]
216
+ for endpoint in endpoints:
217
  try:
218
+ async with httpx.AsyncClient(timeout=30, follow_redirects=True) as client:
219
+ r = await client.get(endpoint, params={"url": url})
220
+ if r.status_code != 200:
221
+ _log(f"ytdl.ga {endpoint} returned {r.status_code}")
222
+ continue
223
+ data = r.json() if r.headers.get("content-type", "").startswith("application/json") else r.text
224
+ if isinstance(data, dict):
225
+ dl_url = data.get("url") or data.get("download") or data.get("link")
226
+ else:
227
+ dl_url = str(data).strip()
228
+ if not dl_url or dl_url == url:
229
+ continue
230
+ ext = ".mp4"
231
+ if quality == "audio":
232
+ ext = ".mp3"
233
+ filename = f"{uuid.uuid4()}{ext}"
234
+ filepath = os.path.join(DOWNLOAD_DIR, filename)
235
+ r2 = await client.get(dl_url, follow_redirects=True, timeout=120)
236
+ if r2.status_code == 200:
237
+ with open(filepath, "wb") as f:
238
+ f.write(r2.content)
239
+ _log(f"SUCCESS via ytdl.ga ({endpoint})")
240
+ return filepath, "YouTube Video"
241
  except Exception as e:
242
+ _log(f"ytdl.ga {endpoint} failed: {e}")
243
  return None, None
244
 
245
 
 
270
  if result[0]:
271
  return result
272
 
273
+ result = await _try_ytdlp_ga(url, quality)
274
+ if result[0]:
275
+ return result
276
+
277
  result = await _try_piped(url, quality)
278
  if result[0]:
279
  return result