DDownloader 0.3.8__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
DDownloader/main.py CHANGED
@@ -72,7 +72,6 @@ def main():
72
72
 
73
73
  downloader = DOWNLOADER()
74
74
 
75
- # Handle downloading if URL is provided
76
75
  if args.url:
77
76
  if re.search(r"\.mpd\b", args.url, re.IGNORECASE):
78
77
  logger.info("DASH stream detected. Initializing DASH downloader...")
@@ -85,8 +84,19 @@ def main():
85
84
  print(Fore.RED + "═" * 100 + Fore.RESET)
86
85
  downloader.normal_downloader(args.url, os.path.join(downloads_dir, args.output))
87
86
  exit(1)
87
+ elif re.search(r"(youtube\.com|youtu\.be)", args.url, re.IGNORECASE):
88
+ logger.info("YouTube URL detected. Initializing YouTube downloader...")
89
+ print(Fore.RED + "═" * 100 + Fore.RESET)
90
+ is_playlist = "list=" in args.url
91
+ downloader.youtube_downloader(
92
+ url=args.url,
93
+ output_file=os.path.join(downloads_dir, args.output),
94
+ download_type="mp4",
95
+ playlist=is_playlist
96
+ )
97
+ exit(0)
88
98
  else:
89
- logger.error("Unsupported URL format. Please provide a valid DASH (.mpd), HLS (.m3u8), or ISM (.ism) URL.")
99
+ logger.error("Unsupported URL format. Please provide a valid DASH (.mpd), HLS (.m3u8), ISM (.ism), or YouTube URL.")
90
100
  exit(1)
91
101
 
92
102
  downloader.manifest_url = args.url
@@ -1 +1 @@
1
- __version__ = "0.3.8"
1
+ __version__ = "0.4.0"
@@ -23,7 +23,7 @@ def banners():
23
23
  stdout.write(""+Fore.YELLOW +"╔════════════════════════════════════════════════════════════════════════════╝\n")
24
24
  stdout.write(""+Fore.YELLOW +"║ \x1b[38;2;255;20;147m• "+Fore.GREEN+"GITHUB "+Fore.RED+" |"+Fore.LIGHTWHITE_EX+" GITHUB.COM/THATNOTEASY "+Fore.YELLOW+"║\n")
25
25
  stdout.write(""+Fore.YELLOW +"╚════════════════════════════════════════════════════════════════════════════╝\n")
26
- print(f"{Fore.YELLOW}[DDownloader] - {Fore.GREEN}A DRM-Protected & Non-Protected Content Downloader - {Fore.RED}[V0.3.8] \n{Fore.RESET}")
26
+ print(f"{Fore.YELLOW}[DDownloader] - {Fore.GREEN}A DRM-Protected & Non-Protected Content Downloader - {Fore.RED}[V0.4.0] \n{Fore.RESET}")
27
27
 
28
28
  # =========================================================================================================== #
29
29
 
@@ -29,16 +29,29 @@ class DOWNLOADER:
29
29
  binary_name = 'N_m3u8DL-RE.exe' if platform.system() == 'Windows' else 'N_m3u8DL-RE'
30
30
  elif binary_type == 'ffmpeg':
31
31
  binary_name = 'ffmpeg.exe' if platform.system() == 'Windows' else 'ffmpeg'
32
+ elif binary_type == 'yt-dlp':
33
+ binary_name = 'yt-dlp.exe' if platform.system() == 'Windows' else 'yt-dlp'
32
34
  else:
33
35
  raise ValueError(f"Unknown binary type: {binary_type}")
34
36
 
37
+ # First check project's bin directory
35
38
  binary_path = os.path.join(bin_dir, binary_name)
39
+
40
+ # For ffmpeg on Linux, fall back to system path if not found in project
41
+ if binary_type == 'ffmpeg' and platform.system() == 'Linux' and not os.path.isfile(binary_path):
42
+ system_ffmpeg = '/usr/bin/ffmpeg'
43
+ if os.path.isfile(system_ffmpeg):
44
+ binary_path = system_ffmpeg
45
+ logger.info(Fore.YELLOW + f"Using system ffmpeg at: {binary_path}" + Fore.RESET)
46
+ else:
47
+ logger.error(f"ffmpeg not found in project bin or system path")
48
+ raise FileNotFoundError(f"ffmpeg not found in project bin or system path")
36
49
 
37
50
  if not os.path.isfile(binary_path):
38
51
  logger.error(f"Binary not found: {binary_path}")
39
52
  raise FileNotFoundError(f"Binary not found: {binary_path}")
40
53
 
41
- if platform.system() == 'Linux':
54
+ if platform.system() == 'Linux' and not binary_path.startswith('/usr/bin/'):
42
55
  chmod_command = ['chmod', '+x', binary_path]
43
56
  try:
44
57
  subprocess.run(chmod_command, check=True)
@@ -105,7 +118,7 @@ class DOWNLOADER:
105
118
 
106
119
  # =========================================================================================================== #
107
120
 
108
- def re_encode_content(self, input_file, quality, codec="libx265", crf=20, preset="medium", audio_bitrate="256k"):
121
+ def re_encode_content(self, input_file, quality, codec="libx265", crf=23, preset="superfast", audio_bitrate="256k", fps=60):
109
122
  resolutions = {
110
123
  "HD": "1280:720",
111
124
  "FHD": "1920:1080",
@@ -128,22 +141,26 @@ class DOWNLOADER:
128
141
 
129
142
  self.binary_path = self._get_binary_path("ffmpeg")
130
143
 
131
- logger.info(f"Re-encoding {input_file} to {quality} ({resolution}) using codec {codec}...")
144
+ logger.info(f"Re-encoding {input_file} to {quality} ({resolution}) at {fps} FPS using codec {codec}...")
132
145
  logger.info(f"Output file: {output_file}")
133
146
 
134
147
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
135
148
 
136
- # Build the ffmpeg command
149
+ # Build the ffmpeg command with multi-threading & FPS increase
137
150
  command = [
138
151
  self.binary_path,
139
152
  "-i", f"\"{input_file}\"",
140
- "-vf", f"scale={resolution}",
153
+ "-r", str(fps), # Increase FPS
154
+ "-vf", f"scale={resolution}:flags=lanczos,unsharp=5:5:1.0:5:5:0.0,hqdn3d=1.5:1.5:6:6", # Scaling + Sharpening + Denoising
141
155
  "-c:v", codec,
142
- "-crf", str(crf),
156
+ "-b:v", "25M", # Video bitrate set to 25 Mbps for better quality
157
+ "-crf", str(crf), # CRF still included for quality control
143
158
  "-preset", preset,
159
+ "-threads", "0", # Enables multi-threading (uses all available CPU cores)
144
160
  "-c:a", "aac",
145
161
  "-b:a", audio_bitrate,
146
162
  "-movflags", "+faststart",
163
+ "-pix_fmt", "yuv444p", # Ensures compatibility
147
164
  f"\"{output_file}\""
148
165
  ]
149
166
 
@@ -152,7 +169,7 @@ class DOWNLOADER:
152
169
 
153
170
  # Check if output file exists to confirm success
154
171
  if os.path.isfile(output_file):
155
- logger.info(f"Re-encoding to {quality} completed successfully. Output saved to: {output_file}")
172
+ logger.info(f"Re-encoding to {quality} at {fps} FPS completed successfully. Output saved to: {output_file}")
156
173
  return output_file
157
174
  else:
158
175
  logger.error(f"Re-encoding failed. Output file not created: {output_file}")
@@ -199,4 +216,88 @@ class DOWNLOADER:
199
216
  print(f"Download complete: {output_file}")
200
217
 
201
218
  except requests.exceptions.RequestException as e:
202
- print(f"Error during download: {e}")
219
+ print(f"Error during download: {e}")
220
+
221
+ # =========================================================================================================== #
222
+
223
+ def youtube_downloader(self, url, output_file, download_type="mp4", playlist=False):
224
+ """
225
+ Download a video, audio, or playlist from YouTube using yt-dlp.
226
+
227
+ Args:
228
+ url (str): The YouTube video or playlist URL.
229
+ output_file (str): The output file path to save the video or audio.
230
+ download_type (str): The type of download ("mp4" for video, "mp3" for audio).
231
+ playlist (bool): Whether the URL is a playlist.
232
+ """
233
+ try:
234
+ # Get the yt-dlp binary path
235
+ yt_dlp_path = self._get_binary_path("yt-dlp")
236
+
237
+ # Determine the output file extension based on download type
238
+ if download_type == "mp3":
239
+ output_file = os.path.splitext(output_file)[0] + ".mp3"
240
+ elif download_type == "mp4":
241
+ output_file = os.path.splitext(output_file)[0] + ".mp4"
242
+ else:
243
+ logger.error(Fore.RED + f"Invalid download type: {download_type}. Use 'mp4' or 'mp3'." + Fore.RESET)
244
+ return
245
+
246
+ # Build the yt-dlp command
247
+ command = [
248
+ yt_dlp_path,
249
+ "-o", f"\"{output_file}\"", # Output file
250
+ "--no-check-certificate", # Bypass certificate verification
251
+ "--extractor-args", "youtube:player_client=android", # Force a specific extractor
252
+ "--ignore-errors", # Ignore errors and continue downloading
253
+ ]
254
+
255
+ # Add playlist-specific options if the URL is a playlist
256
+ if playlist:
257
+ command.extend([
258
+ "--yes-playlist", # Force downloading the playlist
259
+ "--output", f"\"{output_file}/%(playlist_index)s - %(title)s.%(ext)s\"", # Organize files in a folder
260
+ ])
261
+ else:
262
+ command.extend([
263
+ "--no-playlist", # Ignore playlists if the URL is a single video
264
+ ])
265
+
266
+ # Add audio extraction options if downloading MP3
267
+ if download_type == "mp3":
268
+ command.extend([
269
+ "--extract-audio", # Extract audio
270
+ "--audio-format", "mp3", # Convert to MP3
271
+ "--audio-quality", "0", # Best quality
272
+ ])
273
+ else:
274
+ # For MP4, download the best video and audio formats and merge them
275
+ command.extend([
276
+ "-f", "bv*+ba/b", # Download best video + best audio, or fallback to best combined format
277
+ "--merge-output-format", "mp4", # Merge into MP4
278
+ ])
279
+
280
+ # Add the YouTube URL
281
+ command.append(url)
282
+
283
+ # Execute the command
284
+ self._execute_command(command)
285
+
286
+ # Check if output file(s) exist to confirm success
287
+ if playlist:
288
+ if os.path.exists(output_file) and os.listdir(output_file):
289
+ logger.info(f"Playlist download completed successfully. Files saved to: {output_file}")
290
+ return output_file
291
+ else:
292
+ logger.error(f"Playlist download failed. No files were created in: {output_file}")
293
+ return None
294
+ else:
295
+ if os.path.isfile(output_file):
296
+ logger.info(f"Download from YouTube completed successfully. Output saved to: {output_file}")
297
+ return output_file
298
+ else:
299
+ logger.error(f"Download from YouTube failed. Output file not created: {output_file}")
300
+ return None
301
+
302
+ except Exception as e:
303
+ logger.error(Fore.RED + f"An unexpected error occurred: {e}" + Fore.RESET)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: DDownloader
3
- Version: 0.3.8
3
+ Version: 0.4.0
4
4
  Summary: A downloader for DRM-protected & Non DRM-protected content.
5
5
  License: MIT License
6
6
 
@@ -6,15 +6,15 @@ DDownloader/bin/mp4decrypt.exe,sha256=JnI7mk4UduPVnUDg1aZBr4y_SWRFy8s-u_H6gG5xeO
6
6
  DDownloader/bin/N_m3u8DL-RE.exe,sha256=5ck6jeDFjFCSLBeoo7q9fSGT-0Oxp_rNCxjeknTvgGE,17197568
7
7
  DDownloader/bin/shaka-packager.exe,sha256=oQmfiToKeryylxsR9BiKuhXR_fS-PqPEu9W9rEsbrt8,5369344
8
8
  DDownloader/bin/yt-dlp.exe,sha256=TYiozhv_gpxxZ90h6LSo7rDbFEG8JzQPCJa754HJw8A,19557107
9
- DDownloader/main.py,sha256=7XJrLtMaw_5taymEoPfDgfQCw9K3JJmW8gScR6gVOPw,5792
10
- DDownloader/modules/__init__.py,sha256=kd0YV9qLZ1Lpx7vbSzAMrAwjgdZJD_tInTnDqY6-nTY,21
9
+ DDownloader/main.py,sha256=eX0hrpBHKcpoqoyzKffnStU-3btaQK0VhcLCAYlL-Eg,6281
10
+ DDownloader/modules/__init__.py,sha256=1NSg4yHgqJJKYBklxFwmel_5eSNX51umiqsyFgx4770,21
11
11
  DDownloader/modules/args_parser.py,sha256=Xc9ZzBu-QPFrBURIcq7rl8IJbrdPMy7EMWc-odVM2QU,1105
12
- DDownloader/modules/banners.py,sha256=yiMLSbH92XXf_92g4No5i7wLF50bPyp2wuBh4rfV5Yk,5656
13
- DDownloader/modules/downloader.py,sha256=Ul0zCB5t9DR8sx1YisP_RFzCWVWm7J8mor4rhOKudNA,7867
12
+ DDownloader/modules/banners.py,sha256=fK5JpztKeE4Se3p5-yB4jdUzsKZXsBSESoeGfbPzF84,5656
13
+ DDownloader/modules/downloader.py,sha256=D5k6GO5xb601D64W1ixlLd8C9D9hzpw_Ldm6yA5k1bs,13154
14
14
  DDownloader/modules/helper.py,sha256=-PMfT0pd3AsXY1K_WP1mER3dpw9gJ99Y-Erque_62nQ,8242
15
15
  DDownloader/modules/streamlink.py,sha256=t7aaHCnINzSFybTmAd-dvfGFQkepFHJwrOBcNxyJviY,504
16
- ddownloader-0.3.8.dist-info/entry_points.txt,sha256=36xFMHKWyVvFKBCCMd3ctyd6tyujf685-qilrMpsA1E,53
17
- ddownloader-0.3.8.dist-info/LICENSE,sha256=cnjTim3BMjb9cVC_b3oS41FESKLuvuDsufVHa_ymZRw,1090
18
- ddownloader-0.3.8.dist-info/METADATA,sha256=hM7TxtkmJc31-ftcjhhTcmNhyjm7Xz-a7ILCZq9fGUI,4906
19
- ddownloader-0.3.8.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
- ddownloader-0.3.8.dist-info/RECORD,,
16
+ ddownloader-0.4.0.dist-info/entry_points.txt,sha256=36xFMHKWyVvFKBCCMd3ctyd6tyujf685-qilrMpsA1E,53
17
+ ddownloader-0.4.0.dist-info/LICENSE,sha256=cnjTim3BMjb9cVC_b3oS41FESKLuvuDsufVHa_ymZRw,1090
18
+ ddownloader-0.4.0.dist-info/METADATA,sha256=yjYFF7BQku2Xu0y46eMsgME-ZdJNcosgwLVeJ-djoxI,4906
19
+ ddownloader-0.4.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
+ ddownloader-0.4.0.dist-info/RECORD,,