Beispiel #1
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

        """

        if len(result_set) > 3 and result_set[3] != "":
            Logger.debug("Sub category folder found.")
            url = parse.urljoin(self.baseUrl, HtmlEntityHelper.convert_html_entities(result_set[3]))
            name = "\a.: %s :." % (result_set[4],)
            item = MediaItem(name, url)
            item.thumb = self.noImage
            item.complete = True
            item.type = "folder"
            return item

        url = parse.urljoin(self.baseUrl, HtmlEntityHelper.convert_html_entities(result_set[0]))
        name = HtmlEntityHelper.convert_html_entities(result_set[1])

        helper = HtmlHelper(result_set[2])
        description = helper.get_tag_content("div", {'class': 'description'})

        item = MediaItem(name, "%s/RSS" % (url,))
        item.thumb = self.noImage
        item.type = 'folder'
        item.description = description.strip()

        date = helper.get_tag_content("div", {'class': 'date'})
        if date == "":
            date = helper.get_tag_content("span", {'class': 'lastPublishedDate'})

        if not date == "":
            date_parts = Regexer.do_regex(r"(\w+) (\d+)[^<]+, (\d+)", date)
            if len(date_parts) > 0:
                date_parts = date_parts[0]
                month_part = date_parts[0].lower()
                day_part = date_parts[1]
                year_part = date_parts[2]

                try:
                    month = DateHelper.get_month_from_name(month_part, "en")
                    item.set_date(year_part, month, day_part)
                except:
                    Logger.error("Error matching month: %s", month_part, exc_info=True)

        item.complete = True
        return item
    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[str,str] result_set: The result_set of the self.episodeItemRegex

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

        """

        url = parse.urljoin(
            self.baseUrl,
            HtmlEntityHelper.convert_html_entities(result_set[0]))
        name = result_set[1]

        if name == "Tags":
            return None
        if name == "Authors":
            return None
        if name == "Most Viewed":
            return None
        if name == "Top Rated":
            name = "Recent"
            url = "http://channel9.msdn.com/Feeds/RSS"
        else:
            url = "%s?sort=atoz" % (url, )

        item = MediaItem(name, url)
        item.icon = self.icon
        item.complete = True
        return item
    def __add_breadcrumb(self,
                         handle,
                         channel,
                         selected_item,
                         last_only=False):
        """ Updates the Kodi category with a breadcrumb to the current parent item

        :param int handle:                      The Kodi file handle
        :param ChannelInfo|Channel channel:     The channel to which the item belongs
        :param MediaItem selected_item:         The item from which to show the breadcrumbs
        :param bool last_only:                  Show only the last item

        """

        bread_crumb = None
        if selected_item is not None:
            bread_crumb = selected_item.name
        elif self.channelObject is not None:
            bread_crumb = channel.channelName

        if not bread_crumb:
            return

        bread_crumb = HtmlEntityHelper.convert_html_entities(bread_crumb)
        xbmcplugin.setPluginCategory(handle=handle, category=bread_crumb)
    def __convert_ttml_to_srt(ttml):
        """Converts sami format into SRT format:

        Arguments:
        ttml : string - TTML (Timed Text Markup Language) subtitle format

        Returns:
        SRT formatted subtitle:

        Example:
            1
            00:00:20,000 --> 00:00:24,400
            text

        """

        pars_regex = r'<p[^>]+begin="([^"]+)\.(\d+)"[^>]+end="([^"]+)\.(\d+)"[^>]*>([\w\W]+?)</p>'
        subs = Regexer.do_regex(pars_regex, ttml)

        srt = ""
        i = 1

        for sub in subs:
            try:
                start = "%s,%03d" % (sub[0], int(sub[1]))
                end = "%s,%03d" % (sub[2], int(sub[3]))
                text = sub[4].replace("<br />", "\n")
                text = HtmlEntityHelper.convert_html_entities(text)
                text = text.replace("\r\n", "")
                srt = "%s\n%s\n%s --> %s\n%s\n" % (srt, i, start, end, text.strip())
                i += 1
            except:
                Logger.error("Error parsing subtitle: %s", sub[1], exc_info=True)

        return srt
    def update_video_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)

        # sources
        part = item.create_new_empty_media_part()
        # high, web, mobile, url
        media_sources = media_info.json.get("sources", {})
        for quality in media_sources:
            url = media_sources[quality]
            if quality == "high":
                bitrate = 2000
            elif quality == "web":
                bitrate = 800
            elif quality == "mobile":
                bitrate = 400
            else:
                bitrate = 0
            part.append_media_stream(url, bitrate)

        # geoLocRestriction
        item.isGeoLocked = not media_info.get_value(
            "geoLocRestriction", fallback="world") == "world"
        item.complete = True
        return item
Beispiel #6
0
    def get_kodi_item(self):
        """ Creates an Kodi ListItem object for this channel
        
        :return: a Kodi ListItem with all required properties set.
        :rtype: xbmcgui.ListItem

        """

        name = HtmlEntityHelper.convert_html_entities(self.channelName)
        description = HtmlEntityHelper.convert_html_entities(
            self.channelDescription)

        if self.uses_external_addon:
            other = LanguageHelper.get_localized_string(
                LanguageHelper.OtherAddon)
            name = "{0} {1} [COLOR gold]{2}[/COLOR]".format(
                name, unichr(187), other)

        self.icon = self.__get_image_path(self.icon)
        item = xbmcgui.ListItem(name, description)
        item.setArt({'thumb': self.icon, 'icon': self.icon})

        # http://mirrors.kodi.tv/docs/python-docs/14.x-helix/xbmcgui.html#ListItem-setInfo
        item.setInfo(
            "video",
            {
                "Title": name,
                # "Count": self.sortOrderPerCountry,
                # "TrackNumber": self.sortOrder,
                "Genre": LanguageHelper.get_full_language(self.language),
                # "Tagline": description,
                "Plot": description
            })

        if AddonSettings.hide_fanart():
            return item

        if self.fanart is not None:
            self.fanart = self.__get_image_path(self.fanart)
        else:
            self.fanart = os.path.join(Config.rootDir, "fanart.jpg")
        item.setArt({'fanart': self.fanart})
        return item
Beispiel #7
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
    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)

        # now the mediaurl is derived. First we try WMV
        data = UriHandler.open(item.url)

        urls = Regexer.do_regex(
            '<a href="([^"]+.(?:wmv|mp4))">(High|Medium|Mid|Low|MP4)', data)
        media_part = item.create_new_empty_media_part()
        for url in urls:
            if url[1].lower() == "high":
                bitrate = 2000
            elif url[1].lower() == "medium" or url[1].lower() == "mid":
                bitrate = 1200
            elif url[1].lower() == "low" or url[1].lower() == "mp4":
                bitrate = 200
            else:
                bitrate = 0
            media_part.append_media_stream(
                HtmlEntityHelper.convert_html_entities(url[0]), bitrate)

        item.complete = True
        return item
    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
    def __convert_json_subtitle_to_srt(json_subtitle):
        """Converts Json Subtitle format into SRT format:

        Arguments:
        jsonSubtitle : string - Json Subtitle subtitle format

        Returns:
        SRT formatted subtitle:

        Example:
            {"startMillis":80,"endMillis":4170,"text":"Ett Kanal 5:\nAlla gonblick i \"100 jdare!!!\"?","posX":0.5,"posY":0.9,"colorR":220,"colorG":220,"colorB":220}

        Returns
            1
            00:00:20,000 --> 00:00:24,400
            text

        The format of the timecode is Hours:Minutes:Seconds:Ticks where a "Tick"
        is a value of between 0 and 249 and lasts 4 milliseconds.

        """

        regex = r'"startMillis":(\d+),"endMillis":(\d+),"text":"(.+?)(?=["] *,)'
        subs = Regexer.do_regex(regex, json_subtitle)

        # Init some stuff
        srt = ""
        i = 1

        for sub in subs:
            try:
                start = SubtitleHelper.__convert_to_time(sub[0])
                end = SubtitleHelper.__convert_to_time(sub[1])

                text = sub[2].replace('\"', '"')
                text = JsonHelper.convert_special_chars(text)
                text = HtmlEntityHelper.convert_html_entities(text)
                srt = "%s\n%s\n%s --> %s\n%s\n" % (srt, i, start, end,
                                                   text.strip())
                i += 1
            except:
                Logger.error("Error parsing subtitle: %s", sub, exc_info=True)

        return srt
    def __convert_web_vtt_to_srt(webvvt):
        """Converts sami format into SRT format:

        Arguments:
        ttml : string - TTML (Timed Text Markup Language) subtitle format

        Returns:
        SRT formatted subtitle:

        Example:
            1
            00:00:20,000 --> 00:00:24,400
            text

        """

        count = 0
        result = ""
        for line in webvvt.split("\n"):
            line = line.strip()
            if line.endswith("WEBVTT") or line.startswith("X-TIMESTAMP"):
                continue
            if not line:
                continue

            if " --> " in line:
                count += 1
                start, end = line.split(" --> ")
                result = "%s\n\n%s" % (result, count)
                if start.count(":") == 1:
                    result = "%s\n00:%s --> 00:%s" % (
                        result, start.replace(".", ","), end.replace(".", ","))
                else:
                    result = "%s\n%s --> %s" % (result, start.replace(
                        ".", ","), end.replace(".", ","))
            elif line == str(count + 1):
                # we apparently have built-in numbering using WebVTT cue-numbering
                continue
            else:
                result = "%s\n%s" % (
                    result, HtmlEntityHelper.convert_html_entities(line))

        return result
Beispiel #12
0
    def create_page_item(self, result_set):
        """ Creates a MediaItem of type 'page' using the result_set from the regex.

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

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

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

        """

        url = parse.urljoin(self.baseUrl, HtmlEntityHelper.convert_html_entities(result_set[0]))
        item = MediaItem(result_set[self.pageNavigationRegexIndex], url)
        item.type = "page"
        item.complete = True

        Logger.trace("Created '%s' for url %s", item.name, item.url)
        return item
    def __convert_sami_to_srt(sami):
        """Converts sami format into SRT format:

        Arguments:
        sami : string - SAMI subtitle format

        Returns:
        SRT formatted subtitle:

        Example:
            1
            00:00:20,000 --> 00:00:24,400
            text

        """
        pars_regex = r'<sync start="(\d+)"><p[^>]+>([^<]+)</p></sync>\W+<sync start="(\d+)">'
        subs = Regexer.do_regex(pars_regex, sami)

        if len(subs) == 0:
            pars_regex2 = r'<sync start=(\d+)>\W+<p[^>]+>([^\n]+)\W+<sync start=(\d+)>'
            subs = Regexer.do_regex(pars_regex2, sami)

        srt = ""
        i = 1

        for sub in subs:
            try:
                start = SubtitleHelper.__convert_to_time(sub[0])
                end = SubtitleHelper.__convert_to_time(sub[2])
                text = sub[1]
                text = HtmlEntityHelper.convert_html_entities(text)
                srt = "%s\n%s\n%s --> %s\n%s\n" % (srt, i, start, end, text)
                i += 1
            except:
                Logger.error("Error parsing subtitle: %s",
                             sub[1],
                             exc_info=True)

        # re-encode to be able to write it
        return srt
    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[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)

        genres = result_set[0]
        if self.__genre and self.__genre not in genres:
            Logger.debug("Item '%s' filtered due to genre: %s", result_set[2],
                         genres)
            return None

        url = result_set[1]
        if "&" in url:
            url = HtmlEntityHelper.convert_html_entities(url)

        if not url.startswith("http:"):
            url = "%s%s" % (self.baseUrl, url)

        # get the ajax page for less bandwidth
        url = "%s?sida=1&amp;sort=tid_stigande&embed=true" % (url, )

        item = MediaItem(result_set[2], url)
        item.icon = self.icon
        item.thumb = self.noImage
        item.complete = True
        item.isGeoLocked = True
        return item
Beispiel #15
0
    def __full_decode_text(self, string_value):
        """ Decodes a byte encoded string with HTML content into Unicode String

        Arguments:
        stringValue : string - The byte encoded string to decode

        Returns:
        An Unicode String with all HTML entities replaced by their UTF8 characters

        The decoding is done by first decode the string to UTF8 and then replace
        the HTML entities to their UTF8 characters.

        """

        if string_value is None:
            return None

        if string_value == "":
            return ""

        # then get rid of the HTML entities
        string_value = HtmlEntityHelper.convert_html_entities(string_value)
        return string_value
    def __convert_dc_subtitle_to_srt(dc_subtitle):
        """Converts DC Subtitle format into SRT format:

        Arguments:
        dcSubtitle : string - DC Subtitle subtitle format

        Returns:
        SRT formatted subtitle:

        Example:
            <Subtitle SpotNumber="1" TimeIn="00:00:01:220" TimeOut="00:00:04:001" FadeUpTime="20" FadeDownTime="20">
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="6.0">Line 1</Text>
            </Subtitle>
            <Subtitle SpotNumber="2" TimeIn="00:02:07:180" TimeOut="00:02:10:040" FadeUpTime="20" FadeDownTime="20">
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="6.0">Line 1</Text>
            </Subtitle>
            <Subtitle SpotNumber="3" TimeIn="00:02:15:190" TimeOut="00:02:17:190" FadeUpTime="20" FadeDownTime="20">
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="14.0">Line 1</Text>
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="6.0">Line 2</Text>
            </Subtitle>
            <Subtitle SpotNumber="4" TimeIn="00:03:23:140" TimeOut="00:03:30:120" FadeUpTime="20" FadeDownTime="20">
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="14.0">Line 1</Text>
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="14.0">Line 2</Text>
              <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="14.0">Line 3</Text>
            </Subtitle>

        Returns
            1
            00:00:20,000 --> 00:00:24,400
            text

        The format of the timecode is Hours:Minutes:Seconds:Ticks where a "Tick"
        is a value of between 0 and 249 and lasts 4 milliseconds.

        """

        parse_regex = r'<subtitle[^>]+spotnumber="(\d+)" timein="(\d+:\d+:\d+):(\d+)" ' \
                      r'timeout="(\d+:\d+:\d+):(\d+)"[^>]+>|<text[^>]+>([^<]+)</text>'
        parse_regex = parse_regex.replace('"', '["\']')
        subs = Regexer.do_regex(parse_regex, dc_subtitle)

        srt = ""
        i = 1
        text = ""
        start = ""
        end = ""

        for sub in subs:
            #Logger.Trace(sub)
            try:
                if sub[0]:
                    # new start of a sub
                    if text and start and end:
                        # if we have a complete old one, save it
                        text = HtmlEntityHelper.convert_html_entities(text)
                        srt = "%s\n%s\n%s --> %s\n%s\n" % (srt, i, start, end,
                                                           text.strip())
                        i += 1
                    start = "%s,%03d" % (sub[1], int(sub[2]))
                    end = "%s,%03d" % (sub[3], int(sub[4]))
                    text = ""
                else:
                    text = "%s\n%s" % (text, sub[5].replace("<br />", "\n"))
            except:
                Logger.error("Error parsing subtitle: %s", sub, exc_info=True)
        return srt