semi udemy support

pull/12/head
Puyodead1 2021-05-18 10:15:54 -04:00
parent 1d2d2edc6d
commit 8d41a494c9
5 changed files with 39 additions and 212 deletions

2
.gitignore vendored
View File

@ -112,3 +112,5 @@ dmypy.json
# Pyre type checker
.pyre/
*.mp4
keyfile.json

View File

@ -1,156 +0,0 @@
#dashdownloader
import os,requests,shutil,json,glob
from mpegdash.parser import MPEGDASHParser
from mpegdash.nodes import Descriptor
from mpegdash.utils import (
parse_attr_value, parse_child_nodes, parse_node_value,
write_attr_value, write_child_node, write_node_value
)
#global ids
quality = 1080 #default to 1080p
retry = 3
download_dir = os.getcwd() # set the folder to output
working_dir = os.getcwd() # set the folder to download ephemeral files
keyfile_path = working_dir + "/keyfile.json"
#Patching the Mpegdash lib for keyID
def __init__(self):
self.scheme_id_uri = '' # xs:anyURI (required)
self.value = None # xs:string
self.id = None # xs:string
self.key_id = None # xs:string
def parse(self, xmlnode):
self.scheme_id_uri = parse_attr_value(xmlnode, 'schemeIdUri', str)
self.value = parse_attr_value(xmlnode, 'value', str)
self.id = parse_attr_value(xmlnode, 'id', str)
self.key_id = parse_attr_value(xmlnode, 'ns2:default_KID', str)
if(self.key_id == None):
self.key_id = parse_attr_value(xmlnode, 'cenc:default_KID', str)
def write(self, xmlnode):
write_attr_value(xmlnode, 'schemeIdUri', self.scheme_id_uri)
write_attr_value(xmlnode, 'value', self.value)
write_attr_value(xmlnode, 'id', self.id)
write_attr_value(xmlnode, 'ns2:default_KID', self.key_id)
if(self.key_id == None):
write_attr_value(xmlnode, 'cenc:default_KID', self.key_id)
Descriptor.__init__ = __init__
Descriptor.parse = parse
Descriptor.write = write
#Get the keys
with open(keyfile_path,'r') as keyfile:
keyfile = keyfile.read()
keyfile = json.loads(keyfile)
def manifest_parser(mpd_url):
manifest = requests.get(mpd_url).text
with open("manifest.mpd",'w') as manifest_handler:
manifest_handler.write(manifest)
mpd = MPEGDASHParser.parse("./manifest.mpd")
audio = []
video = []
for period in mpd.periods:
for adapt_set in period.adaptation_sets:
content_type = adapt_set.content_type
for repr in adapt_set.representations:
base_url = repr.base_urls[0].base_url_value
if(content_type == "audio"):
audio.append(base_url)
elif(content_type == "video" and repr.height == quality):
video.append(base_url)
for prot in adapt_set.content_protections:
if(prot.value == "cenc"):
kId = prot.key_id.replace('-','')
if(content_type == "audio"):
audio.append(kId)
elif(content_type == "video" and repr.height == quality):
video.append(kId)
break
return video + audio
def download(url,filename,count = 0):
video = requests.get(url, stream=True)
if video.status_code == 200:
video_length = int(video.headers.get('content-length'))
if(os.path.isfile(filename) and os.path.getsize(filename) >= video_length):
print("Video already downloaded.. skipping write to disk..")
else:
try:
with open(filename, 'wb') as video_file:
shutil.copyfileobj(video.raw, video_file)
except:
print(url,filename)
print("Write to disk error: Reattempting download and write..")
if(count <= retry):
count += 1
download(url,filename,count)
else:
exit("Error Writing Video to Disk. Exiting...")
if os.path.getsize(filename) >= video_length:
pass
else:
print("Error downloaded video is faulty.. Retrying to download")
if(count <= retry):
count += 1
download(url,filename,count)
else:
exit("Error Writing Video to Disk. Exiting...")
else:
print("Video file is not accessible",filename,"Retrying...")
if(count <= retry):
count += 1
download(url,filename,count)
else:
print("Adding Video file not accessible to log")
with open(download_dir + "\video_access_error.txt",'a') as videoaccerr:
videoaccerr.write(filename + " " + url +"\n")
def decrypt(filename,keyid,video_title):
try:
key = keyfile[keyid]
print(key)
os.system(f"ffmpeg -y -decryption_key {key} -i {filename} -codec copy -metadata title={video_title} dec_{filename}")
except KeyError as error:
print("Key not found")
exit()
def mux_process(outfile):
command = f"ffmpeg -y -i dec_audio.mp4 -i dec_video.mp4 -acodec copy -vcodec copy -metadata title=\"{video_title}\" {outfile}.mp4"
print(command)
os.system(command)
def cleanup(path):
leftover_files = glob.glob(path + '/*.mp4', recursive=True)
mpd_files = glob.glob(path + '/*.mpd', recursive=True)
leftover_files = leftover_files + mpd_files
for file_list in leftover_files:
try:
os.remove(file_list)
except OSError:
print(f"Error deleting file: {file_list}")
if __name__ == "__main__":
mpd = "https://demo.com/stream.mpd"
base_url = mpd.split("stream.mpd")[0]
os.chdir(working_dir)
video_url,video_keyid,audio_url,audio_keyid = manifest_parser(mpd)
video_url = base_url + video_url
audio_url = base_url + audio_url
audio_filename = "audio.mp4"
video_filename = "video.mp4"
video_title = "Video Title"
audio_title = video_title
download(video_url,video_filename)
download(audio_url,audio_filename)
decrypt(video_filename,video_keyid,video_title)
decrypt(audio_filename,audio_keyid,audio_title)
final_file = download_dir + '/' + video_title
print(final_file)
mux_process(final_file)
cleanup(working_dir)

View File

@ -11,7 +11,7 @@ from mpegdash.utils import (
retry = 3
download_dir = os.getcwd() # set the folder to output
working_dir = os.getcwd() + "\working_dir" # set the folder to download ephemeral files
keyfile_path = download_dir + "\keyfile_test.json"
keyfile_path = download_dir + "\keyfile.json"
if not os.path.exists(working_dir):
os.makedirs(working_dir)
@ -63,46 +63,35 @@ def durationtoseconds(period):
def download_media(filename,url,epoch = 0):
if(os.path.isfile(filename)):
media_head = requests.head(url, allow_redirects = True)
if media_head.status_code == 200:
media_length = int(media_head.headers.get("content-length"))
if(os.path.getsize(filename) >= media_length):
print("Video already downloaded.. skipping Downloading..")
else:
print("Redownloading faulty download..")
os.remove(filename) #Improve removing logic
download_media(filename,url)
else:
if (epoch > retry):
exit("Server doesn't support HEAD.")
download_media(filename,url,epoch + 1)
print("Segment already downloaded.. skipping..")
else:
media = requests.get(url, stream=True)
media_length = int(media.headers.get("content-length"))
if media.status_code == 200:
if(os.path.isfile(filename) and os.path.getsize(filename) >= video_length):
print("Video already downloaded.. skipping write to disk..")
if(os.path.isfile(filename) and os.path.getsize(filename) >= media_length):
print("Segment already downloaded.. skipping write to disk..")
else:
try:
with open(filename, 'wb') as video_file:
shutil.copyfileobj(media.raw, video_file)
print("Segment downloaded: " + filename)
return False #Successfully downloaded the file
except:
print("Connection error: Reattempting download of video..")
print("Connection error: Reattempting download of segment..")
download_media(filename,url, epoch + 1)
if os.path.getsize(filename) >= video_length:
if os.path.getsize(filename) >= media_length:
pass
else:
print("Error downloaded video is faulty.. Retrying to download")
print("Segment is faulty.. Redownloading...")
download_media(filename,url, epoch + 1)
elif(media.status_code == 404):
print("Probably end hit!\n",url)
return True #Probably hit the last of the file
else:
if (epoch > retry):
exit("Error Video fetching exceeded retry times.")
print("Error fetching video file.. Retrying to download")
exit("Error fetching segment, exceeded retry times.")
print("Error fetching segment file.. Redownloading...")
download_media(filename,url, epoch + 1)
def cleanup(path):
@ -117,14 +106,14 @@ def cleanup(path):
def mux_process(video_title,outfile):
if os.name == "nt":
command = f"ffmpeg -y -i decrypted_audio.mp4 -i decrypted_video.mp4 -acodec copy -vcodec copy -fflags +bitexact -map_metadata -1 -metadata title=\"{video_title}\" -metadata creation_time=2020-00-00T70:05:30.000000Z {outfile}.mp4"
command = f"ffmpeg -y -i decrypted_audio.mp4 -i decrypted_video.mp4 -acodec copy -vcodec copy -fflags +bitexact -map_metadata -1 -metadata title=\"{video_title}\" -metadata creation_time=2020-00-00T70:05:30.000000Z \"{outfile}.mp4\""
else:
command = f"nice -n 7 ffmpeg -y -i decrypted_audio.mp4 -i decrypted_video.mp4 -acodec copy -vcodec copy -fflags +bitexact -map_metadata -1 -metadata title=\"{video_title}\" -metadata creation_time=2020-00-00T70:05:30.000000Z {outfile}.mp4"
os.system(command)
def decrypt(kid,filename):
def decrypt(filename):
try:
key = keyfile[kid.lower()]
key = keyfile["0"]
except KeyError as error:
exit("Key not found")
if(os.name == "nt"):
@ -134,31 +123,29 @@ def decrypt(kid,filename):
def handle_irregular_segments(media_info,video_title,output_path):
no_segment,video_url,video_kid,video_extension,no_segment,audio_url,audio_kid,audio_extension = media_info
video_url = base_url + video_url
audio_url = base_url + audio_url
video_init = video_url.replace("$Number$","init")
audio_init = audio_url.replace("$Number$","init")
download_media("video_0.mp4",video_init)
download_media("audio_0.mp4",audio_init)
no_segment,video_url,video_init,video_extension,no_segment,audio_url,audio_init,audio_extension = media_info
download_media("video_0.seg.mp4",video_init)
download_media("audio_0.seg.mp4",audio_init)
for count in range(1,no_segment):
video_segment_url = video_url.replace("$Number$",str(count))
audio_segment_url = audio_url.replace("$Number$",str(count))
video_status = download_media(f"video_{str(count)}.{video_extension}",video_segment_url)
audio_status = download_media(f"audio_{str(count)}.{audio_extension}",audio_segment_url)
video_status = download_media(f"video_{str(count)}.seg.{video_extension}",video_segment_url)
audio_status = download_media(f"audio_{str(count)}.seg.{audio_extension}",audio_segment_url)
if(video_status):
if os.name == "nt":
video_concat_command = "copy /b " + "+".join([f"video_{i}.{video_extension}" for i in range(0,count)]) + " encrypted_video.mp4"
audio_concat_command = "copy /b " + "+".join([f"audio_{i}.{audio_extension}" for i in range(0,count)]) + " encrypted_audio.mp4"
video_concat_command = "copy /b " + "+".join([f"video_{i}.seg.{video_extension}" for i in range(0,count)]) + " encrypted_video.mp4"
audio_concat_command = "copy /b " + "+".join([f"audio_{i}.seg.{audio_extension}" for i in range(0,count)]) + " encrypted_audio.mp4"
else:
video_concat_command = "cat " + " ".join([f"video_{i}.{video_extension}" for i in range(0,count)]) + " > encrypted_video.mp4"
audio_concat_command = "cat " + " ".join([f"audio_{i}.{audio_extension}" for i in range(0,count)]) + " > encrypted_audio.mp4"
video_concat_command = "cat " + " ".join([f"video_{i}.seg.{video_extension}" for i in range(0,count)]) + " > encrypted_video.mp4"
audio_concat_command = "cat " + " ".join([f"audio_{i}.seg.{audio_extension}" for i in range(0,count)]) + " > encrypted_audio.mp4"
print(video_concat_command)
print(audio_concat_command)
os.system(video_concat_command)
os.system(audio_concat_command)
decrypt("video")
decrypt("audio")
mux_process(video_title,output_path)
break
decrypt(video_kid,"video")
decrypt(audio_kid,"audio")
mux_process(video_title,output_path)
def manifest_parser(mpd_url):
@ -181,36 +168,31 @@ def manifest_parser(mpd_url):
total_segments = running_time / segment_time
else:
print("Media segments are of inequal timeframe")
print(segment.media)
approx_no_segments = int(running_time // 10) # aproximate of 10 sec per segment
approx_no_segments = round(running_time / 6) + 20 # aproximate of 6 sec per segment
print("Expected No of segments:",approx_no_segments)
if(content_type == "audio/mp4"):
segment_extension = segment.media.split(".")[-1]
audio.append(approx_no_segments)
audio.append(segment.media)
audio.append(segment.initialization)
audio.append(segment_extension)
elif(content_type == "video/mp4"):
segment_extension = segment.media.split(".")[-1]
video.append(approx_no_segments)
video.append(segment.media)
video.append(segment.initialization)
video.append(segment_extension)
for prot in repr.content_protections:
if(prot.value == "cenc"):
kId = prot.key_id.replace('-','')
if(content_type == "audio/mp4"):
audio.append(kId)
elif(content_type == "video/mp4"):
video.append(kId)
return video + audio
if __name__ == "__main__":
mpd = "https://www.example.com/index.mpd"
mpd = "https://www.udemy.com/assets/25653992/encrypted-files/out/v1/6d2a767a83064e7fa747bedeb1841f7d/06c8dc12da2745f1b0b4e7c2c032dfef/842d4b8e2e014fbbb87c640ddc89d036/index.mpd?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MjEzMjc0NzAsInBhdGgiOiJvdXQvdjEvNmQyYTc2N2E4MzA2NGU3ZmE3NDdiZWRlYjE4NDFmN2QvMDZjOGRjMTJkYTI3NDVmMWIwYjRlN2MyYzAzMmRmZWYvODQyZDRiOGUyZTAxNGZiYmI4N2M2NDBkZGM4OWQwMzYvIn0.4NpalcpDz0i5SXl6UYxnxECoacfRkJBHtKx5tWlJMOQ&provider=cloudfront&v=1"
base_url = mpd.split("index.mpd")[0]
os.chdir(working_dir)
media_info = manifest_parser(mpd)
video_title = "Title of the video"
output_path = download_dir + "\output_video_name"
video_title = "171. Editing Collision Meshes"
output_path = download_dir + "\\171. Editing Collision Meshes"
handle_irregular_segments(media_info,video_title,output_path)
cleanup(working_dir)

3
keyfile.example.json Normal file
View File

@ -0,0 +1,3 @@
{
"KeyID": "key"
}

View File

@ -1,4 +0,0 @@
{
"KeyID": "key",
"5071422d38cb0bea995d655dfc2e45dd": "23a02b9a0608aachee359af99cdacb87"
}