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 __GetApplicationKey(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 """ applicationKeyEncrypted = AddonSettings.GetSetting(Vault.__APPLICATION_KEY_SETTING) if not applicationKeyEncrypted: return None vaultIncorrectPin = LanguageHelper.GetLocalizedString(LanguageHelper.VaultIncorrectPin) pin = XbmcWrapper.ShowKeyBoard( heading=LanguageHelper.GetLocalizedString(LanguageHelper.VaultInputPin), hidden=True) if not pin: XbmcWrapper.ShowNotification("", vaultIncorrectPin, XbmcWrapper.Error) raise RuntimeError("Incorrect Retrospect PIN specified") pinKey = self.__GetPBK(pin) applicationKey = self.__Decrypt(applicationKeyEncrypted, pinKey) if not applicationKey.startswith(Vault.__APPLICATION_KEY_SETTING): Logger.Critical("Invalid Retrospect PIN") XbmcWrapper.ShowNotification("", vaultIncorrectPin, XbmcWrapper.Error) raise RuntimeError("Incorrect Retrospect PIN specified") applicationKeyValue = applicationKey[len(Vault.__APPLICATION_KEY_SETTING) + 1:] Logger.Info("Successfully decrypted the ApplicationKey.") return applicationKeyValue
def __send_log(self): """ Send log files via Pastbin or Gist. """ from 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") ] if sender_mode != "gist": paste_url = log_sender.send_file(Config.logFileNameAddon, files_to_send[0]) else: paste_url = log_sender.send_files(Config.logFileNameAddon, files_to_send) 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(": "))
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 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 ChangePin(self, applicationKey=None): # type: (str) -> bool """ Stores an existing ApplicationKey using a new PIN @param applicationKey: an existing ApplicationKey that will be stored. If none specified, the existing ApplicationKey of the Vault will be used. @return: indication of success """ Logger.Info("Updating the ApplicationKey with a new PIN") if self.__newKeyGeneratedInConstructor: Logger.Info("A key was just generated, no need to change PINs.") return True if applicationKey is None: Logger.Debug("Using the ApplicationKey from the vault.") applicationKey = Vault.__Key else: Logger.Debug("Using the ApplicationKey from the input parameter.") if not applicationKey: raise ValueError("No ApplicationKey specified.") # Now we get a new PIN and (re)encrypt pin = XbmcWrapper.ShowKeyBoard( heading=LanguageHelper.GetLocalizedString(LanguageHelper.VaultNewPin), hidden=True) if not pin: XbmcWrapper.ShowNotification( "", LanguageHelper.GetLocalizedString(LanguageHelper.VaultNoPin), XbmcWrapper.Error) return False pin2 = XbmcWrapper.ShowKeyBoard( heading=LanguageHelper.GetLocalizedString(LanguageHelper.VaultRepeatPin), hidden=True) if pin != pin2: Logger.Critical("Mismatch in PINs") XbmcWrapper.ShowNotification( "", LanguageHelper.GetLocalizedString(LanguageHelper.VaultPinsDontMatch), XbmcWrapper.Error) return False encryptedKey = "%s=%s" % (self.__APPLICATION_KEY_SETTING, applicationKey) # let's generate a pin using the scrypt password-based key derivation pinKey = self.__GetPBK(pin) encryptedKey = self.__Encrypt(encryptedKey, pinKey) AddonSettings.SetSetting(Vault.__APPLICATION_KEY_SETTING, encryptedKey) Logger.Info("Successfully updated the Retrospect PIN") return True
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 __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, proxy=self.proxy) 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], proxy=self.proxy, 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, self.proxy, 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 search_site(self, url=None): """ Creates an list of items by searching the site. This method is called when the URL of an item is "searchSite". The channel calling this should implement the search functionality. This could also include showing of an input keyboard and following actions. The %s the url will be replaced with an URL encoded representation of the text to search for. :param str|None url: Url to use to search with a %s for the search parameters. :return: A list with search results as MediaItems. :rtype: list[MediaItem] """ items = [] needle = XbmcWrapper.show_key_board() if needle: #convert to HTML needle = needle.replace(" ", "%20") search_url = "http://www.dumpert.nl/search/V/%s/ " % (needle, ) temp = MediaItem("Search", search_url) return self.process_folder_list(temp) return items
def search_site(self, url=None): """ Creates an list of items by searching the site. This method is called when the URL of an item is "searchSite". The channel calling this should implement the search functionality. This could also include showing of an input keyboard and following actions. The %s the url will be replaced with an URL encoded representation of the text to search for. :param str|None url: Url to use to search with a %s for the search parameters. :return: A list with search results as MediaItems. :rtype: list[MediaItem] """ items = [] if url is None: item = MediaItem("Search Not Implented", "", type='video') item.icon = self.icon items.append(item) else: items = [] needle = XbmcWrapper.show_key_board() if needle: Logger.debug("Searching for '%s'", needle) # convert to HTML needle = HtmlEntityHelper.url_encode(needle) search_url = url % (needle, ) temp = MediaItem("Search", search_url) return self.process_folder_list(temp) return items
def __ShowFirstTimeMessage(self, channelInfo): # type: (ChannelInfo) -> None """ Checks if it is the first time a channel is executed and if a first time message is available it will be shown Arguments: channelName : string - Name of the channelfile that is loaded channelPath : string - Path of the channelfile Shows a message dialog if the message should be shown. Make sure that each line fits in a single line of a XBMC Dialog box (50 chars) """ hideFirstTime = AddonSettings.HideFirstTimeMessages() if channelInfo.firstTimeMessage: if not hideFirstTime: Logger.Info("Showing first time message '%s' for channel chn_%s.", channelInfo.firstTimeMessage, channelInfo.moduleName) title = LanguageHelper.GetLocalizedString(LanguageHelper.ChannelMessageId) XbmcWrapper.ShowDialog(title, channelInfo.firstTimeMessage.split("|")) else: Logger.Debug("Not showing first time message due to add-on setting set to '%s'.", hideFirstTime) return
def SearchSite(self, url=None): """Creates an list of items by searching the site Keyword Arguments: url : String - Url to use to search with a %s for the search parameters Returns: A list of MediaItems that should be displayed. This method is called when the URL of an item is "searchSite". The channel calling this should implement the search functionality. This could also include showing of an input keyboard and following actions. The %s the url will be replaced with an URL encoded representation of the text to search for. """ items = [] if url is None: item = mediaitem.MediaItem("Search Not Implented", "", type='video') item.icon = self.icon items.append(item) else: items = [] needle = XbmcWrapper.ShowKeyBoard() if needle: Logger.Debug("Searching for '%s'", needle) # convert to HTML needle = htmlentityhelper.HtmlEntityHelper.UrlEncode(needle) searchUrl = url % (needle, ) temp = mediaitem.MediaItem("Search", searchUrl) return self.ProcessFolderList(temp) return items
def DownloadVideoItem(self, item): """Downloads an existing MediaItem with more data. Arguments: item : MediaItem - the MediaItem that should be downloaded. Returns: The original item with more data added to it's properties. Used to download an <item>. If the item is not complete, the self.UpdateVideoItem method is called to update the item. The method downloads only the MediaStream with the bitrate that was set in the addon settings. After downloading the self.downloaded property is set. """ if not item.IsPlayable(): Logger.Error("Cannot download a folder item.") return item if item.IsPlayable(): if not item.complete: Logger.Info("Fetching MediaUrl for PlayableItem[%s]", item.type) item = self.ProcessVideoItem(item) if not item.complete or not item.HasMediaItemParts(): Logger.Error("Cannot download incomplete item or item without MediaItemParts") return item i = 1 bitrate = AddonSettings.GetMaxStreamBitrate() for mediaItemPart in item.MediaItemParts: Logger.Info("Trying to download %s", mediaItemPart) stream = mediaItemPart.GetMediaStreamForBitrate(bitrate) downloadUrl = stream.Url extension = UriHandler.GetExtensionFromUrl(downloadUrl) if len(item.MediaItemParts) > 1: saveFileName = "%s-Part_%s.%s" % (item.name, i, extension) else: saveFileName = "%s.%s" % (item.name, extension) Logger.Debug(saveFileName) # headers = item.HttpHeaders + mediaItemPart.HttpHeaders headers = item.HttpHeaders.copy() headers.update(mediaItemPart.HttpHeaders) progressDialog = XbmcDialogProgressWrapper("Downloading Item", item.name, stream.Url) folderName = XbmcWrapper.ShowFolderSelection('Select download destination for "%s"' % (saveFileName, )) UriHandler.Download(downloadUrl, saveFileName, folderName, progressDialog, proxy=self.proxy, additionalHeaders=headers) i += 1 item.downloaded = True return item
def SearchSite(self, url=None): """Creates an list of items by searching the site Keyword Arguments: url : String - Url to use to search with a %s for the search parameters Returns: A list of MediaItems that should be displayed. This method is called when the URL of an item is "searchSite". The channel calling this should implement the search functionality. This could also include showing of an input keyboard and following actions. The %s the url will be replaced with an URL encoded representation of the text to search for. """ if self.primaryChannelId: shows_url = "https://disco-api.dplay.se/content/shows?" \ "include=genres%%2Cimages%%2CprimaryChannel.images&" \ "filter%%5BprimaryChannel.id%%5D={0}&" \ "page%%5Bsize%%5D={1}&query=%s"\ .format(self.primaryChannelId or "", self.programPageSize) videos_url = "https://disco-api.dplay.se/content/videos?decorators=viewingHistory&" \ "include=images%%2CprimaryChannel%%2Cshow&" \ "filter%%5BprimaryChannel.id%%5D={0}&" \ "page%%5Bsize%%5D={1}&query=%s"\ .format(self.primaryChannelId or "", self.videoPageSize) else: shows_url = "https://disco-api.dplay.se/content/shows?" \ "include=genres%%2Cimages%%2CprimaryChannel.images&" \ "page%%5Bsize%%5D={0}&query=%s" \ .format(self.programPageSize) videos_url = "https://disco-api.dplay.se/content/videos?decorators=viewingHistory&" \ "include=images%%2CprimaryChannel%%2Cshow&" \ "page%%5Bsize%%5D={0}&query=%s" \ .format(self.videoPageSize) needle = XbmcWrapper.ShowKeyBoard() if needle: Logger.Debug("Searching for '%s'", needle) needle = HtmlEntityHelper.UrlEncode(needle) searchUrl = videos_url % (needle, ) temp = mediaitem.MediaItem("Search", searchUrl) episodes = self.ProcessFolderList(temp) searchUrl = shows_url % (needle, ) temp = mediaitem.MediaItem("Search", searchUrl) shows = self.ProcessFolderList(temp) return shows + episodes return []
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 search_site(self, url=None): """ Creates an list of items by searching the site. This method is called when the URL of an item is "searchSite". The channel calling this should implement the search functionality. This could also include showing of an input keyboard and following actions. The %s the url will be replaced with an URL encoded representation of the text to search for. :param str url: Url to use to search with a %s for the search parameters. :return: A list with search results as MediaItems. :rtype: list[MediaItem] """ if self.primaryChannelId: shows_url = "https://{0}/content/shows?" \ "include=genres%%2Cimages%%2CprimaryChannel.images&" \ "filter%%5BprimaryChannel.id%%5D={1}&" \ "page%%5Bsize%%5D={2}&query=%s"\ .format(self.baseUrlApi, self.primaryChannelId or "", self.programPageSize) videos_url = "https://{0}/content/videos?decorators=viewingHistory&" \ "include=images%%2CprimaryChannel%%2Cshow&" \ "filter%%5BprimaryChannel.id%%5D={1}&" \ "page%%5Bsize%%5D={2}&query=%s"\ .format(self.baseUrlApi, self.primaryChannelId or "", self.videoPageSize) else: shows_url = "https://{0}/content/shows?" \ "include=genres%%2Cimages%%2CprimaryChannel.images&" \ "page%%5Bsize%%5D={1}&query=%s" \ .format(self.baseUrlApi, self.programPageSize) videos_url = "https://{0}/content/videos?decorators=viewingHistory&" \ "include=images%%2CprimaryChannel%%2Cshow&" \ "page%%5Bsize%%5D={1}&query=%s" \ .format(self.baseUrlApi, self.videoPageSize) needle = XbmcWrapper.show_key_board() if needle: Logger.debug("Searching for '%s'", needle) needle = HtmlEntityHelper.url_encode(needle) search_url = videos_url % (needle, ) temp = MediaItem("Search", search_url) episodes = self.process_folder_list(temp) search_url = shows_url % (needle, ) temp = MediaItem("Search", search_url) shows = self.process_folder_list(temp) return shows + episodes return []
def ShowFavourites(self, channel, replaceExisting=False): """ Show the favourites Arguments: channel : Channel - The channel to show favourites for. Might be None to show all. Keyword Arguments: replaceExisting : boolean - if True it will replace the current list """ Logger.Debug("Plugin::ShowFavourites") if channel is None: Logger.Info("Showing all favourites") else: Logger.Info("Showing favourites for: %s", channel) stopWatch = stopwatch.StopWatch("Plugin Favourites timer", Logger.Instance()) try: ok = True f = Favourites(Config.favouriteDir) favs = f.List(channel) # get (actionUrl, pickle) tuples # favs = map(lambda (a, p): (a, Pickler.DePickleMediaItem(p)), favs) if len(favs) == 0: ok = self.__ShowEmptyInformation(favs, favs=True) stopWatch.Lap("Items retrieved") # create the XBMC items xbmcItems = map(lambda item: self.__ConvertMainlistItemToXbmcItem(channel, item[1], True, item[0]), favs) stopWatch.Lap("%s items for Kodi generated" % (len(xbmcItems),)) # add them to XBMC ok = ok and xbmcplugin.addDirectoryItems(self.handle, xbmcItems, len(xbmcItems)) # add sort handle, but don't use any dates as they make no sense for favourites self.__AddSortMethodToHandle(self.handle) # set the content xbmcplugin.setContent(handle=self.handle, content=self.contentType) # make sure we do not cache this one to disc! xbmcplugin.endOfDirectory(self.handle, succeeded=ok, updateListing=replaceExisting, cacheToDisc=False) stopWatch.Lap("items send to Kodi") Logger.Debug("Plugin::Favourites completed. Returned %s item(s)", len(favs)) stopWatch.Stop() except: XbmcWrapper.ShowNotification(LanguageHelper.GetLocalizedString(LanguageHelper.ErrorId), LanguageHelper.GetLocalizedString(LanguageHelper.ErrorList), XbmcWrapper.Error, 4000) Logger.Error("Plugin::Error parsing favourites", exc_info=True) xbmcplugin.endOfDirectory(self.handle, False)
def _purge_kodi_cache(self, channel_texture_path): """ Class the JSON RPC within Kodi that removes all changed items which paths contain the value given in channelTexturePath @param channel_texture_path: string - The """ json_cmd = '{' \ '"jsonrpc": "2.0", ' \ '"method": "Textures.GetTextures", ' \ '"params": {' \ '"filter": {"operator": "contains", "field": "url", "value": "%s"}, ' \ '"properties": ["url"]' \ '}, ' \ '"id": "libTextures"' \ '}' % (channel_texture_path,) json_results = XbmcWrapper.execute_json_rpc(json_cmd, self._logger) results = JsonHelper(json_results, logger=self._logger) if "error" in results.json or "result" not in results.json: self._logger.error( "Error retreiving textures:\nCmd : %s\nResult: %s", json_cmd, results.json) return results = results.get_value("result", "textures", fallback=[]) for result in results: texture_id = result["textureid"] texture_url = result["url"] self._logger.debug("Going to remove texture: %d - %s", texture_id, texture_url) json_cmd = '{' \ '"jsonrpc": "2.0", ' \ '"method": "Textures.RemoveTexture", ' \ '"params": {' \ '"textureid": %s' \ '}' \ '}' % (texture_id,) XbmcWrapper.execute_json_rpc(json_cmd, self._logger) return
def __UpdateFromUrl(self, url, zipName): """ Update a channel from an URL @param url: The url to download @param zipName: The name to give the download """ Logger.Info("Going to update from %s", url) # wrapper = XbmcDialogProgressWrapper("Updating XOT", url) # destFilename = UriHandler.Download(url, zipName, Config.cacheDir, wrapper.ProgressUpdate) destFilename = UriHandler.Download(url, zipName, Config.cacheDir, self.__RetrieveProgressDummy) Logger.Debug("Download succeeded: %s", destFilename) # we extract to the deploy folder, so with the first start of XOT, the new channel is deployed deployDir = os.path.abspath(os.path.join(Config.rootDir, "deploy")) zipFile = zipfile.ZipFile(destFilename) # now extract first = True Logger.Debug("Extracting %s to %s", destFilename, deployDir) for name in zipFile.namelist(): if first: folder = os.path.split(name)[0] if os.path.exists(os.path.join(deployDir, folder)): shutil.rmtree(os.path.join(deployDir, folder)) first = False if not name.endswith("/") and not name.endswith("\\"): fileName = os.path.join(deployDir, name) path = os.path.dirname(fileName) if not os.path.exists(path): os.makedirs(path) Logger.Debug("Extracting %s", fileName) outfile = open(fileName, 'wb') outfile.write(zipFile.read(name)) outfile.close() zipFile.close() os.remove(destFilename) Logger.Info("Update completed and zip file (%s) removed", destFilename) message = LanguageHelper.GetLocalizedString( LanguageHelper.UpdateCompleteId, splitOnPipes=False) % (zipName.replace(".zip", ""), ) message = message.split("|") XbmcWrapper.ShowNotification(LanguageHelper.GetLocalizedString( LanguageHelper.RestartId), message, displayTime=5000, logger=Logger.Instance())
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 SearchSite(self, url=None): """ Creates an list of items by searching the site """ items = [] needle = XbmcWrapper.ShowKeyBoard() if needle: #convert to HTML needle = string.replace(needle, " ", "%20") searchUrl = "http://www.dumpert.nl/search/V/%s/ " % (needle, ) temp = mediaitem.MediaItem("Search", searchUrl) return self.ProcessFolderList(temp) return items
def LogOn(self): signatureSettings = "mediaan_signature" signatureSetting = AddonSettings.GetSetting(signatureSettings) # apiKey = "3_HZ0FtkMW_gOyKlqQzW5_0FHRC7Nd5XpXJZcDdXY4pk5eES2ZWmejRW5egwVm4ug-" # from VTM apiKey = "3_OEz9nzakKMkhPdUnz41EqSRfhJg5z9JXvS4wUORkqNf2M2c1wS81ilBgCewkot97" # from Stievie if signatureSetting and "|" not in signatureSetting: url = "https://accounts.eu1.gigya.com/accounts.getAccountInfo" data = "APIKey=%s" \ "&sdk=js_7.4.30" \ "&login_token=%s" % (apiKey, signatureSetting, ) logonData = UriHandler.Open(url, params=data, proxy=self.proxy, noCache=True) if self.__ExtractSessionData(logonData, signatureSettings): return True Logger.Warning("Failed to extend the VTM.be session.") Logger.Info("Logging onto VTM.be") v = Vault() password = v.GetSetting("mediaan_password") username = AddonSettings.GetSetting("mediaan_username") if not username or not password: XbmcWrapper.ShowDialog( title=None, lines=LanguageHelper.GetLocalizedString( LanguageHelper.MissingCredentials), # notificationType=XbmcWrapper.Error, # displayTime=5000 ) return False Logger.Debug("Using: %s / %s", username, "*" * len(password)) url = "https://accounts.eu1.gigya.com/accounts.login" data = "loginID=%s" \ "&password=%s" \ "&targetEnv=jssdk" \ "&APIKey=%s" \ "&includeSSOToken=true" \ "&authMode=cookie" % \ (HtmlEntityHelper.UrlEncode(username), HtmlEntityHelper.UrlEncode(password), apiKey) logonData = UriHandler.Open(url, params=data, proxy=self.proxy, noCache=True) return self.__ExtractSessionData(logonData, signatureSettings)
def __ShowEmptyInformation(self, items, favs=False): """ Adds an empty item to a list or just shows a message. @type favs: boolean indicating that we are dealing with favourites @param items: the list of items @rtype : boolean indicating succes or not """ if self.channelObject: Statistics.RegisterError(self.channelObject) if favs: title = LanguageHelper.GetLocalizedString(LanguageHelper.NoFavsId) else: title = LanguageHelper.GetLocalizedString(LanguageHelper.ErrorNoEpisodes) behaviour = AddonSettings.GetEmptyListBehaviour() 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 emptyListItem = MediaItem("- %s -" % (title.strip("."), ), "", type='video') emptyListItem.icon = self.channelObject.icon emptyListItem.thumb = self.channelObject.noImage emptyListItem.fanart = self.channelObject.fanart emptyListItem.dontGroup = True emptyListItem.description = "This listing was left empty intentionally." emptyListItem.complete = True emptyListItem.fanart = self.channelObject.fanart # add funny stream here? # part = emptyListItem.CreateNewEmptyMediaPart() # for s, b in YouTube.GetStreamsFromYouTube("", self.channelObject.proxy): # part.AppendMediaStream(s, b) # if we add one, set OK to True ok = True items.append(emptyListItem) else: ok = True XbmcWrapper.ShowNotification(LanguageHelper.GetLocalizedString(LanguageHelper.ErrorId), title, XbmcWrapper.Error, 2500) return ok
def __GetAvailableUpdates(self): """ Opens the addon.xml and fetches all updates. Compares them with the installed versions and returns a list of URL's to download @return: a list of URLs """ data = UriHandler.Open(Config.UpdateUrl.replace(".md5", "")) channels = Regexer.DoRegex( '<addon\W+id="(net.rieter.xot(?:.channel.[^"]+|))\W+version="([^"]+)"', data) updates = [] for channel in channels: addonId = channel[0] addonVersion = channel[1] if addonId == Config.addonId: Logger.Debug("Found main Retrospect version: %s", addonVersion) # the main XOT add-on if Version(version=addonVersion) != Config.version: Logger.Warning( "Not deploying new channels because Retrospect versions do not match: " "Installed %s vs Online %s", Config.version, addonVersion) message = LanguageHelper.GetLocalizedString( LanguageHelper.NewVersion2Id, splitOnPipes=False) message = message % (Config.appName, addonVersion) XbmcWrapper.ShowDialog( LanguageHelper.GetLocalizedString( LanguageHelper.NewVersionId), message.split("|")) return [] else: # set the zipfile name here, but check in the next loop! channelId = "%s-%s" % (addonId, addonVersion) if self.__IsVersionInstalled(addonId, addonVersion): # already installed, continue as if Logger.Info("Update already installed: %s", channelId) continue else: url = "http://www.rieter.net/net.rieter.xot.repository/%s/%s-%s.zip" % ( addonId, addonId, addonVersion) filename = "%s-%s.zip" % (addonId, addonVersion) Logger.Info("New update found: %s @ %s", channelId, url) updates.append((url, filename)) return updates
def CtMnTestProxy(self, item): # :@UnusedVariable """ Checks if the proxy is OK""" if not self.proxy: message = "Proxy not configured: %s" % (self.proxy,) else: url = Config.UpdateUrl + "proxy" data = UriHandler.Open(url, proxy=self.proxy) # Logger.Trace(data) if data == "1": message = LanguageHelper.GetLocalizedString(LanguageHelper.ProxyOkId) % (self.proxy,) else: message = LanguageHelper.GetLocalizedString(LanguageHelper.ProxyNokId) % (self.proxy,) Logger.Debug(message) XbmcWrapper.ShowDialog("", message) pass
def Reset(): """ Resets the Vault and Retrospect Machine key, making all encrypted values useless. """ ok = XbmcWrapper.ShowYesNo(LanguageHelper.GetLocalizedString(LanguageHelper.VaultReset), LanguageHelper.GetLocalizedString(LanguageHelper.VaultResetConfirm)) if not ok: Logger.Debug("Aborting Reset Vault") return Logger.Info("Resetting the vault to a new initial state.") AddonSettings.SetSetting(Vault.__APPLICATION_KEY_SETTING, "") # create a vault instance so we initialize a new one with a new PIN. Vault() return
def set_setting(self, setting_id, setting_name=None, setting_action_id=None): """ Reads a value for a setting from the keyboard and encryptes it in the Kodi Add-on settings. The setttingActionId defaults to <settingId>_set :param str setting_id: The ID for the Kodi Add-on setting to set. :param str setting_name: The name to display in the keyboard. :param str setting_action_id: The name of the action that was called. :rtype: None """ Logger.info("Encrypting value for setting '%s'", setting_id) input_value = XbmcWrapper.show_key_board( "", LanguageHelper.get_localized_string( LanguageHelper.VaultSpecifySetting) % (setting_name or setting_id, )) if input_value is None: Logger.debug("Setting of encrypted value cancelled.") return value = "%s=%s" % (setting_id, input_value) encrypted_value = self.__encrypt(value, Vault.__Key) if setting_action_id is None: setting_action_id = "%s_set" % (setting_id, ) Logger.debug("Updating '%s' and '%s'", setting_id, setting_action_id) AddonSettings.set_setting(setting_id, encrypted_value) if input_value: AddonSettings.set_setting(setting_action_id, "******") else: AddonSettings.set_setting(setting_action_id, "") Logger.info("Successfully encrypted value for setting '%s'", setting_id) return
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 SearchSite(self, url=None): """Creates an list of items by searching the site Keyword Arguments: url : String - Url to use to search with a %s for the search parameters Returns: A list of MediaItems that should be displayed. This method is called when the URL of an item is "searchSite". The channel calling this should implement the search functionality. This could also include showing of an input keyboard and following actions. The %s the url will be replaced with an URL encoded representation of the text to search for. """ # http://www.dplay.se/api/v2/ajax/search/?q=test&items=12&types=video&video_types=episode,live # http://www.dplay.se/api/v2/ajax/search/?q=test&items=6&types=show needle = XbmcWrapper.ShowKeyBoard() if needle: Logger.Debug("Searching for '%s'", needle) needle = HtmlEntityHelper.UrlEncode(needle) url = "http://www.dplay.se/api/v2/ajax/search/?types=video&items=%s" \ "&video_types=episode,live&q=%%s&page=0" % (self.videoPageSize, ) searchUrl = url % (needle, ) temp = mediaitem.MediaItem("Search", searchUrl) episodes = self.ProcessFolderList(temp) url = "http://www.dplay.se/api/v2/ajax/search/?types=show&items=%s" \ "&q=%%s&page=0" % (self.programPageSize, ) searchUrl = url % (needle, ) temp = mediaitem.MediaItem("Search", searchUrl) shows = self.ProcessFolderList(temp) return shows + episodes return []
def LogOn(self): if self.__idToken: return True # check if there is a refresh token # refresh token: viervijfzes_refresh_token refreshToken = AddonSettings.GetSetting("viervijfzes_refresh_token") client = AwsIdp("eu-west-1_dViSsKM5Y", "6s1h851s8uplco5h6mqh1jac8m", proxy=self.proxy, logger=Logger.Instance()) if refreshToken: idToken = client.RenewToken(refreshToken) if idToken: self.__idToken = idToken return True else: Logger.Info("Extending token for VierVijfZes failed.") # username: viervijfzes_username username = AddonSettings.GetSetting("viervijfzes_username") # password: viervijfzes_password v = Vault() password = v.GetSetting("viervijfzes_password") if not username or not password: XbmcWrapper.ShowDialog( title=None, lines=LanguageHelper.GetLocalizedString( LanguageHelper.MissingCredentials), ) return False idToken, refreshToken = client.Authenticate(username, password) if not idToken or not refreshToken: Logger.Error("Error getting a new token. Wrong password?") return False self.__idToken = idToken AddonSettings.SetSetting("viervijfzes_refresh_token", refreshToken) return True