]>
Commit | Line | Data |
---|---|---|
dcdb292f | 1 | # coding: utf-8 |
bb198c95 PH |
2 | from __future__ import unicode_literals |
3 | ||
ac6c358c | 4 | import binascii |
cd8b8302 | 5 | import re |
3a105f7b | 6 | import json |
cd8b8302 PH |
7 | |
8 | from .common import InfoExtractor | |
cf282071 S |
9 | from ..compat import ( |
10 | compat_b64decode, | |
11 | compat_ord, | |
12 | ) | |
ce9f47de NJ |
13 | from ..utils import ( |
14 | ExtractorError, | |
15 | qualities, | |
f9f3e3df | 16 | determine_ext, |
ce9f47de | 17 | ) |
cd8b8302 PH |
18 | |
19 | ||
20 | class TeamcocoIE(InfoExtractor): | |
5886b38d | 21 | _VALID_URL = r'https?://teamcoco\.com/video/(?P<video_id>[0-9]+)?/?(?P<display_id>.*)' |
bb799e81 | 22 | _TESTS = [ |
9e1a5b84 JW |
23 | { |
24 | 'url': 'http://teamcoco.com/video/80187/conan-becomes-a-mary-kay-beauty-consultant', | |
9e1a5b84 JW |
25 | 'md5': '3f7746aa0dc86de18df7539903d399ea', |
26 | 'info_dict': { | |
17d2712d PH |
27 | 'id': '80187', |
28 | 'ext': 'mp4', | |
9e1a5b84 | 29 | 'title': 'Conan Becomes A Mary Kay Beauty Consultant', |
641eb10d | 30 | 'description': 'Mary Kay is perhaps the most trusted name in female beauty, so of course Conan is a natural choice to sell their products.', |
7088f5b5 | 31 | 'duration': 504, |
641eb10d | 32 | 'age_limit': 0, |
9e1a5b84 JW |
33 | } |
34 | }, { | |
35 | 'url': 'http://teamcoco.com/video/louis-ck-interview-george-w-bush', | |
9e1a5b84 JW |
36 | 'md5': 'cde9ba0fa3506f5f017ce11ead928f9a', |
37 | 'info_dict': { | |
17d2712d PH |
38 | 'id': '19705', |
39 | 'ext': 'mp4', | |
314368c8 NJ |
40 | 'description': 'Louis C.K. got starstruck by George W. Bush, so what? Part one.', |
41 | 'title': 'Louis C.K. Interview Pt. 1 11/3/11', | |
7088f5b5 | 42 | 'duration': 288, |
641eb10d | 43 | 'age_limit': 0, |
9e1a5b84 | 44 | } |
9c5335a0 YCH |
45 | }, { |
46 | 'url': 'http://teamcoco.com/video/timothy-olyphant-drinking-whiskey', | |
47 | 'info_dict': { | |
48 | 'id': '88748', | |
49 | 'ext': 'mp4', | |
50 | 'title': 'Timothy Olyphant Raises A Toast To “Justified”', | |
51 | 'description': 'md5:15501f23f020e793aeca761205e42c24', | |
52 | }, | |
53 | 'params': { | |
54 | 'skip_download': True, # m3u8 downloads | |
55 | } | |
d31573fa YCH |
56 | }, { |
57 | 'url': 'http://teamcoco.com/video/full-episode-mon-6-1-joel-mchale-jake-tapper-and-musical-guest-courtney-barnett?playlist=x;eyJ0eXBlIjoidGFnIiwiaWQiOjl9', | |
58 | 'info_dict': { | |
59 | 'id': '89341', | |
60 | 'ext': 'mp4', | |
61 | 'title': 'Full Episode - Mon. 6/1 - Joel McHale, Jake Tapper, And Musical Guest Courtney Barnett', | |
62 | 'description': 'Guests: Joel McHale, Jake Tapper, And Musical Guest Courtney Barnett', | |
63 | }, | |
64 | 'params': { | |
65 | 'skip_download': True, # m3u8 downloads | |
66 | } | |
bb799e81 | 67 | } |
bb799e81 | 68 | ] |
3811c567 NJ |
69 | _VIDEO_ID_REGEXES = ( |
70 | r'"eVar42"\s*:\s*(\d+)', | |
71 | r'Ginger\.TeamCoco\.openInApp\("video",\s*"([^"]+)"', | |
72 | r'"id_not"\s*:\s*(\d+)' | |
73 | ) | |
cd8b8302 PH |
74 | |
75 | def _real_extract(self, url): | |
76 | mobj = re.match(self._VALID_URL, url) | |
dfb2cb5c PH |
77 | |
78 | display_id = mobj.group('display_id') | |
12675275 YCH |
79 | webpage, urlh = self._download_webpage_handle(url, display_id) |
80 | if 'src=expired' in urlh.geturl(): | |
81 | raise ExtractorError('This video is expired.', expected=True) | |
5f6a1245 | 82 | |
314368c8 | 83 | video_id = mobj.group('video_id') |
dfb2cb5c | 84 | if not video_id: |
04ee53ec | 85 | video_id = self._html_search_regex( |
3811c567 | 86 | self._VIDEO_ID_REGEXES, webpage, 'video id') |
cd8b8302 | 87 | |
3a105f7b | 88 | data = None |
9c5335a0 | 89 | |
3a105f7b YCH |
90 | preload_codes = self._html_search_regex( |
91 | r'(function.+)setTimeout\(function\(\)\{playlist', | |
92 | webpage, 'preload codes') | |
791ff52f | 93 | base64_fragments = re.findall(r'"([a-zA-Z0-9+/=]+)"', preload_codes) |
3a105f7b | 94 | base64_fragments.remove('init') |
9c5335a0 | 95 | |
3a105f7b YCH |
96 | def _check_sequence(cur_fragments): |
97 | if not cur_fragments: | |
98 | return | |
99 | for i in range(len(cur_fragments)): | |
100 | cur_sequence = (''.join(cur_fragments[i:] + cur_fragments[:i])).encode('ascii') | |
ac6c358c | 101 | try: |
cf282071 | 102 | raw_data = compat_b64decode(cur_sequence) |
3a105f7b YCH |
103 | if compat_ord(raw_data[0]) == compat_ord('{'): |
104 | return json.loads(raw_data.decode('utf-8')) | |
105 | except (TypeError, binascii.Error, UnicodeDecodeError, ValueError): | |
ac6c358c | 106 | continue |
ac6c358c | 107 | |
3a105f7b YCH |
108 | def _check_data(): |
109 | for i in range(len(base64_fragments) + 1): | |
110 | for j in range(i, len(base64_fragments) + 1): | |
111 | data = _check_sequence(base64_fragments[:i] + base64_fragments[j:]) | |
112 | if data: | |
113 | return data | |
114 | ||
115 | self.to_screen('Try to compute possible data sequence. This may take some time.') | |
116 | data = _check_data() | |
9c5335a0 | 117 | |
ac6c358c | 118 | if not data: |
3a105f7b YCH |
119 | raise ExtractorError( |
120 | 'Preload information could not be extracted', expected=True) | |
cd8b8302 | 121 | |
e7e6b54d | 122 | formats = [] |
314368c8 NJ |
123 | get_quality = qualities(['500k', '480p', '1000k', '720p', '1080p']) |
124 | for filed in data['files']: | |
f9f3e3df | 125 | if determine_ext(filed['url']) == 'm3u8': |
d31573fa YCH |
126 | # compat_urllib_parse.urljoin does not work here |
127 | if filed['url'].startswith('/'): | |
128 | m3u8_url = 'http://ht.cdn.turner.com/tbs/big/teamcoco' + filed['url'] | |
129 | else: | |
130 | m3u8_url = filed['url'] | |
131 | m3u8_formats = self._extract_m3u8_formats( | |
132 | m3u8_url, video_id, ext='mp4') | |
133 | for m3u8_format in m3u8_formats: | |
134 | if m3u8_format not in formats: | |
135 | formats.append(m3u8_format) | |
136 | elif determine_ext(filed['url']) == 'f4m': | |
137 | # TODO Correct f4m extraction | |
138 | continue | |
e7e6b54d | 139 | else: |
d31573fa YCH |
140 | if filed['url'].startswith('/mp4:protected/'): |
141 | # TODO Correct extraction for these files | |
142 | continue | |
5bb6328c NJ |
143 | m_format = re.search(r'(\d+(k|p))\.mp4', filed['url']) |
144 | if m_format is not None: | |
145 | format_id = m_format.group(1) | |
146 | else: | |
147 | format_id = filed['bitrate'] | |
148 | tbr = ( | |
149 | int(filed['bitrate']) | |
150 | if filed['bitrate'].isdigit() | |
151 | else None) | |
befdc8f3 | 152 | |
5bb6328c NJ |
153 | formats.append({ |
154 | 'url': filed['url'], | |
155 | 'ext': 'mp4', | |
156 | 'tbr': tbr, | |
157 | 'format_id': format_id, | |
158 | 'quality': get_quality(format_id), | |
159 | }) | |
befdc8f3 PH |
160 | |
161 | self._sort_formats(formats) | |
cd8b8302 | 162 | |
e7e6b54d | 163 | return { |
bb198c95 | 164 | 'id': video_id, |
dfb2cb5c | 165 | 'display_id': display_id, |
e7e6b54d | 166 | 'formats': formats, |
314368c8 NJ |
167 | 'title': data['title'], |
168 | 'thumbnail': data.get('thumb', {}).get('href'), | |
169 | 'description': data.get('teaser'), | |
7088f5b5 | 170 | 'duration': data.get('duration'), |
641eb10d | 171 | 'age_limit': self._family_friendly_search(webpage), |
e7e6b54d | 172 | } |