Esempio n. 1
0
    def search(self, series):
        """Search tvmaze.com for the series name.

        :param series: the query for the series name
        :return: An ordered dict with the show searched for. In the format of OrderedDict{"series": [list of shows]}
        """
        log.debug('Searching for show {0}', series)

        results = None
        # If search term is digit's only, store it and attempt to search by id.
        show_by_id = None

        try:
            if series.isdigit():
                show_by_id = self._get_show_by_id(series, request_language=self.config['language'])
            results = self._show_search(series, request_language=self.config['language'])
        except IndexerShowNotFound:
            pass

        if not results and not show_by_id:
            raise IndexerShowNotFound(
                'Tvmaze show search failed in getting a result for search term {search}'.format(search=series)
            )

        mapped_results = []
        if results:
            mapped_results = self._map_results(results, self.series_map, '|')

        # The search by id result, is already mapped. We can just add it to the array with results.
        if show_by_id:
            mapped_results.append(show_by_id['series'])

        return OrderedDict({'series': mapped_results})['series']
Esempio n. 2
0
    def _get_show_by_id(self, tvmaze_id, request_language='en'):  # pylint: disable=unused-argument
        """
        Retrieve tvmaze show information by tvmaze id, or if no tvmaze id provided by passed external id.

        :param tvmaze_id: The shows tvmaze id
        :return: An ordered dict with the show searched for.
        """
        results = None
        if tvmaze_id:
            log.debug('Getting all show data for {0}', tvmaze_id)

            try:
                results = self.tvmaze_api.get_show(maze_id=tvmaze_id)
            except ShowNotFound as error:
                # Use error.value because TVMaze API exceptions may be utf-8 encoded when using __str__
                raise IndexerShowNotFound(
                    'Show search failed in getting a result with reason: {0}'.format(error.value)
                )
            except BaseError as error:
                raise IndexerUnavailable('Show search failed in getting a result with error: {0!r}'.format(error))

        if not results:
            return

        mapped_results = self._map_results(results, self.series_map)
        return OrderedDict({'series': mapped_results})
Esempio n. 3
0
    def _show_search(self, show, request_language='en'):
        """Use TMDB API to search for a show.

        :param show: The show name that's searched for as a string
        :param request_language: Language in two letter code. TMDB fallsback to en itself.
        :return: A list of Show objects.
        """
        try:
            # get paginated pages
            page = 1
            last = 1
            results = []
            while page <= last:
                search_result = self.tmdb.Search().tv(
                    query=show, language=request_language, page=page)
                last = search_result.get('total_pages', 0)
                results += search_result.get('results')
                page += 1
        except RequestException as error:
            raise IndexerUnavailable(
                'Show search failed using indexer TMDB. Cause: {cause}'.format(
                    cause=error))

        if not results:
            raise IndexerShowNotFound(
                'Show search failed in getting a result with reason: Not found'
            )

        return results
Esempio n. 4
0
    def _get_show_by_id(self, tvdb_id, request_language='de'):  # pylint: disable=unused-argument
        """Retrieve Glotz show information by tvdb id.

        :param tvdb_id: The shows tvdb id
        :return: An ordered dict with the show searched for.
        """
        results = None
        if tvdb_id:
            log.debug('Getting all show data for {0}', tvdb_id)

            try:
                results = self.glotz_api.get_show(tvdb_id=tvdb_id, language=request_language)
            except IDNotFound as error:
                raise IndexerShowNotFound(
                    'Show search failed in getting a result with reason: {0}'.format(error.value)
                )

            except BaseError as error:
                raise IndexerUnavailable('Show search failed in getting a result with error: {0!r}'.format(error))

        if results:
            log.debug('Getting aliases for show {0}', tvdb_id)
            results.aliases = self.glotz_api.get_show_aliases(tvdb_id)

        if not results:
            log.debug('Getting show data for {0} on Glotz failed', tvdb_id)
            return

        mapped_results = self._map_results(results, self.series_map)

        return OrderedDict({'series': mapped_results})
Esempio n. 5
0
    def _get_series(self, series):
        """Search for the series name.

        If a custom_ui UI is configured, it uses this to select the correct
        series. If not, and interactive == True, ConsoleUI is used, if not
        BaseUI is used to select the first result.

        :param series: the query for the series name
        :return: A list of series mapped to a UI (for example: a BaseUI or custom_ui).
        """
        all_series = self.search(series)
        if not all_series:
            log.debug('Series result returned zero')
            raise IndexerShowNotFound(
                'Show search returned zero results (cannot find show on Indexer)'
            )

        if not isinstance(all_series, list):
            all_series = [all_series]

        if self.config['custom_ui'] is not None:
            log.debug('Using custom UI: {0!r}', self.config['custom_ui'])
            custom_ui = self.config['custom_ui']
            ui = custom_ui(config=self.config)
        else:
            if not self.config['interactive']:
                log.debug('Auto-selecting first search result using BaseUI')
                ui = BaseUI(config=self.config)
            else:
                log.debug('Interactively selecting show using ConsoleUI')
                ui = ConsoleUI(config=self.config)  # pylint: disable=redefined-variable-type

        return ui.select_series(all_series)
Esempio n. 6
0
    def _get_show_by_id(self, tvdbv2_id, request_language='en'):  # pylint: disable=unused-argument
        """Retrieve tvdbv2 show information by tvdbv2 id, or if no tvdbv2 id provided by passed external id.

        :param tvdbv2_id: The shows tvdbv2 id
        :return: An ordered dict with the show searched for.
        """
        results = None
        if tvdbv2_id:
            log.debug('Getting all show data for {0}', tvdbv2_id)
            try:
                results = self.config['session'].series_api.series_id_get(
                    tvdbv2_id, accept_language=request_language)
            except ApiException as error:
                if error.status == 401:
                    raise IndexerAuthFailed(
                        'Authentication failed, possible bad API key. Reason: {reason} ({status})'
                        .format(reason=error.reason, status=error.status))
                if error.status == 404:
                    raise IndexerShowNotFound(
                        'Show search failed in getting a result with reason: {reason} ({status})'
                        .format(reason=error.reason, status=error.status))
                raise IndexerUnavailable(error.reason)

        if not results:
            return

        if not getattr(results.data, 'series_name', None):
            raise IndexerShowNotFoundInLanguage(
                'Missing attribute series_name, cant index in language: {0}'.
                format(request_language), request_language)

        mapped_results = self._map_results(results, self.series_map, '|')
        return OrderedDict({'series': mapped_results})
Esempio n. 7
0
    def _show_search(self, show, request_language='en'):
        """
        Use the TVMaze API to search for a show.

        :param show: The show name that's searched for as a string
        :param request_language: Language in two letter code. TVMaze fallsback to en itself.
        :return: A list of Show objects.
        """
        try:
            results = self.tvmaze_api.get_show_list(show)
        except ShowNotFound as error:
            # Use error.value because TVMaze API exceptions may be utf-8 encoded when using __str__
            raise IndexerShowNotFound(
                'Show search failed in getting a result with reason: {0}'.format(error.value)
            )
        except BaseError as error:
            raise IndexerUnavailable('Show search failed in getting a result with error: {0!r}'.format(error))

        return results
Esempio n. 8
0
    def _show_search(self, show, request_language='de'):
        """
        Use the Glotz API to search for a show.

        :param show: The show name that's searched for as a string.
        :param request_language: Language in two letter code. As Glotz is primarily a German indexer, default is German
        :return: A list of Show objects.
        """
        try:
            results = self.glotz_api.get_show_list(show, request_language)
        except ShowNotFound as error:
            # Use error.value because Glotz API exceptions may be utf-8 encoded when using __str__
            raise IndexerShowNotFound(
                'Show search failed in getting a result with reason: {0}'.format(error.value)
            )
        except BaseError as error:
            raise IndexerUnavailable('Show search failed in getting a result with error: {0!r}'.format(error))

        return results
Esempio n. 9
0
    def _show_search(self, show, request_language='en'):
        """Use the pytvdbv2 API to search for a show.

        @param show: The show name that's searched for as a string
        @return: A list of Show objects.
        """
        try:
            results = self.config['session'].search_api.search_series_get(
                name=show, accept_language=request_language)
        except ApiException as error:
            if error.status == 401:
                raise IndexerAuthFailed(
                    'Authentication failed, possible bad API key. Reason: {reason} ({status})'
                    .format(reason=error.reason, status=error.status))
            if error.status == 404:
                raise IndexerShowNotFound(
                    'Show search failed in getting a result with reason: {reason} ({status})'
                    .format(reason=error.reason, status=error.status))
            raise IndexerUnavailable(error.reason)

        return results
Esempio n. 10
0
    def _show_search(self, series):
        """
        Use the Imdb API to search for a show.

        :param series: The series name that's searched for as a string
        :return: A list of Show objects.series_map
        """
        try:
            results = self.imdb_api.search_for_title(series)
        except LookupError as error:
            raise IndexerShowNotFound(
                'Could not get any results searching for {series} using indexer Imdb. Cause: {cause!r}'
                .format(series=series, cause=error))
        except (AttributeError, RequestException) as error:
            raise IndexerUnavailable(
                'Could not get any results searching for {series} using indexer Imdb. Cause: {cause!r}'
                .format(series=series, cause=error))

        if results:
            return results
        else:
            return None
Esempio n. 11
0
    def _parse_actors(self, imdb_id):
        """Get and parse actors using the get_title_credits route.

        Actors are retrieved using t['show name]['_actors'].

        Any key starting with an underscore has been processed (not the raw
        data from the indexer)
        """
        log.debug('Getting actors for {0}', imdb_id)

        try:
            actors = self.imdb_api.get_title_credits(
                ImdbIdentifier(imdb_id).imdb_id)
        except LookupError as error:
            raise IndexerShowNotFound(
                'Could not find show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))
        except (AttributeError, RequestException) as error:
            raise IndexerUnavailable(
                'Could not get actors for show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))

        if not actors.get('credits') or not actors['credits'].get('cast'):
            return

        cur_actors = Actors()
        for order, cur_actor in enumerate(actors['credits']['cast'][:25]):
            save_actor = Actor()
            save_actor['id'] = cur_actor['id'].split('/')[-2]
            save_actor['image'] = cur_actor.get('image', {}).get('url', None)
            save_actor['name'] = cur_actor['name']
            save_actor['role'] = cur_actor['characters'][0] if cur_actor.get(
                'characters') else ''
            save_actor['sortorder'] = order
            cur_actors.append(save_actor)
        self._set_show_data(imdb_id, '_actors', cur_actors)
Esempio n. 12
0
    def _parse_images(self, imdb_id, language='en'):
        """Parse Show and Season posters.

        Any key starting with an underscore has been processed (not the raw
        data from the XML)

        This interface will be improved in future versions.
        Available sources: amazon, custom, getty, paidcustomer, presskit, userupload.
        Available types: behind_the_scenes, event, poster, product, production_art, publicity, still_frame
        """
        log.debug('Getting show banners for {0}', imdb_id)

        try:
            images = self.imdb_api.get_title_images(
                ImdbIdentifier(imdb_id).imdb_id)
        except LookupError as error:
            raise IndexerShowNotFound(
                'Could not find show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))
        except (AttributeError, RequestException) as error:
            raise IndexerUnavailable(
                'Could not get images for show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))

        image_mapping = {
            'poster': 'poster',
            'production_art': 'fanart'
        }  # Removed 'still_frame': 'fanart',
        thumb_height = 640

        _images = {}
        try:
            for image in images.get('images', []):
                image_type = image_mapping.get(image.get('type'))
                if image_type not in ('poster', 'fanart'):
                    continue
                image_type_thumb = image_type + '_thumb'
                if image_type not in _images:
                    _images[image_type] = {}
                    _images[image_type + '_thumb'] = {}

                # Store the images for each resolution available
                # Always provide a resolution or 'original'.
                resolution = '{0}x{1}'.format(image['width'], image['height'])
                thumb_width = int(
                    (float(image['width']) / image['height']) * thumb_height)
                resolution_thumb = '{0}x{1}'.format(thumb_width, thumb_height)

                if resolution not in _images[image_type]:
                    _images[image_type][resolution] = {}
                    _images[image_type_thumb][resolution_thumb] = {}

                bid = image['id'].split('/')[-1]

                if image_type in ['season', 'seasonwide']:
                    if int(image.sub_key
                           ) not in _images[image_type][resolution]:
                        _images[image_type][resolution][int(
                            image.sub_key)] = {}
                    if bid not in _images[image_type][resolution][int(
                            image.sub_key)]:
                        _images[image_type][resolution][int(
                            image.sub_key)][bid] = {}
                    base_path = _images[image_type_thumb][resolution][int(
                        image.sub_key)][bid]
                else:
                    if bid not in _images[image_type][resolution]:
                        _images[image_type][resolution][bid] = {}
                        _images[image_type_thumb][resolution_thumb][bid] = {}
                    base_path = _images[image_type][resolution][bid]
                    base_path_thumb = _images[image_type_thumb][
                        resolution_thumb][bid]

                base_path['bannertype'] = image_type
                base_path['bannertype2'] = resolution
                base_path['_bannerpath'] = image.get('url')
                base_path['bannerpath'] = image.get('url').split('/')[-1]
                base_path['languages'] = image.get('languages')
                base_path['source'] = image.get('source')
                base_path['id'] = bid

                base_path_thumb['bannertype'] = image_type_thumb
                base_path_thumb['bannertype2'] = resolution_thumb
                base_path_thumb['_bannerpath'] = image['url'].split(
                    'V1')[0] + 'V1_SY{0}_AL_.jpg'.format(thumb_height)
                base_path_thumb['bannerpath'] = image['url'].split('V1')[
                    0] + 'V1_SY{0}_AL_.jpg'.format(thumb_height).split('/')[-1]
                base_path_thumb['id'] = bid

        except Exception as error:
            log.warning(
                'Could not parse Poster for show id: {0}, with exception: {1!r}',
                imdb_id, error)
            return

        def _get_poster_thumb(thumbs):
            for bid in thumbs.values():
                for image in bid.values():
                    return image.get('bannerpath')

        if _images.get('poster_thumb'):
            self._set_show_data(imdb_id, 'poster_thumb',
                                _get_poster_thumb(_images.get('poster_thumb')))

        self._save_images(imdb_id, _images, language=language)
        self._set_show_data(imdb_id, '_banners', _images)
Esempio n. 13
0
    def _get_show_by_id(self, imdb_id):  # pylint: disable=unused-argument
        """Retrieve imdb show information by imdb id, or if no imdb id provided by passed external id.

        :param imdb_id: The shows imdb id
        :return: An ordered dict with the show searched for.
        """
        results = None
        log.debug('Getting all show data for {0}', imdb_id)
        try:
            results = self.imdb_api.get_title(ImdbIdentifier(imdb_id).imdb_id)
        except LookupError as error:
            raise IndexerShowNotFound(
                'Could not find show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))
        except (AttributeError, RequestException) as error:
            raise IndexerUnavailable(
                'Could not find show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))

        if not results:
            return

        mapped_results = self._map_results(results, self.series_map)

        if not mapped_results:
            return

        try:
            # Get firstaired
            releases = self.imdb_api.get_title_releases(
                ImdbIdentifier(imdb_id).imdb_id)
        except LookupError as error:
            raise IndexerShowNotFound(
                'Could not find show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))
        except (AttributeError, RequestException) as error:
            raise IndexerUnavailable(
                'Could not get title releases for show {imdb_id} using indexer Imdb. Cause: {cause!r}'
                .format(imdb_id=imdb_id, cause=error))

        if releases.get('releases'):
            first_released = sorted([r['date']
                                     for r in releases['releases']])[0]
            mapped_results['firstaired'] = first_released

        try:
            companies = self.imdb_api.get_title_companies(
                ImdbIdentifier(imdb_id).imdb_id)
            # If there was a release check if it was distributed.
            if companies.get('distribution'):
                origins = self.imdb_api.get_title_versions(
                    ImdbIdentifier(imdb_id).imdb_id)['origins'][0]
                released_in_regions = [
                    dist for dist in companies['distribution']
                    if dist.get('regions') and origins in dist['regions']
                ]
                # Used item.get('startYear') because a startYear is not always available.
                first_release = sorted(released_in_regions,
                                       key=lambda x: x.get('startYear'))

                if first_release:
                    mapped_results['network'] = first_release[0]['company'][
                        'name']
        except (AttributeError, LookupError, RequestException):
            log.info('No company data available for {0}, cant get a network',
                     imdb_id)

        return OrderedDict({'series': mapped_results})