upload
This commit is contained in:
369
helpers/aria2.py
Normal file
369
helpers/aria2.py
Normal file
@@ -0,0 +1,369 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import logging
|
||||
from configs.config import tool
|
||||
from helpers.ripprocess import ripprocess
|
||||
|
||||
|
||||
class aria2Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class aria2_moded:
|
||||
def __init__(self, aria2_download_command):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.aria2_download_command = aria2_download_command
|
||||
self.env = self.aria2DisableProxies()
|
||||
self.ripprocess = ripprocess()
|
||||
self.tool = tool()
|
||||
self.LOGA_PATH = self.tool.paths()["LOGA_PATH"]
|
||||
self.bin = self.tool.bin()
|
||||
self.aria2c_exe = self.bin["aria2c"]
|
||||
self.last_message_printed = 0
|
||||
self.speed_radar = "0kbps"
|
||||
|
||||
def aria2DisableProxies(self):
|
||||
env = os.environ.copy()
|
||||
|
||||
if env.get("http_proxy"):
|
||||
del env["http_proxy"]
|
||||
|
||||
if env.get("HTTP_PROXY"):
|
||||
del env["HTTP_PROXY"]
|
||||
|
||||
if env.get("https_proxy"):
|
||||
del env["https_proxy"]
|
||||
|
||||
if env.get("HTTPS_PROXY"):
|
||||
del env["HTTPS_PROXY"]
|
||||
|
||||
return env
|
||||
|
||||
def read_stdout(self, line):
|
||||
speed = re.search(r"DL:(.+?)ETA", line)
|
||||
eta = re.search(r"ETA:(.+?)]", line)
|
||||
connection = re.search(r"CN:(.+?)DL", line)
|
||||
percent = re.search(r"\((.*?)\)", line)
|
||||
size = re.search(r" (.*?)/(.*?)\(", line)
|
||||
|
||||
if speed and eta and connection and percent and size:
|
||||
percent = percent.group().strip().replace(")", "").replace("(", "")
|
||||
size = size.group().strip().replace(")", "").replace("(", "")
|
||||
complete, total = size.split("/")
|
||||
connection = connection.group(1).strip()
|
||||
eta = eta.group(1).strip()
|
||||
speed = speed.group(1).strip()
|
||||
self.speed_radar = speed
|
||||
|
||||
stdout_data = {
|
||||
"percent": str(percent),
|
||||
"size": str(total),
|
||||
"complete": str(complete),
|
||||
"total": str(total),
|
||||
"connection": str(connection),
|
||||
"eta": str(eta),
|
||||
"speed": str(speed),
|
||||
}
|
||||
|
||||
return stdout_data
|
||||
|
||||
return None
|
||||
|
||||
def if_errors(self, line):
|
||||
if "exception" in str(line).lower() or "errorcode" in str(line).lower():
|
||||
return line
|
||||
return None
|
||||
|
||||
def delete_last_message_printed(self):
|
||||
print(" " * len(str(self.last_message_printed)), end="\r")
|
||||
|
||||
def get_status(self, stdout_data: dict):
|
||||
return "Aria2c_Status; Size: {Size} | Speed: {Speed} | ETA: {ETA} | Progress: {Complete} -> {Total} ({Percent})".format(
|
||||
Size=stdout_data.get("size"),
|
||||
Speed=stdout_data.get("speed"),
|
||||
ETA=stdout_data.get("eta"),
|
||||
Complete=stdout_data.get("complete"),
|
||||
Total=stdout_data.get("total"),
|
||||
Percent=stdout_data.get("percent"),
|
||||
)
|
||||
|
||||
def is_download_completed(self, line):
|
||||
if "(ok):download completed." in str(line).lower():
|
||||
return "Download completed: (OK) ({}\\s)".format(self.speed_radar)
|
||||
return None
|
||||
|
||||
def start_download(self):
|
||||
proc = subprocess.Popen(
|
||||
self.aria2_download_command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
bufsize=1,
|
||||
universal_newlines=True,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
check_errors = True
|
||||
for line in getattr(proc, "stdout"):
|
||||
if check_errors:
|
||||
if self.if_errors(line):
|
||||
raise aria2Error("Aria2c Error {}".format(self.if_errors(line)))
|
||||
check_errors = False
|
||||
stdout_data = self.read_stdout(line)
|
||||
if stdout_data:
|
||||
status_text = self.get_status(stdout_data)
|
||||
self.delete_last_message_printed()
|
||||
print(status_text, end="\r", flush=True)
|
||||
self.last_message_printed = status_text
|
||||
else:
|
||||
download_finished = self.is_download_completed(line)
|
||||
if download_finished:
|
||||
self.delete_last_message_printed()
|
||||
print(download_finished, end="\r", flush=True)
|
||||
self.last_message_printed = download_finished
|
||||
self.logger.info("")
|
||||
return
|
||||
|
||||
|
||||
class aria2:
|
||||
def __init__(self,):
|
||||
self.env = self.aria2DisableProxies()
|
||||
self.ripprocess = ripprocess()
|
||||
self.tool = tool()
|
||||
self.bin = self.tool.bin()
|
||||
self.LOGA_PATH = self.tool.paths()["LOGA_PATH"]
|
||||
self.config = self.tool.aria2c()
|
||||
self.aria2c_exe = self.bin["aria2c"]
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def convert_args(self, arg):
|
||||
if arg is True:
|
||||
return "true"
|
||||
elif arg is False:
|
||||
return "false"
|
||||
elif arg is None:
|
||||
return "none"
|
||||
else:
|
||||
return str(arg)
|
||||
|
||||
def append_commands(self, command, option_define, option):
|
||||
if option == "skip":
|
||||
return []
|
||||
|
||||
return ["{}{}".format(option_define, option)]
|
||||
|
||||
def append_two_commands(self, command, cmd1, cmd2):
|
||||
if cmd2 == "skip":
|
||||
return []
|
||||
|
||||
return [cmd1] + [cmd2]
|
||||
|
||||
def aria2Options(
|
||||
self,
|
||||
allow_overwrite=True,
|
||||
file_allocation=None,
|
||||
auto_file_renaming=False,
|
||||
async_dns=False,
|
||||
retry_wait=5,
|
||||
summary_interval=0,
|
||||
enable_color=False,
|
||||
connection=16,
|
||||
concurrent_downloads=16,
|
||||
split=16,
|
||||
header="skip",
|
||||
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
|
||||
uri_selector="inorder",
|
||||
console_log_level="skip",
|
||||
download_result="hide",
|
||||
quiet="false",
|
||||
extra_commands=[],
|
||||
):
|
||||
|
||||
options = [] + extra_commands
|
||||
allow_overwrite = self.convert_args(allow_overwrite)
|
||||
quiet = self.convert_args(quiet)
|
||||
file_allocation = self.convert_args(file_allocation)
|
||||
auto_file_renaming = self.convert_args(auto_file_renaming)
|
||||
async_dns = self.convert_args(async_dns)
|
||||
retry_wait = self.convert_args(retry_wait)
|
||||
enable_color = self.convert_args(enable_color)
|
||||
connection = self.convert_args(connection)
|
||||
concurrent_downloads = self.convert_args(concurrent_downloads)
|
||||
split = self.convert_args(split)
|
||||
header = self.convert_args(header)
|
||||
uri_selector = self.convert_args(uri_selector)
|
||||
console_log_level = self.convert_args(console_log_level)
|
||||
download_result = self.convert_args(download_result)
|
||||
|
||||
##############################################################################
|
||||
|
||||
options += self.append_commands(options, "--allow-overwrite=", allow_overwrite)
|
||||
options += self.append_commands(options, "--quiet=", quiet)
|
||||
options += self.append_commands(options, "--file-allocation=", file_allocation)
|
||||
options += self.append_commands(
|
||||
options, "--auto-file-renaming=", auto_file_renaming
|
||||
)
|
||||
options += self.append_commands(options, "--async-dns=", async_dns)
|
||||
options += self.append_commands(options, "--retry-wait=", retry_wait)
|
||||
options += self.append_commands(options, "--enable-color=", enable_color)
|
||||
|
||||
options += self.append_commands(
|
||||
options, "--max-connection-per-server=", connection
|
||||
)
|
||||
|
||||
options += self.append_commands(
|
||||
options, "--max-concurrent-downloads=", concurrent_downloads
|
||||
)
|
||||
options += self.append_commands(options, "--split=", split)
|
||||
options += self.append_commands(options, "--header=", header)
|
||||
options += self.append_commands(options, "--uri-selector=", uri_selector)
|
||||
options += self.append_commands(
|
||||
options, "--console-log-level=", console_log_level
|
||||
)
|
||||
options += self.append_commands(options, "--download-result=", download_result)
|
||||
|
||||
return options
|
||||
|
||||
def aria2DisableProxies(self):
|
||||
env = os.environ.copy()
|
||||
|
||||
if env.get("http_proxy"):
|
||||
del env["http_proxy"]
|
||||
|
||||
if env.get("HTTP_PROXY"):
|
||||
del env["HTTP_PROXY"]
|
||||
|
||||
if env.get("https_proxy"):
|
||||
del env["https_proxy"]
|
||||
|
||||
if env.get("HTTPS_PROXY"):
|
||||
del env["HTTPS_PROXY"]
|
||||
|
||||
return env
|
||||
|
||||
def aria2DownloadUrl(self, url, output, options, debug=False, moded=False):
|
||||
self.debug = debug
|
||||
aria2_download_command = [self.aria2c_exe] + options
|
||||
|
||||
if self.config["enable_logging"]:
|
||||
LogFile = os.path.join(self.LOGA_PATH, output.replace(".mp4", ".log"))
|
||||
if os.path.isfile(LogFile):
|
||||
os.remove(LogFile)
|
||||
aria2_download_command.append("--log={}".format(LogFile))
|
||||
|
||||
if not url.startswith("http"):
|
||||
raise aria2Error("Url does not start with http/https: {}".format(url))
|
||||
|
||||
aria2_download_command.append(url)
|
||||
aria2_download_command += self.append_two_commands(
|
||||
aria2_download_command, "-o", output
|
||||
)
|
||||
|
||||
self.aria2Debug("Sending Commands to aria2c...")
|
||||
self.aria2Debug(aria2_download_command)
|
||||
self.logger.debug("aria2_download_command: {}".format(aria2_download_command))
|
||||
|
||||
if moded:
|
||||
aria2_moded_download = aria2_moded(aria2_download_command)
|
||||
aria2_moded_download.start_download()
|
||||
else:
|
||||
try:
|
||||
aria = subprocess.call(aria2_download_command, env=self.env)
|
||||
except FileNotFoundError:
|
||||
self.logger.info("UNABLE TO FIND {}".format(self.aria2c_exe))
|
||||
exit(-1)
|
||||
if aria != 0:
|
||||
raise aria2Error("Aria2c exited with code {}".format(aria))
|
||||
|
||||
return
|
||||
|
||||
def aria2DownloadDash(
|
||||
self, segments, output, options, debug=False, moded=False, fixbytes=False
|
||||
):
|
||||
self.debug = debug
|
||||
aria2_download_command = [self.aria2c_exe] + options
|
||||
|
||||
if self.config["enable_logging"]:
|
||||
LogFile = os.path.join(self.LOGA_PATH, output.replace(".mp4", ".log"))
|
||||
if os.path.isfile(LogFile):
|
||||
os.remove(LogFile)
|
||||
aria2_download_command.append("--log={}".format(LogFile))
|
||||
|
||||
if not isinstance(segments, list) or segments == []:
|
||||
raise aria2Error("invalid list of urls: {}".format(segments))
|
||||
|
||||
if moded:
|
||||
raise aria2Error("moded version not supported for dash downloads atm...")
|
||||
|
||||
txt = output.replace(".mp4", ".txt")
|
||||
folder = output.replace(".mp4", "")
|
||||
segments = list(dict.fromkeys(segments))
|
||||
|
||||
if os.path.exists(folder):
|
||||
shutil.rmtree(folder)
|
||||
if not os.path.exists(folder):
|
||||
os.makedirs(folder)
|
||||
|
||||
segments_location = []
|
||||
|
||||
opened_txt = open(txt, "w+")
|
||||
for num, url in enumerate(segments, start=1):
|
||||
segment_name = str(num).zfill(5) + ".mp4"
|
||||
segments_location.append(os.path.join(*[os.getcwd(), folder, segment_name]))
|
||||
opened_txt.write(url + f"\n out={segment_name}" + f"\n dir={folder}" + "\n")
|
||||
opened_txt.close()
|
||||
|
||||
aria2_download_command += self.append_commands(
|
||||
aria2_download_command, "--input-file=", txt
|
||||
)
|
||||
|
||||
try:
|
||||
aria = subprocess.call(aria2_download_command, env=self.env)
|
||||
except FileNotFoundError:
|
||||
self.logger.info("UNABLE TO FIND {}".format(self.aria2c_exe))
|
||||
exit(-1)
|
||||
if aria != 0:
|
||||
raise aria2Error("Aria2c exited with code {}".format(aria))
|
||||
|
||||
self.logger.info("\nJoining files...")
|
||||
openfile = open(output, "wb")
|
||||
total = int(len(segments_location))
|
||||
for current, fragment in enumerate(segments_location):
|
||||
if os.path.isfile(fragment):
|
||||
if fixbytes:
|
||||
with open(fragment, "rb") as f:
|
||||
wvdll = f.read()
|
||||
if (
|
||||
re.search(
|
||||
b"tfhd\x00\x02\x00\x1a\x00\x00\x00\x01\x00\x00\x00\x02",
|
||||
wvdll,
|
||||
re.MULTILINE | re.DOTALL,
|
||||
)
|
||||
is not None
|
||||
):
|
||||
fw = open(fragment, "wb")
|
||||
m = re.search(
|
||||
b"tfhd\x00\x02\x00\x1a\x00\x00\x00\x01\x00\x00\x00",
|
||||
wvdll,
|
||||
re.MULTILINE | re.DOTALL,
|
||||
)
|
||||
segment_fixed = (
|
||||
wvdll[: m.end()] + b"\x01" + wvdll[m.end() + 1 :]
|
||||
)
|
||||
fw.write(segment_fixed)
|
||||
fw.close()
|
||||
shutil.copyfileobj(open(fragment, "rb"), openfile)
|
||||
os.remove(fragment)
|
||||
self.ripprocess.updt(total, current + 1)
|
||||
openfile.close()
|
||||
|
||||
if os.path.isfile(txt):
|
||||
os.remove(txt)
|
||||
if os.path.exists(folder):
|
||||
shutil.rmtree(folder)
|
||||
|
||||
def aria2Debug(self, txt):
|
||||
if self.debug:
|
||||
self.logger.info(txt)
|
||||
Reference in New Issue
Block a user