dragonxd1 commited on
Commit
699b3e4
·
verified ·
1 Parent(s): 563ca88

Update DragMusic/platforms/Youtube.py

Browse files
Files changed (1) hide show
  1. DragMusic/platforms/Youtube.py +390 -132
DragMusic/platforms/Youtube.py CHANGED
@@ -1,16 +1,76 @@
1
  import asyncio
 
 
2
  import os
 
3
  import re
4
- import json
5
- import httpx # Make sure to import httpx
6
  from typing import Union
 
 
7
  import yt_dlp
8
  from pyrogram.enums import MessageEntityType
9
  from pyrogram.types import Message
10
- from youtubesearchpython.__future__ import VideosSearch
11
- from DragMusic.utils.database import is_on_off
12
- from DragMusic.utils.formatters import time_to_seconds
13
- import tempfile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  async def shell_cmd(cmd):
16
  proc = await asyncio.create_subprocess_shell(
@@ -26,6 +86,7 @@ async def shell_cmd(cmd):
26
  return errorz.decode("utf-8")
27
  return out.decode("utf-8")
28
 
 
29
  class YouTubeAPI:
30
  def __init__(self):
31
  self.base = "https://www.youtube.com/watch?v="
@@ -33,6 +94,49 @@ class YouTubeAPI:
33
  self.status = "https://www.youtube.com/oembed?url="
34
  self.listbase = "https://youtube.com/playlist?list="
35
  self.reg = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  async def exists(self, link: str, videoid: Union[bool, str] = None):
38
  if videoid:
@@ -71,16 +175,26 @@ class YouTubeAPI:
71
  link = self.base + link
72
  if "&" in link:
73
  link = link.split("&")[0]
74
- results = VideosSearch(link, limit=1)
75
- for result in (await results.next())["result"]:
76
- title = result["title"]
77
- duration_min = result["duration"]
78
- thumbnail = result["thumbnails"][0]["url"].split("?")[0]
79
- vidid = result["id"]
80
- if str(duration_min) == "None":
81
- duration_sec = 0
82
- else:
83
- duration_sec = int(time_to_seconds(duration_min))
 
 
 
 
 
 
 
 
 
 
84
  return title, duration_min, duration_sec, thumbnail, vidid
85
 
86
  async def title(self, link: str, videoid: Union[bool, str] = None):
@@ -88,38 +202,59 @@ class YouTubeAPI:
88
  link = self.base + link
89
  if "&" in link:
90
  link = link.split("&")[0]
91
- results = VideosSearch(link, limit=1)
92
- for result in (await results.next())["result"]:
93
- title = result["title"]
94
- return title
 
 
 
 
 
95
 
96
  async def duration(self, link: str, videoid: Union[bool, str] = None):
97
  if videoid:
98
  link = self.base + link
99
  if "&" in link:
100
  link = link.split("&")[0]
101
- results = VideosSearch(link, limit=1)
102
- for result in (await results.next())["result"]:
103
- duration = result["duration"]
104
- return duration
 
 
 
 
 
105
 
106
  async def thumbnail(self, link: str, videoid: Union[bool, str] = None):
107
  if videoid:
108
  link = self.base + link
109
  if "&" in link:
110
  link = link.split("&")[0]
111
- results = VideosSearch(link, limit=1)
112
- for result in (await results.next())["result"]:
113
- thumbnail = result["thumbnails"][0]["url"].split("?")[0]
114
- return thumbnail
 
 
 
 
 
115
 
116
  async def video(self, link: str, videoid: Union[bool, str] = None):
117
  if videoid:
118
  link = self.base + link
119
  if "&" in link:
120
  link = link.split("&")[0]
 
 
 
 
 
121
  proc = await asyncio.create_subprocess_exec(
122
  "yt-dlp",
 
123
  "-g",
124
  "-f",
125
  "best[height<=?720][width<=?1280]",
@@ -138,8 +273,12 @@ class YouTubeAPI:
138
  link = self.listbase + link
139
  if "&" in link:
140
  link = link.split("&")[0]
 
 
 
 
141
  playlist = await shell_cmd(
142
- f"yt-dlp -i --get-id --flat-playlist --playlist-end {limit} --skip-download {link}"
143
  )
144
  try:
145
  result = playlist.split("\n")
@@ -155,28 +294,34 @@ class YouTubeAPI:
155
  link = self.base + link
156
  if "&" in link:
157
  link = link.split("&")[0]
158
- results = VideosSearch(link, limit=1)
159
- for result in (await results.next())["result"]:
160
- title = result["title"]
161
- duration_min = result["duration"]
162
- vidid = result["id"]
163
- yturl = result["link"]
164
- thumbnail = result["thumbnails"][0]["url"].split("?")[0]
 
 
165
  track_details = {
166
- "title": title,
167
- "link": yturl,
168
- "vidid": vidid,
169
- "duration_min": duration_min,
170
- "thumb": thumbnail,
171
  }
172
- return track_details, vidid
173
 
174
  async def formats(self, link: str, videoid: Union[bool, str] = None):
175
  if videoid:
176
  link = self.base + link
177
  if "&" in link:
178
  link = link.split("&")[0]
179
- ytdl_opts = {"quiet": True}
 
 
 
 
180
  ydl = yt_dlp.YoutubeDL(ytdl_opts)
181
  with ydl:
182
  formats_available = []
@@ -207,39 +352,51 @@ class YouTubeAPI:
207
  )
208
  return formats_available, link
209
 
210
- async def slider(
211
- self,
212
- link: str,
213
- query_type: int,
214
- videoid: Union[bool, str] = None,
215
- ):
216
  if videoid:
217
  link = self.base + link
218
  if "&" in link:
219
  link = link.split("&")[0]
220
- a = VideosSearch(link, limit=10)
221
- result = (await a.next()).get("result")
222
- title = result[query_type]["title"]
223
- duration_min = result[query_type]["duration"]
224
- vidid = result[query_type]["id"]
225
- thumbnail = result[query_type]["thumbnails"][0]["url"].split("?")[0]
226
- return title, duration_min, thumbnail, vidid
227
-
228
- async def get_video_info_from_bitflow(self, url: str, video: bool):
229
- api_url = "https://bitflow.in/api/youtube"
230
- params = {
231
- "query": url,
232
- "format": "video" if video else "audio",
233
- "download": True,
234
- "api_key": "1spiderkey2"
235
- }
236
-
237
- async with httpx.AsyncClient() as client:
238
- response = await client.get(api_url, params=params, timeout=150)
239
- if response.status_code == 200:
240
- return response.json()
241
- else:
242
- return {"status": "error", "message": "Failed to fetch data from Bitflow API."}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
 
244
  async def download(
245
  self,
@@ -253,65 +410,164 @@ class YouTubeAPI:
253
  title: Union[bool, str] = None,
254
  ) -> str:
255
  if videoid:
 
256
  link = self.base + link
257
- if "&" in link:
258
- link = link.split("&")[0]
259
  loop = asyncio.get_running_loop()
260
- bitflow_info = await self.get_video_info_from_bitflow(link, video)
261
- def audio_dl(bitflow_info):
262
- temp_dir = tempfile.gettempdir()
263
- xyz = os.path.join(temp_dir, f"{bitflow_info['videoid']}.{bitflow_info['ext']}")
264
- url = bitflow_info['url']
265
- # If the url is not a YouTube link, download directly
266
- if not (url.startswith('http') and ('youtube.com' in url or 'youtu.be' in url)):
267
- import httpx
268
- with httpx.Client() as client:
269
- r = client.get(url)
270
- with open(xyz, "wb") as f:
271
- f.write(r.content)
272
- return xyz
273
- ydl_optssx = {
274
- "format": "bestaudio/best",
275
- "outtmpl": xyz,
276
- "geo_bypass": True,
277
- "nocheckcertificate": True,
278
  "quiet": True,
279
- "no_warnings": True,
280
- }
281
- x = yt_dlp.YoutubeDL(ydl_optssx)
282
- if os.path.exists(xyz):
283
- return xyz
284
- x.download([url])
285
- return xyz
286
- def video_dl(bitflow_info):
287
- temp_dir = tempfile.gettempdir()
288
- xyz = os.path.join(temp_dir, f"{bitflow_info['videoid']}.{bitflow_info['ext']}")
289
- url = bitflow_info['url']
290
- # If the url is not a YouTube link, download directly
291
- if not (url.startswith('http') and ('youtube.com' in url or 'youtu.be' in url)):
292
- import httpx
293
- with httpx.Client() as client:
294
- r = client.get(url)
295
- with open(xyz, "wb") as f:
296
- f.write(r.content)
297
- return xyz
298
- ydl_optssx = {
299
- "format": "(bestvideo[height<=?720][width<=?1280][ext=mp4])+(bestaudio[ext=m4a])",
300
- "outtmpl": xyz,
301
- "geo_bypass": True,
302
  "nocheckcertificate": True,
303
- "quiet": True,
304
- "no_warnings": True,
 
 
 
305
  }
306
- x = yt_dlp.YoutubeDL(ydl_optssx)
307
- if os.path.exists(xyz):
308
- return xyz
309
- x.download([url])
310
- return xyz
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  def song_video_dl():
312
- temp_dir = tempfile.gettempdir()
313
- fpath = os.path.join(temp_dir, f"{title}")
314
  formats = f"{format_id}+140"
 
315
  ydl_optssx = {
316
  "format": formats,
317
  "outtmpl": fpath,
@@ -319,14 +575,15 @@ class YouTubeAPI:
319
  "nocheckcertificate": True,
320
  "quiet": True,
321
  "no_warnings": True,
 
322
  "prefer_ffmpeg": True,
323
  "merge_output_format": "mp4",
324
  }
325
  x = yt_dlp.YoutubeDL(ydl_optssx)
326
  x.download([link])
 
327
  def song_audio_dl():
328
- temp_dir = tempfile.gettempdir()
329
- fpath = os.path.join(temp_dir, f"{title}.%(ext)s")
330
  ydl_optssx = {
331
  "format": format_id,
332
  "outtmpl": fpath,
@@ -334,6 +591,7 @@ class YouTubeAPI:
334
  "nocheckcertificate": True,
335
  "quiet": True,
336
  "no_warnings": True,
 
337
  "prefer_ffmpeg": True,
338
  "postprocessors": [
339
  {
@@ -345,20 +603,20 @@ class YouTubeAPI:
345
  }
346
  x = yt_dlp.YoutubeDL(ydl_optssx)
347
  x.download([link])
 
348
  if songvideo:
349
  await loop.run_in_executor(None, song_video_dl)
350
- temp_dir = tempfile.gettempdir()
351
- fpath = os.path.join(temp_dir, f"{title}.mp4")
352
  return fpath
353
  elif songaudio:
354
  await loop.run_in_executor(None, song_audio_dl)
355
- temp_dir = tempfile.gettempdir()
356
- fpath = os.path.join(temp_dir, f"{title}.mp3")
357
  return fpath
358
  elif video:
359
  direct = True
360
- downloaded_file = await loop.run_in_executor(None, video_dl, bitflow_info)
361
  else:
362
  direct = True
363
- downloaded_file = await loop.run_in_executor(None, audio_dl, bitflow_info)
 
364
  return downloaded_file, direct
 
1
  import asyncio
2
+ import glob
3
+ import json
4
  import os
5
+ import random
6
  import re
7
+ from concurrent.futures import ThreadPoolExecutor
 
8
  from typing import Union
9
+ import string
10
+ import requests
11
  import yt_dlp
12
  from pyrogram.enums import MessageEntityType
13
  from pyrogram.types import Message
14
+ from requests.adapters import HTTPAdapter
15
+ from urllib3.util.retry import Retry
16
+ from youtubesearchpython.__future__ import VideosSearch, CustomSearch
17
+ import base64
18
+ from AnonXMusic import LOGGER
19
+ from AnonXMusic.utils.database import is_on_off
20
+ from AnonXMusic.utils.formatters import time_to_seconds
21
+ from config import YT_API_KEY, YTPROXY_URL as YTPROXY
22
+
23
+ logger = LOGGER(__name__)
24
+
25
+ def cookie_txt_file():
26
+ try:
27
+ folder_path = f"{os.getcwd()}/cookies"
28
+ filename = f"{os.getcwd()}/cookies/logs.csv"
29
+ txt_files = glob.glob(os.path.join(folder_path, '*.txt'))
30
+ if not txt_files:
31
+ raise FileNotFoundError("No .txt files found in the specified folder.")
32
+ cookie_txt_file = random.choice(txt_files)
33
+ with open(filename, 'a') as file:
34
+ file.write(f'Choosen File : {cookie_txt_file}\n')
35
+ return f"""cookies/{str(cookie_txt_file).split("/")[-1]}"""
36
+ except:
37
+ return None
38
+
39
+
40
+ async def check_file_size(link):
41
+ async def get_format_info(link):
42
+ proc = await asyncio.create_subprocess_exec(
43
+ "yt-dlp",
44
+ "--cookies", cookie_txt_file(),
45
+ "-J",
46
+ link,
47
+ stdout=asyncio.subprocess.PIPE,
48
+ stderr=asyncio.subprocess.PIPE
49
+ )
50
+ stdout, stderr = await proc.communicate()
51
+ if proc.returncode != 0:
52
+ print(f'Error:\n{stderr.decode()}')
53
+ return None
54
+ return json.loads(stdout.decode())
55
+
56
+ def parse_size(formats):
57
+ total_size = 0
58
+ for format in formats:
59
+ if 'filesize' in format:
60
+ total_size += format['filesize']
61
+ return total_size
62
+
63
+ info = await get_format_info(link)
64
+ if info is None:
65
+ return None
66
+
67
+ formats = info.get('formats', [])
68
+ if not formats:
69
+ print("No formats found.")
70
+ return None
71
+
72
+ total_size = parse_size(formats)
73
+ return total_size
74
 
75
  async def shell_cmd(cmd):
76
  proc = await asyncio.create_subprocess_shell(
 
86
  return errorz.decode("utf-8")
87
  return out.decode("utf-8")
88
 
89
+
90
  class YouTubeAPI:
91
  def __init__(self):
92
  self.base = "https://www.youtube.com/watch?v="
 
94
  self.status = "https://www.youtube.com/oembed?url="
95
  self.listbase = "https://youtube.com/playlist?list="
96
  self.reg = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
97
+ self.dl_stats = {
98
+ "total_requests": 0,
99
+ "okflix_downloads": 0,
100
+ "cookie_downloads": 0,
101
+ "existing_files": 0
102
+ }
103
+
104
+ async def _get_video_details(self, link: str, limit: int = 20) -> Union[dict, None]:
105
+ """Helper function to get video details with duration limit and error handling"""
106
+ try:
107
+ results = VideosSearch(link, limit=limit)
108
+ search_results = (await results.next()).get("result", [])
109
+
110
+ for result in search_results:
111
+ duration_str = result.get("duration", "0:00")
112
+
113
+ # Convert duration to seconds
114
+ try:
115
+ parts = duration_str.split(":")
116
+ duration_secs = 0
117
+ if len(parts) == 3: # HH:MM:SS
118
+ duration_secs = int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
119
+ elif len(parts) == 2: # MM:SS
120
+ duration_secs = int(parts[0]) * 60 + int(parts[1])
121
+
122
+ # Skip videos longer than 1 hour
123
+ if duration_secs > 3600:
124
+ continue
125
+
126
+ return result
127
+
128
+ except (ValueError, IndexError):
129
+ continue
130
+
131
+ search = CustomSearch(query=link, searchPreferences="EgIYAw==" ,limit=1)
132
+ for res in (await search.next()).get("result", []):
133
+ return res
134
+
135
+ return None
136
+
137
+ except Exception as e:
138
+ LOGGER(__name__).error(f"Error in _get_video_details: {str(e)}")
139
+ return None
140
 
141
  async def exists(self, link: str, videoid: Union[bool, str] = None):
142
  if videoid:
 
175
  link = self.base + link
176
  if "&" in link:
177
  link = link.split("&")[0]
178
+ if "?si=" in link:
179
+ link = link.split("?si=")[0]
180
+ elif "&si=" in link:
181
+ link = link.split("&si=")[0]
182
+
183
+
184
+ result = await self._get_video_details(link)
185
+ if not result:
186
+ raise ValueError("No suitable video found (duration > 1 hour or video unavailable)")
187
+
188
+ title = result["title"]
189
+ duration_min = result["duration"]
190
+ thumbnail = result["thumbnails"][0]["url"].split("?")[0]
191
+ vidid = result["id"]
192
+
193
+ if str(duration_min) == "None":
194
+ duration_sec = 0
195
+ else:
196
+ duration_sec = int(time_to_seconds(duration_min))
197
+
198
  return title, duration_min, duration_sec, thumbnail, vidid
199
 
200
  async def title(self, link: str, videoid: Union[bool, str] = None):
 
202
  link = self.base + link
203
  if "&" in link:
204
  link = link.split("&")[0]
205
+ if "?si=" in link:
206
+ link = link.split("?si=")[0]
207
+ elif "&si=" in link:
208
+ link = link.split("&si=")[0]
209
+
210
+ result = await self._get_video_details(link)
211
+ if not result:
212
+ raise ValueError("No suitable video found (duration > 1 hour or video unavailable)")
213
+ return result["title"]
214
 
215
  async def duration(self, link: str, videoid: Union[bool, str] = None):
216
  if videoid:
217
  link = self.base + link
218
  if "&" in link:
219
  link = link.split("&")[0]
220
+ if "?si=" in link:
221
+ link = link.split("?si=")[0]
222
+ elif "&si=" in link:
223
+ link = link.split("&si=")[0]
224
+
225
+ result = await self._get_video_details(link)
226
+ if not result:
227
+ raise ValueError("No suitable video found (duration > 1 hour or video unavailable)")
228
+ return result["duration"]
229
 
230
  async def thumbnail(self, link: str, videoid: Union[bool, str] = None):
231
  if videoid:
232
  link = self.base + link
233
  if "&" in link:
234
  link = link.split("&")[0]
235
+ if "?si=" in link:
236
+ link = link.split("?si=")[0]
237
+ elif "&si=" in link:
238
+ link = link.split("&si=")[0]
239
+
240
+ result = await self._get_video_details(link)
241
+ if not result:
242
+ raise ValueError("No suitable video found (duration > 1 hour or video unavailable)")
243
+ return result["thumbnails"][0]["url"].split("?")[0]
244
 
245
  async def video(self, link: str, videoid: Union[bool, str] = None):
246
  if videoid:
247
  link = self.base + link
248
  if "&" in link:
249
  link = link.split("&")[0]
250
+ if "?si=" in link:
251
+ link = link.split("?si=")[0]
252
+ elif "&si=" in link:
253
+ link = link.split("&si=")[0]
254
+
255
  proc = await asyncio.create_subprocess_exec(
256
  "yt-dlp",
257
+ "--cookies",cookie_txt_file(),
258
  "-g",
259
  "-f",
260
  "best[height<=?720][width<=?1280]",
 
273
  link = self.listbase + link
274
  if "&" in link:
275
  link = link.split("&")[0]
276
+ if "?si=" in link:
277
+ link = link.split("?si=")[0]
278
+ elif "&si=" in link:
279
+ link = link.split("&si=")[0]
280
  playlist = await shell_cmd(
281
+ f"yt-dlp -i --get-id --flat-playlist --cookies {cookie_txt_file()} --playlist-end {limit} --skip-download {link}"
282
  )
283
  try:
284
  result = playlist.split("\n")
 
294
  link = self.base + link
295
  if "&" in link:
296
  link = link.split("&")[0]
297
+ if "?si=" in link:
298
+ link = link.split("?si=")[0]
299
+ elif "&si=" in link:
300
+ link = link.split("&si=")[0]
301
+
302
+ result = await self._get_video_details(link)
303
+ if not result:
304
+ raise ValueError("No suitable video found (duration > 1 hour or video unavailable)")
305
+
306
  track_details = {
307
+ "title": result["title"],
308
+ "link": result["link"],
309
+ "vidid": result["id"],
310
+ "duration_min": result["duration"],
311
+ "thumb": result["thumbnails"][0]["url"].split("?")[0],
312
  }
313
+ return track_details, result["id"]
314
 
315
  async def formats(self, link: str, videoid: Union[bool, str] = None):
316
  if videoid:
317
  link = self.base + link
318
  if "&" in link:
319
  link = link.split("&")[0]
320
+ if "?si=" in link:
321
+ link = link.split("?si=")[0]
322
+ elif "&si=" in link:
323
+ link = link.split("&si=")[0]
324
+ ytdl_opts = {"quiet": True, "cookiefile" : cookie_txt_file()}
325
  ydl = yt_dlp.YoutubeDL(ytdl_opts)
326
  with ydl:
327
  formats_available = []
 
352
  )
353
  return formats_available, link
354
 
355
+ async def slider(self, link: str, query_type: int, videoid: Union[bool, str] = None):
 
 
 
 
 
356
  if videoid:
357
  link = self.base + link
358
  if "&" in link:
359
  link = link.split("&")[0]
360
+ if "?si=" in link:
361
+ link = link.split("?si=")[0]
362
+ elif "&si=" in link:
363
+ link = link.split("&si=")[0]
364
+
365
+ try:
366
+ results = []
367
+ search = VideosSearch(link, limit=10)
368
+ search_results = (await search.next()).get("result", [])
369
+
370
+ # Filter videos longer than 1 hour
371
+ for result in search_results:
372
+ duration_str = result.get("duration", "0:00")
373
+ try:
374
+ parts = duration_str.split(":")
375
+ duration_secs = 0
376
+ if len(parts) == 3:
377
+ duration_secs = int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
378
+ elif len(parts) == 2:
379
+ duration_secs = int(parts[0]) * 60 + int(parts[1])
380
+
381
+ if duration_secs <= 3600:
382
+ results.append(result)
383
+ except (ValueError, IndexError):
384
+ continue
385
+
386
+ if not results or query_type >= len(results):
387
+ raise ValueError("No suitable videos found within duration limit")
388
+
389
+ selected = results[query_type]
390
+ return (
391
+ selected["title"],
392
+ selected["duration"],
393
+ selected["thumbnails"][0]["url"].split("?")[0],
394
+ selected["id"]
395
+ )
396
+
397
+ except Exception as e:
398
+ LOGGER(__name__).error(f"Error in slider: {str(e)}")
399
+ raise ValueError("Failed to fetch video details")
400
 
401
  async def download(
402
  self,
 
410
  title: Union[bool, str] = None,
411
  ) -> str:
412
  if videoid:
413
+ vid_id = link
414
  link = self.base + link
 
 
415
  loop = asyncio.get_running_loop()
416
+
417
+ def create_session():
418
+ session = requests.Session()
419
+ retries = Retry(total=3, backoff_factor=0.1)
420
+ session.mount('http://', HTTPAdapter(max_retries=retries))
421
+ session.mount('https://', HTTPAdapter(max_retries=retries))
422
+ return session
423
+
424
+ def get_ydl_opts(output_path):
425
+ return {
426
+ "outtmpl": output_path,
 
 
 
 
 
 
 
427
  "quiet": True,
428
+ "xff": "IN",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  "nocheckcertificate": True,
430
+ "compat-options": "allow-unsafe-ext",
431
+ "concurrent-fragments": 99, # Increased from 10
432
+ "retries": 3,
433
+ # "http-chunk-size": 10485760, # 10MB chunks
434
+ # "buffersize": 32768,
435
  }
436
+ ## Method added by sparrow...
437
+ # def audio_dl(vid_id):
438
+ # try:
439
+ # session = create_session()
440
+ # random_prefix = ''.join(random.choices(string.ascii_letters + string.digits, k=12))
441
+ # ruseragent = f"{random_prefix} Mozilla/5.9 ({random.randint(1000, 9999)})"
442
+ # bsid = base64.b64encode(vid_id.encode()).decode() ## For next update
443
+ # headers = {
444
+ # "x-api-key": f"{YT_API_KEY}",
445
+ # "User-Agent": ruseragent
446
+ # }
447
+ # res = session.get(f"{YTPROXY}/api/info?video_id={vid_id}", headers=headers, timeout=300)
448
+ # response = res.json()
449
+
450
+ # if res.status_code == 200 and response['status'] == 'success':
451
+ # xyz = os.path.join("downloads", f"{vid_id}.m4a")
452
+ # if os.path.exists(xyz):
453
+ # return xyz
454
+
455
+ # with session.get(response['download_url'], headers=headers, stream=True, timeout=300) as r:
456
+ # r.raise_for_status()
457
+ # total_size = int(r.headers.get('content-length', 0))
458
+ # block_size = 1024 * 1024 # 1MB chunks
459
+
460
+ # with open(xyz, 'wb') as f:
461
+ # for chunk in r.iter_content(chunk_size=block_size):
462
+ # if chunk: # filter out keep-alive chunks
463
+ # f.write(chunk)
464
+
465
+ # return xyz
466
+ # else:
467
+ # print(f"Proxy returned error status: {response}")
468
+
469
+ # except requests.exceptions.RequestException as e:
470
+ # print(f"Network error while downloading: {str(e)}")
471
+ # except json.JSONDecodeError as e:
472
+ # print(f"Invalid response from proxy: {str(e)}")
473
+ # except Exception as e:
474
+ # print(f"Error in downloading song: {str(e)}")
475
+ # return None
476
+
477
+
478
+ # New updated Method...
479
+ def audio_dl(vid_id):
480
+ try:
481
+ if not YT_API_KEY:
482
+ print("API KEY not set in config, Set API Key you got from @tgmusic_apibot")
483
+ return None
484
+ if not YTPROXY:
485
+ print("API Endpoint not set in config\nPlease set a valid endpoint for YTPROXY_URL in config.")
486
+ return None
487
+ headers = {
488
+ "x-api-key": f"{YT_API_KEY}",
489
+ "User-Agent": "Mozilla/5"
490
+ }
491
+ xyz = os.path.join("downloads", f"{vid_id}.mp3")
492
+ if os.path.exists(xyz):
493
+ return xyz
494
+ getAudio = requests.get(f"{YTPROXY}/audio/{vid_id}", headers=headers, timeout=60)
495
+ try:
496
+ songData = getAudio.json()
497
+ except Exception as e:
498
+ print(f"Invalid response from API: {str(e)}")
499
+ return None
500
+ status = songData.get('status')
501
+ if status == 'success':
502
+ songlink = songData['audio_url']
503
+ audio_url = base64.b64decode(songlink).decode()
504
+ ydl_opts = get_ydl_opts(xyz)
505
+ with ThreadPoolExecutor(max_workers=4) as executor:
506
+ future = executor.submit(lambda: yt_dlp.YoutubeDL(ydl_opts).download(audio_url))
507
+ future.result()
508
+ return xyz
509
+ elif status == 'error':
510
+ print(f"Error: {songData.get('message', 'Unknown error from API.')}")
511
+ return None
512
+ else:
513
+ print("Could not fetch Backend \nPlease contact API provider.")
514
+ return None
515
+ except requests.exceptions.RequestException as e:
516
+ print(f"Network error while downloading: {str(e)}")
517
+ except json.JSONDecodeError as e:
518
+ print(f"Invalid response from proxy: {str(e)}")
519
+ except Exception as e:
520
+ print(f"Error in downloading song: {str(e)}")
521
+ return None
522
+
523
+ def video_dl(vid_id):
524
+ try:
525
+ if not YT_API_KEY:
526
+ print("API KEY not set in config, Set API Key you got from @tgmusic_apibot")
527
+ return None
528
+ if not YTPROXY:
529
+ print("API Endpoint not set in config\nPlease set a valid endpoint for YTPROXY_URL in config.")
530
+ return None
531
+ headers = {
532
+ "x-api-key": f"{YT_API_KEY}",
533
+ "User-Agent": "Mozilla/5"
534
+ }
535
+ xyz = os.path.join("downloads", f"{vid_id}.mp4")
536
+ if os.path.exists(xyz):
537
+ return xyz
538
+ getVideo = requests.get(f"{YTPROXY}/beta/{vid_id}", headers=headers, timeout=60)
539
+ try:
540
+ videoData = getVideo.json()
541
+ except Exception as e:
542
+ print(f"Invalid response from API: {str(e)}")
543
+ return None
544
+ status = videoData.get('status')
545
+ if status == 'success':
546
+ videolink = videoData['video_sd']
547
+ video_url = base64.b64decode(videolink).decode()
548
+ logger.debug(f"Got video url {video_url}")
549
+ ydl_opts = get_ydl_opts(f"downloads/{vid_id}.mp4")
550
+ with ThreadPoolExecutor(max_workers=4) as executor:
551
+ future = executor.submit(lambda: yt_dlp.YoutubeDL(ydl_opts).download(video_url))
552
+ future.result()
553
+ return xyz
554
+ elif status == 'error':
555
+ print(f"Error: {videoData.get('message', 'Unknown error from API.')}")
556
+ return None
557
+ else:
558
+ print("Could not fetch Backend \nPlease contact API provider.")
559
+ return None
560
+ except requests.exceptions.RequestException as e:
561
+ print(f"Network error while downloading: {str(e)}")
562
+ except json.JSONDecodeError as e:
563
+ print(f"Invalid response from proxy: {str(e)}")
564
+ except Exception as e:
565
+ print(f"Error in downloading song: {str(e)}")
566
+ return None
567
+
568
  def song_video_dl():
 
 
569
  formats = f"{format_id}+140"
570
+ fpath = f"downloads/{title}"
571
  ydl_optssx = {
572
  "format": formats,
573
  "outtmpl": fpath,
 
575
  "nocheckcertificate": True,
576
  "quiet": True,
577
  "no_warnings": True,
578
+ "cookiefile" : cookie_txt_file(),
579
  "prefer_ffmpeg": True,
580
  "merge_output_format": "mp4",
581
  }
582
  x = yt_dlp.YoutubeDL(ydl_optssx)
583
  x.download([link])
584
+
585
  def song_audio_dl():
586
+ fpath = f"downloads/{title}.%(ext)s"
 
587
  ydl_optssx = {
588
  "format": format_id,
589
  "outtmpl": fpath,
 
591
  "nocheckcertificate": True,
592
  "quiet": True,
593
  "no_warnings": True,
594
+ "cookiefile" : cookie_txt_file(),
595
  "prefer_ffmpeg": True,
596
  "postprocessors": [
597
  {
 
603
  }
604
  x = yt_dlp.YoutubeDL(ydl_optssx)
605
  x.download([link])
606
+
607
  if songvideo:
608
  await loop.run_in_executor(None, song_video_dl)
609
+ fpath = f"downloads/{title}.mp4"
 
610
  return fpath
611
  elif songaudio:
612
  await loop.run_in_executor(None, song_audio_dl)
613
+ fpath = f"downloads/{title}.mp3"
 
614
  return fpath
615
  elif video:
616
  direct = True
617
+ downloaded_file = await loop.run_in_executor(None, lambda:video_dl(vid_id))
618
  else:
619
  direct = True
620
+ downloaded_file = await loop.run_in_executor(None, lambda:audio_dl(vid_id))
621
+
622
  return downloaded_file, direct