diff --git a/app/chain/message.py b/app/chain/message.py index 745f8366..290557c9 100644 --- a/app/chain/message.py +++ b/app/chain/message.py @@ -136,371 +136,400 @@ class MessageChain(ChainBase): logger.info(f'收到用户消息内容,用户:{userid},内容:{text}') # 加载缓存 user_cache: Dict[str, dict] = self.load_cache(self._cache_file) or {} - # 保存消息 - if not text.startswith('CALLBACK:'): - self.messagehelper.put( - CommingMessage( - userid=userid, - username=username, - channel=channel, - 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( + try: + # 保存消息 + if not text.startswith('CALLBACK:'): + self.messagehelper.put( + CommingMessage( + userid=userid, + username=username, channel=channel, source=source, - title=f"{mediainfo.title}" - f"{_current_meta.sea} 未搜索到需要的资源!", - userid=userid)) - return - # 搜索结果排序 - contexts = TorrentHelper().sort_torrents(contexts) - # 判断是否设置自动下载 - 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) + 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: - # 更新缓存 - 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)) - - 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: - # 广播事件 + logger.warning(f"渠道 {channel.value} 不支持回调,但收到了回调消息:{text}") + elif text.startswith('/'): + # 执行命令 self.eventmanager.send_event( - EventType.UserMessage, + EventType.CommandExcute, { - "text": content, - "userid": userid, + "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 + 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, userid: Union[str, int], username: str, diff --git a/app/chain/search.py b/app/chain/search.py index c649f88e..0502e072 100644 --- a/app/chain/search.py +++ b/app/chain/search.py @@ -365,6 +365,7 @@ class SearchChain(ChainBase): logger.info(f"站点搜索完成,有效资源数:{len(results)},总耗时 {(end_time - start_time).seconds} 秒") # 结束进度 progress.end(ProgressKey.Search) + # 返回 return results diff --git a/app/chain/site.py b/app/chain/site.py index 4ca13d2a..eece198d 100644 --- a/app/chain/site.py +++ b/app/chain/site.py @@ -1,4 +1,5 @@ import base64 +import gc import re from datetime import datetime from typing import Optional, Tuple, Union, Dict @@ -106,6 +107,11 @@ class SiteChain(ChainBase): EventManager().send_event(EventType.SiteRefreshed, { "site_id": "*" }) + + # 如果不是大内存模式,进行垃圾回收 + if not settings.BIG_MEMORY_MODE: + gc.collect() + return result def is_special_site(self, domain: str) -> bool: diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index bf1348fb..5d491fbd 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -1,4 +1,5 @@ import copy +import gc import json import random import threading @@ -438,6 +439,10 @@ class SubscribeChain(ChainBase): subscribes.clear() del subscribes + # 如果不是大内存模式,进行垃圾回收 + if not settings.BIG_MEMORY_MODE: + gc.collect() + def update_subscribe_priority(self, subscribe: Subscribe, meta: MetaBase, mediainfo: MediaInfo, downloads: Optional[List[Context]]): """ @@ -509,6 +514,9 @@ class SubscribeChain(ChainBase): self.match( TorrentsChain().refresh(sites=sites) ) + # 如果不是大内存模式,进行垃圾回收 + if not settings.BIG_MEMORY_MODE: + gc.collect() @staticmethod def get_sub_sites(subscribe: Subscribe) -> List[int]: @@ -633,163 +641,159 @@ class SubscribeChain(ChainBase): torrenthelper = TorrentHelper() systemconfig = SystemConfigOper() wordsmatcher = WordsMatcher() - try: - for domain, contexts in processed_torrents.items(): - if global_vars.is_system_stopped: - break - if domains and domain not in domains: - continue - logger.debug(f'开始匹配站点:{domain},共缓存了 {len(contexts)} 个种子...') - try: - for context in contexts: - if global_vars.is_system_stopped: - break - # 提取信息 - _context = copy.copy(context) - torrent_meta = _context.meta_info - torrent_mediainfo = _context.media_info - torrent_info = _context.torrent_info + for domain, contexts in processed_torrents.items(): + if global_vars.is_system_stopped: + break + if domains and domain not in domains: + continue + logger.debug(f'开始匹配站点:{domain},共缓存了 {len(contexts)} 个种子...') + try: + for context in contexts: + if global_vars.is_system_stopped: + break + # 提取信息 + _context = copy.copy(context) + torrent_meta = _context.meta_info + torrent_mediainfo = _context.media_info + torrent_info = _context.torrent_info - # 不在订阅站点范围的不处理 - sub_sites = self.get_sub_sites(subscribe) - if sub_sites and torrent_info.site not in sub_sites: - logger.debug(f"{torrent_info.site_name} - {torrent_info.title} 不符合订阅站点要求") - continue + # 不在订阅站点范围的不处理 + sub_sites = self.get_sub_sites(subscribe) + if sub_sites and torrent_info.site not in sub_sites: + logger.debug(f"{torrent_info.site_name} - {torrent_info.title} 不符合订阅站点要求") + continue - # 有自定义识别词时,需要判断是否需要重新识别 - if custom_words_list: - # 使用org_string,应用一次后理论上不能再次应用 - _, apply_words = wordsmatcher.prepare(torrent_meta.org_string, - custom_words=custom_words_list) - 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): + # 有自定义识别词时,需要判断是否需要重新识别 + if custom_words_list: + # 使用org_string,应用一次后理论上不能再次应用 + _, apply_words = wordsmatcher.prepare(torrent_meta.org_string, + custom_words=custom_words_list) + if apply_words: logger.info( - f'{torrent_info.site_name} - {torrent_info.title} 重新识别失败,尝试通过标题匹配...') - if torrenthelper.match_torrent(mediainfo=mediainfo, - torrent_meta=torrent_meta, - torrent=torrent_info): - # 匹配成功 - logger.info( - f'{mediainfo.title_year} 通过标题匹配到可选资源:{torrent_info.site_name} - {torrent_info.title}') - torrent_mediainfo = mediainfo + 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 = mediainfo - else: - continue + _context.media_info = torrent_mediainfo - # 直接比对媒体信息 - if torrent_mediainfo and (torrent_mediainfo.tmdb_id or torrent_mediainfo.douban_id): - if torrent_mediainfo.type != mediainfo.type: - continue - if torrent_mediainfo.tmdb_id \ - and torrent_mediainfo.tmdb_id != mediainfo.tmdb_id: - continue - if torrent_mediainfo.douban_id \ - and torrent_mediainfo.douban_id != mediainfo.douban_id: - continue + # 如果仍然没有识别到媒体信息,尝试标题匹配 + if not torrent_mediainfo or (not torrent_mediainfo.tmdb_id and not torrent_mediainfo.douban_id): + logger.info( + f'{torrent_info.site_name} - {torrent_info.title} 重新识别失败,尝试通过标题匹配...') + if torrenthelper.match_torrent(mediainfo=mediainfo, + torrent_meta=torrent_meta, + torrent=torrent_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: 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} 季不匹配') - continue - elif meta.begin_season != 1: + # 直接比对媒体信息 + if torrent_mediainfo and (torrent_mediainfo.tmdb_id or torrent_mediainfo.douban_id): + if torrent_mediainfo.type != mediainfo.type: + continue + if torrent_mediainfo.tmdb_id \ + and torrent_mediainfo.tmdb_id != mediainfo.tmdb_id: + continue + if torrent_mediainfo.douban_id \ + and torrent_mediainfo.douban_id != mediainfo.douban_id: + continue + logger.info( + 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} 季不匹配') continue - # 非洗版 - if not subscribe.best_version: - # 不是缺失的剧集不要 - if no_exists and no_exists.get(mediakey): - # 缺失集 - no_exists_info = no_exists.get(mediakey).get(subscribe.season) - if no_exists_info: - # 是否有交集 - if no_exists_info.episodes and \ - torrent_meta.episode_list and \ - not set(no_exists_info.episodes).intersection( - set(torrent_meta.episode_list) - ): - logger.debug( - f'{torrent_info.title} 对应剧集 {torrent_meta.episode_list} 未包含缺失的剧集' - ) - continue - else: - # 洗版时,非整季不要 - if meta.type == MediaType.TV: - if torrent_meta.episode_list: - logger.debug(f'{subscribe.name} 正在洗版,{torrent_info.title} 不是整季') + elif meta.begin_season != 1: + logger.debug(f'{torrent_info.title} 季不匹配') + continue + # 非洗版 + if not subscribe.best_version: + # 不是缺失的剧集不要 + if no_exists and no_exists.get(mediakey): + # 缺失集 + no_exists_info = no_exists.get(mediakey).get(subscribe.season) + if no_exists_info: + # 是否有交集 + if no_exists_info.episodes and \ + torrent_meta.episode_list and \ + not set(no_exists_info.episodes).intersection( + set(torrent_meta.episode_list) + ): + logger.debug( + f'{torrent_info.title} 对应剧集 {torrent_meta.episode_list} 未包含缺失的剧集' + ) 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: - 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} 不匹配过滤规则") + # 洗版时,非整季不要 + if meta.type == MediaType.TV: + if torrent_meta.episode_list: + logger.debug(f'{subscribe.name} 正在洗版,{torrent_info.title} 不是整季') + 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: + 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 - # 洗版时,优先级小于已下载优先级的不要 - 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 - - # 匹配成功 - logger.info(f'{mediainfo.title_year} 匹配成功:{torrent_info.title}') - # 自定义属性 - 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 + # 匹配成功 + logger.info(f'{mediainfo.title_year} 匹配成功:{torrent_info.title}') + # 自定义属性 + 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 if not _match_context: # 未匹配到资源 @@ -816,6 +820,8 @@ class SubscribeChain(ChainBase): self.finish_subscribe_or_not(subscribe=subscribe, meta=meta, mediainfo=mediainfo, downloads=downloads, lefts=lefts) finally: + processed_torrents.clear() + del processed_torrents subscribes.clear() del subscribes diff --git a/app/chain/transfer.py b/app/chain/transfer.py index 82d867ad..f8fe124e 100755 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -1,3 +1,4 @@ +import gc import queue import re import threading @@ -866,6 +867,10 @@ class TransferChain(ChainBase, metaclass=Singleton): torrents.clear() del torrents + # 如果不是大内存模式,进行垃圾回收 + if not settings.BIG_MEMORY_MODE: + gc.collect() + # 结束 logger.info("所有下载器中下载完成的文件已整理完成") return True