fix arr api

This commit is contained in:
jxxghp 2023-06-14 15:27:54 +08:00
parent b18d6cabd9
commit 0eb789f711
10 changed files with 157 additions and 72 deletions

View File

@ -1,3 +1,4 @@
from pathlib import Path
from typing import Any, List from typing import Any, List
from fastapi import APIRouter, HTTPException, Depends from fastapi import APIRouter, HTTPException, Depends
@ -7,6 +8,7 @@ from app import schemas
from app.chain.identify import IdentifyChain from app.chain.identify import IdentifyChain
from app.chain.subscribe import SubscribeChain from app.chain.subscribe import SubscribeChain
from app.core.config import settings from app.core.config import settings
from app.core.metainfo import MetaInfo
from app.db import get_db from app.db import get_db
from app.db.models.subscribe import Subscribe from app.db.models.subscribe import Subscribe
from app.schemas import RadarrMovie, SonarrSeries 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( result.append(RadarrMovie(
id=subscribe.id, id=subscribe.id,
title=subscribe.name, title=subscribe.name,
year=subscribe.year,
isAvailable=True, isAvailable=True,
monitored=True, monitored=True,
tmdbId=subscribe.tmdbid, tmdbId=subscribe.tmdbid,
imdbId=subscribe.imdbid,
profileId=1, profileId=1,
qualityProfileId=1, qualityProfileId=1,
hasFile=False, hasFile=False
)) ))
return result return result
@ -228,26 +232,49 @@ async def arr_movie_lookup(apikey: str, term: str, db: Session = Depends(get_db)
detail="认证失败!", detail="认证失败!",
) )
tmdbid = term.replace("tmdb:", "") tmdbid = term.replace("tmdb:", "")
subscribe = Subscribe.get_by_tmdbid(db, int(tmdbid)) # 查询媒体信息
if subscribe: mediainfo = IdentifyChain().recognize_media(mtype=MediaType.MOVIE, tmdbid=int(tmdbid))
return [RadarrMovie( if not mediainfo:
id=subscribe.id,
title=subscribe.name,
isAvailable=True,
monitored=True,
tmdbId=subscribe.tmdbid,
profileId=1,
qualityProfileId=1,
hasFile=False,
)]
else:
return [RadarrMovie()] 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) @arr_router.get("/movie/{mid}", response_model=schemas.RadarrMovie)
async def arr_movie(apikey: str, mid: int, db: Session = Depends(get_db)) -> Any: async def arr_movie(apikey: str, mid: int, db: Session = Depends(get_db)) -> Any:
""" """
查询Rardar电影 查询Rardar电影订阅
""" """
if not apikey or apikey != settings.API_TOKEN: if not apikey or apikey != settings.API_TOKEN:
raise HTTPException( raise HTTPException(
@ -259,12 +286,14 @@ async def arr_movie(apikey: str, mid: int, db: Session = Depends(get_db)) -> Any
return RadarrMovie( return RadarrMovie(
id=subscribe.id, id=subscribe.id,
title=subscribe.name, title=subscribe.name,
year=subscribe.year,
isAvailable=True, isAvailable=True,
monitored=True, monitored=True,
tmdbId=subscribe.tmdbid, tmdbId=subscribe.tmdbid,
imdbId=subscribe.imdbid,
profileId=1, profileId=1,
qualityProfileId=1, qualityProfileId=1,
hasFile=False, hasFile=False
) )
else: else:
raise HTTPException( raise HTTPException(
@ -284,7 +313,7 @@ async def arr_add_movie(apikey: str, movie: RadarrMovie) -> Any:
detail="认证失败!", detail="认证失败!",
) )
sid = SubscribeChain().process(title=movie.title, sid = SubscribeChain().process(title=movie.title,
year=str(movie.year) if movie.year else None, year=movie.year,
mtype=MediaType.MOVIE, mtype=MediaType.MOVIE,
tmdbid=movie.tmdbId, tmdbid=movie.tmdbId,
userid="Seerr") userid="Seerr")
@ -446,14 +475,17 @@ async def arr_series(apikey: str, db: Session = Depends(get_db)) -> Any:
"seasonNumber": subscribe.season, "seasonNumber": subscribe.season,
"monitored": True, "monitored": True,
}], }],
remotePoster=subscribe.image,
year=subscribe.year, year=subscribe.year,
isAvailable=True,
monitored=True,
tmdbId=subscribe.tmdbid, tmdbId=subscribe.tmdbid,
tvdbId=subscribe.tvdbid,
imdbId=subscribe.imdbid,
profileId=1, profileId=1,
languageProfileId=1, languageProfileId=1,
qualityProfileId=1, qualityProfileId=1,
hasFile=False, isAvailable=True,
monitored=True,
hasFile=False
)) ))
return result return result
@ -468,38 +500,81 @@ async def arr_series_lookup(apikey: str, term: str, db: Session = Depends(get_db
status_code=403, status_code=403,
detail="认证失败!", detail="认证失败!",
) )
# 季列表 # 查询TMDB媒体信息
seasons = []
if not term.startswith("tvdb:"): if not term.startswith("tvdb:"):
title = term mediainfo = IdentifyChain().recognize_media(meta=MetaInfo(term),
subscribe = Subscribe.get_by_title(db, title) mtype=MediaType.MOVIE)
if not mediainfo:
return [SonarrSeries()]
tvdbid = mediainfo.tvdb_id
tmdbid = mediainfo.tmdb_id
else: else:
tmdbid = term.replace("tvdb:", "") tvdbid = int(term.replace("tvdb:", ""))
subscribe = Subscribe.get_by_tmdbid(db, int(tmdbid)) mediainfo = IdentifyChain().recognize_media(mtype=MediaType.MOVIE,
if not subscribe: tmdbid=tvdbid)
# 查询TMDB季信息 if not mediainfo:
tmdbinfo = IdentifyChain().tvdb_info(tvdbid=int(tmdbid)) return [SonarrSeries()]
if tmdbinfo: tmdbid = mediainfo.tmdb_id
season_num = tmdbinfo.get('season') # 查询TVDB季信息
if season_num: seas: List[int] = []
seasons = [{"seasonNumber": sea} for sea in range(1, int(season_num) + 1)] if tvdbid:
if subscribe: tvdbinfo = IdentifyChain().tvdb_info(tvdbid=tvdbid)
return [SonarrSeries( if tvdbinfo:
id=subscribe.id, sea_num = tvdbinfo.get('season')
title=subscribe.name, if sea_num:
seasonCount=1, seas = list(range(1, int(sea_num) + 1))
seasons=[{"seasonNumber": subscribe.season}], # 查询是否存在
year=subscribe.year, exists = IdentifyChain().media_exists(mediainfo)
isAvailable=True, if exists:
monitored=True, hasfile = True
tvdbId=subscribe.tvdbid,
profileId=1,
languageProfileId=1,
qualityProfileId=1,
hasFile=False,
)]
else: 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}") @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, "monitored": True,
}], }],
year=subscribe.year, year=subscribe.year,
isAvailable=True, remotePoster=subscribe.image,
monitored=True, tmdbId=subscribe.tmdbid,
tvdbId=subscribe.tvdbid, tvdbId=subscribe.tvdbid,
imdbId=subscribe.imdbid,
profileId=1, profileId=1,
languageProfileId=1, languageProfileId=1,
qualityProfileId=1, qualityProfileId=1,
added=True, isAvailable=True,
hasFile=False, monitored=True,
hasFile=False
) )
else: else:
raise HTTPException( raise HTTPException(
@ -554,8 +631,9 @@ async def arr_add_series(apikey: str, tv: schemas.SonarrSeries) -> Any:
if not season.get("monitored"): if not season.get("monitored"):
continue continue
sid = SubscribeChain().process(title=tv.title, sid = SubscribeChain().process(title=tv.title,
year=str(tv.year) if tv.year else None, year=tv.year,
season=season.get("seasonNumber"), season=season.get("seasonNumber"),
tmdbid=tv.tmdbId,
mtype=MediaType.TV, mtype=MediaType.TV,
userid="Seerr") userid="Seerr")

View File

@ -69,7 +69,7 @@ class ChainBase(AbstractSingleton, metaclass=Singleton):
subtitle: str = None) -> Tuple[str, str]: subtitle: str = None) -> Tuple[str, str]:
return self.run_module("prepare_recognize", title=title, subtitle=subtitle) 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, mtype: MediaType = None,
tmdbid: int = None) -> Optional[MediaInfo]: tmdbid: int = None) -> Optional[MediaInfo]:
return self.run_module("recognize_media", meta=meta, mtype=mtype, tmdbid=tmdbid) return self.run_module("recognize_media", meta=meta, mtype=mtype, tmdbid=tmdbid)

View File

@ -382,8 +382,7 @@ class DownloadChain(ChainBase):
else: else:
if not mediainfo.seasons: if not mediainfo.seasons:
# 补充媒体信息 # 补充媒体信息
mediainfo: MediaInfo = self.recognize_media(meta=MetaInfo(title=mediainfo.title_year), mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type,
mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id) tmdbid=mediainfo.tmdb_id)
if not mediainfo: if not mediainfo:
logger.error(f"媒体信息识别失败!") logger.error(f"媒体信息识别失败!")

View File

@ -48,8 +48,7 @@ class SearchChain(ChainBase):
return [] return []
# 补充媒体信息 # 补充媒体信息
if not mediainfo.names: if not mediainfo.names:
mediainfo: MediaInfo = self.recognize_media(meta=meta, mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type,
mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id) tmdbid=mediainfo.tmdb_id)
if not mediainfo: if not mediainfo:
logger.error(f'媒体信息识别失败!') logger.error(f'媒体信息识别失败!')

View File

@ -67,8 +67,7 @@ class SubscribeChain(ChainBase):
if not kwargs.get('total_episode'): if not kwargs.get('total_episode'):
if not mediainfo.seasons: if not mediainfo.seasons:
# 补充媒体信息 # 补充媒体信息
mediainfo: MediaInfo = self.recognize_media(meta=metainfo, mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type,
mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id) tmdbid=mediainfo.tmdb_id)
if not mediainfo: if not mediainfo:
logger.error(f"媒体信息识别失败!") logger.error(f"媒体信息识别失败!")

View File

@ -14,6 +14,7 @@ class Subscribe(Base):
type = Column(String) type = Column(String)
keyword = Column(String) keyword = Column(String)
tmdbid = Column(Integer, index=True) tmdbid = Column(Integer, index=True)
imdbid = Column(String)
tvdbid = Column(Integer, index=True) tvdbid = Column(Integer, index=True)
doubanid = Column(String) doubanid = Column(String)
season = Column(Integer) season = Column(Integer)
@ -41,7 +42,7 @@ class Subscribe(Base):
@staticmethod @staticmethod
def get_by_tmdbid(db: Session, tmdbid: int): 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 @staticmethod
def get_by_title(db: Session, title: str): def get_by_title(db: Session, title: str):

View File

@ -24,6 +24,7 @@ class Subscribes:
year=mediainfo.year, year=mediainfo.year,
type=mediainfo.type.value, type=mediainfo.type.value,
tmdbid=mediainfo.tmdb_id, tmdbid=mediainfo.tmdb_id,
imdbid=mediainfo.imdb_id,
tvdbid=mediainfo.tvdb_id, tvdbid=mediainfo.tvdb_id,
image=mediainfo.get_poster_image(), image=mediainfo.get_poster_image(),
description=mediainfo.overview, description=mediainfo.overview,

View File

@ -40,7 +40,7 @@ class _ModuleBase(metaclass=ABCMeta):
""" """
pass pass
def recognize_media(self, meta: MetaBase, def recognize_media(self, meta: MetaBase = None,
mtype: MediaType = None, mtype: MediaType = None,
tmdbid: int = None) -> Optional[MediaInfo]: tmdbid: int = None) -> Optional[MediaInfo]:
""" """

View File

@ -41,7 +41,7 @@ class TheMovieDbModule(_ModuleBase):
def init_setting(self) -> Tuple[str, Union[str, bool]]: def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass pass
def recognize_media(self, meta: MetaBase, def recognize_media(self, meta: MetaBase = None,
mtype: MediaType = None, mtype: MediaType = None,
tmdbid: int = None) -> Optional[MediaInfo]: tmdbid: int = None) -> Optional[MediaInfo]:
""" """
@ -52,14 +52,17 @@ class TheMovieDbModule(_ModuleBase):
:return: 识别的媒体信息包括剧集信息 :return: 识别的媒体信息包括剧集信息
""" """
if not meta: if not meta:
return None cache_info = {}
cache_info = self.cache.get(meta) else:
if not cache_info or tmdbid: if mtype:
meta.type = mtype
cache_info = self.cache.get(meta)
if not cache_info:
# 缓存没有或者强制不使用缓存 # 缓存没有或者强制不使用缓存
if tmdbid: if tmdbid:
# 直接查询详情 # 直接查询详情
info = self.tmdb.get_info(mtype=mtype, tmdbid=tmdbid) info = self.tmdb.get_info(mtype=mtype, tmdbid=tmdbid)
else: elif meta:
logger.info(f"正在识别 {meta.name} ...") logger.info(f"正在识别 {meta.name} ...")
if meta.type == MediaType.UNKNOWN and not meta.year: if meta.type == MediaType.UNKNOWN and not meta.year:
info = self.tmdb.match_multi(meta.name) info = self.tmdb.match_multi(meta.name)
@ -97,8 +100,12 @@ class TheMovieDbModule(_ModuleBase):
if info and not info.get("genres"): if info and not info.get("genres"):
info = self.tmdb.get_info(mtype=info.get("media_type"), info = self.tmdb.get_info(mtype=info.get("media_type"),
tmdbid=info.get("id")) tmdbid=info.get("id"))
else:
logger.error("识别媒体信息时未提供元数据或tmdbid")
return None
# 保存到缓存 # 保存到缓存
self.cache.update(meta, info) if meta:
self.cache.update(meta, info)
else: else:
# 使用缓存信息 # 使用缓存信息
if cache_info.get("title"): if cache_info.get("title"):

View File

@ -5,7 +5,7 @@ from pydantic import BaseModel
class RadarrMovie(BaseModel): class RadarrMovie(BaseModel):
id: Optional[int] id: Optional[int]
title: Optional[str] title: Optional[str]
year: Optional[int] year: Optional[str]
isAvailable: bool = False isAvailable: bool = False
monitored: bool = False monitored: bool = False
tmdbId: Optional[int] tmdbId: Optional[int]
@ -31,7 +31,7 @@ class SonarrSeries(BaseModel):
images: list = [] images: list = []
remotePoster: Optional[str] remotePoster: Optional[str]
seasons: list = [] seasons: list = []
year: Optional[int] year: Optional[str]
path: Optional[str] path: Optional[str]
profileId: Optional[int] profileId: Optional[int]
languageProfileId: Optional[int] languageProfileId: Optional[int]
@ -39,13 +39,14 @@ class SonarrSeries(BaseModel):
monitored: bool = False monitored: bool = False
useSceneNumbering: bool = False useSceneNumbering: bool = False
runtime: Optional[int] runtime: Optional[int]
tmdbId: Optional[int]
imdbId: Optional[str]
tvdbId: Optional[int] tvdbId: Optional[int]
tvRageId: Optional[int] tvRageId: Optional[int]
tvMazeId: Optional[int] tvMazeId: Optional[int]
firstAired: Optional[str] firstAired: Optional[str]
seriesType: Optional[str] seriesType: Optional[str]
cleanTitle: Optional[str] cleanTitle: Optional[str]
imdbId: Optional[str]
titleSlug: Optional[str] titleSlug: Optional[str]
certification: Optional[str] certification: Optional[str]
genres: list = [] genres: list = []