コード例 #1
0
    def ProcessFolderList(self):
        """Wraps the channel.ProcessFolderList"""

        Logger.Info("Plugin::ProcessFolderList Doing ProcessFolderList")
        try:
            ok = True

            selectedItem = None
            if self.keywordPickle in self.params:
                selectedItem = Pickler.DePickleMediaItem(self.params[self.keywordPickle])

            watcher = stopwatch.StopWatch("Plugin ProcessFolderList", Logger.Instance())
            episodeItems = self.channelObject.ProcessFolderList(selectedItem)
            watcher.Lap("Class ProcessFolderList finished")

            if len(episodeItems) == 0:
                Logger.Warning("ProcessFolderList returned %s items", len(episodeItems))
                ok = self.__ShowEmptyInformation(episodeItems)
            else:
                Logger.Debug("ProcessFolderList returned %s items", len(episodeItems))

            xbmcItems = []
            for episodeItem in episodeItems:
                if episodeItem.thumb == "":
                    episodeItem.thumb = self.channelObject.noImage
                if episodeItem.fanart == "":
                    episodeItem.fanart = self.channelObject.fanart

                if episodeItem.type == 'folder' or episodeItem.type == 'append' or episodeItem.type == "page":
                    action = self.actionListFolder
                    folder = True
                elif episodeItem.IsPlayable():
                    action = self.actionPlayVideo
                    folder = False
                else:
                    Logger.Critical("Plugin::ProcessFolderList: Cannot determine what to add")
                    continue

                # Get the XBMC item
                item = episodeItem.GetXBMCItem()
                # Get the context menu items
                contextMenuItems = self.__GetContextMenuItems(self.channelObject, item=episodeItem)
                item.addContextMenuItems(contextMenuItems)
                # Get the action URL
                url = self.__CreateActionUrl(self.channelObject, action=action, item=episodeItem)
                # Add them to the list of XBMC items
                xbmcItems.append((url, item, folder))

            watcher.Lap("Kodi Items generated")
            # add items but if OK was False, keep it like that
            ok = ok and xbmcplugin.addDirectoryItems(self.handle, xbmcItems, len(xbmcItems))
            watcher.Lap("items send to Kodi")

            if selectedItem is None:
                # mainlist item register channel.
                Statistics.RegisterChannelOpen(self.channelObject, Initializer.StartTime)
                watcher.Lap("Statistics send")

            watcher.Stop()

            self.__AddSortMethodToHandle(self.handle, episodeItems)

            # set the content
            xbmcplugin.setContent(handle=self.handle, content=self.contentType)

            xbmcplugin.endOfDirectory(self.handle, ok)
        except:
            Statistics.RegisterError(self.channelObject)
            XbmcWrapper.ShowNotification(LanguageHelper.GetLocalizedString(LanguageHelper.ErrorId),
                                         LanguageHelper.GetLocalizedString(LanguageHelper.ErrorList),
                                         XbmcWrapper.Error, 4000)
            Logger.Error("Plugin::Error Processing FolderList", exc_info=True)
            xbmcplugin.endOfDirectory(self.handle, False)
コード例 #2
0
    def CreateFolderItem(self, resultSet):
        """Creates a MediaItem of type 'folder' using the resultSet from the regex.

        Arguments:
        resultSet : tuple(strig) - the resultSet of the self.folderItemRegex

        Returns:
        A new MediaItem of type 'folder'

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

        """

        if len(resultSet) > 3 and resultSet[3] != "":
            Logger.Debug("Sub category folder found.")
            url = urlparse.urljoin(
                self.baseUrl,
                htmlentityhelper.HtmlEntityHelper.ConvertHTMLEntities(
                    resultSet[3]))
            name = "\a.: %s :." % (resultSet[4], )
            item = mediaitem.MediaItem(name, url)
            item.thumb = self.noImage
            item.complete = True
            item.type = "folder"
            return item

        url = urlparse.urljoin(
            self.baseUrl,
            htmlentityhelper.HtmlEntityHelper.ConvertHTMLEntities(
                resultSet[0]))
        name = htmlentityhelper.HtmlEntityHelper.ConvertHTMLEntities(
            resultSet[1])

        helper = htmlhelper.HtmlHelper(resultSet[2])
        description = helper.GetTagContent("div", {'class': 'description'})

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

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

        if not date == "":
            dateParts = Regexer.DoRegex("(\w+) (\d+)[^<]+, (\d+)", date)
            if len(dateParts) > 0:
                dateParts = dateParts[0]
                monthPart = dateParts[0].lower()
                dayPart = dateParts[1]
                yearPart = dateParts[2]

                try:
                    month = datehelper.DateHelper.GetMonthFromName(
                        monthPart, "en")
                    item.SetDate(yearPart, month, dayPart)
                except:
                    Logger.Error("Error matching month: %s",
                                 monthPart,
                                 exc_info=True)

        item.complete = True
        return item
コード例 #3
0
    def CreateVideoItemJson(self, resultSet):
        """Creates a MediaItem of type 'video' using the resultSet from the regex.

        Arguments:
        resultSet : tuple (string) - the resultSet of the self.videoItemRegex

        Returns:
        A new MediaItem of type 'video' or 'audio' (despite the method's name)

        This method creates a new MediaItem from the Regular Expression
        results <resultSet>. 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.UpdateVideoItem method is called if the item is focussed or selected
        for playback.

        """

        Logger.Trace(resultSet)

        # get the title
        originalTitle = resultSet.get("original_title")
        localTitle = resultSet.get("local_title")
        # Logger.Trace("%s - %s", originalTitle, localTitle)
        if originalTitle == "":
            title = localTitle
        else:
            title = originalTitle

        # get the other meta data
        playLists = resultSet.get("local_playlists", [])
        videoMgid = None
        for playList in playLists:
            language = playList["language_code"]
            if language == self.language:
                Logger.Trace("Found '%s' playlist, using this one.", language)
                videoMgid = playList["id"]
                break
            elif language == "en":
                Logger.Trace("Found '%s' instead of '%s' playlist", language,
                             self.language)
                videoMgid = playList["id"]

        if videoMgid is None:
            Logger.Error("No video MGID found for: %s", title)
            return None

        url = "http://api.mtvnn.com/v2/mrss.xml?uri=mgid:sensei:video:mtvnn.com:local_playlist-%s" % (
            videoMgid, )

        thumb = resultSet.get("riptide_image_id")
        thumb = "http://images.mtvnn.com/%s/original" % (thumb, )

        description = resultSet.get("local_long_description")

        date = resultSet.get("published_from")
        date = date[0:10].split("-")

        item = mediaitem.MediaItem(title, url)
        item.thumb = thumb
        item.description = description
        item.icon = self.icon
        item.type = 'video'
        item.SetDate(date[0], date[1], date[2])
        item.complete = False
        return item
コード例 #4
0
    def Send(templateFilePath: str, commits: list) -> ErrorCode:
        """
      Send an HTML email of the given commits in the style
      of the given template file. Use the email
      settings (subject, to, from) from the config.json.

      Args:
         templateFilePath (str): The path to the email template file.
         commits (list): The list of commits to list in the email.
      
      Returns:
         An ErrorCode object telling what the outcome of calling the function was.
      """
        COMMIT_LIST_ITEM_FORMAT = \
  """
<li>
   {title}
   {author}
   {date}
   {message}
</li>
"""
        config = Config.GetConfig()
        email = EmailMessage()
        email['Subject'] = config.get('Email').get('Subject')
        email['To'] = config.get('Email').get('To')
        email['From'] = config.get('Email').get('From')

        version = ""
        author = ""
        if (len(commits)):
            author = commits[0].author
            version = commits[0].tag

        textTemplate = ""
        htmlPart = ""
        try:
            with open(templateFilePath, 'r') as templateFile:
                textTemplate = templateFile.read()
        except IOError as err:
            Logger.Error(LOG_TAG, err)
            return ErrorCode.FILE_ERROR

        if (len(textTemplate) == 0):
            Logger.Error(LOG_TAG, "Template file empty")
            return ErrorCode.FILE_ERROR

        htmlPart = textTemplate.format(
            title=config.get('Email').get('Subject'),
            version=version,
            author=author,
            changeLog='\n'.join(
                list(
                    map(lambda x: HTMLEmail.COMMIT_LIST_ITEM_FORMAT.format(
                        title=x.title,
                        author=x.author,
                        date=Date.ConvertDateToString(x.date),
                        message=x.message)))))
        email.set_content(htmlPart)
        email.add_alternative(htmlPart, subtype='html')

        smtp = smtplib.SMTP(config.get('Email').get('SMTP').get('Server'))
        smtp.send(email)
        smtp.quit()

        return ErrorCode.OK
コード例 #5
0
    def PrintSettingValues():
        """Prints the settings"""

        pattern = "%s\n%s: %s"
        value = "%s: %s" % ("ClientId", AddonSettings.GetClientId())
        value = pattern % (value, "MaxStreamBitrate",
                           AddonSettings.GetMaxStreamBitrate())
        value = pattern % (value, "SortingAlgorithm",
                           AddonSettings.GetSortAlgorithm())
        value = pattern % (value, "UseSubtitle", AddonSettings.UseSubtitle())
        value = pattern % (value, "CacheHttpResponses",
                           AddonSettings.CacheHttpResponses())
        value = pattern % (value, "Folder Prefx",
                           "'%s'" % AddonSettings.GetFolderPrefix())
        value = pattern % (value, "Empty List Behaviour",
                           AddonSettings.GetEmptyListBehaviour())
        value = pattern % (value, "ListLimit", AddonSettings.GetListLimit())
        value = pattern % (value, "Loglevel", AddonSettings.GetLogLevel())
        value = pattern % (value, "Geo Location",
                           AddonSettings.HideGeoLockedItemsForLocation(
                               None, valueOnly=True))
        value = pattern % (value, "Filter Folders",
                           AddonSettings.HideRestrictedFolders())
        value = pattern % (value, "DRM Warning",
                           AddonSettings.ShowDrmWarning())
        value = pattern % (value, "Hide DRM Items",
                           AddonSettings.HideDrmItems())
        value = pattern % (value, "Hide Premium Items",
                           AddonSettings.HidePremiumItems())
        value = pattern % (value, "Show Dutch",
                           AddonSettings.ShowChannelWithLanguage("nl"))
        value = pattern % (value, "Show Swedish",
                           AddonSettings.ShowChannelWithLanguage("se"))
        value = pattern % (value, "Show Lithuanian",
                           AddonSettings.ShowChannelWithLanguage("lt"))
        value = pattern % (value, "Show Latvian",
                           AddonSettings.ShowChannelWithLanguage("lv"))
        # value = pattern % (value, "Show French Canadian", AddonSettings.ShowChannelWithLanguage("ca-fr"))
        # value = pattern % (value, "Show English Canadian", AddonSettings.ShowChannelWithLanguage("ca-en"))
        value = pattern % (value, "Show British",
                           AddonSettings.ShowChannelWithLanguage("en-gb"))
        value = pattern % (value, "Show German",
                           AddonSettings.ShowChannelWithLanguage("de"))
        # noinspection PyTypeChecker
        value = pattern % (value, "Show Other languages",
                           AddonSettings.ShowChannelWithLanguage(None))
        value = pattern % (value, "UZG Cache Path",
                           AddonSettings.GetUzgCachePath())
        value = pattern % (value, "UZG Cache Time",
                           AddonSettings.GetUzgCacheDuration())

        try:
            proxies = ["NL", "UK", "SE", "Other"]
            for proxy in proxies:
                value = pattern % (value, "%s Proxy" % (proxy, ),
                                   AddonSettings.__GetSetting(
                                       "%s_proxy_server" %
                                       (proxy.lower(), )) or "Not Set")

                value = pattern % (value, "%s Proxy Port" % (proxy, ),
                                   AddonSettings.__GetSetting(
                                       "%s_proxy_port" %
                                       (proxy.lower(), )) or 0)
        except:
            Logger.Error("Error", exc_info=True)
        return value
コード例 #6
0
    def UpdateVideoItem(self, item):
        """
        Accepts an item. It returns an updated item. Usually retrieves the MediaURL 
        and the Thumb! It should return a completed item. 
        """
        Logger.Debug('Starting UpdateVideoItem for %s (%s)', item.name,
                     self.channelName)

        # get additional info
        data = UriHandler.Open(item.url, proxy=self.proxy)
        guid = Regexer.DoRegex(
            '<meta property="og:video" content="http://player.extreme.com/FCPlayer.swf\?id=([^&]+)&amp[^"]+" />',
            data)

        #<param name="flashvars" value="id=dj0xMDEzNzQyJmM9MTAwMDAwNA&amp;tags=source%253Dfreecaster&amp;autoplay=1" />
        # http://freecaster.tv/player/smil/dj0xMDEzNzQyJmM9MTAwMDAwNA -> playlist with bitrate
        # http://freecaster.tv/player/smil/dj0xMDEzNzQyJmM9MTAwMDAwNA -> info (not needed, get description from main page.

        if len(guid) > 0:
            url = '%s/player/smil/%s' % (
                self.baseUrl,
                guid[0],
            )
            data = UriHandler.Open(url)

            smiller = Smil(data)
            baseUrl = smiller.GetBaseUrl()
            urls = smiller.GetVideosAndBitrates()

            part = item.CreateNewEmptyMediaPart()
            for url in urls:
                if "youtube" in url[0]:
                    for s, b in YouTube.GetStreamsFromYouTube(
                            url[0], self.proxy):
                        item.complete = True
                        part.AppendMediaStream(s, b)
                else:
                    part.AppendMediaStream("%s%s" % (baseUrl, url[0]),
                                           bitrate=int(int(url[1]) / 1000))
                item.complete = True

            Logger.Trace("UpdateVideoItem complete: %s", item)
            return item

        # Try the brightcove
        brightCoveRegex = '<object id="myExperience[\w\W]+?videoPlayer" value="(\d+)"[\w\W]{0,1000}?playerKey" value="([^"]+)'
        brightCoveData = Regexer.DoRegex(brightCoveRegex, data)
        Logger.Trace(brightCoveData)
        if len(brightCoveData) > 0:
            seed = "c5f9ae8729f7054d43187989ef3421531ee8678d"
            objectData = brightCoveData[0]
            # from proxyinfo import ProxyInfo
            playerKey = str(objectData[1])
            videoId = int(objectData[0])

            part = item.CreateNewEmptyMediaPart()
            # But we need the IOS streams!
            amfHelper = BrightCove(Logger.Instance(),
                                   playerKey,
                                   videoId,
                                   str(item.url),
                                   seed,
                                   proxy=self.proxy)
            for stream, bitrate in amfHelper.GetStreamInfo(
                    renditions="IOSRenditions"):
                part.AppendMediaStream(stream, bitrate)

        Logger.Error("Cannot find GUID in url: %s", item.url)
        return item
コード例 #7
0
        def __RetreiveData(self,
                           destHandle,
                           uri,
                           timeOutValue,
                           progressCallback=None,
                           proxy=None,
                           maxBytes=0,
                           params="",
                           referer=None,
                           additionalHeaders=None,
                           noCache=False,
                           blockMultiplier=1):
            """Open an URL Async using a thread

            Arguments:
            uri      : string - the URI to download

            Keyword Arguments:
            progressCallback : [opt] boolean - should a progress bar be shown
            proxy            : [opt] string  - The address and port (proxy.address.ext:port) of
                                               a proxy server that should be used.
            bytes            : [opt] integer - the number of bytes to get.
            params           : [opt] string  - data to send with the request (open(uri, params))
            headers          : [opt] dict    - a dictionary of additional headers

            Returns:
            The data that was retrieved from the URI.

            """

            # init parameters
            canceled = False
            timeOut = False
            error = False
            srcHandle = None
            blocksRead = 0
            fileSize = 0
            charSet = None
            blockSize = self.blockSize * blockMultiplier

            try:
                if uri == "":
                    return error, canceled, ""

                if uri.startswith("file:"):
                    index = uri.rfind("?")
                    #index = string.rfind(uri, "?")
                    if index > 0:
                        uri = uri[0:index]

                Logger.Info(
                    "Opening requested uri: %s (callback=%s, timeout=%s)", uri,
                    progressCallback is not None, timeOutValue)
                self.__DoCallback(progressCallback, 0, blockSize, 0, False)

                # set the start time in seconds
                startTime = time.time()

                # get an opener and handle
                opener = self.__GetOpener(uri,
                                          proxy,
                                          disableCaching=noCache,
                                          referer=referer,
                                          additionalHeaders=additionalHeaders)
                if params == '':
                    srcHandle = opener.open(uri)
                else:
                    srcHandle = opener.open(uri, params)

                # get some metadata
                Logger.Debug("Determining number of bytes to fetch")
                data = srcHandle.info()
                if data.get('Content-length'):
                    fileSize = int(data.get('Content-length'))
                    Logger.Debug('ByteSize is known (fileSize=' +
                                 str(fileSize) + ')')
                else:
                    fileSize = -1
                    Logger.Debug('ByteSize is unknown')

                # check for encoding
                charSet = None
                try:
                    contentType = data.get('Content-Type')
                    if contentType:
                        Logger.Trace("Found Content-Type header: %s",
                                     contentType)
                        charSetNeedle = 'charset='
                        charSetIndex = contentType.rfind(charSetNeedle)
                        if charSetIndex > 0:
                            charSetEndIndex = contentType.find(
                                ";", charSetIndex)
                            if charSetEndIndex > 0:
                                charSet = contentType[charSetIndex +
                                                      len(charSetNeedle
                                                          ):charSetEndIndex]
                            else:
                                charSet = contentType[charSetIndex +
                                                      len(charSetNeedle):]
                            Logger.Trace("Found Charset HTML Header: %s",
                                         charSet)
                except:
                    charSet = None

                blocksRead = 0
                while True:
                    block = srcHandle.read(blockSize)
                    if block == "":
                        break

                    destHandle.write(block)
                    blocksRead += 1

                    canceled = self.__DoCallback(progressCallback, blocksRead,
                                                 blockSize, fileSize, False)
                    if canceled:
                        break

                    if time.time() > startTime + timeOutValue:
                        timeOut = True
                        break

                    if 0 < maxBytes < blocksRead * blockSize:
                        Logger.Info(
                            'Stopping download because Bytes > maxBytes')
                        break

                srcHandle.close()

            except (IncompleteRead, ValueError):
                # Python 2.6 throws a IncompleteRead on Chuncked data
                # Python 2.4 throws a ValueError on Chuncked data
                Logger.Error("IncompleteRead error opening url %s", uri)
                try:
                    if srcHandle:
                        srcHandle.close()
                except UnboundLocalError:
                    pass

            except:
                Logger.Critical("Error Opening url %s", uri, exc_info=True)
                error = True
                try:
                    if srcHandle:
                        srcHandle.close()
                except UnboundLocalError:
                    pass

            # we are finished now
            self.__DoCallback(progressCallback, blocksRead, blockSize,
                              fileSize, True)

            if timeOut:
                Logger.Critical(
                    "The URL lookup did not respond within the TimeOut (%s s)",
                    timeOutValue)
            elif canceled:
                Logger.Warning("Opening of %s was canceled", uri)
            elif not error:
                Logger.Info("Url %s was opened successfully", uri)

            if self.cookieJarFile:
                # noinspection PyUnresolvedReferences
                self.cookieJar.save()
            return error, canceled, charSet
コード例 #8
0
    def __UpdateAddOnSettingsWithChannelSettings(contents, channels):
        """ Adds the channel specific settings

        @param contents: The current settings
        @param channels: The available channels
        @return: updated contents and the offset in visibility

        This method first aggregates the settings and then adds them.

        """

        if "<!-- begin of channel settings -->" not in contents:
            Logger.Error(
                "No '<!-- begin of channel settings -->' found in settings.xml. Stopping updating."
            )
            return

        settings = dict()

        # There are 2 settings between the selector list and the channel settings in the settings_template.xml
        settingOffsetForVisibility = 2

        # Let's make sure they are sorted by channel module. So we first go through them all and then create
        # the XML.
        for channel in channels:
            if channel.moduleName not in settings:
                settings[channel.moduleName] = []

            # add channel visibility
            settingXml = '<setting id="channel_%s_visible" type="bool" label="30042" ' \
                         'default="true" visible="eq(-%%s,%s)" />' % \
                         (channel.guid, channel.safeName)
            Logger.Trace(settingXml)
            settings[channel.moduleName].append(settingXml)

            if not channel.settings:
                continue

            # Sort the settings so they are really in the correct order, because this is not guaranteed by the
            # json parser
            channel.settings.sort(lambda a, b: cmp(a["order"], b["order"]))
            for channelSettings in channel.settings:
                settingId = channelSettings["id"]
                settingValue = channelSettings["value"]
                Logger.Debug("Adding setting: '%s' with value '%s'", settingId,
                             settingValue)

                if settingValue.startswith("id="):
                    settingXml = "<setting %s visible=\"eq(-%%s,%s)\" />" % \
                                 (settingValue, channel.safeName)
                else:
                    settingXml = '<setting id="channel_%s_%s" %s visible=\"eq(-%%s,%s)\" />' % \
                                 (channel.guid, settingId, settingValue, channel.safeName)
                settings[channel.moduleName].append(settingXml)

        xmlContent = '\n        <!-- begin of channel settings -->\n'
        # Sort them to make the result more consistent
        settingKeys = settings.keys()
        settingKeys.sort()
        for module in settingKeys:
            xmlContent = '%s        <!-- %s.py -->\n' % (xmlContent, module)
            for setting in settings[module]:
                settingOffsetForVisibility += 1
                xmlContent = "%s        %s\n" % (xmlContent, setting %
                                                 settingOffsetForVisibility)

        begin = contents[:contents.find('<!-- begin of channel settings -->'
                                        )].strip()
        end = contents[contents.find('<!-- end of channel settings -->'):]

        Logger.Trace("Generated channel settings:\n%s", xmlContent)
        contents = "%s\n%s\n        %s" % (begin, xmlContent.rstrip(), end)
        return contents, settingOffsetForVisibility
コード例 #9
0
    def SetDate(self,
                year,
                month,
                day,
                hour=None,
                minutes=None,
                seconds=None,
                onlyIfNewer=False,
                text=None):
        """Sets the datetime of the MediaItem

        Arguments:
        year       : integer - the year of the datetime
        month      : integer - the month of the datetime
        day        : integer - the day of the datetime

        Keyword Arguments:
        hour       : [opt] integer - the hour of the datetime
        minutes    : [opt] integer - the minutes of the datetime
        seconds    : [opt] integer - the seconds of the datetime
        onlyIfNewer: [opt] integer - update only if the new date is more
                                     recent then the currently set one
        text       : [opt] string  - if set it will overwrite the text in the
                                     date label the datetime is also set.

        Sets the datetime of the MediaItem in the self.__date and the
        corresponding text representation of that datetime.

        <hour>, <minutes> and <seconds> can be optional and will be set to 0 in
        that case. They must all be set or none of them. Not just one or two of
        them.

        If <onlyIfNewer> is set to True, the update will only occur if the set
        datetime is newer then the currently set datetime.

        The text representation can be overwritten by setting the <text> keyword
        to a specific value. In that case the timestamp is set to the given time
        values but the text representation will be overwritten.

        If the values form an invalid datetime value, the datetime value will be
        reset to their default values.

        @return: the datetime that was set.
        """

        # dateFormat = xbmc.getRegion('dateshort')
        # correct a small bug in XBMC
        # dateFormat = dateFormat[1:].replace("D-M-", "%D-%M")
        # dateFormatLong = xbmc.getRegion('datelong')
        # timeFormat = xbmc.getRegion('time')
        # dateTimeFormat = "%s %s" % (dateFormat, timeFormat)

        try:
            dateFormat = "%Y-%m-%d"  # "%x"
            dateTimeFormat = dateFormat + " %H:%M"

            if hour is None and minutes is None and seconds is None:
                timeStamp = datetime.datetime(int(year), int(month), int(day))
                date = timeStamp.strftime(dateFormat)
            else:
                timeStamp = datetime.datetime(int(year), int(month), int(day),
                                              int(hour), int(minutes),
                                              int(seconds))
                date = timeStamp.strftime(dateTimeFormat)

            if onlyIfNewer and self.__timestamp > timeStamp:
                return

            self.__timestamp = timeStamp
            if text is None:
                self.__date = date
            else:
                self.__date = text

        except ValueError:
            Logger.Error(
                "Error setting date: Year=%s, Month=%s, Day=%s, Hour=%s, Minutes=%s, Seconds=%s",
                year,
                month,
                day,
                hour,
                minutes,
                seconds,
                exc_info=True)
            self.__timestamp = datetime.datetime.min
            self.__date = ""

        return self.__timestamp
コード例 #10
0
    def __init__(self, title, url, type="folder"):
        """Creates a new MediaItem

        Arguments:
        title  : string - the title of the item, used for appearance in lists.
        url    : string - url that used for further information retrieval.

        Keyword Arguments:
        type   : [opt] string    - type of MediaItem (folder, video, audio).
                                   Defaults to 'folder'.
        parent : [opt] MediaItem - the parent of the current item. None is
                                   the default.

        The <url> can contain an url to a site more info about the item can be
        retrieved, for instance for a video item to retrieve the media url, or
        in case of a folder where child items can be retrieved.

        Essential is that no encoding (like UTF8) is specified in the title of
        the item. This is all taken care of when creating XBMC items in the
        different methods.

        """

        name = title.strip()

        self.name = name
        self.url = url
        self.MediaItemParts = []
        self.description = ""
        self.thumb = ""  # : The local or remote image for the thumbnail of episode
        self.fanart = ""  # : The fanart url
        self.icon = ""  # : low quality icon for list

        self.__date = ""  # : value show in interface
        self.__timestamp = datetime.datetime.min  # : value for sorting, this one is set to minimum so if non is set, it's shown at the bottom

        self.type = type  # : video, audio, folder, append, page, playlist
        self.dontGroup = False  # : if set to True this item will not be auto grouped.
        self.isLive = False  # : if set to True, the item will have a random QuerySting param
        self.isGeoLocked = False  # : if set to True, the item is GeoLocked to the channels language (o)
        self.isDrmProtected = False  # : if set to True, the item is DRM protected and cannot be played (^)
        self.isPaid = False  # : if set to True, the item is a Paid item and cannot be played (*)
        self.__infoLabels = dict()  # : Additional Kodi InfoLabels

        self.complete = False
        self.downloaded = False
        self.downloadable = False
        self.items = []
        self.HttpHeaders = dict()  # : http headers for the item data retrieval
        self.rating = None

        # Items that are not essential for pickled
        self.isCloaked = False
        self.metaData = dict(
        )  # : Additional data that is for internal / routing use only

        # GUID used for identifcation of the object. Do not set from script, MD5 needed
        # to prevent UTF8 issues
        try:
            self.guid = "%s%s" % (EncodingHelper.EncodeMD5(title),
                                  EncodingHelper.EncodeMD5(url or ""))
            # self.guid = ("%s-%s" % (encodinghelper.EncodingHelper.EncodeMD5(title), url)).replace(" ", "")
        except:
            Logger.Error(
                "Error setting GUID for title:'%s' and url:'%s'. Falling back to UUID",
                title,
                url,
                exc_info=True)
            self.guid = self.__GetUUID()
        self.guidValue = int("0x%s" % (self.guid, ), 0)

        self.channels = []  # only needed for Kanalenkiezer
コード例 #11
0
    def __ImportChannels(self):  # , className = None):
        """Import the available channels

        This method will:
         - iterate through the Addons folder and find all the folders name
           <basename>.channel.<channelname>.
         - then adds all the subfolders into a list (with paths).
         - then all paths are added to the system path, so they can be imported.
         - then read all the chn_<name>.xml metadata files and add the ChannelInfo
           objects to the self.__channelsToImport
         - then the channels in the self.__channelsToImport list are instantiated
           into the self.channels list.

        """

        Logger.Debug("Importing available channels")
        # import each channelPath. On import, the channelPath will call the RegisterChannel Method
        try:
            # clear a possible previous import
            self.__enabledChannels = []
            self.__allChannels = []
            self.__validChannels = []
            self.__channelVersions = []

            # first find all folders with channels that we might need to import
            channelImport = []
            importTimer = StopWatch("ChannelImporter :: importing channels", Logger.Instance())

            addonPath = self.__GetAddonPath()

            channelPathStart = "%s.channel" % (Config.addonDir,)
            for directory in os.listdir(addonPath):
                if channelPathStart in directory and "BUILD" not in directory:
                    path = os.path.join(addonPath, directory)

                    channelVersion = self.__ParseChannelVersionInfo(path)
                    if channelVersion:
                        self.__channelVersions.append(channelVersion)
                    else:
                        # no info was returned, so we will not include the channel
                        continue

                    # get all nested channels
                    subDirs = os.listdir(path)
                    channelImport.extend(
                        [os.path.abspath(os.path.join(path, weapon)) for weapon in subDirs])

            channelImport.sort()
            importTimer.Lap("Directories scanned for .channel")

            # we need to make sure we don't load multiple channel classes and track if we found updates
            channelsUpdated = False
            loadedChannels = []
            channelsToImport = []

            # now import the channels
            for channelPath in channelImport:
                if not os.path.isdir(channelPath):
                    continue

                # determine channelname
                channelName = os.path.split(channelPath)[-1]
                if channelName == self.__updateChannelPath:
                    Logger.Trace("Update path found and skipping: %s", channelName)
                    continue

                # if loadedChannels.count(channelName) > 0:
                if channelName in loadedChannels:
                    Logger.Warning(
                        "Not loading: chn_%s.xml in %s because there is already a path with "
                        "name '%s' that name loaded", channelName, channelPath, channelName)
                    continue

                if channelName.startswith("."):
                    continue

                # now we can continue
                loadedChannels.append(channelName)

                fileName = os.path.join(channelPath, "chn_" + channelName + ".json")
                Logger.Trace("Loading info for chn_%s @ %s", channelName, fileName)
                if os.path.isfile(fileName):
                    try:
                        ci = ChannelInfo.FromJson(fileName)
                        if len(ci) <= 0:
                            Logger.Warning("No channels found in '%s'", fileName)
                            continue

                        # Add them to the list to import
                        channelsToImport += ci

                        if self.__IsChannelSetUpdated(ci[0]):
                            if not channelsUpdated:
                                # this was the first update found (otherwise channelsUpdated was True) show a message:
                                title = LanguageHelper.GetLocalizedString(
                                    LanguageHelper.InitChannelTitle)
                                text = LanguageHelper.GetLocalizedString(
                                    LanguageHelper.InitChannelText)
                                XbmcWrapper.ShowNotification(title, text, displayTime=15000)

                            # set the updates found bit
                            channelsUpdated |= True

                            # Initialise the channelset.
                            self.__InitialiseChannelSet(ci[0])

                            # And perform all first actions for the included channels in the set
                            for channelInfo in ci:
                                self.__FirstTimeChannelActions(channelInfo)
                    except:
                        Logger.Error("Error import chn_%s.json", channelName, exc_info=True)

            importTimer.Lap()

            # What platform are we
            platform = envcontroller.EnvController.GetPlatform()

            # instantiate the registered channels
            for channelInfo in channelsToImport:
                # noinspection PyUnusedLocal
                isValid = self.__ValidateChannelInfo(channelInfo, platform)

            # sort the channels
            self.__enabledChannels.sort()

            if channelsUpdated:
                Logger.Info("New or updated channels found. Updating add-on configuration for all "
                            "channels and user agent")
                AddonSettings.UpdateAddOnSettingsWithChannels(self.__validChannels, Config)
                AddonSettings.UpdateUserAgent()
            else:
                Logger.Debug("No channel changes found. Skipping add-on configuration for channels")

            # Should we update the channel index?
            if channelsUpdated or not os.path.isfile(self.__CHANNEL_INDEX):
                self.__CreateChannelIndex()

            Logger.Info("Imported %s channels from which %s are enabled",
                        len(self.__allChannels), len(self.__enabledChannels))
            importTimer.Stop()
        except:
            Logger.Critical("Error loading channel modules", exc_info=True)
コード例 #12
0
    def GetSingleChannel(self, className, channelCode):
        """Imports a single channel

        Arguments:
        className : string - class name of the channel to import.

        Returns:
        The channels in the requested class. So that could be more, but they
        can be distinguished using the channelcode.

        Returns an empty list if no channels were found.

        """

        if not className:
            raise ValueError("className should be specified.")

        Logger.Info("Loading channels for class '%s' and channelCode '%s'", className, channelCode)

        self.__enabledChannels = []
        self.__allChannels = []
        self.__validChannels = []
        self.__channelVersions = []

        # noinspection PyUnusedLocal
        classPath = None
        channelPath = None
        classBaseName = className[4:]
        if os.path.isfile(self.__CHANNEL_INDEX):
            Logger.Debug("Using ChannelIndex for channel lookup: %s", self.__CHANNEL_INDEX)
            fd = None
            try:
                fd = open(self.__CHANNEL_INDEX)
                data = fd.read()
            finally:
                if fd is not None and not fd.closed:
                    fd.close()
            channelIndex = JsonHelper(data)
            classPath = channelIndex.GetValue(className, channelCode or "null")
            if classPath is not None:
                if not os.path.isdir(classPath):
                    Logger.Warning("Missing channel class path '%s' found. Rebuilding the ChannelIndex.", classPath)
                    # remove the old one
                    os.remove(self.__CHANNEL_INDEX)
                    # return self.GetSingleChannel(className, channelCode)
                    return self.__ImportChannel(className, channelCode)
                channelPath = os.path.join(classPath, "..")
        else:
            Logger.Warning("Missing ChannelIndex. Rebuilding the ChannelIndex.")
            return self.__ImportChannel(className, channelCode)

            # Logger.Warning("Falling back to classic find pattern")
            #
            # # walk the channel dirs to find the one that has the channel
            # addonPath = self.__GetAddonPath()
            # channelPathStart = "%s.channel" % (Config.addonDir,)
            #
            # # list all add-ons
            # for directory in os.listdir(addonPath):
            #     # find the xot ones
            #     if channelPathStart in directory and "BUILD" not in directory:
            #         channelPath = os.path.join(addonPath, directory)
            #
            #         # list the subfolders for the requested folder to find the one we need
            #         if classBaseName not in os.listdir(channelPath):
            #             continue
            #
            #         # we perhaps found it.
            #         classPath = os.path.join(channelPath, classBaseName)

        if classPath is None:
            Logger.Error("No Channel found for class '%s' and channelCode '%s'",
                         className, channelCode)
            return None

        Logger.Debug("Found possible channel folder in %s", classPath)

        # check the addon.xml with self.__ParseChannelVersionInfo(path)
        channelVersion = self.__ParseChannelVersionInfo(channelPath)
        if channelVersion:
            self.__channelVersions.append(channelVersion)
        else:
            # no info was returned, so we will not include the channel
            Logger.Error("Match in %s has incorrect version", classPath)
            return None

        # create ChannelInfo objects from the xml file and get the correct ChannelInfo object. It coulde that none
        # is found and we might need to continue (in case there were duplicate channel names
        fileName = os.path.join(classPath, "chn_" + classBaseName + ".json")

        Logger.Debug("Loading info for chn_%s @ %s", classBaseName, fileName)
        if not os.path.isfile(fileName):
            Logger.Error("Could not load %s", fileName)
            return None

        cis = ChannelInfo.FromJson(fileName)
        ci = filter(lambda c: c.moduleName == className and (c.channelCode == channelCode or
                                                             c.channelCode is channelCode), cis)
        if not ci or len(ci) > 1:
            Logger.Error("Could not load channel with className=%s and channelCode=%s from %s",
                         className, channelCode, fileName)
            return None

        ci = ci[0]
        if self.__IsChannelSetUpdated(ci):
            # apparently a new channel was found, so we need to do it all
            Logger.Info("Found a new channel, we need to reload all channels")
            return self.__ImportChannel(className, channelCode)

        # What platform are we
        platform = envcontroller.EnvController.GetPlatform()

        # check if it is enabled or not
        if self.__ValidateChannelInfo(ci, platform):
            return ci.GetChannel()
        else:
            Logger.Error("Invalid Channel found for class '%s' and channelCode '%s'",
                         className, channelCode)
            return None
コード例 #13
0
    def GetSingleChannel_old(self, className, channelCode):
        """Imports a single channel

        Arguments:
        className : string - class name of the channel to import.

        Returns:
        The channels in the requested class. So that could be more, but they
        can be distinguished using the channelcode.

        Returns an empty list if no channels were found.

        """

        if not className:
            raise ValueError("className should be specified.")

        Logger.Info("Loading channels for class '%s' and channelCode '%s'", className, channelCode)

        self.__enabledChannels = []
        self.__allChannels = []
        self.__validChannels = []
        self.__channelVersions = []

        channel = None

        # walk the channel dirs to find the one that has the channel
        addonPath = self.__GetAddonPath()
        channelPathStart = "%s.channel" % (Config.addonDir, )
        folderToFind = className[4:]

        # list all add-ons
        for directory in os.listdir(addonPath):
            # find the xot ones
            if channelPathStart in directory and "BUILD" not in directory:
                channelPath = os.path.join(addonPath, directory)

                # list the subfolders for the requested folder to find the one we need
                if folderToFind not in os.listdir(channelPath):
                    continue

                # we perhaps found it.
                classPath = os.path.join(channelPath, folderToFind)
                Logger.Debug("Found possible channel folder in %s", classPath)

                # check the addon.xml with self.__ParseChannelVersionInfo(path)
                channelVersion = self.__ParseChannelVersionInfo(channelPath)
                if channelVersion:
                    self.__channelVersions.append(channelVersion)
                else:
                    # no info was returned, so we will not include the channel
                    Logger.Warning("Match in %s has incorrect version", classPath)
                    continue

                # create ChannelInfo objects from the xml file and get the correct ChannelInfo object. It coulde that none
                # is found and we might need to continue (in case there were duplicate channel names
                fileName = os.path.join(classPath, "chn_" + folderToFind + ".json")

                Logger.Debug("Loading info for chn_%s @ %s", folderToFind, fileName)
                if not os.path.isfile(fileName):
                    Logger.Warning("Could not load %s", fileName)
                    continue

                cis = ChannelInfo.FromJson(fileName)
                ci = filter(lambda c: c.moduleName == className and (c.channelCode == channelCode or c.channelCode is channelCode), cis)
                if not ci or len(ci) > 1:
                    Logger.Warning("Could not load channel with className=%s and channelCode=%s from %s", className, channelCode, fileName)
                    continue

                ci = ci[0]
                if self.__IsChannelSetUpdated(ci):
                    # apparently a new channel was found, so we need to do it all
                    Logger.Info("Found a new channel, we need to reload all channels")
                    return self.__ImportChannel(className, channelCode)

                # What platform are we
                platform = envcontroller.EnvController.GetPlatform()

                # check if it is enabled or not
                if self.__ValidateChannelInfo(ci, platform):
                    return ci.GetChannel()
                else:
                    continue

        Logger.Error("No Channel found for class '%s' and channelCode '%s'", className, channelCode)
        return channel
コード例 #14
0
    def __ConvertDCSubtitleToSrt(dcSubtitle):
        """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.

        """

        # parseRegex = '<subtitle[^>]+spotnumber="(\d+)" timein="(\d+:\d+:\d+):(\d+)" timeout="(\d+:\d+:\d+):(\d+)"[^>]+>\W+<text[^>]+>([^<]+)</text>\W+(?:<text[^>]+>([^<]+)</text>)*\W+</subtitle>'
        parseRegex = '<subtitle[^>]+spotnumber="(\d+)" timein="(\d+:\d+:\d+):(\d+)" timeout="(\d+:\d+:\d+):(\d+)"[^>]+>|<text[^>]+>([^<]+)</text>'
        parseRegex = parseRegex.replace('"', '["\']')
        subs = Regexer.DoRegex(parseRegex, dcSubtitle)

        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.HtmlEntityHelper.ConvertHTMLEntities(
                            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]) * 4)
                    end = "%s,%03d" % (sub[3], int(sub[4]) * 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
コード例 #15
0
    def __RebuildIndex(self):
        # type: () -> dict
        """ Rebuilds the channel index that contains all channels and performs all necessary steps:

        1. Find all channel add-on paths and determine the version of the channel add-on
        2. For all channel sets in the add-on:
            a. See if it is a new channel set (pyo and pyc check)
            b. If so, initialise the channel set and then perform the first time actions on
               the included channels.
            c. Add all channels within the channel set to the channelIndex

        @return: the new channel index dictionary object.

        Remark: this method only generates the index of the channels, it does not import at all!

        """

        if self.__reindexed:
            Logger.Error("Channel index was already re-indexed this run. Not doing it again.")
            return self.__channelIndex

        Logger.Info("Rebuilding the channel index.")
        index = {
            self.__CHANNEL_INDEX_ADD_ONS_KEY: [],
            self.__CHANNEL_INDEX_CHANNEL_KEY: {}
        }

        # iterate all Retrospect Video Add-ons
        addonPath = self.__GetAddonPath()
        channelPathStart = "%s.channel" % (Config.addonDir,)
        addOns = filter(lambda x: channelPathStart in x and "BUILD" not in x, os.listdir(addonPath))
        for addOnDir in addOns:
            index[self.__CHANNEL_INDEX_ADD_ONS_KEY].append(addOnDir)

            channelAddOnPath = os.path.join(addonPath, addOnDir)
            channelAddOnId, channelAddOnVersion = self.__ValidateAddOnVersion(channelAddOnPath)
            if channelAddOnId is None:
                continue

            channelSets = os.listdir(channelAddOnPath)
            for channelSet in channelSets:
                if not os.path.isdir(os.path.join(channelAddOnPath, channelSet)):
                    continue

                channelSetId = "chn_%s" % (channelSet,)
                Logger.Debug("Found channel set '%s'", channelSetId)
                index[self.__CHANNEL_INDEX_CHANNEL_KEY][channelSetId] = {
                    self.__CHANNEL_INDEX_CHANNEL_VERSION_KEY: str(channelAddOnVersion),
                    self.__CHANNEL_INDEX_CHANNEL_INFO_KEY: os.path.join(channelAddOnPath, channelSet, "%s.json" % (channelSetId,))
                }

        f = None
        try:
            f = open(self.__CHANNEL_INDEX, 'w+')
            f.write(JsonHelper.Dump(index))
        finally:
            if f is not None:
                f.close()

        # now we marked that we already re-indexed.
        self.__reindexed = True
        self.__channelIndex = index
        Logger.Info("Rebuilding channel index completed with %d channelSets and %d add-ons: %s.",
                    len(index[self.__CHANNEL_INDEX_CHANNEL_KEY]),
                    len(index[self.__CHANNEL_INDEX_ADD_ONS_KEY]),
                    index)

        envcontroller.EnvController.UpdateLocalAddons()
        return index
コード例 #16
0
    def DownloadSubtitle(url, fileName="", format='sami', proxy=None):
        """Downloads a SAMI and stores the SRT in the cache folder

        Arguments:
        url      : string - URL location of the SAMI file

        Keyword Arguments:
        fileName : string - Filename to use to store the subtitle in SRT format.
                            if not specified, an MD5 hash of the URL with .xml
                            extension will be used
        format : string   - defines the source format. Defaults to Sami.

        Returns:
        The full patch of the cached SRT file.

        """

        if fileName == "":
            Logger.Debug(
                "No filename present, generating filename using MD5 hash of url."
            )
            fileName = "%s.srt" % (
                encodinghelper.EncodingHelper.EncodeMD5(url), )
        elif not fileName.endswith(".srt"):
            Logger.Debug("No SRT extension present, appending it.")
            fileName = "%s.srt" % (fileName, )

        srt = ""
        try:
            localCompletePath = os.path.join(Config.cacheDir, fileName)

            # no need to download it again!
            if os.path.exists(localCompletePath):
                return localCompletePath

            Logger.Trace("Opening Subtitle URL")
            raw = UriHandler.Open(url, proxy=proxy)

            if raw == "":
                Logger.Warning(
                    "Empty Subtitle path found. Not setting subtitles.")
                return ""

            # try to decode it
            try:
                raw = raw.decode()
            except:
                Logger.Warning(
                    "Converting input to UTF-8 using 'unicode_escape'")
                raw = raw.decode('unicode_escape')

            if format.lower() == 'sami':
                srt = SubtitleHelper.__ConvertSamiToSrt(raw)
            elif format.lower() == 'srt':
                srt = raw
            elif format.lower() == 'ttml':
                srt = SubtitleHelper.__ConvertTtmlToSrt(raw)
            elif format.lower() == 'dcsubtitle':
                srt = SubtitleHelper.__ConvertDCSubtitleToSrt(raw)
            elif format.lower() == 'json':
                srt = SubtitleHelper.__ConvertJsonSubtitleToSrt(raw)
            else:
                error = "Uknown subtitle format: %s" % (format, )
                raise NotImplementedError(error)

            f = open(localCompletePath, 'w')
            f.write(srt)
            f.close()
            Logger.Info("Saved SRT as %s", localCompletePath)
            return localCompletePath
        except:
            Logger.Error("Error handling Subtitle file: [%s]",
                         srt,
                         exc_info=True)
            return ""
コード例 #17
0
    def InitSimpleExpressApp(self, args):
        if self.conf['app-type'] == 'virtualized' or self.conf['app-type'] == 'simple-express-app':
            return Logger.Error("This is already an {0} based repo, can't add this feature".format(self.conf['app-type']))

        return EF.Extend('express', args)
コード例 #18
0
    def __UpdateAddOnSettingsWithLanguages(contents, channels):
        """ Adds the channel showing/hiding to the settings.xml

        @param contents: The current settings
        @param channels: The available channels
        @return: updated contents and the offset in visibility

        """

        if "<!-- start of channel selection -->" not in contents:
            Logger.Error(
                "No '<!-- start of channel selection -->' found in settings.xml. Stopping updating."
            )
            return

        # First we create a new bit of settings file.
        channelXml = '        <!-- start of channel selection -->\n'

        # the distinct list of languages from the channels
        languages = map(lambda c: c.language, channels)
        languages = list(set(languages))
        languages.sort()
        Logger.Debug("Found languages: %s", languages)

        # get the labels and setting identifiers for those languages
        languageLookup = dict()
        for language in languages:
            languageLookup[
                language] = AddonSettings.__GetLanguageSettingsIdAndLabel(
                    language)

        languageLookupSortedKeys = languageLookup.keys()
        languageLookupSortedKeys.sort()

        # create a list of labels
        languageLabels = map(lambda l: str(languageLookup[l][1]),
                             languageLookupSortedKeys)
        channelXml = '%s        <setting type="lsep" label="30060" />\n' % (
            channelXml, )
        channelXml = '%s        <setting id="channel_selected" label="30061" type="labelenum" lvalues="30025|%s" />\n' % (
            channelXml,
            "|".join(languageLabels),
        )

        # we need to keep track of the number of lines, because we have
        # relative visible and enable settings.
        currentLine = 0  # the current line we are writing
        channelXml = '%s        <setting type="sep" />\n' % (channelXml, )
        currentLine += 1

        # first add the overall language settings
        for language in languageLookupSortedKeys:
            currentLine += 1
            languageIndex = languageLookupSortedKeys.index(
                language) + 1  # correct of the None label
            channelXml = '%s        <setting id="%s" type="bool" label="30042" default="true" visible="eq(-%s,%s)" /><!-- %s -->\n' % (
                channelXml, languageLookup[language][0], currentLine,
                languageIndex, languageLookup[language][1])

        # then the channels
        for channel in channels:
            currentLine += 1
            name = channel.channelName
            languageIndex = languageLookupSortedKeys.index(
                channel.language) + 1  # correct of the None label
            channelXml = '%s        <setting id="%s" type="bool" label="- %s" default="true" visible="eq(-%s,%s)" enable="eq(-%s,True)" />\n' % (
                channelXml, AddonSettings.__CHANNEL_SETTINGS_PATTERN %
                (channel.guid, ), name, currentLine, languageIndex,
                currentLine - languageIndex - 1)

        begin = contents[:contents.find('<!-- start of channel selection -->'
                                        )].strip()
        end = contents[contents.find('<!-- end of channel selection -->'
                                     ):].strip()
        contents = "%s\n    \n%s        %s" % (begin, channelXml, end)
        return contents
コード例 #19
0
    def AddDocker(self, args):
        if self.conf['app-type'] == 'non-virtualized':
            return Logger.Error("This is already an {0} based repo, can't add this feature".format(self.conf['app-type']))

        return EF.Extend('docker', args)
コード例 #20
0
ファイル: youtube.py プロジェクト: normico21/repository.xvbmc
    def GetStreamsFromYouTube(url, proxy=None):
        """ Parsers standard YouTube videos and returns a list of tuples with streams and bitrates that can be used by
        other methods

        @param proxy:   Proxy  - The proxy to use for opening
        @param url:     String - The url to download

        Can be used like this:

            part = item.CreateNewEmptyMediaPart()
            for s, b in YouTube.GetStreamsFromYouTube(url, self.proxy):
                item.complete = True
                # s = self.GetVerifiableVideoUrl(s)
                part.AppendMediaStream(s, b)
        """

        youTubeStreams = []
        youTubeAddOnAvailable = xbmc.getCondVisibility(
            'System.HasAddon("plugin.video.youtube")') == 1

        if youTubeAddOnAvailable:
            Logger.Info("Found Youtube add-on. Using it")
            youTubeStreams.append((YouTube.__PlayYouTubeUrl(url), 0))
            Logger.Trace(youTubeStreams)
            return youTubeStreams

        Logger.Info("No Kodi Youtube Video add-on was found. Falling back.")

        if "watch?v=" in url:
            videoId = url.split("?v=")[-1]
            Logger.Debug("Using Youtube ID '%s' retrieved from '%s'", videoId,
                         url)
            # get the meta data url
            url = "http://www.youtube.com/get_video_info?hl=en_GB&asv=3&video_id=%s" % (
                videoId, )

        elif "get_video_info" not in url:
            Logger.Error("Invalid Youtube URL specified: '%s'", url)
            return url

        data = UriHandler.Open(url, proxy=proxy)
        # get the stream data from the page
        urlEncodedFmtStreamMap = Regexer.DoRegex(
            "url_encoded_fmt_stream_map=([^&]+)", data)
        urlEncodedFmtStreamMapData = HtmlEntityHelper.UrlDecode(
            urlEncodedFmtStreamMap[0])
        # split per stream
        streams = urlEncodedFmtStreamMapData.split(',')

        for stream in streams:
            # let's create a new part
            qsData = dict([x.split("=") for x in stream.split("&")])
            Logger.Trace(qsData)

            # get the stream encoding information from the iTag
            iTag = int(qsData.get('itag', -1))
            streamEncoding = YouTube.__YouTubeEncodings.get(iTag, None)
            if streamEncoding is None:
                # if the iTag was not in the list, skip it.
                Logger.Debug(
                    "Not using iTag %s as it is not in the list of supported encodings.",
                    iTag)
                continue

            bitrate = streamEncoding[0]
            signature = qsData.get('sig', None)
            quality = qsData['quality']
            videoUrl = HtmlEntityHelper.UrlDecode(qsData['url'])
            if signature is None:
                url = "%s&&quality=%s&ext=.%s" % (videoUrl, quality,
                                                  streamEncoding[1])
            else:
                url = "%s&signature=%s&quality=%s&ext=.%s" % (
                    videoUrl, signature, quality, streamEncoding[1])

            youTubeStreams.append((url, bitrate))

        return youTubeStreams
コード例 #21
0
    def CreateFolderItem(self, resultSet):
        """Creates a MediaItem of type 'folder' using the resultSet from the regex.

        Arguments:
        resultSet : tuple(strig) - the resultSet of the self.folderItemRegex

        Returns:
        A new MediaItem of type 'folder'

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

        """

        Logger.Trace(resultSet)
        matchedRegex = resultSet[0]
        resultSet = resultSet[1]

        if matchedRegex == 0:
            #  Main regex match for the More Clips/Episodes
            folderId = resultSet["url"]
            folderType = resultSet["type"]

            # http://www.kijk.nl/ajax/qw/moreepisodes?format=wegmisbruikers&page=1&season=0&station=sbs6
            if "ajax" in self.parentItem.url:
                # for ajax pages determine the next one and it's always a clip list or episode list
                folderNumber = int(self.parentItem.url.split("/")[-2])
                folderNumber += 1
                if "clip" in self.parentItem.url.lower():
                    title = "\bMeer clips"
                else:
                    title = "\bMeer afleveringen"

            elif "clip" in folderType.lower():
                # default clip start page = 1
                title = "\bClips"
                folderNumber = 1
            else:
                # default more episode page = 2
                title = "\bMeer afleveringen"
                folderNumber = 2

            url = "http://www.kijk.nl/ajax/section/series/%s/%s/%s" % (
                folderId, folderNumber, self.pageSize)

        elif matchedRegex == 1:
            # match for the Seasons on the main pages.
            if "ajax" in self.parentItem.url:
                # don't add then om Ajax call backs, only on main listing
                return None

            title = resultSet["title"]
            url = resultSet["url"]
            url = "http://www.kijk.nl/ajax/section/series/%s/1/%s" % (
                url, self.pageSize)
        else:
            Logger.Error("Unmatched multi regex match")
            return None

        item = mediaitem.MediaItem(title, url)
        item.thumb = self.noImage
        item.icon = self.icon
        item.type = 'folder'
        item.complete = True
        Logger.Trace(item)
        return item