]>
Commit | Line | Data |
---|---|---|
ddbd9035 PH |
1 | # coding: utf-8 |
2 | ||
8a32b82e PH |
3 | from __future__ import unicode_literals |
4 | ||
9c286cfa PH |
5 | import math |
6 | import random | |
7 | import re | |
8 | import time | |
9 | ||
10 | from .common import InfoExtractor | |
11 | from ..utils import ( | |
12 | ExtractorError, | |
13 | ) | |
14 | ||
15 | ||
16 | class YoukuIE(InfoExtractor): | |
8a32b82e PH |
17 | _VALID_URL = r'''(?x) |
18 | (?: | |
19 | http://(?:v|player)\.youku\.com/(?:v_show/id_|player\.php/sid/)| | |
20 | youku:) | |
21 | (?P<id>[A-Za-z0-9]+)(?:\.html|/v\.swf|) | |
22 | ''' | |
23 | _TEST = { | |
24 | 'url': 'http://v.youku.com/v_show/id_XNDgyMDQ2NTQw.html', | |
25 | 'md5': 'ffe3f2e435663dc2d1eea34faeff5b5b', | |
26 | 'params': { | |
27 | 'test': False | |
28 | }, | |
29 | 'info_dict': { | |
30 | 'id': 'XNDgyMDQ2NTQw_part00', | |
31 | 'ext': 'flv', | |
32 | 'title': 'youtube-dl test video "\'/\\ä↭𝕐' | |
67f51b3d PH |
33 | } |
34 | } | |
35 | ||
9c286cfa PH |
36 | def _gen_sid(self): |
37 | nowTime = int(time.time() * 1000) | |
5f6a1245 JW |
38 | random1 = random.randint(1000, 1998) |
39 | random2 = random.randint(1000, 9999) | |
9c286cfa | 40 | |
5f6a1245 | 41 | return "%d%d%d" % (nowTime, random1, random2) |
9c286cfa PH |
42 | |
43 | def _get_file_ID_mix_string(self, seed): | |
44 | mixed = [] | |
45 | source = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\:._-1234567890") | |
46 | seed = float(seed) | |
47 | for i in range(len(source)): | |
8bcc8756 JW |
48 | seed = (seed * 211 + 30031) % 65536 |
49 | index = math.floor(seed / 65536 * len(source)) | |
9c286cfa PH |
50 | mixed.append(source[int(index)]) |
51 | source.remove(source[int(index)]) | |
5f6a1245 | 52 | # return ''.join(mixed) |
9c286cfa PH |
53 | return mixed |
54 | ||
55 | def _get_file_id(self, fileId, seed): | |
56 | mixed = self._get_file_ID_mix_string(seed) | |
57 | ids = fileId.split('*') | |
58 | realId = [] | |
59 | for ch in ids: | |
60 | if ch: | |
61 | realId.append(mixed[int(ch)]) | |
62 | return ''.join(realId) | |
63 | ||
64 | def _real_extract(self, url): | |
65 | mobj = re.match(self._VALID_URL, url) | |
8a32b82e | 66 | video_id = mobj.group('id') |
9c286cfa PH |
67 | |
68 | info_url = 'http://v.youku.com/player/getPlayList/VideoIDS/' + video_id | |
69 | ||
8a32b82e PH |
70 | config = self._download_json(info_url, video_id) |
71 | ||
72 | error_code = config['data'][0].get('error_code') | |
73 | if error_code: | |
74 | # -8 means blocked outside China. | |
75 | error = config['data'][0].get('error') # Chinese and English, separated by newline. | |
76 | raise ExtractorError(error or 'Server reported error %i' % error_code, | |
9e1a5b84 | 77 | expected=True) |
9c286cfa | 78 | |
8a32b82e PH |
79 | video_title = config['data'][0]['title'] |
80 | seed = config['data'][0]['seed'] | |
9c286cfa | 81 | |
8a32b82e PH |
82 | format = self._downloader.params.get('format', None) |
83 | supported_format = list(config['data'][0]['streamfileids'].keys()) | |
84 | ||
85 | # TODO proper format selection | |
86 | if format is None or format == 'best': | |
87 | if 'hd2' in supported_format: | |
88 | format = 'hd2' | |
89 | else: | |
90 | format = 'flv' | |
91 | ext = 'flv' | |
92 | elif format == 'worst': | |
93 | format = 'mp4' | |
94 | ext = 'mp4' | |
95 | else: | |
96 | format = 'flv' | |
97 | ext = 'flv' | |
98 | ||
99 | fileid = config['data'][0]['streamfileids'][format] | |
100 | keys = [s['k'] for s in config['data'][0]['segs'][format]] | |
101 | # segs is usually a dictionary, but an empty *list* if an error occured. | |
9c286cfa | 102 | |
5f6a1245 | 103 | files_info = [] |
9c286cfa PH |
104 | sid = self._gen_sid() |
105 | fileid = self._get_file_id(fileid, seed) | |
106 | ||
5f6a1245 JW |
107 | # column 8,9 of fileid represent the segment number |
108 | # fileid[7:9] should be changed | |
9c286cfa | 109 | for index, key in enumerate(keys): |
9c286cfa | 110 | temp_fileid = '%s%02X%s' % (fileid[0:8], index, fileid[10:]) |
8a32b82e | 111 | download_url = 'http://k.youku.com/player/getFlvPath/sid/%s_%02X/st/flv/fileid/%s?k=%s' % (sid, index, temp_fileid, key) |
9c286cfa PH |
112 | |
113 | info = { | |
114 | 'id': '%s_part%02d' % (video_id, index), | |
115 | 'url': download_url, | |
116 | 'uploader': None, | |
117 | 'upload_date': None, | |
118 | 'title': video_title, | |
119 | 'ext': ext, | |
120 | } | |
121 | files_info.append(info) | |
122 | ||
123 | return files_info |