def __get_title(self, name): """ Create the title based on the MediaItems name and type. :param str name: the name to update. :return: an updated name :rtype: str """ if not name: name = self.name if self.type == 'page': # We need to add the Page prefix to the item name = "%s %s" % (LanguageHelper.get_localized_string( LanguageHelper.Page), name) Logger.debug("MediaItem.__get_title :: Adding Page Prefix") elif self.__date != '' and not self.is_playable( ) and not AddonSettings.is_min_version(18): # not playable items should always show date name = "%s [COLOR=dimgray](%s)[/COLOR]" % (name, self.__date) folder_prefix = AddonSettings.get_folder_prefix() if self.type == "folder" and not folder_prefix == "": name = "%s %s" % (folder_prefix, name) return name
def set_bitrate(self): """ Sets the bitrate for the selected channel via a specific dialog. """ if self.channelObject is None: raise ValueError("Missing channel") # taken from the settings.xml bitrate_options = "Retrospect|100|250|500|750|1000|1500|2000|2500|4000|8000|20000"\ .split("|") current_bitrate = AddonSettings.get_max_channel_bitrate( self.channelObject) Logger.debug("Found bitrate for %s: %s", self.channelObject, current_bitrate) current_bitrate_index = 0 if current_bitrate not in bitrate_options \ else bitrate_options.index(current_bitrate) dialog = xbmcgui.Dialog() heading = LanguageHelper.get_localized_string( LanguageHelper.BitrateSelection) selected_bitrate = dialog.select(heading, bitrate_options, preselect=current_bitrate_index) if selected_bitrate < 0: return Logger.info("Changing bitrate for %s from %s to %s", self.channelObject, bitrate_options[current_bitrate_index], bitrate_options[selected_bitrate]) AddonSettings.set_max_channel_bitrate( self.channelObject, bitrate_options[selected_bitrate]) return
def __update_live_video(self, item, manifest, headers): video_info = manifest.get_value("playable", "assets", 0) url = video_info["url"] encrypted = video_info["encrypted"] part = item.create_new_empty_media_part() if encrypted: use_adaptive = AddonSettings.use_adaptive_stream_add_on(with_encryption=True) if not use_adaptive: Logger.error("Cannot playback encrypted item without inputstream.adaptive with encryption support") return item stream = part.append_media_stream(url, 0) key = M3u8.get_license_key("", key_headers=headers, key_type="R") M3u8.set_input_stream_addon_input(stream, proxy=self.proxy, headers=headers, license_key=key) item.complete = True else: use_adaptive = AddonSettings.use_adaptive_stream_add_on(with_encryption=False) if use_adaptive: stream = part.append_media_stream(url, 0) M3u8.set_input_stream_addon_input(stream, self.proxy, headers=headers) item.complete = True else: for s, b in M3u8.get_streams_from_m3u8(url, self.proxy, headers=headers): item.complete = True part.append_media_stream(s, b) return item
def execute(self): """ Shows the current channels settings dialog. """ if not self.__channel_info: Logger.warning("Cannot configure channel without channel info") Logger.info("Configuring channel: %s", self.__channel_info) AddonSettings.show_channel_settings(self.__channel_info)
def show_country_settings(self): """ Shows the country settings page where channels can be shown/hidden based on the country of origin. """ if AddonSettings.is_min_version(18): AddonSettings.show_settings(-99) else: AddonSettings.show_settings(101) self.refresh()
def __exit__(self, exc_type, exc_val, exc_tb): if exc_val: Logger.critical("Error in menu handling: %s", str(exc_val), exc_info=True) # make sure we leave no references behind AddonSettings.clear_cached_addon_settings_object() # close the log to prevent locking on next call Logger.instance().close_log() return False
def log_on(self): """ Logs on to a website, using an url. First checks if the channel requires log on. If so and it's not already logged on, it should handle the log on. That part should be implemented by the specific channel. More arguments can be passed on, but must be handled by custom code. After a successful log on the self.loggedOn property is set to True and True is returned. :return: indication if the login was successful. :rtype: bool """ if self.__idToken: return True # check if there is a refresh token # refresh token: viervijfzes_refresh_token refresh_token = AddonSettings.get_setting("viervijfzes_refresh_token") client = AwsIdp("eu-west-1_dViSsKM5Y", "6s1h851s8uplco5h6mqh1jac8m", proxy=self.proxy, logger=Logger.instance()) if refresh_token: id_token = client.renew_token(refresh_token) if id_token: self.__idToken = id_token return True else: Logger.info("Extending token for VierVijfZes failed.") # username: viervijfzes_username username = AddonSettings.get_setting("viervijfzes_username") # password: viervijfzes_password v = Vault() password = v.get_setting("viervijfzes_password") if not username or not password: XbmcWrapper.show_dialog( title=None, lines=LanguageHelper.get_localized_string( LanguageHelper.MissingCredentials), ) return False id_token, refresh_token = client.authenticate(username, password) if not id_token or not refresh_token: Logger.error("Error getting a new token. Wrong password?") return False self.__idToken = id_token AddonSettings.set_setting("viervijfzes_refresh_token", refresh_token) return True
def __configure_channel(self, channel_info): """ Shows the current channels settings dialog. :param ChannelInfo channel_info: The channel info for the channel """ if not channel_info: Logger.warning("Cannot configure channel without channel info") Logger.info("Configuring channel: %s", channel_info) AddonSettings.show_channel_settings(channel_info)
def select_channels(self): """ Selects the channels that should be visible. @return: None """ valid_channels = ChannelIndex.get_register().get_channels( include_disabled=True) channels_to_show = [c for c in valid_channels if c.visible] # The old way # channels_to_show = filter(lambda c: c.visible, valid_channels) selected_channels = [c for c in channels_to_show if c.enabled] selected_indices = list( [channels_to_show.index(c) for c in selected_channels]) Logger.debug("Currently selected channels: %s", selected_indices) channel_to_show_names = [ HtmlEntityHelper.convert_html_entities(c.channelName) for c in channels_to_show ] # The old way # channel_to_show_names = list(map(lambda c: HtmlEntityHelper.convert_html_entities(c.channelName), channels_to_show)) dialog = xbmcgui.Dialog() heading = LanguageHelper.get_localized_string( LanguageHelper.ChannelSelection)[:-1] selected_channels = dialog.multiselect(heading, channel_to_show_names, preselect=selected_indices) if selected_channels is None: return selected_channels = list(selected_channels) Logger.debug("New selected channels: %s", selected_channels) indices_to_remove = [ i for i in selected_indices if i not in selected_channels ] indices_to_add = [ i for i in selected_channels if i not in selected_indices ] for i in indices_to_remove: Logger.info("Hiding channel: %s", channels_to_show[i]) AddonSettings.set_channel_visiblity(channels_to_show[i], False) for i in indices_to_add: Logger.info("Showing channel: %s", channels_to_show[i]) AddonSettings.set_channel_visiblity(channels_to_show[i], True) self.refresh() return
def __get_application_key(self): """ Gets the decrypted application key that is used for all the encryption. :return: The decrypted application key that is used for all the encryption. :rtype: bytes """ application_key_encrypted = AddonSettings.get_setting( Vault.__APPLICATION_KEY_SETTING, store=LOCAL) # The key was never in the local store the value was None. It was "" if it was reset. if application_key_encrypted is None: application_key_encrypted = AddonSettings.get_setting( Vault.__APPLICATION_KEY_SETTING, store=KODI) if not application_key_encrypted: return None Logger.info("Moved ApplicationKey to local storage") AddonSettings.set_setting(Vault.__APPLICATION_KEY_SETTING, application_key_encrypted, store=LOCAL) # Still no application key? Then there was no key! if application_key_encrypted == "" or application_key_encrypted is None: return None vault_incorrect_pin = LanguageHelper.get_localized_string( LanguageHelper.VaultIncorrectPin) pin = XbmcWrapper.show_key_board( heading=LanguageHelper.get_localized_string( LanguageHelper.VaultInputPin), hidden=True) if not pin: XbmcWrapper.show_notification("", vault_incorrect_pin, XbmcWrapper.Error) raise RuntimeError("Incorrect Retrospect PIN specified") pin_key = self.__get_pbk(pin) application_key = self.__decrypt(application_key_encrypted, pin_key) if not application_key.startswith(Vault.__APPLICATION_KEY_SETTING): Logger.critical("Invalid Retrospect PIN") XbmcWrapper.show_notification("", vault_incorrect_pin, XbmcWrapper.Error) raise RuntimeError("Incorrect Retrospect PIN specified") application_key_value = application_key[ len(Vault.__APPLICATION_KEY_SETTING) + 1:] Logger.info("Successfully decrypted the ApplicationKey.") if PY2: return application_key_value # We return bytes on Python 3 return application_key_value.encode()
def log_off(self, username): """ Check if the user with the given name is currently authenticated. :param str username: The username to log off :returns: Indication of success :rtype: bool """ # clean older data UriHandler.delete_cookie(domain=".sso.rtl.nl") AddonSettings.set_setting(self.__setting_signature, "", store=LOCAL) return True
def toggle_cloak(self): """ Toggles the cloaking (showing/hiding) of the selected folder. """ item = self._pickler.de_pickle_media_item( self.params[self.keywordPickle]) Logger.info("Cloaking current item: %s", item) c = Cloaker(self.channelObject, AddonSettings.store(LOCAL), logger=Logger.instance()) if c.is_cloaked(item.url): c.un_cloak(item.url) self.refresh() return first_time = c.cloak(item.url) if first_time: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string( LanguageHelper.CloakFirstTime), LanguageHelper.get_localized_string( LanguageHelper.CloakMessage)) del c self.refresh()
def get_setting(self, setting_id): """ Retrieves an encrypted setting from the Kodi Add-on Settings. :param str setting_id: the ID for the setting to retrieve. :return: the decrypted value for the setting. :rtype: str """ Logger.info("Decrypting value for setting '%s'", setting_id) encrypted_value = AddonSettings.get_setting(setting_id) if not encrypted_value: Logger.warning("Found empty string as encrypted data") return encrypted_value try: decrypted_value = self.__decrypt(encrypted_value, Vault.__Key) if not decrypted_value.startswith(setting_id): Logger.error("Invalid decrypted value for setting '%s'", setting_id) return None decrypted_value = decrypted_value[len(setting_id) + 1:] Logger.info("Successfully decrypted value for setting '%s'", setting_id) except UnicodeDecodeError: Logger.error( "Invalid Unicode data returned from decryption. Must be wrong data" ) return None return decrypted_value
def active_authentication(self): """ Check if the user with the given name is currently authenticated. :returns: a AuthenticationResult with the account data. :rtype: AuthenticationResult """ login_token = AddonSettings.get_setting(self.__setting_signature, store=LOCAL) login_cookie = UriHandler.get_cookie("gmid", domain=".sso.rtl.nl") if login_token and \ login_cookie is not None and \ not login_cookie.is_expired(): # only retrieve the account information using the cookie and the token account_info_url = "https://sso.rtl.nl/accounts.getAccountInfo?{}" \ "&login_token={}".format(self.__common_params, login_token) account_info = UriHandler.open(account_info_url, no_cache=True) # See if it was successful auth_info = self.__extract_session_data(account_info) auth_info.existing_login = True return auth_info return AuthenticationResult(None)
def update_live_item(self, item): """ Updates an existing live MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ part = item.create_new_empty_media_part() if AddonSettings.use_adaptive_stream_add_on(): stream = part.append_media_stream(item.url, 0) M3u8.set_input_stream_addon_input(stream, self.proxy) item.complete = True else: for s, b in M3u8.get_streams_from_m3u8(item.url, self.proxy): item.complete = True part.append_media_stream(s, b) return item
def __show_first_time_message(self, channel_info): """ Checks if it is the first time a channel is executed and if a first time message is available it will be shown. Shows a message dialog if the message should be shown. Make sure that each line fits in a single line of a Kodi Dialog box (50 chars). :param ChannelInfo channel_info: The ChannelInfo to show a message for. """ hide_first_time = AddonSettings.hide_first_time_messages() if channel_info.firstTimeMessage: if not hide_first_time: Logger.info( "Showing first time message '%s' for channel chn_%s.", channel_info.firstTimeMessage, channel_info.moduleName) title = LanguageHelper.get_localized_string( LanguageHelper.ChannelMessageId) XbmcWrapper.show_dialog( title, channel_info.firstTimeMessage.split("|")) else: Logger.debug( "Not showing first time message due to add-on setting set to '%s'.", hide_first_time) return
def get_verifiable_video_url(self, url): """ Creates an RTMP(E) url that can be verified using an SWF URL. Returns a new URL that includes the self.swfUrl in the form of "url --swfVfy|-W swfUrl". If self.swfUrl == "", the original URL is returned. :param str url: The URL that should be made verifiable. :return: A new URL that includes the self.swfUrl :rtype: str """ if self.swfUrl == "": return url # TODO: Kodi 17.x also accepts an SWF-url as swfvfy option (https://www.ffmpeg.org/ffmpeg-protocols.html#rtmp). # This option should be set via the XbmcListItem.setProperty, so within Retrospect via: # part.add_property("swfvfy", self.swfUrl) # Or as an URL parameter swfvfy where we add the full URL instead of just 1: # return "%s swfvfy=%s" % (url, self.swfUrl) if AddonSettings.is_min_version(17): Logger.debug("Using Kodi 17+ RTMP parameters") return "%s swfvfy=%s" % (url, self.swfUrl) else: Logger.debug("Using Legacy (Kodi 16 and older) RTMP parameters") return "%s swfurl=%s swfvfy=1" % (url, self.swfUrl)
def update_json_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ headers = {} if self.localIP: headers.update(self.localIP) data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=headers) video_data = JsonHelper(data) stream_data = video_data.get_value("mediaAssetsOnDemand") if not stream_data: return item use_adaptive = AddonSettings.use_adaptive_stream_add_on() stream_data = stream_data[0] part = item.create_new_empty_media_part() if "hlsUrl" in stream_data: hls_url = stream_data["hlsUrl"] if use_adaptive: stream = part.append_media_stream(hls_url, 0) M3u8.set_input_stream_addon_input(stream, self.proxy, headers=headers) item.complete = True else: for s, b in M3u8.get_streams_from_m3u8(hls_url, self.proxy, headers=headers): item.complete = True part.append_media_stream(s, b) if "timedTextSubtitlesUrl" in stream_data and stream_data[ "timedTextSubtitlesUrl"]: sub_url = stream_data["timedTextSubtitlesUrl"].replace( ".ttml", ".vtt") sub_url = HtmlEntityHelper.url_decode(sub_url) part.Subtitle = SubtitleHelper.download_subtitle(sub_url, format="webvtt") return item
def add_others(self, data): """ Performs pre-process actions for data processing. Accepts an data from the process_folder_list method, BEFORE the items are processed. Allows setting of parameters (like title etc) for the channel. Inside this method the <data> could be changed and additional items can be created. The return values should always be instantiated in at least ("", []). :param str data: The retrieve data that was loaded for the current item and URL. :return: A tuple of the data and a list of MediaItems that were generated. :rtype: tuple[str|JsonHelper,list[MediaItem]] """ Logger.info("Performing Pre-Processing") items = [] others = MediaItem( "\b.: Populair :.", "https://api.kijk.nl/v2/default/sections/popular_PopularVODs?offset=0" ) items.append(others) days = MediaItem("\b.: Deze week :.", "#lastweek") items.append(days) search = MediaItem("\b.: Zoeken :.", "searchSite") search.complete = True search.dontGroup = True search.HttpHeaders = {"X-Requested-With": "XMLHttpRequest"} items.append(search) if self.channelCode == "veronica": live = LanguageHelper.get_localized_string( LanguageHelper.LiveStreamTitleId) live_radio = MediaItem("Radio Veronica {}".format(live), "") live_radio.type = "video" live_radio.dontGroup = True part = live_radio.create_new_empty_media_part() live_stream = "https://talparadiohls-i.akamaihd.net/hls/live/585615/VR-Veronica-1/playlist.m3u8" if AddonSettings.use_adaptive_stream_add_on(with_encryption=False, channel=self): stream = part.append_media_stream(live_stream, 0) M3u8.set_input_stream_addon_input(stream, self.proxy) live_radio.complete = True else: for s, b in M3u8.get_streams_from_m3u8(live_stream, self.proxy): live_radio.complete = True part.append_media_stream(s, b) items.append(live_radio) Logger.debug("Pre-Processing finished") return data, items
def __set_proxy(self, language, proxy_id, local_ip): """ Sets the proxy and local IP configuration for channels. :param str language: The language for what channels to update. :param int proxy_id: The proxy index to use. :param int local_ip: The local_ip index to use. If no proxy_id is specified (None) then the proxy_id will be determined based on language If no local_ip is specified (None) then the local_ip will be determined based on language """ languages = AddonSettings.get_available_countries( as_country_codes=True) if language is not None and language not in languages: Logger.warning("Missing language: %s", language) return if proxy_id is None: proxy_id = languages.index(language) else: # noinspection PyTypeChecker proxy_id = int(proxy_id) if local_ip is None: local_ip = languages.index(language) else: # noinspection PyTypeChecker local_ip = int(local_ip) channels = ChannelIndex.get_register().get_channels() Logger.info( "Setting proxy='%s' (%s) and local_ip='%s' (%s) for country '%s'", proxy_id, languages[proxy_id], local_ip, languages[local_ip], language) channels_in_country = [ c for c in channels if c.language == language or language is None ] for channel in channels_in_country: Logger.debug("Setting Proxy for: %s", channel) AddonSettings.set_proxy_id_for_channel(channel, proxy_id) if channel.localIPSupported: Logger.debug("Setting Local IP for: %s", channel) AddonSettings.set_local_ip_for_channel(channel, local_ip)
def update_part_with_m3u8_streams(part, url, encrypted=False, headers=None, map_audio=False, bitrate=0, channel=None): """ Updates an existing MediaItemPart with M3u8 data either using the Adaptive Inputstream Add-on or with the built-in code. :param MediaItemPart part: The part to update :param str url: The url to download :param bool encrypted: Is the stream encrypted? :param dict[str,str] headers: Possible HTTP Headers :param bool map_audio: Should audio tracks be mapped separately? :param int bitrate: Initial bitrate to use. Will be overridden later. :param ChannelInfo channel: If specified, the channel specific configuration is considered. :return: indication if updating was successful. :rtype: bool """ input_stream = AddonSettings.use_adaptive_stream_add_on( encrypted, channel=channel) if not input_stream and encrypted: Logger.error( "Cannot play encrypted stream without InputStream Adaptive with Encryption support!" ) return False if input_stream: Logger.debug( "Using InputStream Adaptive add-on for M3u8 playback.") stream = part.append_media_stream(url, bitrate) M3u8.set_input_stream_addon_input(stream, headers) return True complete = False if map_audio: Logger.debug( "Using Retrospect code with Audio mapping for M3u8 playback.") for s, b, a in M3u8.get_streams_from_m3u8(url, map_audio=True): if a: audio_part = a.rsplit("-", 1)[-1] audio_part = "-%s" % (audio_part, ) s = s.replace(".m3u8", audio_part) part.append_media_stream(s, b) complete = True else: Logger.debug("Using Retrospect code for M3u8 playback.") for s, b in M3u8.get_streams_from_m3u8(url): part.append_media_stream(s, b) complete = True return complete
def __extract_session_data(self, logon_data): """ :param logon_data: :return: :rtype: AuthenticationResult """ logon_json = json.loads(logon_data) result_code = logon_json.get("statusCode") Logger.trace("Logging in returned: %s", result_code) if result_code != 200: Logger.error("Error loging in: %s - %s", logon_json.get("errorMessage"), logon_json.get("errorDetails")) return AuthenticationResult(None) user_name = logon_json.get("profile", {}).get("email") or None signature_setting = logon_json.get("sessionInfo", {}).get("login_token") if signature_setting: Logger.info("Found 'login_token'. Saving it.") AddonSettings.set_setting(self.__setting_signature, signature_setting.split("|")[0], store=LOCAL) self.__signature = logon_json.get("UIDSignature") self.__user_id = logon_json.get("UID") self.__signature_timestamp = logon_json.get("signatureTimestamp") # TODO: is this correct? has_premium = logon_json.\ get("data", {}).\ get("authorization", {}).\ get("rtlxl_premium", {}).\ get("subscription", {}).\ get("id") == "premium" # The channels are not interesting # premium_channels = logon_json.get_value( # "data", "authorization", "Stievie_free", "channels") return AuthenticationResult(user_name, has_premium=has_premium)
def _get_current_user_in_settings(self): """ Retrieves the current user in the local settings. Can be used if there is no other means of retrieving the currently authenticated user. """ store = AddonSettings.store(LOCAL) return store.get_setting("{}:authenticated_user".format(self._realm), default=None)
def __show_empty_information(self, items, favs=False): """ Adds an empty item to a list or just shows a message. @type favs: boolean @param items: :param list[MediaItem] items: The list of items. :param bool favs: Indicating that we are dealing with favourites. :return: boolean indicating to report the listing as succes or not. :rtype: ok """ if favs: title = LanguageHelper.get_localized_string(LanguageHelper.NoFavsId) else: title = LanguageHelper.get_localized_string(LanguageHelper.ErrorNoEpisodes) behaviour = AddonSettings.get_empty_list_behaviour() Logger.debug("Showing empty info for mode (favs=%s): [%s]", favs, behaviour) if behaviour == "error": # show error ok = False elif behaviour == "dummy" and not favs: # We should add a dummy items, but not for favs empty_list_item = MediaItem("- %s -" % (title.strip("."), ), "", type='video') if self.channelObject: empty_list_item.icon = self.channelObject.icon empty_list_item.thumb = self.channelObject.noImage empty_list_item.fanart = self.channelObject.fanart else: icon = Config.icon fanart = Config.fanart empty_list_item.icon = icon empty_list_item.thumb = fanart empty_list_item.fanart = fanart empty_list_item.dontGroup = True empty_list_item.description = "This listing was left empty intentionally." empty_list_item.complete = True # add funny stream here? # part = empty_list_item.create_new_empty_media_part() # for s, b in YouTube.get_streams_from_you_tube("", self.channelObject.proxy): # part.append_media_stream(s, b) # if we add one, set OK to True ok = True items.append(empty_list_item) else: ok = True XbmcWrapper.show_notification(LanguageHelper.get_localized_string(LanguageHelper.ErrorId), title, XbmcWrapper.Error, 2500) return ok
def reset(): """ Resets the Vault and Retrospect Machine key, making all encrypted values useless. :rtype: None """ ok = XbmcWrapper.show_yes_no(LanguageHelper.get_localized_string(LanguageHelper.VaultReset), LanguageHelper.get_localized_string(LanguageHelper.VaultResetConfirm)) if not ok: Logger.debug("Aborting Reset Vault") return Logger.info("Resetting the vault to a new initial state.") AddonSettings.set_setting(Vault.__APPLICATION_KEY_SETTING, "", store=LOCAL) # create a vault instance so we initialize a new one with a new PIN. Vault() return
def create_json_video_item(self, result_set): """ Creates a MediaItem of type 'video' using the result_set from the regex. This method creates a new MediaItem from the Regular Expression or Json results <result_set>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.update_video_item method is called if the item is focussed or selected for playback. :param list[str]|dict[str,any] result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'video' or 'audio' (despite the method's name). :rtype: MediaItem|None """ Logger.trace(result_set) url = "http://playapi.mtgx.tv/v3/videos/stream/%(id)s" % result_set item = MediaItem(result_set["title"], url) item.type = "video" item.thumb = self.parentItem.thumb item.icon = self.parentItem.icon item.description = result_set.get("summary", None) aired_at = result_set.get("airedAt", None) if aired_at is None: aired_at = result_set.get("publishedAt", None) if aired_at is not None: # 2016-05-20T15:05:00+00:00 aired_at = aired_at.split("+")[0].rstrip('Z') time_stamp = DateHelper.get_date_from_string( aired_at, "%Y-%m-%dT%H:%M:%S") item.set_date(*time_stamp[0:6]) item.thumb = self.__get_thumb_image(result_set.get("image")) # webvttPath / samiPath # loginRequired is_premium = result_set.get("loginRequired", False) if is_premium and AddonSettings.hide_premium_items(): Logger.debug("Found premium item, hiding it.") return None srt = result_set.get("samiPath") if not srt: srt = result_set.get("subtitles_webvtt") if srt: Logger.debug("Storing SRT/WebVTT path: %s", srt) part = item.create_new_empty_media_part() part.Subtitle = srt return item
def set_inputstream_adaptive(self): """ Set the InputStream Adaptive for this channel """ if self.channelObject is None: raise ValueError("Missing channel") if not self.channelObject.adaptiveAddonSelectable: Logger.warning( "Cannot set InputStream Adaptive add-on mode for %s", self.channelObject) return current_mode = AddonSettings.get_adaptive_mode(self.channelObject) mode_values = [None, True, False] current_index = mode_values.index(current_mode) mode_options = [ LanguageHelper.get_localized_string(LanguageHelper.Retrospect), LanguageHelper.get_localized_string(LanguageHelper.Enabled), LanguageHelper.get_localized_string(LanguageHelper.Disabled) ] dialog = xbmcgui.Dialog() heading = LanguageHelper.get_localized_string( LanguageHelper.ChannelAdaptiveMode) selected_index = dialog.select(heading, mode_options, preselect=current_index) if selected_index < 0: return selected_value = mode_values[selected_index] Logger.info("Changing InputStream Adaptive mode for %s from %s to %s", self.channelObject, mode_options[current_index], mode_options[selected_index]) AddonSettings.set_adaptive_mode(self.channelObject, selected_value) # Refresh if we have a video item selected, so the cached urls are removed. if self.keywordPickle in self.params: Logger.debug("Refreshing list to clear URL caches") self.refresh()
def _store_current_user_in_settings(self, username): """ Store the current user in the local settings. :param str|None username: The currently authenticated user Can be used if there is no other means of retrieving the currently authenticated user. """ store = AddonSettings.store(LOCAL) store.set_setting("{}:authenticated_user".format(self._realm), username)
def __show_howto(self, force=False): """ Shows the Vault howto if it was not already shown. :param bool force: Force the howto to show :returns: indicator if the howto was shown :rtype: bool """ if not force: vault_shown = AddonSettings.store(LOCAL).get_boolean_setting( Vault.__VAULT_HOWTO_SETTING, default=False) if vault_shown: return False XbmcWrapper.show_text(LanguageHelper.VaultHowToTitle, LanguageHelper.VaultHowToText) AddonSettings.store(LOCAL).set_setting(Vault.__VAULT_HOWTO_SETTING, True) return True
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ headers = {} if self.localIP: headers.update(self.localIP) data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=headers) m3u8_url = Regexer.do_regex('data-file="([^"]+)"', data)[0] part = item.create_new_empty_media_part() if AddonSettings.use_adaptive_stream_add_on(with_encryption=False): stream = part.append_media_stream(m3u8_url, 0) M3u8.set_input_stream_addon_input(stream, proxy=self.proxy, headers=headers) item.complete = True else: for s, b, a in M3u8.get_streams_from_m3u8(m3u8_url, self.proxy, headers=headers, map_audio=True): if a and "-audio" not in s: video_part = s.rsplit("-", 1)[-1] video_part = "-%s" % (video_part, ) s = a.replace(".m3u8", video_part) part.append_media_stream(s, b) item.complete = True return item