From 0eb789f7112f147cee29410c287f52eedbb85d86 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 14 Jun 2023 15:27:54 +0800 Subject: [PATCH] fix arr api --- app/api/servarr.py | 186 ++++++++++++++++++++--------- app/chain/__init__.py | 2 +- app/chain/download.py | 3 +- app/chain/search.py | 3 +- app/chain/subscribe.py | 3 +- app/db/models/subscribe.py | 3 +- app/db/subscribes.py | 1 + app/modules/__init__.py | 2 +- app/modules/themoviedb/__init__.py | 19 ++- app/schemas/servarr.py | 7 +- 10 files changed, 157 insertions(+), 72 deletions(-) diff --git a/app/api/servarr.py b/app/api/servarr.py index 1b815bb2..7b127acc 100644 --- a/app/api/servarr.py +++ b/app/api/servarr.py @@ -1,3 +1,4 @@ +from pathlib import Path from typing import Any, List from fastapi import APIRouter, HTTPException, Depends @@ -7,6 +8,7 @@ from app import schemas from app.chain.identify import IdentifyChain from app.chain.subscribe import SubscribeChain from app.core.config import settings +from app.core.metainfo import MetaInfo from app.db import get_db from app.db.models.subscribe import Subscribe from app.schemas import RadarrMovie, SonarrSeries @@ -206,12 +208,14 @@ async def arr_movies(apikey: str, db: Session = Depends(get_db)) -> Any: result.append(RadarrMovie( id=subscribe.id, title=subscribe.name, + year=subscribe.year, isAvailable=True, monitored=True, tmdbId=subscribe.tmdbid, + imdbId=subscribe.imdbid, profileId=1, qualityProfileId=1, - hasFile=False, + hasFile=False )) return result @@ -228,26 +232,49 @@ async def arr_movie_lookup(apikey: str, term: str, db: Session = Depends(get_db) detail="认证失败!", ) tmdbid = term.replace("tmdb:", "") - subscribe = Subscribe.get_by_tmdbid(db, int(tmdbid)) - if subscribe: - return [RadarrMovie( - id=subscribe.id, - title=subscribe.name, - isAvailable=True, - monitored=True, - tmdbId=subscribe.tmdbid, - profileId=1, - qualityProfileId=1, - hasFile=False, - )] - else: + # 查询媒体信息 + mediainfo = IdentifyChain().recognize_media(mtype=MediaType.MOVIE, tmdbid=int(tmdbid)) + if not mediainfo: return [RadarrMovie()] + # 查询是否已存在 + exists = IdentifyChain().media_exists(mediainfo=mediainfo) + if not exists: + # 文件不存在 + hasfile = False + else: + # 文件存在 + hasfile = True + # 查询是否已订阅 + subscribes = Subscribe.get_by_tmdbid(db, int(tmdbid)) + if subscribes: + # 订阅ID + subid = subscribes[0].id + # 已订阅 + monitored = True + else: + subid = None + monitored = False + + return [RadarrMovie( + id=subid, + title=mediainfo.title, + year=mediainfo.year, + isAvailable=True, + monitored=monitored, + tmdbId=mediainfo.tmdb_id, + imdbId=mediainfo.imdb_id, + titleSlug=mediainfo.original_title, + folderName=mediainfo.title_year, + profileId=1, + qualityProfileId=1, + hasFile=hasfile + )] @arr_router.get("/movie/{mid}", response_model=schemas.RadarrMovie) async def arr_movie(apikey: str, mid: int, db: Session = Depends(get_db)) -> Any: """ - 查询Rardar电影 + 查询Rardar电影订阅 """ if not apikey or apikey != settings.API_TOKEN: raise HTTPException( @@ -259,12 +286,14 @@ async def arr_movie(apikey: str, mid: int, db: Session = Depends(get_db)) -> Any return RadarrMovie( id=subscribe.id, title=subscribe.name, + year=subscribe.year, isAvailable=True, monitored=True, tmdbId=subscribe.tmdbid, + imdbId=subscribe.imdbid, profileId=1, qualityProfileId=1, - hasFile=False, + hasFile=False ) else: raise HTTPException( @@ -284,7 +313,7 @@ async def arr_add_movie(apikey: str, movie: RadarrMovie) -> Any: detail="认证失败!", ) sid = SubscribeChain().process(title=movie.title, - year=str(movie.year) if movie.year else None, + year=movie.year, mtype=MediaType.MOVIE, tmdbid=movie.tmdbId, userid="Seerr") @@ -446,14 +475,17 @@ async def arr_series(apikey: str, db: Session = Depends(get_db)) -> Any: "seasonNumber": subscribe.season, "monitored": True, }], + remotePoster=subscribe.image, year=subscribe.year, - isAvailable=True, - monitored=True, tmdbId=subscribe.tmdbid, + tvdbId=subscribe.tvdbid, + imdbId=subscribe.imdbid, profileId=1, languageProfileId=1, qualityProfileId=1, - hasFile=False, + isAvailable=True, + monitored=True, + hasFile=False )) return result @@ -468,38 +500,81 @@ async def arr_series_lookup(apikey: str, term: str, db: Session = Depends(get_db status_code=403, detail="认证失败!", ) - # 季列表 - seasons = [] + # 查询TMDB媒体信息 if not term.startswith("tvdb:"): - title = term - subscribe = Subscribe.get_by_title(db, title) + mediainfo = IdentifyChain().recognize_media(meta=MetaInfo(term), + mtype=MediaType.MOVIE) + if not mediainfo: + return [SonarrSeries()] + tvdbid = mediainfo.tvdb_id + tmdbid = mediainfo.tmdb_id else: - tmdbid = term.replace("tvdb:", "") - subscribe = Subscribe.get_by_tmdbid(db, int(tmdbid)) - if not subscribe: - # 查询TMDB季信息 - tmdbinfo = IdentifyChain().tvdb_info(tvdbid=int(tmdbid)) - if tmdbinfo: - season_num = tmdbinfo.get('season') - if season_num: - seasons = [{"seasonNumber": sea} for sea in range(1, int(season_num) + 1)] - if subscribe: - return [SonarrSeries( - id=subscribe.id, - title=subscribe.name, - seasonCount=1, - seasons=[{"seasonNumber": subscribe.season}], - year=subscribe.year, - isAvailable=True, - monitored=True, - tvdbId=subscribe.tvdbid, - profileId=1, - languageProfileId=1, - qualityProfileId=1, - hasFile=False, - )] + tvdbid = int(term.replace("tvdb:", "")) + mediainfo = IdentifyChain().recognize_media(mtype=MediaType.MOVIE, + tmdbid=tvdbid) + if not mediainfo: + return [SonarrSeries()] + tmdbid = mediainfo.tmdb_id + # 查询TVDB季信息 + seas: List[int] = [] + if tvdbid: + tvdbinfo = IdentifyChain().tvdb_info(tvdbid=tvdbid) + if tvdbinfo: + sea_num = tvdbinfo.get('season') + if sea_num: + seas = list(range(1, int(sea_num) + 1)) + # 查询是否存在 + exists = IdentifyChain().media_exists(mediainfo) + if exists: + hasfile = True else: - return [SonarrSeries(seasons=seasons)] + hasfile = False + # 查询订阅信息 + seasons: List[dict] = [] + subscribes = Subscribe.get_by_tmdbid(db, tmdbid) + if subscribes: + # 已监控 + monitored = True + # 已监控季 + sub_seas = [sub.season for sub in subscribes] + for sea in seas: + if sea in sub_seas: + seasons.append({ + "seasonNumber": sea, + "monitored": True, + }) + else: + seasons.append({ + "seasonNumber": sea, + "monitored": False, + }) + subid = subscribes[-1].id + else: + subid = None + monitored = False + for sea in seas: + seasons.append({ + "seasonNumber": sea, + "monitored": False, + }) + + return [SonarrSeries( + id=subid, + title=mediainfo.title, + seasonCount=len(seasons), + seasons=seasons, + remotePoster=mediainfo.get_poster_image(), + year=mediainfo.year, + tmdbId=mediainfo.tmdb_id, + tvdbId=mediainfo.tvdb_id, + imdbId=mediainfo.imdb_id, + profileId=1, + languageProfileId=1, + qualityProfileId=1, + isAvailable=True, + monitored=monitored, + hasFile=hasfile + )] @arr_router.get("/series/{tid}") @@ -523,14 +598,16 @@ async def arr_serie(apikey: str, tid: int, db: Session = Depends(get_db)) -> Any "monitored": True, }], year=subscribe.year, - isAvailable=True, - monitored=True, + remotePoster=subscribe.image, + tmdbId=subscribe.tmdbid, tvdbId=subscribe.tvdbid, + imdbId=subscribe.imdbid, profileId=1, languageProfileId=1, qualityProfileId=1, - added=True, - hasFile=False, + isAvailable=True, + monitored=True, + hasFile=False ) else: raise HTTPException( @@ -554,8 +631,9 @@ async def arr_add_series(apikey: str, tv: schemas.SonarrSeries) -> Any: if not season.get("monitored"): continue sid = SubscribeChain().process(title=tv.title, - year=str(tv.year) if tv.year else None, + year=tv.year, season=season.get("seasonNumber"), + tmdbid=tv.tmdbId, mtype=MediaType.TV, userid="Seerr") diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 22175458..85884b0c 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -69,7 +69,7 @@ class ChainBase(AbstractSingleton, metaclass=Singleton): subtitle: str = None) -> Tuple[str, str]: return self.run_module("prepare_recognize", title=title, subtitle=subtitle) - def recognize_media(self, meta: MetaBase, + def recognize_media(self, meta: MetaBase = None, mtype: MediaType = None, tmdbid: int = None) -> Optional[MediaInfo]: return self.run_module("recognize_media", meta=meta, mtype=mtype, tmdbid=tmdbid) diff --git a/app/chain/download.py b/app/chain/download.py index 1a0646af..495ba24c 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -382,8 +382,7 @@ class DownloadChain(ChainBase): else: if not mediainfo.seasons: # 补充媒体信息 - mediainfo: MediaInfo = self.recognize_media(meta=MetaInfo(title=mediainfo.title_year), - mtype=mediainfo.type, + mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type, tmdbid=mediainfo.tmdb_id) if not mediainfo: logger.error(f"媒体信息识别失败!") diff --git a/app/chain/search.py b/app/chain/search.py index f1386615..c48770b3 100644 --- a/app/chain/search.py +++ b/app/chain/search.py @@ -48,8 +48,7 @@ class SearchChain(ChainBase): return [] # 补充媒体信息 if not mediainfo.names: - mediainfo: MediaInfo = self.recognize_media(meta=meta, - mtype=mediainfo.type, + mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type, tmdbid=mediainfo.tmdb_id) if not mediainfo: logger.error(f'媒体信息识别失败!') diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index d196d25f..a319ebf3 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -67,8 +67,7 @@ class SubscribeChain(ChainBase): if not kwargs.get('total_episode'): if not mediainfo.seasons: # 补充媒体信息 - mediainfo: MediaInfo = self.recognize_media(meta=metainfo, - mtype=mediainfo.type, + mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type, tmdbid=mediainfo.tmdb_id) if not mediainfo: logger.error(f"媒体信息识别失败!") diff --git a/app/db/models/subscribe.py b/app/db/models/subscribe.py index ac16e6c5..02961917 100644 --- a/app/db/models/subscribe.py +++ b/app/db/models/subscribe.py @@ -14,6 +14,7 @@ class Subscribe(Base): type = Column(String) keyword = Column(String) tmdbid = Column(Integer, index=True) + imdbid = Column(String) tvdbid = Column(Integer, index=True) doubanid = Column(String) season = Column(Integer) @@ -41,7 +42,7 @@ class Subscribe(Base): @staticmethod def get_by_tmdbid(db: Session, tmdbid: int): - return db.query(Subscribe).filter(Subscribe.tmdbid == tmdbid).first() + return db.query(Subscribe).filter(Subscribe.tmdbid == tmdbid).all() @staticmethod def get_by_title(db: Session, title: str): diff --git a/app/db/subscribes.py b/app/db/subscribes.py index 18998aad..5229830c 100644 --- a/app/db/subscribes.py +++ b/app/db/subscribes.py @@ -24,6 +24,7 @@ class Subscribes: year=mediainfo.year, type=mediainfo.type.value, tmdbid=mediainfo.tmdb_id, + imdbid=mediainfo.imdb_id, tvdbid=mediainfo.tvdb_id, image=mediainfo.get_poster_image(), description=mediainfo.overview, diff --git a/app/modules/__init__.py b/app/modules/__init__.py index f86ed846..4c4057b0 100644 --- a/app/modules/__init__.py +++ b/app/modules/__init__.py @@ -40,7 +40,7 @@ class _ModuleBase(metaclass=ABCMeta): """ pass - def recognize_media(self, meta: MetaBase, + def recognize_media(self, meta: MetaBase = None, mtype: MediaType = None, tmdbid: int = None) -> Optional[MediaInfo]: """ diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index 126c70e6..1663cd68 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -41,7 +41,7 @@ class TheMovieDbModule(_ModuleBase): def init_setting(self) -> Tuple[str, Union[str, bool]]: pass - def recognize_media(self, meta: MetaBase, + def recognize_media(self, meta: MetaBase = None, mtype: MediaType = None, tmdbid: int = None) -> Optional[MediaInfo]: """ @@ -52,14 +52,17 @@ class TheMovieDbModule(_ModuleBase): :return: 识别的媒体信息,包括剧集信息 """ if not meta: - return None - cache_info = self.cache.get(meta) - if not cache_info or tmdbid: + cache_info = {} + else: + if mtype: + meta.type = mtype + cache_info = self.cache.get(meta) + if not cache_info: # 缓存没有或者强制不使用缓存 if tmdbid: # 直接查询详情 info = self.tmdb.get_info(mtype=mtype, tmdbid=tmdbid) - else: + elif meta: logger.info(f"正在识别 {meta.name} ...") if meta.type == MediaType.UNKNOWN and not meta.year: info = self.tmdb.match_multi(meta.name) @@ -97,8 +100,12 @@ class TheMovieDbModule(_ModuleBase): if info and not info.get("genres"): info = self.tmdb.get_info(mtype=info.get("media_type"), tmdbid=info.get("id")) + else: + logger.error("识别媒体信息时未提供元数据或tmdbid") + return None # 保存到缓存 - self.cache.update(meta, info) + if meta: + self.cache.update(meta, info) else: # 使用缓存信息 if cache_info.get("title"): diff --git a/app/schemas/servarr.py b/app/schemas/servarr.py index 50bd35db..a4530e23 100644 --- a/app/schemas/servarr.py +++ b/app/schemas/servarr.py @@ -5,7 +5,7 @@ from pydantic import BaseModel class RadarrMovie(BaseModel): id: Optional[int] title: Optional[str] - year: Optional[int] + year: Optional[str] isAvailable: bool = False monitored: bool = False tmdbId: Optional[int] @@ -31,7 +31,7 @@ class SonarrSeries(BaseModel): images: list = [] remotePoster: Optional[str] seasons: list = [] - year: Optional[int] + year: Optional[str] path: Optional[str] profileId: Optional[int] languageProfileId: Optional[int] @@ -39,13 +39,14 @@ class SonarrSeries(BaseModel): monitored: bool = False useSceneNumbering: bool = False runtime: Optional[int] + tmdbId: Optional[int] + imdbId: Optional[str] tvdbId: Optional[int] tvRageId: Optional[int] tvMazeId: Optional[int] firstAired: Optional[str] seriesType: Optional[str] cleanTitle: Optional[str] - imdbId: Optional[str] titleSlug: Optional[str] certification: Optional[str] genres: list = []