feat:消息交互支持洗版订阅及全量重新下载

fix #1202
This commit is contained in:
jxxghp 2024-02-19 17:47:20 +08:00
parent 70adbfe6b5
commit d7c6c27679

View File

@ -1,7 +1,7 @@
import copy import copy
import json import json
import re import re
from typing import Any, Optional, Dict from typing import Any, Optional, Dict, Union
from app.chain import ChainBase from app.chain import ChainBase
from app.chain.download import DownloadChain from app.chain.download import DownloadChain
@ -14,7 +14,7 @@ from app.core.event import EventManager
from app.core.meta import MetaBase from app.core.meta import MetaBase
from app.helper.torrent import TorrentHelper from app.helper.torrent import TorrentHelper
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 EventType, MessageChannel, MediaType from app.schemas.types import EventType, MessageChannel, MediaType
from app.utils.string import StringUtils from app.utils.string import StringUtils
@ -40,10 +40,47 @@ class MessageChain(ChainBase):
self.downloadchain = DownloadChain() self.downloadchain = DownloadChain()
self.subscribechain = SubscribeChain() self.subscribechain = SubscribeChain()
self.searchchain = SearchChain() self.searchchain = SearchChain()
self.medtachain = MediaChain() self.mediachain = MediaChain()
self.eventmanager = EventManager() self.eventmanager = EventManager()
self.torrenthelper = TorrentHelper() self.torrenthelper = TorrentHelper()
@staticmethod
def __get_noexits_info(
_meta: MetaBase,
_mediainfo: MediaInfo) -> Dict[Union[int, str], Dict[int, NotExistMediaInfo]]:
"""
获取缺失的媒体信息
"""
if _mediainfo.type == MediaType.TV:
_mediakey = _mediainfo.tmdb_id or _mediainfo.douban_id
_no_exists = {
_mediakey: {}
}
if _meta.begin_season:
episodes = _mediainfo.seasons.get(_meta.begin_season)
if not episodes:
return {}
_no_exists[_mediakey][_meta.begin_season] = NotExistMediaInfo(
season=_meta.begin_season,
episodes=[],
total_episode=len(episodes),
start_episode=episodes[0]
)
else:
for sea, eps in _mediainfo.seasons.items():
if not eps:
continue
_no_exists[_mediakey][sea] = NotExistMediaInfo(
season=sea,
episodes=[],
total_episode=len(eps),
start_episode=eps[0]
)
else:
_no_exists = {}
return _no_exists
def process(self, body: Any, form: Any, args: Any) -> None: def process(self, body: Any, form: Any, args: Any) -> None:
""" """
识别消息内容执行操作 识别消息内容执行操作
@ -84,6 +121,7 @@ class MessageChain(ChainBase):
) )
elif text.isdigit(): elif text.isdigit():
# 用户选择了具体的条目
# 缓存 # 缓存
cache_data: dict = user_cache.get(userid) cache_data: dict = user_cache.get(userid)
# 选择项目 # 选择项目
@ -100,31 +138,44 @@ class MessageChain(ChainBase):
# 缓存列表 # 缓存列表
cache_list: list = copy.deepcopy(cache_data.get('items')) cache_list: list = copy.deepcopy(cache_data.get('items'))
# 选择 # 选择
if cache_type == "Search": if cache_type in ["Search", "ReSearch"]:
# 当前媒体信息
mediainfo: MediaInfo = cache_list[_choice] mediainfo: MediaInfo = cache_list[_choice]
_current_media = mediainfo _current_media = mediainfo
# 查询缺失的媒体信息 # 查询缺失的媒体信息
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=_current_meta, exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=_current_meta,
mediainfo=_current_media) mediainfo=_current_media)
if exist_flag: if exist_flag and cache_type == "Search":
# 媒体库中已存在
self.post_message( self.post_message(
Notification(channel=channel, Notification(channel=channel,
title=f"{_current_media.title_year}" title=f"{_current_media.title_year}"
f"{_current_meta.sea} 媒体库中已存在", f"{_current_meta.sea} 媒体库中已存在,如需重新下载请发送:搜索 XXX 或 下载 XXX",
userid=userid)) userid=userid))
return return
elif exist_flag:
# 没有缺失,但要全量重新搜索和下载
no_exists = self.__get_noexits_info(_current_meta, _current_media)
# 发送缺失的媒体信息 # 发送缺失的媒体信息
if no_exists: messages = []
# 发送消息 if no_exists and cache_type == "Search":
# 发送缺失消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [ messages = [
f"{sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episode}" f"{sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episode}"
for sea, no_exist in no_exists.get(mediakey).items()] for sea, no_exist in no_exists.get(mediakey).items()]
elif no_exists:
# 发送总集数的消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
f"{sea} 季总 {no_exist.total_episode}"
for sea, no_exist in no_exists.get(mediakey).items()]
if messages:
self.post_message(Notification(channel=channel, self.post_message(Notification(channel=channel,
title=f"{mediainfo.title_year}\n" + "\n".join(messages), title=f"{mediainfo.title_year}\n" + "\n".join(messages),
userid=userid)) userid=userid))
# 搜索种子,过滤掉不需要的剧集,以便选择 # 搜索种子,过滤掉不需要的剧集,以便选择
logger.info(f"{mediainfo.title_year} 媒体库中不存在,开始搜索 ...") logger.info(f"开始搜索 {mediainfo.title_year} ...")
self.post_message( self.post_message(
Notification(channel=channel, Notification(channel=channel,
title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...", title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...",
@ -144,13 +195,16 @@ class MessageChain(ChainBase):
# 判断是否设置自动下载 # 判断是否设置自动下载
auto_download_user = settings.AUTO_DOWNLOAD_USER auto_download_user = settings.AUTO_DOWNLOAD_USER
# 匹配到自动下载用户 # 匹配到自动下载用户
if auto_download_user and (auto_download_user == "all" or any(userid == user for user in auto_download_user.split(","))): if auto_download_user \
logger.info(f"用户 {userid} 在自动下载用户中,开始自动择优下载") and (auto_download_user == "all"
or any(userid == user for user in auto_download_user.split(","))):
logger.info(f"用户 {userid} 在自动下载用户中,开始自动择优下载 ...")
# 自动选择下载 # 自动选择下载
self.__auto_download(channel=channel, self.__auto_download(channel=channel,
cache_list=contexts, cache_list=contexts,
userid=userid, userid=userid,
username=username) username=username,
no_exists=no_exists)
else: else:
# 更新缓存 # 更新缓存
user_cache[userid] = { user_cache[userid] = {
@ -165,19 +219,24 @@ class MessageChain(ChainBase):
userid=userid, userid=userid,
total=len(contexts)) total=len(contexts))
elif cache_type == "Subscribe": elif cache_type in ["Subscribe", "ReSubscribe"]:
# 订阅媒体 # 订阅或洗版媒体
mediainfo: MediaInfo = cache_list[_choice] mediainfo: MediaInfo = cache_list[_choice]
# 洗版标识
best_version = False
# 查询缺失的媒体信息 # 查询缺失的媒体信息
exist_flag, _ = self.downloadchain.get_no_exists_info(meta=_current_meta, if cache_type == "Subscribe":
mediainfo=mediainfo) exist_flag, _ = self.downloadchain.get_no_exists_info(meta=_current_meta,
if exist_flag: mediainfo=mediainfo)
self.post_message(Notification( if exist_flag:
channel=channel, self.post_message(Notification(
title=f"{mediainfo.title_year}" channel=channel,
f"{_current_meta.sea} 媒体库中已存在", title=f"{mediainfo.title_year}"
userid=userid)) f"{_current_meta.sea} 媒体库中已存在,如需洗版请发送:洗版 XXX",
return userid=userid))
return
else:
best_version = True
# 添加订阅状态为N # 添加订阅状态为N
self.subscribechain.add(title=mediainfo.title, self.subscribechain.add(title=mediainfo.title,
year=mediainfo.year, year=mediainfo.year,
@ -186,10 +245,11 @@ class MessageChain(ChainBase):
season=_current_meta.begin_season, season=_current_meta.begin_season,
channel=channel, channel=channel,
userid=userid, userid=userid,
username=username) username=username,
best_version=best_version)
elif cache_type == "Torrent": elif cache_type == "Torrent":
if int(text) == 0: if int(text) == 0:
# 自动选择下载 # 自动选择下载,强制下载模式
self.__auto_download(channel=channel, self.__auto_download(channel=channel,
cache_list=cache_list, cache_list=cache_list,
userid=userid, userid=userid,
@ -280,6 +340,14 @@ class MessageChain(ChainBase):
# 订阅 # 订阅
content = re.sub(r"订阅[:\s]*", "", text) content = re.sub(r"订阅[:\s]*", "", text)
action = "Subscribe" action = "Subscribe"
elif text.startswith("洗版"):
# 洗版
content = re.sub(r"洗版[:\s]*", "", text)
action = "ReSubscribe"
elif text.startswith("搜索") or text.startswith("下载"):
# 重新搜索/下载
content = re.sub(r"(搜索|下载)[:\s]*", "", text)
action = "ReSearch"
elif text.startswith("#") \ elif text.startswith("#") \
or re.search(r"^请[问帮你]", text) \ or re.search(r"^请[问帮你]", text) \
or re.search(r"[?]$", text) \ or re.search(r"[?]$", text) \
@ -290,12 +358,12 @@ class MessageChain(ChainBase):
action = "chat" action = "chat"
else: else:
# 搜索 # 搜索
content = re.sub(r"(搜索|下载)[:\s]*", "", text) content = text
action = "Search" action = "Search"
if action in ["Subscribe", "Search"]: if action != "chat":
# 搜索 # 搜索
meta, medias = self.medtachain.search(content) meta, medias = self.mediachain.search(content)
# 识别 # 识别
if not meta.name: if not meta.name:
self.post_message(Notification( self.post_message(Notification(
@ -334,20 +402,22 @@ class MessageChain(ChainBase):
# 保存缓存 # 保存缓存
self.save_cache(user_cache, self._cache_file) self.save_cache(user_cache, self._cache_file)
def __auto_download(self, channel, cache_list, userid, username): def __auto_download(self, channel: MessageChannel, cache_list: list[Context],
userid: Union[str, int], username: str,
no_exists: Optional[Dict[Union[int, str], Dict[int, NotExistMediaInfo]]] = None):
""" """
自动择优下载 自动择优下载
""" """
# 查询缺失的媒体信息 if no_exists is None:
exist_flag, no_exists = self.downloadchain.get_no_exists_info(meta=_current_meta, # 查询缺失的媒体信息
mediainfo=_current_media) exist_flag, no_exists = self.downloadchain.get_no_exists_info(
if exist_flag: meta=_current_meta,
self.post_message(Notification( mediainfo=_current_media
channel=channel, )
title=f"{_current_media.title_year}" if exist_flag:
f"{_current_meta.sea} 媒体库中已存在", # 媒体库中已存在,查询全量
userid=userid)) no_exists = self.__get_noexits_info(_current_meta, _current_media)
return
# 批量下载 # 批量下载
downloads, lefts = self.downloadchain.batch_download(contexts=cache_list, downloads, lefts = self.downloadchain.batch_download(contexts=cache_list,
no_exists=no_exists, no_exists=no_exists,