feat:非大内存模式下主动gc

This commit is contained in:
jxxghp
2025-06-27 09:44:47 +08:00
parent 0baf6e5fe7
commit bb4438ac42
5 changed files with 545 additions and 498 deletions
+385 -356
View File
@@ -136,371 +136,400 @@ class MessageChain(ChainBase):
logger.info(f'收到用户消息内容,用户:{userid},内容:{text}') logger.info(f'收到用户消息内容,用户:{userid},内容:{text}')
# 加载缓存 # 加载缓存
user_cache: Dict[str, dict] = self.load_cache(self._cache_file) or {} user_cache: Dict[str, dict] = self.load_cache(self._cache_file) or {}
# 保存消息 try:
if not text.startswith('CALLBACK:'): # 保存消息
self.messagehelper.put( if not text.startswith('CALLBACK:'):
CommingMessage( self.messagehelper.put(
userid=userid, CommingMessage(
username=username, userid=userid,
channel=channel, username=username,
source=source,
text=text
), role="user")
self.messageoper.add(
channel=channel,
source=source,
userid=username or userid,
text=text,
action=0
)
# 处理消息
if text.startswith('CALLBACK:'):
# 处理按钮回调(适配支持回调的渠道)
if ChannelCapabilityManager.supports_callbacks(channel):
self._handle_callback(text=text, channel=channel, source=source,
userid=userid, username=username,
original_message_id=original_message_id, original_chat_id=original_chat_id)
else:
logger.warning(f"渠道 {channel.value} 不支持回调,但收到了回调消息:{text}")
elif text.startswith('/'):
# 执行命令
self.eventmanager.send_event(
EventType.CommandExcute,
{
"cmd": text,
"user": userid,
"channel": channel,
"source": source
}
)
elif text.isdigit():
# 用户选择了具体的条目
# 缓存
cache_data: dict = user_cache.get(userid).copy()
# 选择项目
if not cache_data \
or not cache_data.get('items') \
or len(cache_data.get('items')) < int(text):
# 发送消息
self.post_message(Notification(channel=channel, source=source, title="输入有误!", userid=userid))
return
# 选择的序号
_choice = int(text) + _current_page * self._page_size - 1
# 缓存类型
cache_type: str = cache_data.get('type')
# 缓存列表
cache_list: list = cache_data.get('items').copy()
# 选择
if cache_type in ["Search", "ReSearch"]:
# 当前媒体信息
mediainfo: MediaInfo = cache_list[_choice]
_current_media = mediainfo
# 查询缺失的媒体信息
exist_flag, no_exists = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=_current_media)
if exist_flag and cache_type == "Search":
# 媒体库中已存在
self.post_message(
Notification(channel=channel,
source=source,
title=f"{_current_media.title_year}"
f"{_current_meta.sea} 媒体库中已存在,如需重新下载请发送:搜索 名称 或 下载 名称】",
userid=userid))
return
elif exist_flag:
# 没有缺失,但要全量重新搜索和下载
no_exists = self.__get_noexits_info(_current_meta, _current_media)
# 发送缺失的媒体信息
messages = []
if no_exists and cache_type == "Search":
# 发送缺失消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
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()]
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,
source=source,
title=f"{mediainfo.title_year}\n" + "\n".join(messages),
userid=userid))
# 搜索种子,过滤掉不需要的剧集,以便选择
logger.info(f"开始搜索 {mediainfo.title_year} ...")
self.post_message(
Notification(channel=channel,
source=source,
title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...",
userid=userid))
# 开始搜索
contexts = SearchChain().process(mediainfo=mediainfo,
no_exists=no_exists)
if not contexts:
# 没有数据
self.post_message(Notification(
channel=channel, channel=channel,
source=source, source=source,
title=f"{mediainfo.title}" text=text
f"{_current_meta.sea} 未搜索到需要的资源!", ), role="user")
userid=userid)) self.messageoper.add(
return channel=channel,
# 搜索结果排序 source=source,
contexts = TorrentHelper().sort_torrents(contexts) userid=username or userid,
# 判断是否设置自动下载 text=text,
auto_download_user = settings.AUTO_DOWNLOAD_USER action=0
# 匹配到自动下载用户 )
if auto_download_user \ # 处理消息
and (auto_download_user == "all" if text.startswith('CALLBACK:'):
or any(userid == user for user in auto_download_user.split(","))): # 处理按钮回调(适配支持回调的渠道)
logger.info(f"用户 {userid} 在自动下载用户中,开始自动择优下载 ...") if ChannelCapabilityManager.supports_callbacks(channel):
# 自动选择下载 self._handle_callback(text=text, channel=channel, source=source,
self.__auto_download(channel=channel, userid=userid, username=username,
source=source, original_message_id=original_message_id, original_chat_id=original_chat_id)
cache_list=contexts,
userid=userid,
username=username,
no_exists=no_exists)
else: else:
# 更新缓存 logger.warning(f"渠道 {channel.value} 不支持回调,但收到了回调消息:{text}")
user_cache[userid] = { elif text.startswith('/'):
"type": "Torrent", # 执行命令
"items": contexts
}
_current_page = 0
# 保存缓存
self.save_cache(user_cache, self._cache_file)
# 删除原消息
if (original_message_id and original_chat_id and
ChannelCapabilityManager.supports_deletion(channel)):
self.delete_message(
channel=channel,
source=source,
message_id=original_message_id,
chat_id=original_chat_id
)
# 发送种子数据
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
self.__post_torrents_message(channel=channel,
source=source,
title=mediainfo.title,
items=contexts[:self._page_size],
userid=userid,
total=len(contexts))
elif cache_type in ["Subscribe", "ReSubscribe"]:
# 订阅或洗版媒体
mediainfo: MediaInfo = cache_list[_choice]
# 洗版标识
best_version = False
# 查询缺失的媒体信息
if cache_type == "Subscribe":
exist_flag, _ = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=mediainfo)
if exist_flag:
self.post_message(Notification(
channel=channel,
source=source,
title=f"{mediainfo.title_year}"
f"{_current_meta.sea} 媒体库中已存在,如需洗版请发送:洗版 XXX】",
userid=userid))
return
else:
best_version = True
# 转换用户名
mp_name = UserOper().get_name(**{f"{channel.name.lower()}_userid": userid}) if channel else None
# 添加订阅,状态为N
SubscribeChain().add(title=mediainfo.title,
year=mediainfo.year,
mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id,
season=_current_meta.begin_season,
channel=channel,
source=source,
userid=userid,
username=mp_name or username,
best_version=best_version)
elif cache_type == "Torrent":
if int(text) == 0:
# 自动选择下载,强制下载模式
self.__auto_download(channel=channel,
source=source,
cache_list=cache_list,
userid=userid,
username=username)
else:
# 下载种子
context: Context = cache_list[_choice]
# 下载
DownloadChain().download_single(context, channel=channel, source=source,
userid=userid, username=username)
elif text.lower() == "p":
# 上一页
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
if _current_page == 0:
# 第一页
self.post_message(Notification(
channel=channel, source=source, title="已经是第一页了!", userid=userid))
return
# 减一页
_current_page -= 1
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
if _current_page == 0:
start = 0
end = self._page_size
else:
start = _current_page * self._page_size
end = start + self._page_size
if cache_type == "Torrent":
# 发送种子数据
self.__post_torrents_message(channel=channel,
source=source,
title=_current_media.title,
items=cache_list[start:end],
userid=userid,
total=len(cache_list),
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 发送媒体数据
self.__post_medias_message(channel=channel,
source=source,
title=_current_meta.name,
items=cache_list[start:end],
userid=userid,
total=len(cache_list),
original_message_id=original_message_id,
original_chat_id=original_chat_id)
elif text.lower() == "n":
# 下一页
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
total = len(cache_list)
# 加一页
cache_list = cache_list[
(_current_page + 1) * self._page_size:(_current_page + 2) * self._page_size]
if not cache_list:
# 没有数据
self.post_message(Notification(
channel=channel, source=source, title="已经是最后一页了!", userid=userid))
return
else:
# 加一页
_current_page += 1
if cache_type == "Torrent":
# 发送种子数据
self.__post_torrents_message(channel=channel,
source=source,
title=_current_media.title,
items=cache_list,
userid=userid,
total=total,
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 发送媒体数据
self.__post_medias_message(channel=channel,
source=source,
title=_current_meta.name,
items=cache_list,
userid=userid,
total=total,
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 搜索或订阅
if text.startswith("订阅"):
# 订阅
content = re.sub(r"订阅[:\s]*", "", text)
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("#") \
or re.search(r"^请[问帮你]", text) \
or re.search(r"[?]$", text) \
or StringUtils.count_words(text) > 10 \
or text.find("继续") != -1:
# 聊天
content = text
action = "Chat"
elif StringUtils.is_link(text):
# 链接
content = text
action = "Link"
else:
# 搜索
content = text
action = "Search"
if action in ["Search", "ReSearch", "Subscribe", "ReSubscribe"]:
# 搜索
meta, medias = MediaChain().search(content)
# 识别
if not meta.name:
self.post_message(Notification(
channel=channel, source=source, title="无法识别输入内容!", userid=userid))
return
# 开始搜索
if not medias:
self.post_message(Notification(
channel=channel, source=source, title=f"{meta.name} 没有找到对应的媒体信息!", userid=userid))
return
logger.info(f"搜索到 {len(medias)} 条相关媒体信息")
# 记录当前状态
_current_meta = meta
# 保存缓存
user_cache[userid] = {
'type': action,
'items': medias
}
self.save_cache(user_cache, self._cache_file)
_current_page = 0
_current_media = None
# 发送媒体列表
self.__post_medias_message(channel=channel,
source=source,
title=meta.name,
items=medias[:self._page_size],
userid=userid, total=len(medias))
else:
# 广播事件
self.eventmanager.send_event( self.eventmanager.send_event(
EventType.UserMessage, EventType.CommandExcute,
{ {
"text": content, "cmd": text,
"userid": userid, "user": userid,
"channel": channel, "channel": channel,
"source": source "source": source
} }
) )
elif text.isdigit():
# 用户选择了具体的条目
# 缓存
cache_data: dict = user_cache.get(userid).copy()
# 选择项目
if not cache_data \
or not cache_data.get('items') \
or len(cache_data.get('items')) < int(text):
# 发送消息
self.post_message(Notification(channel=channel, source=source, title="输入有误!", userid=userid))
return
try:
# 选择的序号
_choice = int(text) + _current_page * self._page_size - 1
# 缓存类型
cache_type: str = cache_data.get('type')
# 缓存列表
cache_list: list = cache_data.get('items').copy()
# 选择
try:
if cache_type in ["Search", "ReSearch"]:
# 当前媒体信息
mediainfo: MediaInfo = cache_list[_choice]
_current_media = mediainfo
# 查询缺失的媒体信息
exist_flag, no_exists = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=_current_media)
if exist_flag and cache_type == "Search":
# 媒体库中已存在
self.post_message(
Notification(channel=channel,
source=source,
title=f"{_current_media.title_year}"
f"{_current_meta.sea} 媒体库中已存在,如需重新下载请发送:搜索 名称 或 下载 名称】",
userid=userid))
return
elif exist_flag:
# 没有缺失,但要全量重新搜索和下载
no_exists = self.__get_noexits_info(_current_meta, _current_media)
# 发送缺失的媒体信息
messages = []
if no_exists and cache_type == "Search":
# 发送缺失消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
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()]
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,
source=source,
title=f"{mediainfo.title_year}\n" + "\n".join(messages),
userid=userid))
# 搜索种子,过滤掉不需要的剧集,以便选择
logger.info(f"开始搜索 {mediainfo.title_year} ...")
self.post_message(
Notification(channel=channel,
source=source,
title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...",
userid=userid))
# 开始搜索
contexts = SearchChain().process(mediainfo=mediainfo,
no_exists=no_exists)
if not contexts:
# 没有数据
self.post_message(Notification(
channel=channel,
source=source,
title=f"{mediainfo.title}"
f"{_current_meta.sea} 未搜索到需要的资源!",
userid=userid))
return
# 搜索结果排序
contexts = TorrentHelper().sort_torrents(contexts)
try:
# 判断是否设置自动下载
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(","))):
logger.info(f"用户 {userid} 在自动下载用户中,开始自动择优下载 ...")
# 自动选择下载
self.__auto_download(channel=channel,
source=source,
cache_list=contexts,
userid=userid,
username=username,
no_exists=no_exists)
else:
# 更新缓存
user_cache[userid] = {
"type": "Torrent",
"items": contexts
}
_current_page = 0
# 保存缓存
self.save_cache(user_cache, self._cache_file)
# 删除原消息
if (original_message_id and original_chat_id and
ChannelCapabilityManager.supports_deletion(channel)):
self.delete_message(
channel=channel,
source=source,
message_id=original_message_id,
chat_id=original_chat_id
)
# 发送种子数据
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
self.__post_torrents_message(channel=channel,
source=source,
title=mediainfo.title,
items=contexts[:self._page_size],
userid=userid,
total=len(contexts))
finally:
contexts.clear()
del contexts
elif cache_type in ["Subscribe", "ReSubscribe"]:
# 订阅或洗版媒体
mediainfo: MediaInfo = cache_list[_choice]
# 洗版标识
best_version = False
# 查询缺失的媒体信息
if cache_type == "Subscribe":
exist_flag, _ = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=mediainfo)
if exist_flag:
self.post_message(Notification(
channel=channel,
source=source,
title=f"{mediainfo.title_year}"
f"{_current_meta.sea} 媒体库中已存在,如需洗版请发送:洗版 XXX】",
userid=userid))
return
else:
best_version = True
# 转换用户名
mp_name = UserOper().get_name(**{f"{channel.name.lower()}_userid": userid}) if channel else None
# 添加订阅,状态为N
SubscribeChain().add(title=mediainfo.title,
year=mediainfo.year,
mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id,
season=_current_meta.begin_season,
channel=channel,
source=source,
userid=userid,
username=mp_name or username,
best_version=best_version)
elif cache_type == "Torrent":
if int(text) == 0:
# 自动选择下载,强制下载模式
self.__auto_download(channel=channel,
source=source,
cache_list=cache_list,
userid=userid,
username=username)
else:
# 下载种子
context: Context = cache_list[_choice]
# 下载
DownloadChain().download_single(context, channel=channel, source=source,
userid=userid, username=username)
finally:
cache_list.clear()
del cache_list
finally:
cache_data.clear()
del cache_data
elif text.lower() == "p":
# 上一页
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
try:
if _current_page == 0:
# 第一页
self.post_message(Notification(
channel=channel, source=source, title="已经是第一页了!", userid=userid))
return
# 减一页
_current_page -= 1
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
try:
if _current_page == 0:
start = 0
end = self._page_size
else:
start = _current_page * self._page_size
end = start + self._page_size
if cache_type == "Torrent":
# 发送种子数据
self.__post_torrents_message(channel=channel,
source=source,
title=_current_media.title,
items=cache_list[start:end],
userid=userid,
total=len(cache_list),
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 发送媒体数据
self.__post_medias_message(channel=channel,
source=source,
title=_current_meta.name,
items=cache_list[start:end],
userid=userid,
total=len(cache_list),
original_message_id=original_message_id,
original_chat_id=original_chat_id)
finally:
cache_list.clear()
del cache_list
finally:
cache_data.clear()
del cache_data
elif text.lower() == "n":
# 下一页
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
try:
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
total = len(cache_list)
# 加一页
cache_list = cache_list[(_current_page + 1) * self._page_size:(_current_page + 2) * self._page_size]
if not cache_list:
# 没有数据
self.post_message(Notification(
channel=channel, source=source, title="已经是最后一页了!", userid=userid))
return
else:
try:
# 加一页
_current_page += 1
if cache_type == "Torrent":
# 发送种子数据
self.__post_torrents_message(channel=channel,
source=source,
title=_current_media.title,
items=cache_list,
userid=userid,
total=total,
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 发送媒体数据
self.__post_medias_message(channel=channel,
source=source,
title=_current_meta.name,
items=cache_list,
userid=userid,
total=total,
original_message_id=original_message_id,
original_chat_id=original_chat_id)
finally:
cache_list.clear()
del cache_list
finally:
cache_data.clear()
del cache_data
else:
# 搜索或订阅
if text.startswith("订阅"):
# 订阅
content = re.sub(r"订阅[:\s]*", "", text)
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("#") \
or re.search(r"^请[问帮你]", text) \
or re.search(r"[?]$", text) \
or StringUtils.count_words(text) > 10 \
or text.find("继续") != -1:
# 聊天
content = text
action = "Chat"
elif StringUtils.is_link(text):
# 链接
content = text
action = "Link"
else:
# 搜索
content = text
action = "Search"
if action in ["Search", "ReSearch", "Subscribe", "ReSubscribe"]:
# 搜索
meta, medias = MediaChain().search(content)
# 识别
if not meta.name:
self.post_message(Notification(
channel=channel, source=source, title="无法识别输入内容!", userid=userid))
return
# 开始搜索
if not medias:
self.post_message(Notification(
channel=channel, source=source, title=f"{meta.name} 没有找到对应的媒体信息!", userid=userid))
return
logger.info(f"搜索到 {len(medias)} 条相关媒体信息")
try:
# 记录当前状态
_current_meta = meta
# 保存缓存
user_cache[userid] = {
'type': action,
'items': medias
}
self.save_cache(user_cache, self._cache_file)
_current_page = 0
_current_media = None
# 发送媒体列表
self.__post_medias_message(channel=channel,
source=source,
title=meta.name,
items=medias[:self._page_size],
userid=userid, total=len(medias))
finally:
medias.clear()
del medias
else:
# 广播事件
self.eventmanager.send_event(
EventType.UserMessage,
{
"text": content,
"userid": userid,
"channel": channel,
"source": source
}
)
finally:
user_cache.clear()
del user_cache
def _handle_callback(self, text: str, channel: MessageChannel, source: str, def _handle_callback(self, text: str, channel: MessageChannel, source: str,
userid: Union[str, int], username: str, userid: Union[str, int], username: str,
+1
View File
@@ -365,6 +365,7 @@ class SearchChain(ChainBase):
logger.info(f"站点搜索完成,有效资源数:{len(results)},总耗时 {(end_time - start_time).seconds}") logger.info(f"站点搜索完成,有效资源数:{len(results)},总耗时 {(end_time - start_time).seconds}")
# 结束进度 # 结束进度
progress.end(ProgressKey.Search) progress.end(ProgressKey.Search)
# 返回 # 返回
return results return results
+6
View File
@@ -1,4 +1,5 @@
import base64 import base64
import gc
import re import re
from datetime import datetime from datetime import datetime
from typing import Optional, Tuple, Union, Dict from typing import Optional, Tuple, Union, Dict
@@ -106,6 +107,11 @@ class SiteChain(ChainBase):
EventManager().send_event(EventType.SiteRefreshed, { EventManager().send_event(EventType.SiteRefreshed, {
"site_id": "*" "site_id": "*"
}) })
# 如果不是大内存模式,进行垃圾回收
if not settings.BIG_MEMORY_MODE:
gc.collect()
return result return result
def is_special_site(self, domain: str) -> bool: def is_special_site(self, domain: str) -> bool:
+148 -142
View File
@@ -1,4 +1,5 @@
import copy import copy
import gc
import json import json
import random import random
import threading import threading
@@ -438,6 +439,10 @@ class SubscribeChain(ChainBase):
subscribes.clear() subscribes.clear()
del subscribes del subscribes
# 如果不是大内存模式,进行垃圾回收
if not settings.BIG_MEMORY_MODE:
gc.collect()
def update_subscribe_priority(self, subscribe: Subscribe, meta: MetaBase, def update_subscribe_priority(self, subscribe: Subscribe, meta: MetaBase,
mediainfo: MediaInfo, downloads: Optional[List[Context]]): mediainfo: MediaInfo, downloads: Optional[List[Context]]):
""" """
@@ -509,6 +514,9 @@ class SubscribeChain(ChainBase):
self.match( self.match(
TorrentsChain().refresh(sites=sites) TorrentsChain().refresh(sites=sites)
) )
# 如果不是大内存模式,进行垃圾回收
if not settings.BIG_MEMORY_MODE:
gc.collect()
@staticmethod @staticmethod
def get_sub_sites(subscribe: Subscribe) -> List[int]: def get_sub_sites(subscribe: Subscribe) -> List[int]:
@@ -633,163 +641,159 @@ class SubscribeChain(ChainBase):
torrenthelper = TorrentHelper() torrenthelper = TorrentHelper()
systemconfig = SystemConfigOper() systemconfig = SystemConfigOper()
wordsmatcher = WordsMatcher() wordsmatcher = WordsMatcher()
try: for domain, contexts in processed_torrents.items():
for domain, contexts in processed_torrents.items(): if global_vars.is_system_stopped:
if global_vars.is_system_stopped: break
break if domains and domain not in domains:
if domains and domain not in domains: continue
continue logger.debug(f'开始匹配站点:{domain},共缓存了 {len(contexts)} 个种子...')
logger.debug(f'开始匹配站点:{domain},共缓存了 {len(contexts)} 个种子...') try:
try: for context in contexts:
for context in contexts: if global_vars.is_system_stopped:
if global_vars.is_system_stopped: break
break # 提取信息
# 提取信息 _context = copy.copy(context)
_context = copy.copy(context) torrent_meta = _context.meta_info
torrent_meta = _context.meta_info torrent_mediainfo = _context.media_info
torrent_mediainfo = _context.media_info torrent_info = _context.torrent_info
torrent_info = _context.torrent_info
# 不在订阅站点范围的不处理 # 不在订阅站点范围的不处理
sub_sites = self.get_sub_sites(subscribe) sub_sites = self.get_sub_sites(subscribe)
if sub_sites and torrent_info.site not in sub_sites: if sub_sites and torrent_info.site not in sub_sites:
logger.debug(f"{torrent_info.site_name} - {torrent_info.title} 不符合订阅站点要求") logger.debug(f"{torrent_info.site_name} - {torrent_info.title} 不符合订阅站点要求")
continue continue
# 有自定义识别词时,需要判断是否需要重新识别 # 有自定义识别词时,需要判断是否需要重新识别
if custom_words_list: if custom_words_list:
# 使用org_string,应用一次后理论上不能再次应用 # 使用org_string,应用一次后理论上不能再次应用
_, apply_words = wordsmatcher.prepare(torrent_meta.org_string, _, apply_words = wordsmatcher.prepare(torrent_meta.org_string,
custom_words=custom_words_list) custom_words=custom_words_list)
if apply_words: if apply_words:
logger.info(
f'{torrent_info.site_name} - {torrent_info.title} 因订阅存在自定义识别词,重新识别元数据...')
# 重新识别元数据
torrent_meta = MetaInfo(title=torrent_info.title, subtitle=torrent_info.description,
custom_words=custom_words_list)
# 更新元数据缓存
_context.meta_info = torrent_meta
# 重新识别媒体信息
torrent_mediainfo = self.recognize_media(meta=torrent_meta,
episode_group=subscribe.episode_group)
if torrent_mediainfo:
# 清理多余信息
torrent_mediainfo.clear()
# 更新种子缓存
_context.media_info = torrent_mediainfo
# 如果仍然没有识别到媒体信息,尝试标题匹配
if not torrent_mediainfo or (not torrent_mediainfo.tmdb_id and not torrent_mediainfo.douban_id):
logger.info( logger.info(
f'{torrent_info.site_name} - {torrent_info.title} 重新识别失败,尝试通过标题匹配...') f'{torrent_info.site_name} - {torrent_info.title} 因订阅存在自定义识别词,重新识别元数据...')
if torrenthelper.match_torrent(mediainfo=mediainfo, # 重新识别元数据
torrent_meta=torrent_meta, torrent_meta = MetaInfo(title=torrent_info.title, subtitle=torrent_info.description,
torrent=torrent_info): custom_words=custom_words_list)
# 匹配成功 # 更新元数据缓存
logger.info( _context.meta_info = torrent_meta
f'{mediainfo.title_year} 通过标题匹配到可选资源:{torrent_info.site_name} - {torrent_info.title}') # 重新识别媒体信息
torrent_mediainfo = mediainfo torrent_mediainfo = self.recognize_media(meta=torrent_meta,
episode_group=subscribe.episode_group)
if torrent_mediainfo:
# 清理多余信息
torrent_mediainfo.clear()
# 更新种子缓存 # 更新种子缓存
_context.media_info = mediainfo _context.media_info = torrent_mediainfo
else:
continue
# 直接比对媒体信息 # 如果仍然没有识别到媒体信息,尝试标题匹配
if torrent_mediainfo and (torrent_mediainfo.tmdb_id or torrent_mediainfo.douban_id): if not torrent_mediainfo or (not torrent_mediainfo.tmdb_id and not torrent_mediainfo.douban_id):
if torrent_mediainfo.type != mediainfo.type: logger.info(
continue f'{torrent_info.site_name} - {torrent_info.title} 重新识别失败,尝试通过标题匹配...')
if torrent_mediainfo.tmdb_id \ if torrenthelper.match_torrent(mediainfo=mediainfo,
and torrent_mediainfo.tmdb_id != mediainfo.tmdb_id: torrent_meta=torrent_meta,
continue torrent=torrent_info):
if torrent_mediainfo.douban_id \ # 匹配成功
and torrent_mediainfo.douban_id != mediainfo.douban_id:
continue
logger.info( logger.info(
f'{mediainfo.title_year} 通过媒体信ID匹配到可选资源:{torrent_info.site_name} - {torrent_info.title}') f'{mediainfo.title_year} 通过标题匹配到可选资源:{torrent_info.site_name} - {torrent_info.title}')
torrent_mediainfo = mediainfo
# 更新种子缓存
_context.media_info = mediainfo
else: else:
continue continue
# 如果是电视剧 # 直接比对媒体信息
if torrent_mediainfo.type == MediaType.TV: if torrent_mediainfo and (torrent_mediainfo.tmdb_id or torrent_mediainfo.douban_id):
# 有多季的不要 if torrent_mediainfo.type != mediainfo.type:
if len(torrent_meta.season_list) > 1: continue
logger.debug(f'{torrent_info.title} 有多季,不处理') if torrent_mediainfo.tmdb_id \
continue and torrent_mediainfo.tmdb_id != mediainfo.tmdb_id:
# 比对季 continue
if torrent_meta.begin_season: if torrent_mediainfo.douban_id \
if meta.begin_season != torrent_meta.begin_season: and torrent_mediainfo.douban_id != mediainfo.douban_id:
logger.debug(f'{torrent_info.title} 季不匹配') continue
continue logger.info(
elif meta.begin_season != 1: f'{mediainfo.title_year} 通过媒体信ID匹配到可选资源:{torrent_info.site_name} - {torrent_info.title}')
else:
continue
# 如果是电视剧
if torrent_mediainfo.type == MediaType.TV:
# 有多季的不要
if len(torrent_meta.season_list) > 1:
logger.debug(f'{torrent_info.title} 有多季,不处理')
continue
# 比对季
if torrent_meta.begin_season:
if meta.begin_season != torrent_meta.begin_season:
logger.debug(f'{torrent_info.title} 季不匹配') logger.debug(f'{torrent_info.title} 季不匹配')
continue continue
# 非洗版 elif meta.begin_season != 1:
if not subscribe.best_version: logger.debug(f'{torrent_info.title} 季不匹配')
# 不是缺失的剧集不要 continue
if no_exists and no_exists.get(mediakey): # 非洗版
# 缺失集 if not subscribe.best_version:
no_exists_info = no_exists.get(mediakey).get(subscribe.season) # 不是缺失的剧集不要
if no_exists_info: if no_exists and no_exists.get(mediakey):
# 是否有交 # 缺失
if no_exists_info.episodes and \ no_exists_info = no_exists.get(mediakey).get(subscribe.season)
torrent_meta.episode_list and \ if no_exists_info:
not set(no_exists_info.episodes).intersection( # 是否有交集
set(torrent_meta.episode_list) if no_exists_info.episodes and \
): torrent_meta.episode_list and \
logger.debug( not set(no_exists_info.episodes).intersection(
f'{torrent_info.title} 对应剧集 {torrent_meta.episode_list} 未包含缺失的剧集' set(torrent_meta.episode_list)
) ):
continue logger.debug(
else: f'{torrent_info.title} 对应剧集 {torrent_meta.episode_list} 未包含缺失的剧集'
# 洗版时,非整季不要 )
if meta.type == MediaType.TV:
if torrent_meta.episode_list:
logger.debug(f'{subscribe.name} 正在洗版,{torrent_info.title} 不是整季')
continue continue
# 匹配订阅附加参数
if not torrenthelper.filter_torrent(torrent_info=torrent_info,
filter_params=self.get_params(subscribe)):
continue
# 优先级过滤规则
if subscribe.best_version:
rule_groups = subscribe.filter_groups \
or systemconfig.get(SystemConfigKey.BestVersionFilterRuleGroups)
else: else:
rule_groups = subscribe.filter_groups \ # 洗版时,非整季不要
or systemconfig.get(SystemConfigKey.SubscribeFilterRuleGroups) if meta.type == MediaType.TV:
result: List[TorrentInfo] = self.filter_torrents( if torrent_meta.episode_list:
rule_groups=rule_groups, logger.debug(f'{subscribe.name} 正在洗版,{torrent_info.title} 不是整季')
torrent_list=[torrent_info], continue
mediainfo=torrent_mediainfo)
if result is not None and not result: # 匹配订阅附加参数
# 不符合过滤规则 if not torrenthelper.filter_torrent(torrent_info=torrent_info,
logger.debug(f"{torrent_info.title} 不匹配过滤规则") filter_params=self.get_params(subscribe)):
continue
# 优先级过滤规则
if subscribe.best_version:
rule_groups = subscribe.filter_groups \
or systemconfig.get(SystemConfigKey.BestVersionFilterRuleGroups)
else:
rule_groups = subscribe.filter_groups \
or systemconfig.get(SystemConfigKey.SubscribeFilterRuleGroups)
result: List[TorrentInfo] = self.filter_torrents(
rule_groups=rule_groups,
torrent_list=[torrent_info],
mediainfo=torrent_mediainfo)
if result is not None and not result:
# 不符合过滤规则
logger.debug(f"{torrent_info.title} 不匹配过滤规则")
continue
# 洗版时,优先级小于已下载优先级的不要
if subscribe.best_version:
if subscribe.current_priority \
and torrent_info.pri_order <= subscribe.current_priority:
logger.info(
f'{subscribe.name} 正在洗版,{torrent_info.title} 优先级低于或等于已下载优先级')
continue continue
# 洗版时,优先级小于已下载优先级的不要 # 匹配成功
if subscribe.best_version: logger.info(f'{mediainfo.title_year} 匹配成功:{torrent_info.title}')
if subscribe.current_priority \ # 自定义属性
and torrent_info.pri_order <= subscribe.current_priority: if subscribe.media_category:
logger.info( torrent_mediainfo.category = subscribe.media_category
f'{subscribe.name} 正在洗版,{torrent_info.title} 优先级低于或等于已下载优先级') if subscribe.episode_group:
continue torrent_mediainfo.episode_group = subscribe.episode_group
_match_context.append(_context)
# 匹配成功 finally:
logger.info(f'{mediainfo.title_year} 匹配成功:{torrent_info.title}') contexts.clear()
# 自定义属性 del contexts
if subscribe.media_category:
torrent_mediainfo.category = subscribe.media_category
if subscribe.episode_group:
torrent_mediainfo.episode_group = subscribe.episode_group
_match_context.append(_context)
finally:
contexts.clear()
del contexts
finally:
processed_torrents.clear()
del processed_torrents
if not _match_context: if not _match_context:
# 未匹配到资源 # 未匹配到资源
@@ -816,6 +820,8 @@ class SubscribeChain(ChainBase):
self.finish_subscribe_or_not(subscribe=subscribe, meta=meta, mediainfo=mediainfo, self.finish_subscribe_or_not(subscribe=subscribe, meta=meta, mediainfo=mediainfo,
downloads=downloads, lefts=lefts) downloads=downloads, lefts=lefts)
finally: finally:
processed_torrents.clear()
del processed_torrents
subscribes.clear() subscribes.clear()
del subscribes del subscribes
+5
View File
@@ -1,3 +1,4 @@
import gc
import queue import queue
import re import re
import threading import threading
@@ -866,6 +867,10 @@ class TransferChain(ChainBase, metaclass=Singleton):
torrents.clear() torrents.clear()
del torrents del torrents
# 如果不是大内存模式,进行垃圾回收
if not settings.BIG_MEMORY_MODE:
gc.collect()
# 结束 # 结束
logger.info("所有下载器中下载完成的文件已整理完成") logger.info("所有下载器中下载完成的文件已整理完成")
return True return True