DDownloader 0.1.9__tar.gz → 0.2.3__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.
- ddownloader-0.2.3/DDownloader/main.py +95 -0
- ddownloader-0.2.3/DDownloader/modules/args_parser.py +24 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader/modules/banners.py +1 -1
- ddownloader-0.2.3/DDownloader/modules/dash_downloader.py +94 -0
- ddownloader-0.2.3/DDownloader/modules/helper.py +69 -0
- ddownloader-0.2.3/DDownloader/modules/hls_downloader.py +93 -0
- ddownloader-0.2.3/DDownloader.egg-info/PKG-INFO +86 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader.egg-info/SOURCES.txt +4 -1
- ddownloader-0.2.3/LICENSE +21 -0
- ddownloader-0.2.3/PKG-INFO +86 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/README.md +11 -1
- ddownloader-0.2.3/pyproject.toml +34 -0
- ddownloader-0.1.9/DDownloader/main.py +0 -57
- ddownloader-0.1.9/DDownloader/modules/dash_downloader.py +0 -74
- ddownloader-0.1.9/DDownloader/modules/hls_downloader.py +0 -73
- ddownloader-0.1.9/DDownloader.egg-info/PKG-INFO +0 -56
- ddownloader-0.1.9/PKG-INFO +0 -56
- ddownloader-0.1.9/setup.py +0 -35
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader/__init__.py +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader/modules/__init__.py +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader/modules/streamlink.py +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader.egg-info/dependency_links.txt +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader.egg-info/entry_points.txt +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader.egg-info/requires.txt +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/DDownloader.egg-info/top_level.txt +0 -0
- {ddownloader-0.1.9 → ddownloader-0.2.3}/setup.cfg +0 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
import os
|
2
|
+
import re
|
3
|
+
import logging
|
4
|
+
import coloredlogs
|
5
|
+
import time
|
6
|
+
from pathlib import Path
|
7
|
+
from colorama import Fore, Style
|
8
|
+
from DDownloader.modules.helper import download_binaries, detect_platform
|
9
|
+
from DDownloader.modules.args_parser import parse_arguments
|
10
|
+
from DDownloader.modules.banners import banners
|
11
|
+
from DDownloader.modules.dash_downloader import DASH
|
12
|
+
from DDownloader.modules.hls_downloader import HLS
|
13
|
+
|
14
|
+
# Setup logger
|
15
|
+
logger = logging.getLogger("+ MAIN + ")
|
16
|
+
coloredlogs.install(level='DEBUG', logger=logger)
|
17
|
+
|
18
|
+
def validate_directories():
|
19
|
+
downloads_dir = 'downloads'
|
20
|
+
if not os.path.exists(downloads_dir):
|
21
|
+
os.makedirs(downloads_dir)
|
22
|
+
# logger.debug(f"Created '{downloads_dir}' directory.")
|
23
|
+
|
24
|
+
def display_help():
|
25
|
+
"""Display custom help message with emoji."""
|
26
|
+
print(
|
27
|
+
f"{Fore.WHITE}+" + "=" * 80 + f"+{Style.RESET_ALL}\n"
|
28
|
+
f"{Fore.CYAN}{'Option':<40}{'Description':<90}{Style.RESET_ALL}\n"
|
29
|
+
f"{Fore.WHITE}+" + "=" * 80 + f"+{Style.RESET_ALL}\n"
|
30
|
+
f" {Fore.GREEN}-u, --url{' ' * 22}{Style.RESET_ALL}URL of the manifest (mpd/m3u8) 🌐\n"
|
31
|
+
f" {Fore.GREEN}-p, --proxy{' ' * 20}{Style.RESET_ALL}A proxy with protocol (http://ip:port) 🌍\n"
|
32
|
+
f" {Fore.GREEN}-o, --output{' ' * 19}{Style.RESET_ALL}Name of the output file 💾\n"
|
33
|
+
f" {Fore.GREEN}-k, --key{' ' * 22}{Style.RESET_ALL}Decryption key in KID:KEY format 🔑\n"
|
34
|
+
f" {Fore.GREEN}-h, --help{' ' * 21}{Style.RESET_ALL}Show this help message and exit ❓\n"
|
35
|
+
f"{Fore.WHITE}+" + "=" * 80 + f"+{Style.RESET_ALL}\n"
|
36
|
+
)
|
37
|
+
|
38
|
+
def main():
|
39
|
+
banners()
|
40
|
+
time.sleep(1)
|
41
|
+
platform_name = detect_platform()
|
42
|
+
logger.info(f"Running on platform: {platform_name}")
|
43
|
+
time.sleep(1)
|
44
|
+
|
45
|
+
logger.info(f"Downloading binaries... Please wait!")
|
46
|
+
bin_dir = Path(__file__).resolve().parent / "bin"
|
47
|
+
download_binaries(bin_dir)
|
48
|
+
logger.info(f"{Fore.GREEN}Downloading completed! Bye!{Fore.RESET}")
|
49
|
+
time.sleep(1)
|
50
|
+
banners()
|
51
|
+
|
52
|
+
validate_directories()
|
53
|
+
try:
|
54
|
+
args = parse_arguments()
|
55
|
+
except SystemExit:
|
56
|
+
display_help()
|
57
|
+
exit(1)
|
58
|
+
|
59
|
+
# Detect and initialize appropriate downloader
|
60
|
+
downloader = None
|
61
|
+
if re.search(r"\.mpd\b", args.url, re.IGNORECASE):
|
62
|
+
logger.info("DASH stream detected. Initializing DASH downloader...")
|
63
|
+
downloader = DASH()
|
64
|
+
elif re.search(r"\.m3u8\b", args.url, re.IGNORECASE):
|
65
|
+
logger.info("HLS stream detected. Initializing HLS downloader...")
|
66
|
+
downloader = HLS()
|
67
|
+
else:
|
68
|
+
logger.error("Unsupported URL format. Please provide a valid DASH (.mpd) or HLS (.m3u8) URL.")
|
69
|
+
exit(1)
|
70
|
+
|
71
|
+
# Configure downloader
|
72
|
+
downloader.manifest_url = args.url
|
73
|
+
downloader.output_name = args.output
|
74
|
+
downloader.decryption_keys = args.key or []
|
75
|
+
downloader.proxy = args.proxy # Add proxy if provided
|
76
|
+
|
77
|
+
# Log provided decryption keys
|
78
|
+
if downloader.decryption_keys:
|
79
|
+
logger.info("Decryption keys provided:")
|
80
|
+
for key in downloader.decryption_keys:
|
81
|
+
logger.info(f" --key {key}")
|
82
|
+
print(Fore.MAGENTA + "=" * 80 + Fore.RESET)
|
83
|
+
|
84
|
+
# Execute downloader
|
85
|
+
try:
|
86
|
+
if isinstance(downloader, DASH):
|
87
|
+
downloader.dash_downloader()
|
88
|
+
elif isinstance(downloader, HLS):
|
89
|
+
downloader.hls_downloader()
|
90
|
+
except Exception as e:
|
91
|
+
logger.error(f"An error occurred during the download process: {e}")
|
92
|
+
exit(1)
|
93
|
+
|
94
|
+
if __name__ == "__main__":
|
95
|
+
main()
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import argparse
|
2
|
+
from colorama import Fore, Style
|
3
|
+
|
4
|
+
def parse_arguments():
|
5
|
+
"""Parse and return command-line arguments."""
|
6
|
+
# Create the ArgumentParser with no default help and no description
|
7
|
+
parser = argparse.ArgumentParser(
|
8
|
+
add_help=False, # Disable default help
|
9
|
+
usage="", # Suppress the default usage message
|
10
|
+
)
|
11
|
+
|
12
|
+
# Add arguments (these will not include the default descriptions)
|
13
|
+
parser.add_argument("-u", "--url", required=True, help=argparse.SUPPRESS)
|
14
|
+
parser.add_argument("-p", "--proxy", help=argparse.SUPPRESS)
|
15
|
+
parser.add_argument("-o", "--output", required=True, help=argparse.SUPPRESS)
|
16
|
+
parser.add_argument("-k", "--key", action="append", help=argparse.SUPPRESS)
|
17
|
+
parser.add_argument(
|
18
|
+
"-h", "--help",
|
19
|
+
action="help",
|
20
|
+
default=argparse.SUPPRESS,
|
21
|
+
help=argparse.SUPPRESS
|
22
|
+
)
|
23
|
+
|
24
|
+
return parser.parse_args()
|
@@ -20,7 +20,7 @@ def banners():
|
|
20
20
|
stdout.write(""+Fore.YELLOW +"╔════════════════════════════════════════════════════════════════════════════╝\n")
|
21
21
|
stdout.write(""+Fore.YELLOW +"║ \x1b[38;2;255;20;147m• "+Fore.GREEN+"GITHUB "+Fore.RED+" |"+Fore.LIGHTWHITE_EX+" GITHUB.COM/THATNOTEASY "+Fore.YELLOW+"║\n")
|
22
22
|
stdout.write(""+Fore.YELLOW +"╚════════════════════════════════════════════════════════════════════════════╝\n")
|
23
|
-
print(f"{Fore.YELLOW}[DDownloader] - {Fore.GREEN}Download DASH or HLS streams with decryption keys. - {Fore.RED}[V0.
|
23
|
+
print(f"{Fore.YELLOW}[DDownloader] - {Fore.GREEN}Download DASH or HLS streams with decryption keys. - {Fore.RED}[V0.2.3] \n{Fore.RESET}")
|
24
24
|
|
25
25
|
|
26
26
|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import os
|
2
|
+
import subprocess
|
3
|
+
import logging
|
4
|
+
import platform
|
5
|
+
import coloredlogs
|
6
|
+
from colorama import Fore
|
7
|
+
|
8
|
+
logger = logging.getLogger(Fore.RED + "+ DASH + ")
|
9
|
+
coloredlogs.install(level='DEBUG', logger=logger)
|
10
|
+
|
11
|
+
class DASH:
|
12
|
+
def __init__(self):
|
13
|
+
self.manifest_url = None
|
14
|
+
self.output_name = None
|
15
|
+
self.proxy = None
|
16
|
+
self.decryption_keys = []
|
17
|
+
self.binary_path = self._get_binary_path()
|
18
|
+
|
19
|
+
def _get_binary_path(self):
|
20
|
+
"""
|
21
|
+
Dynamically determine the path to the binary file in the 'bin' directory relative to the main module.
|
22
|
+
"""
|
23
|
+
# Locate the base directory for the project (relative to main.py)
|
24
|
+
base_dir = os.path.dirname(os.path.abspath(__file__)) # Directory containing the current module
|
25
|
+
project_root = os.path.dirname(base_dir) # Go up one level to the project root
|
26
|
+
bin_dir = os.path.join(project_root, 'bin') # Bin directory is under the project root
|
27
|
+
|
28
|
+
# Determine the binary file name based on the platform
|
29
|
+
binary_name = 'N_m3u8DL-RE.exe' if platform.system() == 'Windows' else 'N_m3u8DL-RE'
|
30
|
+
binary = os.path.join(bin_dir, binary_name)
|
31
|
+
|
32
|
+
# Check if the binary exists
|
33
|
+
if not os.path.isfile(binary):
|
34
|
+
logger.error(f"Binary not found: {binary}")
|
35
|
+
raise FileNotFoundError(f"Binary not found: {binary}")
|
36
|
+
|
37
|
+
# Ensure the binary is executable on Linux
|
38
|
+
if platform.system() == 'Linux':
|
39
|
+
chmod_command = ['chmod', '+x', binary]
|
40
|
+
try:
|
41
|
+
subprocess.run(chmod_command, check=True)
|
42
|
+
logger.info(Fore.CYAN + f"Set executable permission for: {binary}" + Fore.RESET)
|
43
|
+
except subprocess.CalledProcessError as e:
|
44
|
+
logger.error(Fore.RED + f"Failed to set executable permissions for: {binary}" + Fore.RESET)
|
45
|
+
raise RuntimeError(f"Could not set executable permissions for: {binary}") from e
|
46
|
+
|
47
|
+
return binary
|
48
|
+
|
49
|
+
def dash_downloader(self):
|
50
|
+
if not self.manifest_url:
|
51
|
+
logger.error("Manifest URL is not set.")
|
52
|
+
return
|
53
|
+
command = self._build_command()
|
54
|
+
self._execute_command(command)
|
55
|
+
|
56
|
+
def _build_command(self):
|
57
|
+
command = [
|
58
|
+
self.binary_path,
|
59
|
+
f'"{self.manifest_url}"',
|
60
|
+
'--select-video', 'BEST',
|
61
|
+
'--select-audio', 'BEST',
|
62
|
+
'-mt',
|
63
|
+
'-M', 'format=mp4',
|
64
|
+
'--save-dir', 'downloads',
|
65
|
+
'--tmp-dir', 'downloads',
|
66
|
+
'--del-after-done',
|
67
|
+
'--save-name', self.output_name
|
68
|
+
]
|
69
|
+
|
70
|
+
for key in self.decryption_keys:
|
71
|
+
command.extend(['--key', key])
|
72
|
+
|
73
|
+
if self.proxy:
|
74
|
+
if not self.proxy.startswith("http://"):
|
75
|
+
self.proxy = f"http://{self.proxy}"
|
76
|
+
command.extend(['--custom-proxy', self.proxy])
|
77
|
+
# logger.debug(f"Built command: {' '.join(command)}")
|
78
|
+
return command
|
79
|
+
|
80
|
+
def _execute_command(self, command):
|
81
|
+
try:
|
82
|
+
command_str = ' '.join(command)
|
83
|
+
# logger.debug(f"Executing command: {command_str}")
|
84
|
+
result = os.system(command_str)
|
85
|
+
|
86
|
+
if result == 0:
|
87
|
+
logger.info(Fore.GREEN + "Downloaded successfully. Bye!" + Fore.RESET)
|
88
|
+
else:
|
89
|
+
logger.info(Fore.GREEN + "Downloaded successfully. Bye!" + Fore.RESET)
|
90
|
+
# logger.error(Fore.RED + f"Download failed with result code: {result}" + Fore.RESET)
|
91
|
+
# logger.error(Fore.RED + f"Command: {command_str}" + Fore.RESET)
|
92
|
+
except Exception as e:
|
93
|
+
logger.error(Fore.RED + f"An unexpected error occurred: {e}" + Fore.RESET)
|
94
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import os
|
2
|
+
import requests
|
3
|
+
from tqdm import tqdm
|
4
|
+
from colorama import Fore
|
5
|
+
import logging
|
6
|
+
import coloredlogs
|
7
|
+
import platform
|
8
|
+
|
9
|
+
logger = logging.getLogger(Fore.GREEN + "+ HELPER + ")
|
10
|
+
coloredlogs.install(level='DEBUG', logger=logger)
|
11
|
+
|
12
|
+
binaries = [
|
13
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/N_m3u8DL-RE",
|
14
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/N_m3u8DL-RE.exe",
|
15
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/ffmpeg.exe",
|
16
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/aria2c.exe",
|
17
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/mp4decrypt.exe",
|
18
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/shaka-packager.exe",
|
19
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/yt-dl.exe",
|
20
|
+
"https://github.com/ThatNotEasy/DDownloader/raw/refs/heads/main/DDownloader/bin/mkvmerge.exe"
|
21
|
+
]
|
22
|
+
|
23
|
+
def download_binaries(bin_dir):
|
24
|
+
os.makedirs(bin_dir, exist_ok=True)
|
25
|
+
# logger.info(f"Created or confirmed directory: {bin_dir}")
|
26
|
+
|
27
|
+
for binary_url in binaries:
|
28
|
+
try:
|
29
|
+
filename = binary_url.split("/")[-1]
|
30
|
+
filepath = os.path.join(bin_dir, filename)
|
31
|
+
|
32
|
+
if os.path.exists(filepath):
|
33
|
+
logger.info(f"Skipping {filename} (already exists).")
|
34
|
+
continue
|
35
|
+
|
36
|
+
logger.info(f"Downloading {filename} from {binary_url}...")
|
37
|
+
response = requests.get(binary_url, stream=True, timeout=30)
|
38
|
+
response.raise_for_status()
|
39
|
+
|
40
|
+
# Total size for progress bar
|
41
|
+
total_size = int(response.headers.get('content-length', 0))
|
42
|
+
with open(filepath, "wb") as file, tqdm(
|
43
|
+
total=total_size,
|
44
|
+
unit='B',
|
45
|
+
unit_scale=True,
|
46
|
+
desc=f"{Fore.CYAN}{filename}{Fore.RESET}",
|
47
|
+
dynamic_ncols=True,
|
48
|
+
bar_format="{l_bar}{bar} | {n_fmt}/{total_fmt} [{rate_fmt}]"
|
49
|
+
) as progress_bar:
|
50
|
+
for chunk in response.iter_content(chunk_size=8192):
|
51
|
+
file.write(chunk)
|
52
|
+
progress_bar.update(len(chunk))
|
53
|
+
|
54
|
+
logger.info(f"{Fore.GREEN}Downloaded and saved: {filepath}{Fore.RESET}")
|
55
|
+
except requests.exceptions.RequestException as e:
|
56
|
+
logger.error(f"{Fore.RED}Failed to download {binary_url}: {e}{Fore.RESET}")
|
57
|
+
except Exception as e:
|
58
|
+
logger.error(f"{Fore.RED}Unexpected error for {binary_url}: {e}{Fore.RESET}")
|
59
|
+
|
60
|
+
def detect_platform():
|
61
|
+
system_platform = platform.system().lower()
|
62
|
+
if system_platform == 'windows':
|
63
|
+
return 'Windows'
|
64
|
+
elif system_platform == 'linux':
|
65
|
+
return 'Linux'
|
66
|
+
elif system_platform == 'darwin':
|
67
|
+
return 'MacOS'
|
68
|
+
else:
|
69
|
+
return 'Unknown'
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import os
|
2
|
+
import subprocess
|
3
|
+
import logging
|
4
|
+
import platform
|
5
|
+
import coloredlogs
|
6
|
+
from colorama import Fore
|
7
|
+
|
8
|
+
logger = logging.getLogger(Fore.RED + "+ HLS + ")
|
9
|
+
coloredlogs.install(level='DEBUG', logger=logger)
|
10
|
+
|
11
|
+
class HLS:
|
12
|
+
def __init__(self):
|
13
|
+
self.manifest_url = None
|
14
|
+
self.output_name = None
|
15
|
+
self.proxy = None
|
16
|
+
self.decryption_keys = []
|
17
|
+
self.binary_path = self._get_binary_path()
|
18
|
+
|
19
|
+
def _get_binary_path(self):
|
20
|
+
"""
|
21
|
+
Dynamically determine the path to the binary file in the 'bin' directory relative to the main module.
|
22
|
+
"""
|
23
|
+
# Locate the base directory for the project (relative to main.py)
|
24
|
+
base_dir = os.path.dirname(os.path.abspath(__file__)) # Directory containing the current module
|
25
|
+
project_root = os.path.dirname(base_dir) # Go up one level to the project root
|
26
|
+
bin_dir = os.path.join(project_root, 'bin') # Bin directory is under the project root
|
27
|
+
|
28
|
+
# Determine the binary file name based on the platform
|
29
|
+
binary_name = 'N_m3u8DL-RE.exe' if platform.system() == 'Windows' else 'N_m3u8DL-RE'
|
30
|
+
binary = os.path.join(bin_dir, binary_name)
|
31
|
+
|
32
|
+
# Check if the binary exists
|
33
|
+
if not os.path.isfile(binary):
|
34
|
+
logger.error(f"Binary not found: {binary}")
|
35
|
+
raise FileNotFoundError(f"Binary not found: {binary}")
|
36
|
+
|
37
|
+
# Ensure the binary is executable on Linux
|
38
|
+
if platform.system() == 'Linux':
|
39
|
+
chmod_command = ['chmod', '+x', binary]
|
40
|
+
try:
|
41
|
+
subprocess.run(chmod_command, check=True)
|
42
|
+
logger.info(Fore.CYAN + f"Set executable permission for: {binary}" + Fore.RESET)
|
43
|
+
except subprocess.CalledProcessError as e:
|
44
|
+
logger.error(Fore.RED + f"Failed to set executable permissions for: {binary}" + Fore.RESET)
|
45
|
+
raise RuntimeError(f"Could not set executable permissions for: {binary}") from e
|
46
|
+
|
47
|
+
return binary
|
48
|
+
|
49
|
+
def hls_downloader(self):
|
50
|
+
if not self.manifest_url:
|
51
|
+
logger.error("Manifest URL is not set.")
|
52
|
+
return
|
53
|
+
command = self._build_command()
|
54
|
+
self._execute_command(command)
|
55
|
+
|
56
|
+
def _build_command(self):
|
57
|
+
command = [
|
58
|
+
self.binary_path,
|
59
|
+
f'"{self.manifest_url}"',
|
60
|
+
'--select-video', 'BEST',
|
61
|
+
'--select-audio', 'BEST',
|
62
|
+
'-mt',
|
63
|
+
'-M', 'format=mp4',
|
64
|
+
'--save-dir', 'downloads',
|
65
|
+
'--tmp-dir', 'downloads',
|
66
|
+
'--del-after-done',
|
67
|
+
'--save-name', self.output_name
|
68
|
+
]
|
69
|
+
|
70
|
+
for key in self.decryption_keys:
|
71
|
+
command.extend(['--key', key])
|
72
|
+
|
73
|
+
if self.proxy:
|
74
|
+
if not self.proxy.startswith("http://"):
|
75
|
+
self.proxy = f"http://{self.proxy}"
|
76
|
+
command.extend(['--custom-proxy', self.proxy])
|
77
|
+
# logger.debug(f"Built command: {' '.join(command)}")
|
78
|
+
return command
|
79
|
+
|
80
|
+
def _execute_command(self, command):
|
81
|
+
try:
|
82
|
+
command_str = ' '.join(command)
|
83
|
+
# logger.debug(f"Executing command: {command_str}")
|
84
|
+
result = os.system(command_str)
|
85
|
+
|
86
|
+
if result == 0:
|
87
|
+
logger.info(Fore.GREEN + "Downloaded successfully. Bye!" + Fore.RESET)
|
88
|
+
else:
|
89
|
+
logger.info(Fore.GREEN + "Downloaded successfully. Bye!" + Fore.RESET)
|
90
|
+
# logger.error(Fore.RED + f"Download failed with result code: {result}" + Fore.RESET)
|
91
|
+
# logger.error(Fore.RED + f"Command: {command_str}" + Fore.RESET)
|
92
|
+
except Exception as e:
|
93
|
+
logger.error(Fore.RED + f"An unexpected error occurred: {e}" + Fore.RESET)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: DDownloader
|
3
|
+
Version: 0.2.3
|
4
|
+
Summary: A downloader for DRM-protected content.
|
5
|
+
Author-email: ThatNotEasy <apidotmy@proton.me>
|
6
|
+
License: MIT License
|
7
|
+
|
8
|
+
Copyright (c) [2024] [DDownloader]
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following condition:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in
|
18
|
+
all copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
25
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
26
|
+
IN THE SOFTWARE.
|
27
|
+
Project-URL: homepage, https://github.com/ThatNotEasy/DDownloader
|
28
|
+
Classifier: Programming Language :: Python :: 3
|
29
|
+
Classifier: Programming Language :: Python :: 3.10
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
31
|
+
Classifier: Operating System :: OS Independent
|
32
|
+
Requires-Python: >=3.10
|
33
|
+
Description-Content-Type: text/markdown
|
34
|
+
License-File: LICENSE
|
35
|
+
Requires-Dist: requests>=2.26.0
|
36
|
+
Requires-Dist: coloredlogs>=15.0
|
37
|
+
Requires-Dist: loguru>=0.6.0
|
38
|
+
|
39
|
+
# DDownloader
|
40
|
+
- DDownloader is a Python library to download HLS and DASH manifests and decrypt media files.
|
41
|
+
|
42
|
+
# Features
|
43
|
+
- Download HLS streams using N_m3u8DL-RE.
|
44
|
+
- Download DASH manifests and segments.
|
45
|
+
- Decrypt media files using mp4decrypt.
|
46
|
+
|
47
|
+
# Installation
|
48
|
+
Use the package manager pip to install DDownloader.
|
49
|
+
```pip install DDownloader```
|
50
|
+
|
51
|
+
# Usage
|
52
|
+
|
53
|
+
- Download DASH content using the library:
|
54
|
+
|
55
|
+
```python
|
56
|
+
from DDownloader.dash_downloader import DASH
|
57
|
+
|
58
|
+
dash_downloader = DASH()
|
59
|
+
dash_downloader.manifest_url = "https://example.com/path/to/manifest.mpd" # Set your DASH manifest URL
|
60
|
+
dash_downloader.output_name = "output.mp4" # Set desired output name
|
61
|
+
dash_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
62
|
+
dash_downloader.dash_downloader()
|
63
|
+
```
|
64
|
+
|
65
|
+
- Download HLS content using the library:
|
66
|
+
```python
|
67
|
+
from DDownloader.hls_downloader import HLS
|
68
|
+
|
69
|
+
hls_downloader = HLS()
|
70
|
+
hls_downloader.manifest_url = "https://example.com/path/to/manifest.m3u8" # Set your HLS manifest URL
|
71
|
+
hls_downloader.output_name = "output.mp4" # Set desired output name
|
72
|
+
hls_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
73
|
+
hls_downloader.hls_downloader() # Call the downloader method
|
74
|
+
```
|
75
|
+
|
76
|
+
- CLI Usage:
|
77
|
+
```bash
|
78
|
+
DDownloader -h
|
79
|
+
```
|
80
|
+
|
81
|
+
- 
|
82
|
+
|
83
|
+
|
84
|
+
## THIS PROJECT STILL IN DEVELOPMENT
|
85
|
+
|
86
|
+
- Contributions are welcome! Feel free to open issues, create pull requests, or provide suggestions.
|
@@ -1,5 +1,6 @@
|
|
1
|
+
LICENSE
|
1
2
|
README.md
|
2
|
-
|
3
|
+
pyproject.toml
|
3
4
|
DDownloader/__init__.py
|
4
5
|
DDownloader/main.py
|
5
6
|
DDownloader.egg-info/PKG-INFO
|
@@ -9,7 +10,9 @@ DDownloader.egg-info/entry_points.txt
|
|
9
10
|
DDownloader.egg-info/requires.txt
|
10
11
|
DDownloader.egg-info/top_level.txt
|
11
12
|
DDownloader/modules/__init__.py
|
13
|
+
DDownloader/modules/args_parser.py
|
12
14
|
DDownloader/modules/banners.py
|
13
15
|
DDownloader/modules/dash_downloader.py
|
16
|
+
DDownloader/modules/helper.py
|
14
17
|
DDownloader/modules/hls_downloader.py
|
15
18
|
DDownloader/modules/streamlink.py
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) [2024] [DDownloader]
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following condition:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
+
IN THE SOFTWARE.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: DDownloader
|
3
|
+
Version: 0.2.3
|
4
|
+
Summary: A downloader for DRM-protected content.
|
5
|
+
Author-email: ThatNotEasy <apidotmy@proton.me>
|
6
|
+
License: MIT License
|
7
|
+
|
8
|
+
Copyright (c) [2024] [DDownloader]
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following condition:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in
|
18
|
+
all copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
25
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
26
|
+
IN THE SOFTWARE.
|
27
|
+
Project-URL: homepage, https://github.com/ThatNotEasy/DDownloader
|
28
|
+
Classifier: Programming Language :: Python :: 3
|
29
|
+
Classifier: Programming Language :: Python :: 3.10
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
31
|
+
Classifier: Operating System :: OS Independent
|
32
|
+
Requires-Python: >=3.10
|
33
|
+
Description-Content-Type: text/markdown
|
34
|
+
License-File: LICENSE
|
35
|
+
Requires-Dist: requests>=2.26.0
|
36
|
+
Requires-Dist: coloredlogs>=15.0
|
37
|
+
Requires-Dist: loguru>=0.6.0
|
38
|
+
|
39
|
+
# DDownloader
|
40
|
+
- DDownloader is a Python library to download HLS and DASH manifests and decrypt media files.
|
41
|
+
|
42
|
+
# Features
|
43
|
+
- Download HLS streams using N_m3u8DL-RE.
|
44
|
+
- Download DASH manifests and segments.
|
45
|
+
- Decrypt media files using mp4decrypt.
|
46
|
+
|
47
|
+
# Installation
|
48
|
+
Use the package manager pip to install DDownloader.
|
49
|
+
```pip install DDownloader```
|
50
|
+
|
51
|
+
# Usage
|
52
|
+
|
53
|
+
- Download DASH content using the library:
|
54
|
+
|
55
|
+
```python
|
56
|
+
from DDownloader.dash_downloader import DASH
|
57
|
+
|
58
|
+
dash_downloader = DASH()
|
59
|
+
dash_downloader.manifest_url = "https://example.com/path/to/manifest.mpd" # Set your DASH manifest URL
|
60
|
+
dash_downloader.output_name = "output.mp4" # Set desired output name
|
61
|
+
dash_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
62
|
+
dash_downloader.dash_downloader()
|
63
|
+
```
|
64
|
+
|
65
|
+
- Download HLS content using the library:
|
66
|
+
```python
|
67
|
+
from DDownloader.hls_downloader import HLS
|
68
|
+
|
69
|
+
hls_downloader = HLS()
|
70
|
+
hls_downloader.manifest_url = "https://example.com/path/to/manifest.m3u8" # Set your HLS manifest URL
|
71
|
+
hls_downloader.output_name = "output.mp4" # Set desired output name
|
72
|
+
hls_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
73
|
+
hls_downloader.hls_downloader() # Call the downloader method
|
74
|
+
```
|
75
|
+
|
76
|
+
- CLI Usage:
|
77
|
+
```bash
|
78
|
+
DDownloader -h
|
79
|
+
```
|
80
|
+
|
81
|
+
- 
|
82
|
+
|
83
|
+
|
84
|
+
## THIS PROJECT STILL IN DEVELOPMENT
|
85
|
+
|
86
|
+
- Contributions are welcome! Feel free to open issues, create pull requests, or provide suggestions.
|
@@ -35,4 +35,14 @@ hls_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
|
35
35
|
hls_downloader.hls_downloader() # Call the downloader method
|
36
36
|
```
|
37
37
|
|
38
|
-
|
38
|
+
- CLI Usage:
|
39
|
+
```bash
|
40
|
+
DDownloader -h
|
41
|
+
```
|
42
|
+
|
43
|
+
- 
|
44
|
+
|
45
|
+
|
46
|
+
## THIS PROJECT STILL IN DEVELOPMENT
|
47
|
+
|
48
|
+
- Contributions are welcome! Feel free to open issues, create pull requests, or provide suggestions.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "DDownloader"
|
7
|
+
version = "0.2.3"
|
8
|
+
description = "A downloader for DRM-protected content."
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
10
|
+
authors = [
|
11
|
+
{ name = "ThatNotEasy", email = "apidotmy@proton.me" }
|
12
|
+
]
|
13
|
+
license = { file = "LICENSE" }
|
14
|
+
requires-python = ">=3.10"
|
15
|
+
classifiers = [
|
16
|
+
"Programming Language :: Python :: 3",
|
17
|
+
"Programming Language :: Python :: 3.10",
|
18
|
+
"License :: OSI Approved :: MIT License",
|
19
|
+
"Operating System :: OS Independent"
|
20
|
+
]
|
21
|
+
dependencies = [
|
22
|
+
"requests>=2.26.0",
|
23
|
+
"coloredlogs>=15.0",
|
24
|
+
"loguru>=0.6.0"
|
25
|
+
]
|
26
|
+
|
27
|
+
[project.urls]
|
28
|
+
homepage = "https://github.com/ThatNotEasy/DDownloader"
|
29
|
+
|
30
|
+
[tool.setuptools.packages.find]
|
31
|
+
include = ["DDownloader", "DDownloader.*"]
|
32
|
+
|
33
|
+
[project.scripts]
|
34
|
+
DDownloader = "DDownloader.main:main"
|
@@ -1,57 +0,0 @@
|
|
1
|
-
import argparse
|
2
|
-
import logging
|
3
|
-
import coloredlogs
|
4
|
-
from DDownloader.modules.banners import banners
|
5
|
-
from DDownloader.modules.dash_downloader import DASH
|
6
|
-
from DDownloader.modules.hls_downloader import HLS
|
7
|
-
|
8
|
-
logger = logging.getLogger("+ MAIN + ")
|
9
|
-
coloredlogs.install(level='DEBUG', logger=logger)
|
10
|
-
|
11
|
-
def parse_arguments():
|
12
|
-
"""
|
13
|
-
Parse command-line arguments for the downloader.
|
14
|
-
"""
|
15
|
-
parser = argparse.ArgumentParser(description="Download DASH or HLS streams with decryption keys.")
|
16
|
-
parser.add_argument("-u", "--url", required=True, help="Manifest URL pointing to the stream (.mpd or .m3u8).")
|
17
|
-
parser.add_argument("-k", "--key", action="append", help="Decryption keys in the format KID:KEY. Use multiple -k options for multiple keys.")
|
18
|
-
parser.add_argument("-o", "--output", required=True, help="Output file name.")
|
19
|
-
return parser.parse_args()
|
20
|
-
|
21
|
-
def main():
|
22
|
-
banners()
|
23
|
-
args = parse_arguments()
|
24
|
-
|
25
|
-
# Detect DASH or HLS based on URL extension
|
26
|
-
if args.url.endswith(".mpd"):
|
27
|
-
logger.info("DASH stream detected. Initializing DASH downloader...")
|
28
|
-
downloader = DASH()
|
29
|
-
elif args.url.endswith(".m3u8"):
|
30
|
-
logger.info("HLS stream detected. Initializing HLS downloader...")
|
31
|
-
downloader = HLS()
|
32
|
-
else:
|
33
|
-
logger.error("Unsupported URL format. Please provide a valid DASH (.mpd) or HLS (.m3u8) URL.")
|
34
|
-
return
|
35
|
-
|
36
|
-
# Set downloader properties
|
37
|
-
downloader.manifest_url = args.url
|
38
|
-
downloader.output_name = args.output
|
39
|
-
downloader.decryption_keys = args.key or [] # Default to an empty list if no keys provided
|
40
|
-
|
41
|
-
# Log decryption keys
|
42
|
-
if downloader.decryption_keys:
|
43
|
-
logger.info("Decryption key(s) provided:")
|
44
|
-
for key in downloader.decryption_keys:
|
45
|
-
logger.info(f"--key {key}")
|
46
|
-
|
47
|
-
# Start download
|
48
|
-
try:
|
49
|
-
if isinstance(downloader, DASH):
|
50
|
-
downloader.dash_downloader()
|
51
|
-
else:
|
52
|
-
downloader.hls_downloader()
|
53
|
-
except Exception as e:
|
54
|
-
logger.error(f"An error occurred: {e}")
|
55
|
-
|
56
|
-
if __name__ == "__main__":
|
57
|
-
main()
|
@@ -1,74 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import subprocess
|
3
|
-
import logging
|
4
|
-
import platform
|
5
|
-
import coloredlogs
|
6
|
-
from colorama import Fore
|
7
|
-
|
8
|
-
logger = logging.getLogger("+ DASH + ")
|
9
|
-
coloredlogs.install(level='DEBUG', logger=logger)
|
10
|
-
|
11
|
-
class DASH:
|
12
|
-
def __init__(self):
|
13
|
-
self.manifest_url = None
|
14
|
-
self.output_name = None
|
15
|
-
self.decryption_keys = [] # Store multiple keys as a list
|
16
|
-
self.binary_path = self._get_binary_path()
|
17
|
-
|
18
|
-
def _get_binary_path(self):
|
19
|
-
"""Determine the correct binary path based on the platform."""
|
20
|
-
base_path = os.path.join(os.path.dirname(__file__), 'bin', 'N_m3u8DL-RE')
|
21
|
-
|
22
|
-
if platform.system() == 'Windows':
|
23
|
-
binary = f"{base_path}.exe"
|
24
|
-
elif platform.system() == 'Linux':
|
25
|
-
binary = base_path
|
26
|
-
elif platform.system() == 'Darwin':
|
27
|
-
binary = base_path
|
28
|
-
else:
|
29
|
-
logger.error(f"Unsupported platform: {platform.system()}")
|
30
|
-
raise OSError(f"Unsupported platform: {platform.system()}")
|
31
|
-
|
32
|
-
if not os.path.exists(binary):
|
33
|
-
logger.error(f"Binary not found: {binary}")
|
34
|
-
raise FileNotFoundError(f"Binary not found: {binary}")
|
35
|
-
|
36
|
-
return binary
|
37
|
-
|
38
|
-
def dash_downloader(self):
|
39
|
-
if not self.manifest_url:
|
40
|
-
logger.error("Manifest URL is not set.")
|
41
|
-
return
|
42
|
-
|
43
|
-
command = self._build_command()
|
44
|
-
self._execute_command(command)
|
45
|
-
|
46
|
-
def _build_command(self):
|
47
|
-
command = [
|
48
|
-
self.binary_path,
|
49
|
-
self.manifest_url,
|
50
|
-
'--auto-select',
|
51
|
-
'-mt',
|
52
|
-
'-M', 'format=mp4',
|
53
|
-
'--save-dir', 'downloads',
|
54
|
-
'--tmp-dir', 'downloads',
|
55
|
-
'--save-name', self.output_name
|
56
|
-
]
|
57
|
-
for key in self.decryption_keys:
|
58
|
-
command.extend(['--key', key])
|
59
|
-
logger.debug(f"Built command: {' '.join(command)}")
|
60
|
-
return command
|
61
|
-
|
62
|
-
def _execute_command(self, command):
|
63
|
-
try:
|
64
|
-
result = subprocess.run(command, check=True)
|
65
|
-
if result.returncode == 0:
|
66
|
-
logger.info("Downloaded using N_m3u8DL-RE successfully.")
|
67
|
-
else:
|
68
|
-
logger.error(f"Download failed with result code: {result.returncode}")
|
69
|
-
|
70
|
-
except subprocess.CalledProcessError as e:
|
71
|
-
logger.error(f"Command failed: {e}")
|
72
|
-
raise RuntimeError(f"Download process failed: {e}")
|
73
|
-
except Exception as e:
|
74
|
-
logger.error(f"An unexpected error occurred: {e}")
|
@@ -1,73 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import subprocess
|
3
|
-
import logging
|
4
|
-
import platform
|
5
|
-
import coloredlogs
|
6
|
-
from colorama import Fore
|
7
|
-
|
8
|
-
logger = logging.getLogger(Fore.RED + "+ HLS + ")
|
9
|
-
coloredlogs.install(level='DEBUG', logger=logger)
|
10
|
-
|
11
|
-
class HLS:
|
12
|
-
def __init__(self):
|
13
|
-
self.manifest_url = None
|
14
|
-
self.output_name = None
|
15
|
-
self.decryption_keys = []
|
16
|
-
self.binary_path = self._get_binary_path()
|
17
|
-
|
18
|
-
def _get_binary_path(self):
|
19
|
-
base_path = os.path.join(os.path.dirname(__file__), 'bin', 'N_m3u8DL-RE')
|
20
|
-
|
21
|
-
if platform.system() == 'Windows':
|
22
|
-
binary = f"{base_path}.exe"
|
23
|
-
elif platform.system() == 'Linux':
|
24
|
-
binary = base_path
|
25
|
-
elif platform.system() == 'Darwin': # macOS
|
26
|
-
binary = base_path
|
27
|
-
else:
|
28
|
-
logger.error(f"Unsupported platform: {platform.system()}")
|
29
|
-
raise OSError(f"Unsupported platform: {platform.system()}")
|
30
|
-
|
31
|
-
if not os.path.exists(binary):
|
32
|
-
logger.error(f"Binary not found: {binary}")
|
33
|
-
raise FileNotFoundError(f"Binary not found: {binary}")
|
34
|
-
|
35
|
-
return binary
|
36
|
-
|
37
|
-
def hls_downloader(self):
|
38
|
-
if not self.manifest_url:
|
39
|
-
logger.error("Manifest URL is not set.")
|
40
|
-
return
|
41
|
-
|
42
|
-
command = self._build_command()
|
43
|
-
self._execute_command(command)
|
44
|
-
|
45
|
-
def _build_command(self):
|
46
|
-
command = [
|
47
|
-
self.binary_path,
|
48
|
-
self.manifest_url,
|
49
|
-
'--auto-select',
|
50
|
-
'-mt',
|
51
|
-
'-M', 'format=mp4',
|
52
|
-
'--save-dir', 'downloads',
|
53
|
-
'--tmp-dir', 'downloads',
|
54
|
-
'--save-name', self.output_name
|
55
|
-
]
|
56
|
-
for key in self.decryption_keys:
|
57
|
-
command.extend(['--key', key])
|
58
|
-
logger.debug(f"Built command: {' '.join(command)}")
|
59
|
-
return command
|
60
|
-
|
61
|
-
def _execute_command(self, command):
|
62
|
-
try:
|
63
|
-
result = subprocess.run(command, check=True)
|
64
|
-
if result.returncode == 0:
|
65
|
-
logger.info("Downloaded using N_m3u8DL-RE successfully.")
|
66
|
-
else:
|
67
|
-
logger.error(f"Download failed with result code: {result.returncode}")
|
68
|
-
|
69
|
-
except subprocess.CalledProcessError as e:
|
70
|
-
logger.error(f"Command failed: {e}")
|
71
|
-
raise RuntimeError(f"Download process failed: {e}")
|
72
|
-
except Exception as e:
|
73
|
-
logger.error(f"An unexpected error occurred: {e}")
|
@@ -1,56 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: DDownloader
|
3
|
-
Version: 0.1.9
|
4
|
-
Summary: A downloader for DRM-protected content.
|
5
|
-
Home-page: https://github.com/ThatNotEasy/DDownloader
|
6
|
-
Author: ThatNotEasy
|
7
|
-
Author-email: apidotmy@proton.me
|
8
|
-
License: MIT
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
12
|
-
Classifier: Operating System :: OS Independent
|
13
|
-
Requires-Python: >=3.10
|
14
|
-
Description-Content-Type: text/markdown
|
15
|
-
Requires-Dist: requests>=2.26.0
|
16
|
-
Requires-Dist: coloredlogs>=15.0
|
17
|
-
Requires-Dist: loguru>=0.6.0
|
18
|
-
|
19
|
-
# DDownloader
|
20
|
-
- DDownloader is a Python library to download HLS and DASH manifests and decrypt media files.
|
21
|
-
|
22
|
-
# Features
|
23
|
-
- Download HLS streams using N_m3u8DL-RE.
|
24
|
-
- Download DASH manifests and segments.
|
25
|
-
- Decrypt media files using mp4decrypt.
|
26
|
-
|
27
|
-
# Installation
|
28
|
-
Use the package manager pip to install DDownloader.
|
29
|
-
```pip install DDownloader```
|
30
|
-
|
31
|
-
# Usage
|
32
|
-
|
33
|
-
- Download DASH content using the library:
|
34
|
-
|
35
|
-
```python
|
36
|
-
from DDownloader.dash_downloader import DASH
|
37
|
-
|
38
|
-
dash_downloader = DASH()
|
39
|
-
dash_downloader.manifest_url = "https://example.com/path/to/manifest.mpd" # Set your DASH manifest URL
|
40
|
-
dash_downloader.output_name = "output.mp4" # Set desired output name
|
41
|
-
dash_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
42
|
-
dash_downloader.dash_downloader()
|
43
|
-
```
|
44
|
-
|
45
|
-
- Download HLS content using the library:
|
46
|
-
```python
|
47
|
-
from DDownloader.hls_downloader import HLS
|
48
|
-
|
49
|
-
hls_downloader = HLS()
|
50
|
-
hls_downloader.manifest_url = "https://example.com/path/to/manifest.m3u8" # Set your HLS manifest URL
|
51
|
-
hls_downloader.output_name = "output.mp4" # Set desired output name
|
52
|
-
hls_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
53
|
-
hls_downloader.hls_downloader() # Call the downloader method
|
54
|
-
```
|
55
|
-
|
56
|
-
# THIS PROJECT STILL IN DEVELOPMENT
|
ddownloader-0.1.9/PKG-INFO
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: DDownloader
|
3
|
-
Version: 0.1.9
|
4
|
-
Summary: A downloader for DRM-protected content.
|
5
|
-
Home-page: https://github.com/ThatNotEasy/DDownloader
|
6
|
-
Author: ThatNotEasy
|
7
|
-
Author-email: apidotmy@proton.me
|
8
|
-
License: MIT
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
12
|
-
Classifier: Operating System :: OS Independent
|
13
|
-
Requires-Python: >=3.10
|
14
|
-
Description-Content-Type: text/markdown
|
15
|
-
Requires-Dist: requests>=2.26.0
|
16
|
-
Requires-Dist: coloredlogs>=15.0
|
17
|
-
Requires-Dist: loguru>=0.6.0
|
18
|
-
|
19
|
-
# DDownloader
|
20
|
-
- DDownloader is a Python library to download HLS and DASH manifests and decrypt media files.
|
21
|
-
|
22
|
-
# Features
|
23
|
-
- Download HLS streams using N_m3u8DL-RE.
|
24
|
-
- Download DASH manifests and segments.
|
25
|
-
- Decrypt media files using mp4decrypt.
|
26
|
-
|
27
|
-
# Installation
|
28
|
-
Use the package manager pip to install DDownloader.
|
29
|
-
```pip install DDownloader```
|
30
|
-
|
31
|
-
# Usage
|
32
|
-
|
33
|
-
- Download DASH content using the library:
|
34
|
-
|
35
|
-
```python
|
36
|
-
from DDownloader.dash_downloader import DASH
|
37
|
-
|
38
|
-
dash_downloader = DASH()
|
39
|
-
dash_downloader.manifest_url = "https://example.com/path/to/manifest.mpd" # Set your DASH manifest URL
|
40
|
-
dash_downloader.output_name = "output.mp4" # Set desired output name
|
41
|
-
dash_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
42
|
-
dash_downloader.dash_downloader()
|
43
|
-
```
|
44
|
-
|
45
|
-
- Download HLS content using the library:
|
46
|
-
```python
|
47
|
-
from DDownloader.hls_downloader import HLS
|
48
|
-
|
49
|
-
hls_downloader = HLS()
|
50
|
-
hls_downloader.manifest_url = "https://example.com/path/to/manifest.m3u8" # Set your HLS manifest URL
|
51
|
-
hls_downloader.output_name = "output.mp4" # Set desired output name
|
52
|
-
hls_downloader.decryption_key = "12345:678910" # Set decryption key if needed
|
53
|
-
hls_downloader.hls_downloader() # Call the downloader method
|
54
|
-
```
|
55
|
-
|
56
|
-
# THIS PROJECT STILL IN DEVELOPMENT
|
ddownloader-0.1.9/setup.py
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
from setuptools import setup, find_packages
|
2
|
-
from pathlib import Path
|
3
|
-
|
4
|
-
# Read the long description from README.md
|
5
|
-
long_description = Path("README.md").read_text(encoding="utf-8")
|
6
|
-
|
7
|
-
setup(
|
8
|
-
name="DDownloader",
|
9
|
-
version="0.1.9",
|
10
|
-
description="A downloader for DRM-protected content.",
|
11
|
-
long_description=long_description,
|
12
|
-
long_description_content_type="text/markdown",
|
13
|
-
author="ThatNotEasy",
|
14
|
-
author_email="apidotmy@proton.me",
|
15
|
-
url="https://github.com/ThatNotEasy/DDownloader",
|
16
|
-
license="MIT",
|
17
|
-
packages=find_packages(include=["DDownloader", "DDownloader.*"]),
|
18
|
-
classifiers=[
|
19
|
-
"Programming Language :: Python :: 3",
|
20
|
-
"Programming Language :: Python :: 3.10",
|
21
|
-
"License :: OSI Approved :: MIT License",
|
22
|
-
"Operating System :: OS Independent",
|
23
|
-
],
|
24
|
-
python_requires=">=3.10",
|
25
|
-
install_requires=[
|
26
|
-
"requests>=2.26.0",
|
27
|
-
"coloredlogs>=15.0",
|
28
|
-
"loguru>=0.6.0",
|
29
|
-
],
|
30
|
-
entry_points={
|
31
|
-
"console_scripts": [
|
32
|
-
"DDownloader=DDownloader.main:main",
|
33
|
-
],
|
34
|
-
}
|
35
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|