Merge pull request #914 from wumode/imdbsource

This commit is contained in:
jxxghp
2025-11-01 19:51:22 +08:00
committed by GitHub
4 changed files with 56 additions and 59 deletions

View File

@@ -453,11 +453,12 @@
"name": "IMDb源",
"description": "让探索推荐和媒体识别支持IMDb数据源。",
"labels": "探索",
"version": "1.6.1",
"version": "1.6.2",
"icon": "IMDb_IOS-OSX_App.png",
"author": "wumode",
"level": 1,
"history": {
"v1.6.2": "修复 API 查询错误重试问题",
"v1.6.1": "添加中文主屏幕组件; 修复 bug",
"v1.5.8": "修改UA",
"v1.5.7": "改进异常处理",

View File

@@ -30,7 +30,7 @@ class ImdbSource(_PluginBase):
# 插件图标
plugin_icon = "IMDb_IOS-OSX_App.png"
# 插件版本
plugin_version = "1.6.1"
plugin_version = "1.6.2"
# 插件作者
plugin_author = "wumode"
# 作者主页

View File

@@ -35,7 +35,7 @@ class ImdbApiClient:
client=self._free_api_client
)
@retry(Exception, logger=logger)
@retry(Exception, logger=logger, delay=1)
@cached(maxsize=1024, ttl=CACHE_LIFESPAN)
def _free_imdb_api(self, path: str, params: Optional[dict] = None) -> Optional[dict]:
r = self._req.get_res(url=f"{self.BASE_URL}{path}", params=params, raise_exception=True)
@@ -49,7 +49,7 @@ class ImdbApiClient:
return None
return r.json()
@retry(Exception, logger=logger)
@retry(Exception, logger=logger, delay=1)
@cached(maxsize=1024, ttl=CACHE_LIFESPAN)
async def _async_free_imdb_api(self, path: str, params: Optional[dict] = None) -> Optional[dict]:
r = await self._async_req.get_res(url=f"{self.BASE_URL}{path}", params=params, raise_exception=True)

View File

@@ -13,7 +13,6 @@ from app.utils.http import RequestUtils, AsyncRequestUtils
from .schema.imdbtypes import ImdbType
from .schema import VerticalList, AdvancedTitleSearchResponse, AdvancedTitleSearch, TitleEdge, SearchParams
INTERESTS_ID: Final[Dict[str, Dict[str, str]]] = {
"Action": {
"Action": "in0000001",
@@ -277,45 +276,45 @@ INTERESTS_ID: Final[Dict[str, Dict[str, str]]] = {
}
CACHE_LIFETIME: Final[int] = 86400
IMDB_GRAPHQL_QUERY: Final[str] = \
"""query VerticalListPageItems( $titles: [ID!]! $names: [ID!]! $images: [ID!]! $videos: [ID!]!) {
titles(ids: $titles) { ...TitleParts meterRanking { currentRank meterType rankChange {changeDirection difference} } ratingsSummary { aggregateRating } }
names(ids: $names) { ...NameParts }
videos(ids: $videos) { ...VideoParts }
images(ids: $images) { ...ImageParts }
}
fragment TitleParts on Title {
id
titleText { text }
titleType { id }
releaseYear { year }
akas(first: 50) { edges { node { text country { id text } language { text } } } }
plot { plotText {plainText}}
primaryImage { id url width height }
releaseDate {day month year}
titleGenres {genres {genre { text }}}
certificate { rating }
originalTitleText{ text }
runtime { seconds }
}
fragment NameParts on Name {
id
nameText { text }
primaryImage { id url width height }
}
fragment ImageParts on Image {
id
height
width
url
}
fragment VideoParts on Video {
id
name { value }
contentType { displayName { value } id }
previewURLs { displayName { value } url videoDefinition videoMimeType }
playbackURLs { displayName { value } url videoDefinition videoMimeType }
thumbnail { height url width }
}"""
"""query VerticalListPageItems( $titles: [ID!]! $names: [ID!]! $images: [ID!]! $videos: [ID!]!) {
titles(ids: $titles) { ...TitleParts meterRanking { currentRank meterType rankChange {changeDirection difference} } ratingsSummary { aggregateRating } }
names(ids: $names) { ...NameParts }
videos(ids: $videos) { ...VideoParts }
images(ids: $images) { ...ImageParts }
}
fragment TitleParts on Title {
id
titleText { text }
titleType { id }
releaseYear { year }
akas(first: 50) { edges { node { text country { id text } language { text } } } }
plot { plotText {plainText}}
primaryImage { id url width height }
releaseDate {day month year}
titleGenres {genres {genre { text }}}
certificate { rating }
originalTitleText{ text }
runtime { seconds }
}
fragment NameParts on Name {
id
nameText { text }
primaryImage { id url width height }
}
fragment ImageParts on Image {
id
height
width
url
}
fragment VideoParts on Video {
id
name { value }
contentType { displayName { value } id }
previewURLs { displayName { value } url videoDefinition videoMimeType }
playbackURLs { displayName { value } url videoDefinition videoMimeType }
thumbnail { height url width }
}"""
class PersistedQueryNotFound(Exception):
@@ -332,7 +331,7 @@ class OfficialApiClient:
self._req = RequestUtils(accept_type="application/json",
content_type="application/json",
timeout=10,
ua=None,
ua=ua,
proxies=proxies,
session=requests.Session())
if proxies:
@@ -358,7 +357,7 @@ class OfficialApiClient:
return {'error': error}
return data.get("data")
@retry(Exception, logger=logger)
@retry(Exception, logger=logger, delay=1)
@cached(maxsize=1024, ttl=CACHE_LIFETIME)
def _query_graphql(self, query: str, variables: Dict[str, Any]) -> Optional[dict]:
params = {'query': query, 'variables': variables}
@@ -370,7 +369,7 @@ class OfficialApiClient:
return {'error': error}
return data.get("data")
@retry(Exception, logger=logger)
@retry(Exception, logger=logger, delay=1)
@cached(maxsize=1024, ttl=CACHE_LIFETIME)
async def _async_query_graphql(self, query: str, variables: Dict[str, Any]) -> Optional[Dict]:
params = {'query': query, 'variables': variables}
@@ -438,12 +437,12 @@ class OfficialApiClient:
return ret
@retry(Exception, logger=logger)
@retry(Exception, logger=logger, delay=1)
async def async_advanced_title_search(self,
params: SearchParams,
sha256: str,
last_cursor: Optional[str] = None,
) -> Optional[AdvancedTitleSearch]:
params: SearchParams,
sha256: str,
last_cursor: Optional[str] = None,
) -> Optional[AdvancedTitleSearch]:
variables: Dict[str, Any] = {"first": 50,
"locale": "en-US",
@@ -457,7 +456,7 @@ class OfficialApiClient:
if title_type in ImdbType._value2member_map_:
title_type_ids.append(title_type)
if len(title_type_ids):
variables["titleTypeConstraint"] = {"anyTitleTypeIds": params.title_types}
variables["titleTypeConstraint"] = {"anyTitleTypeIds": title_type_ids}
if params.genres:
variables["genreConstraint"] = {"allGenreIds": params.genres, "excludeGenreIds": []}
if params.countries:
@@ -504,11 +503,7 @@ class OfficialApiClient:
params = {"operationName": operation_name,
"variables": variables}
try:
data = await self._async_request(params, sha256)
except Exception as e:
logger.debug(f"An error occurred while querying {operation_name}: {e}")
return None
data = await self._async_request(params, sha256)
if not data:
return None
if 'error' in data:
@@ -525,7 +520,8 @@ class OfficialApiClient:
return None
return ret.advanced_title_search
async def advanced_title_search_generator(self, params: SearchParams, sha256: str) -> AsyncGenerator[TitleEdge, None]:
async def advanced_title_search_generator(self, params: SearchParams, sha256: str) -> AsyncGenerator[
TitleEdge, None]:
last_cursor = None
while True:
response = await self.async_advanced_title_search(params, sha256, last_cursor=last_cursor)