def Authenticate(baseUrl,
                     authenticationMethod,
                     username=None,
                     userId=None,
                     password=None,
                     deviceId=None):
        if not password:
            raise ValueError('invalid password')

        # prepare the authentication URL
        authUrl = baseUrl
        authUrl = Url.append(authUrl, constants.URL_USERS)

        body = {constants.PROPERTY_USER_AUTHENTICATION_PASSWORD: password}
        if authenticationMethod == Authentication.Method.UserId:
            if not userId:
                raise ValueError('invalid userId')

            authUrl = Url.append(authUrl, userId, constants.URL_AUTHENTICATE)

        elif authenticationMethod == Authentication.Method.Username:
            if not username:
                raise ValueError('invalid username')

            authUrl = Url.append(authUrl, constants.URL_AUTHENTICATE_BY_NAME)

            body[constants.PROPERTY_USER_AUTHENTICATION_USERNAME] = username

        else:
            raise ValueError('invalid authenticationMethod')

        headers = Request.PrepareApiCallHeaders(deviceId=deviceId,
                                                userId=userId)
        headers['Content-Type'] = constants.EMBY_CONTENT_TYPE

        resultObj = Request.PostAsJson(
            authUrl,
            headers=headers,
            json=body,
            timeout=Authentication.REQUEST_TIMEOUT_S)
        if not resultObj:
            return Authentication.Result()

        if constants.PROPERTY_USER_AUTHENTICATION_ACCESS_TOKEN not in resultObj:
            return Authentication.Result()
        accessToken = \
            resultObj[constants.PROPERTY_USER_AUTHENTICATION_ACCESS_TOKEN]

        if constants.PROPERTY_USER_AUTHENTICATION_USER not in resultObj:
            return Authentication.Result()
        userObj = resultObj[constants.PROPERTY_USER_AUTHENTICATION_USER]
        if constants.PROPERTY_USER_AUTHENTICATION_USER_ID not in userObj:
            return Authentication.Result()

        userId = userObj[constants.PROPERTY_USER_AUTHENTICATION_USER_ID]

        return Authentication.Result(result=True,
                                     accessToken=accessToken,
                                     userId=userId)
Exemplo n.º 2
0
    def BuildUserUrl(self, endpoint):
        if not endpoint:
            raise ValueError('Invalid endpoint')
        if not self._authenticate():
            raise RuntimeError('media provider {} has not yet been authenticated'.format(self._id))

        url = self._url
        userId = self.UserId()
        if not userId:
            raise RuntimeError('No valid user authentication available to access endpoint "{}"'.format(endpoint))
        url = Url.append(url, constants.URL_USERS, userId)

        return Url.append(url, endpoint)
Exemplo n.º 3
0
    def BuildUserUrl(self, endpoint):
        if not endpoint:
            raise ValueError('Invalid endpoint')
        self._assertAuthentication()

        url = self._url
        userId = self.UserId()
        if not userId:
            raise RuntimeError(
                'No valid user authentication available to access endpoint "{}"'
                .format(endpoint))
        url = Url.append(url, constants.URL_USERS, userId)

        return Url.append(url, endpoint)
Exemplo n.º 4
0
    def Authenticate(username, password):
        if not username:
            raise ValueError('invalid username')
        if not password:
            raise ValueError('invalid password')

        url = Url.append(constants.URL_EMBY_CONNECT_BASE, constants.URL_EMBY_CONNECT_AUTHENTICATE)
        headers = EmbyConnect._getApplicationHeader()

        body = {
            constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_NAME_OR_EMAIL: username,
            constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_PASSWORD: hashlib.md5(password),  # nosec
        }

        resultObj = Request.PostAsJson(url, headers=headers, json=body)
        if not resultObj or \
           constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_ACCESS_TOKEN not in resultObj or \
           constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_USER not in resultObj:
            log('invalid response from {}: {}'.format(url, resultObj))
            return None

        userObj = resultObj.get(constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_USER)
        if constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_USER_ID not in userObj:
            log('invalid response from {}: {}'.format(url, resultObj))
            return None

        return EmbyConnect.AuthenticationResult(
            accessToken=resultObj.get(constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_ACCESS_TOKEN),
            userId=userObj.get(constants.PROPERTY_EMBY_CONNECT_AUTHENTICATION_USER_ID)
        )
Exemplo n.º 5
0
        def exchange(self):
            if not self.pin:
                return None

            if not self.finished or self.expired:
                return None

            if self._authenticationResult:
                return self._authenticationResult

            url = Url.append(constants.URL_EMBY_CONNECT_BASE, constants.URL_EMBY_CONNECT_PIN,
                             constants.URL_EMBY_CONNECT_PIN_AUTHENTICATE)
            body = {
                constants.URL_QUERY_DEVICE_ID: self.deviceId,
                constants.URL_QUERY_PIN: self.pin,
            }

            resultObj = Request.PostAsJson(url, json=body)
            if not resultObj or \
               constants.PROPERTY_EMBY_CONNECT_PIN_USER_ID not in resultObj or \
               constants.PROPERTY_EMBY_CONNECT_PIN_ACCESS_TOKEN not in resultObj:
                log('failed to authenticate with PIN {} at {}: {}'.format(self.pin, url, resultObj))
                return None

            self._authenticationResult = EmbyConnect.AuthenticationResult(
                accessToken=resultObj.get(constants.PROPERTY_EMBY_CONNECT_PIN_ACCESS_TOKEN),
                userId=resultObj.get(constants.PROPERTY_EMBY_CONNECT_PIN_USER_ID))
            return self._authenticationResult
Exemplo n.º 6
0
        def checkLogin(self):
            if self.finished:
                return not self.expired

            url = Url.append(constants.URL_EMBY_CONNECT_BASE, constants.URL_EMBY_CONNECT_PIN)
            url = Url.addOptions(url, {
                constants.URL_QUERY_DEVICE_ID: self.deviceId,
                constants.URL_QUERY_PIN: self.pin,
            })

            resultObj = Request.GetAsJson(url)
            if not resultObj or \
               constants.PROPERTY_EMBY_CONNECT_PIN_IS_CONFIRMED not in resultObj or \
               constants.PROPERTY_EMBY_CONNECT_PIN_IS_EXPIRED not in resultObj:
                log('failed to check status of PIN {} at {}: {}'.format(self.pin, url, resultObj), xbmc.LOGWARNING)
                self.finished = True
                self.expired = True
                return False

            self.finished = resultObj.get(constants.PROPERTY_EMBY_CONNECT_PIN_IS_CONFIRMED)
            self.expired = resultObj.get(constants.PROPERTY_EMBY_CONNECT_PIN_IS_EXPIRED)
            if self.expired:
                self.finished = True

            return self.finished
Exemplo n.º 7
0
    def BuildPublicInfoUrl(baseUrl):
        if not baseUrl:
            raise ValueError('Invalid baseUrl')

        return Url.append(Server._buildBaseUrl(baseUrl), constants.URL_SYSTEM,
                          constants.URL_SYSTEM_INFO,
                          constants.URL_SYSTEM_INFO_PUBLIC)
Exemplo n.º 8
0
    def BuildPublicInfoUrl(baseUrl):
        if not baseUrl:
            raise ValueError('Invalid baseUrl')

        return Url.append(baseUrl, constants.EMBY_PROTOCOL,
                          constants.URL_SYSTEM, constants.URL_SYSTEM_INFO,
                          constants.URL_SYSTEM_INFO_PUBLIC)
Exemplo n.º 9
0
    def BuildDirectStreamUrl(self, mediaType, itemId, container):
        if not itemId:
            raise ValueError('Invalid itemId')

        embyMediaType = None
        if mediaType == 'Video':
            embyMediaType = constants.URL_PLAYBACK_MEDIA_TYPE_VIDEO
        elif mediaType == 'Audio':
            embyMediaType = constants.URL_PLAYBACK_MEDIA_TYPE_AUDIO
        else:
            raise ValueError('Invalid mediaType "{}"'.format(mediaType))

        url = self.BuildUrl(embyMediaType)
        url = Url.append(url, itemId, constants.URL_PLAYBACK_STREAM)
        if container:
            containers = container.split(',')
            # TODO(Montellese): for now pick the first container but maybe we
            # need some sanity checking / priorization
            url = '{}.{}'.format(url, containers[0])

        url = Url.addOptions(
            url, {
                constants.URL_PLAYBACK_OPTION_STATIC:
                constants.URL_PLAYBACK_OPTION_STATIC_TRUE,
                constants.URL_QUERY_API_KEY: self.AccessToken()
            })

        return url
Exemplo n.º 10
0
    def GetPublicUsers(baseUrl, deviceId=None):
        users = []

        usersUrl = Url.append(baseUrl, constants.EMBY_PROTOCOL,
                              constants.URL_USERS, constants.URL_USERS_PUBLIC)
        headers = Request.PrepareApiCallHeaders(deviceId=deviceId)
        resultObj = Request.GetAsJson(usersUrl, headers=headers)
        if not resultObj:
            return users

        for userObj in resultObj:
            # make sure the 'Name' and 'Id' properties are available
            if not constants.PROPERTY_USER_NAME in userObj or not constants.PROPERTY_USER_ID in userObj:
                continue

            # make sure the name and id properties are valid
            user = User(userObj[constants.PROPERTY_USER_NAME],
                        userObj[constants.PROPERTY_USER_ID])
            if not user.name or not user.id:
                continue

            # check if the user is disabled
            if constants.PROPERTY_USER_POLICY in userObj and \
               constants.PROPERTY_USER_IS_DISABLED in userObj[constants.PROPERTY_USER_POLICY] and \
               userObj[constants.PROPERTY_USER_POLICY][constants.PROPERTY_USER_IS_DISABLED]:
                continue

            users.append(user)

        return users
Exemplo n.º 11
0
    def BuildImageUrl(self, itemId, imageType, imageTag=''):
        if not itemId:
            raise ValueError('Invalid itemId')
        if not imageType:
            raise ValueError('Invalid imageType')

        url = self.BuildItemUrl(itemId)
        url = Url.append(url, constants.URL_IMAGES, imageType)
        if imageTag:
            url = Url.addOptions(url, {constants.URL_QUERY_TAG: imageTag})

        return url
Exemplo n.º 12
0
    def BuildConnectExchangeUrl(baseUrl, userId):
        if not baseUrl:
            raise ValueError('Invalid baseUrl')
        if not userId:
            raise ValueError('Invalid userId')

        url = Url.append(Server._buildBaseUrl(baseUrl), constants.URL_CONNECT, constants.URL_CONNECT_EXCHANGE)
        url = Url.addOptions(url, {
            constants.URL_QUERY_CONNECT_EXCHANGE_FORMAT: constants.URL_QUERY_CONNECT_EXCHANGE_FORMAT_JSON,
            constants.URL_QUERY_CONNECT_EXCHANGE_USER_ID: userId,
        })

        return url
Exemplo n.º 13
0
    def GetServers(accessToken, userId):
        if not accessToken:
            raise ValueError('invalid accessToken')
        if not userId:
            raise ValueError('invalid userId')

        url = Url.append(constants.URL_EMBY_CONNECT_BASE,
                         constants.URL_EMBY_CONNECT_SERVERS)
        url = Url.addOptions(url, {
            constants.URL_QUERY_USER_ID: userId,
        })
        headers = EmbyConnect._getApplicationHeader()
        headers.update({
            constants.EMBY_CONNECT_USER_TOKEN_HEADER: accessToken,
        })

        resultObj = Request.GetAsJson(url, headers=headers)
        if not resultObj:
            log('invalid response from {}: {}'.format(url, resultObj))
            return None

        servers = []
        for server in resultObj:
            id = server.get(constants.PROPERTY_EMBY_CONNECT_SERVER_ID, None)
            systemId = server.get(
                constants.PROPERTY_EMBY_CONNECT_SERVER_SYSTEM_ID, None)
            accessKey = server.get(
                constants.PROPERTY_EMBY_CONNECT_SERVER_ACCESS_KEY, None)
            name = server.get(constants.PROPERTY_EMBY_CONNECT_SERVER_NAME,
                              None)
            remoteUrl = server.get(
                constants.PROPERTY_EMBY_CONNECT_SERVER_REMOTE_URL, None)
            localUrl = server.get(
                constants.PROPERTY_EMBY_CONNECT_SERVER_LOCAL_URL, None)

            if None in (id, accessKey, name, remoteUrl, localUrl):
                log('invalid Emby server received from {}: {}'.format(
                    url, server))
                continue

            servers.append(
                EmbyConnect.Server(id=id,
                                   systemId=systemId,
                                   accessKey=accessKey,
                                   name=name,
                                   remoteUrl=remoteUrl,
                                   localUrl=localUrl))

        return servers
Exemplo n.º 14
0
    def BuildSubtitleStreamUrl(self, itemId, sourceId, index, codec):
        if not itemId:
            raise ValueError('invalid itemId')
        if not sourceId:
            raise ValueError('invalid sourceId')
        if not index:
            raise ValueError('invalid index')
        if not codec:
            raise ValueError('invalid codec')

        # <url>/Videos/<itemId>/<sourceId>/Subtitles/<index>/Stream.<codec>?api_key=<token>
        url = Url.append(self._url, constants.URL_VIDEOS, itemId, sourceId, constants.URL_VIDEOS_SUBTITLES, str(index),
                         constants.URL_VIDEOS_SUBTITLES_STREAM)
        url = '{}.{}'.format(url, codec)
        return Url.addOptions(url, {constants.URL_QUERY_API_KEY: self._authenticator.AccessToken()})
Exemplo n.º 15
0
        def GetItems(embyServer, date, filters=None):
            if not embyServer:
                raise ValueError('invalid embyServer')
            if not date:
                raise ValueError('invalid date')

            # determine the endpoint based on whether we are talking to an Emby or Jellyfin server
            endpoint = KodiCompanion.SyncQueue.ENDPOINT_EMBY
            serverInfo = Server.GetInfo(embyServer.Url())
            if serverInfo and serverInfo.isJellyfinServer():
                endpoint = KodiCompanion.SyncQueue.ENDPOINT_JELLYFIN

            # build the URL to retrieve the items from the sync queue
            url = embyServer.BuildUrl(endpoint)
            url = Url.append(url, embyServer.UserId(),
                             KodiCompanion.SyncQueue.ENDPOINT_GET_ITEMS)
            url = Url.addOptions(
                url, {
                    KodiCompanion.SyncQueue.QUERY_GET_ITEMS_LAST_UPDATE: date,
                    KodiCompanion.SyncQueue.QUERY_GET_ITEMS_FILTER: filters
                })

            itemsObj = embyServer.ApiGet(url)
            if not itemsObj:
                return []

            itemsAdded = []
            itemsUpdated = []
            itemsRemoved = []
            userDataChanged = []
            if KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_ADDED in itemsObj:
                itemsAdded = itemsObj[
                    KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_ADDED]
            if KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_UPDATED in itemsObj:
                itemsUpdated = itemsObj[
                    KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_UPDATED]
            if KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_REMOVED in itemsObj:
                itemsRemoved = itemsObj[
                    KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_REMOVED]
            if KodiCompanion.SyncQueue.PROPERTY_GET_ITEMS_USER_DATA_CHANGED in itemsObj:
                userDataChanged = itemsObj[
                    KodiCompanion.SyncQueue.
                    PROPERTY_GET_ITEMS_USER_DATA_CHANGED]

            return KodiCompanion.SyncQueue(itemsAdded=itemsAdded,
                                           itemsUpdated=itemsUpdated,
                                           itemsRemoved=itemsRemoved,
                                           userDataChanged=userDataChanged)
Exemplo n.º 16
0
        def _getPin(self):
            if self.pin:
                return self.pin

            url = Url.append(constants.URL_EMBY_CONNECT_BASE,
                             constants.URL_EMBY_CONNECT_PIN)
            body = {constants.URL_QUERY_DEVICE_ID: self.deviceId}

            resultObj = Request.PostAsJson(url, json=body)
            if not resultObj or \
               not constants.PROPERTY_EMBY_CONNECT_PIN in resultObj:
                log('failed to get a PIN from {}: {}'.format(url, resultObj))
                return None

            self.pin = resultObj.get(constants.PROPERTY_EMBY_CONNECT_PIN)

            return self.pin
Exemplo n.º 17
0
    def BuildDirectStreamUrl(self, mediaType, itemId):
        if not itemId:
            raise ValueError('Invalid itemId')

        embyMediaType = None
        if mediaType == 'Video':
            embyMediaType = constants.URL_PLAYBACK_MEDIA_TYPE_VIDEO
        elif mediaType == 'Audio':
            embyMediaType = constants.URL_PLAYBACK_MEDIA_TYPE_AUDIO
        else:
            raise ValueError('Invalid mediaType "{}"'.format(mediaType))

        url = self.BuildUrl(embyMediaType)
        url = Url.append(url, itemId, constants.URL_PLAYBACK_STREAM)

        url = Url.addOptions(url, {
            constants.URL_PLAYBACK_OPTION_STATIC: constants.URL_PLAYBACK_OPTION_STATIC_TRUE,
            constants.URL_QUERY_API_KEY: self.AccessToken()
        })

        return url
Exemplo n.º 18
0
    def __init__(self, provider):
        if not provider:
            raise ValueError('Invalid provider')

        self._baseUrl = provider.getBasePath()
        self._url = Url.append(self._baseUrl, constants.EMBY_PROTOCOL)
        self._id = provider.getIdentifier()

        settings = provider.getSettings()
        if not settings:
            raise ValueError('Invalid provider without settings')

        self._devideId = settings.getString(
            constants.SETTING_PROVIDER_DEVICEID)

        userId = settings.getString(constants.SETTING_PROVIDER_USER)
        username = settings.getString(constants.SETTING_PROVIDER_USERNAME)
        password = settings.getString(constants.SETTING_PROVIDER_PASSWORD)
        if userId == constants.SETTING_PROVIDER_USER_OPTION_MANUAL:
            self._authenticator = Authenticator.WithUsername(
                self._url, self._devideId, username, password)
        else:
            self._authenticator = Authenticator.WithUserId(
                self._url, self._devideId, userId, password)
Exemplo n.º 19
0
    def BuildStreamDeliveryUrl(self, deliveryUrl):
        if not deliveryUrl:
            raise ValueError('invalid deliveryUrl')

        return Url.append(self._url, deliveryUrl)
Exemplo n.º 20
0
    def BuildUrl(self, endpoint):
        if not endpoint:
            raise ValueError('Invalid endpoint')

        url = self._url
        return Url.append(url, endpoint)
Exemplo n.º 21
0
 def _buildBaseUrl(baseUrl):
     return Url.append(baseUrl, constants.EMBY_PROTOCOL)
Exemplo n.º 22
0
    def BuildIconUrl(baseUrl):
        if not baseUrl:
            raise ValueError('Invalid baseUrl')

        return Url.append(baseUrl, constants.EMBY_PROTOCOL, 'web',
                          'touchicon144.png')
Exemplo n.º 23
0
    def BuildIconUrl(baseUrl):
        if not baseUrl:
            raise ValueError('Invalid baseUrl')

        return Url.append(Server._buildBaseUrl(baseUrl), 'web', 'touchicon144.png')
Exemplo n.º 24
0
 def BuildSessionsPlayingStoppedUrl(self):
     url = self.BuildSessionsPlayingUrl()
     return Url.append(url, constants.URL_SESSIONS_PLAYING_STOPPED)
Exemplo n.º 25
0
 def BuildSessionsPlayingProgressUrl(self):
     url = self.BuildSessionsPlayingUrl()
     return Url.append(url, constants.URL_SESSIONS_PLAYING_PROGRESS)
Exemplo n.º 26
0
 def BuildSessionsPlayingUrl(self):
     url = self._url
     return Url.append(url, constants.URL_SESSIONS, constants.URL_SESSIONS_PLAYING)
Exemplo n.º 27
0
    def BuildLocalTrailersUrl(self, itemId):
        if not itemId:
            raise ValueError('Invalid itemId')

        url = self.BuildUserItemUrl(itemId)
        return Url.append(url, constants.URL_LOCAL_TRAILERS)
Exemplo n.º 28
0
    def BuildItemRefreshUrl(self, itemId):
        if not itemId:
            raise ValueError('Invalid itemId')

        url = self.BuildItemUrl(itemId)
        return Url.append(url, constants.URL_ITEMS_REFRESH)
Exemplo n.º 29
0
    def BuildUserItemUserDataUrl(self, itemId):
        if not itemId:
            raise ValueError('Invalid itemId')

        url = self.BuildUserUrl(constants.URL_ITEMS)
        return Url.append(url, itemId, constants.URL_USER_DATA)
Exemplo n.º 30
0
    def BuildUserPlayedItemUrl(self, itemId):
        if not itemId:
            raise ValueError('Invalid itemId')

        url = self.BuildUserUrl(constants.URL_PLAYED_ITEMS)
        return Url.append(url, itemId)