This commit is contained in:
widevinedump
2021-12-25 10:54:39 +05:30
parent 087f294ca3
commit fdc26b99ee
155 changed files with 216857 additions and 2 deletions

View File

@@ -0,0 +1,45 @@
import requests, json, os, re
import pywidevine.clients.appletv.config as aptv_cfg
import urllib.parse
currentFile = 'appletv'
realPath = os.path.realpath(currentFile)
dirPath = os.path.dirname(realPath)
cookies_file = dirPath + '/cookies/' + 'cookies_aptv.txt'
def get_auth_headers(content_url):
def urldecode(str):
return urllib.parse.unquote(str)
def parseCookieFile(cookiefile):
cookies = {}
with open (cookies_file, 'r') as fp:
for line in fp:
if not re.match(r'^\#', line):
lineFields = line.strip().split('\t')
cookies[lineFields[5]] = lineFields[6]
return cookies
COOKIES = parseCookieFile(dirPath + '/cookies/' + cookies_file)
COMMOM_HEADERS = aptv_cfg.COMMOM_HEADERS
COMMOM_HEADERS["media-user-token"] = COOKIES["media-user-token"]
while 1:
html_data = requests.get(url=content_url, headers=COMMOM_HEADERS)
if html_data.ok:
break
html_data = html_data.text.replace('\r\n', '').replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '')
html_data_list = re.split('(</div>)(?i)', html_data)
json_web = []
for div in html_data_list:
rg = re.compile('(<meta name="web-tv-app/config/environment" content=")(.*)("><!-- EMBER_CLI_FASTBOOT_TITLE --)')
m = rg.search(div)
if m:
AUTH_TOKEN = json.loads(urldecode(m[2]))["MEDIA_API"]["token"]
COMMOM_HEADERS["authorization"] = "Bearer %s" % (AUTH_TOKEN)
return {"wvHeaders": COMMOM_HEADERS}, COOKIES

View File

@@ -0,0 +1,49 @@
from shutil import which
from os.path import dirname, realpath, join
from os import pathsep, environ
APTV_ENDPOINTS = {
'SERIES': 'https://tv.apple.com/api/uts/v2/view/show/umc.cmc.%s/episodes',
'PRODUCT': 'https://tv.apple.com/api/uts/v2/view/product/%s',
'CONTENT_DATA': 'https://tv.apple.com/api/uts/v2/view/product/%s/personalized',
'WV_LICENSE': 'https://play.itunes.apple.com/WebObjects/MZPlay.woa/web/video/subscription/license',
'WV_CERT': 'https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/widevineCert'
}
APTV_PARAMS = {'utscf': 'OjAAAAAAAAA~', 'utsk': '6e3013c6d6fae3c2::::::9724ac949afa4bb2', 'caller': 'web', 'sf': '143468', 'v': '40', 'pfm': 'web', 'locale': 'en-US'}
SCRIPT_PATH = dirname(realpath('appletv'))
BINARIES_FOLDER = join(SCRIPT_PATH, 'binaries')
SHAKA_PACKAGER_BINARY = 'packager-win'
MEDIAINFO_BINARY = 'mediainfo'
MP4DUMP_BINARY = 'mp4dump'
MKVMERGE_BINARY = 'mkvmerge'
FFMPEG_BINARY = 'ffmpeg'
ARIA2C_BINARY = 'aria2c'
SUBTITLE_EDIT_BINARY = 'subtitleedit'
# Add binaries folder to PATH as the first item
environ['PATH'] = pathsep.join([BINARIES_FOLDER, environ['PATH']])
SHAKA_PACKAGER = which(SHAKA_PACKAGER_BINARY)
MEDIAINFO = which(MEDIAINFO_BINARY)
MP4DUMP = which(MP4DUMP_BINARY)
MKVMERGE = which(MKVMERGE_BINARY)
FFMPEG = which(FFMPEG_BINARY)
ARIA2C = which(ARIA2C_BINARY)
SUBTITLE_EDIT = which(SUBTITLE_EDIT_BINARY)
class WvDownloaderConfig(object):
def __init__(self, m3u8, output_file):
self.m3u8 = m3u8
self.output_file = output_file
COMMOM_HEADERS = {
'Connection': 'keep-alive',
'User-Agent': 'AppleCoreMedia/1.0.0.12B466 (Apple TV; U; CPU OS 8_1_3 like Mac OS X; en_us)',
'Content-Type': 'application/json',
'Origin': 'https://tv.apple.com',
'Referer': 'https://tv.apple.com/',
}

View File

@@ -0,0 +1,162 @@
import sys, os, shutil, requests, re
import subprocess, math, pathlib
from m3u8 import parse as m3u8parser
dlthreads = 24
class WvDownloader(object):
def __init__(self, config):
self.m3u8_url = config.m3u8
self.output_file = config.output_file
self.config = config
def downloadM3u8(self, Link_List, Folder, file_name):
TempFolder = file_name.replace('.mp4', '')
if os.path.exists(TempFolder):
shutil.rmtree(TempFolder)
if not os.path.exists(TempFolder):
os.makedirs(TempFolder)
LinkList_txt = file_name.replace('.mp4', '_LinkList.txt')
if os.path.isfile(LinkList_txt):
os.remove(LinkList_txt)
counter = 0
with open(LinkList_txt, 'a', encoding='ansi') as (file):
for link in Link_List:
mp4_segment = re.split('(/)(?i)', link)[(-1)]
seg_num = str(counter).zfill(5)
seg_num = f"{seg_num}.mp4"
file.write(f"{link}\n\tdir={TempFolder}\n\tout={seg_num}\n")
counter = counter + 1
aria_command = [
'aria2c', '-i', LinkList_txt,
'--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"',
'--async-dns=false',
'--enable-color=false',
'--allow-overwrite=true',
'--download-result=hide',
'--auto-file-renaming=false',
'--file-allocation=none',
'--summary-interval=0',
'--retry-wait=5',
'--uri-selector=inorder',
'--console-log-level=warn',
'-x16', '-j16', '-s16']
if sys.version_info >= (3, 5):
aria_out = subprocess.run(aria_command)
aria_out.check_returncode()
if os.path.isfile(LinkList_txt):
os.remove(LinkList_txt)
source_files = pathlib.Path(TempFolder).rglob('./*.mp4')
with open(file_name, mode='wb') as (destination):
for file in source_files:
with open(file, mode='rb') as (source):
shutil.copyfileobj(source, destination)
if os.path.exists(TempFolder):
shutil.rmtree(TempFolder)
if os.path.exists(TempFolder):
shutil.rmtree(TempFolder)
def get_intro_m3u8(self):
m3u8_json = m3u8parser(requests.get(self.m3u8_url).text)
url_dict_list = []
init_url_list = []
for segment in m3u8_json['segments']:
if not 'key' in segment:
init_url_list.append(segment['init_section']['uri'])
for init_mp4 in init_url_list:
url_list = []
for segment in m3u8_json['segments']:
if not 'key' in segment:
init_id = 'INTRO'
url_list.append(init_mp4)
url_list.append(segment['uri'])
url_dict_list.append({'id':init_id, 'url_list':url_list})
return url_dict_list
def get_segs_m3u8(self):
m3u8_json = m3u8parser(requests.get(self.m3u8_url).text)
url_dict_list = []
init_url_list = []
for segment in m3u8_json['segments']:
if 'key' in segment:
init_url_list.append(segment['init_section']['uri'])
for init_mp4 in init_url_list:
url_list = []
for segment in m3u8_json['segments']:
if 'key' in segment:
url_list.append(segment['init_section']['uri'])
init = list(url_list)[0]
seg_list = []
for segment in m3u8_json['segments']:
if init == segment['init_section']['uri']:
init_id = 'MAIN'
seg_list.append(segment['uri'])
seg_list = [init] + seg_list
url_dict_list.append({'id':init_id, 'url_list':seg_list})
return url_dict_list
def get_decon_m3u8(self):
m3u8_json = m3u8parser(requests.get(self.m3u8_url).text)
url_dict_list = []
init_url_list = []
for segment in m3u8_json['segments']:
if 'key' in segment:
init_url_list.append(segment['init_section']['uri'])
for init_mp4 in init_url_list:
url_list = []
for segment in m3u8_json['segments']:
if 'key' in segment:
url_list.append(segment['init_section']['uri'])
init = list(url_list)[-1]
seg_list = []
for segment in m3u8_json['segments']:
if init == segment['init_section']['uri']:
init_id = 'EXTRAS'
seg_list.append(segment['uri'])
seg_list = [init] + seg_list
url_dict_list.append({'id':init_id, 'url_list':seg_list})
return url_dict_list
def run(self):
segment_list = []
segment_list = self.get_segs_m3u8()
print('\n' + self.output_file)
global temp_folder
aria2c_infile = 'aria2c_infile.txt'
if os.path.isfile(aria2c_infile):
os.remove(aria2c_infile)
temp_folder = self.output_file.replace('.mp4', '')
counter = 0
for url_dic in segment_list:
url_id = url_dic['id']
count_id = str(counter).zfill(4)
fileName = temp_folder + f'_{count_id}_{url_id}.mp4'
self.downloadM3u8(Link_List=url_dic['url_list'], Folder=temp_folder, file_name=fileName)
counter = counter + 1
return segment_list

View File

@@ -0,0 +1,15 @@
config = {
'proxies': {
'none': None
},
}
class ProxyConfig(object):
def __init__(self, proxies):
self.config = config
self.config['proxies'] = proxies
def get_proxy(self, proxy):
return self.config['proxies'].get(proxy)