DDownloader 0.4.0__tar.gz → 0.4.2__tar.gz

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.
Files changed (22) hide show
  1. ddownloader-0.4.2/DDownloader/bin/aria2c.exe +0 -0
  2. ddownloader-0.4.2/DDownloader/bin/mp4decrypt.exe +0 -0
  3. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/bin/shaka-packager.exe +0 -0
  4. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/main.py +19 -1
  5. ddownloader-0.4.2/DDownloader/modules/__init__.py +1 -0
  6. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/modules/args_parser.py +4 -0
  7. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/modules/banners.py +2 -1
  8. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/modules/downloader.py +76 -0
  9. {ddownloader-0.4.0 → ddownloader-0.4.2}/PKG-INFO +3 -2
  10. {ddownloader-0.4.0 → ddownloader-0.4.2}/pyproject.toml +2 -2
  11. ddownloader-0.4.0/DDownloader/bin/aria2c.exe +0 -0
  12. ddownloader-0.4.0/DDownloader/bin/mp4decrypt.exe +0 -0
  13. ddownloader-0.4.0/DDownloader/modules/__init__.py +0 -1
  14. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/__init__.py +0 -0
  15. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/bin/N_m3u8DL-RE.exe +0 -0
  16. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/bin/ffmpeg.exe +0 -0
  17. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/bin/mkvmerge.exe +0 -0
  18. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/bin/yt-dlp.exe +0 -0
  19. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/modules/helper.py +0 -0
  20. {ddownloader-0.4.0 → ddownloader-0.4.2}/DDownloader/modules/streamlink.py +0 -0
  21. {ddownloader-0.4.0 → ddownloader-0.4.2}/LICENSE +0 -0
  22. {ddownloader-0.4.0 → ddownloader-0.4.2}/README.md +0 -0
@@ -71,6 +71,7 @@ def main():
71
71
  exit(1)
72
72
 
73
73
  downloader = DOWNLOADER()
74
+ downloader.auto_select = args.auto_select
74
75
 
75
76
  if args.url:
76
77
  if re.search(r"\.mpd\b", args.url, re.IGNORECASE):
@@ -88,6 +89,7 @@ def main():
88
89
  logger.info("YouTube URL detected. Initializing YouTube downloader...")
89
90
  print(Fore.RED + "═" * 100 + Fore.RESET)
90
91
  is_playlist = "list=" in args.url
92
+ downloader.cookies = args.cookies
91
93
  downloader.youtube_downloader(
92
94
  url=args.url,
93
95
  output_file=os.path.join(downloads_dir, args.output),
@@ -95,8 +97,20 @@ def main():
95
97
  playlist=is_playlist
96
98
  )
97
99
  exit(0)
100
+ elif re.search(r"iq\.com", args.url, re.IGNORECASE):
101
+ logger.info("IQ.com URL detected. Initializing IQ.com downloader...")
102
+ print(Fore.RED + "═" * 100 + Fore.RESET)
103
+ # Set default output name if not provided
104
+ output_name = args.output if args.output else "iq_video"
105
+ downloader.cookies = args.cookies
106
+ downloader.iq_downloader(
107
+ url=args.url,
108
+ output_file=os.path.join(downloads_dir, output_name),
109
+ download_type="mp4"
110
+ )
111
+ exit(0)
98
112
  else:
99
- logger.error("Unsupported URL format. Please provide a valid DASH (.mpd), HLS (.m3u8), ISM (.ism), or YouTube URL.")
113
+ logger.error("Unsupported URL format. Please provide a valid DASH (.mpd), HLS (.m3u8), ISM (.ism), YouTube, or IQ.com URL.")
100
114
  exit(1)
101
115
 
102
116
  downloader.manifest_url = args.url
@@ -122,6 +136,10 @@ def main():
122
136
  for key in downloader.decryption_keys:
123
137
  logger.info(f" - {key}")
124
138
  print(Fore.RED + "═" * 100 + Fore.RESET + "\n")
139
+
140
+ if downloader.auto_select:
141
+ logger.info("Auto-select enabled - will choose best quality automatically")
142
+ print(Fore.RED + "═" * 100 + Fore.RESET + "\n")
125
143
 
126
144
  try:
127
145
  downloader.drm_downloader()
@@ -0,0 +1 @@
1
+ __version__ = "0.4.2"
@@ -15,8 +15,12 @@ def parse_arguments():
15
15
  parser.add_argument("-o", "--output", help=argparse.SUPPRESS)
16
16
  parser.add_argument("-k", "--key", action="append", help=argparse.SUPPRESS)
17
17
  parser.add_argument("-H", "--header", action="append", help=argparse.SUPPRESS)
18
+ parser.add_argument("-c", "--cookies", help=argparse.SUPPRESS)
18
19
  parser.add_argument("-i", "--input", help=argparse.SUPPRESS)
19
20
  parser.add_argument("-q", "--quality", help=argparse.SUPPRESS)
21
+ parser.add_argument("--auto-select",
22
+ action="store_true",
23
+ help=argparse.SUPPRESS)
20
24
  parser.add_argument(
21
25
  "-h", "--help",
22
26
  action="help",
@@ -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.4.0] \n{Fore.RESET}")
26
+ print(f"{Fore.YELLOW}[DDownloader] - {Fore.GREEN}A DRM-Protected & Non-Protected Content Downloader - {Fore.RED}[V0.4.2] \n{Fore.RESET}")
27
27
 
28
28
  # =========================================================================================================== #
29
29
 
@@ -45,6 +45,7 @@ def display_help():
45
45
  f" {Fore.GREEN}-o, --output{' ' * 19}{Style.RESET_ALL}Name of the output file 💾\n"
46
46
  f" {Fore.GREEN}-k, --key{' ' * 22}{Style.RESET_ALL}Decryption key in KID:KEY format 🔑\n"
47
47
  f" {Fore.GREEN}-H, --header{' ' * 19}{Style.RESET_ALL}Custom HTTP headers (e.g., User-Agent: value) 📋\n"
48
+ f" {Fore.GREEN}-c, --cookies{' ' * 19}{Style.RESET_ALL}Cookies file (e.g., netscape/json formatter) 📋\n"
48
49
  f"{Fore.RED}.++" + "═" * 100 + f"++.{Style.RESET_ALL}\n"
49
50
  f" {Fore.GREEN}-i, --input{' ' * 20}{Style.RESET_ALL}Input file for re-encoding. 📂\n"
50
51
  f" {Fore.GREEN}-q, --quality{' ' * 18}{Style.RESET_ALL}Target quality: HD, FHD, UHD. 🎥\n"
@@ -16,7 +16,9 @@ class DOWNLOADER:
16
16
  self.proxy = None
17
17
  self.decryption_keys = []
18
18
  self.headers = []
19
+ self.cookies = None
19
20
  self.binary_path = None
21
+ self.auto_select = False
20
22
 
21
23
  # =========================================================================================================== #
22
24
 
@@ -94,6 +96,9 @@ class DOWNLOADER:
94
96
  if not self.proxy.startswith("http://"):
95
97
  self.proxy = f"http://{self.proxy}"
96
98
  command.extend(['--custom-proxy', f'"{self.proxy}"'])
99
+
100
+ if self.auto_select:
101
+ command.extend(['--auto-select'])
97
102
 
98
103
  for header in self.headers:
99
104
  command.extend(['-H', f'"{header}"'])
@@ -116,6 +121,73 @@ class DOWNLOADER:
116
121
  except Exception as e:
117
122
  logger.error(Fore.RED + f"An unexpected error occurred: {e}" + Fore.RESET)
118
123
 
124
+ # =========================================================================================================== #
125
+
126
+ def iq_downloader(self, url, output_file, download_type="mp4"):
127
+ """
128
+ Download a video from IQ.com using yt-dlp.
129
+
130
+ Args:
131
+ url (str): The IQ.com video URL.
132
+ output_file (str): The output file path to save the video.
133
+ download_type (str): The type of download ("mp4" for video, "mp3" for audio).
134
+ """
135
+ try:
136
+ # Get the yt-dlp binary path
137
+ yt_dlp_path = self._get_binary_path("yt-dlp")
138
+
139
+ # Determine the output file extension based on download type
140
+ if download_type == "mp3":
141
+ output_file = os.path.splitext(output_file)[0] + ".mp3"
142
+ elif download_type == "mp4":
143
+ output_file = os.path.splitext(output_file)[0] + ".mp4"
144
+ else:
145
+ logger.error(Fore.RED + f"Invalid download type: {download_type}. Use 'mp4' or 'mp3'." + Fore.RESET)
146
+ return
147
+
148
+ # Build the yt-dlp command for IQ.com
149
+ command = [
150
+ yt_dlp_path,
151
+ "-o", f"\"{output_file}\"", # Output file
152
+ "--no-check-certificate", # Bypass certificate verification
153
+ "--ignore-errors", # Ignore errors and continue downloading
154
+ ]
155
+
156
+ # Add cookies if provided
157
+ if self.cookies:
158
+ command.extend(["--cookies", f"\"{self.cookies}\""])
159
+
160
+ # Add audio extraction options if downloading MP3
161
+ if download_type == "mp3":
162
+ command.extend([
163
+ "--extract-audio", # Extract audio
164
+ "--audio-format", "mp3", # Convert to MP3
165
+ "--audio-quality", "0", # Best quality
166
+ ])
167
+ else:
168
+ # For MP4, download the best video and audio formats and merge them
169
+ command.extend([
170
+ "-f", "bv*+ba/b", # Download best video + best audio, or fallback to best combined format
171
+ "--merge-output-format", "mp4", # Merge into MP4
172
+ ])
173
+
174
+ # Add the IQ.com URL
175
+ command.append(url)
176
+
177
+ # Execute the command
178
+ self._execute_command(command)
179
+
180
+ # Check if output file exists to confirm success
181
+ if os.path.isfile(output_file):
182
+ logger.info(f"Download from IQ.com completed successfully. Output saved to: {output_file}")
183
+ return output_file
184
+ else:
185
+ logger.error(f"Download from IQ.com failed. Output file not created: {output_file}")
186
+ return None
187
+
188
+ except Exception as e:
189
+ logger.error(Fore.RED + f"An unexpected error occurred: {e}" + Fore.RESET)
190
+
119
191
  # =========================================================================================================== #
120
192
 
121
193
  def re_encode_content(self, input_file, quality, codec="libx265", crf=23, preset="superfast", audio_bitrate="256k", fps=60):
@@ -252,6 +324,10 @@ class DOWNLOADER:
252
324
  "--ignore-errors", # Ignore errors and continue downloading
253
325
  ]
254
326
 
327
+ # Add cookies if provided
328
+ if self.cookies:
329
+ command.extend(["--cookies", f"\"{self.cookies}\""])
330
+
255
331
  # Add playlist-specific options if the URL is a playlist
256
332
  if playlist:
257
333
  command.extend([
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: DDownloader
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: A downloader for DRM-protected & Non DRM-protected content.
5
5
  License: MIT License
6
6
 
@@ -23,6 +23,7 @@ License: MIT License
23
23
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
24
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25
25
  IN THE SOFTWARE.
26
+ License-File: LICENSE
26
27
  Author: ThatNotEasy
27
28
  Author-email: apidotmy@proton.me
28
29
  Requires-Python: >=3.7
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "DDownloader"
7
- version = "0.4.0"
7
+ version = "0.4.2"
8
8
  description = "A downloader for DRM-protected & Non DRM-protected content."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  authors = [
@@ -25,7 +25,7 @@ classifiers = [
25
25
 
26
26
  [tool.poetry]
27
27
  name = "DDownloader"
28
- version = "0.4.0"
28
+ version = "0.4.2"
29
29
  description = "A downloader for DRM-protected & Non DRM-protected content."
30
30
  authors = ["ThatNotEasy <apidotmy@proton.me>"]
31
31
  license = "MIT"
@@ -1 +0,0 @@
1
- __version__ = "0.4.0"
File without changes
File without changes