]>
Commit | Line | Data |
---|---|---|
940b606a | 1 | # coding: utf-8 |
4cd759f7 JMF |
2 | from __future__ import unicode_literals |
3 | ||
bc2ca1bb | 4 | import json |
5118d2ec | 5 | import uuid |
4cd759f7 JMF |
6 | |
7 | from .common import InfoExtractor | |
0b98f3a7 | 8 | from ..compat import compat_HTTPError |
5448b781 | 9 | from ..utils import ( |
864a4576 | 10 | determine_ext, |
0cf2352e | 11 | ExtractorError, |
864a4576 | 12 | float_or_none, |
5448b781 | 13 | int_or_none, |
bc2ca1bb | 14 | strip_or_none, |
5118d2ec | 15 | try_get, |
864a4576 | 16 | unified_timestamp, |
5448b781 | 17 | ) |
940b606a | 18 | |
4cd759f7 | 19 | |
5118d2ec | 20 | class DPlayBaseIE(InfoExtractor): |
bc2ca1bb | 21 | _PATH_REGEX = r'/(?P<id>[^/]+/[^/?#]+)' |
5118d2ec AG |
22 | _auth_token_cache = {} |
23 | ||
24 | def _get_auth(self, disco_base, display_id, realm, needs_device_id=True): | |
25 | key = (disco_base, realm) | |
26 | st = self._get_cookies(disco_base).get('st') | |
27 | token = (st and st.value) or self._auth_token_cache.get(key) | |
28 | ||
29 | if not token: | |
30 | query = {'realm': realm} | |
31 | if needs_device_id: | |
32 | query['deviceId'] = uuid.uuid4().hex | |
33 | token = self._download_json( | |
34 | disco_base + 'token', display_id, 'Downloading token', | |
35 | query=query)['data']['attributes']['token'] | |
36 | ||
37 | # Save cache only if cookies are not being set | |
38 | if not self._get_cookies(disco_base).get('st'): | |
39 | self._auth_token_cache[key] = token | |
40 | ||
41 | return f'Bearer {token}' | |
42 | ||
43 | def _process_errors(self, e, geo_countries): | |
44 | info = self._parse_json(e.cause.read().decode('utf-8'), None) | |
45 | error = info['errors'][0] | |
46 | error_code = error.get('code') | |
47 | if error_code == 'access.denied.geoblocked': | |
48 | self.raise_geo_restricted(countries=geo_countries) | |
49 | elif error_code in ('access.denied.missingpackage', 'invalid.token'): | |
50 | raise ExtractorError( | |
51 | 'This video is only available for registered users. You may want to use --cookies.', expected=True) | |
52 | raise ExtractorError(info['errors'][0]['detail'], expected=True) | |
53 | ||
54 | def _update_disco_api_headers(self, headers, disco_base, display_id, realm): | |
55 | headers['Authorization'] = self._get_auth(disco_base, display_id, realm, False) | |
56 | ||
57 | def _download_video_playback_info(self, disco_base, video_id, headers): | |
58 | streaming = self._download_json( | |
59 | disco_base + 'playback/videoPlaybackInfo/' + video_id, | |
60 | video_id, headers=headers)['data']['attributes']['streaming'] | |
61 | streaming_list = [] | |
62 | for format_id, format_dict in streaming.items(): | |
63 | streaming_list.append({ | |
64 | 'type': format_id, | |
65 | 'url': format_dict.get('url'), | |
66 | }) | |
67 | return streaming_list | |
68 | ||
69 | def _get_disco_api_info(self, url, display_id, disco_host, realm, country, domain=''): | |
70 | geo_countries = [country.upper()] | |
71 | self._initialize_geo_bypass({ | |
72 | 'countries': geo_countries, | |
73 | }) | |
74 | disco_base = 'https://%s/' % disco_host | |
75 | headers = { | |
76 | 'Referer': url, | |
77 | } | |
78 | self._update_disco_api_headers(headers, disco_base, display_id, realm) | |
79 | try: | |
80 | video = self._download_json( | |
81 | disco_base + 'content/videos/' + display_id, display_id, | |
82 | headers=headers, query={ | |
83 | 'fields[channel]': 'name', | |
84 | 'fields[image]': 'height,src,width', | |
85 | 'fields[show]': 'name', | |
86 | 'fields[tag]': 'name', | |
87 | 'fields[video]': 'description,episodeNumber,name,publishStart,seasonNumber,videoDuration', | |
88 | 'include': 'images,primaryChannel,show,tags' | |
89 | }) | |
90 | except ExtractorError as e: | |
91 | if isinstance(e.cause, compat_HTTPError) and e.cause.code == 400: | |
92 | self._process_errors(e, geo_countries) | |
93 | raise | |
94 | video_id = video['data']['id'] | |
95 | info = video['data']['attributes'] | |
96 | title = info['name'].strip() | |
97 | formats = [] | |
98 | subtitles = {} | |
99 | try: | |
100 | streaming = self._download_video_playback_info( | |
101 | disco_base, video_id, headers) | |
102 | except ExtractorError as e: | |
103 | if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403: | |
104 | self._process_errors(e, geo_countries) | |
105 | raise | |
106 | for format_dict in streaming: | |
107 | if not isinstance(format_dict, dict): | |
108 | continue | |
109 | format_url = format_dict.get('url') | |
110 | if not format_url: | |
111 | continue | |
112 | format_id = format_dict.get('type') | |
113 | ext = determine_ext(format_url) | |
114 | if format_id == 'dash' or ext == 'mpd': | |
115 | dash_fmts, dash_subs = self._extract_mpd_formats_and_subtitles( | |
116 | format_url, display_id, mpd_id='dash', fatal=False) | |
117 | formats.extend(dash_fmts) | |
118 | subtitles = self._merge_subtitles(subtitles, dash_subs) | |
119 | elif format_id == 'hls' or ext == 'm3u8': | |
120 | m3u8_fmts, m3u8_subs = self._extract_m3u8_formats_and_subtitles( | |
121 | format_url, display_id, 'mp4', | |
122 | entry_protocol='m3u8_native', m3u8_id='hls', | |
123 | fatal=False) | |
124 | formats.extend(m3u8_fmts) | |
125 | subtitles = self._merge_subtitles(subtitles, m3u8_subs) | |
126 | else: | |
127 | formats.append({ | |
128 | 'url': format_url, | |
129 | 'format_id': format_id, | |
130 | }) | |
131 | self._sort_formats(formats) | |
132 | ||
133 | creator = series = None | |
134 | tags = [] | |
135 | thumbnails = [] | |
136 | included = video.get('included') or [] | |
137 | if isinstance(included, list): | |
138 | for e in included: | |
139 | attributes = e.get('attributes') | |
140 | if not attributes: | |
141 | continue | |
142 | e_type = e.get('type') | |
143 | if e_type == 'channel': | |
144 | creator = attributes.get('name') | |
145 | elif e_type == 'image': | |
146 | src = attributes.get('src') | |
147 | if src: | |
148 | thumbnails.append({ | |
149 | 'url': src, | |
150 | 'width': int_or_none(attributes.get('width')), | |
151 | 'height': int_or_none(attributes.get('height')), | |
152 | }) | |
153 | if e_type == 'show': | |
154 | series = attributes.get('name') | |
155 | elif e_type == 'tag': | |
156 | name = attributes.get('name') | |
157 | if name: | |
158 | tags.append(name) | |
159 | return { | |
160 | 'id': video_id, | |
161 | 'display_id': display_id, | |
162 | 'title': title, | |
163 | 'description': strip_or_none(info.get('description')), | |
164 | 'duration': float_or_none(info.get('videoDuration'), 1000), | |
165 | 'timestamp': unified_timestamp(info.get('publishStart')), | |
166 | 'series': series, | |
167 | 'season_number': int_or_none(info.get('seasonNumber')), | |
168 | 'episode_number': int_or_none(info.get('episodeNumber')), | |
169 | 'creator': creator, | |
170 | 'tags': tags, | |
171 | 'thumbnails': thumbnails, | |
172 | 'formats': formats, | |
173 | 'subtitles': subtitles, | |
174 | 'http_headers': { | |
175 | 'referer': domain, | |
176 | }, | |
177 | } | |
178 | ||
179 | ||
180 | class DPlayIE(DPlayBaseIE): | |
0b98f3a7 RA |
181 | _VALID_URL = r'''(?x)https?:// |
182 | (?P<domain> | |
00dd0cd5 | 183 | (?:www\.)?(?P<host>d |
184 | (?: | |
185 | play\.(?P<country>dk|fi|jp|se|no)| | |
186 | iscoveryplus\.(?P<plus_country>dk|es|fi|it|se|no) | |
187 | ) | |
188 | )| | |
0b98f3a7 | 189 | (?P<subdomain_country>es|it)\.dplay\.com |
5118d2ec | 190 | )/[^/]+''' + DPlayBaseIE._PATH_REGEX |
95050537 | 191 | |
940b606a | 192 | _TESTS = [{ |
5448b781 | 193 | # non geo restricted, via secure api, unsigned download hls URL |
0b98f3a7 | 194 | 'url': 'https://www.dplay.se/videos/nugammalt-77-handelser-som-format-sverige/nugammalt-77-handelser-som-format-sverige-101', |
940b606a | 195 | 'info_dict': { |
0b98f3a7 RA |
196 | 'id': '13628', |
197 | 'display_id': 'nugammalt-77-handelser-som-format-sverige/nugammalt-77-handelser-som-format-sverige-101', | |
5448b781 | 198 | 'ext': 'mp4', |
940b606a S |
199 | 'title': 'Svensken lär sig njuta av livet', |
200 | 'description': 'md5:d3819c9bccffd0fe458ca42451dd50d8', | |
0b98f3a7 RA |
201 | 'duration': 2649.856, |
202 | 'timestamp': 1365453720, | |
940b606a | 203 | 'upload_date': '20130408', |
0b98f3a7 | 204 | 'creator': 'Kanal 5', |
940b606a S |
205 | 'series': 'Nugammalt - 77 händelser som format Sverige', |
206 | 'season_number': 1, | |
207 | 'episode_number': 1, | |
0b98f3a7 RA |
208 | }, |
209 | 'params': { | |
0b98f3a7 | 210 | 'skip_download': True, |
95050537 | 211 | }, |
940b606a | 212 | }, { |
5448b781 | 213 | # geo restricted, via secure api, unsigned download hls URL |
0b98f3a7 | 214 | 'url': 'http://www.dplay.dk/videoer/ted-bundy-mind-of-a-monster/ted-bundy-mind-of-a-monster', |
940b606a | 215 | 'info_dict': { |
0b98f3a7 RA |
216 | 'id': '104465', |
217 | 'display_id': 'ted-bundy-mind-of-a-monster/ted-bundy-mind-of-a-monster', | |
5448b781 | 218 | 'ext': 'mp4', |
0b98f3a7 RA |
219 | 'title': 'Ted Bundy: Mind Of A Monster', |
220 | 'description': 'md5:8b780f6f18de4dae631668b8a9637995', | |
221 | 'duration': 5290.027, | |
222 | 'timestamp': 1570694400, | |
223 | 'upload_date': '20191010', | |
224 | 'creator': 'ID - Investigation Discovery', | |
225 | 'series': 'Ted Bundy: Mind Of A Monster', | |
226 | 'season_number': 1, | |
227 | 'episode_number': 1, | |
228 | }, | |
229 | 'params': { | |
0b98f3a7 | 230 | 'skip_download': True, |
940b606a | 231 | }, |
864a4576 S |
232 | }, { |
233 | # disco-api | |
234 | 'url': 'https://www.dplay.no/videoer/i-kongens-klr/sesong-1-episode-7', | |
235 | 'info_dict': { | |
236 | 'id': '40206', | |
237 | 'display_id': 'i-kongens-klr/sesong-1-episode-7', | |
238 | 'ext': 'mp4', | |
239 | 'title': 'Episode 7', | |
240 | 'description': 'md5:e3e1411b2b9aebeea36a6ec5d50c60cf', | |
241 | 'duration': 2611.16, | |
242 | 'timestamp': 1516726800, | |
243 | 'upload_date': '20180123', | |
244 | 'series': 'I kongens klær', | |
245 | 'season_number': 1, | |
246 | 'episode_number': 7, | |
247 | }, | |
248 | 'params': { | |
864a4576 S |
249 | 'skip_download': True, |
250 | }, | |
0b98f3a7 | 251 | 'skip': 'Available for Premium users', |
a0ee342b | 252 | }, { |
0b98f3a7 RA |
253 | 'url': 'http://it.dplay.com/nove/biografie-imbarazzanti/luigi-di-maio-la-psicosi-di-stanislawskij/', |
254 | 'md5': '2b808ffb00fc47b884a172ca5d13053c', | |
255 | 'info_dict': { | |
256 | 'id': '6918', | |
257 | 'display_id': 'biografie-imbarazzanti/luigi-di-maio-la-psicosi-di-stanislawskij', | |
258 | 'ext': 'mp4', | |
259 | 'title': 'Luigi Di Maio: la psicosi di Stanislawskij', | |
260 | 'description': 'md5:3c7a4303aef85868f867a26f5cc14813', | |
261 | 'thumbnail': r're:^https?://.*\.jpe?g', | |
262 | 'upload_date': '20160524', | |
263 | 'timestamp': 1464076800, | |
264 | 'series': 'Biografie imbarazzanti', | |
265 | 'season_number': 1, | |
266 | 'episode': 'Episode 1', | |
267 | 'episode_number': 1, | |
268 | }, | |
269 | }, { | |
270 | 'url': 'https://es.dplay.com/dmax/la-fiebre-del-oro/temporada-8-episodio-1/', | |
271 | 'info_dict': { | |
272 | 'id': '21652', | |
273 | 'display_id': 'la-fiebre-del-oro/temporada-8-episodio-1', | |
274 | 'ext': 'mp4', | |
275 | 'title': 'Episodio 1', | |
276 | 'description': 'md5:b9dcff2071086e003737485210675f69', | |
277 | 'thumbnail': r're:^https?://.*\.png', | |
278 | 'upload_date': '20180709', | |
279 | 'timestamp': 1531173540, | |
280 | 'series': 'La fiebre del oro', | |
281 | 'season_number': 8, | |
282 | 'episode': 'Episode 1', | |
283 | 'episode_number': 1, | |
284 | }, | |
285 | 'params': { | |
286 | 'skip_download': True, | |
287 | }, | |
288 | }, { | |
289 | 'url': 'https://www.dplay.fi/videot/shifting-gears-with-aaron-kaufman/episode-16', | |
a0ee342b | 290 | 'only_matching': True, |
d6b15291 | 291 | }, { |
0b98f3a7 | 292 | 'url': 'https://www.dplay.jp/video/gold-rush/24086', |
d6b15291 | 293 | 'only_matching': True, |
00dd0cd5 | 294 | }, { |
295 | 'url': 'https://www.discoveryplus.se/videos/nugammalt-77-handelser-som-format-sverige/nugammalt-77-handelser-som-format-sverige-101', | |
296 | 'only_matching': True, | |
297 | }, { | |
298 | 'url': 'https://www.discoveryplus.dk/videoer/ted-bundy-mind-of-a-monster/ted-bundy-mind-of-a-monster', | |
299 | 'only_matching': True, | |
300 | }, { | |
301 | 'url': 'https://www.discoveryplus.no/videoer/i-kongens-klr/sesong-1-episode-7', | |
302 | 'only_matching': True, | |
303 | }, { | |
304 | 'url': 'https://www.discoveryplus.it/videos/biografie-imbarazzanti/luigi-di-maio-la-psicosi-di-stanislawskij', | |
305 | 'only_matching': True, | |
306 | }, { | |
307 | 'url': 'https://www.discoveryplus.es/videos/la-fiebre-del-oro/temporada-8-episodio-1', | |
308 | 'only_matching': True, | |
309 | }, { | |
310 | 'url': 'https://www.discoveryplus.fi/videot/shifting-gears-with-aaron-kaufman/episode-16', | |
311 | 'only_matching': True, | |
940b606a | 312 | }] |
4cd759f7 JMF |
313 | |
314 | def _real_extract(self, url): | |
5ad28e7f | 315 | mobj = self._match_valid_url(url) |
940b606a | 316 | display_id = mobj.group('id') |
0b98f3a7 | 317 | domain = mobj.group('domain').lstrip('www.') |
00dd0cd5 | 318 | country = mobj.group('country') or mobj.group('subdomain_country') or mobj.group('plus_country') |
319 | host = 'disco-api.' + domain if domain[0] == 'd' else 'eu2-prod.disco-api.com' | |
0b98f3a7 | 320 | return self._get_disco_api_info( |
5118d2ec | 321 | url, display_id, host, 'dplay' + country, country, domain) |
bc2ca1bb | 322 | |
323 | ||
5118d2ec AG |
324 | class HGTVDeIE(DPlayBaseIE): |
325 | _VALID_URL = r'https?://de\.hgtv\.com/sendungen' + DPlayBaseIE._PATH_REGEX | |
45d1f157 S |
326 | _TESTS = [{ |
327 | 'url': 'https://de.hgtv.com/sendungen/tiny-house-klein-aber-oho/wer-braucht-schon-eine-toilette/', | |
328 | 'info_dict': { | |
329 | 'id': '151205', | |
330 | 'display_id': 'tiny-house-klein-aber-oho/wer-braucht-schon-eine-toilette', | |
331 | 'ext': 'mp4', | |
332 | 'title': 'Wer braucht schon eine Toilette', | |
333 | 'description': 'md5:05b40a27e7aed2c9172de34d459134e2', | |
334 | 'duration': 1177.024, | |
335 | 'timestamp': 1595705400, | |
336 | 'upload_date': '20200725', | |
337 | 'creator': 'HGTV', | |
338 | 'series': 'Tiny House - klein, aber oho', | |
339 | 'season_number': 3, | |
340 | 'episode_number': 3, | |
341 | }, | |
45d1f157 S |
342 | }] |
343 | ||
344 | def _real_extract(self, url): | |
345 | display_id = self._match_id(url) | |
346 | return self._get_disco_api_info( | |
347 | url, display_id, 'eu1-prod.disco-api.com', 'hgtv', 'de') | |
348 | ||
349 | ||
0bb5ac1a | 350 | class DiscoveryPlusBaseIE(DPlayBaseIE): |
bc2ca1bb | 351 | def _update_disco_api_headers(self, headers, disco_base, display_id, realm): |
c12977bd | 352 | headers['x-disco-client'] = f'WEB:UNKNOWN:{self._PRODUCT}:25.2.6' |
bc2ca1bb | 353 | |
354 | def _download_video_playback_info(self, disco_base, video_id, headers): | |
355 | return self._download_json( | |
356 | disco_base + 'playback/v3/videoPlaybackInfo', | |
357 | video_id, headers=headers, data=json.dumps({ | |
358 | 'deviceInfo': { | |
359 | 'adBlocker': False, | |
360 | }, | |
361 | 'videoId': video_id, | |
362 | 'wisteriaProperties': { | |
363 | 'platform': 'desktop', | |
45d1f157 | 364 | 'product': self._PRODUCT, |
bc2ca1bb | 365 | }, |
366 | }).encode('utf-8'))['data']['attributes']['streaming'] | |
367 | ||
368 | def _real_extract(self, url): | |
0bb5ac1a | 369 | return self._get_disco_api_info(url, self._match_id(url), **self._DISCO_API_PARAMS) |
bc2ca1bb | 370 | |
371 | ||
7df07a3b S |
372 | class GoDiscoveryIE(DiscoveryPlusBaseIE): |
373 | _VALID_URL = r'https?://(?:go\.)?discovery\.com/video' + DPlayBaseIE._PATH_REGEX | |
374 | _TESTS = [{ | |
375 | 'url': 'https://go.discovery.com/video/dirty-jobs-discovery-atve-us/rodbuster-galvanizer', | |
376 | 'info_dict': { | |
377 | 'id': '4164906', | |
378 | 'display_id': 'dirty-jobs-discovery-atve-us/rodbuster-galvanizer', | |
379 | 'ext': 'mp4', | |
380 | 'title': 'Rodbuster / Galvanizer', | |
381 | 'description': 'Mike installs rebar with a team of rodbusters, then he galvanizes steel.', | |
382 | 'season_number': 9, | |
383 | 'episode_number': 1, | |
384 | }, | |
385 | 'skip': 'Available for Premium users', | |
386 | }, { | |
387 | 'url': 'https://discovery.com/video/dirty-jobs-discovery-atve-us/rodbuster-galvanizer', | |
388 | 'only_matching': True, | |
389 | }] | |
390 | ||
391 | _PRODUCT = 'dsc' | |
392 | _DISCO_API_PARAMS = { | |
393 | 'disco_host': 'us1-prod-direct.go.discovery.com', | |
394 | 'realm': 'go', | |
395 | 'country': 'us', | |
396 | } | |
397 | ||
398 | ||
399 | class TravelChannelIE(DiscoveryPlusBaseIE): | |
400 | _VALID_URL = r'https?://(?:watch\.)?travelchannel\.com/video' + DPlayBaseIE._PATH_REGEX | |
401 | _TESTS = [{ | |
402 | 'url': 'https://watch.travelchannel.com/video/ghost-adventures-travel-channel/ghost-train-of-ely', | |
403 | 'info_dict': { | |
404 | 'id': '2220256', | |
405 | 'display_id': 'ghost-adventures-travel-channel/ghost-train-of-ely', | |
406 | 'ext': 'mp4', | |
407 | 'title': 'Ghost Train of Ely', | |
408 | 'description': 'The crew investigates the dark history of the Nevada Northern Railway.', | |
409 | 'season_number': 24, | |
410 | 'episode_number': 1, | |
411 | }, | |
412 | 'skip': 'Available for Premium users', | |
413 | }, { | |
414 | 'url': 'https://watch.travelchannel.com/video/ghost-adventures-travel-channel/ghost-train-of-ely', | |
415 | 'only_matching': True, | |
416 | }] | |
417 | ||
418 | _PRODUCT = 'trav' | |
419 | _DISCO_API_PARAMS = { | |
420 | 'disco_host': 'us1-prod-direct.watch.travelchannel.com', | |
421 | 'realm': 'go', | |
422 | 'country': 'us', | |
423 | } | |
424 | ||
425 | ||
426 | class CookingChannelIE(DiscoveryPlusBaseIE): | |
427 | _VALID_URL = r'https?://(?:watch\.)?cookingchanneltv\.com/video' + DPlayBaseIE._PATH_REGEX | |
428 | _TESTS = [{ | |
429 | 'url': 'https://watch.cookingchanneltv.com/video/carnival-eats-cooking-channel/the-postman-always-brings-rice-2348634', | |
430 | 'info_dict': { | |
431 | 'id': '2348634', | |
432 | 'display_id': 'carnival-eats-cooking-channel/the-postman-always-brings-rice-2348634', | |
433 | 'ext': 'mp4', | |
434 | 'title': 'The Postman Always Brings Rice', | |
435 | 'description': 'Noah visits the Maui Fair and the Aurora Winter Festival in Vancouver.', | |
436 | 'season_number': 9, | |
437 | 'episode_number': 1, | |
438 | }, | |
439 | 'skip': 'Available for Premium users', | |
440 | }, { | |
441 | 'url': 'https://watch.cookingchanneltv.com/video/carnival-eats-cooking-channel/the-postman-always-brings-rice-2348634', | |
442 | 'only_matching': True, | |
443 | }] | |
444 | ||
445 | _PRODUCT = 'cook' | |
446 | _DISCO_API_PARAMS = { | |
447 | 'disco_host': 'us1-prod-direct.watch.cookingchanneltv.com', | |
448 | 'realm': 'go', | |
449 | 'country': 'us', | |
450 | } | |
451 | ||
452 | ||
453 | class HGTVUsaIE(DiscoveryPlusBaseIE): | |
454 | _VALID_URL = r'https?://(?:watch\.)?hgtv\.com/video' + DPlayBaseIE._PATH_REGEX | |
455 | _TESTS = [{ | |
456 | 'url': 'https://watch.hgtv.com/video/home-inspector-joe-hgtv-atve-us/this-mold-house', | |
457 | 'info_dict': { | |
458 | 'id': '4289736', | |
459 | 'display_id': 'home-inspector-joe-hgtv-atve-us/this-mold-house', | |
460 | 'ext': 'mp4', | |
461 | 'title': 'This Mold House', | |
462 | 'description': 'Joe and Noel help take a familys dream home from hazardous to fabulous.', | |
463 | 'season_number': 1, | |
464 | 'episode_number': 1, | |
465 | }, | |
466 | 'skip': 'Available for Premium users', | |
467 | }, { | |
468 | 'url': 'https://watch.hgtv.com/video/home-inspector-joe-hgtv-atve-us/this-mold-house', | |
469 | 'only_matching': True, | |
470 | }] | |
471 | ||
472 | _PRODUCT = 'hgtv' | |
473 | _DISCO_API_PARAMS = { | |
474 | 'disco_host': 'us1-prod-direct.watch.hgtv.com', | |
475 | 'realm': 'go', | |
476 | 'country': 'us', | |
477 | } | |
478 | ||
479 | ||
480 | class FoodNetworkIE(DiscoveryPlusBaseIE): | |
481 | _VALID_URL = r'https?://(?:watch\.)?foodnetwork\.com/video' + DPlayBaseIE._PATH_REGEX | |
482 | _TESTS = [{ | |
483 | 'url': 'https://watch.foodnetwork.com/video/kids-baking-championship-food-network/float-like-a-butterfly', | |
484 | 'info_dict': { | |
485 | 'id': '4116449', | |
486 | 'display_id': 'kids-baking-championship-food-network/float-like-a-butterfly', | |
487 | 'ext': 'mp4', | |
488 | 'title': 'Float Like a Butterfly', | |
489 | 'description': 'The 12 kid bakers create colorful carved butterfly cakes.', | |
490 | 'season_number': 10, | |
491 | 'episode_number': 1, | |
492 | }, | |
493 | 'skip': 'Available for Premium users', | |
494 | }, { | |
495 | 'url': 'https://watch.foodnetwork.com/video/kids-baking-championship-food-network/float-like-a-butterfly', | |
496 | 'only_matching': True, | |
497 | }] | |
498 | ||
499 | _PRODUCT = 'food' | |
500 | _DISCO_API_PARAMS = { | |
501 | 'disco_host': 'us1-prod-direct.watch.foodnetwork.com', | |
502 | 'realm': 'go', | |
503 | 'country': 'us', | |
504 | } | |
505 | ||
506 | ||
507 | class DestinationAmericaIE(DiscoveryPlusBaseIE): | |
508 | _VALID_URL = r'https?://(?:www\.)?destinationamerica\.com/video' + DPlayBaseIE._PATH_REGEX | |
509 | _TESTS = [{ | |
510 | 'url': 'https://www.destinationamerica.com/video/alaska-monsters-destination-america-atve-us/central-alaskas-bigfoot', | |
511 | 'info_dict': { | |
512 | 'id': '4210904', | |
513 | 'display_id': 'alaska-monsters-destination-america-atve-us/central-alaskas-bigfoot', | |
514 | 'ext': 'mp4', | |
515 | 'title': 'Central Alaskas Bigfoot', | |
516 | 'description': 'A team heads to central Alaska to investigate an aggressive Bigfoot.', | |
517 | 'season_number': 1, | |
518 | 'episode_number': 1, | |
519 | }, | |
520 | 'skip': 'Available for Premium users', | |
521 | }, { | |
522 | 'url': 'https://www.destinationamerica.com/video/alaska-monsters-destination-america-atve-us/central-alaskas-bigfoot', | |
523 | 'only_matching': True, | |
524 | }] | |
525 | ||
526 | _PRODUCT = 'dam' | |
527 | _DISCO_API_PARAMS = { | |
528 | 'disco_host': 'us1-prod-direct.destinationamerica.com', | |
529 | 'realm': 'go', | |
530 | 'country': 'us', | |
531 | } | |
532 | ||
533 | ||
534 | class InvestigationDiscoveryIE(DiscoveryPlusBaseIE): | |
535 | _VALID_URL = r'https?://(?:www\.)?investigationdiscovery\.com/video' + DPlayBaseIE._PATH_REGEX | |
536 | _TESTS = [{ | |
537 | 'url': 'https://www.investigationdiscovery.com/video/unmasked-investigation-discovery/the-killer-clown', | |
538 | 'info_dict': { | |
539 | 'id': '2139409', | |
540 | 'display_id': 'unmasked-investigation-discovery/the-killer-clown', | |
541 | 'ext': 'mp4', | |
542 | 'title': 'The Killer Clown', | |
543 | 'description': 'A wealthy Florida woman is fatally shot in the face by a clown at her door.', | |
544 | 'season_number': 1, | |
545 | 'episode_number': 1, | |
546 | }, | |
547 | 'skip': 'Available for Premium users', | |
548 | }, { | |
549 | 'url': 'https://www.investigationdiscovery.com/video/unmasked-investigation-discovery/the-killer-clown', | |
550 | 'only_matching': True, | |
551 | }] | |
552 | ||
553 | _PRODUCT = 'ids' | |
554 | _DISCO_API_PARAMS = { | |
555 | 'disco_host': 'us1-prod-direct.investigationdiscovery.com', | |
556 | 'realm': 'go', | |
557 | 'country': 'us', | |
558 | } | |
559 | ||
560 | ||
561 | class AmHistoryChannelIE(DiscoveryPlusBaseIE): | |
562 | _VALID_URL = r'https?://(?:www\.)?ahctv\.com/video' + DPlayBaseIE._PATH_REGEX | |
563 | _TESTS = [{ | |
564 | 'url': 'https://www.ahctv.com/video/modern-sniper-ahc/army', | |
565 | 'info_dict': { | |
566 | 'id': '2309730', | |
567 | 'display_id': 'modern-sniper-ahc/army', | |
568 | 'ext': 'mp4', | |
569 | 'title': 'Army', | |
570 | 'description': 'Snipers today face challenges their predecessors couldve only dreamed of.', | |
571 | 'season_number': 1, | |
572 | 'episode_number': 1, | |
573 | }, | |
574 | 'skip': 'Available for Premium users', | |
575 | }, { | |
576 | 'url': 'https://www.ahctv.com/video/modern-sniper-ahc/army', | |
577 | 'only_matching': True, | |
578 | }] | |
579 | ||
580 | _PRODUCT = 'ahc' | |
581 | _DISCO_API_PARAMS = { | |
582 | 'disco_host': 'us1-prod-direct.ahctv.com', | |
583 | 'realm': 'go', | |
584 | 'country': 'us', | |
585 | } | |
586 | ||
587 | ||
0bb5ac1a | 588 | class ScienceChannelIE(DiscoveryPlusBaseIE): |
5118d2ec | 589 | _VALID_URL = r'https?://(?:www\.)?sciencechannel\.com/video' + DPlayBaseIE._PATH_REGEX |
bc2ca1bb | 590 | _TESTS = [{ |
45d1f157 | 591 | 'url': 'https://www.sciencechannel.com/video/strangest-things-science-atve-us/nazi-mystery-machine', |
bc2ca1bb | 592 | 'info_dict': { |
45d1f157 S |
593 | 'id': '2842849', |
594 | 'display_id': 'strangest-things-science-atve-us/nazi-mystery-machine', | |
bc2ca1bb | 595 | 'ext': 'mp4', |
45d1f157 S |
596 | 'title': 'Nazi Mystery Machine', |
597 | 'description': 'Experts investigate the secrets of a revolutionary encryption machine.', | |
598 | 'season_number': 1, | |
599 | 'episode_number': 1, | |
bc2ca1bb | 600 | }, |
45d1f157 | 601 | 'skip': 'Available for Premium users', |
7df07a3b S |
602 | }, { |
603 | 'url': 'https://www.sciencechannel.com/video/strangest-things-science-atve-us/nazi-mystery-machine', | |
604 | 'only_matching': True, | |
bc2ca1bb | 605 | }] |
606 | ||
45d1f157 | 607 | _PRODUCT = 'sci' |
0bb5ac1a | 608 | _DISCO_API_PARAMS = { |
609 | 'disco_host': 'us1-prod-direct.sciencechannel.com', | |
610 | 'realm': 'go', | |
611 | 'country': 'us', | |
612 | } | |
b5a39ed4 S |
613 | |
614 | ||
0bb5ac1a | 615 | class DIYNetworkIE(DiscoveryPlusBaseIE): |
5118d2ec | 616 | _VALID_URL = r'https?://(?:watch\.)?diynetwork\.com/video' + DPlayBaseIE._PATH_REGEX |
b5a39ed4 S |
617 | _TESTS = [{ |
618 | 'url': 'https://watch.diynetwork.com/video/pool-kings-diy-network/bringing-beach-life-to-texas', | |
619 | 'info_dict': { | |
620 | 'id': '2309730', | |
621 | 'display_id': 'pool-kings-diy-network/bringing-beach-life-to-texas', | |
622 | 'ext': 'mp4', | |
623 | 'title': 'Bringing Beach Life to Texas', | |
624 | 'description': 'The Pool Kings give a family a day at the beach in their own backyard.', | |
625 | 'season_number': 10, | |
626 | 'episode_number': 2, | |
627 | }, | |
628 | 'skip': 'Available for Premium users', | |
7df07a3b S |
629 | }, { |
630 | 'url': 'https://watch.diynetwork.com/video/pool-kings-diy-network/bringing-beach-life-to-texas', | |
631 | 'only_matching': True, | |
b5a39ed4 S |
632 | }] |
633 | ||
634 | _PRODUCT = 'diy' | |
0bb5ac1a | 635 | _DISCO_API_PARAMS = { |
636 | 'disco_host': 'us1-prod-direct.watch.diynetwork.com', | |
637 | 'realm': 'go', | |
638 | 'country': 'us', | |
639 | } | |
c12977bd S |
640 | |
641 | ||
7df07a3b S |
642 | class DiscoveryLifeIE(DiscoveryPlusBaseIE): |
643 | _VALID_URL = r'https?://(?:www\.)?discoverylife\.com/video' + DPlayBaseIE._PATH_REGEX | |
644 | _TESTS = [{ | |
645 | 'url': 'https://www.discoverylife.com/video/surviving-death-discovery-life-atve-us/bodily-trauma', | |
646 | 'info_dict': { | |
647 | 'id': '2218238', | |
648 | 'display_id': 'surviving-death-discovery-life-atve-us/bodily-trauma', | |
649 | 'ext': 'mp4', | |
650 | 'title': 'Bodily Trauma', | |
651 | 'description': 'Meet three people who tested the limits of the human body.', | |
652 | 'season_number': 1, | |
653 | 'episode_number': 2, | |
654 | }, | |
655 | 'skip': 'Available for Premium users', | |
656 | }, { | |
657 | 'url': 'https://www.discoverylife.com/video/surviving-death-discovery-life-atve-us/bodily-trauma', | |
658 | 'only_matching': True, | |
659 | }] | |
660 | ||
661 | _PRODUCT = 'dlf' | |
662 | _DISCO_API_PARAMS = { | |
663 | 'disco_host': 'us1-prod-direct.discoverylife.com', | |
664 | 'realm': 'go', | |
665 | 'country': 'us', | |
666 | } | |
667 | ||
668 | ||
0bb5ac1a | 669 | class AnimalPlanetIE(DiscoveryPlusBaseIE): |
5118d2ec | 670 | _VALID_URL = r'https?://(?:www\.)?animalplanet\.com/video' + DPlayBaseIE._PATH_REGEX |
c12977bd S |
671 | _TESTS = [{ |
672 | 'url': 'https://www.animalplanet.com/video/north-woods-law-animal-planet/squirrel-showdown', | |
673 | 'info_dict': { | |
674 | 'id': '3338923', | |
675 | 'display_id': 'north-woods-law-animal-planet/squirrel-showdown', | |
676 | 'ext': 'mp4', | |
677 | 'title': 'Squirrel Showdown', | |
678 | 'description': 'A woman is suspected of being in possession of flying squirrel kits.', | |
679 | 'season_number': 16, | |
680 | 'episode_number': 11, | |
681 | }, | |
682 | 'skip': 'Available for Premium users', | |
7df07a3b S |
683 | }, { |
684 | 'url': 'https://www.animalplanet.com/video/north-woods-law-animal-planet/squirrel-showdown', | |
685 | 'only_matching': True, | |
c12977bd S |
686 | }] |
687 | ||
688 | _PRODUCT = 'apl' | |
0bb5ac1a | 689 | _DISCO_API_PARAMS = { |
690 | 'disco_host': 'us1-prod-direct.animalplanet.com', | |
691 | 'realm': 'go', | |
692 | 'country': 'us', | |
693 | } | |
694 | ||
695 | ||
7df07a3b S |
696 | class TLCIE(DiscoveryPlusBaseIE): |
697 | _VALID_URL = r'https?://(?:go\.)?tlc\.com/video' + DPlayBaseIE._PATH_REGEX | |
698 | _TESTS = [{ | |
699 | 'url': 'https://go.tlc.com/video/my-600-lb-life-tlc/melissas-story-part-1', | |
700 | 'info_dict': { | |
701 | 'id': '2206540', | |
702 | 'display_id': 'my-600-lb-life-tlc/melissas-story-part-1', | |
703 | 'ext': 'mp4', | |
704 | 'title': 'Melissas Story (Part 1)', | |
705 | 'description': 'At 650 lbs, Melissa is ready to begin her seven-year weight loss journey.', | |
706 | 'season_number': 1, | |
707 | 'episode_number': 1, | |
708 | }, | |
709 | 'skip': 'Available for Premium users', | |
710 | }, { | |
711 | 'url': 'https://go.tlc.com/video/my-600-lb-life-tlc/melissas-story-part-1', | |
712 | 'only_matching': True, | |
713 | }] | |
714 | ||
715 | _PRODUCT = 'tlc' | |
716 | _DISCO_API_PARAMS = { | |
717 | 'disco_host': 'us1-prod-direct.tlc.com', | |
718 | 'realm': 'go', | |
719 | 'country': 'us', | |
720 | } | |
721 | ||
722 | ||
0bb5ac1a | 723 | class DiscoveryPlusIE(DiscoveryPlusBaseIE): |
724 | _VALID_URL = r'https?://(?:www\.)?discoveryplus\.com/(?!it/)(?:\w{2}/)?video' + DPlayBaseIE._PATH_REGEX | |
725 | _TESTS = [{ | |
726 | 'url': 'https://www.discoveryplus.com/video/property-brothers-forever-home/food-and-family', | |
727 | 'info_dict': { | |
728 | 'id': '1140794', | |
729 | 'display_id': 'property-brothers-forever-home/food-and-family', | |
730 | 'ext': 'mp4', | |
731 | 'title': 'Food and Family', | |
732 | 'description': 'The brothers help a Richmond family expand their single-level home.', | |
733 | 'duration': 2583.113, | |
734 | 'timestamp': 1609304400, | |
735 | 'upload_date': '20201230', | |
736 | 'creator': 'HGTV', | |
737 | 'series': 'Property Brothers: Forever Home', | |
738 | 'season_number': 1, | |
739 | 'episode_number': 1, | |
740 | }, | |
741 | 'skip': 'Available for Premium users', | |
742 | }, { | |
743 | 'url': 'https://discoveryplus.com/ca/video/bering-sea-gold-discovery-ca/goldslingers', | |
744 | 'only_matching': True, | |
745 | }] | |
746 | ||
747 | _PRODUCT = 'dplus_us' | |
748 | _DISCO_API_PARAMS = { | |
749 | 'disco_host': 'us1-prod-direct.discoveryplus.com', | |
750 | 'realm': 'go', | |
751 | 'country': 'us', | |
752 | } | |
5118d2ec AG |
753 | |
754 | ||
0bb5ac1a | 755 | class DiscoveryPlusIndiaIE(DiscoveryPlusBaseIE): |
5118d2ec AG |
756 | _VALID_URL = r'https?://(?:www\.)?discoveryplus\.in/videos?' + DPlayBaseIE._PATH_REGEX |
757 | _TESTS = [{ | |
758 | 'url': 'https://www.discoveryplus.in/videos/how-do-they-do-it/fugu-and-more?seasonId=8&type=EPISODE', | |
759 | 'info_dict': { | |
760 | 'id': '27104', | |
761 | 'ext': 'mp4', | |
762 | 'display_id': 'how-do-they-do-it/fugu-and-more', | |
763 | 'title': 'Fugu and More', | |
764 | 'description': 'The Japanese catch, prepare and eat the deadliest fish on the planet.', | |
0bb5ac1a | 765 | 'duration': 1319.32, |
5118d2ec AG |
766 | 'timestamp': 1582309800, |
767 | 'upload_date': '20200221', | |
768 | 'series': 'How Do They Do It?', | |
769 | 'season_number': 8, | |
770 | 'episode_number': 2, | |
771 | 'creator': 'Discovery Channel', | |
0bb5ac1a | 772 | 'thumbnail': r're:https://.+\.jpeg', |
773 | 'episode': 'Episode 2', | |
774 | 'season': 'Season 8', | |
775 | 'tags': [], | |
5118d2ec AG |
776 | }, |
777 | 'params': { | |
778 | 'skip_download': True, | |
779 | } | |
780 | }] | |
781 | ||
0bb5ac1a | 782 | _PRODUCT = 'dplus-india' |
783 | _DISCO_API_PARAMS = { | |
784 | 'disco_host': 'ap2-prod-direct.discoveryplus.in', | |
785 | 'realm': 'dplusindia', | |
786 | 'country': 'in', | |
787 | 'domain': 'https://www.discoveryplus.in/', | |
788 | } | |
789 | ||
5118d2ec AG |
790 | def _update_disco_api_headers(self, headers, disco_base, display_id, realm): |
791 | headers.update({ | |
792 | 'x-disco-params': 'realm=%s' % realm, | |
0bb5ac1a | 793 | 'x-disco-client': f'WEB:UNKNOWN:{self._PRODUCT}:17.0.0', |
5118d2ec AG |
794 | 'Authorization': self._get_auth(disco_base, display_id, realm), |
795 | }) | |
796 | ||
5118d2ec AG |
797 | |
798 | class DiscoveryNetworksDeIE(DPlayBaseIE): | |
799 | _VALID_URL = r'https?://(?:www\.)?(?P<domain>(?:tlc|dmax)\.de|dplay\.co\.uk)/(?:programme|show|sendungen)/(?P<programme>[^/]+)/(?:video/)?(?P<alternate_id>[^/]+)' | |
800 | ||
801 | _TESTS = [{ | |
802 | 'url': 'https://www.tlc.de/programme/breaking-amish/video/die-welt-da-drauen/DCB331270001100', | |
803 | 'info_dict': { | |
804 | 'id': '78867', | |
805 | 'ext': 'mp4', | |
806 | 'title': 'Die Welt da draußen', | |
807 | 'description': 'md5:61033c12b73286e409d99a41742ef608', | |
808 | 'timestamp': 1554069600, | |
809 | 'upload_date': '20190331', | |
0bb5ac1a | 810 | 'creator': 'TLC', |
811 | 'season': 'Season 1', | |
812 | 'series': 'Breaking Amish', | |
813 | 'episode_number': 1, | |
814 | 'tags': ['new york', 'großstadt', 'amische', 'landleben', 'modern', 'infos', 'tradition', 'herausforderung'], | |
815 | 'display_id': 'breaking-amish/die-welt-da-drauen', | |
816 | 'episode': 'Episode 1', | |
817 | 'duration': 2625.024, | |
818 | 'season_number': 1, | |
819 | 'thumbnail': r're:https://.+\.jpg', | |
5118d2ec AG |
820 | }, |
821 | 'params': { | |
822 | 'skip_download': True, | |
823 | }, | |
824 | }, { | |
825 | 'url': 'https://www.dmax.de/programme/dmax-highlights/video/tuning-star-sidney-hoffmann-exklusiv-bei-dmax/191023082312316', | |
826 | 'only_matching': True, | |
827 | }, { | |
828 | 'url': 'https://www.dplay.co.uk/show/ghost-adventures/video/hotel-leger-103620/EHD_280313B', | |
829 | 'only_matching': True, | |
830 | }, { | |
831 | 'url': 'https://tlc.de/sendungen/breaking-amish/die-welt-da-drauen/', | |
832 | 'only_matching': True, | |
833 | }] | |
834 | ||
835 | def _real_extract(self, url): | |
836 | domain, programme, alternate_id = self._match_valid_url(url).groups() | |
837 | country = 'GB' if domain == 'dplay.co.uk' else 'DE' | |
838 | realm = 'questuk' if country == 'GB' else domain.replace('.', '') | |
839 | return self._get_disco_api_info( | |
840 | url, '%s/%s' % (programme, alternate_id), | |
841 | 'sonic-eu1-prod.disco-api.com', realm, country) | |
842 | ||
843 | ||
844 | class DiscoveryPlusShowBaseIE(DPlayBaseIE): | |
845 | ||
846 | def _entries(self, show_name): | |
847 | headers = { | |
848 | 'x-disco-client': self._X_CLIENT, | |
849 | 'x-disco-params': f'realm={self._REALM}', | |
850 | 'referer': self._DOMAIN, | |
851 | 'Authentication': self._get_auth(self._BASE_API, None, self._REALM), | |
852 | } | |
853 | show_json = self._download_json( | |
854 | f'{self._BASE_API}cms/routes/{self._SHOW_STR}/{show_name}?include=default', | |
855 | video_id=show_name, headers=headers)['included'][self._INDEX]['attributes']['component'] | |
856 | show_id = show_json['mandatoryParams'].split('=')[-1] | |
857 | season_url = self._BASE_API + 'content/videos?sort=episodeNumber&filter[seasonNumber]={}&filter[show.id]={}&page[size]=100&page[number]={}' | |
858 | for season in show_json['filters'][0]['options']: | |
859 | season_id = season['id'] | |
860 | total_pages, page_num = 1, 0 | |
861 | while page_num < total_pages: | |
862 | season_json = self._download_json( | |
863 | season_url.format(season_id, show_id, str(page_num + 1)), show_name, headers=headers, | |
864 | note='Downloading season %s JSON metadata%s' % (season_id, ' page %d' % page_num if page_num else '')) | |
865 | if page_num == 0: | |
866 | total_pages = try_get(season_json, lambda x: x['meta']['totalPages'], int) or 1 | |
867 | episodes_json = season_json['data'] | |
868 | for episode in episodes_json: | |
86f3d52f | 869 | video_path = episode['attributes']['path'] |
5118d2ec | 870 | yield self.url_result( |
86f3d52f AG |
871 | '%svideos/%s' % (self._DOMAIN, video_path), |
872 | ie=self._VIDEO_IE.ie_key(), video_id=episode.get('id') or video_path) | |
5118d2ec AG |
873 | page_num += 1 |
874 | ||
875 | def _real_extract(self, url): | |
876 | show_name = self._match_valid_url(url).group('show_name') | |
877 | return self.playlist_result(self._entries(show_name), playlist_id=show_name) | |
878 | ||
879 | ||
0bb5ac1a | 880 | class DiscoveryPlusItalyIE(DiscoveryPlusBaseIE): |
0f86a1cd | 881 | _VALID_URL = r'https?://(?:www\.)?discoveryplus\.com/it/video' + DPlayBaseIE._PATH_REGEX |
882 | _TESTS = [{ | |
883 | 'url': 'https://www.discoveryplus.com/it/video/i-signori-della-neve/stagione-2-episodio-1-i-preparativi', | |
884 | 'only_matching': True, | |
885 | }] | |
886 | ||
0bb5ac1a | 887 | _PRODUCT = 'dplus_us' |
888 | _DISCO_API_PARAMS = { | |
889 | 'disco_host': 'eu1-prod-direct.discoveryplus.com', | |
890 | 'realm': 'dplay', | |
891 | 'country': 'it', | |
892 | } | |
0f86a1cd | 893 | |
894 | ||
5118d2ec AG |
895 | class DiscoveryPlusItalyShowIE(DiscoveryPlusShowBaseIE): |
896 | _VALID_URL = r'https?://(?:www\.)?discoveryplus\.it/programmi/(?P<show_name>[^/]+)/?(?:[?#]|$)' | |
897 | _TESTS = [{ | |
898 | 'url': 'https://www.discoveryplus.it/programmi/deal-with-it-stai-al-gioco', | |
899 | 'playlist_mincount': 168, | |
900 | 'info_dict': { | |
901 | 'id': 'deal-with-it-stai-al-gioco', | |
902 | }, | |
903 | }] | |
904 | ||
905 | _BASE_API = 'https://disco-api.discoveryplus.it/' | |
906 | _DOMAIN = 'https://www.discoveryplus.it/' | |
907 | _X_CLIENT = 'WEB:UNKNOWN:dplay-client:2.6.0' | |
908 | _REALM = 'dplayit' | |
909 | _SHOW_STR = 'programmi' | |
910 | _INDEX = 1 | |
911 | _VIDEO_IE = DPlayIE | |
912 | ||
913 | ||
914 | class DiscoveryPlusIndiaShowIE(DiscoveryPlusShowBaseIE): | |
915 | _VALID_URL = r'https?://(?:www\.)?discoveryplus\.in/show/(?P<show_name>[^/]+)/?(?:[?#]|$)' | |
916 | _TESTS = [{ | |
917 | 'url': 'https://www.discoveryplus.in/show/how-do-they-do-it', | |
918 | 'playlist_mincount': 140, | |
919 | 'info_dict': { | |
920 | 'id': 'how-do-they-do-it', | |
921 | }, | |
922 | }] | |
923 | ||
924 | _BASE_API = 'https://ap2-prod-direct.discoveryplus.in/' | |
925 | _DOMAIN = 'https://www.discoveryplus.in/' | |
926 | _X_CLIENT = 'WEB:UNKNOWN:dplus-india:prod' | |
927 | _REALM = 'dplusindia' | |
928 | _SHOW_STR = 'show' | |
929 | _INDEX = 4 | |
930 | _VIDEO_IE = DiscoveryPlusIndiaIE |