def test_make_kodi_url(self): attrs = { 'rating': 'PG', 'obj_type': 'Program', 'description': "Stuff happens", 'episode_no': 1, 'entry_type': 'Episode', 'title': 'Re-Launch', 'season_no': 2, 'series_title': 'New Girl', 'id': '1604589635977', 'thumb': 'https://foo.bar/image.jpg' } expected = ( 'description=Stuff+happens&entry_type=Episode&episode_no=1&id' '=1604589635977&obj_type=Program&rating=PG&season_no=2' '&series_title=New+Girl&thumb=https%3A%2F%2Ffoo.bar%2Fimage.jpg' '&title=Re-Launch') p = classes.Program() attrs = OrderedDict(sorted(attrs.items(), key=lambda x: x[0])) for k, v in attrs.items(): setattr(p, k, v) p.__dict__.pop('date') # do we still need the date attrib? observed = p.make_kodi_url() self.assertEqual(expected, observed)
def test_get_list_title_season(self): p = classes.Program() p.title = 'Foobar' p.season_no = 3 observed = p.get_list_title() expected = 'Foobar - S03' self.assertEqual(expected, observed)
def test_get_list_title_episode(self): p = classes.Program() p.title = 'Foobar' p.episode_no = 10 observed = p.get_list_title() expected = 'Foobar - E10' self.assertEqual(expected, observed)
def test_get_duration_isengard(self, mock_version): mock_version.return_value = 15 p = classes.Program() p.duration = '903' observed = p.get_duration() expected = 903 self.assertEqual(expected, observed)
def test_get_description(self): p = classes.Program() p.description = 'Foo kills Bar' p.expire = datetime(2019, 8, 13) observed = p.get_description() expected = 'Foo kills Bar\n\nExpires: Tue, 13 Aug 2019' self.assertEqual(expected, observed)
def parse_search_results(data): json_data = json.loads(data) show_list = [] for show in json_data['results'].get('items', []): if show.get('_entity') == 'show': s = classes.Series() s.num_episodes = show.get('episodeCount') s.title = show.get('title') additional_title = '' if show.get('status'): additional_title = show['status'].get('title', '').lower() title_match = re.match('^[Ss]eries\\s?(?P<series>\\w+)', additional_title) if title_match: s.title += ' Series ' + title_match.groups()[0] s.url = show.get('_links', '').get('deeplink', '').get('href') elif show.get('_entity') == 'video': s = classes.Program() s.title = show.get('showTitle') s.duration = show.get('duration') s.house_number = show.get('houseNumber') s.url = show.get('_links').get('self').get('href') else: continue s.description = show.get('title') s.thumb = show.get('thumbnail') show_list.append(s) if len(show_list) == 0: s = classes.Series() s.title = 'No results!' s.num_episodes = 0 s.dummy = True show_list.append(s) return show_list
def parse_livestreams_from_feed(data): collection_json_data = json.loads(data)['_embedded'].get('collections') for collection in collection_json_data: if collection.get('title'): if 'watch abc channels live' in collection['title'].lower(): collection_id = collection.get('id') import resources.lib.comm as comm data = comm.fetch_url( config.API_BASE_URL.format( path='/v2/collection/{0}'.format(collection_id))) json_data = json.loads(data) programs_list = [] for item in json_data.get('items'): if item.get('type') != 'livestream': continue p = classes.Program() title = item.get('showTitle') p.title = title p.house_number = item.get('houseNumber') p.description = item.get('description') p.thumb = item.get('thumbnail') p.fanart = item.get('thumbnail') p.url = item['_links']['self'].get('href') p.rating = item.get('classification') p.duration = item.get('duration') p.captions = item.get('captions') p.set_date(item.get('pubDate')) p.set_expire(item.get('expireDate')) programs_list.append(p) return programs_list
def parse_programme_from_feed(data, params): json_data = json.loads(data) show_list = [] for show in json_data.get('items'): if show.get('_entity') == 'show': s = classes.Series() s.num_episodes = show.get('episodeCount') s.title = show.get('title') additional_title = '' if show.get('status'): additional_title = show['status'].get('title', '').lower() title_match = re.match('^[Ss]eries\\s?(?P<series>\\w+)', additional_title) if title_match: s.title += ' Series ' + title_match.groups()[0] s.url = show.get('_links', '').get('deeplink', '').get('href') elif show.get('_entity') == 'video': s = classes.Program() s.title = show.get('showTitle') s.duration = show.get('duration') s.house_number = show.get('houseNumber') s.url = show.get('_links').get('self').get('href') parse_subtitle(s, show) else: continue s.description = show.get('title') s.thumb = show.get('thumbnail') fanart = params.get('fanart') if fanart: s.fanart = params.get('fanart') else: s.fanart = s.thumb show_list.append(s) return show_list
def test_set_datetime_objects(self): expire = '2019-09-12 10:01:36' p = classes.Program() p.set_expire(expire) observed = p.expire expected = datetime(2019, 9, 12, 10, 1, 36) self.assertEqual(expected, observed)
def create_program(entry): p = classes.Program() p.entry_type = entry.get('type') p.id = entry.get('id') if not p.id: p.id = entry.get('pilat', {}).get('id') if p.id: p.id = p.id.split("/")[-1] p.thumb = entry.get('thumbnailUrl') p.outline = entry.get('shortDescription') p.description = entry.get('description') p.duration = entry.get('duration') p.creditsBegin = entry.get('inStreamEvents', {}).get('creditsBegin') p.season_no = entry.get('partOfSeason', {}).get('seasonNumber') p.episode_no = entry.get('episodeNumber') p.pilatDealcode = (entry.get('externalRelations', {}).get('pilat', {}).get('deal', {}).get('id', '').split("/")[-1]) p.rating = entry.get('contentRating', '').upper() p.date = entry.get('publication', {}).get('startDate') p.expire = entry.get('offer', {}).get('availabilityEnds') p.series_title = entry.get('partOfSeries', {}).get('name') titles = entry.get('displayTitles', {}) p.title = titles.get('videoPlayer', {}).get('title') if not p.series_title or not p.title: p.title = entry.get('name') p.series_title = None return p
def test_get_list_title_season_episode_title(self): p = classes.Program() p.series_title = 'Foobar' p.season_no = '3' p.title = 'Revenge of Spam' observed = p.get_list_title() expected = 'Foobar - S03 - Revenge of Spam' self.assertEqual(expected, observed)
def test_get_list_title_season_episode(self): p = classes.Program() p.title = 'Foobar' p.series = '3' p.episode = '10' observed = p.get_list_title() expected = 'Foobar (S03E10)' self.assertEqual(expected, observed)
def parse_programs_from_feed(data, from_series_list=False): json_data = json.loads(data) programs_list = [] serieslist_data = [] fanart = json_data.get('thumbnail') if json_data.get('type') == 'series': item_list = json_data['_embedded']['selectedSeries']['_embedded'].get( 'videoEpisodes') if not item_list: # let's see if there are 'extras' instead item_list = json_data['_embedded']['selectedSeries'][ '_embedded'].get('videoExtras') serieslist_data = json_data['_embedded']['seriesList'] else: item_list = [json_data['_embedded']['highlightVideo']] for item in item_list: p = classes.Program() title = item.get('seriesTitle') if title: p.title = title else: p.title = item.get('title') parse_subtitle(p, item) p.house_number = item.get('houseNumber') p.description = item.get('description') p.thumb = item.get('thumbnail') p.fanart = fanart p.url = item['_links']['self'].get('href') p.rating = item.get('classification') p.duration = item.get('duration') p.captions = item.get('captions') p.set_date(item.get('pubDate')) p.set_expire(item.get('expireDate')) programs_list.append(p) sorted_programs = sorted(programs_list, key=lambda x: x.get_date_time(), reverse=True) if len(serieslist_data) > 1 and not from_series_list: for series in serieslist_data: if series.get('id') == json_data['_embedded'][ 'selectedSeries'].get('id'): continue s = classes.Series() s.title = series.get('title') s.url = series.get('_links', '').get('deeplink', '').get('href') s.description = series.get('description') s.thumb = series.get('thumbnail') s.num_episodes = 0 s.from_serieslist = True s.fanart = fanart sorted_programs.append(s) return sorted_programs
def test_make_kodi_url(self): p = classes.Program() attrs = OrderedDict( sorted(fakes.PROGRAM_ATTRS.items(), key=lambda x: x[0])) for k, v in attrs.items(): setattr(p, k, v) p.__dict__.pop('date') # do we still need the date attrib? observed = p.make_kodi_url() self.assertEqual(fakes.PROGRAM_URL, observed)
def test_parse_kodi_url(self): url = ('date=2019-12-04T10%3A35%3A00Z&description=Stuff+happens' '&entry_type=Episode&episode_no=1&id=1604589635977' '&obj_type=Program&rating=PG&season_no=2' '&series_title=New+Girl&thumb=https%3A%2F%2Ffoo.bar%2Fimage.jpg' '&title=Re-Launch') p = classes.Program() p.parse_kodi_url(url) observed = p.make_kodi_url() self.assertEqual(url, observed)
def test_get_kodi_list_item(self, mock_version): mock_version.return_value = 15 p = classes.Program() p.title = 'Foo' p.episode_title = 'Return of Foo' p.series = '2' p.duration = '100' p.date = datetime(2019, 8, 13, 20, 1, 23) observed = p.get_kodi_list_item() expected = fakes.INFO_DICT self.assertEqual(expected, observed)
def test_get_kodi_list_item(self, mock_version): mock_version.return_value = 15 p = classes.Program() p.title = 'Foo' p.series_title = 'Return of Foo' p.season_no = 2 p.duration = '100' p.date = datetime(2019, 8, 13, 20, 1, 23) observed = p.get_kodi_list_item() expected = { 'tvshowtitle': 'Return of Foo', 'title': 'Return of Foo - S02 - Foo', 'duration': 100, 'year': 2019, 'aired': '2019-08-13', 'season': 2, 'mediatype': 'episode' } self.assertEqual(expected, observed)
def play(url): try: # Remove cookies.dat for Kodi < 17.0 - causes issues with playback addon = xbmcaddon.Addon() cookies_dat = xbmc.translatePath('special://home/cache/cookies.dat') if os.path.isfile(cookies_dat): os.remove(cookies_dat) p = classes.Program() p.parse_kodi_url(url) stream_data = comm.get_stream_url(p.get_house_number(), p.get_url()) stream_url = stream_data.get('stream_url') if not stream_url: utils.log('Not Playable: {0}'.format(repr(stream_data))) raise AussieAddonsException( 'Not available: {0}\n{1}'.format(stream_data.get('msg'), stream_data.get( 'availability'))) use_ia = addon.getSetting('USE_IA') == 'true' if use_ia: if addon.getSetting('IGNORE_DRM') == 'false': try: import drmhelper if not drmhelper.check_inputstream(drm=False): return except ImportError: utils.log("Failed to import drmhelper") utils.dialog_message( 'DRM Helper is needed for inputstream.adaptive ' 'playback. Disable "Use inputstream.adaptive for ' 'playback" in settings or install drmhelper. For ' 'more information, please visit: ' 'http://aussieaddons.com/drm') return hdrs = stream_url[stream_url.find('|') + 1:] listitem = xbmcgui.ListItem(label=p.get_list_title(), path=stream_url) thumb = p.get_thumb() listitem.setArt({'icon': thumb, 'thumb': thumb}) if use_ia: listitem.setProperty('inputstreamaddon', 'inputstream.adaptive') listitem.setProperty('inputstream.adaptive.manifest_type', 'hls') listitem.setProperty('inputstream.adaptive.stream_headers', hdrs) listitem.setProperty('inputstream.adaptive.license_key', stream_url) listitem.setInfo('video', p.get_kodi_list_item()) # Add subtitles if available if p.is_captions(): captions_url = stream_data.get('captions_url') profile = xbmcaddon.Addon().getAddonInfo('profile') path = xbmc.translatePath(profile) if not os.path.isdir(path): os.makedirs(path) caption_file = os.path.join(path, 'subtitles.eng.srt') if os.path.isfile(caption_file): os.remove(caption_file) try: sess = session.Session() webvtt_data = sess.get(captions_url).text if webvtt_data: with io.BytesIO() as buf: webvtt_captions = WebVTTReader().read(webvtt_data) srt_captions = SRTWriter().write(webvtt_captions) srt_unicode = srt_captions.encode('utf-8') buf.write(srt_unicode) with io.open(caption_file, "wb") as f: f.write(buf.getvalue()) if hasattr(listitem, 'setSubtitles'): listitem.setSubtitles([caption_file]) except Exception as e: utils.log( 'Subtitles not available for this program: {0}'.format(e)) if hasattr(listitem, 'addStreamInfo'): listitem.addStreamInfo('audio', p.get_kodi_audio_stream_info()) listitem.addStreamInfo('video', p.get_kodi_video_stream_info()) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem=listitem) except Exception: utils.handle_error('Unable to play video')
def play(url): try: addon = xbmcaddon.Addon() p = classes.Program() p.parse_kodi_url(url) stream_info = comm.get_stream(p.id) if not stream_info: return stream_url = stream_info.get('stream_url') bandwidth = addon.getSetting('BANDWIDTH') if bandwidth == '0': stream_url = stream_url.replace('&b=0-2000', '&b=400-600') elif bandwidth == '1': stream_url = stream_url.replace('&b=0-2000', '&b=900-1100') elif bandwidth == '2': stream_url = stream_url.replace('&b=0-2000', '&b=1400-1600') listitem = comm.create_listitem(label=p.get_list_title(), path=str(stream_url)) listitem.setArt({'icon': p.thumb, 'thumb': p.thumb}) listitem.setInfo('video', p.get_kodi_list_item()) # Add subtitles if available if 'subtitles' in stream_info: sub_url = stream_info['subtitles'] profile = addon.getAddonInfo('profile') path = xbmc.translatePath(profile) if not os.path.isdir(path): os.makedirs(path) subfile = xbmc.translatePath( os.path.join(path, 'subtitles.eng.srt')) if os.path.isfile(subfile): os.remove(subfile) try: sess = session.Session() data = sess.get(sub_url).text f = open(subfile, 'w') f.write(data) f.close() if hasattr(listitem, 'setSubtitles'): # This function only supported from Kodi v14+ listitem.setSubtitles([subfile]) except Exception: utils.log('Subtitles not available for this program') listitem.setProperty('inputstreamaddon', 'inputstream.adaptive') listitem.setProperty('inputstream.adaptive.manifest_type', 'hls') listitem.setProperty('inputstream.adaptive.license_key', stream_url) if hasattr(listitem, 'addStreamInfo'): listitem.addStreamInfo('audio', p.get_kodi_audio_stream_info()) listitem.addStreamInfo('video', p.get_kodi_video_stream_info()) listitem.setProperty('isPlayable', 'true') if utils.get_kodi_major_version() >= 18: listitem.setIsFolder(False) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem=listitem) try: import upnext except Exception as e: utils.log('UpNext addon not installed: %s' % e) return np = comm.get_next_program(p) if not isinstance(np, classes.Program): return next_info = OrderedDict(current_episode=OrderedDict( episodeid=p.id, tvshowid=p.get_tvshowid(), title=p.get_title(), art={ 'thumb': p.get_thumb(), 'tvshow.fanart': p.get_fanart(), }, season=p.get_season_no(), episode=p.get_episode_no(), showtitle=p.get_series_title(), plot=p.get_description(), playcount=0, rating=None, firstaired=p.get_date(), runtime=p.get_duration(), ), next_episode=OrderedDict( episodeid=np.id, tvshowid=np.get_tvshowid(), title=np.get_title(), art={ 'thumb': np.get_thumb(), 'tvshow.fanart': np.get_fanart(), }, season=np.get_season_no(), episode=np.get_episode_no(), showtitle=np.get_series_title(), plot=np.get_description(), playcount=0, rating=None, firstaired=np.get_date(), runtime=np.get_duration(), ), play_url='{0}?{1}'.format( sys.argv[0], np.make_kodi_url()), notification_offset=p.get_credits_time()) upnext.send_signal(xbmcaddon.Addon().getAddonInfo('id'), next_info) except Exception: utils.handle_error("Unable to play video")
def test_parse_kodi_url(self): p = classes.Program() p.parse_kodi_url(fakes.PROGRAM_URL) p.__dict__.pop('date') # do we still need the date attrib? observed = p.make_kodi_url() self.assertEqual(fakes.PROGRAM_URL, observed)
def test_set_datetime_strings(self): expire = '2019-09-12 10:01:36' p = classes.Program() p.set_expire(expire) observed = p.expire self.assertEqual(expire, str(observed))
def test_get_episode_title_blank(self): p = classes.Program() observed = p.get_episode_title() expected = None self.assertEqual(expected, observed)
def test_get_episode_title(self): p = classes.Program() p.episode_title = '<spam&eggs>' observed = p.get_episode_title() expected = '<spam&eggs>' self.assertEqual(expected, observed)
def test_get_date(self): p = classes.Program() p.date = datetime(2019, 8, 13) observed = p.get_date() expected = '2019-08-13' self.assertEqual(expected, observed)
def test_get_date_empty(self): p = classes.Program() date_string = None observed = p.get_date(date_string) self.assertEqual(None, observed)
def test_get_date_as_datetime(self): p = classes.Program() p.date = '2019-12-04T10:35:00Z' observed = p.get_date(as_datetime=True) expected = datetime(2019, 12, 4, 10, 35, 0) self.assertEqual(expected, observed)
def test_get_expire(self): p = classes.Program() p.expire = datetime(2019, 8, 13, 0, 0, 0) observed = p.get_expire() expected = '2019-08-13 00:00:00' self.assertEqual(expected, observed)
def test_get_subfilename(self): p = classes.Program() p.subfilename = 'subtitles_en' observed = p.get_subfilename() expected = 'subtitles_en.SRT' self.assertEqual(expected, observed)