This commit is contained in:
jxxghp 2023-08-09 08:29:59 +08:00
parent 293b992ac0
commit d16c7b3133
4 changed files with 123 additions and 5 deletions

View File

@ -1,5 +1,7 @@
import json
import re import re
import time import time
from typing import Tuple, Optional
from app.chain import ChainBase from app.chain import ChainBase
from app.chain.download import DownloadChain from app.chain.download import DownloadChain
@ -11,7 +13,7 @@ from app.db.systemconfig_oper import SystemConfigOper
from app.helper.rss import RssHelper from app.helper.rss import RssHelper
from app.helper.sites import SitesHelper from app.helper.sites import SitesHelper
from app.log import logger from app.log import logger
from app.schemas import Notification from app.schemas import Notification, NotExistMediaInfo
from app.schemas.types import SystemConfigKey, MediaType, NotificationType from app.schemas.types import SystemConfigKey, MediaType, NotificationType
from app.utils.string import StringUtils from app.utils.string import StringUtils
@ -28,6 +30,73 @@ class RssChain(ChainBase):
self.systemconfig = SystemConfigOper() self.systemconfig = SystemConfigOper()
self.downloadchain = DownloadChain() self.downloadchain = DownloadChain()
def add(self, title: str, year: str,
mtype: MediaType = None,
season: int = None,
**kwargs) -> Tuple[Optional[int], str]:
"""
识别媒体信息并添加订阅
"""
logger.info(f'开始添加自定义订阅,标题:{title} ...')
# 识别元数据
metainfo = MetaInfo(title)
if year:
metainfo.year = year
if mtype:
metainfo.type = mtype
if season:
metainfo.type = MediaType.TV
metainfo.begin_season = season
# 识别媒体信息
mediainfo: MediaInfo = self.recognize_media(meta=metainfo)
if not mediainfo:
logger.warn(f'{title} 未识别到媒体信息')
return None, "未识别到媒体信息"
# 更新媒体图片
self.obtain_images(mediainfo=mediainfo)
# 总集数
if mediainfo.type == MediaType.TV:
if not season:
season = 1
# 总集数
if not kwargs.get('total_episode'):
if not mediainfo.seasons:
# 补充媒体信息
mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id)
if not mediainfo:
logger.error(f"媒体信息识别失败!")
return None, "媒体信息识别失败"
if not mediainfo.seasons:
logger.error(f"{title} 媒体信息中没有季集信息")
return None, "媒体信息中没有季集信息"
total_episode = len(mediainfo.seasons.get(season) or [])
if not total_episode:
logger.error(f'{title} 未获取到总集数')
return None, "未获取到总集数"
kwargs.update({
'total_episode': total_episode
})
# 添加订阅
sid = self.rssoper.add(title=mediainfo.title,
year=mediainfo.year,
mtype=mediainfo.type.value,
season=season,
tmdbid=mediainfo.tmdb_id,
poster=mediainfo.get_poster_image(),
backdrop=mediainfo.get_backdrop_image(),
vote=mediainfo.vote_average,
description=mediainfo.overview,
**kwargs)
if not sid:
logger.error(f'{mediainfo.title_year} 添加自定义订阅失败')
return None, "添加自定义订阅失败"
else:
logger.info(f'{mediainfo.title_year}{metainfo.season} 添加订阅成功')
# 返回结果
return sid, ""
def refresh(self): def refresh(self):
""" """
刷新RSS订阅数据 刷新RSS订阅数据
@ -56,9 +125,18 @@ class RssChain(ChainBase):
filter_rule = self.systemconfig.get(SystemConfigKey.FilterRules) filter_rule = self.systemconfig.get(SystemConfigKey.FilterRules)
# 处理RSS条目 # 处理RSS条目
matched_contexts = [] matched_contexts = []
# 处理过的title
processed_data = json.loads(rss_task.note) if rss_task.note else {
"titles": [],
"season_episodes": []
}
for item in items: for item in items:
if not item.get("title"): if not item.get("title"):
continue continue
# 标题是否已处理过
if item.get("title") in processed_data.get('titles'):
logger.info(f"{item.get('title')} 已处理过")
continue
# 基本要素匹配 # 基本要素匹配
if rss_task.include \ if rss_task.include \
and not re.search(r"%s" % rss_task.include, item.get("title")): and not re.search(r"%s" % rss_task.include, item.get("title")):
@ -80,6 +158,10 @@ class RssChain(ChainBase):
if mediainfo.tmdb_id != rss_task.tmdbid: if mediainfo.tmdb_id != rss_task.tmdbid:
logger.error(f"{item.get('title')} 不匹配") logger.error(f"{item.get('title')} 不匹配")
continue continue
# 季集是否已处理过
if meta.season_episode in processed_data.get('season_episodes'):
logger.info(f"{meta.season_episode} 已处理过")
continue
# 种子 # 种子
torrentinfo = TorrentInfo( torrentinfo = TorrentInfo(
site=site_info.get("id"), site=site_info.get("id"),
@ -103,14 +185,19 @@ class RssChain(ChainBase):
if not result: if not result:
logger.info(f"{rss_task.name} 不匹配过滤规则") logger.info(f"{rss_task.name} 不匹配过滤规则")
continue continue
# 匹配 # 更新已处理数据
processed_data['titles'].append(item.get("title"))
processed_data['season_episodes'].append(meta.season_episode)
# 清除多条数据
mediainfo.clear() mediainfo.clear()
# 匹配到的数据
matched_contexts.append(Context( matched_contexts.append(Context(
meta_info=meta, meta_info=meta,
media_info=mediainfo, media_info=mediainfo,
torrent_info=torrentinfo torrent_info=torrentinfo
)) ))
# 过滤规则 # 更新已处理过的title
self.rssoper.update(rssid=rss_task.id, note=json.dumps(processed_data))
if not matched_contexts: if not matched_contexts:
logger.info(f"{rss_task.name} 未匹配到数据") logger.info(f"{rss_task.name} 未匹配到数据")
continue continue
@ -119,6 +206,8 @@ class RssChain(ChainBase):
if not rss_task.best_version: if not rss_task.best_version:
# 查询缺失的媒体信息 # 查询缺失的媒体信息
rss_meta = MetaInfo(title=rss_task.title) rss_meta = MetaInfo(title=rss_task.title)
rss_meta.year = rss_task.year
rss_meta.begin_season = rss_task.season
rss_meta.type = MediaType(rss_task.type) rss_meta.type = MediaType(rss_task.type)
exist_flag, no_exists = self.downloadchain.get_no_exists_info( exist_flag, no_exists = self.downloadchain.get_no_exists_info(
meta=rss_meta, meta=rss_meta,
@ -137,8 +226,23 @@ class RssChain(ChainBase):
title=f'自定义订阅 {rss_task.name} 已完成', title=f'自定义订阅 {rss_task.name} 已完成',
image=rss_task.backdrop)) image=rss_task.backdrop))
continue continue
elif rss_meta.type == MediaType.TV.value:
# 打印缺失集信息
if no_exists and no_exists.get(rss_task.tmdbid):
no_exists_info = no_exists.get(rss_task.tmdbid).get(rss_task.season)
if no_exists_info:
logger.info(f'订阅 {rss_task.name} 缺失集:{no_exists_info.episodes}')
else: else:
no_exists = {} if rss_task.type == MediaType.TV.value:
no_exists = {
rss_task.season: NotExistMediaInfo(
season=rss_task.season,
episodes=[],
total_episodes=rss_task.total_episode,
start_episode=1)
}
else:
no_exists = {}
# 开始下载 # 开始下载
downloads, lefts = self.downloadchain.batch_download(contexts=matched_contexts, downloads, lefts = self.downloadchain.batch_download(contexts=matched_contexts,
no_exists=no_exists) no_exists=no_exists)

View File

@ -31,6 +31,8 @@ class Rss(Base):
vote = Column(Integer) vote = Column(Integer)
# 简介 # 简介
description = Column(String) description = Column(String)
# 总集数
total_episode = Column(Integer)
# 包含 # 包含
include = Column(String) include = Column(String)
# 排除 # 排除
@ -46,7 +48,7 @@ class Rss(Base):
# 最后更新时间 # 最后更新时间
last_update = Column(String) last_update = Column(String)
# 状态 0-停用1-启用 # 状态 0-停用1-启用
state = Column(Integer) state = Column(Integer, default=1)
@staticmethod @staticmethod
def get_by_tmdbid(db: Session, tmdbid: int, season: int = None): def get_by_tmdbid(db: Session, tmdbid: int, season: int = None):

View File

@ -38,3 +38,13 @@ class RssOper(DbOper):
item.delete(self._db) item.delete(self._db)
return True return True
return False return False
def update(self, rssid: int, **kwargs) -> bool:
"""
更新RSS订阅
"""
item = Rss.get(self._db, rssid)
if item:
item.update(self._db, kwargs)
return True
return False

View File

@ -27,6 +27,8 @@ class Rss(BaseModel):
vote: Optional[float] vote: Optional[float]
# 简介 # 简介
description: Optional[str] description: Optional[str]
# 总集数
total_episodes: Optional[int]
# 包含 # 包含
include: Optional[str] include: Optional[str]
# 排除 # 排除