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 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 add_categories_and_search(self, data): """ Adds some generic items such as search and categories to the main listing. 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 = [] max_items = 200 categories = { LanguageHelper.Popular: "https://urplay.se/api/bff/v1/search?product_type=program&query=&rows={}&start=0&view=most_viewed".format(max_items), LanguageHelper.MostRecentEpisodes: "https://urplay.se/api/bff/v1/search?product_type=program&rows={}&start=0&view=published".format(max_items), LanguageHelper.LastChance: "https://urplay.se/api/bff/v1/search?product_type=program&rows={}&start=0&view=last_chance".format(max_items), LanguageHelper.Categories: "https://urplay.se/", LanguageHelper.Search: "searchSite" } for cat in categories: title = "\a.: {} :.".format(LanguageHelper.get_localized_string(cat)) item = MediaItem(title, categories[cat]) item.thumb = self.noImage item.complete = True item.icon = self.icon item.dontGroup = True items.append(item) Logger.debug("Pre-Processing finished") return data, items
def create_api_tvseason_type(self, result_set): """ Creates a new MediaItem for an TV Season. 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. :param dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ season_number = result_set["seasonNumber"] title = LanguageHelper.get_localized_string(LanguageHelper.SeasonId) title = "{} {:02d}".format(title, season_number) season_id = result_set["id"].rsplit("/", 1)[-1] url = self.__get_api_query_url( query= 'programs(tvSeasonId:"{}",programTypes:EPISODE,skip:0,limit:{})'. format(season_id, self.__list_limit), fields=self.__video_fields) item = MediaItem(title, url) return item
def execute(self): title = LanguageHelper.get_localized_string( LanguageHelper.CleanupCache)[:-1] clean = \ XbmcWrapper.show_yes_no(title, LanguageHelper.CleanupConfirmation) if not clean: Logger.warning("Clean-up cancelled") return files_to_remove = { "channelindex.json": "Cleaning: Channel Index", "xot.session.lock": "Cleaning: Session lock" } for file_name, log_line in files_to_remove.items(): Logger.info(log_line) files_to_remove = os.path.join(Config.profileDir, file_name) if os.path.isfile(files_to_remove): os.remove(files_to_remove) Logger.info("Clearing cookies") UriHandler.clear_cookies() Logger.info("Cleaning: PickeStore objects") self.parameter_parser.pickler.purge_store(Config.addonId, age=0) Logger.info("Cleaning: Cache objects in cache folder") env_ctrl = EnvController(Logger.instance()) env_ctrl.cache_clean_up(Config.cacheDir, 0)
def create_page_item(self, result_set): """ Creates a MediaItem of type 'page' 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. :param list[str]|dict[str,str] result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'page'. :rtype: MediaItem|None """ items = [] if 'next' in result_set: title = LanguageHelper.get_localized_string( LanguageHelper.MorePages) url = result_set['next'] item = MediaItem(title, url) item.fanart = self.parentItem.fanart item.thumb = self.parentItem.thumb items.append(item) return items
def create_page_item(self, result_set): """ Creates a MediaItem of type 'page' 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. :param list[str]|dict[str,str] result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'page'. :rtype: MediaItem|None """ Logger.trace(result_set) next_page = result_set["next"] if not next_page: Logger.debug("No more items available") return None more = LanguageHelper.get_localized_string(LanguageHelper.MorePages) url = "%s=%s" % (self.parentItem.url.rsplit("=", 1)[0], next_page) item = MediaItem(more, url) item.complete = True return item
def create_alpha_item(self, result_set): """ Creates a MediaItem of type 'folder' using the Alpha chars available. It uses 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. :param list[str]|dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ program_count = result_set.get("availableInternationally", 0) if program_count <= 0: return None title = result_set["title"] url_part = title.lower() if url_part == "0-9": url_part = "$" url = "https://psapi.nrk.no/medium/tv/letters/{}/indexelements?onlyOnDemandRights=false&" \ "apiKey={}".format(url_part, self.__api_key) title = LanguageHelper.get_localized_string( LanguageHelper.StartWith) % (title, ) item = MediaItem(title, url) item.type = 'folder' return item
def show_folder_selection(title, default_path=None, dialog_type=3, mask=''): """ Shows a file/folder selection dialog for a given `dialog_type`: * 0 : ShowAndGetDirectory * 1 : ShowAndGetFile * 2 : ShowAndGetImage * 3 : ShowAndGetWriteableDirectory :param str|int title: The title of the box or its language ID. :param str default_path: Default path or file. :param int dialog_type: Type of file/folder selection type. :param str mask: '|' separated file mask. (i.e. '.jpg|.png'). :return: the selected file/folder. :rtype: str """ if isinstance(title, int): title = LanguageHelper.get_localized_string(title) if default_path is None: default_path = translatePath("special://home") browse_dialog = xbmcgui.Dialog() dest_folder = browse_dialog.browse(dialog_type, title, 'files', mask, False, False, default_path) return dest_folder
def add_live_channel_and_extract_data(self, data): """ Add the live channel and extract the correct data to process further. 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 = [] title = LanguageHelper.get_localized_string( LanguageHelper.LiveStreamTitleId) item = MediaItem("\a.: {} :.".format(title), self.liveUrl) item.type = "folder" items.append(item) if not data: return "[]", items json_data = Regexer.do_regex( r"setupBroadcastArchive\('Tv',\s*([^;]+)\);", data) if isinstance(json_data, (tuple, list)) and len(json_data) > 0: Logger.debug("Pre-Processing finished") return json_data[0], items Logger.info("Cannot extract JSON data from HTML.") return data, items
def alpha_listing(self, data): """ Creates a alpha listing with items pointing to the alpha listing on line. :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("Generating an Alpha list for BBC") items = [] # https://www.bbc.co.uk/iplayer/a-z/a title_format = LanguageHelper.get_localized_string( LanguageHelper.StartWith) url_format = "https://www.bbc.co.uk/iplayer/a-z/%s" for char in "abcdefghijklmnopqrstuvwxyz0": if char == "0": char = "0-9" sub_item = MediaItem(title_format % (char.upper(), ), url_format % (char, )) sub_item.complete = True sub_item.dontGroup = True sub_item.HttpHeaders = {"X-Requested-With": "XMLHttpRequest"} items.append(sub_item) return data, items
def add_live_channel(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 = [] title = LanguageHelper.get_localized_string( LanguageHelper.LiveStreamTitleId) item = MediaItem("\a.: {} :.".format(title), "") item.type = "folder" items.append(item) live_item = MediaItem(title, "#livestream") live_item.type = "video" live_item.isLive = True item.items.append(live_item) Logger.debug("Pre-Processing finished") return data, items
def create_api_tvseason_type(self, result_set): """ Creates a new MediaItem for an TV Season. 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. :param dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ season_number = result_set["seasonNumber"] title = LanguageHelper.get_localized_string(LanguageHelper.SeasonId) title = "{} {:02d}".format(title, season_number) season_id = result_set["id"].rsplit("/", 1)[-1] url = self.__get_api_query_url( query='programs(tvSeasonId:"{}",programTypes:EPISODE,skip:0,limit:100)'.format(season_id), fields="{items{__typename,title,description,guid,updated,seriesTvSeasons{id}," "imageMedia{url,label},type,sources{type,drm,file},series{title},seasonNumber," "tvSeasonEpisodeNumber,lastPubDate}}") item = MediaItem(title, url) return item
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(AddonSettings.KodiLeia): # 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 add_live_streams(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]] """ items = [] if self.parentItem is None: live_item = MediaItem( "\a.: Live TV :.", "https://d5ms27yy6exnf.cloudfront.net/live/omroepflevoland/tv/index.m3u8" ) live_item.icon = self.icon live_item.thumb = self.noImage live_item.type = 'video' live_item.dontGroup = True now = datetime.datetime.now() live_item.set_date(now.year, now.month, now.day, now.hour, now.minute, now.second) items.append(live_item) live_item = MediaItem( "\a.: Live Radio :.", "https://d5ms27yy6exnf.cloudfront.net/live/omroepflevoland/radio/index.m3u8" ) live_item.icon = self.icon live_item.thumb = self.noImage live_item.type = 'video' live_item.dontGroup = True now = datetime.datetime.now() live_item.set_date(now.year, now.month, now.day, now.hour, now.minute, now.second) items.append(live_item) # add "More" more = LanguageHelper.get_localized_string(LanguageHelper.MorePages) current_url = self.parentItem.url if self.parentItem is not None else self.mainListUri url, page = current_url.rsplit("=", 1) url = "{}={}".format(url, int(page) + 1) item = MediaItem(more, url) item.thumb = self.noImage item.icon = self.icon item.fanart = self.fanart item.complete = True items.append(item) return data, items
def __get_context_menu_items(self, channel, item=None): """ Retrieves the custom context menu items to display. favouritesList : Boolean - Indication that the menu is for the favorites :param Channel|None channel: The channel from which to get the context menu items. The channel might be None in case of some actions that do not require a channel. :param MediaItem|None item: The item to which the context menu belongs. :return: A list of context menu names and their commands. :rtype: list[tuple[str,str]] """ context_menu_items = [] # Genenric, none-Python menu items that would normally cause an unwanted reload of the # Python interpreter instance within Kodi. refresh = LanguageHelper.get_localized_string(LanguageHelper.RefreshListId) context_menu_items.append((refresh, 'XBMC.Container.Refresh()')) if item is None: return context_menu_items # if it was a favourites list, don't add the channel methods as they might be from a different channel if channel is None: return context_menu_items # now we process the other items possible_methods = self.__get_members(channel) # Logger.Debug(possible_methods) for menu_item in channel.contextMenuItems: # Logger.Debug(menu_item) if menu_item.itemTypes is None or item.type in menu_item.itemTypes: # We don't care for complete here! # if menu_item.completeStatus == None or menu_item.completeStatus == item.complete: # see if the method is available method_available = False for method in possible_methods: if method == menu_item.functionName: method_available = True # break from the method loop break if not method_available: Logger.warning("No method for: %s", menu_item) continue cmd_url = self._create_action_url(channel, action=menu_item.functionName, item=item) cmd = "XBMC.RunPlugin(%s)" % (cmd_url,) title = "Retro: %s" % (menu_item.label,) Logger.trace("Adding command: %s | %s", title, cmd) context_menu_items.append((title, cmd)) return context_menu_items
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 __update_video_from_mpd(self, item, mpd_info, use_adaptive_with_encryption): """ Updates an existing MediaItem with more data based on an MPD stream. :param dict[str,str] mpd_info: Stream info retrieved from the stream json. :param bool use_adaptive_with_encryption: Do we use the Adaptive InputStream add-on? :param MediaItem item: The original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug("Updating streams using BrightCove data.") part = item.create_new_empty_media_part() mpd_manifest_url = "https:{0}".format(mpd_info["mediaLocator"]) mpd_data = UriHandler.open(mpd_manifest_url) subtitles = Regexer.do_regex(r'<BaseURL>([^<]+\.vtt)</BaseURL>', mpd_data) if subtitles: Logger.debug("Found subtitle: %s", subtitles[0]) subtitle = SubtitleHelper.download_subtitle(subtitles[0], format="webvtt") part.Subtitle = subtitle if use_adaptive_with_encryption: # We can use the adaptive add-on with encryption Logger.info("Using MPD InputStreamAddon") license_url = Regexer.do_regex('licenseUrl="([^"]+)"', mpd_data)[0] token = "Bearer {0}".format(mpd_info["playToken"]) key_headers = {"Authorization": token} license_key = Mpd.get_license_key(license_url, key_headers=key_headers) stream = part.append_media_stream(mpd_manifest_url, 0) Mpd.set_input_stream_addon_input(stream, license_key=license_key) item.complete = True else: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item
def create_main_list(self, data): """ Performs pre-process actions for data processing and creates the main menu list 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 = [] live = LanguageHelper.get_localized_string( LanguageHelper.LiveStreamTitleId) live_tv = "{} - TV".format(live) live_radio = "{} - Radio".format(live) links = { live_tv: "https://psapi.nrk.no/tv/live?apiKey={}".format(self.__api_key), live_radio: "https://psapi.nrk.no/radio/live?apiKey={}".format(self.__api_key), "Recommended": "https://psapi.nrk.no/medium/tv/recommendedprograms?maxnumber=100&startRow=0&apiKey={}" .format(self.__api_key), "Popular": "https://psapi.nrk.no/medium/tv/popularprogramssuper?maxnumber=100&startRow=0&apiKey={}" .format(self.__api_key), "Recent": "https://psapi.nrk.no/medium/tv/recentlysentprograms?maxnumber=100&startRow=0&apiKey={}" .format(self.__api_key), "Categories": "https://psapi.nrk.no/medium/tv/categories?apiKey={}".format( self.__api_key), "A - Å": "https://psapi.nrk.no/medium/tv/letters?apiKey={}".format( self.__api_key), "Søk": "#searchSite" } for name, url in links.items(): item = MediaItem(name, url) item.icon = self.icon item.thumb = self.noImage item.complete = True item.HttpHeaders = self.httpHeaders items.append(item) Logger.debug("Pre-Processing finished") return data, items
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') empty_list_item.dontGroup = True empty_list_item.complete = True # 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 __show_warnings(self, media_item): """ Show playback warnings for this MediaItem :param MediaItem media_item: The current MediaItem that will be played. """ if (media_item.isDrmProtected or media_item.isPaid) and AddonSettings.show_drm_paid_warning(): if media_item.isDrmProtected: Logger.debug("Showing DRM Warning message") title = LanguageHelper.get_localized_string(LanguageHelper.DrmTitle) message = LanguageHelper.get_localized_string(LanguageHelper.DrmText) XbmcWrapper.show_dialog(title, message) elif media_item.isPaid: Logger.debug("Showing Paid Warning message") title = LanguageHelper.get_localized_string(LanguageHelper.PaidTitle) message = LanguageHelper.get_localized_string(LanguageHelper.PaidText) XbmcWrapper.show_dialog(title, message)
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 list_dates(self, data): """ Generates a list of the past week days. 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]] """ items = [] # https://api.kijk.nl/v2/templates/page/missed/all/20180201 days = ["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"] for i in range(0, 7): date = datetime.datetime.now() - datetime.timedelta(days=i) # https://api.kijk.nl/v2/templates/page/missed/all/20180626 # url = "https://api.kijk.nl/v2/templates/page/missed/all/{0}{1:02d}{2:02d}".format(date.year, date.month, date.day) # https://api.kijk.nl/v1/default/sections/missed-all-20180619 url = "https://api.kijk.nl/v1/default/sections/missed-all-{0}{1:02d}{2:02d}".format(date.year, date.month, date.day) if i == 0: title = LanguageHelper.get_localized_string(LanguageHelper.Today) elif i == 1: title = LanguageHelper.get_localized_string(LanguageHelper.Yesterday) elif i == 2: title = LanguageHelper.get_localized_string(LanguageHelper.DayBeforeYesterday) else: day_name = days[date.weekday()] title = day_name date_item = MediaItem(title, url) date_item.set_date(date.year, date.month, date.day) items.append(date_item) Logger.debug("Pre-Processing finished") return data, items
def toggle_cloak(self): """ Toggles the cloaking (showing/hiding) of the selected folder. """ item = self.media_item 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_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 process_video_item(self, item): """ Process a video item using the required dataparsers :param MediaItem item: The Item to update :return: An updated item. :rtype: MediaItem """ data_parsers = self.__get_data_parsers(item.url) if not data_parsers: Logger.error("No dataparsers found cannot update item.") return item data_parsers = [d for d in data_parsers if d.Updater is not None] if len(data_parsers) < 1: Logger.warning("No DataParsers with Updaters found.") return item if len(data_parsers) > 1: Logger.warning( "More than 2 DataParsers with Updaters found. Only using first one." ) data_parser = data_parsers[0] if not data_parser.Updater: Logger.error("No videoupdater found cannot update item.") return item if data_parser.LogOnRequired: Logger.info("One or more dataparsers require logging in.") self.loggedOn = self.log_on() if not self.loggedOn: Logger.warning("Could not log on for: %s", self) title = LanguageHelper.get_localized_string( LanguageHelper.LoginErrorTitle) text = LanguageHelper.get_localized_string( LanguageHelper.LoginErrorText) XbmcWrapper.show_dialog(title, text) Logger.debug("Processing Updater from %s", data_parser) return data_parser.Updater(item)
def add_recent_items(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]] """ items = [] today = datetime.datetime.now() days = LanguageHelper.get_days_list() for d in range(0, 7, 1): air_date = today - datetime.timedelta(d) Logger.trace("Adding item for: %s", air_date) # Determine a nice display date day = days[air_date.weekday()] if d == 0: day = LanguageHelper.get_localized_string(LanguageHelper.Today) elif d == 1: day = LanguageHelper.get_localized_string(LanguageHelper.Yesterday) title = "%04d-%02d-%02d - %s" % (air_date.year, air_date.month, air_date.day, day) url = "https://www.goplay.be/api/epg/{}/{:04d}-{:02d}-{:02d}".\ format(self.__channel_brand, air_date.year, air_date.month, air_date.day) extra = MediaItem(title, url) extra.complete = True extra.dontGroup = True extra.set_date(air_date.year, air_date.month, air_date.day, text="") extra.content_type = contenttype.VIDEOS items.append(extra) return data, items
def __update_dash_video(self, item, stream_info): """ :param MediaItem item: The item that was updated :param JsonHelper stream_info: The stream info """ if not AddonSettings.use_adaptive_stream_add_on(with_encryption=True): XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item playback_item = stream_info.get_value("playbackItem") stream_url = playback_item["manifestUrl"] part = item.create_new_empty_media_part() stream = part.append_media_stream(stream_url, 0) license_info = playback_item.get("license", None) if license_info is not None: license_key_token = license_info["token"] auth_token = license_info["castlabsToken"] header = { "x-dt-auth-token": auth_token, "content-type": "application/octstream" } license_url = license_info["castlabsServer"] license_key = Mpd.get_license_key(license_url, key_value=license_key_token, key_headers=header) Mpd.set_input_stream_addon_input(stream, proxy=self.proxy, license_key=license_key) item.isDrmProtected = False else: Mpd.set_input_stream_addon_input(stream, proxy=self.proxy) item.complete = True return item
def add_graphql_extras(self, data): """ Adds additional items to the main listings :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]] """ items = [] if self.parentItem is not None: return data, items popular_url = self.__get_api_query_url( "trendingPrograms", "{__typename,title,description,guid,updated,seriesTvSeasons{id},imageMedia{url,label}}" ) popular_title = LanguageHelper.get_localized_string(LanguageHelper.Popular) popular = MediaItem( "\a.: {} :.".format(popular_title), popular_url ) popular.dontGroup = True items.append(popular) # https://graph.kijk.nl/graphql?operationName=programsByDate&variables={"date":"2020-04-19","numOfDays":7}&extensions={"persistedQuery":{"version":1,"sha256Hash":"1445cc0d283e10fa21fcdf95b127207d5f8c22834c1d0d17df1aacb8a9da7a8e"}} recent_url = "#recentgraphql" recent_title = LanguageHelper.get_localized_string(LanguageHelper.Recent) recent = MediaItem( "\a.: {} :.".format(recent_title), recent_url ) recent.dontGroup = True items.append(recent) search_title = LanguageHelper.get_localized_string(LanguageHelper.Search) search = MediaItem("\a.: {} :.".format(search_title), "#searchSite") search.dontGroup = True items.append(search) return data, items
def execute(self): """ Send log files via Pastbin or Gist. """ from resources.lib.helpers.logsender import LogSender sender_mode = 'hastebin' log_sender = LogSender(Config.logSenderApi, logger=Logger.instance(), mode=sender_mode) try: title = LanguageHelper.get_localized_string(LanguageHelper.LogPostSuccessTitle) url_text = LanguageHelper.get_localized_string(LanguageHelper.LogPostLogUrl) files_to_send = [Logger.instance().logFileName, Logger.instance().logFileName.replace(".log", ".old.log")] paste_url = log_sender.send_file(Config.logFileNameAddon, files_to_send[0]) XbmcWrapper.show_dialog(title, url_text % (paste_url,)) except Exception as e: Logger.error("Error sending %s", Config.logFileNameAddon, exc_info=True) title = LanguageHelper.get_localized_string(LanguageHelper.LogPostErrorTitle) error_text = LanguageHelper.get_localized_string(LanguageHelper.LogPostError) error = error_text % (str(e),) XbmcWrapper.show_dialog(title, error.strip(": "))