diff --git a/src/you_get/extractors/letv.py b/src/you_get/extractors/letv.py index eaf92fbb..43b26908 100644 --- a/src/you_get/extractors/letv.py +++ b/src/you_get/extractors/letv.py @@ -1,34 +1,16 @@ #!/usr/bin/env python -__all__ = ['letv_download', 'letvcloud_download', 'letvcloud_download_by_vu'] - import json import random -import xml.etree.ElementTree as ET -import base64, hashlib, urllib, time, re +import base64, time, re from ..common import * - -#@DEPRECATED -def get_timestamp(): - tn = random.random() - url = 'http://api.letv.com/time?tn={}'.format(tn) - result = get_content(url) - return json.loads(result)['stime'] -#@DEPRECATED -def get_key(t): - for s in range(0, 8): - e = 1 & t - t >>= 1 - e <<= 31 - t += e - return t ^ 185025305 +from ..extractor import VideoExtractor def calcTimeKey(t): ror = lambda val, r_bits, : ((val & (2**32-1)) >> r_bits%32) | (val << (32-(r_bits%32)) & (2**32-1)) return ror(ror(t,773625421%13)^773625421,773625421%17) - def decode(data): version = data[0:5] if version.lower() == b'vc_01': @@ -48,102 +30,86 @@ def decode(data): # directly return return data +class Letv(VideoExtractor): + name = "乐视 (Letv)" + stream_types = [ + {'id': '1080p', 'container': 'mp4', 'video_profile': '1080p'}, + {'id': '1300', 'container': 'mp4', 'video_profile': '超清'}, + {'id': '1000', 'container': 'mp4', 'video_profile': '高清'}, + {'id': '720p', 'container': 'mp4', 'video_profile': '标清'}, + {'id': '350', 'container': 'mp4', 'video_profile': '流畅'}, + ] - -def video_info(vid,**kwargs): - url = 'http://api.letv.com/mms/out/video/playJson?id={}&platid=1&splatid=101&format=1&tkey={}&domain=www.letv.com'.format(vid,calcTimeKey(int(time.time()))) - r = get_content(url, decoded=False) - info=json.loads(str(r,"utf-8")) + def prepare(self, **kwargs): + assert self.url or self.vid + if self.vid: + self.url = "http://www.letv.com/ptv/vplay/{}.html".format(self.vid) + html = get_content(self.url) + if not self.vid: + self.vid = match1(self.url, r'http://www.letv.com/ptv/vplay/(\d+).html') + if not self.vid: + #self embed + vids = matchall(html, ['vid="(\d+)"']) + for v in vids: + self.download_by_vid(v, **kwargs) - stream_id = None - support_stream_id = info["playurl"]["dispatch"].keys() - if "stream_id" in kwargs and kwargs["stream_id"].lower() in support_stream_id: - stream_id = kwargs["stream_id"] - else: - print("Current Video Supports:") - for i in support_stream_id: - print("\t--format",i,"") - if "1080p" in support_stream_id: - stream_id = '1080p' - elif "720p" in support_stream_id: - stream_id = '720p' + #normal process + self.title = match1(html,r'name="irTitle" content="(.*?)"') + info_url = 'http://api.letv.com/mms/out/video/playJson?id={}&platid=1&splatid=101&format=1&tkey={}&domain=www.letv.com'.format(self.vid, calcTimeKey(int(time.time()))) + r = get_content(info_url, decoded=False) + info=json.loads(str(r,"utf-8")) + support_stream_id = info["playurl"]["dispatch"].keys() + for stream in self.stream_types: + if stream['id'] in support_stream_id: + s_url =info["playurl"]["domain"][0]+info["playurl"]["dispatch"][stream['id']][0] + ext = info["playurl"]["dispatch"][stream['id']][1].split('.')[-1] + s_url+="&ctv=pc&m3v=1&termid=1&format=1&hwtype=un&ostype=Linux&tag=letv&sign=letv&expect=3&tn={}&pay=0&iscpn=f9051&rateid={}".format(random.random(),stream['id']) + r2=get_content(s_url,decoded=False) + info2=json.loads(str(r2,"utf-8")) + + # hold on ! more things to do + # to decode m3u8 (encoded) + m3u8 = get_content(info2["location"],decoded=False) + m3u8_list = decode(m3u8) + urls = re.findall(r'^[^#][^\r]*',m3u8_list,re.MULTILINE) + self.streams[stream['id']] = {'container': ext, 'video_profile': stream['video_profile'], 'src': urls, 'size' : 0} + + def extract(self, **kwargs): + if 'info_only' in kwargs and kwargs['info_only']: + for stream_id in self.streams.keys(): + size = 0 + for i in self.streams[stream_id]['src']: + _, _, tmp = url_info(i) + size += tmp + stream['size'] = size + return + #ignore video size in download/play mode, for preformence issue + if 'stream_id' in kwargs and kwargs['stream_id']: + # Extract the stream + stream_id = kwargs['stream_id'] + + if stream_id not in self.streams: + log.e('[Error] Invalid video format.') + log.e('Run \'-i\' command with no specific video format to view all available formats.') + exit(2) else: - stream_id =sorted(support_stream_id,key= lambda i: int(i[1:]))[-1] + # Extract stream with the best quality + stream_id = self.streams_sorted[0]['id'] - url =info["playurl"]["domain"][0]+info["playurl"]["dispatch"][stream_id][0] - ext = info["playurl"]["dispatch"][stream_id][1].split('.')[-1] - url+="&ctv=pc&m3v=1&termid=1&format=1&hwtype=un&ostype=Linux&tag=letv&sign=letv&expect=3&tn={}&pay=0&iscpn=f9051&rateid={}".format(random.random(),stream_id) + size = 0 + for i in self.streams[stream_id]['src']: + _, _, tmp = url_info(i) + size += tmp + self.streams[stream_id]['size'] = size - r2=get_content(url,decoded=False) - info2=json.loads(str(r2,"utf-8")) - # hold on ! more things to do - # to decode m3u8 (encoded) - m3u8 = get_content(info2["location"],decoded=False) - m3u8_list = decode(m3u8) - urls = re.findall(r'^[^#][^\r]*',m3u8_list,re.MULTILINE) - return ext,urls +def letvcloud_download_by_vu(vu, uu, title=None, output_dir='.', merge=True, info_only=False, **kwargs): + from .letvcloud import letvcloud_download_by_vid + letvcloud_download_by_vid((vu, uu), title=title, output_dir=output_dir, merge=merge, info_only=info_only,**kwargs) -def letv_download_by_vid(vid,title, output_dir='.', merge=True, info_only=False,**kwargs): - ext , urls = video_info(vid,**kwargs) - size = 0 - for i in urls: - _, _, tmp = url_info(i) - size += tmp - - print_info(site_info, title, ext, size) - if not info_only: - download_urls(urls, title, ext, size, output_dir=output_dir, merge=merge) - -def letvcloud_download_by_vu(vu, uu, title=None, output_dir='.', merge=True, info_only=False): - #ran = float('0.' + str(random.randint(0, 9999999999999999))) # For ver 2.1 - #str2Hash = 'cfflashformatjsonran{ran}uu{uu}ver2.2vu{vu}bie^#@(%27eib58'.format(vu = vu, uu = uu, ran = ran) #Magic!/ In ver 2.1 - argumet_dict ={'cf' : 'flash', 'format': 'json', 'ran': str(int(time.time())), 'uu': str(uu),'ver': '2.2', 'vu': str(vu), } - sign_key = '2f9d6924b33a165a6d8b5d3d42f4f987' #ALL YOUR BASE ARE BELONG TO US - str2Hash = ''.join([i + argumet_dict[i] for i in sorted(argumet_dict)]) + sign_key - sign = hashlib.md5(str2Hash.encode('utf-8')).hexdigest() - request_info = urllib.request.Request('http://api.letvcloud.com/gpc.php?' + '&'.join([i + '=' + argumet_dict[i] for i in argumet_dict]) + '&sign={sign}'.format(sign = sign)) - response = urllib.request.urlopen(request_info) - data = response.read() - info = json.loads(data.decode('utf-8')) - type_available = [] - for video_type in info['data']['video_info']['media']: - type_available.append({'video_url': info['data']['video_info']['media'][video_type]['play_url']['main_url'], 'video_quality': int(info['data']['video_info']['media'][video_type]['play_url']['vtype'])}) - urls = [base64.b64decode(sorted(type_available, key = lambda x:x['video_quality'])[-1]['video_url']).decode("utf-8")] - size = urls_size(urls) - ext = 'mp4' - print_info(site_info, title, ext, size) - if not info_only: - download_urls(urls, title, ext, size, output_dir=output_dir, merge=merge) - -def letvcloud_download(url, output_dir='.', merge=True, info_only=False): - for i in url.split('&'): - if 'vu=' in i: - vu = i[3:] - if 'uu=' in i: - uu = i[3:] - if len(vu) == 0: - raise ValueError('Cannot get vu!') - if len(uu) == 0: - raise ValueError('Cannot get uu!') - title = "LETV-%s" % vu - letvcloud_download_by_vu(vu, uu, title=title, output_dir=output_dir, merge=merge, info_only=info_only) - -def letv_download(url, output_dir='.', merge=True, info_only=False ,**kwargs): - if re.match(r'http://yuntv.letv.com/', url): - letvcloud_download(url, output_dir=output_dir, merge=merge, info_only=info_only) - else: - html = get_content(url) - #to get title - if re.match(r'http://www.letv.com/ptv/vplay/(\d+).html', url): - vid = match1(url, r'http://www.letv.com/ptv/vplay/(\d+).html') - else: - vid = match1(html, r'vid="(\d+)"') - title = match1(html,r'name="irTitle" content="(.*?)"') - letv_download_by_vid(vid, title=title, output_dir=output_dir, merge=merge, info_only=info_only,**kwargs) - -site_info = "LeTV.com" -download = letv_download +site = Letv() +download = site.download_by_url +letv_download_by_vid = site.download_by_vid download_playlist = playlist_not_supported('letv') diff --git a/src/you_get/extractors/letvcloud.py b/src/you_get/extractors/letvcloud.py new file mode 100644 index 00000000..0e6b84f8 --- /dev/null +++ b/src/you_get/extractors/letvcloud.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +from ..common import * +from ..extractor import VideoExtractor +import json +import base64, hashlib, time, re + +class Letvcloud(VideoExtractor): + name = "乐视云 (Letvcloud)" + + stream_types = [ + {'id': 'yuanhua', 'container': 'mp4', 'video_profile': '原画'}, + {'id': 'super', 'container': 'mp4', 'video_profile': '超清'}, + {'id': 'high', 'container': 'mp4', 'video_profile': '高清'}, + {'id': 'low', 'container': 'mp4', 'video_profile': '标清'}, + ] + + def letvcloud_download_by_vu(self): + #ran = float('0.' + str(random.randint(0, 9999999999999999))) # For ver 2.1 + #str2Hash = 'cfflashformatjsonran{ran}uu{uu}ver2.2vu{vu}bie^#@(%27eib58'.format(vu = vu, uu = uu, ran = ran) #Magic!/ In ver 2.1 + vu, uu = self.vid + argumet_dict ={'cf' : 'flash', 'format': 'json', 'ran': str(int(time.time())), 'uu': str(uu),'ver': '2.2', 'vu': str(vu), } + sign_key = '2f9d6924b33a165a6d8b5d3d42f4f987' #ALL YOUR BASE ARE BELONG TO US + str2Hash = ''.join([i + argumet_dict[i] for i in sorted(argumet_dict)]) + sign_key + sign = hashlib.md5(str2Hash.encode('utf-8')).hexdigest() + html = get_content('http://api.letvcloud.com/gpc.php?' + '&'.join([i + '=' + argumet_dict[i] for i in argumet_dict]) + '&sign={sign}'.format(sign = sign), decoded = False) + info = json.loads(str(html,"utf-8")) + + available_stream_type = info['data']['video_info']['media'].keys() + for stream in self.stream_types: + if stream['id'] in available_stream_type: + urls = [base64.b64decode(info['data']['video_info']['media'][stream['id']]['play_url']['main_url']).decode("utf-8")] + size = urls_size(urls) + ext = 'mp4' + self.streams[stream['id']] = {'container': ext, 'video_profile': stream['video_profile'], 'src': urls, 'size' : size} + + def prepare(self, **kwargs): + assert self.url or self.vid + + if self.url and not self.vid: + #maybe error!! + self.vid = (vu, uu) = matchall(self.url, ["vu=([^&]+)","uu=([^&]+)"]) + _, vu = self.vid + if 'title' in kwargs and kwargs['title']: + self.title = kwargs['title'] + else: + self.title = "LeTV - {}".format(vu) + self.letvcloud_download_by_vu() + +site = Letvcloud() +download = site.download_by_url +letvcloud_download_by_vid = site.download_by_vid +download_playlist = playlist_not_supported('letvcloud')