Erfan commited on
Commit
b73f3ca
·
1 Parent(s): 7b04a3b

fix: use pytubefix primary, yt-dlp fallback

Browse files
Files changed (2) hide show
  1. bot/youtube.py +55 -23
  2. requirements.txt +1 -0
bot/youtube.py CHANGED
@@ -8,19 +8,6 @@ os.makedirs(DOWNLOAD_DIR, exist_ok=True)
8
  COOKIES_FILE = os.path.join(DATA_DIR, "cookies.txt")
9
 
10
 
11
- def _get_ydl_opts(format_spec: str):
12
- opts = {
13
- "format": format_spec,
14
- "outtmpl": os.path.join(DOWNLOAD_DIR, f"{uuid.uuid4()}.%(ext)s"),
15
- "quiet": True,
16
- "no_warnings": True,
17
- "extractor_args": {"youtube": {"player_client": ["web"]}},
18
- }
19
- if os.path.exists(COOKIES_FILE):
20
- opts["cookiefile"] = COOKIES_FILE
21
- return opts
22
-
23
-
24
  def _find_downloaded_file():
25
  for f in os.listdir(DOWNLOAD_DIR):
26
  p = os.path.join(DOWNLOAD_DIR, f)
@@ -30,27 +17,72 @@ def _find_downloaded_file():
30
 
31
 
32
  async def get_video_info(url: str):
33
- ydl_opts = _get_ydl_opts("best")
34
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
35
- info = ydl.extract_info(url, download=False)
36
  return {
37
- "title": info.get("title", "Unknown"),
38
- "duration": info.get("duration", 0),
39
- "thumbnail": info.get("thumbnail", ""),
40
  "url": url,
41
  }
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
 
44
  async def download_yt(url: str, quality: str = "audio"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  if quality == "audio":
46
- formats = ["bestaudio[ext=m4a]", "bestaudio", "best"]
47
  else:
48
- formats = ["bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"]
49
 
50
  for fmt in formats:
51
  try:
52
- opts = _get_ydl_opts(fmt)
53
- opts["merge_output_format"] = "mp4"
 
 
 
 
 
 
 
54
  with yt_dlp.YoutubeDL(opts) as ydl:
55
  info = ydl.extract_info(url, download=True)
56
  file_path = ydl.prepare_filename(info)
 
8
  COOKIES_FILE = os.path.join(DATA_DIR, "cookies.txt")
9
 
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  def _find_downloaded_file():
12
  for f in os.listdir(DOWNLOAD_DIR):
13
  p = os.path.join(DOWNLOAD_DIR, f)
 
17
 
18
 
19
  async def get_video_info(url: str):
20
+ try:
21
+ from pytubefix import YouTube
22
+ yt = YouTube(url)
23
  return {
24
+ "title": yt.title,
25
+ "duration": yt.length,
26
+ "thumbnail": yt.thumbnail_url,
27
  "url": url,
28
  }
29
+ except Exception:
30
+ ydl_opts = {"quiet": True, "no_warnings": True}
31
+ if os.path.exists(COOKIES_FILE):
32
+ ydl_opts["cookiefile"] = COOKIES_FILE
33
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
34
+ info = ydl.extract_info(url, download=False)
35
+ return {
36
+ "title": info.get("title", "Unknown"),
37
+ "duration": info.get("duration", 0),
38
+ "thumbnail": info.get("thumbnail", ""),
39
+ "url": url,
40
+ }
41
 
42
 
43
  async def download_yt(url: str, quality: str = "audio"):
44
+ try:
45
+ from pytubefix import YouTube
46
+ from pytubefix.cli import on_progress
47
+
48
+ yt = YouTube(url, on_progress_callback=on_progress)
49
+
50
+ if quality == "audio":
51
+ stream = yt.streams.filter(only_audio=True).first()
52
+ elif quality == "720p":
53
+ stream = yt.streams.filter(res="720p").first() or yt.streams.filter(res="480p").first() or yt.streams.get_highest_resolution()
54
+ elif quality == "1080p":
55
+ stream = yt.streams.filter(res="1080p").first() or yt.streams.get_highest_resolution()
56
+ else:
57
+ stream = yt.streams.get_highest_resolution()
58
+
59
+ if stream:
60
+ file_path = stream.download(output_path=DOWNLOAD_DIR)
61
+ return file_path, yt.title
62
+ except Exception as e:
63
+ print(f"[youtube] pytubefix failed: {e}")
64
+
65
+ print("[youtube] Falling back to yt-dlp...")
66
+ return await _download_ytdlp(url, quality)
67
+
68
+
69
+ async def _download_ytdlp(url: str, quality: str = "audio"):
70
  if quality == "audio":
71
+ formats = ["bestaudio", "best"]
72
  else:
73
+ formats = ["best", "worst"]
74
 
75
  for fmt in formats:
76
  try:
77
+ opts = {
78
+ "format": fmt,
79
+ "outtmpl": os.path.join(DOWNLOAD_DIR, f"{uuid.uuid4()}.%(ext)s"),
80
+ "quiet": True,
81
+ "no_warnings": True,
82
+ "extractor_args": {"youtube": {"player_client": ["web"]}},
83
+ }
84
+ if os.path.exists(COOKIES_FILE):
85
+ opts["cookiefile"] = COOKIES_FILE
86
  with yt_dlp.YoutubeDL(opts) as ydl:
87
  info = ydl.extract_info(url, download=True)
88
  file_path = ydl.prepare_filename(info)
requirements.txt CHANGED
@@ -3,6 +3,7 @@ uvicorn[standard]>=0.23.0
3
  httpx>=0.25.0
4
  aiosqlite>=0.19.0
5
  yt-dlp>=2024.0.0
 
6
  openai>=1.0.0
7
  python-multipart>=0.0.6
8
  jinja2>=3.1.0
 
3
  httpx>=0.25.0
4
  aiosqlite>=0.19.0
5
  yt-dlp>=2024.0.0
6
+ pytubefix>=7.0.0
7
  openai>=1.0.0
8
  python-multipart>=0.0.6
9
  jinja2>=3.1.0