DDownloader 0.3.7__py3-none-any.whl → 0.3.9__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.7"
1
+ __version__ = "0.3.9"
@@ -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.7] \n{Fore.RESET}")
26
+ print(f"{Fore.YELLOW}[DDownloader] - {Fore.GREEN}A DRM-Protected & Non-Protected Content Downloader - {Fore.RED}[V0.3.9] \n{Fore.RESET}")
27
27
 
28
28
  # =========================================================================================================== #
29
29
 
@@ -29,6 +29,8 @@ 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
 
@@ -61,15 +63,16 @@ class DOWNLOADER:
61
63
  # =========================================================================================================== #
62
64
 
63
65
  def _build_command(self):
64
- self.binary_path = self._get_binary_path("N_m3u8DL-RE")
65
66
  command = [
66
- self.binary_path,
67
+ self._get_binary_path("N_m3u8DL-RE"),
67
68
  f'"{self.manifest_url}"',
68
69
  '-mt',
69
70
  '-M', 'format=mp4',
70
71
  '--save-dir', '"downloads"',
71
72
  '--tmp-dir', '"downloads"',
72
73
  '--del-after-done',
74
+ '--decryption-engine', '"FFMPEG"',
75
+ '--decryption-binary-path', f'"{self._get_binary_path("ffmpeg")}"',
73
76
  '--save-name', f'"{self.output_name}"'
74
77
  ]
75
78
 
@@ -104,7 +107,7 @@ class DOWNLOADER:
104
107
 
105
108
  # =========================================================================================================== #
106
109
 
107
- def re_encode_content(self, input_file, quality, codec="libx265", crf=20, preset="medium", audio_bitrate="256k"):
110
+ def re_encode_content(self, input_file, quality, codec="libx265", crf=23, preset="superfast", audio_bitrate="256k", fps=60):
108
111
  resolutions = {
109
112
  "HD": "1280:720",
110
113
  "FHD": "1920:1080",
@@ -127,22 +130,26 @@ class DOWNLOADER:
127
130
 
128
131
  self.binary_path = self._get_binary_path("ffmpeg")
129
132
 
130
- logger.info(f"Re-encoding {input_file} to {quality} ({resolution}) using codec {codec}...")
133
+ logger.info(f"Re-encoding {input_file} to {quality} ({resolution}) at {fps} FPS using codec {codec}...")
131
134
  logger.info(f"Output file: {output_file}")
132
135
 
133
136
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
134
137
 
135
- # Build the ffmpeg command
138
+ # Build the ffmpeg command with multi-threading & FPS increase
136
139
  command = [
137
140
  self.binary_path,
138
141
  "-i", f"\"{input_file}\"",
139
- "-vf", f"scale={resolution}",
142
+ "-r", str(fps), # Increase FPS
143
+ "-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
140
144
  "-c:v", codec,
141
- "-crf", str(crf),
145
+ "-b:v", "25M", # Video bitrate set to 25 Mbps for better quality
146
+ "-crf", str(crf), # CRF still included for quality control
142
147
  "-preset", preset,
148
+ "-threads", "0", # Enables multi-threading (uses all available CPU cores)
143
149
  "-c:a", "aac",
144
150
  "-b:a", audio_bitrate,
145
151
  "-movflags", "+faststart",
152
+ "-pix_fmt", "yuv444p", # Ensures compatibility
146
153
  f"\"{output_file}\""
147
154
  ]
148
155
 
@@ -151,7 +158,7 @@ class DOWNLOADER:
151
158
 
152
159
  # Check if output file exists to confirm success
153
160
  if os.path.isfile(output_file):
154
- logger.info(f"Re-encoding to {quality} completed successfully. Output saved to: {output_file}")
161
+ logger.info(f"Re-encoding to {quality} at {fps} FPS completed successfully. Output saved to: {output_file}")
155
162
  return output_file
156
163
  else:
157
164
  logger.error(f"Re-encoding failed. Output file not created: {output_file}")
@@ -198,4 +205,87 @@ class DOWNLOADER:
198
205
  print(f"Download complete: {output_file}")
199
206
 
200
207
  except requests.exceptions.RequestException as e:
201
- print(f"Error during download: {e}")
208
+ print(f"Error during download: {e}")
209
+
210
+ # =========================================================================================================== #
211
+
212
+ def youtube_downloader(self, url, output_file, download_type="mp4", playlist=False):
213
+ """
214
+ Download a video, audio, or playlist from YouTube using yt-dlp.
215
+
216
+ Args:
217
+ url (str): The YouTube video or playlist URL.
218
+ output_file (str): The output file path to save the video or audio.
219
+ download_type (str): The type of download ("mp4" for video, "mp3" for audio).
220
+ playlist (bool): Whether the URL is a playlist.
221
+ """
222
+ try:
223
+ # Get the yt-dlp binary path
224
+ yt_dlp_path = self._get_binary_path("yt-dlp")
225
+
226
+ # Determine the output file extension based on download type
227
+ if download_type == "mp3":
228
+ output_file = os.path.splitext(output_file)[0] + ".mp3"
229
+ elif download_type == "mp4":
230
+ output_file = os.path.splitext(output_file)[0] + ".mp4"
231
+ else:
232
+ logger.error(Fore.RED + f"Invalid download type: {download_type}. Use 'mp4' or 'mp3'." + Fore.RESET)
233
+ return
234
+
235
+ # Build the yt-dlp command
236
+ command = [
237
+ yt_dlp_path,
238
+ "-o", f"\"{output_file}\"", # Output file
239
+ "--no-check-certificate", # Bypass certificate verification
240
+ "--extractor-args", "youtube:player_client=android", # Force a specific extractor
241
+ ]
242
+
243
+ # Add playlist-specific options if the URL is a playlist
244
+ if playlist:
245
+ command.extend([
246
+ "--yes-playlist", # Force downloading the playlist
247
+ "--output", f"\"{output_file}/%(playlist_index)s - %(title)s.%(ext)s\"", # Organize files in a folder
248
+ ])
249
+ else:
250
+ command.extend([
251
+ "--no-playlist", # Ignore playlists if the URL is a single video
252
+ ])
253
+
254
+ # Add audio extraction options if downloading MP3
255
+ if download_type == "mp3":
256
+ command.extend([
257
+ "--extract-audio", # Extract audio
258
+ "--audio-format", "mp3", # Convert to MP3
259
+ "--audio-quality", "0", # Best quality
260
+ ])
261
+ else:
262
+ # For MP4, download the best video and audio formats and merge them
263
+ command.extend([
264
+ "-f", "bv*+ba/b", # Download best video + best audio, or fallback to best combined format
265
+ "--merge-output-format", "mp4", # Merge into MP4
266
+ ])
267
+
268
+ # Add the YouTube URL
269
+ command.append(url)
270
+
271
+ # Execute the command
272
+ self._execute_command(command)
273
+
274
+ # Check if output file(s) exist to confirm success
275
+ if playlist:
276
+ if os.path.exists(output_file) and os.listdir(output_file):
277
+ logger.info(f"Playlist download completed successfully. Files saved to: {output_file}")
278
+ return output_file
279
+ else:
280
+ logger.error(f"Playlist download failed. No files were created in: {output_file}")
281
+ return None
282
+ else:
283
+ if os.path.isfile(output_file):
284
+ logger.info(f"Download from YouTube completed successfully. Output saved to: {output_file}")
285
+ return output_file
286
+ else:
287
+ logger.error(f"Download from YouTube failed. Output file not created: {output_file}")
288
+ return None
289
+
290
+ except Exception as e:
291
+ logger.error(Fore.RED + f"An unexpected error occurred: {e}" + Fore.RESET)
@@ -92,52 +92,89 @@ def detect_platform():
92
92
 
93
93
  def get_media_info(file_path):
94
94
  try:
95
- logger.info(f"Parsing media file: {file_path}")
95
+ logger.info(f"📂 Parsing media file: {file_path}")
96
96
  media_info = MediaInfo.parse(file_path)
97
- result = {"file_path": file_path, "tracks": []}
97
+
98
+ result = {
99
+ "file_path": file_path,
100
+ "tracks": [],
101
+ "container": None,
102
+ "file_size": None,
103
+ "duration": None,
104
+ "bit_rate": None,
105
+ }
98
106
 
99
107
  for track in media_info.tracks:
100
108
  track_info = {"track_type": track.track_type}
101
109
 
102
- if track.track_type == "Video":
110
+ if track.track_type == "General":
111
+ result.update({
112
+ "container": getattr(track, "format", None),
113
+ "file_size": getattr(track, "file_size", None),
114
+ "duration": getattr(track, "duration", None),
115
+ "bit_rate": getattr(track, "overall_bit_rate", None),
116
+ "title": getattr(track, "title", None),
117
+ "encoded_application": getattr(track, "encoded_application", None),
118
+ "encoded_library": getattr(track, "encoded_library", None),
119
+ "writing_library": getattr(track, "writing_library", None),
120
+ "file_creation_date": getattr(track, "file_created_date", None),
121
+ })
122
+
123
+ elif track.track_type == "Video":
103
124
  track_info.update({
104
- "codec": track.codec,
105
- "width": track.width,
106
- "height": track.height,
107
- "frame_rate": track.frame_rate,
108
- "bit_rate": track.bit_rate,
109
- "duration": track.duration,
110
- "aspect_ratio": track.display_aspect_ratio,
125
+ "codec": getattr(track, "codec_id", getattr(track, "format", None)),
126
+ "codec_profile": getattr(track, "format_profile", None),
127
+ "width": getattr(track, "width", None),
128
+ "height": getattr(track, "height", None),
129
+ "frame_rate": getattr(track, "frame_rate", None),
130
+ "bit_rate": getattr(track, "bit_rate", None),
131
+ "duration": getattr(track, "duration", None),
132
+ "aspect_ratio": getattr(track, "display_aspect_ratio", None),
133
+ "hdr_format": getattr(track, "hdr_format", None),
134
+ "bit_depth": getattr(track, "bit_depth", None),
135
+ "color_space": getattr(track, "colour_primaries", None),
136
+ "color_range": getattr(track, "colour_range", None),
137
+ "color_transfer": getattr(track, "transfer_characteristics", None),
138
+ "chroma_subsampling": getattr(track, "chroma_subsampling", None),
111
139
  })
140
+
112
141
  elif track.track_type == "Audio":
113
142
  track_info.update({
114
- "codec": track.codec,
115
- "channels": track.channel_s,
116
- "sample_rate": track.sampling_rate,
117
- "bit_rate": track.bit_rate,
118
- "duration": track.duration,
119
- "language": track.language,
143
+ "codec": getattr(track, "codec_id", getattr(track, "format", None)),
144
+ "codec_profile": getattr(track, "format_profile", None),
145
+ "channels": getattr(track, "channel_s", None),
146
+ "sample_rate": getattr(track, "sampling_rate", None),
147
+ "bit_rate": getattr(track, "bit_rate", None),
148
+ "duration": getattr(track, "duration", None),
149
+ "language": getattr(track, "language", "Unknown"),
150
+ "compression_mode": getattr(track, "compression_mode", None),
151
+ "bit_depth": getattr(track, "bit_depth", None),
120
152
  })
153
+
121
154
  elif track.track_type == "Text":
122
155
  track_info.update({
123
- "language": track.language,
124
- "format": track.format,
156
+ "format": getattr(track, "format", None),
157
+ "language": getattr(track, "language", "Unknown"),
158
+ "default": getattr(track, "default", None),
159
+ "forced": getattr(track, "forced", None),
160
+ "format_profile": getattr(track, "format_profile", None),
125
161
  })
126
- elif track.track_type == "General":
162
+
163
+ elif track.track_type == "Chapters":
127
164
  track_info.update({
128
- "file_size": track.file_size,
129
- "format": track.format,
130
- "duration": track.duration,
131
- "overall_bit_rate": track.overall_bit_rate,
165
+ "title": getattr(track, "title", None),
166
+ "chapter_count": getattr(track, "part_count", None),
132
167
  })
133
168
 
134
- result["tracks"].append(track_info)
169
+ if any(value is not None for value in track_info.values()): # Avoid empty entries
170
+ result["tracks"].append(track_info)
135
171
 
136
- logger.info(f"Successfully extracted media information for: {file_path}")
172
+ logger.info(f"Successfully extracted media info for: {file_path}")
137
173
  return result
138
174
 
139
175
  except Exception as e:
140
- logger.error(f"Error occurred while parsing media file '{file_path}': {e}")
176
+ logger.error(f"Error parsing media file '{file_path}': {e}")
141
177
  return None
178
+
142
179
 
143
180
  # =========================================================================================================== #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: DDownloader
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: A downloader for DRM-protected & Non DRM-protected content.
5
5
  License: MIT License
6
6
 
@@ -0,0 +1,20 @@
1
+ DDownloader/__init__.py,sha256=lVZwmZNId0Dai7XBQpxglmJtIxAtZplRHDsvobL2UNo,33
2
+ DDownloader/bin/aria2c.exe,sha256=7NovO7hmaCdsPJK3Hue8N5mefFlAcJMjU_LnUnE9f6g,4840960
3
+ DDownloader/bin/ffmpeg.exe,sha256=NqWbY4tJ-ObGIvTefEyKr4RC8wE4pYiC7irz9BDl_Vw,148103168
4
+ DDownloader/bin/mkvmerge.exe,sha256=s2WkBPBuhpWPNHKXwDBfQ4vOMXLYTfxu62PbnRqK55A,19144712
5
+ DDownloader/bin/mp4decrypt.exe,sha256=JnI7mk4UduPVnUDg1aZBr4y_SWRFy8s-u_H6gG5xeOg,452096
6
+ DDownloader/bin/N_m3u8DL-RE.exe,sha256=5ck6jeDFjFCSLBeoo7q9fSGT-0Oxp_rNCxjeknTvgGE,17197568
7
+ DDownloader/bin/shaka-packager.exe,sha256=oQmfiToKeryylxsR9BiKuhXR_fS-PqPEu9W9rEsbrt8,5369344
8
+ DDownloader/bin/yt-dlp.exe,sha256=TYiozhv_gpxxZ90h6LSo7rDbFEG8JzQPCJa754HJw8A,19557107
9
+ DDownloader/main.py,sha256=eX0hrpBHKcpoqoyzKffnStU-3btaQK0VhcLCAYlL-Eg,6281
10
+ DDownloader/modules/__init__.py,sha256=7YeBgSVj8ydF7tymPSFdq22NONiQoBjKL1iwcxp4TJo,21
11
+ DDownloader/modules/args_parser.py,sha256=Xc9ZzBu-QPFrBURIcq7rl8IJbrdPMy7EMWc-odVM2QU,1105
12
+ DDownloader/modules/banners.py,sha256=0ymDNt6Wi6A7s10eCHz-99C4VSVtDxPmBt78XvHkXA8,5656
13
+ DDownloader/modules/downloader.py,sha256=8_aAnK0zto6jfx6uxFzMk8EGCCvaTULlBQdM-f9-7_4,12359
14
+ DDownloader/modules/helper.py,sha256=-PMfT0pd3AsXY1K_WP1mER3dpw9gJ99Y-Erque_62nQ,8242
15
+ DDownloader/modules/streamlink.py,sha256=t7aaHCnINzSFybTmAd-dvfGFQkepFHJwrOBcNxyJviY,504
16
+ ddownloader-0.3.9.dist-info/entry_points.txt,sha256=36xFMHKWyVvFKBCCMd3ctyd6tyujf685-qilrMpsA1E,53
17
+ ddownloader-0.3.9.dist-info/LICENSE,sha256=cnjTim3BMjb9cVC_b3oS41FESKLuvuDsufVHa_ymZRw,1090
18
+ ddownloader-0.3.9.dist-info/METADATA,sha256=rOC8-zZa5Jm8kLhoQJhRrgV6Q8cXEnSp4Gl4TSlCg-E,4906
19
+ ddownloader-0.3.9.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
+ ddownloader-0.3.9.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.1
2
+ Generator: poetry-core 2.1.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,26 +0,0 @@
1
- DDownloader/__init__.py,sha256=lVZwmZNId0Dai7XBQpxglmJtIxAtZplRHDsvobL2UNo,33
2
- DDownloader/bin/aria2c.exe,sha256=7NovO7hmaCdsPJK3Hue8N5mefFlAcJMjU_LnUnE9f6g,4840960
3
- DDownloader/bin/ffmpeg.exe,sha256=NqWbY4tJ-ObGIvTefEyKr4RC8wE4pYiC7irz9BDl_Vw,148103168
4
- DDownloader/bin/mkvmerge.exe,sha256=s2WkBPBuhpWPNHKXwDBfQ4vOMXLYTfxu62PbnRqK55A,19144712
5
- DDownloader/bin/mp4decrypt.exe,sha256=JnI7mk4UduPVnUDg1aZBr4y_SWRFy8s-u_H6gG5xeOg,452096
6
- DDownloader/bin/N_m3u8DL-RE.exe,sha256=5ck6jeDFjFCSLBeoo7q9fSGT-0Oxp_rNCxjeknTvgGE,17197568
7
- DDownloader/bin/shaka-packager.exe,sha256=oQmfiToKeryylxsR9BiKuhXR_fS-PqPEu9W9rEsbrt8,5369344
8
- DDownloader/bin/yt-dlp.exe,sha256=TYiozhv_gpxxZ90h6LSo7rDbFEG8JzQPCJa754HJw8A,19557107
9
- DDownloader/main.py,sha256=7XJrLtMaw_5taymEoPfDgfQCw9K3JJmW8gScR6gVOPw,5792
10
- DDownloader/modules/__init__.py,sha256=Jl3PXrkK7-Eox4dKIMxhOA7uVtSB0CC7qOf4NAQqa_s,21
11
- DDownloader/modules/__pycache__/__init__.cpython-310.pyc,sha256=XTOXC62dWICZNMKQGsrzT2Q_plhIs0EDYWbbzPnP4cI,192
12
- DDownloader/modules/__pycache__/args_parser.cpython-310.pyc,sha256=wRZBVDvaj3u6kMxUgDeegIgCDbpI5Xc8-FcnePt8O-Y,845
13
- DDownloader/modules/__pycache__/banners.cpython-310.pyc,sha256=OPyrjSYpT2vf2uKiVJJ3QeMbiLUECT1fVo7B51Dc7LM,5618
14
- DDownloader/modules/__pycache__/dash_downloader.cpython-310.pyc,sha256=dGuwXBw_MuwE9i7sC_Ze_wK3iz_9KA85w-0aJjwJyDs,4644
15
- DDownloader/modules/__pycache__/helper.cpython-310.pyc,sha256=wOX6-I0QgXxXQXfzV7TUBahhb30Xid6MWx6rxZkIv0g,4200
16
- DDownloader/modules/__pycache__/hls_downloader.cpython-310.pyc,sha256=Hg5C_O0M4WtnP6fN9OTwRDr1s8F67feBVkQONLNIT-E,4633
17
- DDownloader/modules/args_parser.py,sha256=Xc9ZzBu-QPFrBURIcq7rl8IJbrdPMy7EMWc-odVM2QU,1105
18
- DDownloader/modules/banners.py,sha256=s63Rd9cwGLvDbNUvCpWMK0I2rIBAYGl5dmQO9eP9Wvs,5656
19
- DDownloader/modules/downloader.py,sha256=xzuWBzXSoz0yU-BtkAPuqRNaPsxgcnTYvunWOtroQKU,7783
20
- DDownloader/modules/helper.py,sha256=b8h-h4_JqE02D26qBzSRW11LWhYUTnBkNIeYlWRO-ZY,5951
21
- DDownloader/modules/streamlink.py,sha256=t7aaHCnINzSFybTmAd-dvfGFQkepFHJwrOBcNxyJviY,504
22
- ddownloader-0.3.7.dist-info/entry_points.txt,sha256=36xFMHKWyVvFKBCCMd3ctyd6tyujf685-qilrMpsA1E,53
23
- ddownloader-0.3.7.dist-info/LICENSE,sha256=cnjTim3BMjb9cVC_b3oS41FESKLuvuDsufVHa_ymZRw,1090
24
- ddownloader-0.3.7.dist-info/METADATA,sha256=8Utz-Ii1130UMi1wnkM0qQu6sgD6eDUSFlG_ge4KrMA,4906
25
- ddownloader-0.3.7.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
26
- ddownloader-0.3.7.dist-info/RECORD,,