dragonxd1 commited on
Commit
b6e4391
·
verified ·
1 Parent(s): c059037

Update DragMusic/platforms/Youtube.py

Browse files
Files changed (1) hide show
  1. DragMusic/platforms/Youtube.py +278 -229
DragMusic/platforms/Youtube.py CHANGED
@@ -1,126 +1,37 @@
 
 
 
1
  import asyncio
2
  import os
 
3
  import re
4
- import json
5
- from typing import Union
6
- import requests
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 os
14
- import glob
15
- import random
16
- import logging
17
- import aiohttp
18
  import config
19
- from config import API_URL, API_KEY
20
-
21
-
22
- def cookie_txt_file():
23
- cookie_dir = f"{os.getcwd()}/cookies"
24
- cookies_files = [f for f in os.listdir(cookie_dir) if f.endswith(".txt")]
25
-
26
- cookie_file = os.path.join(cookie_dir, random.choice(cookies_files))
27
- return cookie_file
28
-
29
-
30
- async def download_song(link: str):
31
- video_id = link.split('v=')[-1].split('&')[0]
32
-
33
- download_folder = "/tmp/downloads"
34
- for ext in ["mp3", "m4a", "webm"]:
35
- file_path = f"{download_folder}/{video_id}.{ext}"
36
- if os.path.exists(file_path):
37
- #print(f"File already exists: {file_path}")
38
- return file_path
39
-
40
- song_url = f"{API_URL}/song/{video_id}?api={API_KEY}"
41
- async with aiohttp.ClientSession() as session:
42
- while True:
43
- try:
44
- async with session.get(song_url) as response:
45
- if response.status != 200:
46
- raise Exception(f"API request failed with status code {response.status}")
47
- data = await response.json()
48
- status = data.get("status", "").lower()
49
- if status == "downloading":
50
- await asyncio.sleep(2)
51
- continue
52
- elif status == "error":
53
- error_msg = data.get("error") or data.get("message") or "Unknown error"
54
- raise Exception(f"API error: {error_msg}")
55
- elif status == "done":
56
- download_url = data.get("link")
57
- if not download_url:
58
- raise Exception("API response did not provide a download URL.")
59
- break
60
- else:
61
- raise Exception(f"Unexpected status '{status}' from API.")
62
- except Exception as e:
63
- print(f"Error while checking API status: {e}")
64
- return None
65
 
66
- try:
67
- file_format = data.get("format", "mp3")
68
- file_extension = file_format.lower()
69
- file_name = f"{video_id}.{file_extension}"
70
- download_folder = "/tmp/downloads"
71
- os.makedirs(download_folder, exist_ok=True)
72
- file_path = os.path.join(download_folder, file_name)
73
-
74
- async with session.get(download_url) as file_response:
75
- with open(file_path, 'wb') as f:
76
- while True:
77
- chunk = await file_response.content.read(8192)
78
- if not chunk:
79
- break
80
- f.write(chunk)
81
- return file_path
82
- except aiohttp.ClientError as e:
83
- print(f"Network or client error occurred while downloading: {e}")
84
- return None
85
- except Exception as e:
86
- print(f"Error occurred while downloading song: {e}")
87
- return None
88
- return None
89
 
90
- async def check_file_size(link):
91
- async def get_format_info(link):
92
- proc = await asyncio.create_subprocess_exec(
93
- "yt-dlp",
94
- "--cookies", cookie_txt_file(),
95
- "-J",
96
- link,
97
- stdout=asyncio.subprocess.PIPE,
98
- stderr=asyncio.subprocess.PIPE
99
  )
100
- stdout, stderr = await proc.communicate()
101
- if proc.returncode != 0:
102
- print(f'Error:\n{stderr.decode()}')
103
- return None
104
- return json.loads(stdout.decode())
105
-
106
- def parse_size(formats):
107
- total_size = 0
108
- for format in formats:
109
- if 'filesize' in format:
110
- total_size += format['filesize']
111
- return total_size
112
-
113
- info = await get_format_info(link)
114
- if info is None:
115
- return None
116
-
117
- formats = info.get('formats', [])
118
- if not formats:
119
- print("No formats found.")
120
- return None
121
-
122
- total_size = parse_size(formats)
123
- return total_size
124
 
125
  async def shell_cmd(cmd):
126
  proc = await asyncio.create_subprocess_shell(
@@ -137,7 +48,7 @@ async def shell_cmd(cmd):
137
  return out.decode("utf-8")
138
 
139
 
140
- class YouTubeAPI:
141
  def __init__(self):
142
  self.base = "https://www.youtube.com/watch?v="
143
  self.regex = r"(?:youtube\.com|youtu\.be)"
@@ -145,7 +56,7 @@ class YouTubeAPI:
145
  self.listbase = "https://youtube.com/playlist?list="
146
  self.reg = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
147
 
148
- async def exists(self, link: str, videoid: Union[bool, str] = None):
149
  if videoid:
150
  link = self.base + link
151
  if re.search(self.regex, link):
@@ -153,7 +64,17 @@ class YouTubeAPI:
153
  else:
154
  return False
155
 
156
- async def url(self, message_1: Message) -> Union[str, None]:
 
 
 
 
 
 
 
 
 
 
157
  messages = [message_1]
158
  if message_1.reply_to_message:
159
  messages.append(message_1.reply_to_message)
@@ -177,7 +98,8 @@ class YouTubeAPI:
177
  return None
178
  return text[offset : offset + length]
179
 
180
- async def details(self, link: str, videoid: Union[bool, str] = None):
 
181
  if videoid:
182
  link = self.base + link
183
  if "&" in link:
@@ -194,7 +116,8 @@ class YouTubeAPI:
194
  duration_sec = int(time_to_seconds(duration_min))
195
  return title, duration_min, duration_sec, thumbnail, vidid
196
 
197
- async def title(self, link: str, videoid: Union[bool, str] = None):
 
198
  if videoid:
199
  link = self.base + link
200
  if "&" in link:
@@ -204,7 +127,8 @@ class YouTubeAPI:
204
  title = result["title"]
205
  return title
206
 
207
- async def duration(self, link: str, videoid: Union[bool, str] = None):
 
208
  if videoid:
209
  link = self.base + link
210
  if "&" in link:
@@ -214,7 +138,8 @@ class YouTubeAPI:
214
  duration = result["duration"]
215
  return duration
216
 
217
- async def thumbnail(self, link: str, videoid: Union[bool, str] = None):
 
218
  if videoid:
219
  link = self.base + link
220
  if "&" in link:
@@ -224,18 +149,22 @@ class YouTubeAPI:
224
  thumbnail = result["thumbnails"][0]["url"].split("?")[0]
225
  return thumbnail
226
 
227
- async def video(self, link: str, videoid: Union[bool, str] = None):
228
  if videoid:
229
  link = self.base + link
230
  if "&" in link:
231
  link = link.split("&")[0]
232
- proc = await asyncio.create_subprocess_exec(
233
  "yt-dlp",
234
- "--cookies",cookie_txt_file(),
 
235
  "-g",
236
  "-f",
237
  "best[height<=?720][width<=?1280]",
238
  f"{link}",
 
 
 
239
  stdout=asyncio.subprocess.PIPE,
240
  stderr=asyncio.subprocess.PIPE,
241
  )
@@ -245,164 +174,284 @@ class YouTubeAPI:
245
  else:
246
  return 0, stderr.decode()
247
 
248
- async def playlist(self, link, limit, user_id, videoid: Union[bool, str] = None):
 
249
  if videoid:
250
  link = self.listbase + link
251
  if "&" in link:
252
  link = link.split("&")[0]
253
-
254
- ydl_opts = {"ignoreerrors": True, "quiet": True, "dump_single_json": True, "flat_playlist": True, "playlist_items": f"1-{limit}"}
255
-
256
- proc = await asyncio.create_subprocess_exec(
257
- "yt-dlp",
258
- "--cookies", cookie_txt_file(),
259
- *yt_dlp.utils.shell_quote(ydl_opts),
260
- link,
261
- stdout=asyncio.subprocess.PIPE,
262
- stderr=asyncio.subprocess.PIPE,
263
  )
264
- stdout, stderr = await proc.communicate()
265
-
266
- if stderr and "ERROR" in stderr.decode():
267
- return 0, f"Error fetching playlist: {stderr.decode()}"
268
-
269
  try:
270
- playlist_data = json.loads(stdout)
271
- entries = playlist_data.get("entries", [])
272
- if not entries:
273
- return 0, "No videos found in the playlist."
274
- except json.JSONDecodeError:
275
- return 0, "Failed to parse playlist data."
276
-
277
- return 1, entries
278
-
279
- async def track(self, link: str, videoid: Union[bool, str] = None):
280
  if videoid:
281
  link = self.base + link
282
  if "&" in link:
283
  link = link.split("&")[0]
284
- results = VideosSearch(link, limit=1)
285
- for result in (await results.next())["result"]:
286
- title = result["title"]
287
- duration = result["duration"]
288
- vidid = result["id"]
289
- return title, duration, vidid
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
- async def formats(self, link: str, videoid: Union[bool, str] = None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  if videoid:
293
  link = self.base + link
294
  if "&" in link:
295
  link = link.split("&")[0]
296
- cmd = f'yt-dlp -F "{link}"'
297
- out = await shell_cmd(cmd)
298
- return out
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  async def slider(
301
  self,
302
  link: str,
303
  query_type: int,
304
- videoid: Union[bool, str] = None,
305
  ):
306
  if videoid:
307
  link = self.base + link
308
- if query_type == 1:
309
- cmd = f'yt-dlp -F "{link}"'
310
- else:
311
- cmd = f'yt-dlp -F "ytsearch:{link}"'
312
- out = await shell_cmd(cmd)
313
- return out
 
 
 
314
 
315
  async def download(
316
  self,
317
  link: str,
318
  mystic,
319
- video: Union[bool, str] = None,
320
- videoid: Union[bool, str] = None,
321
- songaudio: Union[bool, str] = None,
322
- songvideo: Union[bool, str] = None,
323
- format_id: Union[bool, str] = None,
324
- title: Union[bool, str] = None,
325
  ) -> str:
326
  if videoid:
327
  link = self.base + link
328
 
 
329
  def audio_dl():
330
- opts = {
331
- "format": "bestaudio",
332
- "addmetadata": True,
333
  "geo_bypass": True,
 
334
  "nocheckcertificate": True,
335
- "outtmpl": f"/tmp/downloads/%(id)s.%(ext)s",
336
- "quiet": False,
337
- "logtostderr": False,
 
338
  }
339
- return opts
340
 
 
 
 
 
 
 
 
 
 
341
  def video_dl():
342
- opts = {
343
- "format": "best",
344
- "addmetadata": True,
345
  "geo_bypass": True,
 
346
  "nocheckcertificate": True,
347
- "outtmpl": f"/tmp/downloads/%(id)s.%(ext)s",
348
- "quiet": False,
349
- "logtostderr": False,
 
350
  }
351
- return opts
352
 
 
 
 
 
 
 
 
 
 
353
  def song_video_dl():
354
- opts = {
355
- "format": "best",
356
- "addmetadata": True,
 
 
357
  "geo_bypass": True,
 
358
  "nocheckcertificate": True,
359
- "outtmpl": f"/tmp/downloads/{title}.%(ext)s",
360
- "quiet": False,
361
- "logtostderr": False,
 
 
362
  }
363
- return opts
364
 
 
 
 
 
 
 
365
  def song_audio_dl():
366
- opts = {
367
- "format": "bestaudio",
368
- "addmetadata": True,
 
369
  "geo_bypass": True,
 
370
  "nocheckcertificate": True,
371
- "outtmpl": f"/tmp/downloads/{title}.%(ext)s",
372
- "quiet": False,
373
- "logtostderr": False,
 
 
 
 
 
 
 
 
374
  }
375
- return opts
 
 
 
 
376
 
377
  if songvideo:
378
- opts = song_video_dl()
 
379
  elif songaudio:
380
- opts = song_audio_dl()
 
381
  elif video:
382
- opts = video_dl()
383
- else:
384
- opts = audio_dl()
385
- if format_id:
386
- opts["format"] = format_id
387
- with yt_dlp.YoutubeDL(opts) as ydl:
388
- try:
389
- await mystic.edit("📥 **downloading...**")
390
- ydl.download([link])
391
- except Exception as y:
392
- return await mystic.edit(f"**Failed to download this video.**\n\n**Reason:** {y}")
393
- if songvideo:
394
- for file in os.listdir("/tmp/downloads"):
395
- if file.startswith(title):
396
- return f"/tmp/downloads/{file}"
397
- elif songaudio:
398
- for file in os.listdir("/tmp/downloads"):
399
- if file.startswith(title):
400
- return f"/tmp/downloads/{file}"
 
 
 
 
 
 
 
 
401
  else:
402
- for file in os.listdir("/tmp/downloads"):
403
- if file.endswith(".webm"):
404
- return f"/tmp/downloads/{file}"
405
- elif file.endswith(".m4a"):
406
- return f"/tmp/downloads/{file}"
407
- elif file.endswith(".mp3"):
408
- return f"/tmp/downloads/{file}"
 
1
+
2
+ # All rights reserved.
3
+ #
4
  import asyncio
5
  import os
6
+ import random
7
  import re
8
+
9
+ from async_lru import alru_cache
10
+ from py_yt import VideosSearch
 
11
  from pyrogram.enums import MessageEntityType
12
  from pyrogram.types import Message
13
+ from yt_dlp import YoutubeDL
14
+
 
 
 
 
 
 
15
  import config
16
+ from VenomX.utils.database import is_on_off
17
+ from VenomX.utils.decorators import asyncify
18
+ from VenomX.utils.formatters import seconds_to_min, time_to_seconds
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ NOTHING = {"cookies_dead": None}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+
23
+ def cookies():
24
+ folder_path = f"{os.getcwd()}/cookies"
25
+ txt_files = [file for file in os.listdir(folder_path) if file.endswith(".txt")]
26
+ if not txt_files:
27
+ raise FileNotFoundError(
28
+ "No Cookies found in cookies directory make sure your cookies file written .txt file"
 
 
29
  )
30
+ cookie_txt_file = random.choice(txt_files)
31
+ cookie_txt_file = os.path.join(folder_path, cookie_txt_file)
32
+ return cookie_txt_file
33
+ # return f"""cookies/{str(cookie_txt_file).split("/")[-1]}"""
34
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  async def shell_cmd(cmd):
37
  proc = await asyncio.create_subprocess_shell(
 
48
  return out.decode("utf-8")
49
 
50
 
51
+ class YouTube:
52
  def __init__(self):
53
  self.base = "https://www.youtube.com/watch?v="
54
  self.regex = r"(?:youtube\.com|youtu\.be)"
 
56
  self.listbase = "https://youtube.com/playlist?list="
57
  self.reg = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
58
 
59
+ async def exists(self, link: str, videoid: bool | str = None):
60
  if videoid:
61
  link = self.base + link
62
  if re.search(self.regex, link):
 
64
  else:
65
  return False
66
 
67
+ @property
68
+ def use_fallback(self):
69
+ return NOTHING["cookies_dead"] is True
70
+
71
+ @use_fallback.setter
72
+ def use_fallback(self, value):
73
+ if NOTHING["cookies_dead"] is None:
74
+ NOTHING["cookies_dead"] = value
75
+
76
+ @asyncify
77
+ def url(self, message_1: Message) -> str | None:
78
  messages = [message_1]
79
  if message_1.reply_to_message:
80
  messages.append(message_1.reply_to_message)
 
98
  return None
99
  return text[offset : offset + length]
100
 
101
+ @alru_cache(maxsize=None)
102
+ async def details(self, link: str, videoid: bool | str = None):
103
  if videoid:
104
  link = self.base + link
105
  if "&" in link:
 
116
  duration_sec = int(time_to_seconds(duration_min))
117
  return title, duration_min, duration_sec, thumbnail, vidid
118
 
119
+ @alru_cache(maxsize=None)
120
+ async def title(self, link: str, videoid: bool | str = None):
121
  if videoid:
122
  link = self.base + link
123
  if "&" in link:
 
127
  title = result["title"]
128
  return title
129
 
130
+ @alru_cache(maxsize=None)
131
+ async def duration(self, link: str, videoid: bool | str = None):
132
  if videoid:
133
  link = self.base + link
134
  if "&" in link:
 
138
  duration = result["duration"]
139
  return duration
140
 
141
+ @alru_cache(maxsize=None)
142
+ async def thumbnail(self, link: str, videoid: bool | str = None):
143
  if videoid:
144
  link = self.base + link
145
  if "&" in link:
 
149
  thumbnail = result["thumbnails"][0]["url"].split("?")[0]
150
  return thumbnail
151
 
152
+ async def video(self, link: str, videoid: bool | str = None):
153
  if videoid:
154
  link = self.base + link
155
  if "&" in link:
156
  link = link.split("&")[0]
157
+ cmd = [
158
  "yt-dlp",
159
+ f"--cookies",
160
+ cookies(),
161
  "-g",
162
  "-f",
163
  "best[height<=?720][width<=?1280]",
164
  f"{link}",
165
+ ]
166
+ proc = await asyncio.create_subprocess_exec(
167
+ *cmd,
168
  stdout=asyncio.subprocess.PIPE,
169
  stderr=asyncio.subprocess.PIPE,
170
  )
 
174
  else:
175
  return 0, stderr.decode()
176
 
177
+ @alru_cache(maxsize=None)
178
+ async def playlist(self, link, limit, videoid: bool | str = None):
179
  if videoid:
180
  link = self.listbase + link
181
  if "&" in link:
182
  link = link.split("&")[0]
183
+
184
+ cmd = (
185
+ f"yt-dlp -i --compat-options no-youtube-unavailable-videos "
186
+ f'--get-id --flat-playlist --playlist-end {limit} --skip-download "{link}" '
187
+ f"2>/dev/null"
 
 
 
 
 
188
  )
189
+
190
+ playlist = await shell_cmd(cmd)
191
+
 
 
192
  try:
193
+ result = [key for key in playlist.split("\n") if key]
194
+ except Exception:
195
+ result = []
196
+ return result
197
+
198
+ @alru_cache(maxsize=None)
199
+ async def track(self, link: str, videoid: bool | str = None):
 
 
 
200
  if videoid:
201
  link = self.base + link
202
  if "&" in link:
203
  link = link.split("&")[0]
204
+ if link.startswith("http://") or link.startswith("https://"):
205
+ return await self._track(link)
206
+ try:
207
+ results = VideosSearch(link, limit=1)
208
+ for result in (await results.next())["result"]:
209
+ title = result["title"]
210
+ duration_min = result["duration"]
211
+ vidid = result["id"]
212
+ yturl = result["link"]
213
+ thumbnail = result["thumbnails"][0]["url"].split("?")[0]
214
+ track_details = {
215
+ "title": title,
216
+ "link": yturl,
217
+ "vidid": vidid,
218
+ "duration_min": duration_min,
219
+ "thumb": thumbnail,
220
+ }
221
+ return track_details, vidid
222
+ except Exception:
223
+ return await self._track(link)
224
 
225
+ @asyncify
226
+ def _track(self, q):
227
+ options = {
228
+ "format": "best",
229
+ "noplaylist": True,
230
+ "quiet": True,
231
+ "extract_flat": "in_playlist",
232
+ "cookiefile": f"{cookies()}",
233
+ }
234
+ with YoutubeDL(options) as ydl:
235
+ info_dict = ydl.extract_info(f"ytsearch: {q}", download=False)
236
+ details = info_dict.get("entries")[0]
237
+ info = {
238
+ "title": details["title"],
239
+ "link": details["url"],
240
+ "vidid": details["id"],
241
+ "duration_min": (
242
+ seconds_to_min(details["duration"])
243
+ if details["duration"] != 0
244
+ else None
245
+ ),
246
+ "thumb": details["thumbnails"][0]["url"],
247
+ }
248
+ return info, details["id"]
249
+
250
+ @alru_cache(maxsize=None)
251
+ @asyncify
252
+ def formats(self, link: str, videoid: bool | str = None):
253
  if videoid:
254
  link = self.base + link
255
  if "&" in link:
256
  link = link.split("&")[0]
 
 
 
257
 
258
+ ytdl_opts = {
259
+ "quiet": True,
260
+ "cookiefile": f"{cookies()}",
261
+ }
262
+
263
+ ydl = YoutubeDL(ytdl_opts)
264
+ with ydl:
265
+ formats_available = []
266
+ r = ydl.extract_info(link, download=False)
267
+ for format in r["formats"]:
268
+ try:
269
+ str(format["format"])
270
+ except Exception:
271
+ continue
272
+ if "dash" not in str(format["format"]).lower():
273
+ try:
274
+ format["format"]
275
+ format["filesize"]
276
+ format["format_id"]
277
+ format["ext"]
278
+ format["format_note"]
279
+ except KeyError:
280
+ continue
281
+ formats_available.append(
282
+ {
283
+ "format": format["format"],
284
+ "filesize": format["filesize"],
285
+ "format_id": format["format_id"],
286
+ "ext": format["ext"],
287
+ "format_note": format["format_note"],
288
+ "yturl": link,
289
+ }
290
+ )
291
+ return formats_available, link
292
+
293
+ @alru_cache(maxsize=None)
294
  async def slider(
295
  self,
296
  link: str,
297
  query_type: int,
298
+ videoid: bool | str = None,
299
  ):
300
  if videoid:
301
  link = self.base + link
302
+ if "&" in link:
303
+ link = link.split("&")[0]
304
+ a = VideosSearch(link, limit=10)
305
+ result = (await a.next()).get("result")
306
+ title = result[query_type]["title"]
307
+ duration_min = result[query_type]["duration"]
308
+ vidid = result[query_type]["id"]
309
+ thumbnail = result[query_type]["thumbnails"][0]["url"].split("?")[0]
310
+ return title, duration_min, thumbnail, vidid
311
 
312
  async def download(
313
  self,
314
  link: str,
315
  mystic,
316
+ video: bool | str = None,
317
+ videoid: bool | str = None,
318
+ songaudio: bool | str = None,
319
+ songvideo: bool | str = None,
320
+ format_id: bool | str = None,
321
+ title: bool | str = None,
322
  ) -> str:
323
  if videoid:
324
  link = self.base + link
325
 
326
+ @asyncify
327
  def audio_dl():
328
+ ydl_optssx = {
329
+ "format": "bestaudio/best",
330
+ "outtmpl": "downloads/%(id)s.%(ext)s",
331
  "geo_bypass": True,
332
+ "noplaylist": True,
333
  "nocheckcertificate": True,
334
+ "quiet": True,
335
+ "no_warnings": True,
336
+ "cookiefile": f"{cookies()}",
337
+ "prefer_ffmpeg": True,
338
  }
 
339
 
340
+ with YoutubeDL(ydl_optssx) as x:
341
+ info = x.extract_info(link, False)
342
+ xyz = os.path.join("downloads", f"{info['id']}.{info['ext']}")
343
+ if os.path.exists(xyz):
344
+ return xyz
345
+ x.download([link])
346
+ return xyz
347
+
348
+ @asyncify
349
  def video_dl():
350
+ ydl_optssx = {
351
+ "format": "(bestvideo[height<=?720][width<=?1280][ext=mp4])+(bestaudio[ext=m4a])",
352
+ "outtmpl": "downloads/%(id)s.%(ext)s",
353
  "geo_bypass": True,
354
+ "noplaylist": True,
355
  "nocheckcertificate": True,
356
+ "quiet": True,
357
+ "no_warnings": True,
358
+ "prefer_ffmpeg": True,
359
+ "cookiefile": f"{cookies()}",
360
  }
 
361
 
362
+ with YoutubeDL(ydl_optssx) as x:
363
+ info = x.extract_info(link, False)
364
+ xyz = os.path.join("downloads", f"{info['id']}.{info['ext']}")
365
+ if os.path.exists(xyz):
366
+ return xyz
367
+ x.download([link])
368
+ return xyz
369
+
370
+ @asyncify
371
  def song_video_dl():
372
+ formats = f"{format_id}+140"
373
+ fpath = f"downloads/{title}"
374
+ ydl_optssx = {
375
+ "format": formats,
376
+ "outtmpl": fpath,
377
  "geo_bypass": True,
378
+ "noplaylist": True,
379
  "nocheckcertificate": True,
380
+ "quiet": True,
381
+ "no_warnings": True,
382
+ "prefer_ffmpeg": True,
383
+ "merge_output_format": "mp4",
384
+ "cookiefile": f"{cookies()}",
385
  }
 
386
 
387
+ with YoutubeDL(ydl_optssx) as x:
388
+ info = x.extract_info(link)
389
+ file_path = x.prepare_filename(info)
390
+ return file_path
391
+
392
+ @asyncify
393
  def song_audio_dl():
394
+ fpath = f"downloads/{title}.%(ext)s"
395
+ ydl_optssx = {
396
+ "format": format_id,
397
+ "outtmpl": fpath,
398
  "geo_bypass": True,
399
+ "noplaylist": True,
400
  "nocheckcertificate": True,
401
+ "quiet": True,
402
+ "no_warnings": True,
403
+ "prefer_ffmpeg": True,
404
+ "postprocessors": [
405
+ {
406
+ "key": "FFmpegExtractAudio",
407
+ "preferredcodec": "mp3",
408
+ "preferredquality": "192",
409
+ }
410
+ ],
411
+ "cookiefile": f"{cookies()}",
412
  }
413
+
414
+ with YoutubeDL(ydl_optssx) as x:
415
+ info = x.extract_info(link)
416
+ file_path = x.prepare_filename(info)
417
+ return file_path
418
 
419
  if songvideo:
420
+ return await song_video_dl()
421
+
422
  elif songaudio:
423
+ return await song_audio_dl()
424
+
425
  elif video:
426
+ if await is_on_off(config.YTDOWNLOADER):
427
+ direct = True
428
+ downloaded_file = await video_dl()
429
+ else:
430
+ command = [
431
+ "yt-dlp",
432
+ f"--cookies",
433
+ cookies(),
434
+ "-g",
435
+ "-f",
436
+ "best",
437
+ link,
438
+ ]
439
+
440
+ proc = await asyncio.create_subprocess_exec(
441
+ *command,
442
+ stdout=asyncio.subprocess.PIPE,
443
+ stderr=asyncio.subprocess.PIPE,
444
+ )
445
+ stdout, stderr = await proc.communicate()
446
+
447
+ if stdout:
448
+ downloaded_file = stdout.decode().split("\n")[0]
449
+ direct = None
450
+ else:
451
+ downloaded_file = await video_dl()
452
+ direct = True
453
  else:
454
+ direct = True
455
+ downloaded_file = await audio_dl()
456
+
457
+ return downloaded_file, direct