| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | # coding: utf-8 | 
					
						
							|  |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import re | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  | from uuid import uuid4 | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | from .common import InfoExtractor | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  | from ..compat import ( | 
					
						
							|  |  |  |     compat_HTTPError, | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     compat_str, | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  | ) | 
					
						
							|  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     ExtractorError, | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |     int_or_none, | 
					
						
							|  |  |  |     try_get, | 
					
						
							| 
									
										
										
										
											2018-07-21 19:08:28 +07:00
										 |  |  |     url_or_none, | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     urlencode_postdata, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  | class ZattooPlatformBaseIE(InfoExtractor): | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     _power_guide_hash = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     def _host_url(self): | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |         return 'https://%s' % (self._API_HOST if hasattr(self, '_API_HOST') else self._HOST) | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |     def _login(self): | 
					
						
							| 
									
										
										
										
											2018-05-26 16:12:44 +01:00
										 |  |  |         username, password = self._get_login_info() | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         if not username or not password: | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             self.raise_login_required( | 
					
						
							|  |  |  |                 'A valid %s account is needed to access this media.' | 
					
						
							|  |  |  |                 % self._NETRC_MACHINE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             data = self._download_json( | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |                 '%s/zapi/v2/account/login' % self._host_url(), None, 'Logging in', | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |                 data=urlencode_postdata({ | 
					
						
							|  |  |  |                     'login': username, | 
					
						
							|  |  |  |                     'password': password, | 
					
						
							|  |  |  |                     'remember': 'true', | 
					
						
							|  |  |  |                 }), headers={ | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |                     'Referer': '%s/login' % self._host_url(), | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |                     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |         except ExtractorError as e: | 
					
						
							|  |  |  |             if isinstance(e.cause, compat_HTTPError) and e.cause.code == 400: | 
					
						
							|  |  |  |                 raise ExtractorError( | 
					
						
							|  |  |  |                     'Unable to login: incorrect username and/or password', | 
					
						
							|  |  |  |                     expected=True) | 
					
						
							|  |  |  |             raise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._power_guide_hash = data['session']['power_guide_hash'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_initialize(self): | 
					
						
							|  |  |  |         webpage = self._download_webpage( | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |             self._host_url(), None, 'Downloading app token') | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         app_token = self._html_search_regex( | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             r'appToken\s*=\s*(["\'])(?P<token>(?:(?!\1).)+?)\1', | 
					
						
							|  |  |  |             webpage, 'app token', group='token') | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         app_version = self._html_search_regex( | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             r'<!--\w+-(.+?)-', webpage, 'app version', default='2.8.2') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Will setup appropriate cookies | 
					
						
							|  |  |  |         self._request_webpage( | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |             '%s/zapi/v2/session/hello' % self._host_url(), None, | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             'Opening session', data=urlencode_postdata({ | 
					
						
							|  |  |  |                 'client_app_token': app_token, | 
					
						
							|  |  |  |                 'uuid': compat_str(uuid4()), | 
					
						
							|  |  |  |                 'lang': 'en', | 
					
						
							|  |  |  |                 'app_version': app_version, | 
					
						
							|  |  |  |                 'format': 'json', | 
					
						
							|  |  |  |             })) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |         self._login() | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _extract_cid(self, video_id, channel_name): | 
					
						
							|  |  |  |         channel_groups = self._download_json( | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |             '%s/zapi/v2/cached/channels/%s' % (self._host_url(), | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |                                                self._power_guide_hash), | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             video_id, 'Downloading channel list', | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |             query={'details': False})['channel_groups'] | 
					
						
							|  |  |  |         channel_list = [] | 
					
						
							|  |  |  |         for chgrp in channel_groups: | 
					
						
							|  |  |  |             channel_list.extend(chgrp['channels']) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return next( | 
					
						
							|  |  |  |                 chan['cid'] for chan in channel_list | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |                 if chan.get('cid') and ( | 
					
						
							|  |  |  |                     chan.get('display_alias') == channel_name or | 
					
						
							|  |  |  |                     chan.get('cid') == channel_name)) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         except StopIteration: | 
					
						
							|  |  |  |             raise ExtractorError('Could not extract channel id') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _extract_cid_and_video_info(self, video_id): | 
					
						
							|  |  |  |         data = self._download_json( | 
					
						
							| 
									
										
										
										
											2018-09-23 16:34:47 +02:00
										 |  |  |             '%s/zapi/v2/cached/program/power_details/%s' % ( | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |                 self._host_url(), self._power_guide_hash), | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |             video_id, | 
					
						
							|  |  |  |             'Downloading video information', | 
					
						
							|  |  |  |             query={ | 
					
						
							| 
									
										
										
										
											2018-09-23 16:34:47 +02:00
										 |  |  |                 'program_ids': video_id, | 
					
						
							|  |  |  |                 'complete': True, | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 16:34:47 +02:00
										 |  |  |         p = data['programs'][0] | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |         cid = p['cid'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         info_dict = { | 
					
						
							|  |  |  |             'id': video_id, | 
					
						
							| 
									
										
										
										
											2018-09-23 16:34:47 +02:00
										 |  |  |             'title': p.get('t') or p['et'], | 
					
						
							|  |  |  |             'description': p.get('d'), | 
					
						
							|  |  |  |             'thumbnail': p.get('i_url'), | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             'creator': p.get('channel_name'), | 
					
						
							| 
									
										
										
										
											2018-09-23 16:34:47 +02:00
										 |  |  |             'episode': p.get('et'), | 
					
						
							|  |  |  |             'episode_number': int_or_none(p.get('e_no')), | 
					
						
							|  |  |  |             'season_number': int_or_none(p.get('s_no')), | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             'release_year': int_or_none(p.get('year')), | 
					
						
							| 
									
										
										
										
											2018-09-23 16:34:47 +02:00
										 |  |  |             'categories': try_get(p, lambda x: x['c'], list), | 
					
						
							|  |  |  |             'tags': try_get(p, lambda x: x['g'], list) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         return cid, info_dict | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _extract_formats(self, cid, video_id, record_id=None, is_live=False): | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |         postdata_common = { | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |             'https_watch_urls': True, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if is_live: | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |             postdata_common.update({'timeshift': 10800}) | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |             url = '%s/zapi/watch/live/%s' % (self._host_url(), cid) | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |         elif record_id: | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |             url = '%s/zapi/watch/recording/%s' % (self._host_url(), record_id) | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |             url = '%s/zapi/watch/recall/%s/%s' % (self._host_url(), cid, video_id) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         formats = [] | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |         for stream_type in ('dash', 'hls', 'hls5', 'hds'): | 
					
						
							|  |  |  |             postdata = postdata_common.copy() | 
					
						
							|  |  |  |             postdata['stream_type'] = stream_type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             data = self._download_json( | 
					
						
							|  |  |  |                 url, video_id, 'Downloading %s formats' % stream_type.upper(), | 
					
						
							|  |  |  |                 data=urlencode_postdata(postdata), fatal=False) | 
					
						
							|  |  |  |             if not data: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             watch_urls = try_get( | 
					
						
							|  |  |  |                 data, lambda x: x['stream']['watch_urls'], list) | 
					
						
							|  |  |  |             if not watch_urls: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for watch in watch_urls: | 
					
						
							|  |  |  |                 if not isinstance(watch, dict): | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2018-07-21 19:08:28 +07:00
										 |  |  |                 watch_url = url_or_none(watch.get('url')) | 
					
						
							|  |  |  |                 if not watch_url: | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |                     continue | 
					
						
							|  |  |  |                 format_id_list = [stream_type] | 
					
						
							|  |  |  |                 maxrate = watch.get('maxrate') | 
					
						
							|  |  |  |                 if maxrate: | 
					
						
							|  |  |  |                     format_id_list.append(compat_str(maxrate)) | 
					
						
							|  |  |  |                 audio_channel = watch.get('audio_channel') | 
					
						
							|  |  |  |                 if audio_channel: | 
					
						
							|  |  |  |                     format_id_list.append(compat_str(audio_channel)) | 
					
						
							|  |  |  |                 preference = 1 if audio_channel == 'A' else None | 
					
						
							|  |  |  |                 format_id = '-'.join(format_id_list) | 
					
						
							|  |  |  |                 if stream_type in ('dash', 'dash_widevine', 'dash_playready'): | 
					
						
							|  |  |  |                     this_formats = self._extract_mpd_formats( | 
					
						
							|  |  |  |                         watch_url, video_id, mpd_id=format_id, fatal=False) | 
					
						
							|  |  |  |                 elif stream_type in ('hls', 'hls5', 'hls5_fairplay'): | 
					
						
							|  |  |  |                     this_formats = self._extract_m3u8_formats( | 
					
						
							|  |  |  |                         watch_url, video_id, 'mp4', | 
					
						
							|  |  |  |                         entry_protocol='m3u8_native', m3u8_id=format_id, | 
					
						
							|  |  |  |                         fatal=False) | 
					
						
							|  |  |  |                 elif stream_type == 'hds': | 
					
						
							|  |  |  |                     this_formats = self._extract_f4m_formats( | 
					
						
							|  |  |  |                         watch_url, video_id, f4m_id=format_id, fatal=False) | 
					
						
							|  |  |  |                 elif stream_type == 'smooth_playready': | 
					
						
							|  |  |  |                     this_formats = self._extract_ism_formats( | 
					
						
							|  |  |  |                         watch_url, video_id, ism_id=format_id, fatal=False) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     assert False | 
					
						
							|  |  |  |                 for this_format in this_formats: | 
					
						
							|  |  |  |                     this_format['preference'] = preference | 
					
						
							|  |  |  |                 formats.extend(this_formats) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |         self._sort_formats(formats) | 
					
						
							|  |  |  |         return formats | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _extract_video(self, channel_name, video_id, record_id=None, is_live=False): | 
					
						
							|  |  |  |         if is_live: | 
					
						
							|  |  |  |             cid = self._extract_cid(video_id, channel_name) | 
					
						
							|  |  |  |             info_dict = { | 
					
						
							|  |  |  |                 'id': channel_name, | 
					
						
							|  |  |  |                 'title': self._live_title(channel_name), | 
					
						
							|  |  |  |                 'is_live': True, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             cid, info_dict = self._extract_cid_and_video_info(video_id) | 
					
						
							|  |  |  |         formats = self._extract_formats( | 
					
						
							|  |  |  |             cid, video_id, record_id=record_id, is_live=is_live) | 
					
						
							|  |  |  |         info_dict['formats'] = formats | 
					
						
							|  |  |  |         return info_dict | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  | class QuicklineBaseIE(ZattooPlatformBaseIE): | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     _NETRC_MACHINE = 'quickline' | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _HOST = 'mobiltv.quickline.com' | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class QuicklineIE(QuicklineBaseIE): | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = r'https?://(?:www\.)?%s/watch/(?P<channel>[^/]+)/(?P<id>[0-9]+)' % re.escape(QuicklineBaseIE._HOST) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://mobiltv.quickline.com/watch/prosieben/130671867-maze-runner-die-auserwaehlten-in-der-brandwueste', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         channel_name, video_id = re.match(self._VALID_URL, url).groups() | 
					
						
							|  |  |  |         return self._extract_video(channel_name, video_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class QuicklineLiveIE(QuicklineBaseIE): | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = r'https?://(?:www\.)?%s/watch/(?P<id>[^/]+)' % re.escape(QuicklineBaseIE._HOST) | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://mobiltv.quickline.com/watch/srf1', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def suitable(cls, url): | 
					
						
							|  |  |  |         return False if QuicklineIE.suitable(url) else super(QuicklineLiveIE, cls).suitable(url) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         channel_name = video_id = self._match_id(url) | 
					
						
							|  |  |  |         return self._extract_video(channel_name, video_id, is_live=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  | class ZattooBaseIE(ZattooPlatformBaseIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'zattoo' | 
					
						
							|  |  |  |     _HOST = 'zattoo.com' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _make_valid_url(tmpl, host): | 
					
						
							|  |  |  |     return tmpl % re.escape(host) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | class ZattooIE(ZattooBaseIE): | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL_TEMPLATE = r'https?://(?:www\.)?%s/watch/(?P<channel>[^/]+?)/(?P<id>[0-9]+)[^/]+(?:/(?P<recid>[0-9]+))?' | 
					
						
							|  |  |  |     _VALID_URL = _make_valid_url(_VALID_URL_TEMPLATE, ZattooBaseIE._HOST) | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Since regular videos are only available for 7 days and recorded videos | 
					
						
							|  |  |  |     # are only available for a specific user, we cannot have detailed tests. | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://zattoo.com/watch/prosieben/130671867-maze-runner-die-auserwaehlten-in-der-brandwueste', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }, { | 
					
						
							|  |  |  |         'url': 'https://zattoo.com/watch/srf_zwei/132905652-eishockey-spengler-cup/102791477/1512211800000/1514433500000/92000', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         channel_name, video_id, record_id = re.match(self._VALID_URL, url).groups() | 
					
						
							|  |  |  |         return self._extract_video(channel_name, video_id, record_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ZattooLiveIE(ZattooBaseIE): | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |     _VALID_URL = r'https?://(?:www\.)?zattoo\.com/watch/(?P<id>[^/]+)' | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _TEST = { | 
					
						
							|  |  |  |         'url': 'https://zattoo.com/watch/srf1', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 01:48:21 +07:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def suitable(cls, url): | 
					
						
							|  |  |  |         return False if ZattooIE.suitable(url) else super(ZattooLiveIE, cls).suitable(url) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 18:07:35 +01:00
										 |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |         channel_name = video_id = self._match_id(url) | 
					
						
							|  |  |  |         return self._extract_video(channel_name, video_id, is_live=True) | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NetPlusIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'netplus' | 
					
						
							|  |  |  |     _HOST = 'netplus.tv' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.netplus.tv/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MNetTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'mnettv' | 
					
						
							|  |  |  |     _HOST = 'tvplus.m-net.de' | 
					
						
							|  |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |         'url': 'https://tvplus.m-net.de/watch/abc/123-abc', | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class WalyTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'walytv' | 
					
						
							|  |  |  |     _HOST = 'player.waly.tv' | 
					
						
							|  |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |         'url': 'https://player.waly.tv/watch/abc/123-abc', | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BBVTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'bbvtv' | 
					
						
							|  |  |  |     _HOST = 'bbv-tv.net' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.bbv-tv.net/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VTXTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'vtxtv' | 
					
						
							|  |  |  |     _HOST = 'vtxtv.ch' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.vtxtv.ch/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MyVisionTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'myvisiontv' | 
					
						
							|  |  |  |     _HOST = 'myvisiontv.ch' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.myvisiontv.ch/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GlattvisionTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'glattvisiontv' | 
					
						
							|  |  |  |     _HOST = 'iptv.glattvision.ch' | 
					
						
							|  |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |         'url': 'https://iptv.glattvision.ch/watch/abc/123-abc', | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SAKTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'saktv' | 
					
						
							|  |  |  |     _HOST = 'saktv.ch' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.saktv.ch/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EWETVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'ewetv' | 
					
						
							|  |  |  |     _HOST = 'tvonline.ewe.de' | 
					
						
							|  |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |         'url': 'https://tvonline.ewe.de/watch/abc/123-abc', | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class QuantumTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'quantumtv' | 
					
						
							|  |  |  |     _HOST = 'quantum-tv.com' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.quantum-tv.com/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class OsnatelTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'osnateltv' | 
					
						
							| 
									
										
										
										
											2018-11-05 17:09:57 +07:00
										 |  |  |     _HOST = 'tvonline.osnatel.de' | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |         'url': 'https://tvonline.osnatel.de/watch/abc/123-abc', | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EinsUndEinsTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = '1und1tv' | 
					
						
							|  |  |  |     _HOST = '1und1.tv' | 
					
						
							| 
									
										
										
										
											2018-11-05 15:52:46 +07:00
										 |  |  |     _API_HOST = 'www.%s' % _HOST | 
					
						
							| 
									
										
										
										
											2018-09-23 23:30:18 +07:00
										 |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://www.1und1.tv/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] | 
					
						
							| 
									
										
										
										
											2019-01-28 20:20:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SaltTVIE(ZattooIE): | 
					
						
							|  |  |  |     _NETRC_MACHINE = 'salttv' | 
					
						
							|  |  |  |     _HOST = 'tv.salt.ch' | 
					
						
							|  |  |  |     _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |         'url': 'https://tv.salt.ch/watch/abc/123-abc', | 
					
						
							|  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |     }] |