diff --git a/src/args.py b/src/args.py index cf6b03aa..c18e7588 100644 --- a/src/args.py +++ b/src/args.py @@ -49,6 +49,7 @@ def parse(self, args, meta): parser.add_argument('--no-tag', dest='no_tag', action='store_true', required=False, help="Remove Group Tag from title") parser.add_argument('--no-edition', dest='no_edition', action='store_true', required=False, help="Remove Edition from title") parser.add_argument('--dual-audio', dest='dual_audio', action='store_true', required=False, help="Add Dual-Audio to the title") + parser.add_argument('-ol', '--original-language', dest='manual_language', nargs='*', required=False, help="Set original audio language") parser.add_argument('-ns', '--no-seed', action='store_true', required=False, help="Do not add torrent to the client") parser.add_argument('-year', '--year', dest='manual_year', nargs='?', required=False, help="Override the year found", type=int, default=0) parser.add_argument('-ptp', '--ptp', nargs='*', required=False, help="PTP torrent id/permalink", type=str) diff --git a/src/prep.py b/src/prep.py index 631ebdfd..85373bd2 100644 --- a/src/prep.py +++ b/src/prep.py @@ -621,6 +621,10 @@ async def process_tracker(tracker_name, meta): console.print("Skipping existing search as meta already populated") console.print("[yellow]Building meta data.....") + if meta['debug']: + meta_start_time = time.time() + if meta.get('manual_language'): + meta['original_langauge'] = meta.get('manual_language').lower() meta['tmdb'] = meta.get('tmdb_manual', None) meta['type'] = self.get_type(video, meta['scene'], meta['is_disc'], meta) if meta.get('category', None) is None: @@ -651,7 +655,7 @@ async def process_tracker(tracker_name, meta): if meta.get('imdb_id', None) is None: meta['imdb_id'] = await self.search_imdb(filename, meta['search_year']) if meta.get('imdb_info', None) is None and int(meta['imdb_id']) != 0: - meta['imdb_info'] = await self.get_imdb_info(meta['imdb_id'], meta) + meta['imdb_info'] = await self.get_imdb_info_api(meta['imdb_id'], meta) if meta.get('tag', None) is None: meta['tag'] = self.get_tag(video, meta) else: @@ -705,6 +709,9 @@ async def process_tracker(tracker_name, meta): meta['edition'] = "" meta['name_notag'], meta['name'], meta['clean_name'], meta['potential_missing'] = await self.get_name(meta) + if meta['debug']: + meta_finish_time = time.time() + console.print(f"Metadata processed in {meta_finish_time - meta_start_time:.2f} seconds") parser = Args(config) helper = UploadHelper() confirm = helper.get_confirmation(meta) @@ -2085,11 +2092,13 @@ async def get_tmdb_from_imdb(self, meta, filename): if len(info['movie_results']) >= 1: meta['category'] = "MOVIE" meta['tmdb'] = info['movie_results'][0]['id'] + meta['original_language'] = info['movie_results'][0].get('original_language') elif len(info['tv_results']) >= 1: meta['category'] = "TV" meta['tmdb'] = info['tv_results'][0]['id'] + meta['original_language'] = info['tv_results'][0].get('original_language') else: - imdb_info = await self.get_imdb_info(imdb_id.replace('tt', ''), meta) + imdb_info = await self.get_imdb_info_api(imdb_id.replace('tt', ''), meta) title = imdb_info.get("title") if title is None: title = filename @@ -2199,7 +2208,7 @@ async def tmdb_other_meta(self, meta): except Exception: console.print('[yellow]Unable to grab videos from TMDb.') - meta['aka'], original_language = await self.get_imdb_aka(meta['imdb_id']) + meta['aka'], original_language = await self.get_imdb_aka_api(meta['imdb_id'], meta) if original_language is not None: meta['original_language'] = original_language else: @@ -2253,7 +2262,7 @@ async def tmdb_other_meta(self, meta): console.print('[yellow]Unable to grab videos from TMDb.') # meta['aka'] = f" AKA {response['original_name']}" - meta['aka'], original_language = await self.get_imdb_aka(meta['imdb_id']) + meta['aka'], original_language = await self.get_imdb_aka_api(meta['imdb_id'], meta) if original_language is not None: meta['original_language'] = original_language else: @@ -2497,7 +2506,7 @@ def get_audio_v2(self, mi, meta, bdinfo): if meta.get('dual_audio', False): dual = "Dual-Audio" else: - if meta.get('original_language', '') != 'en': + if not meta.get('original_language', '').startswith('en'): eng, orig = False, False try: for t in tracks: @@ -4248,12 +4257,67 @@ async def package(self, meta): return False return + async def get_imdb_aka_api(self, imdb_id, meta): + if imdb_id == "0": + return "", None + if not imdb_id.startswith("tt"): + imdb_id = f"tt{imdb_id}" + url = "https://api.graphql.imdb.com/" + query = { + "query": f""" + query {{ + title(id: "{imdb_id}") {{ + id + titleText {{ + text + isOriginalTitle + }} + originalTitleText {{ + text + }} + countriesOfOrigin {{ + countries {{ + id + }} + }} + }} + }} + """ + } + + headers = { + "Content-Type": "application/json", + } + + response = requests.post(url, headers=headers, json=query) + data = response.json() + + # Check if `data` and `title` exist + title_data = data.get("data", {}).get("title") + if title_data is None: + console.print("Title data is missing from response") + return "", None + + # Extract relevant fields from the response + aka = title_data.get("originalTitleText", {}).get("text", "") + is_original = title_data.get("titleText", {}).get("isOriginalTitle", False) + if meta.get('manual_language'): + original_language = meta.get('manual_language') + else: + original_language = None + + if not is_original and aka: + aka = f" AKA {aka}" + + return aka, original_language + async def get_imdb_aka(self, imdb_id): if imdb_id == "0": return "", None + if not imdb_id.startswith("tt"): + imdb_id = f"tt{imdb_id}" ia = Cinemagoer() result = ia.get_movie(imdb_id.replace('tt', '')) - original_language = result.get('language codes') if isinstance(original_language, list): if len(original_language) > 1: @@ -4318,6 +4382,138 @@ def daily_to_tmdb_season_episode(self, tmdbid, date): console.print(f"[yellow]Unable to map the date ([bold yellow]{str(date)}[/bold yellow]) to a Season/Episode number") return season, episode + async def get_imdb_info_api(self, imdbID, meta): + imdb_info = {} + + if imdbID == "0": + return "", None + else: + if not imdbID.startswith("tt"): + imdbIDtt = f"tt{imdbID}" + query = { + "query": f""" + query GetTitleInfo {{ + title(id: "{imdbIDtt}") {{ + id + titleText {{ + text + isOriginalTitle + }} + originalTitleText {{ + text + }} + releaseYear {{ + year + }} + titleType {{ + id + }} + plot {{ + plotText {{ + plainText + }} + }} + ratingsSummary {{ + aggregateRating + voteCount + }} + primaryImage {{ + url + }} + runtime {{ + displayableProperty {{ + value {{ + plainText + }} + }} + seconds + }} + titleGenres {{ + genres {{ + genre {{ + text + }} + }} + }} + principalCredits {{ + category {{ + text + id + }} + credits {{ + name {{ + id + nameText {{ + text + }} + }} + }} + }} + }} + }} + """ + } + + url = "https://api.graphql.imdb.com/" + headers = {"Content-Type": "application/json"} + + response = requests.post(url, json=query, headers=headers) + data = response.json() + + title_data = data.get("data", {}).get("title", {}) + if not title_data: + return meta + imdb_info['imdbID'] = imdbID + imdb_info['title'] = title_data.get('titleText', {}).get('text', '') or '' + imdb_info['year'] = title_data.get('releaseYear', {}).get('year', '') or '' + original_title = title_data.get('originalTitleText', {}).get('text', '') + if not original_title or original_title == imdb_info['title']: + original_title = imdb_info['title'] + imdb_info['aka'] = original_title + imdb_info['type'] = title_data.get('titleType', {}).get('id', '') + runtime_data = title_data.get('runtime', {}) + runtime_seconds = runtime_data.get('seconds', 0) + runtime_minutes = runtime_seconds // 60 if runtime_seconds else 0 + imdb_info['runtime'] = str(runtime_minutes) + imdb_info['cover'] = title_data.get('primaryImage', {}).get('url', '') or meta.get('poster', '') + imdb_info['plot'] = title_data.get('plot', {}).get('plotText', {}).get('plainText', '') or 'No plot available' + title_genres = title_data.get('titleGenres') + if title_genres and isinstance(title_genres, dict): + genres = title_genres.get('genres', []) + else: + genres = [] + genre_list = [g.get('genre', {}).get('text', '') for g in genres if g.get('genre', {}).get('text')] + imdb_info['genres'] = ', '.join(genre_list) or '' + imdb_info['rating'] = title_data.get('ratingsSummary', {}).get('aggregateRating', 'N/A') + imdb_info['directors'] = [] + principal_credits = title_data.get('principalCredits', []) + if principal_credits and isinstance(principal_credits, list): + for pc in principal_credits: + category_text = pc.get('category', {}).get('text', '') + if 'Direct' in category_text: + credits = pc.get('credits', []) + if credits and isinstance(credits, list): + for c in credits: + name_id = c.get('name', {}).get('id', '') + if name_id.startswith('nm'): + imdb_info['directors'].append(name_id) + break + if meta.get('manual_language'): + imdb_info['original_langauge'] = meta.get('manual_language') + + if not title_data: + imdb_info = { + 'title': meta['title'], + 'year': meta['year'], + 'aka': '', + 'type': None, + 'runtime': meta.get('runtime', '60'), + 'cover': meta.get('poster'), + } + if len(meta.get('tmdb_directors', [])) >= 1: + imdb_info['directors'] = meta['tmdb_directors'] + return imdb_info + async def get_imdb_info(self, imdbID, meta): imdb_info = {} if int(str(imdbID).replace('tt', '')) != 0: @@ -4356,7 +4552,6 @@ async def get_imdb_info(self, imdbID, meta): } if len(meta.get('tmdb_directors', [])) >= 1: imdb_info['directors'] = meta['tmdb_directors'] - return imdb_info async def search_imdb(self, filename, search_year): @@ -4370,7 +4565,7 @@ async def search_imdb(self, filename, search_year): return imdbID async def imdb_other_meta(self, meta): - imdb_info = meta['imdb_info'] = await self.get_imdb_info(meta['imdb_id'], meta) + imdb_info = meta['imdb_info'] = await self.get_imdb_info_api(meta['imdb_id'], meta) meta['title'] = imdb_info['title'] meta['year'] = imdb_info['year'] meta['aka'] = imdb_info['aka']