4 from .turner
import TurnerBaseIE
21 class TeamcocoBaseIE(TurnerBaseIE
):
29 def _get_formats_and_subtitles(self
, info
, video_id
):
30 formats
, subtitles
= [], {}
32 for src
in traverse_obj(info
, ('src', ..., {dict}
)):
33 format_id
= src
.get('label')
34 src_url
= src
.get('src')
35 if re
.match(r
'https?:/[^/]', src_url
):
36 src_url
= src_url
.replace(':/', '://', 1)
37 ext
= determine_ext(src_url
, mimetype2ext(src
.get('type')))
39 if not format_id
or not src_url
:
41 elif format_id
== 'hls' or ext
== 'm3u8':
42 fmts
, subs
= self
._extract
_m
3u8_formats
_and
_subtitles
(
43 src_url
, video_id
, 'mp4', m3u8_id
=format_id
, fatal
=False)
45 self
._merge
_subtitles
(subs
, target
=subtitles
)
47 elif format_id
in self
._QUALITIES
:
48 if src_url
.startswith('/mp4:protected/'):
49 # TODO: Correct extraction for these files
54 'format_id': format_id
,
55 'width': self
._QUALITIES
[format_id
][0],
56 'height': self
._QUALITIES
[format_id
][1],
59 return formats
, subtitles
62 class TeamcocoIE(TeamcocoBaseIE
):
63 _VALID_URL
= r
'https?://(?:www\.)?teamcoco\.com/(?P<id>([^/]+/)*[^/?#]+)'
66 'url': 'http://teamcoco.com/video/mary-kay-remote',
69 'display_id': 'video_mary-kay-remote',
71 'title': 'Conan Becomes A Mary Kay Beauty Consultant',
72 'description': 'md5:9fb64e45b5aef6b2af1b67612b36c162',
73 'thumbnail': 'https://teamcoco.com/image/thumb?id=80187',
74 'upload_date': '20140402',
75 'timestamp': 1396440000,
78 'skip_download': 'm3u8',
81 'url': 'http://teamcoco.com/video/louis-ck-interview-george-w-bush',
84 'display_id': 'video_louis-ck-interview-george-w-bush',
86 'title': 'Louis C.K. Interview Pt. 1 11/3/11',
87 'description': 'Louis C.K. got starstruck by George W. Bush, so what? Part one.',
88 'thumbnail': 'https://teamcoco.com/image/thumb?id=19705',
89 'upload_date': '20111104',
90 'timestamp': 1320408000,
93 'skip_download': 'm3u8',
96 'url': 'http://teamcoco.com/video/timothy-olyphant-drinking-whiskey',
99 'display_id': 'video_timothy-olyphant-drinking-whiskey',
101 'title': 'Timothy Olyphant Raises A Toast To “Justified”',
102 'description': 'md5:15501f23f020e793aeca761205e42c24',
103 'upload_date': '20150415',
104 'timestamp': 1429099200,
105 'thumbnail': 'https://teamcoco.com/image/thumb?id=88748',
108 'url': 'http://teamcoco.com/video/full-episode-mon-6-1-joel-mchale-jake-tapper-and-musical-guest-courtney-barnett?playlist=x;eyJ0eXBlIjoidGFnIiwiaWQiOjl9',
112 'title': 'Full Episode - Mon. 6/1 - Joel McHale, Jake Tapper, And Musical Guest Courtney Barnett',
113 'description': 'Guests: Joel McHale, Jake Tapper, And Musical Guest Courtney Barnett',
115 'skip': 'This video is no longer available.',
117 'url': 'http://teamcoco.com/video/the-conan-audiencey-awards-for-04/25/18',
118 'only_matching': True,
120 'url': 'http://teamcoco.com/italy/conan-jordan-schlansky-hit-the-streets-of-florence',
121 'only_matching': True,
123 'url': 'http://teamcoco.com/haiti/conan-s-haitian-history-lesson',
124 'only_matching': True,
126 'url': 'http://teamcoco.com/israel/conan-hits-the-streets-beaches-of-tel-aviv',
127 'only_matching': True,
131 def _real_extract(self
, url
):
132 display_id
= self
._match
_id
(url
).replace('/', '_')
133 webpage
= self
._download
_webpage
(url
, display_id
)
134 data
= self
._search
_nextjs
_data
(webpage
, display_id
)['props']['pageProps']['pageData']
135 info
= merge_dicts(*traverse_obj(data
, (
136 'blocks', lambda _
, v
: v
['name'] in ('meta-tags', 'video-player', 'video-info'), 'props', {dict}
)))
138 thumbnail
= traverse_obj(
139 info
, (('image', 'poster'), {lambda x
: urljoin('https://teamcoco.com/', x
)}), get_all
=False)
140 video_id
= traverse_obj(parse_qs(thumbnail
), ('id', 0)) or display_id
142 formats
, subtitles
= self
._get
_formats
_and
_subtitles
(info
, video_id
)
146 'display_id': display_id
,
148 'subtitles': subtitles
,
149 'thumbnail': thumbnail
,
150 **traverse_obj(info
, {
152 'description': (('descriptionHtml', 'description'), {clean_html}
),
153 'timestamp': ('publishedOn', {lambda x
: f
'{x} 12:00AM'}, {unified_timestamp}
),
158 class ConanClassicIE(TeamcocoBaseIE
):
159 _VALID_URL
= r
'https?://(?:(?:www\.)?conanclassic|conan25\.teamcoco)\.com/(?P<id>([^/]+/)*[^/?#]+)'
161 'url': 'https://conanclassic.com/video/ice-cube-kevin-hart-conan-share-lyft',
165 'title': 'Ice Cube, Kevin Hart, & Conan Share A Lyft Car',
166 'display_id': 'video/ice-cube-kevin-hart-conan-share-lyft',
167 'description': 'The stars of "Ride Along" teach Conan how to roll around Hollywood.',
168 'thumbnail': 'http://cdn.teamcococdn.com/image/640x360/lyft-5bd75f82b616c.png',
170 'upload_date': '20131211',
171 'timestamp': 1386721620,
172 '_old_archive_ids': ['teamcoco 74709'],
174 'params': {'skip_download': 'm3u8'},
176 'url': 'https://conan25.teamcoco.com/video/ice-cube-kevin-hart-conan-share-lyft',
177 'only_matching': True,
180 _GRAPHQL_QUERY
= '''query find($id: ID!) {
181 findRecord(id: $id) {
183 ... on MetaInterface {
191 ... on FileInterface {
219 findRecordVideoMetadata(id: $id) {
227 def _real_extract(self
, url
):
228 display_id
= self
._match
_id
(url
)
229 webpage
= self
._download
_webpage
(url
, display_id
)
230 data
= self
._search
_nextjs
_data
(webpage
, display_id
)['props']['pageProps']['pageData']
231 video_id
= traverse_obj(
232 data
, ('blocks', ..., 'props', 'fieldDefs', lambda _
, v
: v
['name'] == 'incomingVideoId', 'value'),
233 ('blocks', ..., 'props', 'fields', 'incomingVideoRecord', 'id'), get_all
=False)
235 self
.raise_no_formats('Unable to extract video ID from webpage', expected
=True)
237 response
= self
._download
_json
(
238 'https://conanclassic.com/api/legacy/graphql', video_id
, data
=json
.dumps({
239 'query': self
._GRAPHQL
_QUERY
,
240 'variables': {'id': video_id
},
241 }, separators
=(',', ':')).encode(), headers
={
242 'Content-Type': 'application/json',
245 info
= traverse_obj(response
, ('data', 'findRecord', {
247 'description': 'teaser',
248 'thumbnail': ('thumb', 'preview', {url_or_none}
),
249 'duration': ('duration', {parse_duration}
),
250 'timestamp': ('publishOn', {unified_timestamp}
),
253 media_id
= traverse_obj(
254 response
, ('data', ('findRecord', 'findRecordVideoMetadata'), 'turnerMediaId'), get_all
=False)
256 token
= traverse_obj(
257 response
, ('data', ('findRecord', 'findRecordVideoMetadata'), 'turnerMediaAuthToken'), get_all
=False)
259 raise ExtractorError('No Turner Media auth token found in API response')
260 self
._initialize
_geo
_bypass
({
263 info
.update(self
._extract
_ngtv
_info
(media_id
, {
264 'accessToken': token
,
265 'accessTokenType': 'jws',
268 formats
, subtitles
= self
._get
_formats
_and
_subtitles
(
269 traverse_obj(response
, ('data', 'findRecordVideoMetadata')), video_id
)
272 'subtitles': subtitles
,
277 'display_id': display_id
,
278 '_old_archive_ids': [make_archive_id('Teamcoco', video_id
)],