from .common import InfoExtractor from ..utils import ( float_or_none, parse_resolution, traverse_obj, urlencode_postdata, variadic, ) class TubeTuGrazBaseIE(InfoExtractor): _NETRC_MACHINE = 'tubetugraz' _API_EPISODE = 'https://tube.tugraz.at/search/episode.json' _FORMAT_TYPES = ('presentation', 'presenter') def _perform_login(self, username, password): urlh = self._request_webpage( 'https://tube.tugraz.at/Shibboleth.sso/Login?target=/paella/ui/index.html', None, fatal=False, note='downloading login page', errnote='unable to fetch login page') if not urlh: return content, urlh = self._download_webpage_handle( urlh.url, None, fatal=False, headers={'referer': urlh.url}, note='logging in', errnote='unable to log in', data=urlencode_postdata({ 'lang': 'de', '_eventId_proceed': '', 'j_username': username, 'j_password': password })) if not urlh or urlh.url == 'https://tube.tugraz.at/paella/ui/index.html': return if not self._html_search_regex( r'
]*>(Bitte geben Sie einen OTP-Wert ein:)
', content, 'TFA prompt', default=None): self.report_warning('unable to login: incorrect password') return content, urlh = self._download_webpage_handle( urlh.url, None, fatal=False, headers={'referer': urlh.url}, note='logging in with TFA', errnote='unable to log in with TFA', data=urlencode_postdata({ 'lang': 'de', '_eventId_proceed': '', 'j_tokenNumber': self._get_tfa_info(), })) if not urlh or urlh.url == 'https://tube.tugraz.at/paella/ui/index.html': return self.report_warning('unable to login: incorrect TFA code') def _extract_episode(self, episode_info): id = episode_info.get('id') formats = list(self._extract_formats( traverse_obj(episode_info, ('mediapackage', 'media', 'track')), id)) title = traverse_obj(episode_info, ('mediapackage', 'title'), 'dcTitle') series_title = traverse_obj(episode_info, ('mediapackage', 'seriestitle')) creator = ', '.join(variadic(traverse_obj( episode_info, ('mediapackage', 'creators', 'creator'), 'dcCreator', default=''))) return { 'id': id, 'title': title, 'creator': creator or None, 'duration': traverse_obj(episode_info, ('mediapackage', 'duration'), 'dcExtent'), 'series': series_title, 'series_id': traverse_obj(episode_info, ('mediapackage', 'series'), 'dcIsPartOf'), 'episode': series_title and title, 'formats': formats } def _set_format_type(self, formats, type): for f in formats: f['format_note'] = type if not type.startswith(self._FORMAT_TYPES[0]): f['preference'] = -2 return formats def _extract_formats(self, format_list, id): has_hls, has_dash = False, False for format_info in format_list or []: url = traverse_obj(format_info, ('tags', 'url'), 'url') if url is None: continue type = format_info.get('type') or 'unknown' transport = (format_info.get('transport') or 'https').lower() if transport == 'https': formats = [{ 'url': url, 'abr': float_or_none(traverse_obj(format_info, ('audio', 'bitrate')), 1000), 'vbr': float_or_none(traverse_obj(format_info, ('video', 'bitrate')), 1000), 'fps': traverse_obj(format_info, ('video', 'framerate')), **parse_resolution(traverse_obj(format_info, ('video', 'resolution'))), }] elif transport == 'hls': has_hls, formats = True, self._extract_m3u8_formats( url, id, 'mp4', fatal=False, note=f'downloading {type} HLS manifest') elif transport == 'dash': has_dash, formats = True, self._extract_mpd_formats( url, id, fatal=False, note=f'downloading {type} DASH manifest') else: # RTMP, HDS, SMOOTH, and unknown formats # - RTMP url fails on every tested entry until now # - HDS url 404's on every tested entry until now # - SMOOTH url 404's on every tested entry until now continue yield from self._set_format_type(formats, type) # TODO: Add test for these for type in self._FORMAT_TYPES: if not has_hls: hls_formats = self._extract_m3u8_formats( f'https://wowza.tugraz.at/matterhorn_engage/smil:engage-player_{id}_{type}.smil/playlist.m3u8', id, 'mp4', fatal=False, note=f'Downloading {type} HLS manifest', errnote=False) or [] yield from self._set_format_type(hls_formats, type) if not has_dash: dash_formats = self._extract_mpd_formats( f'https://wowza.tugraz.at/matterhorn_engage/smil:engage-player_{id}_{type}.smil/manifest_mpm4sav_mvlist.mpd', id, fatal=False, note=f'Downloading {type} DASH manifest', errnote=False) yield from self._set_format_type(dash_formats, type) class TubeTuGrazIE(TubeTuGrazBaseIE): IE_DESC = 'tube.tugraz.at' _VALID_URL = r'''(?x) https?://tube\.tugraz\.at/paella/ui/watch.html\?id= (?P