Пример #1
0
    def __Store(self, updateFirstTimeMessage=True):
        # type: () -> bool
        """ Store the current cloak information to the profile folder.

        @type updateFirstTimeMessage: bool
        @return: boolean indicating whether this was the first run.

        """

        firstTime = not self.__cloaked.get(Cloaker.__MESSAGE_SHOWN, False)

        # update the first time message setting unless we should not.
        if updateFirstTimeMessage:
            self.__cloaked[Cloaker.__MESSAGE_SHOWN] = updateFirstTimeMessage

        with file(self.__cloakedSettings, mode='w') as fp:
            if self.__logger:
                self.__logger.Info(
                    "Storing Cloaking information to cloak file '%s'.",
                    self.__cloakedSettings)
            fp.write(JsonHelper.Dump(self.__cloaked, prettyPrint=True))

        if self.__logger:
            self.__logger.Debug("First time cloak found.")
        return firstTime
Пример #2
0
    def __init__(self, profilePath, channelId, logger=None):
        """ Creates a Cloaker object that helps with cloaking objects

        @param profilePath: the path to the Kodi profile settings folder.
        @param channelId:   the GUID of the channel for which we need cloak information.
        @param logger:      a Logger object for logging purposes.

        """

        self.__cloakedSettings = os.path.join(profilePath, "cloaked.json")
        self.__logger = logger
        self.__channelId = channelId

        if self.__logger:
            self.__logger.Debug("Setting up a Cloaker based on '%s'",
                                self.__cloakedSettings)

        # Create a new file if none existed
        if not os.path.exists(self.__cloakedSettings):
            self.__cloaked = {Cloaker.__MESSAGE_SHOWN: False}
            if self.__logger:
                self.__logger.Info(
                    "Creating a new cloaked settings file at '%s'",
                    self.__cloakedSettings)
            # store but keep the first time message
            self.__Store(False)

        with file(self.__cloakedSettings, mode='r') as fp:
            self.__cloaked = JsonHelper.Loads(fp.read())

        if self.__channelId not in self.__cloaked:
            self.__cloaked[self.__channelId] = {}
            # store but keep the first time message
            self.__Store(False)

        if self.__logger:
            self.__logger.Trace(
                "Found cloaked data:\n%s",
                JsonHelper.Dump(self.__cloaked, prettyPrint=True))
Пример #3
0
    def __CreateChannelIndex(self):
        """ Creates a channel index file for lookups purposes """

        indexPath = self.__CHANNEL_INDEX
        Logger.Info("Generating channel index at '%s'", indexPath)
        channels = dict()
        for channel in self.__allChannels:
            if channel.moduleName not in channels:
                channels[channel.moduleName] = dict()
            if channel.channelCode in channels[channel.moduleName]:
                Logger.Error("Cannot create duplicate channelCode for channel:\n'%s'", channel)
            else:
                channels[channel.moduleName][channel.channelCode] = channel.path

        data = JsonHelper.Dump(channels)
        fd = None
        try:
            fd = file(indexPath, mode='w')
            fd.write(data)
        finally:
            if fd is not None and not fd.closed:
                fd.close()
        return
Пример #4
0
    def __UpdateVideoItem(self, item, videoId):
        # we need a token:
        token = self.__GetToken()

        # deviceId = AddonSettings.GetClientId()
        mediaUrl = "https://vod.medialaan.io/vod/v2/videos/" \
                   "%s" \
                   "/watch?deviceId=%s" % (
                       videoId,
                       uuid.uuid4()
                   )

        auth = "apikey=%s&access_token=%s" % (self.__apiKey, token)
        headers = {"Authorization": auth}
        data = UriHandler.Open(mediaUrl, proxy=self.proxy, additionalHeaders=headers)

        jsonData = JsonHelper(data)
        dashInfo = jsonData.GetValue("response", "dash-cenc")
        if self.__dashStreamsSupported and dashInfo:
            Logger.Debug("Using Dash streams to playback")
            dashInfo = jsonData.GetValue("response", "dash-cenc")
            licenseUrl = dashInfo["widevineLicenseServerURL"]
            streamUrl = dashInfo["url"]
            sessionId = jsonData.GetValue("request", "access_token")

            licenseHeader = {
                "merchant": "medialaan",
                "userId": self.__userId,
                "sessionId": sessionId
            }
            licenseHeader = JsonHelper.Dump(licenseHeader, False)
            licenseHeaders = "x-dt-custom-data={0}&Content-Type=application/octstream".format(base64.b64encode(licenseHeader))

            kodiProps = {
                "inputstreamaddon": "inputstream.adaptive",
                "inputstream.adaptive.manifest_type": "mpd",
                "inputstream.adaptive.license_type": "com.widevine.alpha",
                "inputstream.adaptive.license_key": "{0}?specConform=true|{1}|R{{SSM}}|".format(licenseUrl, licenseHeaders or "")
            }

            part = item.CreateNewEmptyMediaPart()
            stream = part.AppendMediaStream(streamUrl, 0)
            # noinspection PyTypeChecker
            for k, v in kodiProps.iteritems():
                stream.AddProperty(k, v)
        else:
            Logger.Debug("No Dash streams supported or no Dash streams available. Using M3u8 streams")

            m3u8Url = jsonData.GetValue("response", "hls-encrypted", "url")
            if not m3u8Url:
                m3u8Url = jsonData.GetValue("response", "uri")
                # m3u8Url = jsonData.GetValue("response", "hls-drm-uri")  # not supported by Kodi

            part = item.CreateNewEmptyMediaPart()
            # Set the Range header to a proper value to make all streams start at the beginning. Make
            # sure that a complete TS part comes in a single call otherwise we get stuttering.
            byteRange = 10 * 1024 * 1024
            Logger.Debug("Setting an 'Range' http header of bytes=0-%d to force playback at the start "
                         "of a stream and to include a full .ts part.", byteRange)
            part.HttpHeaders["Range"] = 'bytes=0-%d' % (byteRange, )

            for s, b in M3u8.GetStreamsFromM3u8(m3u8Url, self.proxy):
                item.complete = True
                # s = self.GetVerifiableVideoUrl(s)
                part.AppendMediaStream(s, b)

        return item
Пример #5
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