def get_excluded_types(cls) -> {str}: ''' :return: ''' iso_639_2_name = Settings.get_lang_iso_639_2() iso_639_1_name = Settings.get_lang_iso_639_1() return { '- JP Sub', 'Interview', '- UK', '- BR Sub', '- FR', '- IT', '- AU', '- MX', '- MX Sub', '- BR', '- RU', '- DE', '- ES', '- FR Sub', '- KR Sub', '- Russian', '- French', '- Spanish', '- German', '- Latin American Spanish', '- Italian' }
def get_excluded_types(cls): # type: () -> {str} ''' :return: ''' iso_639_2_name = Settings.get_lang_iso_639_2() iso_639_1_name = Settings.get_lang_iso_639_1() if cls._logger.isEnabledFor(LazyLogger.DEBUG): cls._logger.debug('iso_639_2:', iso_639_2_name, 'iso_639_1:', iso_639_1_name) return { '- JP Sub', 'Interview', '- UK', '- BR Sub', '- FR', '- IT', '- AU', '- MX', '- MX Sub', '- BR', '- RU', '- DE', '- ES', '- FR Sub', '- KR Sub', '- Russian', '- French', '- Spanish', '- German', '- Latin American Spanish', '- Italian' }
def get_tmdb_id(cls, movie): # type: (MovieType) -> int """ :param movie: :return: """ tmdb_id: Optional[str] = None imdb_id = None title = movie[Movie.TITLE] unique_id = movie.get(Movie.UNIQUE_ID, None) if unique_id is not None: # if cls._logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): # for key in unique_id: # cls._logger.debug_extra_verbose(title, key, unique_id.get(key, '')) tmdb_id = unique_id.get(Movie.UNIQUE_ID_TMDB, None) if tmdb_id is not None: # Make sure we don't have a IMDB id in here by error if tmdb_id.startswith('tt'): tmdb_id = None if tmdb_id is not None: tmdb_id: int = int(tmdb_id) else: imdb_id = unique_id.get(Movie.UNIQUE_ID_IMDB, None) if imdb_id is None: imdb_id = unique_id.get(Movie.UNIQUE_ID_UNKNOWN, None) if imdb_id is not None and not imdb_id.startswith('tt'): imdb_id = None if imdb_id is not None: data = {} data['external_source'] = 'imdb_id' # TODO: iso-639-1 gives two char lang. Prefer en-US data['language'] = Settings.get_lang_iso_639_1() data['api_key'] = Settings.get_tmdb_api_key() url = 'http://api.themoviedb.org/3/find/' + str(imdb_id) try: Monitor.throw_exception_if_abort_requested() status_code, tmdb_result = JsonUtilsBasic.get_json( url, error_msg=title, params=data, dump_results=True, dump_msg='') Monitor.throw_exception_if_abort_requested() if status_code == 0 and tmdb_result is not None: s_code = tmdb_result.get('status_code', None) if s_code is not None: status_code = s_code if status_code != 0: pass elif tmdb_result is not None: movie_results = tmdb_result.get( 'movie_results', []) if len(movie_results) == 0: pass elif len(movie_results) > 1: pass else: tmdb_id = movie_results[0].get('id', None) if tmdb_id is None: if cls._logger.isEnabledFor(LazyLogger.DEBUG): cls._logger.debug('Did not find movie for', 'imdb_id:', imdb_id, 'title:', title) else: cls.set_tmdb_id(movie, tmdb_id) cls.update_database_unique_id(movie) except AbortException: reraise(*sys.exc_info()) except Exception: cls._logger.exception('') if tmdb_id is not None: tmdb_id = int(tmdb_id) return tmdb_id
def get_alternate_titles(cls, movie_title, # type: str movie_id, # type: Union[int, str] ): # type: (...) -> MovieType """ :param cls: :param movie_title: :param movie_id: :return: """ if cls._logger.isEnabledFor(LazyLogger.DEBUG): cls._logger.debug('title:', movie_title, 'movie_id:', movie_id) data = {} # data['append_to_response'] = 'credits,releases' data['language'] = Settings.get_lang_iso_639_1() data['api_key'] = Settings.get_tmdb_api_key() data['append_to_response'] = 'alternative_titles' url = 'http://api.themoviedb.org/3/movie/' + str(movie_id) tmdb_result = None year = 0 dump_msg = 'movie_id: ' + str(movie_id) try: Monitor.throw_exception_if_abort_requested() status_code, tmdb_result = JsonUtilsBasic.get_json( url, error_msg=movie_title, params=data, dump_results=False, dump_msg=dump_msg) Monitor.throw_exception_if_abort_requested() if status_code == 0: s_code = tmdb_result.get('status_code', None) if s_code is not None: status_code = s_code if status_code != 0 and cls._logger.isEnabledFor(LazyLogger.DEBUG): cls._logger.debug( 'Error getting TMDB data for:', movie_title, 'status:', status_code) return None except AbortException: reraise(*sys.exc_info()) except Exception: cls._logger.exception('Error processing movie: ', movie_title) return None parsed_data = {} try: # release_date TMDB key is different from Kodi's try: year = tmdb_result['release_date'][:-6] year = int(year) except AbortException: reraise(*sys.exc_info()) except Exception: year = 0 parsed_data[Movie.YEAR] = year title = tmdb_result[Movie.TITLE] if cls._logger.isEnabledFor(LazyLogger.DEBUG): cls._logger.debug('Processing:', title, 'type:', type(title).__name__) parsed_data[Movie.TITLE] = title studios = tmdb_result['production_companies'] studio = [] for s in studios: studio.append(s['name']) parsed_data[Movie.STUDIO] = studio tmdb_cast_members = tmdb_result['credits']['cast'] cast = [] for cast_member in tmdb_cast_members: fake_cast_entry = {} fake_cast_entry['name'] = cast_member['name'] fake_cast_entry['character'] = cast_member['character'] cast.append(fake_cast_entry) parsed_data[Movie.CAST] = cast tmdb_crew_members = tmdb_result['credits']['crew'] director = [] writer = [] for crew_member in tmdb_crew_members: if crew_member['job'] == 'Director': director.append(crew_member['name']) if crew_member['department'] == 'Writing': writer.append(crew_member['name']) parsed_data[Movie.DIRECTOR] = director parsed_data[Movie.WRITER] = writer titles = tmdb_result.get('alternative_titles', {'titles': []}) alt_titles = [] for title in titles['titles']: alt_title = (title['title'], title['iso_3166_1']) alt_titles.append(alt_title) parsed_data['alt_titles'] = alt_titles original_title = tmdb_result['original_title'] if original_title is not None: parsed_data[Movie.ORIGINAL_TITLE] = original_title except AbortException as e: reraise(*sys.exc_info()) except Exception as e: cls._logger.exception('%s %s'.format( 'Error getting info for movie_id:', movie_id)) try: if cls._logger.isEnabledFor(LazyLogger.DEBUG): json_text = json.dumps( tmdb_result, indent=3, sort_keys=True) cls._logger.debug(json_text) except AbortException: reraise(*sys.exc_info()) except Exception as e: cls._logger('failed to get Json data') parsed_data = None cls._logger.exit('Finished processing movie: ', movie_title, 'year:', year) return parsed_data
def score(self, movie_title: str, movie_year: Union[str, None], movie_tmdb_id: str = None, runtime_seconds: int = 0) -> None: # Score tmdb movie: # Highest score if movie title, year and original language match # perfectly # (When searching for match of TFH movie, there is no date) # # Second highest score if all but original language matches # # Third score if title, original language match perfectly # # Fourth score if title nearly matches and year and original language # match perfectly # # Fifth score if title nearly matches, year matches but not language # # Sixth score if title nearly matches and original language matches # # Seventh score clz = type(self) try: score = 0 lower_movie_title = movie_title.lower() if lower_movie_title == self._lower_title: score = 1000 else: # # Perhaps there is a erroneous leading prefix, such as: 'The' # filtered_tmdb_title = re.sub( TMDBMatcher.FILTER_TITLE_PATTERN, r'\1', self._lower_title) filtered_movie_title = re.sub( TMDBMatcher.FILTER_TITLE_PATTERN, r'\1', lower_movie_title) if filtered_tmdb_title == lower_movie_title: score = 900 elif self._lower_title == filtered_movie_title: score = 900 if clz._logger.isEnabledFor( LazyLogger.DEBUG_EXTRA_VERBOSE): clz._logger.debug_extra_verbose( f'tmdb_title: {self._lower_title}' f' filtered: {filtered_tmdb_title}' f' movie_title: {lower_movie_title}' f' filtered: {filtered_movie_title}' f' score: {score}') # Check if within a year of expected year if movie_year is not None: if abs(int(movie_year) - int(self._year)) < 2: score += 500 if self._language == Settings.get_lang_iso_639_1(): score += 10 if runtime_seconds > 0 and self._runtime_seconds > 0: # Movie duration may be off a bit time_delta = abs(runtime_seconds - self._runtime_seconds) # Non-linear penalty for more error score += 250 * (sqrt(runtime_seconds**2 - time_delta**2) / runtime_seconds) else: if self._runtime_seconds >= 50 * 60: # Avoid movies < 50 minutes score += 50 self._score = score except AbortException: reraise(*sys.exc_info()) except Exception as e: clz._logger.exception(e)
def __init__(self, title: str, year: Union[str, None], runtime_seconds: int) -> None: clz = type(self) if clz._logger is None: clz._logger = module_logger.getChild(clz.__name__) self._title_to_match: str = title self._year_to_match: Union[str, None] = year self._runtime_seconds_to_match: int = runtime_seconds self.candidate_movies: List[clz.CandidateMovie] = [] data = { 'api_key': Settings.get_tmdb_api_key(), 'page': '1', 'query': title, 'language': Settings.get_lang_iso_639_1() } if year is not None: data['primary_release_year'] = year try: include_adult = 'false' country_id = Settings.get_country_iso_3166_1().lower() certifications = WorldCertifications.get_certifications(country_id) adult_certification = certifications.get_certification( 'dummy', True) if certifications.filter(adult_certification): include_adult = 'true' data['include_adult'] = include_adult data['append_to_response'] = 'alternative_titles' url = 'https://api.themoviedb.org/3/search/movie' status_code, _info_string = \ JsonUtilsBasic.get_json(url, params=data, dump_msg='get_tmdb_id_from_title_year', dump_results=True, error_msg=title + f' ({year})') if clz._logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): clz._logger.debug_extra_verbose( f'Getting TMDB movie for title: {title} year: {year} ' f'runtime: {runtime_seconds}') if _info_string is not None: results = _info_string.get('results', []) if len(results) > 1: if clz._logger.isEnabledFor( LazyLogger.DEBUG_EXTRA_VERBOSE): clz._logger.debug_extra_verbose( f'Got multiple matching movies: {title} ' f'year: {year} runtime: {runtime_seconds}') # TODO: Improve. Create best trailer function from get_tmdb_trailer # TODO: find best trailer_id current_language = Settings.get_lang_iso_639_1() for movie in results: release_date = movie.get('release_date', '') # 1932-04-22 tmdb_year = release_date[:-6] movie[Movie.YEAR] = tmdb_year tmdb_title = movie.get('title', '') tmdb_id = movie.get('id', None) tmdb_language = movie.get('original_language') runtime_minutes = movie.get(Movie.RUNTIME, 0) runtime_seconds = int(runtime_minutes * 60) titles = movie.get('alternative_titles', {'titles': []}) alt_titles = [] for title in titles['titles']: alt_title = (title['title'], title['iso_3166_1']) alt_titles.append(alt_title) if clz._logger.isEnabledFor( LazyLogger.DEBUG_EXTRA_VERBOSE): clz._logger.debug_extra_verbose( f'Matching Movie date: {tmdb_year}' f' tmdb_title: {tmdb_title}' f' lang: {tmdb_language}' f' current_lang: {current_language}') self._add(movie, tmdb_title, tmdb_year, tmdb_language, tmdb_id, runtime_seconds) except AbortException: reraise(*sys.exc_info()) except Exception as e: clz._logger.exception(e)
def _get_tmdb_id_from_title_year(title: str, year: int) -> Optional[int]: """ When we don't have a trailer for a movie, we can see if TMDB has one. :param title: :param year: :return: """ year_str = str(year) found_movie = None trailer_id = None data = {} data['api_key'] = Settings.get_tmdb_api_key() data['page'] = '1' data['query'] = title data['language'] = Settings.get_lang_iso_639_1() data['primary_release_year'] = year try: include_adult = 'false' country_id = Settings.get_country_iso_3166_1().lower() certifications = WorldCertifications.get_certifications(country_id) adult_certification = certifications.get_certification( 'dummy', True) if certifications.filter(adult_certification): include_adult = 'true' data['include_adult'] = include_adult url = 'https://api.themoviedb.org/3/search/movie' status_code, _info_string = \ JsonUtilsBasic.get_json(url, params=data, dump_msg='get_tmdb_id_from_title_year', dump_results=True, error_msg=title + ' (' + year_str + ')') if _info_string is not None: results = _info_string.get('results', []) if len(results) > 1: if TMDBUtils._logger.isEnabledFor( LazyLogger.DEBUG_EXTRA_VERBOSE): TMDBUtils._logger.debug_extra_verbose( 'Got multiple matching movies:', title, 'year:', year) # TODO: Improve. Create best trailer function from get_tmdb_trailer # TODO: find best trailer_id matches = [] current_language = Settings.get_lang_iso_639_1() movie = None for movie in results: release_date = movie.get('release_date', '') # 1932-04-22 found_year = release_date[:-6] found_title = movie.get('title', '') if (found_title.lower() == title.lower() and found_year == year_str and movie.get('original_language') == current_language): matches.append(movie) # TODO: Consider close match heuristics. if len(matches) == 1: found_movie = matches[0] elif len(matches) > 1: if TMDBUtils._logger.isEnabledFor( LazyLogger.DEBUG_VERBOSE): TMDBUtils._logger.debug_extra_verbose( 'More than one matching movie in same year choosing first ' 'one matching current language.', 'Num choices:', len(matches)) found_movie = matches[0] if movie is None: if TMDBUtils._logger.isEnabledFor( LazyLogger.DEBUG_EXTRA_VERBOSE): TMDBUtils._logger.debug_extra_verbose( 'Could not find movie:', title, 'year:', year, 'at TMDB. found', len(results), 'candidates') for a_movie in results: release_date = a_movie.get('release_date', '') # 1932-04-22 found_year = release_date[:-6] found_title = a_movie.get('title', '') tmdb_id = a_movie.get('id', None) if TMDBUtils._logger.isEnabledFor(LazyLogger.DISABLED): TMDBUtils._logger.debug_extra_verbose( 'found:', found_title, '(', found_year, ')', 'tmdb id:', tmdb_id) tmdb_data = MovieEntryUtils.get_alternate_titles( title, tmdb_id) for alt_title, country in tmdb_data['alt_titles']: if alt_title.lower() == title.lower(): found_movie = tmdb_data # Not actually in "movie" format break else: if TMDBUtils._logger.isEnabledFor(LazyLogger.INFO): TMDBUtils._logger.info('Could not find movie:', title, 'year:', year, 'at TMDB. found no candidates') except AbortException: reraise(*sys.exc_info()) except Exception: TMDBUtils._logger.exception('') tmdb_id = None if found_movie is not None: tmdb_id = found_movie.get('id', None) if tmdb_id is None: return None return int(tmdb_id)