def get_items(self, category=None, content_filter=None, cache=CACHE_ONLY):
        """ Get a list of all the items in a category.

        :type category: str
        :type content_filter: class
        :type cache: int
        :rtype list[resources.lib.streamz.Movie | resources.lib.streamz.Program]
        """
        # Fetch from API
        response = util.http_get(API_ENDPOINT + '/%s/catalog' % self._mode(),
                                 params={'pageSize': 2000, 'filter': quote(category) if category else None},
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        info = json.loads(response.text)
        content = info.get('pagedTeasers', {}).get('content', [])

        items = []
        for item in content:
            if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE and content_filter in [None, Movie]:
                items.append(self._parse_movie_teaser(item, cache=cache))

            elif item.get('target', {}).get('type') == CONTENT_TYPE_PROGRAM and content_filter in [None, Program]:
                items.append(self._parse_program_teaser(item, cache=cache))

        return items
Beispiel #2
0
    def get_recommendations(self, storefront):
        """ Returns the config for the dashboard """
        response = util.http_get(API_ENDPOINT + '/%s/storefronts/%s' %
                                 (self._mode(), storefront),
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        recommendations = json.loads(response.text)

        categories = []
        for cat in recommendations.get('rows', []):
            if cat.get('rowType') not in ['SWIMLANE_DEFAULT']:
                _LOGGER.debug('Skipping recommendation %s with type %s',
                              cat.get('title'), cat.get('rowType'))
                continue

            items = []
            for item in cat.get('teasers'):
                if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE:
                    items.append(self._parse_movie_teaser(item))

                elif item.get('target',
                              {}).get('type') == CONTENT_TYPE_PROGRAM:
                    items.append(self._parse_program_teaser(item))

            categories.append(
                Category(
                    category_id=cat.get('id'),
                    title=cat.get('title'),
                    content=items,
                ))

        return categories
    def get_config(self):
        """ Returns the config for the app. """
        response = util.http_get(API_ENDPOINT + '/config', token=self._tokens.jwt_token)
        info = json.loads(response.text)

        # This contains a player.updateIntervalSeconds that could be used to notify Streamz about the playing progress
        return info
Beispiel #4
0
    def get_episode(self, episode_id):
        """ Get some details of the specified episode.
        :type episode_id: str
        :rtype Episode
        """
        response = util.http_get(API_ENDPOINT + '/%s/play/episode/%s' %
                                 (self._mode(), episode_id),
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        episode = json.loads(response.text)

        # Extract next episode info if available
        next_playable = episode.get('nextPlayable')
        if next_playable:
            next_episode = Episode(
                episode_id=next_playable['id'],
                program_name=next_playable['title'],
                name=next_playable['subtitle'],
                description=next_playable['description'],
                cover=next_playable['imageUrl'],
            )
        else:
            next_episode = None

        return Episode(
            episode_id=episode.get('id'),
            name=episode.get('title'),
            cover=episode.get('posterImageUrl'),
            progress=episode.get('playerPositionSeconds'),
            next_episode=next_episode,
        )
Beispiel #5
0
    def _get_video_info(self, strtype, stream_id, player_token):
        """ Get the stream info for the specified stream.
        :param str strtype:
        :param str stream_id:
        :param str player_token:
        :rtype: dict
        """
        url = 'https://videoplayer-service.api.persgroep.cloud/config/%s/%s' % (
            strtype, stream_id)
        _LOGGER.debug('Getting video info from %s', url)
        response = util.http_get(
            url,
            params={
                'startPosition': '0.0',
                'autoPlay': 'true',
            },
            headers={
                'Accept': 'application/json',
                'x-api-key': self._API_KEY,
                # 'x-dpg-correlation-id': '',
                'Popcorn-SDK-Version': '4',
                'User-Agent':
                'Dalvik/2.1.0 (Linux; U; Android 6.0.1; MotoG3 Build/MPIS24.107-55-2-17)',
                'Authorization': 'Bearer ' + player_token,
            })

        info = json.loads(response.text)
        return info
Beispiel #6
0
    def get_swimlane(self, swimlane=None):
        """ Returns the contents of My List """
        response = util.http_get(API_ENDPOINT + '/%s/main/swimlane/%s' %
                                 (self._mode(), swimlane),
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)

        # Result can be empty
        if not response.text:
            return []

        result = json.loads(response.text)

        items = []
        for item in result.get('teasers'):
            if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE:
                items.append(self._parse_movie_teaser(item))

            elif item.get('target', {}).get('type') == CONTENT_TYPE_PROGRAM:
                items.append(self._parse_program_teaser(item))

            elif item.get('target', {}).get('type') == CONTENT_TYPE_EPISODE:
                items.append(self._parse_episode_teaser(item))

        return items
Beispiel #7
0
    def get_storefront_category(self, storefront, category):
        """ Returns a storefront.

         :param str storefront:         The ID of the storefront.
         :param str category:           The ID of the category.
         :rtype: Category
         """
        response = util.http_get(API_ENDPOINT +
                                 '/%s/storefronts/%s/detail/%s' %
                                 (self._mode(), storefront, category),
                                 token=self._tokens.access_token,
                                 profile=self._tokens.profile)
        result = json.loads(response.text)

        items = []
        for item in result.get('row', {}).get('teasers'):
            if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE:
                items.append(self._parse_movie_teaser(item))

            elif item.get('target', {}).get('type') == CONTENT_TYPE_PROGRAM:
                items.append(self._parse_program_teaser(item))

            elif item.get('target', {}).get('type') == CONTENT_TYPE_EPISODE:
                items.append(self._parse_episode_teaser(item))

        return Category(category_id=category,
                        title=result.get('row', {}).get('title'),
                        content=items)
Beispiel #8
0
    def get_items(self, category=None):
        """ Get a list of all the items in a category.
        :type category: str
        :rtype list[Union[Movie, Program]]
        """
        # Fetch from API
        response = util.http_get(API_ENDPOINT + '/%s/catalog' % self._mode(),
                                 params={
                                     'pageSize':
                                     2000,
                                     'filter':
                                     quote(category) if category else None
                                 },
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        info = json.loads(response.text)
        content = info.get('pagedTeasers', {}).get('content', [])

        items = []
        for item in content:
            if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE:
                items.append(self._parse_movie_teaser(item))

            elif item.get('target', {}).get('type') == CONTENT_TYPE_PROGRAM:
                items.append(self._parse_program_teaser(item))

        return items
Beispiel #9
0
    def get_storefront(self, storefront):
        """ Returns a storefront.

         :param str storefront:         The ID of the storefront.
         :rtype: list[Category|Program|Movie]
         """
        response = util.http_get(API_ENDPOINT + '/%s/storefronts/%s' %
                                 (self._mode(), storefront),
                                 token=self._tokens.access_token,
                                 profile=self._tokens.profile)
        result = json.loads(response.text)

        items = []
        for row in result.get('rows', []):
            if row.get('rowType') in [
                    'SWIMLANE_DEFAULT', 'SWIMLANE_PORTRAIT',
                    'SWIMLANE_LANDSCAPE'
            ]:
                items.append(
                    Category(
                        category_id=row.get('id'),
                        title=row.get('title'),
                    ))
                continue

            if row.get('rowType') == 'CAROUSEL':
                for item in row.get('teasers'):
                    if item.get('target',
                                {}).get('type') == CONTENT_TYPE_MOVIE:
                        items.append(self._parse_movie_teaser(item))

                    elif item.get('target',
                                  {}).get('type') == CONTENT_TYPE_PROGRAM:
                        items.append(self._parse_program_teaser(item))
                continue

            if row.get('rowType') in ['TOP_BANNER', 'MARKETING_BLOCK']:
                item = row.get('teaser')
                if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE:
                    items.append(self._parse_movie_teaser(item))

                elif item.get('target',
                              {}).get('type') == CONTENT_TYPE_PROGRAM:
                    items.append(self._parse_program_teaser(item))
                continue

            _LOGGER.debug('Skipping recommendation %s with type %s',
                          row.get('title'), row.get('rowType'))

        return items
    def check_status(self):
        """ Check customer status """
        response = util.http_get(
            'https://customer-api.streamz.be/onboarding/customer-status',
            headers={
                'authorization': 'Bearer ' + self._account.login_token,
            })

        status = json.loads(response.text)

        if status.get('customerStatus') == 'NOT_AUTHORIZED':
            raise NoStreamzSubscriptionException()

        if status.get('customerStatus') == 'NOT_AUTHORIZED_TELENET':
            raise NoTelenetSubscriptionException()
    def get_categories(self):
        """ Get a list of all the categories.

        :rtype list[Category]
        """
        response = util.http_get(API_ENDPOINT + '/%s/catalog/filters' % self._mode(),
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        info = json.loads(response.text)

        categories = []
        for item in info.get('catalogFilters', []):
            categories.append(Category(
                category_id=item.get('id'),
                title=item.get('title'),
            ))

        return categories
    def get_catalog_ids(self):
        """ Returns the IDs of the contents of the Catalog """
        # Try to fetch from cache
        items = kodiutils.get_cache(['catalog_id'], 300)  # 5 minutes ttl
        if items:
            return items

        # Fetch from API
        response = util.http_get(API_ENDPOINT + '/%s/catalog' % self._mode(),
                                 params={'pageSize': 2000, 'filter': None},
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        info = json.loads(response.text)

        items = [item.get('target', {}).get('id') for item in info.get('pagedTeasers', {}).get('content', [])]

        kodiutils.set_cache(['catalog_id'], items)
        return items
Beispiel #13
0
    def _get_video_info(self, strtype, stream_id, player_token):
        """ Get the stream info for the specified stream.
        :type strtype: str
        :type stream_id: str
        :type player_token: str
        :rtype: dict
        """
        url = 'https://videoplayer-service.api.persgroep.cloud/config/%s/%s' % (
            strtype, stream_id)
        _LOGGER.debug('Getting stream info from %s', url)
        response = util.http_get(
            url,
            params={
                'startPosition': '0.0',
                'autoPlay': 'true',
            },
            headers={
                'Accept': 'application/json',
                'x-api-key': self._API_KEY,
                # 'x-dpg-correlation-id': '',
                'Popcorn-SDK-Version': '4',
                'User-Agent':
                'Dalvik/2.1.0 (Linux; U; Android 6.0.1; MotoG3 Build/MPIS24.107-55-2-17)',
                'Authorization': 'Bearer ' + player_token,
            })

        _LOGGER.debug('Got response (status=%s): %s', response.status_code,
                      response.text)

        if response.status_code == 403:
            error = json.loads(response.text)
            if error['type'] == 'videoPlaybackGeoblocked':
                raise StreamGeoblockedException()
            if error['type'] == 'serviceError':
                raise StreamUnavailableException()

        if response.status_code == 404:
            raise StreamUnavailableException()

        if response.status_code != 200:
            raise StreamUnavailableException()

        info = json.loads(response.text)
        return info
    def get_mylist_ids(self):
        """ Returns the IDs of the contents of My List """
        # Try to fetch from cache
        items = kodiutils.get_cache(['mylist_id'], 300)  # 5 minutes ttl
        if items:
            return items

        # Fetch from API
        response = util.http_get(API_ENDPOINT + '/%s/main/swimlane/%s' % (self._mode(), 'my-list'),
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)

        # Result can be empty
        result = json.loads(response.text) if response.text else []

        items = [item.get('target', {}).get('id') for item in result.get('teasers', [])]

        kodiutils.set_cache(['mylist_id'], items)
        return items
    def do_search(self, search):
        """ Do a search in the full catalog.
        :type search: str
        :rtype list[Union[Movie, Program]]
        """
        response = util.http_get(API_ENDPOINT + '/%s/search/?query=%s' % (self._mode(),
                                                                          kodiutils.to_unicode(quote(kodiutils.from_unicode(search)))),
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)
        results = json.loads(response.text)

        items = []
        for category in results.get('results', []):
            for item in category.get('teasers'):
                if item.get('target', {}).get('type') == CONTENT_TYPE_MOVIE:
                    items.append(self._parse_movie_teaser(item))

                elif item.get('target', {}).get('type') == CONTENT_TYPE_PROGRAM:
                    items.append(self._parse_program_teaser(item))
        return items
Beispiel #16
0
    def get_profiles(self, products='STREAMZ,STREAMZ_KIDS'):
        """ Returns the available profiles """
        response = util.http_get(API_ENDPOINT + '/profiles',
                                 {'products': products},
                                 token=self._account.access_token)
        result = json.loads(response.text)

        profiles = [
            Profile(
                key=profile.get('id'),
                product=profile.get('product'),
                name=profile.get('name'),
                gender=profile.get('gender'),
                birthdate=profile.get('birthDate'),
                color=profile.get('color', {}).get('start'),
                color2=profile.get('color', {}).get('end'),
            ) for profile in result
        ]

        return profiles
Beispiel #17
0
    def get_movie(self, movie_id, cache=CACHE_AUTO):
        """ Get the details of the specified movie.

        :type movie_id: str
        :type cache: int
        :rtype Movie
        """
        if cache in [CACHE_AUTO, CACHE_ONLY]:
            # Try to fetch from cache
            movie = kodiutils.get_cache(['movie', movie_id])
            if movie is None and cache == CACHE_ONLY:
                return None
        else:
            movie = None

        if movie is None:
            # Fetch from API
            response = util.http_get(API_ENDPOINT + '/%s/movies/%s' %
                                     (self._mode(), movie_id),
                                     token=self._tokens.access_token,
                                     profile=self._tokens.profile)
            info = json.loads(response.text)
            movie = info.get('movie', {})
            kodiutils.set_cache(['movie', movie_id], movie)

        return Movie(
            movie_id=movie.get('id'),
            name=movie.get('name'),
            description=movie.get('description'),
            duration=movie.get('durationSeconds'),
            thumb=movie.get('teaserImageUrl'),
            fanart=movie.get('bigPhotoUrl'),
            year=movie.get('productionYear'),
            geoblocked=movie.get('geoBlocked'),
            remaining=movie.get('remainingDaysAvailable'),
            legal=movie.get('legalIcons'),
            # aired=movie.get('broadcastTimestamp'),
            channel=self._parse_channel(movie.get('channelLogoUrl')),
            # my_list=program.get('addedToMyList'),  # Don't use addedToMyList, since we might have cached this info
            available=movie.get('blockedFor') != 'SUBSCRIPTION',
        )
Beispiel #18
0
    def _get_stream_tokens(self, strtype, stream_id):
        """ Get the stream info for the specified stream.
        :param str strtype:
        :param str stream_id:
        :rtype: dict
        """
        if strtype == 'movies':
            url = API_ENDPOINT + '/%s/play/movie/%s' % (self._mode(),
                                                        stream_id)
        elif strtype == 'episodes':
            url = API_ENDPOINT + '/%s/play/episode/%s' % (self._mode(),
                                                          stream_id)
        else:
            raise Exception('Unknown stream type: %s' % strtype)

        _LOGGER.debug('Getting stream tokens from %s', url)
        response = util.http_get(url,
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)

        return json.loads(response.text)
Beispiel #19
0
    def _get_stream_tokens(self, strtype, stream_id):
        """ Get the stream info for the specified stream.
        :type strtype: str
        :type stream_id: str
        :rtype: dict
        """

        if strtype == 'movies':
            url = API_ENDPOINT + '/%s/play/movie/%s' % (self._mode(),
                                                        stream_id)
        elif strtype == 'episodes':
            url = API_ENDPOINT + '/%s/play/episode/%s' % (self._mode(),
                                                          stream_id)
        else:
            raise Exception('Unknown stream type: %s' % strtype)

        _LOGGER.debug('Getting stream info from %s', url)
        response = util.http_get(url,
                                 token=self._tokens.jwt_token,
                                 profile=self._tokens.profile)

        _LOGGER.debug('Got response (status=%s): %s', response.status_code,
                      response.text)

        # TODO: handle errors
        # if response.status_code == 403:
        #     error = json.loads(response.text)
        #     if error['type'] == 'videoPlaybackGeoblocked':
        #         raise StreamGeoblockedException()
        #     if error['type'] == 'serviceError':
        #         raise StreamUnavailableException()

        if response.status_code == 404:
            raise StreamUnavailableException()

        if response.status_code != 200:
            raise StreamUnavailableException()

        return json.loads(response.text)
Beispiel #20
0
    def get_movie(self, movie_id, cache=CACHE_AUTO):
        """ Get the details of the specified movie.
        :type movie_id: str
        :type cache: int
        :rtype Movie
        """
        if cache in [CACHE_AUTO, CACHE_ONLY]:
            # Try to fetch from cache
            movie = kodiutils.get_cache(['movie', movie_id])
            if movie is None and cache == CACHE_ONLY:
                return None
        else:
            movie = None

        if movie is None:
            # Fetch from API
            response = util.http_get(API_ENDPOINT + '/%s/movies/%s' %
                                     (self._mode(), movie_id),
                                     token=self._tokens.jwt_token,
                                     profile=self._tokens.profile)
            info = json.loads(response.text)
            movie = info.get('movie', {})
            kodiutils.set_cache(['movie', movie_id], movie)

        return Movie(
            movie_id=movie.get('id'),
            name=movie.get('name'),
            description=movie.get('description'),
            duration=movie.get('durationSeconds'),
            cover=movie.get('bigPhotoUrl'),
            image=movie.get('bigPhotoUrl'),
            year=movie.get('productionYear'),
            geoblocked=movie.get('geoBlocked'),
            remaining=movie.get('remainingDaysAvailable'),
            legal=movie.get('legalIcons'),
            # aired=movie.get('broadcastTimestamp'),
            channel=self._parse_channel(movie.get('channelLogoUrl')),
        )
Beispiel #21
0
    def _download_subtitles(subtitles):
        # Clean up old subtitles
        temp_dir = os.path.join(kodiutils.addon_profile(), 'temp', '')
        _, files = kodiutils.listdir(temp_dir)
        if files:
            for item in files:
                kodiutils.delete(temp_dir + kodiutils.to_unicode(item))

        # Return if there are no subtitles available
        if not subtitles:
            return None

        if not kodiutils.exists(temp_dir):
            kodiutils.mkdirs(temp_dir)

        downloaded_subtitles = []
        for subtitle in subtitles:
            output_file = temp_dir + subtitle.get('name')
            webvtt_content = util.http_get(subtitle.get('url')).text
            with kodiutils.open_file(output_file, 'w') as webvtt_output:
                webvtt_output.write(kodiutils.from_unicode(webvtt_content))
            downloaded_subtitles.append(output_file)
        return downloaded_subtitles
Beispiel #22
0
    def get_mylist(self, content_filter=None, cache=CACHE_ONLY):
        """ Returns the contents of My List """
        response = util.http_get(API_ENDPOINT + '/%s/my-list' % (self._mode()),
                                 token=self._tokens.access_token,
                                 profile=self._tokens.profile)

        # Result can be empty
        if not response.text:
            return []

        result = json.loads(response.text)

        items = []
        for item in result.get('teasers'):
            if item.get(
                    'target',
                {}).get('type') == CONTENT_TYPE_MOVIE and content_filter in [
                    None, Movie
                ]:
                items.append(self._parse_movie_teaser(item, cache=cache))

            elif item.get(
                    'target',
                {}).get('type') == CONTENT_TYPE_PROGRAM and content_filter in [
                    None, Program
                ]:
                items.append(self._parse_program_teaser(item, cache=cache))

            elif item.get(
                    'target',
                {}).get('type') == CONTENT_TYPE_EPISODE and content_filter in [
                    None, Episode
                ]:
                items.append(self._parse_episode_teaser(item, cache=cache))

        return items
    def _web_login(self):
        """ Executes a login and returns the JSON Web Token.
        :rtype str
        """
        # Start login flow
        util.http_get('https://account.streamz.be/login')

        # Generate random state and nonce parameters
        import random
        import string
        state = ''.join(
            random.choice(string.ascii_uppercase + string.ascii_lowercase +
                          string.digits) for _ in range(32))
        nonce = ''.join(
            random.choice(string.ascii_uppercase + string.ascii_lowercase +
                          string.digits) for _ in range(32))

        if self._loginprovider == LOGIN_STREAMZ:

            # Send login credentials
            response = util.http_post(
                'https://login.streamz.be/co/authenticate',
                data={
                    "client_id":
                    self.CLIENT_ID,
                    "username":
                    self._username,
                    "password":
                    self._password,
                    "realm":
                    "Username-Password-Authentication",
                    "credential_type":
                    "http://auth0.com/oauth/grant-type/password-realm"
                },
                headers={
                    'Origin': 'https://account.streamz.be',
                    'Referer': 'https://account.streamz.be',
                })
            login_data = json.loads(response.text)

            # Obtain authorization
            response = util.http_get(
                'https://login.streamz.be/authorize',
                params={
                    'audience': 'https://streamz.eu.auth0.com/api/v2/',
                    'domain': 'login.streamz.be',
                    'client_id': self.CLIENT_ID,
                    'response_type': 'id_token token',
                    'redirect_uri': 'https://account.streamz.be/callback',
                    'scope': 'read:current_user profile email openid',
                    'state': state,
                    'nonce': nonce,
                    'auth0Client':
                    'eyJuYW1lIjoiYXV0aDAuanMiLCJ2ZXJzaW9uIjoiOS4xMy4yIn0=',
                    # base64 encoded {"name":"auth0.js","version":"9.13.2"}
                    'realm': 'Username-Password-Authentication',
                    'login_ticket': login_data.get('login_ticket'),
                })

        elif self._loginprovider == LOGIN_TELENET:

            # Obtain authorization
            util.http_get(
                'https://login.streamz.be/authorize',
                params={
                    'audience':
                    'https://streamz.eu.auth0.com/api/v2/',
                    'domain':
                    'login.streamz.be',
                    'client_id':
                    self.CLIENT_ID,
                    'response_type':
                    'id_token token',
                    'redirect_uri':
                    'https://account.streamz.be/callback',
                    'scope':
                    'read:current_user profile email openid',
                    'connection':
                    'TN',
                    'state':
                    state,
                    'nonce':
                    nonce,
                    'auth0Client':
                    'eyJuYW1lIjoiYXV0aDAuanMiLCJ2ZXJzaW9uIjoiOS4xMy4yIn0=',  # base64 encoded {"name":"auth0.js","version":"9.13.2"}
                })

            # Send login credentials
            response = util.http_post(
                'https://login.prd.telenet.be/openid/login.do',
                form={
                    'j_username': self._username,
                    'j_password': self._password,
                    'rememberme': 'true',
                })

            if 'Je gebruikersnaam en/of wachtwoord zijn verkeerd' in response.text:
                raise InvalidLoginException

        else:
            raise Exception('Unsupported login method: %s' %
                            self._loginprovider)

        # Extract login_token
        params = parse_qs(urlsplit(response.url).fragment)
        if params:
            self._account.login_token = params.get('access_token')[0]
        else:
            raise LoginErrorException(code=103)  # Could not extract parameter

        # Check login token
        self.check_status()

        # Login to the actual app
        response = util.http_get('https://www.streamz.be/streamz/aanmelden')

        # Extract state and code
        matches_state = re.search(r'name="state" value="([^"]+)',
                                  response.text)
        if matches_state:
            state = matches_state.group(1)
        else:
            raise LoginErrorException(
                code=101)  # Could not extract authentication state

        matches_code = re.search(r'name="code" value="([^"]+)', response.text)
        if matches_code:
            code = matches_code.group(1)
        else:
            raise LoginErrorException(
                code=102)  # Could not extract authentication code

        # Okay, final stage. We now need to POST our state and code to get a valid JWT.
        util.http_post('https://www.streamz.be/streamz/login-callback',
                       form={
                           'state': state,
                           'code': code,
                       })

        # Get JWT from cookies
        self._account.jwt_token = util.SESSION.cookies.get('lfvp_auth')

        self._save_cache()

        return self._account
Beispiel #24
0
    def get_program(self, program_id, cache=CACHE_AUTO):
        """ Get the details of the specified program.
        :type program_id: str
        :type cache: int
        :rtype Program
        """
        if cache in [CACHE_AUTO, CACHE_ONLY]:
            # Try to fetch from cache
            program = kodiutils.get_cache(['program', program_id])
            if program is None and cache == CACHE_ONLY:
                return None
        else:
            program = None

        if program is None:
            # Fetch from API
            response = util.http_get(API_ENDPOINT + '/%s/programs/%s' %
                                     (self._mode(), program_id),
                                     token=self._tokens.jwt_token,
                                     profile=self._tokens.profile)
            info = json.loads(response.text)
            program = info.get('program', {})
            kodiutils.set_cache(['program', program_id], program)

        channel = self._parse_channel(program.get('channelLogoUrl'))

        seasons = {}
        for item_season in program.get('seasons', []):
            episodes = {}

            for item_episode in item_season.get('episodes', []):
                episodes[item_episode.get('index')] = Episode(
                    episode_id=item_episode.get('id'),
                    program_id=program_id,
                    program_name=program.get('name'),
                    number=item_episode.get('index'),
                    season=item_season.get('index'),
                    name=item_episode.get('name'),
                    description=item_episode.get('description'),
                    duration=item_episode.get('durationSeconds'),
                    cover=item_episode.get('bigPhotoUrl'),
                    geoblocked=program.get('geoBlocked'),
                    remaining=item_episode.get('remainingDaysAvailable'),
                    channel=channel,
                    legal=program.get('legalIcons'),
                    aired=item_episode.get('broadcastTimestamp'),
                    progress=item_episode.get('playerPositionSeconds', 0),
                    watched=item_episode.get('doneWatching', False),
                )

            seasons[item_season.get('index')] = Season(
                number=item_season.get('index'),
                episodes=episodes,
                cover=item_season.get('episodes', [{}])[0].get('bigPhotoUrl')
                if episodes else program.get('bigPhotoUrl'),
                geoblocked=program.get('geoBlocked'),
                channel=channel,
                legal=program.get('legalIcons'),
            )

        return Program(
            program_id=program.get('id'),
            name=program.get('name'),
            description=program.get('description'),
            cover=program.get('bigPhotoUrl'),
            image=program.get('bigPhotoUrl'),
            geoblocked=program.get('geoBlocked'),
            seasons=seasons,
            channel=channel,
            legal=program.get('legalIcons'),
        )