コード例 #1
0
    def __get_title(self, name):
        """ Create the title based on the MediaItems name and type.

        :param str name: the name to update.

        :return: an updated name
        :rtype: str

        """

        if not name:
            name = self.name

        if self.type == 'page':
            # We need to add the Page prefix to the item
            name = "%s %s" % (LanguageHelper.get_localized_string(
                LanguageHelper.Page), name)
            Logger.debug("MediaItem.__get_title :: Adding Page Prefix")

        elif self.__date != '' and not self.is_playable(
        ) and not AddonSettings.is_min_version(18):
            # not playable items should always show date
            name = "%s [COLOR=dimgray](%s)[/COLOR]" % (name, self.__date)

        folder_prefix = AddonSettings.get_folder_prefix()
        if self.type == "folder" and not folder_prefix == "":
            name = "%s %s" % (folder_prefix, name)

        return name
コード例 #2
0
    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
コード例 #3
0
    def __update_live_video(self, item, manifest, headers):
        video_info = manifest.get_value("playable", "assets", 0)
        url = video_info["url"]
        encrypted = video_info["encrypted"]
        part = item.create_new_empty_media_part()

        if encrypted:
            use_adaptive = AddonSettings.use_adaptive_stream_add_on(with_encryption=True)
            if not use_adaptive:
                Logger.error("Cannot playback encrypted item without inputstream.adaptive with encryption support")
                return item
            stream = part.append_media_stream(url, 0)
            key = M3u8.get_license_key("", key_headers=headers, key_type="R")
            M3u8.set_input_stream_addon_input(stream, proxy=self.proxy, headers=headers, license_key=key)
            item.complete = True
        else:
            use_adaptive = AddonSettings.use_adaptive_stream_add_on(with_encryption=False)
            if use_adaptive:
                stream = part.append_media_stream(url, 0)
                M3u8.set_input_stream_addon_input(stream, self.proxy, headers=headers)
                item.complete = True
            else:
                for s, b in M3u8.get_streams_from_m3u8(url, self.proxy, headers=headers):
                    item.complete = True
                    part.append_media_stream(s, b)

        return item
コード例 #4
0
    def execute(self):
        """ Shows the current channels settings dialog. """

        if not self.__channel_info:
            Logger.warning("Cannot configure channel without channel info")

        Logger.info("Configuring channel: %s", self.__channel_info)
        AddonSettings.show_channel_settings(self.__channel_info)
コード例 #5
0
    def show_country_settings(self):
        """ Shows the country settings page where channels can be shown/hidden based on the
        country of origin. """

        if AddonSettings.is_min_version(18):
            AddonSettings.show_settings(-99)
        else:
            AddonSettings.show_settings(101)
        self.refresh()
コード例 #6
0
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_val:
            Logger.critical("Error in menu handling: %s", str(exc_val), exc_info=True)

        # make sure we leave no references behind
        AddonSettings.clear_cached_addon_settings_object()
        # close the log to prevent locking on next call
        Logger.instance().close_log()
        return False
コード例 #7
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
コード例 #8
0
    def __configure_channel(self, channel_info):
        """ Shows the current channels settings dialog.

        :param ChannelInfo channel_info:    The channel info for the channel

        """

        if not channel_info:
            Logger.warning("Cannot configure channel without channel info")

        Logger.info("Configuring channel: %s", channel_info)
        AddonSettings.show_channel_settings(channel_info)
コード例 #9
0
    def select_channels(self):
        """ Selects the channels that should be visible.

        @return: None
        """

        valid_channels = ChannelIndex.get_register().get_channels(
            include_disabled=True)
        channels_to_show = [c for c in valid_channels if c.visible]
        # The old way
        # channels_to_show = filter(lambda c: c.visible, valid_channels)

        selected_channels = [c for c in channels_to_show if c.enabled]
        selected_indices = list(
            [channels_to_show.index(c) for c in selected_channels])
        Logger.debug("Currently selected channels: %s", selected_indices)

        channel_to_show_names = [
            HtmlEntityHelper.convert_html_entities(c.channelName)
            for c in channels_to_show
        ]
        # The old way
        # channel_to_show_names = list(map(lambda c: HtmlEntityHelper.convert_html_entities(c.channelName), channels_to_show))

        dialog = xbmcgui.Dialog()
        heading = LanguageHelper.get_localized_string(
            LanguageHelper.ChannelSelection)[:-1]
        selected_channels = dialog.multiselect(heading,
                                               channel_to_show_names,
                                               preselect=selected_indices)
        if selected_channels is None:
            return

        selected_channels = list(selected_channels)
        Logger.debug("New selected channels:       %s", selected_channels)

        indices_to_remove = [
            i for i in selected_indices if i not in selected_channels
        ]
        indices_to_add = [
            i for i in selected_channels if i not in selected_indices
        ]
        for i in indices_to_remove:
            Logger.info("Hiding channel: %s", channels_to_show[i])
            AddonSettings.set_channel_visiblity(channels_to_show[i], False)

        for i in indices_to_add:
            Logger.info("Showing channel: %s", channels_to_show[i])
            AddonSettings.set_channel_visiblity(channels_to_show[i], True)

        self.refresh()
        return
コード例 #10
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()
コード例 #11
0
    def log_off(self, username):
        """ Check if the user with the given name is currently authenticated.

        :param str username:    The username to log off

        :returns: Indication of success
        :rtype: bool

        """

        # clean older data
        UriHandler.delete_cookie(domain=".sso.rtl.nl")
        AddonSettings.set_setting(self.__setting_signature, "", store=LOCAL)
        return True
コード例 #12
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()
コード例 #13
0
    def get_setting(self, setting_id):
        """ Retrieves an encrypted setting from the Kodi Add-on Settings.

        :param str setting_id: the ID for the setting to retrieve.

        :return: the decrypted value for the setting.
        :rtype: str
        """

        Logger.info("Decrypting value for setting '%s'", setting_id)
        encrypted_value = AddonSettings.get_setting(setting_id)
        if not encrypted_value:
            Logger.warning("Found empty string as encrypted data")
            return encrypted_value

        try:
            decrypted_value = self.__decrypt(encrypted_value, Vault.__Key)
            if not decrypted_value.startswith(setting_id):
                Logger.error("Invalid decrypted value for setting '%s'",
                             setting_id)
                return None

            decrypted_value = decrypted_value[len(setting_id) + 1:]
            Logger.info("Successfully decrypted value for setting '%s'",
                        setting_id)
        except UnicodeDecodeError:
            Logger.error(
                "Invalid Unicode data returned from decryption. Must be wrong data"
            )
            return None

        return decrypted_value
コード例 #14
0
    def active_authentication(self):
        """ Check if the user with the given name is currently authenticated.

        :returns: a AuthenticationResult with the account data.
        :rtype: AuthenticationResult

        """

        login_token = AddonSettings.get_setting(self.__setting_signature,
                                                store=LOCAL)

        login_cookie = UriHandler.get_cookie("gmid", domain=".sso.rtl.nl")
        if login_token and \
                login_cookie is not None and \
                not login_cookie.is_expired():
            # only retrieve the account information using the cookie and the token
            account_info_url = "https://sso.rtl.nl/accounts.getAccountInfo?{}" \
                               "&login_token={}".format(self.__common_params, login_token)
            account_info = UriHandler.open(account_info_url, no_cache=True)

            # See if it was successful
            auth_info = self.__extract_session_data(account_info)
            auth_info.existing_login = True
            return auth_info

        return AuthenticationResult(None)
コード例 #15
0
    def update_live_item(self, item):
        """ Updates an existing live MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        part = item.create_new_empty_media_part()
        if AddonSettings.use_adaptive_stream_add_on():
            stream = part.append_media_stream(item.url, 0)
            M3u8.set_input_stream_addon_input(stream, self.proxy)
            item.complete = True
        else:
            for s, b in M3u8.get_streams_from_m3u8(item.url, self.proxy):
                item.complete = True
                part.append_media_stream(s, b)
        return item
コード例 #16
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
コード例 #17
0
    def get_verifiable_video_url(self, url):
        """ Creates an RTMP(E) url that can be verified using an SWF URL.

        Returns a new URL that includes the self.swfUrl in the form of "url --swfVfy|-W swfUrl".
        If self.swfUrl == "", the original URL is returned.

        :param str url: The URL that should be made verifiable.

        :return:    A new URL that includes the self.swfUrl
        :rtype: str

        """

        if self.swfUrl == "":
            return url

        # TODO: Kodi 17.x also accepts an SWF-url as swfvfy option (https://www.ffmpeg.org/ffmpeg-protocols.html#rtmp).
        # This option should be set via the XbmcListItem.setProperty, so within Retrospect via:
        #   part.add_property("swfvfy", self.swfUrl)
        # Or as an URL parameter swfvfy where we add the full URL instead of just 1:
        #   return "%s swfvfy=%s" % (url, self.swfUrl)

        if AddonSettings.is_min_version(17):
            Logger.debug("Using Kodi 17+ RTMP parameters")
            return "%s swfvfy=%s" % (url, self.swfUrl)
        else:
            Logger.debug("Using Legacy (Kodi 16 and older) RTMP parameters")
            return "%s swfurl=%s swfvfy=1" % (url, self.swfUrl)
コード例 #18
0
    def update_json_video_item(self, item):
        """ Updates an existing MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        headers = {}
        if self.localIP:
            headers.update(self.localIP)

        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=headers)
        video_data = JsonHelper(data)
        stream_data = video_data.get_value("mediaAssetsOnDemand")
        if not stream_data:
            return item

        use_adaptive = AddonSettings.use_adaptive_stream_add_on()
        stream_data = stream_data[0]
        part = item.create_new_empty_media_part()
        if "hlsUrl" in stream_data:
            hls_url = stream_data["hlsUrl"]
            if use_adaptive:
                stream = part.append_media_stream(hls_url, 0)
                M3u8.set_input_stream_addon_input(stream,
                                                  self.proxy,
                                                  headers=headers)
                item.complete = True
            else:
                for s, b in M3u8.get_streams_from_m3u8(hls_url,
                                                       self.proxy,
                                                       headers=headers):
                    item.complete = True
                    part.append_media_stream(s, b)

        if "timedTextSubtitlesUrl" in stream_data and stream_data[
                "timedTextSubtitlesUrl"]:
            sub_url = stream_data["timedTextSubtitlesUrl"].replace(
                ".ttml", ".vtt")
            sub_url = HtmlEntityHelper.url_decode(sub_url)
            part.Subtitle = SubtitleHelper.download_subtitle(sub_url,
                                                             format="webvtt")
        return item
コード例 #19
0
    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
コード例 #20
0
    def __set_proxy(self, language, proxy_id, local_ip):
        """ Sets the proxy and local IP configuration for channels.

        :param str language:    The language for what channels to update.
        :param int proxy_id:    The proxy index to use.
        :param int local_ip:    The local_ip index to use.
        
        If no proxy_id is specified (None) then the proxy_id will be determined based on language
        If no local_ip is specified (None) then the local_ip will be determined based on language
        
        """

        languages = AddonSettings.get_available_countries(
            as_country_codes=True)

        if language is not None and language not in languages:
            Logger.warning("Missing language: %s", language)
            return

        if proxy_id is None:
            proxy_id = languages.index(language)
        else:
            # noinspection PyTypeChecker
            proxy_id = int(proxy_id)

        if local_ip is None:
            local_ip = languages.index(language)
        else:
            # noinspection PyTypeChecker
            local_ip = int(local_ip)

        channels = ChannelIndex.get_register().get_channels()
        Logger.info(
            "Setting proxy='%s' (%s) and local_ip='%s' (%s) for country '%s'",
            proxy_id, languages[proxy_id], local_ip, languages[local_ip],
            language)

        channels_in_country = [
            c for c in channels if c.language == language or language is None
        ]
        for channel in channels_in_country:
            Logger.debug("Setting Proxy for: %s", channel)
            AddonSettings.set_proxy_id_for_channel(channel, proxy_id)
            if channel.localIPSupported:
                Logger.debug("Setting Local IP for: %s", channel)
                AddonSettings.set_local_ip_for_channel(channel, local_ip)
コード例 #21
0
    def update_part_with_m3u8_streams(part,
                                      url,
                                      encrypted=False,
                                      headers=None,
                                      map_audio=False,
                                      bitrate=0,
                                      channel=None):
        """ Updates an existing MediaItemPart with M3u8 data either using the Adaptive Inputstream 
        Add-on or with the built-in code.

        :param MediaItemPart part:      The part to update
        :param str url:                 The url to download
        :param bool encrypted:          Is the stream encrypted?
        :param dict[str,str] headers:   Possible HTTP Headers
        :param bool map_audio:          Should audio tracks be mapped separately?
        :param int bitrate:             Initial bitrate to use. Will be overridden later.
        :param ChannelInfo channel:     If specified, the channel specific configuration is
                                        considered.

        :return: indication if updating was successful.
        :rtype: bool

        """

        input_stream = AddonSettings.use_adaptive_stream_add_on(
            encrypted, channel=channel)
        if not input_stream and encrypted:
            Logger.error(
                "Cannot play encrypted stream without InputStream Adaptive with Encryption support!"
            )
            return False

        if input_stream:
            Logger.debug(
                "Using InputStream Adaptive add-on for M3u8 playback.")
            stream = part.append_media_stream(url, bitrate)
            M3u8.set_input_stream_addon_input(stream, headers)
            return True

        complete = False
        if map_audio:
            Logger.debug(
                "Using Retrospect code with Audio mapping for M3u8 playback.")
            for s, b, a in M3u8.get_streams_from_m3u8(url, map_audio=True):
                if a:
                    audio_part = a.rsplit("-", 1)[-1]
                    audio_part = "-%s" % (audio_part, )
                    s = s.replace(".m3u8", audio_part)
                part.append_media_stream(s, b)
                complete = True
        else:
            Logger.debug("Using Retrospect code for M3u8 playback.")
            for s, b in M3u8.get_streams_from_m3u8(url):
                part.append_media_stream(s, b)
                complete = True

        return complete
コード例 #22
0
    def __extract_session_data(self, logon_data):
        """

        :param logon_data:
        :return:
        :rtype: AuthenticationResult

        """

        logon_json = json.loads(logon_data)
        result_code = logon_json.get("statusCode")
        Logger.trace("Logging in returned: %s", result_code)
        if result_code != 200:
            Logger.error("Error loging in: %s - %s",
                         logon_json.get("errorMessage"),
                         logon_json.get("errorDetails"))
            return AuthenticationResult(None)

        user_name = logon_json.get("profile", {}).get("email") or None

        signature_setting = logon_json.get("sessionInfo",
                                           {}).get("login_token")
        if signature_setting:
            Logger.info("Found 'login_token'. Saving it.")
            AddonSettings.set_setting(self.__setting_signature,
                                      signature_setting.split("|")[0],
                                      store=LOCAL)

        self.__signature = logon_json.get("UIDSignature")
        self.__user_id = logon_json.get("UID")
        self.__signature_timestamp = logon_json.get("signatureTimestamp")

        # TODO: is this correct?
        has_premium = logon_json.\
            get("data", {}).\
            get("authorization", {}).\
            get("rtlxl_premium", {}).\
            get("subscription", {}).\
            get("id") == "premium"

        # The channels are not interesting
        # premium_channels = logon_json.get_value(
        #     "data", "authorization", "Stievie_free", "channels")
        return AuthenticationResult(user_name, has_premium=has_premium)
コード例 #23
0
    def _get_current_user_in_settings(self):
        """ Retrieves the current user in the local settings.

        Can be used if there is no other means of retrieving the currently authenticated user.

        """

        store = AddonSettings.store(LOCAL)
        return store.get_setting("{}:authenticated_user".format(self._realm),
                                 default=None)
コード例 #24
0
    def __show_empty_information(self, items, favs=False):
        """ Adds an empty item to a list or just shows a message.
        @type favs: boolean
        @param items:

        :param list[MediaItem] items:   The list of items.
        :param bool favs:               Indicating that we are dealing with favourites.

        :return: boolean indicating to report the listing as succes or not.
        :rtype: ok

        """

        if favs:
            title = LanguageHelper.get_localized_string(LanguageHelper.NoFavsId)
        else:
            title = LanguageHelper.get_localized_string(LanguageHelper.ErrorNoEpisodes)

        behaviour = AddonSettings.get_empty_list_behaviour()

        Logger.debug("Showing empty info for mode (favs=%s): [%s]", favs, behaviour)
        if behaviour == "error":
            # show error
            ok = False
        elif behaviour == "dummy" and not favs:
            # We should add a dummy items, but not for favs
            empty_list_item = MediaItem("- %s -" % (title.strip("."), ), "", type='video')
            if self.channelObject:
                empty_list_item.icon = self.channelObject.icon
                empty_list_item.thumb = self.channelObject.noImage
                empty_list_item.fanart = self.channelObject.fanart
            else:
                icon = Config.icon
                fanart = Config.fanart
                empty_list_item.icon = icon
                empty_list_item.thumb = fanart
                empty_list_item.fanart = fanart

            empty_list_item.dontGroup = True
            empty_list_item.description = "This listing was left empty intentionally."
            empty_list_item.complete = True
            # add funny stream here?
            # part = empty_list_item.create_new_empty_media_part()
            # for s, b in YouTube.get_streams_from_you_tube("", self.channelObject.proxy):
            #     part.append_media_stream(s, b)

            # if we add one, set OK to True
            ok = True
            items.append(empty_list_item)
        else:
            ok = True

        XbmcWrapper.show_notification(LanguageHelper.get_localized_string(LanguageHelper.ErrorId),
                                      title, XbmcWrapper.Error, 2500)
        return ok
コード例 #25
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
コード例 #26
0
    def create_json_video_item(self, result_set):
        """ Creates a MediaItem of type 'video' using the result_set from the regex.

        This method creates a new MediaItem from the Regular Expression or Json
        results <result_set>. The method should be implemented by derived classes
        and are specific to the channel.

        If the item is completely processed an no further data needs to be fetched
        the self.complete property should be set to True. If not set to True, the
        self.update_video_item method is called if the item is focussed or selected
        for playback.

        :param list[str]|dict[str,any] result_set: The result_set of the self.episodeItemRegex

        :return: A new MediaItem of type 'video' or 'audio' (despite the method's name).
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)
        url = "http://playapi.mtgx.tv/v3/videos/stream/%(id)s" % result_set
        item = MediaItem(result_set["title"], url)
        item.type = "video"
        item.thumb = self.parentItem.thumb
        item.icon = self.parentItem.icon
        item.description = result_set.get("summary", None)

        aired_at = result_set.get("airedAt", None)
        if aired_at is None:
            aired_at = result_set.get("publishedAt", None)
        if aired_at is not None:
            # 2016-05-20T15:05:00+00:00
            aired_at = aired_at.split("+")[0].rstrip('Z')
            time_stamp = DateHelper.get_date_from_string(
                aired_at, "%Y-%m-%dT%H:%M:%S")
            item.set_date(*time_stamp[0:6])

        item.thumb = self.__get_thumb_image(result_set.get("image"))

        # webvttPath / samiPath
        # loginRequired
        is_premium = result_set.get("loginRequired", False)
        if is_premium and AddonSettings.hide_premium_items():
            Logger.debug("Found premium item, hiding it.")
            return None

        srt = result_set.get("samiPath")
        if not srt:
            srt = result_set.get("subtitles_webvtt")
        if srt:
            Logger.debug("Storing SRT/WebVTT path: %s", srt)
            part = item.create_new_empty_media_part()
            part.Subtitle = srt
        return item
コード例 #27
0
    def set_inputstream_adaptive(self):
        """ Set the InputStream Adaptive for this channel """

        if self.channelObject is None:
            raise ValueError("Missing channel")

        if not self.channelObject.adaptiveAddonSelectable:
            Logger.warning(
                "Cannot set InputStream Adaptive add-on mode for %s",
                self.channelObject)
            return

        current_mode = AddonSettings.get_adaptive_mode(self.channelObject)
        mode_values = [None, True, False]
        current_index = mode_values.index(current_mode)
        mode_options = [
            LanguageHelper.get_localized_string(LanguageHelper.Retrospect),
            LanguageHelper.get_localized_string(LanguageHelper.Enabled),
            LanguageHelper.get_localized_string(LanguageHelper.Disabled)
        ]

        dialog = xbmcgui.Dialog()
        heading = LanguageHelper.get_localized_string(
            LanguageHelper.ChannelAdaptiveMode)
        selected_index = dialog.select(heading,
                                       mode_options,
                                       preselect=current_index)
        if selected_index < 0:
            return
        selected_value = mode_values[selected_index]

        Logger.info("Changing InputStream Adaptive mode for %s from %s to %s",
                    self.channelObject, mode_options[current_index],
                    mode_options[selected_index])

        AddonSettings.set_adaptive_mode(self.channelObject, selected_value)

        # Refresh if we have a video item selected, so the cached urls are removed.
        if self.keywordPickle in self.params:
            Logger.debug("Refreshing list to clear URL caches")
            self.refresh()
コード例 #28
0
    def _store_current_user_in_settings(self, username):
        """ Store the current user in the local settings.

        :param str|None username: The currently authenticated user

        Can be used if there is no other means of retrieving the currently authenticated user.

        """

        store = AddonSettings.store(LOCAL)
        store.set_setting("{}:authenticated_user".format(self._realm),
                          username)
コード例 #29
0
    def __show_howto(self, force=False):
        """ Shows the Vault howto if it was not already shown.

        :param bool force:  Force the howto to show

        :returns: indicator if the howto was shown
        :rtype: bool

        """

        if not force:
            vault_shown = AddonSettings.store(LOCAL).get_boolean_setting(
                Vault.__VAULT_HOWTO_SETTING, default=False)
            if vault_shown:
                return False

        XbmcWrapper.show_text(LanguageHelper.VaultHowToTitle,
                              LanguageHelper.VaultHowToText)
        AddonSettings.store(LOCAL).set_setting(Vault.__VAULT_HOWTO_SETTING,
                                               True)
        return True
コード例 #30
0
    def update_video_item(self, item):
        """ Updates an existing MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        headers = {}
        if self.localIP:
            headers.update(self.localIP)

        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=headers)
        m3u8_url = Regexer.do_regex('data-file="([^"]+)"', data)[0]

        part = item.create_new_empty_media_part()
        if AddonSettings.use_adaptive_stream_add_on(with_encryption=False):
            stream = part.append_media_stream(m3u8_url, 0)
            M3u8.set_input_stream_addon_input(stream,
                                              proxy=self.proxy,
                                              headers=headers)
            item.complete = True
        else:
            for s, b, a in M3u8.get_streams_from_m3u8(m3u8_url,
                                                      self.proxy,
                                                      headers=headers,
                                                      map_audio=True):

                if a and "-audio" not in s:
                    video_part = s.rsplit("-", 1)[-1]
                    video_part = "-%s" % (video_part, )
                    s = a.replace(".m3u8", video_part)
                part.append_media_stream(s, b)
                item.complete = True

        return item