From 494557bb0e38b424c1a7daf174fb931e37792534 Mon Sep 17 00:00:00 2001 From: wumode Date: Mon, 21 Jul 2025 18:08:31 +0800 Subject: [PATCH] =?UTF-8?q?update(ImdbSource)=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E5=AA=92=E4=BD=93id=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.v2.json | 3 +- .../__federation_expose_Page-y2yjbals.js | 10 +-- plugins.v2/imdbsource/__init__.py | 89 +++++++++++++++---- plugins.v2/imdbsource/imdbhelper.py | 10 +-- 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/package.v2.json b/package.v2.json index 1638045..28ebe63 100644 --- a/package.v2.json +++ b/package.v2.json @@ -435,11 +435,12 @@ "name": "IMDb源", "description": "让探索,推荐和媒体识别支持IMDb数据源。", "labels": "探索", - "version": "1.5.0", + "version": "1.5.1", "icon": "IMDb_IOS-OSX_App.png", "author": "wumode", "level": 1, "history": { + "v1.5.1": "改进媒体id转换", "v1.5.0": "支持媒体识别", "v1.4.4": "更新数据源", "v1.4.3": "为仪表盘组件添加缓存", diff --git a/plugins.v2/clashruleprovider/dist/assets/__federation_expose_Page-y2yjbals.js b/plugins.v2/clashruleprovider/dist/assets/__federation_expose_Page-y2yjbals.js index 1adef94..6c75e19 100644 --- a/plugins.v2/clashruleprovider/dist/assets/__federation_expose_Page-y2yjbals.js +++ b/plugins.v2/clashruleprovider/dist/assets/__federation_expose_Page-y2yjbals.js @@ -4242,7 +4242,7 @@ const _hoisted_1 = { class: "plugin-page" }; const _hoisted_2 = { key: 2 }; const _hoisted_3 = { class: "mb-6" }; const _hoisted_4 = { class: "pa-4" }; -const _hoisted_5 = { class: "d-flex justify-space-between align-center mb-4" }; +const _hoisted_5 = { class: "d-flex justify-space-between align-center" }; const _hoisted_6 = { class: "d-flex align-center" }; const _hoisted_7 = ["onDragstart", "onDragover", "onDrop"]; const _hoisted_8 = { @@ -4253,7 +4253,7 @@ const _hoisted_9 = { class: "d-flex justify-center" }; const _hoisted_10 = { style: {"position":"absolute","right":"0","bottom":"0"} }; const _hoisted_11 = { class: "mb-6" }; const _hoisted_12 = { class: "pa-4" }; -const _hoisted_13 = { class: "d-flex justify-space-between align-center mb-4" }; +const _hoisted_13 = { class: "d-flex justify-space-between align-center" }; const _hoisted_14 = { class: "d-flex align-center" }; const _hoisted_15 = ["onDragstart", "onDragover", "onDrop"]; const _hoisted_16 = { @@ -4264,7 +4264,7 @@ const _hoisted_17 = { class: "d-flex justify-center" }; const _hoisted_18 = { style: {"position":"absolute","right":"0","bottom":"0"} }; const _hoisted_19 = { class: "mb-6" }; const _hoisted_20 = { class: "pa-4" }; -const _hoisted_21 = { class: "d-flex justify-space-between align-center mb-4" }; +const _hoisted_21 = { class: "d-flex justify-space-between align-center" }; const _hoisted_22 = { class: "d-flex" }; const _hoisted_23 = { class: "position-relative px-4 py-2", @@ -4274,7 +4274,7 @@ const _hoisted_24 = { class: "d-flex justify-center" }; const _hoisted_25 = { style: {"position":"absolute","right":"0","bottom":"0"} }; const _hoisted_26 = { class: "mb-6" }; const _hoisted_27 = { class: "pa-4" }; -const _hoisted_28 = { class: "d-flex justify-space-between align-center mb-4" }; +const _hoisted_28 = { class: "d-flex justify-space-between align-center" }; const _hoisted_29 = { class: "d-flex" }; const _hoisted_30 = { class: "position-relative px-4 py-2", @@ -4284,7 +4284,7 @@ const _hoisted_31 = { class: "d-flex justify-center" }; const _hoisted_32 = { style: {"position":"absolute","right":"0","bottom":"0"} }; const _hoisted_33 = { class: "mb-6" }; const _hoisted_34 = { class: "pa-4" }; -const _hoisted_35 = { class: "d-flex justify-space-between align-center mb-4" }; +const _hoisted_35 = { class: "d-flex justify-space-between align-center" }; const _hoisted_36 = { class: "d-flex align-center" }; const _hoisted_37 = { class: "position-relative px-4 py-2", diff --git a/plugins.v2/imdbsource/__init__.py b/plugins.v2/imdbsource/__init__.py index 83a4fa1..923e8fd 100644 --- a/plugins.v2/imdbsource/__init__.py +++ b/plugins.v2/imdbsource/__init__.py @@ -28,7 +28,7 @@ class ImdbSource(_PluginBase): # 插件图标 plugin_icon = "IMDb_IOS-OSX_App.png" # 插件版本 - plugin_version = "1.5.0" + plugin_version = "1.5.1" # 插件作者 plugin_author = "wumode" # 作者主页 @@ -1672,25 +1672,14 @@ class ImdbSource(_PluginBase): event_data: MediaRecognizeConvertEventData = event.event_data if not event_data: return - api_key = settings.TMDB_API_KEY - if event_data.convert_type != "themoviedb" or not api_key: + if event_data.convert_type != "themoviedb": return if not event_data.mediaid.startswith("imdb"): return imdb_id = event_data.mediaid[5:] - api_url = f"https://{settings.TMDB_API_DOMAIN}/3/find/{imdb_id}?api_key={api_key}&external_source=imdb_id" - ret = RequestUtils(accept_type="application/json").get_res(api_url) - if ret: - data = ret.json() - all_results = [] - for result_type in ["movie_results", "tv_results"]: - if data.get(result_type): - all_results.extend(data[result_type]) - if not all_results: - return # 无匹配结果 - # 按 popularity 降序排序,取最高人气的条目 - most_popular_item = max(all_results, key=lambda x: x.get("popularity", -1)) - event_data.media_dict["id"] = most_popular_item.get("id") + tmdb_id = ImdbSource.imdb_to_tmdb(imdb_id) + if tmdb_id is not None: + event_data.media_dict["id"] = tmdb_id @eventmanager.register(ChainEventType.RecommendSource) def recommend_source(self, event: Event): @@ -1782,6 +1771,7 @@ class ImdbSource(_PluginBase): if info: info = self._imdb_helper.update_info(info.get('id'), info=info) or {} mediainfo = ImdbSource._convert_mediainfo(info) + mediainfo.tmdb_id = ImdbSource.imdb_to_tmdb(info.get('id'), mediainfo) logger.info(f"{meta.name} IMDb 识别结果:{mediainfo.type.value} " f"{mediainfo.title_year} " f"{mediainfo.imdb_id}") @@ -1826,3 +1816,70 @@ class ImdbSource(_PluginBase): if not mediainfo.release_date: mediainfo.release_date = air_date return mediainfo + + @staticmethod + def imdb_to_tmdb(imdb_id: str, media_info: Optional[MediaInfo] = None) -> Optional[int]: + api_key = settings.TMDB_API_KEY + api_url = ( + f"https://{settings.TMDB_API_DOMAIN}/3/find/{imdb_id}" + f"?api_key={api_key}&external_source=imdb_id" + ) + ret = RequestUtils(accept_type="application/json").get_res(api_url) + if not ret: + return None + data = ret.json() + # 合并两种结果 + all_results = [] + for key in ["movie_results", "tv_results"]: + all_results.extend(data.get(key, [])) + if not all_results: + return None # 无匹配结果 + + def pick_most_popular(results): + return max(results, key=lambda x: x.get("popularity", -1), default=None) + + # 未提供 media_info:直接返回人气最高的 + if not media_info: + most_popular = pick_most_popular(all_results) + return most_popular.get("id") if most_popular else None + # 按类型过滤 + type_map = { + MediaType.TV: ['tv'], + MediaType.MOVIE: ['movie'], + None: ['tv', 'movie'] + } + allowed_types = type_map.get(media_info.type, ['tv', 'movie']) + filtered = [res for res in all_results if res.get('type') in allowed_types] + + # 定义一个过滤链:每次过滤后如果只剩一个结果就返回 + def filter_and_return(results, predicate): + filtered_res = [res for res in results if predicate(res)] + if not filtered_res: + return None, [] + if len(filtered_res) == 1: + return filtered_res[0].get("id"), [] + return None, filtered_res + + # 通过年份过滤 + if media_info.year: + def match_year(res): + date = res.get('first_air_date') or res.get('release_date') or '' + return date[:4] == media_info.year + result_id, filtered = filter_and_return(filtered, match_year) + if result_id: + return result_id + if not filtered: + return None + # 通过名称过滤 + if media_info.names: + def match_name(res): + name = res.get('name') or '' + return ImdbHelper.compare_names(name, media_info.names) + result_id, filtered = filter_and_return(filtered, match_name) + if result_id: + return result_id + if not filtered: + return None + # 最终按人气返回 + most_popular = pick_most_popular(filtered) + return most_popular.get("id") if most_popular else None diff --git a/plugins.v2/imdbsource/imdbhelper.py b/plugins.v2/imdbsource/imdbhelper.py index 9679b16..1ecff47 100644 --- a/plugins.v2/imdbsource/imdbhelper.py +++ b/plugins.v2/imdbsource/imdbhelper.py @@ -218,7 +218,7 @@ class ImdbHelper: return None @staticmethod - def __compare_names(file_name: str, names: Union[list,str]) -> bool: + def compare_names(file_name: str, names: Union[list,str]) -> bool: """ 比较文件名是否匹配,忽略大小写和特殊字符 :param file_name: 识别的文件名或者种子名 @@ -688,11 +688,11 @@ class ImdbHelper: start_year = result.get('startYear') if year and str(start_year) != year: continue - if ImdbHelper.__compare_names(name, [result.get('primaryTitle', ''), result.get('originalTitle', '')]): + if ImdbHelper.compare_names(name, [result.get('primaryTitle', ''), result.get('originalTitle', '')]): ret_info = result break names = [edge.get('node', {}).get('text', '') for edge in title.get('akas', {}).get('edges', [])] - if ImdbHelper.__compare_names(name, names): + if ImdbHelper.compare_names(name, names): ret_info = result break if ret_info: @@ -740,13 +740,13 @@ class ImdbHelper: title = titles_dict.get(tv.get('id'), {}) akas = [e.get('node', {}) for e in title.get('akas', {}).get('edges', [])] tv_year = tv.get('startYear') - if self.__compare_names(name, [tv.get('primaryTitle', ''), tv.get('originalTitle', '')]) and \ + if self.compare_names(name, [tv.get('primaryTitle', ''), tv.get('originalTitle', '')]) and \ str(tv_year) == season_year: tv['akas'] = akas tv['rating'] = title.get('ratingsSummary') or {} return tv names = [aka.get('text', '') for aka in akas] - if not tv or not self.__compare_names(name, names): + if not tv or not self.compare_names(name, names): continue if __season_match(_tv_info=tv, _season_year=season_year): tv['akas'] = akas