fix subscribe api

This commit is contained in:
jxxghp 2023-07-02 00:16:43 +08:00
parent 09c84d021d
commit 2590721b97
11 changed files with 137 additions and 55 deletions

View File

@ -1,4 +1,4 @@
from typing import List, Any from typing import List, Any, Union
from fastapi import APIRouter, Request, BackgroundTasks, Depends, HTTPException, Header from fastapi import APIRouter, Request, BackgroundTasks, Depends, HTTPException, Header
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@ -33,6 +33,25 @@ async def read_subscribes(
return Subscribe.list(db) return Subscribe.list(db)
@router.get("/{mediaid}", summary="查询订阅", response_model=schemas.Subscribe)
async def subscribe_info_by_id(
mediaid: str,
season: int,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据TMDBID或豆瓣ID查询订阅 tmdb:/douban:
"""
if mediaid.startswith("tmdb:"):
result = Subscribe.exists(db, int(mediaid[5:]), season)
elif mediaid.startswith("douban:"):
result = Subscribe.get_by_doubanid(db, mediaid[7:])
else:
result = None
return result if result else Subscribe()
@router.post("/", summary="新增订阅", response_model=schemas.Response) @router.post("/", summary="新增订阅", response_model=schemas.Response)
async def create_subscribe( async def create_subscribe(
*, *,
@ -42,8 +61,24 @@ async def create_subscribe(
""" """
新增订阅 新增订阅
""" """
result = SubscribeChain().add(**subscribe_in.dict()) # 类型转换
return schemas.Response(success=result) if subscribe_in.type:
mtype = MediaType.TV if subscribe_in.type == "电视剧" else MediaType.MOVIE
else:
mtype = None
# 标题转换
if subscribe_in.name:
title = subscribe_in.name
else:
title = None
result = SubscribeChain().add(mtype=mtype,
title=title,
year=subscribe_in.year,
tmdbid=subscribe_in.tmdbid,
season=subscribe_in.season,
doubanid=subscribe_in.doubanid,
exist_ok=True)
return schemas.Response(success=True if result else False, message=result)
@router.put("/", summary="更新订阅", response_model=schemas.Subscribe) @router.put("/", summary="更新订阅", response_model=schemas.Subscribe)
@ -79,6 +114,24 @@ async def delete_subscribe(
return schemas.Response(success=True) return schemas.Response(success=True)
@router.delete("/{mediaid}", summary="删除订阅", response_model=schemas.Response)
async def delete_subscribe_by_id(
mediaid: str,
season: int,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)
) -> Any:
"""
根据TMDBID或豆瓣ID删除订阅 tmdb:/douban:
"""
if mediaid.startswith("tmdb:"):
Subscribe().delete_by_tmdbid(db, int(mediaid[5:]), season)
elif mediaid.startswith("douban:"):
Subscribe().delete_by_doubanid(db, mediaid[7:])
return schemas.Response(success=True)
@router.post("/seerr", summary="OverSeerr/JellySeerr通知订阅", response_model=schemas.Response) @router.post("/seerr", summary="OverSeerr/JellySeerr通知订阅", response_model=schemas.Response)
async def seerr_subscribe(request: Request, background_tasks: BackgroundTasks, async def seerr_subscribe(request: Request, background_tasks: BackgroundTasks,
authorization: str = Header(None)) -> Any: authorization: str = Header(None)) -> Any:

View File

@ -34,6 +34,7 @@ class SubscribeChain(ChainBase):
def add(self, title: str, year: str, def add(self, title: str, year: str,
mtype: MediaType = None, mtype: MediaType = None,
tmdbid: int = None, tmdbid: int = None,
doubanid: str = None,
season: int = None, season: int = None,
userid: str = None, userid: str = None,
username: str = None, username: str = None,
@ -60,7 +61,7 @@ class SubscribeChain(ChainBase):
mediainfo: MediaInfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid) mediainfo: MediaInfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid)
if not mediainfo: if not mediainfo:
logger.warn(f'未识别到媒体信息,标题:{title}tmdbid{tmdbid}') logger.warn(f'未识别到媒体信息,标题:{title}tmdbid{tmdbid}')
return False return 0
# 更新媒体图片 # 更新媒体图片
self.obtain_images(mediainfo=mediainfo) self.obtain_images(mediainfo=mediainfo)
# 总集数 # 总集数
@ -75,14 +76,14 @@ class SubscribeChain(ChainBase):
tmdbid=mediainfo.tmdb_id) tmdbid=mediainfo.tmdb_id)
if not mediainfo: if not mediainfo:
logger.error(f"媒体信息识别失败!") logger.error(f"媒体信息识别失败!")
return False return 0
if not mediainfo.seasons: if not mediainfo.seasons:
logger.error(f"媒体信息中没有季集信息,标题:{title}tmdbid{tmdbid}") logger.error(f"媒体信息中没有季集信息,标题:{title}tmdbid{tmdbid}")
return False return 0
total_episode = len(mediainfo.seasons.get(season) or []) total_episode = len(mediainfo.seasons.get(season) or [])
if not total_episode: if not total_episode:
logger.error(f'未获取到总集数,标题:{title}tmdbid{tmdbid}') logger.error(f'未获取到总集数,标题:{title}tmdbid{tmdbid}')
return False return 0
kwargs.update({ kwargs.update({
'total_episode': total_episode 'total_episode': total_episode
}) })
@ -92,7 +93,7 @@ class SubscribeChain(ChainBase):
'lack_episode': kwargs.get('total_episode') 'lack_episode': kwargs.get('total_episode')
}) })
# 添加订阅 # 添加订阅
sid, err_msg = self.subscribehelper.add(mediainfo, season=season, **kwargs) sid, err_msg = self.subscribehelper.add(mediainfo, doubanid=doubanid, season=season, **kwargs)
if not sid: if not sid:
logger.error(f'{mediainfo.title_year} {err_msg}') logger.error(f'{mediainfo.title_year} {err_msg}')
if not exist_ok: if not exist_ok:

View File

@ -109,6 +109,8 @@ class MediaInfo:
title: Optional[str] = None title: Optional[str] = None
# 年份 # 年份
year: Optional[str] = None year: Optional[str] = None
# 季
season: Optional[int] = None
# TMDB ID # TMDB ID
tmdb_id: Optional[int] = None tmdb_id: Optional[int] = None
# IMDB ID # IMDB ID
@ -334,7 +336,10 @@ class MediaInfo:
self.type = MediaType.MOVIE if info.get("type") == "movie" else MediaType.TV self.type = MediaType.MOVIE if info.get("type") == "movie" else MediaType.TV
# 标题 # 标题
if not self.title: if not self.title:
self.title = MetaInfo(info.get("title")).name self.title = info.get("title")
# 识别标题中的季
meta = MetaInfo(self.title)
self.season = meta.begin_season
# 原语种标题 # 原语种标题
if not self.original_title: if not self.original_title:
self.original_title = info.get("original_title") self.original_title = info.get("original_title")

View File

@ -2,6 +2,7 @@ from sqlalchemy import Column, Integer, String, Sequence
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.db.models import Base from app.db.models import Base
from app.schemas import MediaType
class Subscribe(Base): class Subscribe(Base):
@ -19,8 +20,8 @@ class Subscribe(Base):
keyword = Column(String) keyword = Column(String)
tmdbid = Column(Integer, index=True) tmdbid = Column(Integer, index=True)
imdbid = Column(String) imdbid = Column(String)
tvdbid = Column(Integer, index=True) tvdbid = Column(Integer)
doubanid = Column(String) doubanid = Column(String, index=True)
# 季号 # 季号
season = Column(Integer) season = Column(Integer)
# 海报 # 海报
@ -60,7 +61,10 @@ class Subscribe(Base):
return db.query(Subscribe).filter(Subscribe.state == state).all() return db.query(Subscribe).filter(Subscribe.state == state).all()
@staticmethod @staticmethod
def get_by_tmdbid(db: Session, tmdbid: int): def get_by_tmdbid(db: Session, tmdbid: int, season: int = None):
if season:
return db.query(Subscribe).filter(Subscribe.tmdbid == tmdbid,
Subscribe.season == season).all()
return db.query(Subscribe).filter(Subscribe.tmdbid == tmdbid).all() return db.query(Subscribe).filter(Subscribe.tmdbid == tmdbid).all()
@staticmethod @staticmethod
@ -68,5 +72,17 @@ class Subscribe(Base):
return db.query(Subscribe).filter(Subscribe.name == title).first() return db.query(Subscribe).filter(Subscribe.name == title).first()
@staticmethod @staticmethod
def get_by_tvdbid(db: Session, tvdbid: int): def get_by_doubanid(db: Session, doubanid: str):
return db.query(Subscribe).filter(Subscribe.tvdbid == tvdbid).first() return db.query(Subscribe).filter(Subscribe.doubanid == doubanid).first()
def delete_by_tmdbid(self, db: Session, tmdbid: int, season: int):
subscrbies = self.get_by_tmdbid(db, tmdbid, season)
for subscrbie in subscrbies:
subscrbie.delete(db, subscrbie.id)
return True
def delete_by_doubanid(self, db: Session, doubanid: str):
subscribe = self.get_by_doubanid(db, doubanid)
if subscribe:
subscribe.delete(db, subscribe.id)
return True

View File

@ -18,7 +18,8 @@ class SystemConfig(Base):
def get_by_key(db: Session, key: str): def get_by_key(db: Session, key: str):
return db.query(SystemConfig).filter(SystemConfig.key == key).first() return db.query(SystemConfig).filter(SystemConfig.key == key).first()
@staticmethod def delete_by_key(self, db: Session, key: str):
def delete_by_key(db: Session, key: str): systemconfig = self.get_by_key(db, key)
db.query(SystemConfig).filter(SystemConfig.key == key).delete() if systemconfig:
db.commit() systemconfig.delete(db, systemconfig.id)
return True

View File

@ -37,6 +37,8 @@ class User(Base):
def get_by_name(db: Session, name: str): def get_by_name(db: Session, name: str):
return db.query(User).filter(User.name == name).first() return db.query(User).filter(User.name == name).first()
@staticmethod def delete_by_name(self, db: Session, name: str):
def delete_by_name(db: Session, name: str): user = self.get_by_name(db, name)
return db.query(User).filter(User.name == name).delete() if user:
user.delete(db, user.id)
return True

View File

@ -14,22 +14,23 @@ class SubscribeOper(DbOper):
""" """
新增订阅 新增订阅
""" """
subscribe = Subscribe(name=mediainfo.title, subscribe = Subscribe.exists(self._db, tmdbid=mediainfo.tmdb_id, season=kwargs.get('season'))
year=mediainfo.year, if not subscribe:
type=mediainfo.type.value, subscribe = Subscribe(name=mediainfo.title,
tmdbid=mediainfo.tmdb_id, year=mediainfo.year,
imdbid=mediainfo.imdb_id, type=mediainfo.type.value,
tvdbid=mediainfo.tvdb_id, tmdbid=mediainfo.tmdb_id,
poster=mediainfo.get_poster_image(), imdbid=mediainfo.imdb_id,
backdrop=mediainfo.get_backdrop_image(), tvdbid=mediainfo.tvdb_id,
vote=mediainfo.vote_average, poster=mediainfo.get_poster_image(),
description=mediainfo.overview, backdrop=mediainfo.get_backdrop_image(),
**kwargs) vote=mediainfo.vote_average,
if not subscribe.exists(self._db, tmdbid=mediainfo.tmdb_id, season=kwargs.get('season')): description=mediainfo.overview,
**kwargs)
subscribe.create(self._db) subscribe.create(self._db)
return subscribe.id, "新增订阅成功" return subscribe.id, "新增订阅成功"
else: else:
return 0, "订阅已存在" return subscribe.id, "订阅已存在"
def get(self, sid: int) -> Subscribe: def get(self, sid: int) -> Subscribe:
""" """

View File

@ -583,6 +583,8 @@ class TheMovieDbModule(_ModuleBase):
images = self.tmdb.get_tv_images(mediainfo.tmdb_id, season=1) images = self.tmdb.get_tv_images(mediainfo.tmdb_id, season=1)
if not images: if not images:
return mediainfo return mediainfo
if isinstance(images, list):
images = images[0]
# 背景图 # 背景图
if not mediainfo.backdrop_path: if not mediainfo.backdrop_path:
backdrops = images.get("backdrops") backdrops = images.get("backdrops")

View File

@ -37,7 +37,6 @@ class Scheduler(metaclass=Singleton):
}) })
def __init__(self): def __init__(self):
return
# CookieCloud定时同步 # CookieCloud定时同步
if settings.COOKIECLOUD_INTERVAL: if settings.COOKIECLOUD_INTERVAL:
self._scheduler.add_job(CookieCloudChain().process, self._scheduler.add_job(CookieCloudChain().process,

View File

@ -56,6 +56,8 @@ class MediaInfo(BaseModel):
title: Optional[str] = None title: Optional[str] = None
# 年份 # 年份
year: Optional[str] = None year: Optional[str] = None
# 季
season: Optional[int] = None
# TMDB ID # TMDB ID
tmdb_id: Optional[int] = None tmdb_id: Optional[int] = None
# IMDB ID # IMDB ID

View File

@ -4,43 +4,43 @@ from pydantic import BaseModel
class Subscribe(BaseModel): class Subscribe(BaseModel):
id: Optional[int] id: Optional[int] = None
# 订阅名称 # 订阅名称
name: Optional[str] name: Optional[str] = None
# 订阅年份 # 订阅年份
year: Optional[str] year: Optional[str] = None
# 订阅类型 电影/电视剧 # 订阅类型 电影/电视剧
type: Optional[str] type: Optional[str] = None
# 搜索关键字 # 搜索关键字
keyword: Optional[str] keyword: Optional[str] = None
tmdbid: Optional[int] tmdbid: Optional[int] = None
doubanid: Optional[str] doubanid: Optional[str] = None
# 季号 # 季号
season: Optional[int] season: Optional[int] = None
# 海报 # 海报
poster: Optional[str] poster: Optional[str] = None
# 背景图 # 背景图
backdrop: Optional[str] backdrop: Optional[str] = None
# 评分 # 评分
vote: Optional[int] vote: Optional[int] = 0
# 描述 # 描述
description: Optional[str] description: Optional[str] = None
# 过滤规则 # 过滤规则
filter: Optional[str] filter: Optional[str] = None
# 包含 # 包含
include: Optional[str] include: Optional[str] = None
# 排除 # 排除
exclude: Optional[str] exclude: Optional[str] = None
# 总集数 # 总集数
total_episode: Optional[int] total_episode: Optional[int] = 0
# 开始集数 # 开始集数
start_episode: Optional[int] start_episode: Optional[int] = 0
# 缺失集数 # 缺失集数
lack_episode: Optional[int] lack_episode: Optional[int] = 0
# 附加信息 # 附加信息
note: Optional[str] note: Optional[str] = None
# 状态N-新建, R-订阅中 # 状态N-新建, R-订阅中
state: Optional[str] state: Optional[str] = None
class Config: class Config:
orm_mode = True orm_mode = True