def mylist_removed(video_type, content_id): """ Something has been removed from My List. We want to de-index this. """ if video_type == CONTENT_TYPE_MOVIE: if kodiutils.get_setting_int('library_movies') != LIBRARY_ONLY_MYLIST: return Library().clean('plugin://plugin.video.streamz/library/movies/?movie=%s' % content_id) elif video_type == CONTENT_TYPE_PROGRAM: if kodiutils.get_setting_int('library_tvshows') != LIBRARY_ONLY_MYLIST: return Library().clean('plugin://plugin.video.streamz/library/tvshows/?program=%s' % content_id)
def mylist_added(video_type, content_id): """ Something has been added to My List. We want to index this. """ if video_type == CONTENT_TYPE_MOVIE: if kodiutils.get_setting_int('library_movies') != LIBRARY_ONLY_MYLIST: return # This unfortunately adds the movie to the database with the wrong parent path: # Library().update('plugin://plugin.video.streamz/library/movies/?movie=%s&kodi_action=refresh_info' % content_id) Library().update('plugin://plugin.video.streamz/library/movies/') elif video_type == CONTENT_TYPE_PROGRAM: if kodiutils.get_setting_int('library_tvshows') != LIBRARY_ONLY_MYLIST: return Library().update('plugin://plugin.video.streamz/library/tvshows/?program=%s&kodi_action=refresh_info' % content_id)
def show_library_tvshows(self, program=None): """ Return a list of the series that should be exported. """ if program is None: if kodiutils.get_setting_int( 'library_tvshows') == LIBRARY_FULL_CATALOG: # Full catalog # Use cache if available, fetch from api otherwise so we get rich metadata for new content # NOTE: We should probably use CACHE_PREVENT here, so we can pick up new episodes, but we can't since that would # require a massive amount of API calls for each update. We do this only for programs in 'My list'. items = self._api.get_items(content_filter=Program, cache=CACHE_AUTO) else: # Only favourites, don't use cache, fetch from api # If we use CACHE_AUTO, we will miss updates until the user manually opens the program in the Add-on items = self._api.get_mylist(content_filter=Program, cache=CACHE_PREVENT) else: # Fetch only a single program items = [self._api.get_program(program, cache=CACHE_PREVENT)] listing = [] for item in items: title_item = Menu.generate_titleitem(item) # title_item.path = kodiutils.url_for('library_tvshows', program=item.program_id) # We need a trailing / title_item.path = 'plugin://plugin.video.vtm.go/library/tvshows/?program={program_id}'.format( program_id=item.program_id) listing.append(title_item) kodiutils.show_listing(listing, 30003, content='tvshows', sort=['label', 'year', 'duration'])
def show_library_movies(self, movie=None): """ Return a list of the movies that should be exported. """ if movie is None: if kodiutils.get_setting_int( 'library_movies') == LIBRARY_FULL_CATALOG: # Full catalog # Use cache if available, fetch from api otherwise so we get rich metadata for new content items = self._api.get_items(content_filter=Movie, cache=CACHE_AUTO) else: # Only favourites, use cache if available, fetch from api otherwise items = self._api.get_mylist(content_filter=Movie) else: items = [self._api.get_movie(movie)] listing = [] for item in items: title_item = Menu.generate_titleitem(item) # title_item.path = kodiutils.url_for('library_movies', movie=item.movie_id) # We need a trailing / title_item.path = 'plugin://plugin.video.vtm.go/library/movies/?movie=%s' % item.movie_id listing.append(title_item) kodiutils.show_listing(listing, 30003, content='movies', sort=['label', 'year', 'duration'])
def show_channels(self): """ Shows TV channels. """ channels = self._channel_api.get_channels( filter_pin=kodiutils.get_setting_int( 'interface_adult') == SETTINGS_ADULT_HIDE) # Load EPG details for the next 6 hours date_now = datetime.now(dateutil.tz.UTC) date_from = date_now.replace(minute=0, second=0, microsecond=0) date_to = (date_from + timedelta(hours=6)) epg = self._epg_api.get_guide([channel.uid for channel in channels], date_from, date_to) for channel in channels: shows = [ show for show in epg.get(channel.uid, {}) if show.end > date_now ] try: channel.epg_now = shows[0] except (IndexError, KeyError): pass try: channel.epg_next = shows[1] except (IndexError, KeyError): pass listing = [] for item in channels: title_item = Menu.generate_titleitem_channel(item) title_item.path = kodiutils.url_for('show_channel', channel_id=item.get_combi_id()) title_item.is_playable = False listing.append(title_item) kodiutils.show_listing(listing, 30007)
def check_library_movie(self, movie): """ Check if the given movie is still available. """ _LOGGER.debug('Checking if movie %s is still available', movie) # Our parent path always exists if movie is None: kodiutils.library_return_status(True) return if kodiutils.get_setting_int('library_movies') == LIBRARY_FULL_CATALOG: id_list = self._api.get_catalog_ids() else: id_list = self._api.get_mylist_ids() kodiutils.library_return_status(movie in id_list)
def check_library_tvshow(self, program): """ Check if the given program is still available. """ _LOGGER.debug('Checking if program %s is still available', program) # Our parent path always exists if program is None: kodiutils.library_return_status(True) return if kodiutils.get_setting_int('library_tvshows') == LIBRARY_FULL_CATALOG: id_list = self._api.get_catalog_ids() else: id_list = self._api.get_mylist_ids() kodiutils.library_return_status(program in id_list)
def send_channels(self): """ Return JSON-STREAMS formatted information to IPTV Manager. """ channel_api = ChannelApi(self._auth) streams = [] channels = channel_api.get_channels( filter_pin=kodiutils.get_setting_int( 'interface_adult') == SETTINGS_ADULT_HIDE) for channel in channels: streams.append( dict( name=channel.title, stream=kodiutils.url_for('play_asset', asset_id=channel.uid), id=channel.station_id, logo=channel.icon, preset=channel.number, )) return dict(version=1, streams=streams)
def _is_refresh_required(): """Returns if we should trigger an update based on the settings.""" refresh_interval = kodiutils.get_setting_int('refresh_interval', 24) * 3600 last_refreshed = kodiutils.get_setting_int('last_refreshed', 0) return (last_refreshed + refresh_interval) <= time.time()
def play(self, category, item): """ Play the requested item. :type category: string :type item: string """ if not self._check_credentials(): kodiutils.end_of_directory() return # Check if inputstreamhelper is correctly installed if not self._check_inputstream(): kodiutils.end_of_directory() return try: # Get stream information resolved_stream = self._vtm_go_stream.get_stream(category, item) except StreamGeoblockedException: kodiutils.ok_dialog(heading=kodiutils.localize(30709), message=kodiutils.localize(30710)) # This video is geo-blocked... kodiutils.end_of_directory() return except StreamUnavailableException: kodiutils.ok_dialog(heading=kodiutils.localize(30711), message=kodiutils.localize(30712)) # The video is unavailable... kodiutils.end_of_directory() return info_dict = { 'tvshowtitle': resolved_stream.program, 'title': resolved_stream.title, 'duration': resolved_stream.duration, } prop_dict = {} stream_dict = { 'duration': resolved_stream.duration, } upnext_data = None # Lookup metadata try: if category in ['movies', 'oneoffs']: info_dict.update({'mediatype': 'movie'}) # Get details movie_details = self._vtm_go.get_movie(item) if movie_details: info_dict.update({ 'plot': movie_details.description, 'year': movie_details.year, 'aired': movie_details.aired, }) elif category == 'episodes': info_dict.update({'mediatype': 'episode'}) # There is no direct API to get episode details, so we go trough the cached program details program = self._vtm_go.get_program(resolved_stream.program_id) if program: episode_details = self._vtm_go.get_episode_from_program(program, item) if episode_details: info_dict.update({ 'plot': episode_details.description, 'season': episode_details.season, 'episode': episode_details.number, }) # Lookup the next episode next_episode_details = self._vtm_go.get_next_episode_from_program(program, episode_details.season, episode_details.number) # Create the data for Up Next if next_episode_details: upnext_data = self.generate_upnext(episode_details, next_episode_details) elif category == 'channels': info_dict.update({'mediatype': 'episode'}) # For live channels, we need to keep on updating the manifest # This might not be needed, and could be done with the Location-tag updates if inputstream.adaptive supports it # See https://github.com/peak3d/inputstream.adaptive/pull/298#issuecomment-524206935 prop_dict.update({ 'inputstream.adaptive.manifest_update_parameter': 'full', }) else: _LOGGER.warning('Unknown category %s', category) except UnavailableException: # We continue without details. # This allows to play some programs that don't have metadata (yet). pass # If we have enabled the Manifest proxy, route the call trough that. if category in ['movies', 'oneoffs', 'episodes'] and kodiutils.get_setting_bool('manifest_proxy'): try: # Python 3 from urllib.parse import urlencode except ImportError: # Python 2 from urllib import urlencode port = kodiutils.get_setting_int('manifest_proxy_port') if not port: kodiutils.notification(message=kodiutils.localize(30718), icon='error') kodiutils.end_of_directory() return url = 'http://127.0.0.1:{port}/manifest?{path}'.format(port=port, path=urlencode({'path': resolved_stream.url})) else: url = resolved_stream.url license_key = self._vtm_go_stream.create_license_key(resolved_stream.license_url) # Play this item kodiutils.play(url, license_key, resolved_stream.title, {}, info_dict, prop_dict, stream_dict) # Wait for playback to start kodi_player = KodiPlayer() if not kodi_player.waitForPlayBack(url=url): # Playback didn't start kodiutils.end_of_directory() return # Send Up Next data if upnext_data and kodiutils.get_setting_bool('useupnext'): _LOGGER.debug("Sending Up Next data: %s", upnext_data) self.send_upnext(upnext_data)
def show_channel(self, channel_id): """ Shows TV channel details. :param str channel_id: The channel we want to display. """ channel = self._channel_api.get_asset(channel_id.split(':')[0]) # Verify PIN if channel.pin and kodiutils.get_setting_int( 'interface_adult') != SETTINGS_ADULT_ALLOW: pin = kodiutils.get_numeric_input( kodiutils.localize(30204)) # Enter PIN if not pin: # Cancelled kodiutils.end_of_directory() return if not self._channel_api.verify_pin(pin): kodiutils.ok_dialog(message=kodiutils.localize( 30205)) # The PIN you have entered is invalid! kodiutils.end_of_directory() return listing = [] # Play live live_titleitem = Menu.generate_titleitem_channel(channel) live_titleitem.info_dict['title'] = kodiutils.localize( 30051, channel=channel.title) # Watch live [B]{channel}[/B] listing.append(live_titleitem) # Restart currently airing program if channel.epg_now and channel.epg_now.restart: restart_titleitem = Menu.generate_titleitem_program( channel.epg_now) restart_titleitem.info_dict['title'] = kodiutils.localize( 30052, program=channel.epg_now.title) # Restart [B]{program}[/B] restart_titleitem.art_dict['thumb'] = 'DefaultInProgressShows.png' listing.append(restart_titleitem) # TV Guide listing.append( TitleItem( title=kodiutils.localize( 30053, channel=channel.title), # TV Guide for {channel} path=kodiutils.url_for('show_channel_guide', channel_id=channel_id), art_dict=dict(icon='DefaultAddonTvInfo.png', ), info_dict=dict( plot=kodiutils.localize( 30054, channel=channel.title ), # Browse the TV Guide for {channel} ), )) if channel.replay: listing.append( TitleItem( title=kodiutils.localize( 30055, channel=channel.title), # Catalog for {channel} path=kodiutils.url_for('show_channel_replay', channel_id=channel_id), art_dict=dict(icon='DefaultMovieTitle.png', ), info_dict=dict( plot=kodiutils.localize( 30056, channel=channel.title ), # Browse the Catalog for {channel} ), )) kodiutils.show_listing(listing, 30007)
def send_epg(self): """ Return JSON-EPG formatted information to IPTV Manager. """ channel_api = ChannelApi(self._auth) epg_api = EpgApi(self._auth) epg = defaultdict(list) # Load EPG data channels = channel_api.get_channels( filter_pin=kodiutils.get_setting_int( 'interface_adult') == SETTINGS_ADULT_HIDE) for date in ['yesterday', 'today', 'tomorrow']: for channel, programs in epg_api.get_guide_with_capi( [channel.station_id for channel in channels], date).items(): for program in programs: # Hide these items if program.title == EpgApi.EPG_NO_BROADCAST: continue # Construct mapping for credits program_credits = [] for credit in program.credit: if credit.role == Credit.ROLE_ACTOR: program_credits.append({ 'type': 'actor', 'name': credit.person, 'role': credit.character }) elif credit.role == Credit.ROLE_DIRECTOR: program_credits.append({ 'type': 'director', 'name': credit.person }) elif credit.role == Credit.ROLE_PRODUCER: program_credits.append({ 'type': 'producer', 'name': credit.person }) elif credit.role == Credit.ROLE_COMPOSER: program_credits.append({ 'type': 'composer', 'name': credit.person }) elif credit.role == Credit.ROLE_PRESENTER: program_credits.append({ 'type': 'presenter', 'name': credit.person }) elif credit.role == Credit.ROLE_GUEST: program_credits.append({ 'type': 'guest', 'name': credit.person }) epg[channel].append( dict(start=program.start.isoformat(), stop=program.end.isoformat(), title=program.title, description=program.description, subtitle=None, episode='S%dE%d' % (program.season, program.episode) if program.season and program.episode else None, genre=program.genres, image=program.cover, date=None, credits=program_credits, stream=kodiutils.url_for('play_asset', asset_id=program.uid) if program.replay else None)) return dict(version=1, epg=epg)
def play(self, category, item): """ Play the requested item. :type category: string :type item: string """ # Check if inputstreamhelper is correctly installed if not self._check_inputstream(): kodiutils.end_of_directory() return try: # Get stream information resolved_stream = self._stream.get_stream(category, item) except UnavailableException: kodiutils.ok_dialog(message=kodiutils.localize( 30712)) # The video is unavailable... kodiutils.end_of_directory() return except LimitReachedException: kodiutils.ok_dialog( message=kodiutils.localize(30713) ) # You have reached the maximum amount of concurrent streams... kodiutils.end_of_directory() return info_dict = { 'tvshowtitle': resolved_stream.program, 'title': resolved_stream.title, 'duration': resolved_stream.duration, } prop_dict = {} stream_dict = { 'duration': resolved_stream.duration, } upnext_data = None # Lookup metadata try: if category in ['movies', 'oneoffs']: info_dict.update({'mediatype': 'movie'}) # Get details movie_details = self._api.get_movie(item) if movie_details: info_dict.update({ 'plot': movie_details.description, 'year': movie_details.year, 'aired': movie_details.aired, }) elif category == 'episodes': info_dict.update({'mediatype': 'episode'}) # There is no direct API to get episode details, so we go trough the cached program details program = self._api.get_program(resolved_stream.program_id) if program: episode_details = self._api.get_episode_from_program( program, item) if episode_details: info_dict.update({ 'plot': episode_details.description, 'season': episode_details.season, 'episode': episode_details.number, }) # Lookup the next episode next_episode_details = self._api.get_next_episode_from_program( program, episode_details.season, episode_details.number) # Create the data for Up Next if next_episode_details: upnext_data = self.generate_upnext( episode_details, next_episode_details) else: _LOGGER.warning('Unknown category %s', category) except UnavailableException: # We continue without details. # This allows to play some programs that don't have metadata (yet). pass # If we have enabled the Manifest proxy, route the call trough that. if kodiutils.get_setting_bool('manifest_proxy'): try: # Python 3 from urllib.parse import urlencode except ImportError: # Python 2 from urllib import urlencode port = kodiutils.get_setting_int('manifest_proxy_port') if not port: kodiutils.notification(message=kodiutils.localize(30718), icon='error') kodiutils.end_of_directory() return url = 'http://127.0.0.1:{port}/manifest?{path}'.format( port=port, path=urlencode({'path': resolved_stream.url})) else: url = resolved_stream.url license_key = self._stream.create_license_key( resolved_stream.license_url) # Play this item kodiutils.play(url, license_key, resolved_stream.title, {}, info_dict, prop_dict, stream_dict, subtitles=resolved_stream.subtitles) # Wait for playback to start kodi_player = KodiPlayer() if not kodi_player.waitForPlayBack(url=url): # Playback didn't start return # Send Up Next data if upnext_data and kodiutils.get_setting_bool('useupnext'): _LOGGER.debug("Sending Up Next data: %s", upnext_data) self.send_upnext(upnext_data)