class TestAuth(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestAuth, self).__init__(*args, **kwargs) self._auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path()) def test_login(self): # Clear any cache we have self._auth.clear_cache() # We should get a token by logging in token = self._auth.get_token() self.assertTrue(token) # Test it a second time, it should go from memory now token = self._auth.get_token() self.assertTrue(token)
class TestApi(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestApi, self).__init__(*args, **kwargs) self._auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path()) def test_notifications(self): api = ContentApi(self._auth.get_token()) notifications = api.get_notifications() self.assertIsInstance(notifications, list) def test_programs(self): api = ContentApi(self._auth.get_token()) for channel in ['vier', 'vijf', 'zes']: channels = api.get_programs(channel) self.assertIsInstance(channels, list) def test_episodes(self): api = ContentApi(self._auth.get_token()) for channel, program in [('vier', 'auwch'), ('vijf', 'zo-man-zo-vrouw')]: program = api.get_program(channel, program) self.assertIsInstance(program, Program) self.assertIsInstance(program.seasons, dict) # self.assertIsInstance(program.seasons[0], Season) self.assertIsInstance(program.episodes, list) self.assertIsInstance(program.episodes[0], Episode) _LOGGER.info('Got program: %s', program) def test_get_stream(self): api = ContentApi(self._auth.get_token()) program = api.get_program('vier', 'auwch') episode = program.episodes[0] video = api.get_stream(episode.channel, episode.uuid) self.assertTrue(video) _LOGGER.info('Got video URL: %s', video)
class TestEpg(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestEpg, self).__init__(*args, **kwargs) self._auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path()) def test_vier_today(self): epg = EpgApi() programs = epg.get_epg('vier', date.today().strftime('%Y-%m-%d')) self.assertIsInstance(programs, list) self.assertIsInstance(programs[0], EpgProgram) def test_vijf_today(self): epg = EpgApi() programs = epg.get_epg('vijf', date.today().strftime('%Y-%m-%d')) self.assertIsInstance(programs, list) self.assertIsInstance(programs[0], EpgProgram) def test_zes_today(self): epg = EpgApi() programs = epg.get_epg('zes', date.today().strftime('%Y-%m-%d')) self.assertIsInstance(programs, list) self.assertIsInstance(programs[0], EpgProgram) def test_unknown_today(self): epg = EpgApi() with self.assertRaises(Exception): epg.get_epg('vtm', date.today().strftime('%Y-%m-%d')) def test_vier_out_of_range(self): epg = EpgApi() programs = epg.get_epg('vier', '2020-01-01') self.assertEqual(programs, []) 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 Catalog: """ Menu code related to the catalog """ 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()) self._menu = Menu() def show_catalog(self): """ Show all the programs of all channels """ try: items = [] for channel in list(CHANNELS): items.extend(self._api.get_programs(channel)) except Exception as ex: kodiutils.notification(message=str(ex)) raise listing = [self._menu.generate_titleitem(item) for item in items] # Sort items by label, but don't put folders at the top. # Used for A-Z listing or when movies and episodes are mixed. kodiutils.show_listing(listing, 30003, content='tvshows', sort='label') def show_catalog_channel(self, channel): """ Show the programs of a specific channel :type channel: str """ try: items = self._api.get_programs(channel) except Exception as ex: kodiutils.notification(message=str(ex)) raise listing = [] for item in items: listing.append(self._menu.generate_titleitem(item)) # Sort items by label, but don't put folders at the top. # Used for A-Z listing or when movies and episodes are mixed. kodiutils.show_listing(listing, 30003, content='tvshows', sort='label') def show_program(self, channel, program_id): """ Show a program from the catalog :type channel: str :type program_id: str """ try: program = self._api.get_program(channel, program_id) except UnavailableException: kodiutils.ok_dialog( message=kodiutils.localize(30717) ) # This program is not available in the Vier/Vijf/Zes catalogue. kodiutils.end_of_directory() return if not program.episodes: kodiutils.ok_dialog( message=kodiutils.localize(30717) ) # This program is not available in the Vier/Vijf/Zes catalogue. kodiutils.end_of_directory() return # Go directly to the season when we have only one season if len(program.seasons) == 1: self.show_program_season(channel, program_id, program.seasons.values()[0].number) return studio = CHANNELS.get(program.channel, {}).get('studio_icon') listing = [] # Add an '* All seasons' entry when configured in Kodi if kodiutils.get_global_setting('videolibrary.showallitems') is True: listing.append( TitleItem( title='* %s' % kodiutils.localize(30204), # * All seasons path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=-1), art_dict={ 'thumb': program.cover, 'fanart': program.background, }, info_dict={ 'tvshowtitle': program.title, 'title': kodiutils.localize(30204), # All seasons 'plot': program.description, 'set': program.title, 'studio': studio, })) # Add the seasons for s in list(program.seasons.values()): listing.append( TitleItem( title=s. title, # kodiutils.localize(30205, season=s.number), # Season {season} path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=s.number), art_dict={ 'thumb': s.cover, 'fanart': program.background, }, info_dict={ 'tvshowtitle': program.title, 'title': kodiutils.localize(30205, season=s.number), # Season {season} 'plot': s.description, 'set': program.title, 'studio': studio, })) # Sort by label. Some programs return seasons unordered. kodiutils.show_listing(listing, 30003, content='tvshows', sort=['label']) def show_program_season(self, channel, program_id, season): """ Show the episodes of a program from the catalog :type channel: str :type program_id: str :type season: int """ try: program = self._api.get_program(channel, program_id) except UnavailableException: kodiutils.ok_dialog( message=kodiutils.localize(30717) ) # This program is not available in the Vier/Vijf/Zes catalogue. kodiutils.end_of_directory() return if season == -1: # Show all episodes episodes = program.episodes else: # Show the episodes of the season that was selected episodes = [e for e in program.episodes if e.season == season] listing = [ self._menu.generate_titleitem(episode) for episode in episodes ] # Sort by episode number by default. Takes seasons into account. kodiutils.show_listing(listing, 30003, content='episodes', sort=['episode', 'duration'])