예제 #1
0
    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()
예제 #2
0
    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
예제 #3
0
    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(": "))
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
    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
예제 #7
0
    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()
예제 #8
0
    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
예제 #9
0
    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
예제 #10
0
    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
예제 #11
0
    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
예제 #12
0
    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
예제 #13
0
    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
예제 #14
0
    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 []
예제 #15
0
    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)
예제 #16
0
    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 []
예제 #17
0
    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)
예제 #18
0
    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
예제 #19
0
    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())
예제 #20
0
    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)
예제 #21
0
    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
예제 #22
0
    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)
예제 #23
0
    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
예제 #24
0
    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
예제 #25
0
    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
예제 #26
0
    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
예제 #27
0
    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
예제 #28
0
    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
예제 #29
0
    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 []
예제 #30
0
    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