1 # -*- coding:utf-8 -*- 2 import os 3 import sys 4 import requests 5 import datetime 6 from Crypto.Cipher import AES 7 from binascii import b2a_hex, a2b_hex 8 9 # reload(sys) 10 # sys.setdefaultencoding('utf-8') 11 12 if 1: 13 def debug(s): 14 print(s) 15 else: 16 def debug(s): 17 pass 18 19 import importlib 20 importlib.reload(sys) 21 22 def download(url, savefile_path=''): 23 # 创建download目录 24 download_path = os.getcwd() + "download" 25 if not os.path.exists(download_path): 26 os.mkdir(download_path) 27 28 #新建日期文件夹,如果没有指定文件存储位置,就用年月日创建文件夹,否则用指定的文件夹 29 if not savefile_path: 30 savefile_path = os.path.join(download_path, datetime.datetime.now().strftime('%Y%m%d')) 31 else: 32 savefile_path = os.path.join(download_path, savefile_path) 33 print("savefile_path = " + savefile_path) 34 if not os.path.exists(savefile_path): 35 os.mkdir(savefile_path) 36 37 38 #如果不存在first.m3u8,就重新获取,并保存,否则证明之前已经获取过,直接读取就行了 39 if not os.path.exists(os.path.join(download_path,'first.m3u8')): 40 all_content = requests.get(url).text # 获取第一层M3U8文件内容 41 with open( os.path.join(download_path,'first.m3u8'),'w' ) as f: 42 f.write(all_content) 43 print("save first.m3u8") 44 else: 45 print("first.m3u8 is exist,just read it") 46 all_content = open( os.path.join(download_path,'first.m3u8'),'r' ).read() 47 48 # 不是M3U8文件,直接报错退出 49 if "#EXTM3U" not in all_content: 50 raise BaseException("非M3U8的链接") 51 # 52 if "EXT-X-STREAM-INF" in all_content: # 第一层 53 # 从第一层中读取所有的文件组成行列表 file_line 54 print("we need to get the second line") 55 file_line = all_content.split(" ") 56 # 找到 .m3u8 ,拼出第二层的链接 57 for line in file_line: 58 if '.m3u8' in line: 59 url = url.rsplit("/", 1)[0] + "/" + line # 拼出第二层m3u8的URL 60 print("second line url = " + url) 61 # 没存,就存一下,同first.m3u8的逻辑 62 if not os.path.exists(os.path.join(download_path,'second.m3u8')): 63 all_content = requests.get(url).text 64 with open( os.path.join(download_path,'second.m3u8'),'w' ) as f: 65 f.write(all_content) 66 print("second.m3u8 has been saved") 67 else: 68 all_content = open( os.path.join(download_path,'second.m3u8'),'r' ).read() 69 break 70 # 到此为止,all_content里面的内容已经更新成了包含所有文件名的最终文件 71 # url 更新成了下载最终m3u8的URL 72 73 # 把里面的元素分割出来 74 file_line = all_content.split(" ") 75 76 unknow = True 77 key = "" 78 79 for line in file_line: 80 # 先找到解密key 81 if "#EXT-X-KEY" in line: # 找解密Key 82 method_pos = line.find("METHOD") 83 comma_pos = line.find(",") 84 method = line[method_pos:comma_pos].split('=')[1] 85 print("Decode Method:", method) 86 87 uri_pos = line.find("URI") 88 quotation_mark_pos = line.rfind('"') 89 key_path = line[uri_pos:quotation_mark_pos].split('"')[1] 90 91 key_url = url.rsplit("/", 1)[0] + "/" + key_path # 拼出key解密密钥URL 92 res = requests.get(key_url) 93 key = res.content 94 95 with open( os.path.join(download_path,'key.key'),'wb' ) as f: 96 f.write(key) 97 98 cryptor = AES.new(key, AES.MODE_CBC, key) 99 print( "key:" , key) 100 break 101 print("you cann't see me") 102 # 再进行下载和解密 103 for index, line in enumerate(file_line): # 第二层 104 if "EXTINF" in line: # 找ts地址并下载 105 unknow = False 106 pd_url = url.rsplit("/", 1)[0] + "/" + file_line[index + 1] # 拼出ts片段的URL 107 108 c_fule_name = file_line[index + 1].rsplit("/", 1)[-1] 109 # 如果文件已经存在,就下一个 110 if os.path.exists( os.path.join(savefile_path, c_fule_name) ): 111 print("file %s exist, next" % c_fule_name) 112 continue 113 # 网络不好的时候会失败,所以重复3次 114 for i in range(3): 115 # 获取视频内容 116 print("get video " + datetime.datetime.now().strftime('%H:%M:%S')) 117 res = requests.get(pd_url) 118 try: 119 if len(key): # AES 解密,有key就是需要解密 120 with open(os.path.join(savefile_path, c_fule_name), 'ab') as f: 121 f.write(cryptor.decrypt(res.content)) 122 print(c_fule_name + " success") 123 break 124 else: # 没有key就不需要解密了,直接保存文件就行了 125 with open(os.path.join(savefile_path, c_fule_name), 'ab') as f: 126 f.write(res.content) 127 f.flush() 128 print(c_fule_name + " success") 129 break 130 except: # 网络不好导致下载失败,清除文件 131 print( str(i+1) + " download error, file: " + c_fule_name) 132 os.remove(os.path.join(savefile_path, c_fule_name)) 133 else: # 下载失败,先跳过这个文件,后面重新执行的时候在重新下载 134 print("download file has failed 3 times, jump it") 135 #exit() 136 137 if unknow: 138 raise BaseException("未找到对应的下载链接") 139 else: 140 print( "下载完成") 141 # merge_file(savefile_path) 142 143 def merge_file(path): 144 os.chdir(path) 145 cmd = "copy /b * new.ts" 146 #os.system(cmd) 147 #os.system('del /Q *.ts') 148 #os.system('del /Q *.mp4') 149 #os.rename("new.tmp", "new.mp4") 150 151 if __name__ == '__main__': 152 url = input("please input the url of index.m3u8 file: ") 153 savefile_path = input("give me a dir name to save all the video: (or you can just press Enter and I will create one for you) ") 154 # url = r'' 155 # savefile_path = r'' 156 download(url,savefile_path)