示例#1
0
 def __init__(self):
     self._priority = 90
     self._common = OFDBCommon()
     self._genrenorm = GenreNormalize('ofdb.genre')
     self._attrs = {
         'title', 'original_title', 'plot', 'imdbid', 'vote_count',
         'rating', 'directors', 'writers', 'outline', 'year', 'poster',
         'countries', 'genre', 'genre_norm', 'actors'
     }
示例#2
0
 def __init__(self):
     self._base_url = 'http://www.omdbapi.com/?{query}&plot=full'
     self._genrenorm = GenreNormalize('omdb.genre')
     self._priority = 80
     self._attrs = {
         'title', 'plot', 'runtime', 'imdbid', 'vote_count', 'rating',
         'directors', 'writers', 'year', 'poster', 'genre', 'genre_norm',
         'actors', 'original_title'
     }
示例#3
0
 def __init__(self):
     self._config = TMDBConfig.get_instance()
     self._priority = 100
     self._genrenorm = GenreNormalize('tmdb.genre')
     self._attrs = {
         'title', 'original_title', 'plot', 'runtime', 'imdbid',
         'vote_count', 'rating', 'providerid', 'alternative_titles',
         'directors', 'writers', 'crew', 'year', 'poster', 'fanart',
         'countries', 'genre', 'genre_norm', 'collection', 'studios',
         'trailers', 'actors', 'keywords', 'tagline'
     }
示例#4
0
class OFDBMovie(provider.IMovieProvider):
    """ OFDB Movie text metadata provider.

    Interfaces implemented according to hugin.provider.interfaces.

    """
    def __init__(self):
        self._priority = 90
        self._common = OFDBCommon()
        self._genrenorm = GenreNormalize('ofdb.genre')
        self._attrs = {
            'title', 'original_title', 'plot', 'imdbid', 'vote_count',
            'rating', 'directors', 'writers', 'outline', 'year', 'poster',
            'countries', 'genre', 'genre_norm', 'actors'
        }

    def build_url(self, search_params):
        # not enough search params
        if search_params.title is None and search_params.imdbid is None:
            return None

        # try to search by imdbid if available, else use title
        if search_params.imdbid:
            path, query = 'imdb2ofdb_json', search_params.imdbid
        else:
            path, query = 'search_json', quote_plus(search_params.title)
        return [self._common.get_base_url().format(path=path, query=query)]

    def parse_response(self, url_response, search_params):
        # validate the response data
        status, retvalue, url, response = self._common.validate_url_response(
            url_response
        )
        # CHECK IF CRITICAL MATCHES
        if status in ['retry', 'critical']:
            return retvalue

        # validate the response status of the provider
        status, retv = self._common.check_response_status(response)

        if status in ['critical', 'unknown', 'no_data']:
            return retv

        response_type = response['status']['modul']
        response = response['resultat']

        if 'search' in response_type:
            return self._parse_search_module(response, search_params), False

        if 'imdb2ofdb' in response_type:
            return self._parse_imdb2ofdb_module(response), False

        if 'movie' in response_type:
            return self._parse_movie_module(response), True

        return None, True

    def _parse_imdb2ofdb_module(self, response):
        """ Invoke url build method for movie id found in response. """
        return self._common.movieids_to_urllist([response['ofdbid']])

    def _parse_search_module(self, response, search_params):
        """ Parse a search response. Find high prio result. Build urllist."""
        # create similarity matrix for title, check agains german and original
        # title, higher ratio wins
        similarity_map = []
        for response in response['eintrag']:
            # Get the title with the highest similarity ratio:
            ratio = 0.0
            if '-Serie' not in response['titel_de']:
                for title_key in ['titel_de', 'titel_orig']:
                    ratio = max(
                        ratio,
                        string_similarity_ratio(
                            response[title_key],
                            search_params.title
                        )
                    )
                similarity_map.append(
                    {'ofdbid': response['id'], 'ratio': ratio}
                )

        # sort by ratio, generate ofdbid list with requestet item count
        similarity_map.sort(
            key=lambda value: value['ratio'],
            reverse=True
        )
        item_count = min(len(similarity_map), search_params.amount)
        matches = [item['ofdbid'] for item in similarity_map[:item_count]]
        return self._common.movieids_to_urllist(matches)

    def _parse_movie_module(self, response):
        """ Fill in result_dict. """
        result_dict = {k: None for k in self._attrs}

        #str attrs
        result_dict['title'] = response['titel']
        result_dict['original_title'] = response['alternativ']
        result_dict['plot'] = response['beschreibung']
        result_dict['outline'] = response['kurzbeschreibung']
        result_dict['imdbid'] = 'tt{0}'.format(response['imdbid'])
        result_dict['rating'] = response['bewertung']['note']

        # number attrs
        result_dict['vote_count'] = int(response['bewertung'].get('stimmen') or 0)
        result_dict['year'] = int(response['jahr'] or 0)

        # list attrs
        result_dict['poster'] = [(None, response['bild'])]
        result_dict['countries'] = response['produktionsland']
        result_dict['actors'] = self._extract_person(
            response['besetzung'], 'actors'
        )
        try:
            result_dict['directors'] = [r['name'] for r in response['regie']]
        except:
            print('invalid value')
        result_dict['writers'] = self._extract_person(
            response['drehbuch'], 'directors'
        )
        result_dict['genre'] = response['genre']
        result_dict['genre_norm'] = self._genrenorm.normalize_genre_list(
            result_dict['genre']
        )
        return result_dict

    def _extract_person(self, persons, person_type):
        """ Extract person information from person response part. """
        person_list = []
        try:
            for person in persons:
                role, name = person.get('rolle'), person.get('name')
                if person_type == 'actors':
                    person_list.append((role, name))
                elif person_type == 'directors':
                    person_list.append(name)
        except (AttributeError, TypeError):
            return []
        return person_list

    @property
    def supported_attrs(self):
        return self._attrs
示例#5
0
class TMDBMovie(provider.IMovieProvider, provider.IMoviePictureProvider):
    def __init__(self):
        self._config = TMDBConfig.get_instance()
        self._priority = 100
        self._genrenorm = GenreNormalize('tmdb.genre')
        self._attrs = {
            'title', 'original_title', 'plot', 'runtime', 'imdbid',
            'vote_count', 'rating', 'providerid', 'alternative_titles',
            'directors', 'writers', 'crew', 'year', 'poster', 'fanart',
            'countries', 'genre', 'genre_norm', 'collection', 'studios',
            'trailers', 'actors', 'keywords', 'tagline'
        }

    def build_url(self, search_params):
        if search_params.imdbid:
            return self._config.build_movie_urllist(
                [search_params.imdbid],
                search_params
            ).pop()

        if search_params.title:
            title = quote_plus(search_params.title)
            query = '{title}&year={year}&language={language}'.format(
                title=title,
                year=search_params.year or '',
                language=search_params.language or ''
            )
            return [self._config.baseurl.format(
                path='search/movie',
                apikey=self._config.apikey,
                query=query
            )]

    def parse_response(self, url_response, search_params):
        url, response = self._config.validate_url_response(url_response)

        if response is None or response and 'status_code' in response:
            return None, True

        if 'search/movie?' in url and response['total_results'] == 0:
            return [], True

        if 'search/movie?' in url:
            return self._parse_search_module(response, search_params), False

        if '/movie/' in url:
            return self._parse_movie_module(response), True

        return None, True

    def _parse_search_module(self, result, search_params):
        similarity_map = []
        for result in result['results']:
            if result is not None:
                ratio = 0.0
                for title_key in ['original_title', 'title']:
                    ratio = max(
                        ratio,
                        string_similarity_ratio(
                            result[title_key],
                            search_params.title
                        )
                    )
                similarity_map.append({'tmdbid': result['id'], 'ratio': ratio})

        similarity_map.sort(key=lambda value: value['ratio'], reverse=True)
        item_count = min(len(similarity_map), search_params.amount)
        movieids = [item['tmdbid'] for item in similarity_map[:item_count]]
        return self._config.build_movie_urllist(movieids, search_params)

    def _parse_movie_module(self, result):
        result_dict = {key: None for key in self._attrs}

        # str attrs
        strattr_keymap = [
            'imdbid:imdb_id', 'plot:overview', 'rating:vote_average',
            'title:title', 'original_title:original_title', 'providerid:id',
            'tagline:tagline'
        ]
        for keymap in strattr_keymap:
            key_result, key_response = keymap.split(':', maxsplit=1)
            if result[key_response]:
                result_dict[key_result] = str(result[key_response])

        # list attrs
        crew = self._config.extract_keyvalue_attrs(
            result['credits']['crew'], key_a='job', key_b='name'
        )
        result_dict['directors'] = [n for j, n in crew if j == 'Director']
        result_dict['writers'] = [n for j, n in crew if j == 'Writer']
        result_dict['crew'] = [(j, n) for j, n in crew if j not in ['Director', 'Writer']]
        result_dict['actors'] = self._config.extract_keyvalue_attrs(
            result['credits']['cast'], key_a='character', key_b='name'
        )
        result_dict['poster'] = self._config.extract_image_by_type(
            result, 'posters'
        )
        result_dict['fanart'] = self._config.extract_image_by_type(
            result, 'backdrops'
        )
        result_dict['trailers'] = self._extract_trailers(result['trailers'])
        if result['belongs_to_collection']:
            result_dict['collection'] = [result['belongs_to_collection']['name']]
        else:
            result_dict['collection'] = []

        result_dict['alternative_titles'] = self._config.extract_keyvalue_attrs(
            result['alternative_titles']['titles'], 'iso_3166_1', 'title'
        )
        listattr_keymap = [
            'studios:production_companies', 'genre:genres',
            'countries:production_countries'
        ]
        for keymap in listattr_keymap:
            key_result, key_response = keymap.split(':', maxsplit=1)
            result_dict[key_result] = self._config.extract_keyvalue_attrs(
                result[key_response], 'name'
            )
        result_dict['genre_norm'] = self._genrenorm.normalize_genre_list(
            result_dict['genre']
        )
        result_dict['keywords'] = self._config.extract_keyvalue_attrs(
            result['keywords']['keywords'], 'name'
        )

        # numeric attrs
        result_dict['year'] = int(result['release_date'][0:4] or 0) or None
        result_dict['runtime'] = int(result['runtime'] or 0) or None
        result_dict['vote_count'] = int(result['vote_count'] or 0) or None
        return result_dict

    def _extract_trailers(self, response):
        yt_url = 'http://www.youtube.com/watch\\?v\\={path}'
        result = []
        for path in response['youtube']:
            trailer_url = (path['size'], yt_url.format(path=path['source']))
            result.append(trailer_url)

        for source in response['quicktime']:
            for path in source['sources']:
                trailer_url = (path['size'], path['source'])
                result.append(trailer_url)
        return result

    @property
    def supported_attrs(self):
        return self._attrs
示例#6
0
class OMDBMovie(provider.IMovieProvider):
    """ OMDB Person text metadata provider.

    Interfaces implemented according to hugin.provider.interfaces.

    """

    def __init__(self):
        self._base_url = 'http://www.omdbapi.com/?{query}&plot=full'
        self._genrenorm = GenreNormalize('omdb.genre')
        self._priority = 80
        self._attrs = {
            'title', 'plot', 'runtime', 'imdbid', 'vote_count', 'rating',
            'directors', 'writers', 'year', 'poster', 'genre', 'genre_norm',
            'actors', 'original_title'
        }

    def build_url(self, search_params):
        if search_params.imdbid:
            params = {
                'i': search_params.imdbid
            }
            return [self._base_url.format(query=urlencode(params))]
        if search_params.title:
            params = {
                's': quote_plus(search_params.title) or '',
                'y': search_params.year or ''
            }
            return [self._base_url.format(query=urlencode(params))]

    def parse_response(self, url_response, search_params):
        fail_states = ['Incorrect IMDb ID', 'Movie not found!']

        try:
            url, response = url_response.pop()
            if response is None:
                return None, False

            if response:
                # some json docs from this provider have mysterious newlines.
                response = response.replace('\n', '')
            response = json.loads(response)
        except (TypeError, ValueError) as e:
            print('Exception in parse_response omdbmovie:', e)
            return None, True

        if 'Error' in response and response['Error'] in fail_states:
            return [], True

        if 'Search' in response:
            return self._parse_search_module(response, search_params), False

        if 'Title' in response:
            return self._parse_movie_module(response, search_params), True

        return None, True

    def _parse_search_module(self, result, search_params):
        similarity_map = []
        for result in result['Search']:
            if result['Type'] == 'movie' or result['Type'] == 'N/A':
                ratio = string_similarity_ratio(
                    result['Title'],
                    search_params.title
                )
                similarity_map.append(
                    {'imdbid': result['imdbID'], 'ratio': ratio}
                )
        similarity_map.sort(key=lambda value: value['ratio'], reverse=True)
        item_count = min(len(similarity_map), search_params.amount)
        movieids = [item['imdbid'] for item in similarity_map[:item_count]]
        return self._movieids_to_urllist(movieids)

    def _movieids_to_urllist(self, movieids):
        url_list = []
        for movieid in movieids:
            query = 'i={imdb_id}'.format(imdb_id=movieid)
            url_list.append([self._base_url.format(query=query)])
        return url_list

    def _parse_movie_module(self, result, search_params):
        result_dict = {k: None for k in self._attrs}

        #str attrs
        result_dict['title'] = ''.join(result['Title'].split(','))
        result_dict['original_title'] = result_dict.get('title')
        result_dict['plot'] = ''.join(result['Plot'].split(','))
        result_dict['imdbid'] = result.get('imdbID')
        result_dict['rating'] = result.get('imdbRating')

        #list attrs
        result_dict['poster'] = self._parse_poster(result)
        result_dict['actors'] = self._parse_list_attr(result, 'Actors')
        result_dict['directors'] = self._parse_list_attr(result, 'Director')
        result_dict['writers'] = self._parse_list_attr(result, 'Writer')
        result_dict['genre'] = self._parse_list_attr(result, 'Genre')
        result_dict['genre_norm'] = self._genrenorm.normalize_genre_list(
            result_dict['genre']
        )

        #numeric attrs
        result_dict['runtime'] = int(self._format_runtime(result['Runtime']))
        vote_count = result['imdbVotes'].replace(',', '')
        if vote_count.isnumeric():
            result_dict['vote_count'] = int(vote_count)
        if result['Year'].isdecimal():
            result_dict['year'] = int(result['Year'])

        return {key: self._filter_na(val) for key, val in result_dict.items()}

    def _parse_poster(self, response):
        poster = response.get('Poster')
        if self._filter_na(poster):
            return [(None, poster)]

    def _parse_list_attr(self, response, person_type):
        persons = response.get(person_type)
        if self._filter_na(persons):
            persons = persons.split(',')
            if person_type == 'Actors':
                return [(None, person.strip()) for person in persons]
            return [person.strip() for person in persons]

    def _filter_na(self, value):
        if value == 'N/A' or value == ['N/A']:
            return None
        return value

    def _format_runtime(self, runtime):
        result = 0
        time_fmt = {'HM': '{:d} h {:d} min', 'H': '{:d} h', 'M': '{:d} min'}
        if runtime and 'h' in runtime and 'min' in runtime:
            h, m = parse(time_fmt['HM'], runtime)
            result = (h * 60) + m
        elif 'min' in runtime:
            result, = parse(time_fmt['M'], runtime)
        elif 'h' in runtime:
            result, = parse(time_fmt['H'], runtime)
        return result

    @property
    def supported_attrs(self):
        return self._attrs