]>
Commit | Line | Data |
---|---|---|
439a1fff JMF |
1 | from __future__ import unicode_literals |
2 | ||
a08dfd27 PH |
3 | import binascii |
4 | import base64 | |
5 | import hashlib | |
6 | import re | |
fbf189a6 | 7 | import json |
a08dfd27 PH |
8 | |
9 | from .common import InfoExtractor | |
8c25f81b | 10 | from ..compat import ( |
a08dfd27 | 11 | compat_ord, |
9fd3bf04 | 12 | compat_urllib_parse_unquote, |
15707c7e | 13 | compat_urllib_parse_urlencode, |
8c25f81b PH |
14 | ) |
15 | from ..utils import ( | |
a08dfd27 | 16 | ExtractorError, |
5c2266df | 17 | sanitized_Request, |
a08dfd27 PH |
18 | ) |
19 | ||
20 | ||
a08dfd27 | 21 | class MyVideoIE(InfoExtractor): |
b45f2b1d | 22 | _WORKING = False |
5886b38d | 23 | _VALID_URL = r'https?://(?:www\.)?myvideo\.de/(?:[^/]+/)?watch/(?P<id>[0-9]+)/[^?/]+.*' |
439a1fff | 24 | IE_NAME = 'myvideo' |
6f5ac90c | 25 | _TEST = { |
439a1fff JMF |
26 | 'url': 'http://www.myvideo.de/watch/8229274/bowling_fail_or_win', |
27 | 'md5': '2d2753e8130479ba2cb7e0a37002053e', | |
28 | 'info_dict': { | |
29 | 'id': '8229274', | |
30 | 'ext': 'flv', | |
31 | 'title': 'bowling-fail-or-win', | |
6f5ac90c PH |
32 | } |
33 | } | |
a08dfd27 PH |
34 | |
35 | # Original Code from: https://github.com/dersphere/plugin.video.myvideo_de.git | |
36 | # Released into the Public Domain by Tristan Fischer on 2013-05-19 | |
37 | # https://github.com/rg3/youtube-dl/pull/842 | |
5f6a1245 | 38 | def __rc4crypt(self, data, key): |
a08dfd27 PH |
39 | x = 0 |
40 | box = list(range(256)) | |
41 | for i in list(range(256)): | |
42 | x = (x + box[i] + compat_ord(key[i % len(key)])) % 256 | |
43 | box[i], box[x] = box[x], box[i] | |
44 | x = 0 | |
45 | y = 0 | |
46 | out = '' | |
47 | for char in data: | |
48 | x = (x + 1) % 256 | |
49 | y = (y + box[x]) % 256 | |
50 | box[x], box[y] = box[y], box[x] | |
51 | out += chr(compat_ord(char) ^ box[(box[x] + box[y]) % 256]) | |
52 | return out | |
53 | ||
5f6a1245 | 54 | def __md5(self, s): |
a08dfd27 PH |
55 | return hashlib.md5(s).hexdigest().encode() |
56 | ||
5f6a1245 | 57 | def _real_extract(self, url): |
a08dfd27 | 58 | mobj = re.match(self._VALID_URL, url) |
439a1fff | 59 | video_id = mobj.group('id') |
a08dfd27 PH |
60 | |
61 | GK = ( | |
b74e86f4 PH |
62 | b'WXpnME1EZGhNRGhpTTJNM01XVmhOREU0WldNNVpHTTJOakpt' |
63 | b'TW1FMU5tVTBNR05pWkRaa05XRXhNVFJoWVRVd1ptSXhaVEV3' | |
64 | b'TnpsbA0KTVRkbU1tSTRNdz09' | |
a08dfd27 PH |
65 | ) |
66 | ||
67 | # Get video webpage | |
68 | webpage_url = 'http://www.myvideo.de/watch/%s' % video_id | |
69 | webpage = self._download_webpage(webpage_url, video_id) | |
70 | ||
71 | mobj = re.search('source src=\'(.+?)[.]([^.]+)\'', webpage) | |
72 | if mobj is not None: | |
73 | self.report_extraction(video_id) | |
74 | video_url = mobj.group(1) + '.flv' | |
75 | ||
76 | video_title = self._html_search_regex('<title>([^<]+)</title>', | |
9e1a5b84 | 77 | webpage, 'title') |
a08dfd27 | 78 | |
439a1fff JMF |
79 | return { |
80 | 'id': video_id, | |
81 | 'url': video_url, | |
82 | 'title': video_title, | |
83 | } | |
a08dfd27 | 84 | |
fbf189a6 JMF |
85 | mobj = re.search(r'data-video-service="/service/data/video/%s/config' % video_id, webpage) |
86 | if mobj is not None: | |
5c2266df | 87 | request = sanitized_Request('http://www.myvideo.de/service/data/video/%s/config' % video_id, '') |
fbf189a6 | 88 | response = self._download_webpage(request, video_id, |
439a1fff | 89 | 'Downloading video info') |
fbf189a6 | 90 | info = json.loads(base64.b64decode(response).decode('utf-8')) |
439a1fff JMF |
91 | return { |
92 | 'id': video_id, | |
93 | 'title': info['title'], | |
94 | 'url': info['streaming_url'].replace('rtmpe', 'rtmpt'), | |
95 | 'play_path': info['filename'], | |
96 | 'ext': 'flv', | |
97 | 'thumbnail': info['thumbnail'][0]['url'], | |
98 | } | |
fbf189a6 | 99 | |
a08dfd27 PH |
100 | # try encxml |
101 | mobj = re.search('var flashvars={(.+?)}', webpage) | |
102 | if mobj is None: | |
439a1fff | 103 | raise ExtractorError('Unable to extract video') |
a08dfd27 PH |
104 | |
105 | params = {} | |
106 | encxml = '' | |
107 | sec = mobj.group(1) | |
108 | for (a, b) in re.findall('(.+?):\'(.+?)\',?', sec): | |
109 | if not a == '_encxml': | |
110 | params[a] = b | |
111 | else: | |
9fd3bf04 | 112 | encxml = compat_urllib_parse_unquote(b) |
a08dfd27 PH |
113 | if not params.get('domain'): |
114 | params['domain'] = 'www.myvideo.de' | |
15707c7e | 115 | xmldata_url = '%s?%s' % (encxml, compat_urllib_parse_urlencode(params)) |
a08dfd27 | 116 | if 'flash_playertype=MTV' in xmldata_url: |
439a1fff | 117 | self._downloader.report_warning('avoiding MTV player') |
a08dfd27 PH |
118 | xmldata_url = ( |
119 | 'http://www.myvideo.de/dynamic/get_player_video_xml.php' | |
120 | '?flash_playertype=D&ID=%s&_countlimit=4&autorun=yes' | |
121 | ) % video_id | |
122 | ||
123 | # get enc data | |
124 | enc_data = self._download_webpage(xmldata_url, video_id).split('=')[1] | |
125 | enc_data_b = binascii.unhexlify(enc_data) | |
126 | sk = self.__md5( | |
127 | base64.b64decode(base64.b64decode(GK)) + | |
128 | self.__md5( | |
129 | str(video_id).encode('utf-8') | |
130 | ) | |
131 | ) | |
132 | dec_data = self.__rc4crypt(enc_data_b, sk) | |
133 | ||
134 | # extracting infos | |
135 | self.report_extraction(video_id) | |
136 | ||
137 | video_url = None | |
138 | mobj = re.search('connectionurl=\'(.*?)\'', dec_data) | |
139 | if mobj: | |
9fd3bf04 | 140 | video_url = compat_urllib_parse_unquote(mobj.group(1)) |
a08dfd27 | 141 | if 'myvideo2flash' in video_url: |
f45f96f8 | 142 | self.report_warning( |
439a1fff | 143 | 'Rewriting URL to use unencrypted rtmp:// ...', |
f45f96f8 PH |
144 | video_id) |
145 | video_url = video_url.replace('rtmpe://', 'rtmp://') | |
a08dfd27 PH |
146 | |
147 | if not video_url: | |
148 | # extract non rtmp videos | |
149 | mobj = re.search('path=\'(http.*?)\' source=\'(.*?)\'', dec_data) | |
150 | if mobj is None: | |
439a1fff | 151 | raise ExtractorError('unable to extract url') |
9fd3bf04 | 152 | video_url = compat_urllib_parse_unquote(mobj.group(1)) + compat_urllib_parse_unquote(mobj.group(2)) |
a08dfd27 | 153 | |
439a1fff | 154 | video_file = self._search_regex('source=\'(.*?)\'', dec_data, 'video file') |
9fd3bf04 | 155 | video_file = compat_urllib_parse_unquote(video_file) |
a08dfd27 PH |
156 | |
157 | if not video_file.endswith('f4m'): | |
158 | ppath, prefix = video_file.split('.') | |
159 | video_playpath = '%s:%s' % (prefix, ppath) | |
a08dfd27 PH |
160 | else: |
161 | video_playpath = '' | |
a08dfd27 | 162 | |
ec85ded8 | 163 | video_swfobj = self._search_regex(r'swfobject.embedSWF\(\'(.+?)\'', webpage, 'swfobj') |
9fd3bf04 | 164 | video_swfobj = compat_urllib_parse_unquote(video_swfobj) |
a08dfd27 PH |
165 | |
166 | video_title = self._html_search_regex("<h1(?: class='globalHd')?>(.*?)</h1>", | |
9e1a5b84 | 167 | webpage, 'title') |
439a1fff JMF |
168 | |
169 | return { | |
170 | 'id': video_id, | |
171 | 'url': video_url, | |
172 | 'tc_url': video_url, | |
173 | 'title': video_title, | |
174 | 'ext': 'flv', | |
175 | 'play_path': video_playpath, | |
176 | 'player_url': video_swfobj, | |
177 | } |