コード例 #1
0
    def remove(self, item):
        """ Adds a favourite for a specific channel

        :param item:          The mediaitem

        """

        path_mask = os.path.join(self.FavouriteFolder,
                                 "*-%s.xotfav" % (item.guid, ))

        Logger.debug("Removing favourites for mask: %s", path_mask)
        for fav in glob.glob(path_mask):
            Logger.trace("Removing item %s\nFileName: %s", item, fav)
            os.remove(fav)
        return
コード例 #2
0
    def __extract_json_data(self, data, root):
        """ Performs pre-process actions for data processing

        :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("Extracting JSON data during pre-processing")
        data = Regexer.do_regex(r'root\[[\'"]%s[\'"]\] = ([\w\W]+?);\W*root\[' % (root,), data)[-1]
        items = []
        Logger.trace("JSON data found: %s", data)
        return data, items
コード例 #3
0
    def __get_compiled_regex(regex):
        """
        @param regex: The input regex to fetch a compiled version from
        @return: a compiled regex
        """

        if regex in Regexer.__compiledRegexes:
            Logger.debug("Re-using cached Compiled Regex object")
            compiled_regex = Regexer.__compiledRegexes[regex]
        else:
            Logger.trace("Compiling Regex object and storing in cache")
            compiled_regex = re.compile(regex, re.DOTALL + re.IGNORECASE)
            Regexer.__compiledRegexes[regex] = compiled_regex

        return compiled_regex
コード例 #4
0
    def cache_clean_up(path, cache_time, mask="*.*"):
        """Cleans up the XOT cache folder.

        Check the cache files create timestamp and compares it with the current datetime extended
        with the amount of seconds as defined in cacheTime.

        Expired items are deleted.
        :param str path:        The cache path to clean.
        :param int cache_time:  The minimum (in seconds) of files that will be deleted.
        :param str mask:        The file mask to consider when cleaning the cache.

        """

        # let's import htis one here
        import fnmatch

        try:
            Logger.info("Cleaning up cache in '%s' that is older than %s days",
                        os.path.join(path, "**", mask), cache_time / 24 / 3600)

            if not os.path.exists(path):
                Logger.info("Did not cleanup cache: folder does not exist")
                return

            delete_count = 0
            file_count = 0

            #for item in os.listdir(path):
            current_dir = None
            for root, dirs, files in os.walk(path):
                if current_dir != root:
                    Logger.debug("Cleaning cache folder: %s", root)
                    current_dir = root

                for basename in files:
                    if fnmatch.fnmatch(basename, mask):
                        filename = os.path.join(root, basename)
                        Logger.trace("Inspecting: %s", filename)
                        file_count += 1
                        create_time = os.path.getctime(filename)
                        if create_time + cache_time < time.time():
                            os.remove(filename)
                            Logger.debug("Removed file: %s", filename)
                            delete_count += 1

            Logger.info("Removed %s of %s files from cache in: '%s'", delete_count, file_count, path)
        except:
            Logger.critical("Error cleaning the cachefolder: %s", path, exc_info=True)
コード例 #5
0
    def create_page_item(self, result_set):
        """ Creates a MediaItem of type 'page' using the result_set from the regex.

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

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

        :return: A new MediaItem of type 'page'.
        :rtype: MediaItem|None

        """

        if "totalPages" not in result_set:
            return None

        Logger.debug("Starting create_page_item")

        # current page?
        page_uri_part = "page%5Bnumber%5D="
        if page_uri_part not in self.parentItem.url:
            page = 1
            url_format = "{0}&page%5Bnumber%5D={{0:d}}".format(
                self.parentItem.url)
        else:
            base_url, page_part = self.parentItem.url.rsplit(page_uri_part, 1)
            next_part = page_part.find("&")
            if next_part < 0:
                # end
                page = int(page_part)
                url_format = "{0}&page%5Bnumber%5D={{0:d}}".format(base_url)
            else:
                page = int(page_part[0:next_part])
                url_format = "{0}&page%5Bnumber%5D={{0:d}}&{1}".format(
                    base_url, page_part[next_part:])

        max_pages = result_set.get("totalPages", 0)
        Logger.trace("Current Page: %d of %d (%s)", page, max_pages,
                     self.parentItem.url)

        if page + 1 > max_pages:
            return None

        title = LanguageHelper.get_localized_string(LanguageHelper.MorePages)
        url = url_format.format(page + 1)
        item = MediaItem(title, url)
        return item
コード例 #6
0
    def create_episode_item_json(self, result_set):
        """ Creates a new MediaItem for an episode.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)

        # add  { to make it valid Json again. if it would be in the regex it would
        # not find all items
        # data = JsonHelper("{%s" % (result_set,))

        # title
        local_title = result_set.get("local_title")
        original_title = result_set.get("original_name")
        if local_title == "" or local_title is None:
            title = original_title
        elif original_title != local_title:
            title = "%s (%s)" % (local_title, original_title)
        else:
            title = local_title

        # the URL
        serie_id = result_set["id"]
        url = "%sepisodes.json?per=2147483647&franchise_id=%s" % (
            self.mainListUri[0:43], serie_id)

        item = MediaItem(title, url)
        item.complete = True

        # thumbs
        if "image" in result_set and result_set["image"] is not None:
            # noinspection PyTypeChecker
            thumb = result_set["image"]["riptide_image_id"]
            thumb = "http://images.mtvnn.com/%s/original" % (thumb, )
            item.thumb = thumb

        # others
        item.description = result_set["local_long_description"]
        return item
コード例 #7
0
    def add_seasons(self, data, items):
        """ Performs post-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|JsonHelper data:     The retrieve data that was loaded for the
                                         current item and URL.
        :param list[MediaItem] items:   The currently available items

        :return: A tuple of the data and a list of MediaItems that were generated.
        :rtype: list[MediaItem]

        """

        Logger.info("Performing Post-Processing")

        if not self.parentItem or "guid" not in self.parentItem.metaData:
            return items

        existing_seasons = set([i.metaData.get("season_id") for i in items])
        if not existing_seasons:
            return items

        item_id = self.parentItem.metaData["guid"]
        season_info_url = "http://www.mtv.nl/feeds/intl_m308/V8_0_0/{0}/{1}/{1}".\
            format(self.__season_list_id, item_id)
        season_data = UriHandler.open(season_info_url)
        season_info = JsonHelper(season_data)

        for season in season_info.get_value("result", "data", "seasons", fallback=[]):
            Logger.trace("Found season: %s", season)
            season_id = season["id"]
            if season_id in existing_seasons:
                Logger.trace("Season is current season")
                continue

            url = "{}/feeds/intl_m112/V8_0_0/{}/{}/{}"\
                .format(self.baseUrl, self.__show_list_id, item_id, season_id)
            season_item = MediaItem(season["eTitle"], url)
            items.append(season_item)

        Logger.debug("Post-Processing finished")
        return items
コード例 #8
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

        """

        Logger.debug('Starting update_video_item for %s (%s)', item.name,
                     self.channelName)

        if not item.url.endswith("m3u8"):
            data = UriHandler.open(item.url, proxy=self.proxy)
            json_data = Regexer.do_regex(self.mediaUrlRegex, data)
            if not json_data:
                Logger.error("Cannot find JSON stream info.")
                return item

            json = JsonHelper(json_data[0])
            Logger.trace(json.json)
            stream = json.get_value("source", "hls")
            if stream is None:
                stream = json.get_value("mzsource", "hls")
            Logger.debug("Found HLS: %s", stream)
        else:
            stream = item.url

        part = item.create_new_empty_media_part()
        for s, b in M3u8.get_streams_from_m3u8(stream, self.proxy):
            item.complete = True
            part.append_media_stream(s, b)

        # var playerConfig = {"id":"mediaplayer","width":"100%","height":"100%","autostart":"false","image":"http:\/\/www.ketnet.be\/sites\/default\/files\/thumb_5667ea22632bc.jpg","brand":"ketnet","source":{"hls":"http:\/\/vod.stream.vrt.be\/ketnet\/_definst_\/mp4:ketnet\/2015\/12\/Ben_ik_familie_van_R001_A0023_20151208_143112_864.mp4\/playlist.m3u8"},"analytics":{"type_stream":"vod","playlist":"Ben ik familie van?","program":"Ben ik familie van?","episode":"Ben ik familie van?: Warre - Aflevering 3","parts":"1","whatson":"270157835527"},"title":"Ben ik familie van?: Warre - Aflevering 3","description":"Ben ik familie van?: Warre - Aflevering 3"}
        return item
コード例 #9
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

        """

        from resources.lib.streams.m3u8 import M3u8

        Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName)

        meta_data = UriHandler.open(item.url, referer=self.baseUrl)
        meta = JsonHelper(meta_data)
        stream_parts = meta.get_value("feed", "items")
        for stream_part in stream_parts:
            stream_url = stream_part["group"]["content"]
            stream_url = stream_url.replace("&device={device}", "")
            stream_url = "%s&format=json&acceptMethods=hls" % (stream_url, )
            stream_data = UriHandler.open(stream_url)
            stream = JsonHelper(stream_data)

            # subUrls = stream.get_value("package", "video", "item", 0, "transcript", 0, "typographic")  # NOSONAR
            part = item.create_new_empty_media_part()

            hls_streams = stream.get_value("package", "video", "item", 0, "rendition")
            for hls_stream in hls_streams:
                hls_url = hls_stream["src"]
                item.complete |= M3u8.update_part_with_m3u8_streams(part, hls_url)

        item.complete = True
        Logger.trace("Media url: %s", item)
        return item
コード例 #10
0
    def get_tag_attribute(self, tag, *args, **kwargs):
        """Gets the content of an specific attribute of an HTML <tag>
        
        Arguments:
        tag    : string     - name of tag to search for.
        **args : dictionary - each argument is interpreted as a html 
                              attribute. 'cls' is translated to class 
                              attribute. The attribute with value None 
                              is retrieved.
        
        Keyword Arguments:
        firstOnly : [opt] boolean - only return the first result. Default: True
        
        Returns:
        The content of the attribute of the found tag. If no match is found 
        an empty string is returned.
        
        Example: ('div', {'cls':'test'}, {'id':'divTest'}, {'width':None}, {'alt':'test'}) will match 
        <div class="test" id="divTest" width="20" alt="test">...content...</div> and 
        will return 20. 
        
        """

        first_only = True
        if list(kwargs.keys()).count("firstOnly") > 0:
            first_only = kwargs["firstOnly"]
            Logger.trace("Setting 'firstOnly' to '%s'", first_only)

        html_regex = '<%s' % (tag, )

        for arg in args:
            name = list(arg.keys())[0]
            value = arg[list(arg.keys())[0]]
            Logger.trace("Name: %s, Value: %s", name, value)

            # to keep working with older versions where class could not be passed
            if name == "cls":
                name = "class"

            if value is None:
                html_regex += r'[^>]*%s\W*=\W*["\']([^"\']+)["\']' % (name, )
            else:
                html_regex += r'[^>]*%s\W*=\W*["\']%s["\']' % (name, value)

        html_regex += "[^>]*>"
        Logger.trace("HtmlRegex = %s", html_regex)

        result = Regexer.do_regex(html_regex, self.data)
        Logger.trace(result)

        if len(result) > 0:
            if first_only:
                return result[0].strip()
            else:
                return result
        else:
            return ""
コード例 #11
0
    def create_episode_item(self, result_set):
        """ Creates a new MediaItem for an episode.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        # Logger.Trace(result_set)
        json = result_set
        title = json["name"]

        program_id = json["nid"]
        program_id = HtmlEntityHelper.url_encode(program_id)
        url = "https://api.tv4play.se/play/video_assets" \
              "?platform=tablet&per_page=%s&is_live=false&type=episode&" \
              "page=1&node_nids=%s&start=0" % (self.maxPageSize, program_id, )

        if "channel" in json and json["channel"]:
            # noinspection PyTypeChecker
            channel_id = json["channel"]["nid"]
            Logger.trace("ChannelId found: %s", channel_id)
        else:
            channel_id = "tv4"
            Logger.warning("ChannelId NOT found. Assuming %s", channel_id)

        # match the exact channel or put them in TV4
        is_match_for_channel = channel_id.startswith(self.__channelId)
        is_match_for_channel |= self.channelCode == "tv4se" and not channel_id.startswith(
            "sjuan") and not channel_id.startswith("tv12")
        if not is_match_for_channel:
            Logger.debug("Channel mismatch for '%s': %s vs %s", title,
                         channel_id, self.channelCode)
            return None

        item = MediaItem(title, url)
        item.icon = self.icon
        item.thumb = result_set.get("program_image", self.noImage)
        item.fanart = result_set.get("program_image", self.fanart)
        item.isPaid = result_set.get("is_premium", False)
        return item
コード例 #12
0
    def __get_kodi_favourites(self, addon_id):
        """ Retrieves the PickleStore ID's corresponding to Kodi Favourites using the json RPC

        :return: A set of PickleStore ID's
        :rtype: set(str)

        """

        import json
        import xbmc

        # Use a set() for performance
        favourite_pickle_stores = set()

        # Do the RPC
        req = {
            "jsonrpc": "2.0",
            "method": "Favourites.GetFavourites",
            "params": [None, ["path", "windowparameter"]],
            "id": 1
        }
        rpc_result = xbmc.executeJSONRPC(json.dumps(req))
        Logger.trace("PickleStore: Received favourites '%s'", rpc_result)
        rpc_result_data = json.loads(rpc_result)
        favourites = rpc_result_data.get("result", {}).get("favourites")
        if not favourites:
            return favourite_pickle_stores

        # Start of the add-on url
        addon_url = "plugin://{}".format(addon_id)

        for fav in favourites:
            fav_name = fav.get("title", "")
            fav_path = fav.get("path", fav.get("windowparameter")) or ""
            if not fav_path.startswith(addon_url):
                continue

            # Is it a favourite with a PickleStore ID?
            pickle_store_id = Regexer.do_regex(
                r"pickle=([^&]+){}[^&]+".format(Pickler.__store_separator), fav_path)
            if not pickle_store_id:
                continue

            Logger.debug("PickleStore: Found favourite: %s (%s)", fav_name, fav_path)
            favourite_pickle_stores.add(pickle_store_id[0].lower())

        return favourite_pickle_stores
コード例 #13
0
    def create_video_item_json(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 dict 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)

        image_data = result_set.get("media", [])
        thumb = None
        url = None
        for image in image_data:
            thumb = image.get("imageHigh", image["image"])
            url = image.get("url")

        item = MediaItem(result_set["title"], url)
        item.type = "video"
        item.icon = self.icon
        item.thumb = thumb or self.noImage
        item.complete = True
        item.description = result_set.get("text")
        part = item.create_new_empty_media_part()
        M3u8.update_part_with_m3u8_streams(part,
                                           url,
                                           proxy=self.proxy,
                                           channel=self)

        # Let's not do the time now
        time_stamp = result_set["created"]
        date_time = DateHelper.get_date_from_posix(time_stamp)
        item.set_date(date_time.year, date_time.month, date_time.day,
                      date_time.hour, date_time.minute, date_time.second)
        return item
コード例 #14
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 dict 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)
        meta = result_set["meta"]
        name = meta["header"]["title"]
        if isinstance(name, dict):
            name = name["text"]

        sub_heading = meta.get("subHeader")
        if sub_heading:
            name = "{} - {}".format(name, sub_heading)

        url = "{}{}".format(self.baseUrl, result_set["url"])
        item = MediaItem(name, url)
        item.type = "video"
        item.description = meta.get("description")
        item.thumb = result_set.get("media", {}).get("image", {}).get("url")
        item.isGeoLocked = True

        date_value = meta["date"]
        if "." in date_value:
            date = DateHelper.get_date_from_string(date_value,
                                                   date_format="%d.%m.%Y")
        else:
            date = DateHelper.get_date_from_string(date_value,
                                                   date_format="%d/%m/%Y")
        item.set_date(*date[0:6])

        return item
コード例 #15
0
    def create_api_typed_item(self, result_set, add_parent_title=False):
        """ Creates a new MediaItem based on the __typename attribute.

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

        :param list[str]|dict result_set: The result_set of the self.episodeItemRegex
        :param bool add_parent_title: Should the parent's title be included?

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        api_type = result_set["__typename"]
        Logger.trace("%s: %s", api_type, result_set)

        if api_type == "TvSeries":
            item = self.create_api_tvserie_type(result_set)
        elif api_type == "Selection":
            item = self.create_api_selection_type(result_set)
        elif api_type == "Teaser":
            item = self.create_api_teaser_type(result_set)
        elif api_type == "Genre":
            item = self.create_api_genre_type(result_set)
        elif api_type == "TvShow" or api_type == "KidsTvShow":
            item = self.create_api_tvshow_type(result_set)

        # Search Result
        elif api_type == "SearchHit":
            item = self.create_api_typed_item(result_set["item"],
                                              add_parent_title=True)

        # Video items
        elif api_type == "Single":
            item = self.create_api_single_type(result_set)
        elif api_type == "Clip" or api_type == "Trailer":
            item = self.create_api_clip_type(result_set)
        elif api_type == "Episode" or api_type == "Variant":
            item = self.create_api_episode_type(result_set, add_parent_title)
        else:
            Logger.warning("Missing type: %s", api_type)
            return None

        return item
コード例 #16
0
    def create_episode_item_json(self, result_set):
        """ Creates a new MediaItem for an episode.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)

        time_stamp = result_set["created"]
        if time_stamp <= 1420070400:
            # older items don't have videos for now
            return None

        url = "{}/api/article/{}".format(self.baseUrl,
                                         result_set["externalId"])
        item = MediaItem(result_set["title"], url)
        item.description = HtmlHelper.to_text(result_set.get("text"))

        date_time = DateHelper.get_date_from_posix(time_stamp)
        item.set_date(date_time.year, date_time.month, date_time.day)

        # noinspection PyTypeChecker
        image_data = result_set.get("media", [])
        video_url = None
        for image in image_data:
            item.thumb = image.get("imageHigh", image.get("image"))
            video_url = image.get("url")

        # In some cases the main list only has videos
        if result_set.get("video", False):
            if video_url is None:
                return None

            item.type = "video"
            item.url = video_url

        return item
コード例 #17
0
    def create_folder_item(self, result_set):
        """ Creates a MediaItem of type 'folder' using the result_set from the regex.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """
        Logger.trace(result_set)

        if "/sk=" in self.parentItem.url:
            return None

        abstract_key = result_set["abstract_key"]
        abstract_data = self.abstracts.get(abstract_key, None)
        if not abstract_data:
            Logger.warning("Could not find abstract data for key: %s",
                           abstract_key)
            return None

        Logger.debug("Found Abstract Data: %s", abstract_data)

        abstract_name = abstract_data.get("name", "")
        title = result_set["name"]
        if abstract_name:
            title = "%s - %s" % (abstract_name, title)

        description = result_set.get("synopsis", None)
        key_value = result_set["key"]
        url = "http://www.rtl.nl/system/s4m/vfd/version=1/d=pc/output=json/ak=%s/sk=%s/pg=1" % (
            abstract_key, key_value)

        item = MediaItem(title.title(), url)
        item.description = description
        item.thumb = "%s/%s.png" % (
            self.posterBase,
            key_value,
        )
        item.complete = True
        return item
コード例 #18
0
    def update_live_item(self, item):
        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=item.HttpHeaders)
        media_regex = 'data-media="([^"]+)"'
        media_info = Regexer.do_regex(media_regex, data)[0]
        media_info = HtmlEntityHelper.convert_html_entities(media_info)
        media_info = JsonHelper(media_info)
        Logger.trace(media_info)
        part = item.create_new_empty_media_part()

        hls_url = media_info.get_value("streamUrl")
        if hls_url is not None and "m3u8" in hls_url:
            Logger.debug("Found HLS url for %s: %s",
                         media_info.json["streamName"], hls_url)

            for s, b in M3u8.get_streams_from_m3u8(hls_url, self.proxy):
                part.append_media_stream(s, b)
                item.complete = True
        else:
            Logger.debug("No HLS url found for %s. Fetching RTMP Token.",
                         media_info.json["streamName"])
            # fetch the token:
            token_url = "%s/api/media/streaming?streamname=%s" \
                        % (self.baseUrl, media_info.json["streamName"])

            token_data = UriHandler.open(token_url,
                                         proxy=self.proxy,
                                         additional_headers=item.HttpHeaders,
                                         no_cache=True)

            token_data = JsonHelper(token_data)
            token = token_data.get_value("token")
            Logger.debug("Found token '%s' for '%s'", token,
                         media_info.json["streamName"])

            rtmp_url = "rtmp://rtmp.rtbf.be/livecast/%s?%s pageUrl=%s tcUrl=rtmp://rtmp.rtbf.be/livecast" \
                       % (media_info.json["streamName"], token, self.baseUrl)
            rtmp_url = self.get_verifiable_video_url(rtmp_url)
            part.append_media_stream(rtmp_url, 0)
            item.complete = True

        item.isGeoLocked = not media_info.get_value(
            "geoLocRestriction", fallback="world") == "world"
        return item
コード例 #19
0
    def __init__(self, url, bitrate=0, *args):
        """Initialises a new MediaStream

        :param str url:                 The URL of the stream.
        :param int|str bitrate:         The bitrate of the stream (defaults to 0).
        :param tuple[str,str] args:     (name, value) for any stream property.

        """

        Logger.trace("Creating MediaStream '%s' with bitrate '%s'", url, bitrate)
        self.Url = url
        self.Bitrate = int(bitrate)
        self.Properties = []
        self.Adaptive = False

        for prop in args:
            self.add_property(prop[0], prop[1])
        return
コード例 #20
0
    def create_clip_item_json(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 dict 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)

        # get the title
        title = result_set["title"]
        mgid = result_set["id"]

        url = "https://media-utils.mtvnservices.com/services/MediaGenerator/" \
              "mgid:arc:video:{}:{}" \
              "?arcStage=live&format=json&acceptMethods=hls&clang=nl" \
              "&https=true".format(self.__country_id, mgid)

        item = MediaItem(title, url)
        item.type = "video"

        if "images" in result_set:
            item.thumb = result_set["images"]["url"]

        if "airDate" not in result_set:
            return item

        air_date = int(result_set["airDate"])
        date_stamp = DateHelper.get_date_from_posix(air_date, self.__timezone_utc)
        item.set_date(date_stamp.year, date_stamp.month, date_stamp.day)

        return item
コード例 #21
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)
コード例 #22
0
    def create_folder_item(self, result_set):
        """ Creates a MediaItem of type 'folder' using the result_set from the regex.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)

        # Validate the input and raise errors
        if not isinstance(result_set, dict):
            Logger.critical(
                "No Dictionary as a result_set. Implement a custom create_video_item"
            )
            raise NotImplementedError(
                "No Dictionary as a result_set. Implement a custom create_video_item"
            )

        elif "title" not in result_set or "url" not in result_set:
            Logger.warning("No ?P<title> or ?P<url> in result_set")
            raise LookupError("No ?P<title> or ?P<url> in result_set")

        # The URL
        url = self._prefix_urls(result_set["url"])

        # The title
        title = result_set["title"]
        if title.isupper():
            title = title.title()

        item = MediaItem(title, url)
        item.description = result_set.get("description", "")
        item.thumb = result_set.get("thumburl", "")
        item.type = 'folder'
        item.HttpHeaders = self.httpHeaders
        item.complete = True
        return item
コード例 #23
0
    def create_video_item_old(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,str] 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)

        thumb_url = result_set[1]
        url = "%s%s" % (self.baseUrl, result_set[2])
        title = result_set[6]

        item = MediaItem(title, url)
        item.thumb = self.noImage
        if thumb_url:
            item.thumb = thumb_url
        item.icon = self.icon
        item.type = 'video'

        if result_set[3]:
            # set date
            day = result_set[3]
            month = result_set[4]
            year = result_set[5]
            Logger.trace("%s-%s-%s", year, month, day)
            month = datehelper.DateHelper.get_month_from_name(
                month, "nl", True)
            item.set_date(year, month, day)

        item.complete = False
        return item
コード例 #24
0
    def create_json_episode_item(self, result_set):
        """ Creates a new MediaItem for an episode.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)

        channel_id = result_set["channel"]
        if self.__channelId and channel_id != self.__channelId:
            return None

        title = result_set["title"]

        use_season = False
        if use_season:
            url = "https://api.kijk.nl/v2/templates/page/format/{}".format(
                result_set["id"])
        else:
            url = "https://api.kijk.nl/v1/default/sections/series-%(id)s_Episodes-season-0?limit=100&offset=0" % result_set

        item = MediaItem(title, url)
        item.description = result_set.get("synopsis", None)

        if "retina_image_pdp_header" in result_set["images"]:
            # noinspection PyTypeChecker
            item.fanart = result_set["images"]["retina_image_pdp_header"]
        if "retina_image" in result_set["images"]:
            # noinspection PyTypeChecker
            item.thumb = result_set["images"]["retina_image"]
        elif "nonretina_image" in result_set["images"]:
            # noinspection PyTypeChecker
            item.thumb = result_set["images"]["nonretina_image"]

        return item
コード例 #25
0
    def add_recent_items(self, data):
        """ Performs pre-process actions for data processing.

        Accepts an data from the process_folder_list method, BEFORE the items are
        processed. Allows setting of parameters (like title etc) for the channel.
        Inside this method the <data> could be changed and additional items can
        be created.

        The return values should always be instantiated in at least ("", []).

        :param str data: The retrieve data that was loaded for the current item and URL.

        :return: A tuple of the data and a list of MediaItems that were generated.
        :rtype: tuple[str|JsonHelper,list[MediaItem]]

        """

        items = []
        today = datetime.datetime.now()
        days = LanguageHelper.get_days_list()
        for d in range(0, 7, 1):
            air_date = today - datetime.timedelta(d)
            Logger.trace("Adding item for: %s", air_date)

            # Determine a nice display date
            day = days[air_date.weekday()]
            if d == 0:
                day = LanguageHelper.get_localized_string(LanguageHelper.Today)
            elif d == 1:
                day = LanguageHelper.get_localized_string(LanguageHelper.Yesterday)

            title = "%04d-%02d-%02d - %s" % (air_date.year, air_date.month, air_date.day, day)
            url = "https://www.goplay.be/api/epg/{}/{:04d}-{:02d}-{:02d}".\
                format(self.__channel_brand, air_date.year, air_date.month, air_date.day)

            extra = MediaItem(title, url)
            extra.complete = True
            extra.dontGroup = True
            extra.set_date(air_date.year, air_date.month, air_date.day, text="")
            extra.content_type = contenttype.VIDEOS
            items.append(extra)

        return data, items
コード例 #26
0
    def create_folder_item(self, result_set):
        """ Creates a MediaItem of type 'folder' using the result_set from the regex.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)

        result_set["title"] = LanguageHelper.get_localized_string(
            LanguageHelper.MorePages)
        return chn_class.Channel.create_folder_item(self, result_set)
コード例 #27
0
    def create_cinema(self, result_set):
        """ Creates a new MediaItem for an episode.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)
        cinema = MediaItem(result_set["name"], "")
        cinema.icon = self.icon
        cinema.thumb = result_set["image"].replace("nocropthumb/[format]/", "")
        cinema.complete = True

        now_playing_url = "%s/cinemas/%s/movies/nowplaying" % (
            self.baseUrl, result_set["id"])
        now_playing = MediaItem("Trailers", now_playing_url)
        now_playing.icon = self.icon
        # https://www.pathe.nl/nocropthumb/[format]/gfx_content/bioscoop/foto/pathe.nl_380x218px_amersfoort.jpg
        now_playing.complete = True
        now_playing.HttpHeaders = self.httpHeaders
        cinema.items.append(now_playing)

        now = datetime.datetime.now()
        for i in range(0, 10):
            date = now + datetime.timedelta(days=i)
            title = "%s-%02d-%02d" % (date.year, date.month, date.day)
            schedule_url = "%s/cinemas/%s/schedules?date=%s" % (
                self.baseUrl, result_set["id"], title)
            schedule = MediaItem("Agenda: %s" % (title, ), schedule_url)
            schedule.icon = self.icon
            schedule.complete = True
            schedule.thumb = cinema.thumb
            schedule.HttpHeaders = self.httpHeaders
            cinema.items.append(schedule)
        return cinema
コード例 #28
0
    def create_program_items(self, result_set):
        """ Creates a new list of MediaItems for a alpha char listing.

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

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

        :return: A new MediaItem of type 'folder'.
        :rtype: list[MediaItem]|MediaItem|None

        """

        Logger.trace(result_set)

        items = []
        for result in result_set["value"]:
            title = result["title"]
            item_id = result["itemId"]

            url = "{}/feeds/intl_m112/V8_0_0/{}/{}" \
                .format(self.baseUrl, self.__show_list_id, item_id)

            item = MediaItem(title, url)
            item.description = result.get("description", None)
            item.metaData["guid"] = item_id
            item.complete = True
            item.thumb = "http://mtv-intl.mtvnimages.com/uri/mgid:arc:content:{}:{}?" \
                         "ep={}&stage=live&format=jpg&quality=0.8&quality=0.85" \
                         "&width=590&height=332&crop=true"\
                .format(self.__country_id, item_id, self.__country_id)
            item.fanart = "http://mtv-intl.mtvnimages.com/uri/mgid:arc:content:{}:{}?" \
                          "ep={}&stage=live&format=jpg&quality=0.8&quality=0.85" \
                          "&width=1280&height=720&crop=true"\
                .format(self.__country_id, item_id, self.__country_id)
            item.poster = "http://mtv-intl.mtvnimages.com/uri/mgid:arc:content:{}:{}?" \
                          "ep={}&stage=live&format=jpg&quality=0.8&quality=0.85" \
                          "&width=500&height=750&crop=true"\
                .format(self.__country_id, item_id, self.__country_id)
            items.append(item)
        return items
コード例 #29
0
    def create_episode_item(self, result_set):
        """ Creates a new MediaItem for an episode.

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

        :param dict[str,Any] result_set: The result_set of the self.episodeItemRegex

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)
        title = result_set["title"]
        date = result_set["trailers"][0]["postdate"]
        url = result_set["trailers"][0]["url"]
        thumb_url = result_set["poster"]
        if "http:" not in thumb_url:
            thumb_url = "%s%s" % (self.baseUrl, thumb_url)
        fanart = thumb_url.replace("poster.jpg", "background.jpg")

        # get the url that shows all trailers/clips. Because the json
        # only shows the most recent one.
        url = "%s%s" % (self.baseUrl, url)

        # Logger.Trace(date)
        dates = date.split(" ")
        # Logger.Trace(dates)
        day = dates[1]
        month = datehelper.DateHelper.get_month_from_name(dates[2], "en")
        year = dates[3]

        # dummy class
        item = MediaItem(title, url)
        item.icon = self.icon
        item.thumb = thumb_url.replace("poster.jpg", "poster-xlarge.jpg")
        item.fanart = fanart
        item.set_date(year, month, day)
        item.complete = True
        return item
コード例 #30
0
    def create_api_typed_item(self, result_set, add_parent_title=False):
        """ Creates a new MediaItem based on the __typename attribute.

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

        :param list[str]|dict result_set: The result_set of the self.episodeItemRegex
        :param bool add_parent_title: Should the parent's title be included?

        :return: A new MediaItem of type 'folder'.
        :rtype: MediaItem|None

        """

        api_type = result_set["__typename"].lower()
        custom_type = result_set.get("type")
        Logger.trace("%s: %s", api_type, result_set)

        item = None
        if custom_type is not None:
            # Use the kijk.nl custom type
            if custom_type == "EPISODE":
                item = self.create_api_episode_type(result_set)
            elif custom_type == "SERIES":
                item = self.create_api_program_type(result_set)
            elif custom_type == "MOVIE":
                item = self.create_api_movie_type(result_set)
            else:
                Logger.warning("Missing type: %s", api_type)
                return None
            return item

        if api_type == "program":
            item = self.create_api_program_type(result_set)
        elif api_type == "tvseason":
            item = self.create_api_tvseason_type(result_set)
        else:
            Logger.warning("Missing type: %s", api_type)
            return None

        return item