Bug fixes

- Fixed captions not being downloaded
- Fixed trying to load keyfile even if it doesn't exist
- Moved asset and subtitle download processing into lecture processing function (in preparation of subtitle merging)
- Fixed an error in ffmpeg command when not using h265
- no longer need to specify full path to UdemyDownloader.py, also updated readme to reflect this
This commit is contained in:
Puyodead1 2021-09-25 12:14:08 -04:00
parent ec6ac28d0b
commit f3a32a2dd6
4 changed files with 188 additions and 142 deletions

View File

@ -104,41 +104,41 @@ optional arguments:
```
- Passing a Bearer Token and Course ID as an argument
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> -b <Bearer Token>`
- `python udemy_downloader\UdemyDownloader.py -c https://www.udemy.com/courses/myawesomecourse -b <Bearer Token>`
- `python udemy_downloader -c <Course URL> -b <Bearer Token>`
- `python udemy_downloader -c https://www.udemy.com/courses/myawesomecourse -b <Bearer Token>`
- Download a specific quality
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> -q 720`
- `python udemy_downloader -c <Course URL> -q 720`
- Download assets along with lectures
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-assets`
- `python udemy_downloader -c <Course URL> --download-assets`
- Download assets and specify a quality
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> -q 360 --download-assets`
- `python udemy_downloader -c <Course URL> -q 360 --download-assets`
- Download captions (Defaults to English)
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions`
- `python udemy_downloader -c <Course URL> --download-captions`
- Download captions with specific language
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions -l en` - English subtitles
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions -l es` - Spanish subtitles
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions -l it` - Italian subtitles
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions -l pl` - Polish Subtitles
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions -l all` - Downloads all subtitles
- `python udemy_downloader -c <Course URL> --download-captions -l en` - English subtitles
- `python udemy_downloader -c <Course URL> --download-captions -l es` - Spanish subtitles
- `python udemy_downloader -c <Course URL> --download-captions -l it` - Italian subtitles
- `python udemy_downloader -c <Course URL> --download-captions -l pl` - Polish Subtitles
- `python udemy_downloader -c <Course URL> --download-captions -l all` - Downloads all subtitles
- etc
- Skip downloading lecture videos
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --skip-lectures --download-captions` - Downloads only captions
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --skip-lectures --download-assets` - Downloads only assets
- `python udemy_downloader -c <Course URL> --skip-lectures --download-captions` - Downloads only captions
- `python udemy_downloader -c <Course URL> --skip-lectures --download-assets` - Downloads only assets
- Keep .VTT caption files:
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --download-captions --keep-vtt`
- `python udemy_downloader -c <Course URL> --download-captions --keep-vtt`
- Skip parsing HLS Streams (HLS streams usually contain 1080p quality for Non-DRM lectures):
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --skip-hls`
- `python udemy_downloader -c <Course URL> --skip-hls`
- Print course information only:
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --info`
- `python udemy_downloader -c <Course URL> --info`
- Specify max number of concurrent downloads:
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --concurrent-downloads 20`
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> -cd 20`
- `python udemy_downloader -c <Course URL> --concurrent-downloads 20`
- `python udemy_downloader -c <Course URL> -cd 20`
- Encode in H.265:
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --use-h265`
- `python udemy_downloader -c <Course URL> --use-h265`
- Encode in H.265 with custom CRF:
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --use-h265 -h265-crf 20`
- `python udemy_downloader -c <Course URL> --use-h265 -h265-crf 20`
- Encode in H.265 with custom preset:
- `python udemy_downloader\UdemyDownloader.py -c <Course URL> --use-h265 --h265-preset faster`
- `python udemy_downloader -c <Course URL> --use-h265 --h265-preset faster`
# Credits

View File

@ -51,6 +51,7 @@ _udemy_path = os.path.join(saved_dir, "_udemy.json")
udemy = None
parser = None
iknowwhatimdoing = False
retry = 3
_udemy = {}
course_url = None
@ -82,6 +83,7 @@ use_h265 = False
h265_crf = 28
h265_preset = "medium"
def download_segments(url, format_id, video_title, output_path, lecture_file_name, chapter_dir):
os.chdir(os.path.join(chapter_dir))
file_name = lecture_file_name.replace("%", "").replace(".mp4", "")
@ -103,7 +105,6 @@ def download_segments(url, format_id, video_title, output_path, lecture_file_nam
print("Return code from the downloader was non-0 (error), skipping!")
return
# tries to decrypt audio and video, and then merge them
try:
# tries to decrypt audio
@ -113,9 +114,11 @@ def download_segments(url, format_id, video_title, output_path, lecture_file_nam
audio_key = keys[audio_kid.lower()]
print("> Decrypting audio...")
ret_code = decrypt(audio_key, audio_filepath_enc, audio_filepath_dec)
ret_code = decrypt(
audio_key, audio_filepath_enc, audio_filepath_dec)
if(ret_code != 0):
print("WARN: Decrypting returned a non-0 result code which usually indicated an error!")
print(
"WARN: Decrypting returned a non-0 result code which usually indicated an error!")
else:
print("Decryption complete")
except KeyError:
@ -129,32 +132,35 @@ def download_segments(url, format_id, video_title, output_path, lecture_file_nam
video_key = keys[video_kid.lower()]
print("> Decrypting video...")
ret_code2 = decrypt(video_key, video_filepath_enc, video_filepath_dec)
ret_code2 = decrypt(
video_key, video_filepath_enc, video_filepath_dec)
if(ret_code2 != 0):
print("WARN: Decrypting returned a non-0 result code which usually indicated an error!")
print(
"WARN: Decrypting returned a non-0 result code which usually indicated an error!")
else:
print("Decryption complete")
except KeyError:
print("Video key not found!")
raise RuntimeError("No video key")
# tries to merge audio and video
# this should run only if both audio and video decryption returned 0 codes
print("> Merging audio and video files...")
ret_code3 = merge(video_title=video_title, video_filepath=video_filepath_dec, audio_filepath=audio_filepath_dec, output_path=output_path, use_h265=use_h265, h265_crf=h265_crf, h265_preset=h265_preset)
ret_code3 = merge(video_title=video_title, video_filepath=video_filepath_dec, audio_filepath=audio_filepath_dec,
output_path=output_path, use_h265=use_h265, h265_crf=h265_crf, h265_preset=h265_preset)
if(ret_code3 != 0):
print("WARN: Merging returned a non-0 result code which usually indicated an error!")
print(
"WARN: Merging returned a non-0 result code which usually indicated an error!")
if(ret_code == 0 and ret_code2 == 0 and ret_code3 == 0):
print("> Cleaning up...")
# remove all the temporary files left over after decryption and merging if there were no errors
remove_files((video_filepath_enc, video_filepath_dec, audio_filepath_enc, audio_filepath_dec))
remove_files((video_filepath_enc, video_filepath_dec,
audio_filepath_enc, audio_filepath_dec))
print("> Cleanup complete")
except Exception as e:
print(e)
os.chdir(home_dir)
@ -200,7 +206,7 @@ def download_aria(url, file_dir, filename):
print("Return code: " + str(ret_code))
def process_caption(caption, lecture_title, lecture_dir, keep_vtt, tries=0):
def process_caption(caption, lecture_title, lecture_dir, tries=0):
filename = f"%s_%s.%s" % (sanitize(lecture_title), caption.get("language"),
caption.get("extension"))
filename_no_ext = f"%s_%s" % (sanitize(lecture_title),
@ -241,6 +247,78 @@ def process_lecture(lecture, lecture_path, lecture_file_name, chapter_dir):
is_encrypted = lecture.get("is_encrypted")
lecture_sources = lecture.get("video_sources")
if dl_assets:
assets = lecture.get("assets")
print(" > Processing {} asset(s) for lecture...".format(
len(assets)))
for asset in assets:
asset_type = asset.get("type")
filename = asset.get("filename")
download_url = asset.get("download_url")
asset_id = asset.get("id")
if asset_type == "article":
print(
"If you're seeing this message, that means that you reached a secret area that I haven't finished! jk I haven't implemented handling for this asset type, please report this at https://github.com/Puyodead1/udemy-downloader/issues so I can add it. When reporting, please provide the following information: "
)
print("AssetType: Article; AssetData: ", asset)
# html_content = lecture.get("html_content")
# lecture_path = os.path.join(
# chapter_dir, "{}.html".format(sanitize(lecture_title)))
# try:
# with open(lecture_path, 'w') as f:
# f.write(html_content)
# f.close()
# except Exception as e:
# print("Failed to write html file: ", e)
# continue
elif asset_type == "video":
print(
"If you're seeing this message, that means that you reached a secret area that I haven't finished! jk I haven't implemented handling for this asset type, please report this at https://github.com/Puyodead1/udemy-downloader/issues so I can add it. When reporting, please provide the following information: "
)
print("AssetType: Video; AssetData: ", asset)
elif asset_type == "audio" or asset_type == "e-book" or asset_type == "file" or asset_type == "presentation":
try:
download_aria(download_url, chapter_dir,
f"{asset_id}-{filename}")
except Exception as e:
print("> Error downloading asset: ", e)
continue
elif asset_type == "external_link":
filepath = os.path.join(chapter_dir, filename)
savedirs, name = os.path.split(filepath)
filename = u"external-assets-links.txt"
filename = os.path.join(savedirs, filename)
file_data = []
if os.path.isfile(filename):
file_data = [
i.strip().lower()
for i in open(filename,
encoding="utf-8",
errors="ignore") if i
]
content = u"\n{}\n{}\n".format(name, download_url)
if name.lower() not in file_data:
with open(filename,
'a',
encoding="utf-8",
errors="ignore") as f:
f.write(content)
f.close()
subtitles = lecture.get("subtitles")
if dl_captions and subtitles:
selected_subtitles = []
print("Processing {} caption(s)...".format(len(subtitles)))
for subtitle in subtitles:
lang = subtitle.get("language")
if lang == caption_locale or caption_locale == "all":
selected_subtitles.append(subtitle)
process_caption(subtitle, lecture_title, chapter_dir)
print("Selected {} captions".format(len(selected_subtitles)))
if is_encrypted:
if len(lecture_sources) > 0:
source = lecture_sources[-1] # last index is the best quality
@ -251,8 +329,8 @@ def process_lecture(lecture, lecture_path, lecture_file_name, chapter_dir):
print(f" > Lecture '%s' has DRM, attempting to download" %
lecture_title)
download_segments(source.get("download_url"),
source.get(
"format_id"), lecture_title, lecture_path, lecture_file_name, chapter_dir)
source.get(
"format_id"), lecture_title, lecture_path, lecture_file_name, chapter_dir)
else:
print(f" > Lecture '%s' is missing media links" %
lecture_title)
@ -287,7 +365,6 @@ def process_lecture(lecture, lecture_path, lecture_file_name, chapter_dir):
"aria2c", "-o", f"{temp_filepath}", f"{url}"
]).wait()
if ret_code == 0:
# os.rename(temp_filepath, lecture_path)
print(" > HLS Download success")
else:
download_aria(url, chapter_dir, lecture_title + ".mp4")
@ -338,7 +415,6 @@ def parse():
print(
f" > Processing lecture {lecture_index} of {total_lectures}")
if not skip_lectures:
print(lecture_file_name)
# Check if the lecture is already downloaded
if os.path.isfile(lecture_path):
print(
@ -360,76 +436,8 @@ def parse():
print(" > Failed to write html file: ", e)
continue
else:
process_lecture(lecture, lecture_path, lecture_file_name, chapter_dir)
if dl_assets:
assets = lecture.get("assets")
print(" > Processing {} asset(s) for lecture...".format(
len(assets)))
for asset in assets:
asset_type = asset.get("type")
filename = asset.get("filename")
download_url = asset.get("download_url")
asset_id = asset.get("id")
if asset_type == "article":
print(
"If you're seeing this message, that means that you reached a secret area that I haven't finished! jk I haven't implemented handling for this asset type, please report this at https://github.com/Puyodead1/udemy-downloader/issues so I can add it. When reporting, please provide the following information: "
)
print("AssetType: Article; AssetData: ", asset)
# html_content = lecture.get("html_content")
# lecture_path = os.path.join(
# chapter_dir, "{}.html".format(sanitize(lecture_title)))
# try:
# with open(lecture_path, 'w') as f:
# f.write(html_content)
# f.close()
# except Exception as e:
# print("Failed to write html file: ", e)
# continue
elif asset_type == "video":
print(
"If you're seeing this message, that means that you reached a secret area that I haven't finished! jk I haven't implemented handling for this asset type, please report this at https://github.com/Puyodead1/udemy-downloader/issues so I can add it. When reporting, please provide the following information: "
)
print("AssetType: Video; AssetData: ", asset)
elif asset_type == "audio" or asset_type == "e-book" or asset_type == "file" or asset_type == "presentation":
try:
download_aria(download_url, chapter_dir,
f"{asset_id}-{filename}")
except Exception as e:
print("> Error downloading asset: ", e)
continue
elif asset_type == "external_link":
filepath = os.path.join(chapter_dir, filename)
savedirs, name = os.path.split(filepath)
filename = u"external-assets-links.txt"
filename = os.path.join(savedirs, filename)
file_data = []
if os.path.isfile(filename):
file_data = [
i.strip().lower()
for i in open(filename,
encoding="utf-8",
errors="ignore") if i
]
content = u"\n{}\n{}\n".format(name, download_url)
if name.lower() not in file_data:
with open(filename,
'a',
encoding="utf-8",
errors="ignore") as f:
f.write(content)
f.close()
subtitles = lecture.get("subtitles")
if dl_captions and subtitles:
print("Processing {} caption(s)...".format(len(subtitles)))
for subtitle in subtitles:
lang = subtitle.get("language")
if lang == caption_locale or caption_locale == "all":
process_caption(subtitle, lecture_title, chapter_dir)
process_lecture(lecture, lecture_path,
lecture_file_name, chapter_dir)
def process_course():
@ -481,15 +489,15 @@ def process_course():
if isinstance(asset, dict):
asset_type = (asset.get("asset_type").lower()
or asset.get("assetType").lower)
or asset.get("assetType").lower)
if asset_type == "article":
if isinstance(supp_assets,
list) and len(supp_assets) > 0:
list) and len(supp_assets) > 0:
retVal = udemy._extract_supplementary_assets(
supp_assets)
elif asset_type == "video":
if isinstance(supp_assets,
list) and len(supp_assets) > 0:
list) and len(supp_assets) > 0:
retVal = udemy._extract_supplementary_assets(
supp_assets)
elif asset_type == "e-book":
@ -641,6 +649,7 @@ def process_course():
if entry
])
def get_course_information():
global course_info, course_id, title, course_title, portal_name
if(load_from_file):
@ -658,6 +667,7 @@ def get_course_information():
course_title = course_info.get("published_title")
portal_name = course_info.get("portal_name")
def get_course_content():
global course_content
if load_from_file:
@ -666,18 +676,22 @@ def get_course_content():
course_content = json.loads(f.read())
else:
print("course_content.json not found, falling back to fetching")
course_content = udemy._extract_course_json(course_url, course_id, portal_name)
course_content = udemy._extract_course_json(
course_url, course_id, portal_name)
else:
course_content = udemy._extract_course_json(course_url, course_id, portal_name)
course_content = udemy._extract_course_json(
course_url, course_id, portal_name)
def parse_data():
global _udemy
if load_from_file:
if load_from_file and os.path.exists(_udemy_path):
f = open(_udemy_path, 'r')
_udemy = json.loads(f.read())
else:
process_course()
def _print_course_info(course_data):
print("\n\n\n\n")
course_title = course_data.get("title")
@ -746,6 +760,7 @@ def _print_course_info(course_data):
if chapter_index != chapter_count:
print("\n\n")
def setup_parser():
global parser
parser = argparse.ArgumentParser(description='Udemy Downloader')
@ -839,6 +854,12 @@ def setup_parser():
default="medium",
help="Set a custom preset value for H.265 encoding. FFMPEG default is medium",
)
parser.add_argument(
"--iknowwhatimdoing",
dest="iknowwhatimdoing",
action="store_true",
help=argparse.SUPPRESS,
)
parser.add_argument(
"--save-to-file",
dest="save_to_file",
@ -854,10 +875,10 @@ def setup_parser():
parser.add_argument("-v", "--version", action="version",
version='You are running version {version}'.format(version=__version__))
def process_args(args):
global course_url, bearer_token, dl_assets, caption_locale, skip_lectures, quality, keep_vtt, skip_hls, print_info, load_from_file, save_to_file, concurrent_connections, use_h265, h265_crf, h265_preset
global course_url, bearer_token, dl_assets, dl_captions, caption_locale, skip_lectures, quality, keep_vtt, skip_hls, print_info, load_from_file, save_to_file, concurrent_connections, use_h265, h265_crf, h265_preset, iknowwhatimdoing
course_url = args.course_url
if args.download_assets:
dl_assets = True
@ -893,6 +914,8 @@ def process_args(args):
h265_crf = args.h265_crf
if args.h265_preset:
h265_preset = args.h265_preset
if args.iknowwhatimdoing:
iknowwhatimdoing = args.iknowwhatimdoing
if args.load_from_file:
print(
@ -907,6 +930,7 @@ def process_args(args):
else:
bearer_token = os.getenv("UDEMY_BEARER")
def ensure_dependencies_installed():
aria_ret_val = check_for_aria()
if not aria_ret_val:
@ -925,6 +949,7 @@ def ensure_dependencies_installed():
)
sys.exit(1)
def check_dirs():
if not os.path.exists(saved_dir):
os.makedirs(saved_dir)
@ -932,29 +957,17 @@ def check_dirs():
if not os.path.exists(download_dir):
os.makedirs(download_dir)
def load_keys():
def try_load_keys():
global keys
f = open(keyfile_path, 'r')
keys = json.loads(f.read())
def UdemyDownloader():
global udemy, course, resource
check_dirs()
# warn that the keyfile is not found
if not os.path.isfile(keyfile_path):
print("!!! Keyfile not found! This means you probably didn't rename the keyfile correctly, DRM lecture decryption will fail! If you aren't downloading DRM encrypted courses, you can ignore this message. !!!")
print("Waiting for 10 seconds...")
time.sleep(10)
load_keys()
# ensure 3rd party binaries are installed
ensure_dependencies_installed();
# loads the .env file
load_dotenv()
# Creates a new parser and sets up the arguments
setup_parser()
@ -962,6 +975,22 @@ def UdemyDownloader():
args = parser.parse_args()
process_args(args=args)
# warn that the keyfile is not found
if not os.path.exists(keyfile_path):
print("!!! Keyfile not found! This means you probably didn't rename the keyfile correctly, DRM lecture decryption will fail! If you aren't downloading DRM encrypted courses, you can ignore this message. !!!")
if not iknowwhatimdoing:
print("Waiting for 10 seconds...")
time.sleep(10)
else:
try_load_keys()
# ensure 3rd party binaries are installed
ensure_dependencies_installed()
# loads the .env file
load_dotenv()
udemy = Udemy(access_token=bearer_token)
print("> Fetching course information, this may take a minute...")
@ -989,7 +1018,7 @@ def UdemyDownloader():
'w') as f:
f.write(json.dumps(course_content))
print("Saved course content to file")
course = course_content.get("results")
resource = course_content.get("detail")
@ -1010,7 +1039,7 @@ def UdemyDownloader():
if save_to_file:
with open(_udemy_path,
'w') as f:
'w') as f:
f.write(json.dumps(_udemy))
print("Saved parsed data to file")
@ -1021,4 +1050,4 @@ def UdemyDownloader():
if __name__ == "__main__":
UdemyDownloader()
UdemyDownloader()

View File

@ -0,0 +1,4 @@
from UdemyDownloader import UdemyDownloader
if __name__ == "__main__":
UdemyDownloader()

View File

@ -9,6 +9,7 @@ from mp4parse import F4VParser
from widevine_pssh_pb2 import WidevinePsshData
from sanitize import sanitize, slugify, SLUG_OK
def extract_kid(mp4_file):
"""
Parameters
@ -26,7 +27,8 @@ def extract_kid(mp4_file):
boxes = F4VParser.parse(filename=mp4_file)
for box in boxes:
if box.header.box_type == 'moov':
pssh_box = next(x for x in box.pssh if x.system_id == "edef8ba979d64acea3c827dcd51d21ed")
pssh_box = next(x for x in box.pssh if x.system_id ==
"edef8ba979d64acea3c827dcd51d21ed")
hex = codecs.decode(pssh_box.payload, "hex")
pssh = WidevinePsshData()
@ -37,6 +39,7 @@ def extract_kid(mp4_file):
# No Moof or PSSH header found
return None
def _clean(text):
ok = re.compile(r'[^\\/:*?!"<>|]')
text = "".join(x if ok.match(x) else "_" for x in text)
@ -49,6 +52,7 @@ def _sanitize(self, unsafetext):
slugify(unsafetext, lower=False, spaces=True, ok=SLUG_OK + "().[]")))
return text
def durationtoseconds(period):
"""
@author Jayapraveen
@ -74,6 +78,7 @@ def durationtoseconds(period):
print("Duration Format Error")
return None
def cleanup(path):
"""
@author Jayapraveen
@ -86,39 +91,47 @@ def cleanup(path):
print(f"Error deleting file: {file_list}")
os.removedirs(path)
def remove_files(files):
for file in files:
os.remove(file)
def merge(video_title, video_filepath, audio_filepath, output_path, use_h265, h265_crf, h265_preset):
"""
@author Jayapraveen
"""
if os.name == "nt":
if use_h265:
command = "ffmpeg -y -i \"{}\" -i \"{}\" -c:v libx265 -crf {} -preset {} -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(video_filepath, audio_filepath, h265_crf, h265_preset, video_title, output_path)
command = "ffmpeg -y -i \"{}\" -i \"{}\" -c:v libx265 -crf {} -preset {} -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(
video_filepath, audio_filepath, h265_crf, h265_preset, video_title, output_path)
else:
command = "ffmpeg -y -i \"{}\" -i \"{}\" -c:v copy -vtag hvc1 -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(video_filepath, audio_filepath, video_title, output_path)
command = "ffmpeg -y -i \"{}\" -i \"{}\" -c:v copy -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(
video_filepath, audio_filepath, video_title, output_path)
else:
if use_h265:
command = "nide -n 7 ffmpeg -y -i \"{}\" -i \"{}\" -c:v libx265 -crf {} -preset {} -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(video_filepath, audio_filepath, h265_crf, h265_preset, video_title, output_path)
command = "nide -n 7 ffmpeg -y -i \"{}\" -i \"{}\" -c:v libx265 -crf {} -preset {} -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(
video_filepath, audio_filepath, h265_crf, h265_preset, video_title, output_path)
else:
command = "nide -n 7 ffmpeg -y -i \"{}\" -i \"{}\" -c:v copy -vtag hvc1 -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(video_filepath, audio_filepath, video_title, output_path)
command = "nide -n 7 ffmpeg -y -i \"{}\" -i \"{}\" -c:v copy -c:a copy -fflags +bitexact -map_metadata -1 -metadata title=\"{}\" \"{}\"".format(
video_filepath, audio_filepath, video_title, output_path)
return os.system(command)
def decrypt(key, in_filepath, out_filepath):
"""
@author Jayapraveen
"""
if (os.name == "nt"):
ret_code = os.system(f"mp4decrypt --key 1:%s \"%s\" \"%s\"" %
(key, in_filepath, out_filepath))
(key, in_filepath, out_filepath))
else:
ret_code = os.system(f"nice -n 7 mp4decrypt --key 1:%s \"%s\" \"%s\"" %
(key, in_filepath, out_filepath))
(key, in_filepath, out_filepath))
return ret_code
def check_for_aria():
try:
subprocess.Popen(["aria2c", "-v"],
@ -161,4 +174,4 @@ def check_for_mp4decrypt():
print(
"> Unexpected exception while checking for MP4Decrypt, please tell the program author about this! ",
e)
return True
return True