def test_play_video_from_epg(self): epg = EpgApi() epg_programs = epg.get_epg('vier', date.today().strftime('%Y-%m-%d')) epg_program = [program for program in epg_programs if program.video_url][0] # Lookup the Episode data since we don't have an UUID api = ContentApi(self._auth.get_token()) episode = api.get_episode(epg_program.channel, epg_program.video_url) self.assertIsInstance(episode, Episode) # Get stream based on the Episode's UUID video = api.get_stream(episode.channel, episode.uuid) self.assertTrue(video)
class Player: """ Code responsible for playing media """ def __init__(self): """ Initialise object """ self._auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path()) self._api = ContentApi(self._auth.get_token()) def play_from_page(self, channel, path): """ Play the requested item. :type channel: string :type path: string """ # Get episode information episode = self._api.get_episode(channel, path) # Play this now we have the uuid self.play(channel, episode.uuid) def play(self, channel, item): """ Play the requested item. :type channel: string :type item: string """ try: # Get stream information resolved_stream = self._api.get_stream(channel, item) except GeoblockedException: kodiutils.ok_dialog(heading=kodiutils.localize(30709), message=kodiutils.localize(30710)) # This video is geo-blocked... return except UnavailableException: kodiutils.ok_dialog(heading=kodiutils.localize(30711), message=kodiutils.localize(30712)) # The video is unavailable... return # Play this item kodiutils.play(resolved_stream)
class Player: """ Code responsible for playing media """ def __init__(self): """ Initialise object """ auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path()) self._api = ContentApi(auth, cache_path=kodiutils.get_cache_path()) # Workaround for Raspberry Pi 3 and older kodiutils.set_global_setting('videoplayer.useomxplayer', True) @staticmethod def live(channel): """ Play the live channel. :type channel: string """ # TODO: this doesn't work correctly, playing a live program from the PVR won't play something from the beginning # Lookup current program # broadcast = self._epg.get_broadcast(channel, datetime.datetime.now().isoformat()) # if broadcast and broadcast.video_url: # self.play_from_page(broadcast.video_url) # return channel_name = CHANNELS.get(channel, dict(name=channel)) kodiutils.ok_dialog(message=kodiutils.localize(30718, channel=channel_name.get('name'))) # There is no live stream available for {channel}. kodiutils.end_of_directory() def play_from_page(self, path): """ Play the requested item. :type path: string """ if not path: kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable... return # Get episode information episode = self._api.get_episode(path, cache=CACHE_PREVENT) resolved_stream = None if episode is None: kodiutils.ok_dialog(message=kodiutils.localize(30712)) return if episode.stream: # We already have a resolved stream. Nice! # We don't need credentials for these streams. resolved_stream = ResolvedStream( uuid=episode.uuid, url=episode.stream, ) _LOGGER.debug('Already got a resolved stream: %s', resolved_stream) if episode.uuid: # Lookup the stream resolved_stream = self._resolve_stream(episode.uuid) _LOGGER.debug('Resolved stream: %s', resolved_stream) if resolved_stream: titleitem = Menu.generate_titleitem(episode) if resolved_stream.license_url: # Generate license key license_key = self.create_license_key(resolved_stream.license_url, key_headers=dict( customdata=resolved_stream.auth, )) else: license_key = None kodiutils.play(resolved_stream.url, resolved_stream.stream_type, license_key, info_dict=titleitem.info_dict, art_dict=titleitem.art_dict, prop_dict=titleitem.prop_dict) def play(self, uuid): """ Play the requested item. :type uuid: string """ if not uuid: kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable... return # Lookup the stream resolved_stream = self._resolve_stream(uuid) if resolved_stream.license_url: # Generate license key license_key = self.create_license_key(resolved_stream.license_url, key_headers=dict( customdata=resolved_stream.auth, )) else: license_key = None kodiutils.play(resolved_stream.url, resolved_stream.stream_type, license_key) @staticmethod def _resolve_stream(uuid): """ Resolve the stream for the requested item :type uuid: string """ try: # Check if we have credentials if not kodiutils.get_setting('username') or not kodiutils.get_setting('password'): confirm = kodiutils.yesno_dialog( message=kodiutils.localize(30701)) # To watch a video, you need to enter your credentials. Do you want to enter them now? if confirm: kodiutils.open_settings() kodiutils.end_of_directory() return None # Fetch an auth token now try: auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path()) # Get stream information resolved_stream = ContentApi(auth).get_stream_by_uuid(uuid) return resolved_stream except (InvalidLoginException, AuthenticationException) as ex: _LOGGER.exception(ex) kodiutils.ok_dialog(message=kodiutils.localize(30702, error=str(ex))) kodiutils.end_of_directory() return None except GeoblockedException: kodiutils.ok_dialog(message=kodiutils.localize(30710)) # This video is geo-blocked... return None except UnavailableException: kodiutils.ok_dialog(message=kodiutils.localize(30712)) # The video is unavailable... return None @staticmethod def create_license_key(key_url, key_type='R', key_headers=None, key_value=None): """ Create a license key string that we need for inputstream.adaptive. :param str key_url: :param str key_type: :param dict[str, str] key_headers: :param str key_value: :rtype: str """ header = '' if key_headers: header = urlencode(key_headers) if key_type in ('A', 'R', 'B'): key_value = key_type + '{SSM}' elif key_type == 'D': if 'D{SSM}' not in key_value: raise ValueError('Missing D{SSM} placeholder') key_value = quote(key_value) return '%s|%s|%s|' % (key_url, header, key_value)