mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-17 15:09:25 +00:00
Merge pull request #417 from InfinityPacer/main
This commit is contained in:
@@ -355,11 +355,12 @@
|
||||
"name": "站点刷流",
|
||||
"description": "自动托管刷流,将会提高对应站点的访问频率。",
|
||||
"labels": "刷流,仪表板",
|
||||
"version": "3.3",
|
||||
"version": "3.4",
|
||||
"icon": "brush.jpg",
|
||||
"author": "jxxghp,InfinityPacer",
|
||||
"level": 2,
|
||||
"history": {
|
||||
"v3.4": "移除「记录更多日志」配置项并调整为DEBUG日志,支持「删除排除标签」配置项,增加刷流任务时支持触发插件事件",
|
||||
"v3.3": "支持QB删除种子时强制汇报Tracker,站点独立配置增加「站点全局H&R」配置项",
|
||||
"v3.2": "支持推送QB种子时启用「先下载首尾文件块」选项",
|
||||
"v3.1": "支持仪表板显示站点刷流数据,需要主程序升级v1.8.7+版本",
|
||||
|
||||
@@ -25,6 +25,7 @@ from app.modules.qbittorrent import Qbittorrent
|
||||
from app.modules.transmission import Transmission
|
||||
from app.plugins import _PluginBase
|
||||
from app.schemas import NotificationType, TorrentInfo, MediaType
|
||||
from app.schemas.types import EventType
|
||||
from app.utils.http import RequestUtils
|
||||
from app.utils.string import StringUtils
|
||||
|
||||
@@ -67,11 +68,11 @@ class BrushConfig:
|
||||
self.clear_task = config.get("clear_task", False)
|
||||
self.archive_task = config.get("archive_task", False)
|
||||
self.except_tags = config.get("except_tags", True)
|
||||
self.delete_except_tags = config.get("delete_except_tags")
|
||||
self.except_subscribe = config.get("except_subscribe", True)
|
||||
self.brush_sequential = config.get("brush_sequential", False)
|
||||
self.proxy_download = config.get("proxy_download", False)
|
||||
self.proxy_delete = config.get("proxy_delete", False)
|
||||
self.log_more = config.get("log_more", False)
|
||||
self.active_time_range = config.get("active_time_range")
|
||||
self.downloader_monitor = config.get("downloader_monitor")
|
||||
self.qb_category = config.get("qb_category")
|
||||
@@ -257,7 +258,7 @@ class BrushFlow(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "brush.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "3.3"
|
||||
plugin_version = "3.4"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp,InfinityPacer"
|
||||
# 作者主页
|
||||
@@ -295,7 +296,6 @@ class BrushFlow(_PluginBase):
|
||||
# endregion
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
logger.info(f"站点刷流服务初始化")
|
||||
self.siteshelper = SitesHelper()
|
||||
self.siteoper = SiteOper()
|
||||
self.torrents = TorrentsChain()
|
||||
@@ -340,11 +340,10 @@ class BrushFlow(_PluginBase):
|
||||
brush_config.archive_task = False
|
||||
self.__update_config()
|
||||
|
||||
if brush_config.log_more:
|
||||
if brush_config.enable_site_config:
|
||||
logger.info(f"已开启站点独立配置,配置信息:{brush_config}")
|
||||
else:
|
||||
logger.info(f"没有开启站点独立配置,配置信息:{brush_config}")
|
||||
if brush_config.enable_site_config:
|
||||
logger.debug(f"已开启站点独立配置,配置信息:{brush_config}")
|
||||
else:
|
||||
logger.debug(f"没有开启站点独立配置,配置信息:{brush_config}")
|
||||
|
||||
# 停止现有任务
|
||||
self.stop_service()
|
||||
@@ -366,8 +365,6 @@ class BrushFlow(_PluginBase):
|
||||
# 如果开启&存在站点时,才需要启用后台任务
|
||||
self._task_brush_enable = brush_config.enabled and brush_config.brushsites
|
||||
|
||||
# brush_config.onlyonce = True
|
||||
|
||||
# 检查是否启用了一次性任务
|
||||
if brush_config.onlyonce:
|
||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||
@@ -974,11 +971,6 @@ class BrushFlow(_PluginBase):
|
||||
'component': 'VWindow',
|
||||
'props': {
|
||||
'model': '_tabs'
|
||||
# VWindow设置paddnig会导致切换Tab时页面高度变动,调整为修改VRow的方案
|
||||
# 'style': {
|
||||
# 'padding-top': '24px',
|
||||
# 'padding-bottom': '24px',
|
||||
# },
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
@@ -1426,11 +1418,28 @@ class BrushFlow(_PluginBase):
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'seed_inactivetime',
|
||||
'label': '未活动时间(分钟) ',
|
||||
'label': '未活动时间(分钟)',
|
||||
'placeholder': '超过时删除任务'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
"cols": 12,
|
||||
"md": 4
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'delete_except_tags',
|
||||
'label': '删除排除标签',
|
||||
'placeholder': '如:MOVIEPILOT,H&R'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1658,27 +1667,6 @@ class BrushFlow(_PluginBase):
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
"content": [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 4
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'log_more',
|
||||
'label': '记录更多日志',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1742,7 +1730,7 @@ class BrushFlow(_PluginBase):
|
||||
'props': {
|
||||
'type': 'error',
|
||||
'variant': 'tonal',
|
||||
'text': '注意:排除H&R并不保证能完全适配所有站点(部分站点在列表页不显示H&R标志,但实际上是有H&R的),请注意核对使用!'
|
||||
'text': '注意:排除H&R并不保证能完全适配所有站点(部分站点在列表页不显示H&R标志,但实际上是有H&R的),请注意核对使用'
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1850,6 +1838,7 @@ class BrushFlow(_PluginBase):
|
||||
"clear_task": False,
|
||||
"archive_task": False,
|
||||
"except_tags": True,
|
||||
"delete_except_tags": f"{settings.TORRENT_TAG},H&R" if settings.TORRENT_TAG else "H&R",
|
||||
"except_subscribe": True,
|
||||
"brush_sequential": False,
|
||||
"proxy_download": False,
|
||||
@@ -1857,7 +1846,6 @@ class BrushFlow(_PluginBase):
|
||||
"freeleech": "free",
|
||||
"hr": "yes",
|
||||
"enable_site_config": False,
|
||||
"log_more": False,
|
||||
"downloader_monitor": False,
|
||||
"auto_qb_category": False,
|
||||
"qb_first_last_piece": False,
|
||||
@@ -2055,9 +2043,6 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
if brush_config.site_hr_active:
|
||||
logger.info(f"站点 {siteinfo.name} 已开启全站H&R选项,所有种子设置为H&R种子")
|
||||
# 由于缓存原因,这里不能直接改torrents,在后续加入任务中调整
|
||||
# for torrent in torrents:
|
||||
# torrent.hit_and_run = True
|
||||
|
||||
# 排除包含订阅的种子
|
||||
if brush_config.except_subscribe:
|
||||
@@ -2068,7 +2053,7 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
torrents_size = self.__calculate_seeding_torrents_size(torrent_tasks=torrent_tasks)
|
||||
|
||||
logger.info(f"正在准备种子刷流,数量:{len(torrents)}")
|
||||
logger.info(f"正在准备种子刷流,数量 {len(torrents)}")
|
||||
|
||||
# 过滤种子
|
||||
for torrent in torrents:
|
||||
@@ -2078,6 +2063,8 @@ class BrushFlow(_PluginBase):
|
||||
if not pre_condition_passed:
|
||||
return False
|
||||
|
||||
logger.debug(f"种子详情:{torrent}")
|
||||
|
||||
# 判断能否通过保种体积刷流条件
|
||||
size_condition_passed, reason = self.__evaluate_size_condition_for_brush(torrents_size=torrents_size,
|
||||
add_torrent_size=torrent.size)
|
||||
@@ -2098,8 +2085,8 @@ class BrushFlow(_PluginBase):
|
||||
logger.warn(f"{torrent.title} 添加刷流任务失败!")
|
||||
continue
|
||||
|
||||
# 保存任务信息
|
||||
torrent_tasks[hash_string] = {
|
||||
# 触发刷流下载时间并保存任务信息
|
||||
torrent_task = {
|
||||
"site": siteinfo.id,
|
||||
"site_name": siteinfo.name,
|
||||
"title": torrent.title,
|
||||
@@ -2134,6 +2121,12 @@ class BrushFlow(_PluginBase):
|
||||
"time": time.time()
|
||||
}
|
||||
|
||||
self.eventmanager.send_event(etype=EventType.PluginAction, data={
|
||||
"action": "brushflow_download_added",
|
||||
"data": torrent_task
|
||||
})
|
||||
torrent_tasks[hash_string] = torrent_task
|
||||
|
||||
# 统计数据
|
||||
torrents_size += torrent.size
|
||||
statistic_info["count"] += 1
|
||||
@@ -2306,7 +2299,8 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
return True, None
|
||||
|
||||
def __log_brush_conditions(self, passed: bool, reason: str, torrent: Any = None):
|
||||
@staticmethod
|
||||
def __log_brush_conditions(passed: bool, reason: str, torrent: Any = None):
|
||||
"""
|
||||
记录刷流日志
|
||||
"""
|
||||
@@ -2314,9 +2308,7 @@ class BrushFlow(_PluginBase):
|
||||
if not torrent:
|
||||
logger.warn(f"没有通过前置刷流条件校验,原因:{reason}")
|
||||
else:
|
||||
brush_config = self.__get_brush_config()
|
||||
if brush_config.log_more:
|
||||
logger.warn(f"种子没有通过刷流条件校验,原因:{reason} 种子:{torrent.title}|{torrent.description}")
|
||||
logger.debug(f"种子没有通过刷流条件校验,原因:{reason} 种子:{torrent.title}|{torrent.description}")
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -2372,34 +2364,57 @@ class BrushFlow(_PluginBase):
|
||||
# 更新刷流任务列表中在下载器中删除的种子为删除状态
|
||||
self.__update_undeleted_torrents_missing_in_downloader(torrent_tasks, torrent_check_hashes, check_torrents)
|
||||
|
||||
# 排除MoviePilot种子
|
||||
if check_torrents and brush_config.except_tags:
|
||||
check_torrents = self.__filter_torrents_by_tag(torrents=check_torrents,
|
||||
exclude_tag=settings.TORRENT_TAG)
|
||||
# 根据配置的标签进行种子排除
|
||||
if check_torrents:
|
||||
logger.info(f"当前刷流任务共 {len(check_torrents)} 个有效种子,正在准备按设定的种子标签进行排除")
|
||||
# 初始化一个空的列表来存储需要排除的标签
|
||||
tags_to_exclude = set()
|
||||
# 如果 except_tags 配置为 True,将 settings.TORRENT_TAG 添加到排除列表中(前提是它不为空且不是纯空白)
|
||||
if brush_config.except_tags and settings.TORRENT_TAG.strip():
|
||||
tags_to_exclude.add(settings.TORRENT_TAG.strip())
|
||||
# 如果 delete_except_tags 非空且不是纯空白,则添加到排除列表中
|
||||
if brush_config.delete_except_tags and brush_config.delete_except_tags.strip():
|
||||
tags_to_exclude.update(tag.strip() for tag in brush_config.delete_except_tags.split(','))
|
||||
# 将所有需要排除的标签组合成一个字符串,每个标签之间用逗号分隔
|
||||
combined_tags = ",".join(tags_to_exclude)
|
||||
if combined_tags: # 确保有标签需要排除
|
||||
pre_filter_count = len(check_torrents) # 获取过滤前的任务数量
|
||||
check_torrents = self.__filter_torrents_by_tag(torrents=check_torrents, exclude_tag=combined_tags)
|
||||
post_filter_count = len(check_torrents) # 获取过滤后的任务数量
|
||||
excluded_count = pre_filter_count - post_filter_count # 计算被排除的任务数量
|
||||
logger.info(
|
||||
f"有效种子数 {pre_filter_count},排除标签 '{combined_tags}' 后,"
|
||||
f"剩余种子数 {post_filter_count},排除种子数 {excluded_count}")
|
||||
else:
|
||||
logger.info("没有配置有效的排除标签,所有种子均参与后续处理")
|
||||
|
||||
need_delete_hashes = []
|
||||
|
||||
# 如果配置了动态删除以及删种阈值,则根据动态删种进行分组处理
|
||||
if brush_config.proxy_delete and brush_config.delete_size_range:
|
||||
logger.info("已开启动态删种,按系统默认动态删种条件开始检查任务")
|
||||
proxy_delete_hashes = self.__delete_torrent_for_proxy(torrents=check_torrents,
|
||||
torrent_tasks=torrent_tasks) or []
|
||||
need_delete_hashes.extend(proxy_delete_hashes)
|
||||
# 否则均认为是没有开启动态删种
|
||||
# 种子删除检查
|
||||
if not check_torrents:
|
||||
logger.info("没有需要检查的任务,跳过")
|
||||
else:
|
||||
logger.info("没有开启动态删种,按用户设置删种条件开始检查任务")
|
||||
not_proxy_delete_hashes = self.__delete_torrent_for_evaluate_conditions(torrents=check_torrents,
|
||||
torrent_tasks=torrent_tasks) or []
|
||||
need_delete_hashes.extend(not_proxy_delete_hashes)
|
||||
need_delete_hashes = []
|
||||
|
||||
if need_delete_hashes:
|
||||
# 如果是QB,则重新汇报Tracker
|
||||
if brush_config.downloader == "qbittorrent":
|
||||
self.__qb_torrents_reannounce(torrent_hashes=need_delete_hashes)
|
||||
# 删除种子
|
||||
if downloader.delete_torrents(ids=need_delete_hashes, delete_file=True):
|
||||
for torrent_hash in need_delete_hashes:
|
||||
torrent_tasks[torrent_hash]["deleted"] = True
|
||||
# 如果配置了动态删除以及删种阈值,则根据动态删种进行分组处理
|
||||
if brush_config.proxy_delete and brush_config.delete_size_range:
|
||||
logger.info("已开启动态删种,按系统默认动态删种条件开始检查任务")
|
||||
proxy_delete_hashes = self.__delete_torrent_for_proxy(torrents=check_torrents,
|
||||
torrent_tasks=torrent_tasks) or []
|
||||
need_delete_hashes.extend(proxy_delete_hashes)
|
||||
# 否则均认为是没有开启动态删种
|
||||
else:
|
||||
logger.info("没有开启动态删种,按用户设置删种条件开始检查任务")
|
||||
not_proxy_delete_hashes = self.__delete_torrent_for_evaluate_conditions(torrents=check_torrents,
|
||||
torrent_tasks=torrent_tasks) or []
|
||||
need_delete_hashes.extend(not_proxy_delete_hashes)
|
||||
|
||||
if need_delete_hashes:
|
||||
# 如果是QB,则重新汇报Tracker
|
||||
if brush_config.downloader == "qbittorrent":
|
||||
self.__qb_torrents_reannounce(torrent_hashes=need_delete_hashes)
|
||||
# 删除种子
|
||||
if downloader.delete_torrents(ids=need_delete_hashes, delete_file=True):
|
||||
for torrent_hash in need_delete_hashes:
|
||||
torrent_tasks[torrent_hash]["deleted"] = True
|
||||
|
||||
self.__update_and_save_statistic_info(torrent_tasks)
|
||||
|
||||
@@ -2618,8 +2633,7 @@ class BrushFlow(_PluginBase):
|
||||
reason=reason)
|
||||
logger.info(f"站点:{site_name},{reason},删除种子:{torrent_title}|{torrent_desc}")
|
||||
else:
|
||||
if brush_config.log_more:
|
||||
logger.info(f"站点:{site_name},{reason},不删除种子:{torrent_title}|{torrent_desc}")
|
||||
logger.debug(f"站点:{site_name},{reason},不删除种子:{torrent_title}|{torrent_desc}")
|
||||
|
||||
return delete_hashes
|
||||
|
||||
@@ -2657,8 +2671,7 @@ class BrushFlow(_PluginBase):
|
||||
reason=reason)
|
||||
logger.info(f"站点:{site_name},{reason},删除种子:{torrent_title}|{torrent_desc}")
|
||||
else:
|
||||
if brush_config.log_more:
|
||||
logger.info(f"站点:{site_name},{reason},不删除种子:{torrent_title}|{torrent_desc}")
|
||||
logger.debug(f"站点:{site_name},{reason},不删除种子:{torrent_title}|{torrent_desc}")
|
||||
|
||||
return delete_hashes
|
||||
|
||||
@@ -2914,7 +2927,7 @@ class BrushFlow(_PluginBase):
|
||||
"active_downloaded": active_downloaded
|
||||
})
|
||||
|
||||
logger.info(f"刷流任务统计数据:总任务数:{total_count},活跃任务数:{active_count},已删除:{total_deleted},"
|
||||
logger.info(f"刷流任务统计数据,总任务数:{total_count},活跃任务数:{active_count},已删除:{total_deleted},"
|
||||
f"待归档:{total_unarchived},"
|
||||
f"活跃上传量:{StringUtils.str_filesize(active_uploaded)},"
|
||||
f"活跃下载量:{StringUtils.str_filesize(active_downloaded)},"
|
||||
@@ -3030,11 +3043,11 @@ class BrushFlow(_PluginBase):
|
||||
"clear_task": brush_config.clear_task,
|
||||
"archive_task": brush_config.archive_task,
|
||||
"except_tags": brush_config.except_tags,
|
||||
"delete_except_tags": brush_config.delete_except_tags,
|
||||
"except_subscribe": brush_config.except_subscribe,
|
||||
"brush_sequential": brush_config.brush_sequential,
|
||||
"proxy_download": brush_config.proxy_download,
|
||||
"proxy_delete": brush_config.proxy_delete,
|
||||
"log_more": brush_config.log_more,
|
||||
"active_time_range": brush_config.active_time_range,
|
||||
"downloader_monitor": brush_config.downloader_monitor,
|
||||
"qb_category": brush_config.qb_category,
|
||||
@@ -3131,7 +3144,7 @@ class BrushFlow(_PluginBase):
|
||||
data = data.get(key)
|
||||
if not data:
|
||||
return None
|
||||
logger.info(f"获取到下载地址:{data}")
|
||||
logger.debug(f"获取到下载地址:{data}")
|
||||
return data
|
||||
return None
|
||||
|
||||
@@ -3201,8 +3214,7 @@ class BrushFlow(_PluginBase):
|
||||
# 获取种子Hash
|
||||
torrent_hash = self.qb.get_torrent_id_by_tag(tags=tag)
|
||||
if not torrent_hash:
|
||||
logger.error(f"{brush_config.downloader} 获取种子Hash失败"
|
||||
f"{',请尝试启用「代理下载种子」配置项' if not brush_config.proxy_download else ''}")
|
||||
logger.error(f"{brush_config.downloader} 获取种子Hash失败,详细信息请查看 README")
|
||||
return None
|
||||
return torrent_hash
|
||||
return None
|
||||
@@ -3705,14 +3717,21 @@ class BrushFlow(_PluginBase):
|
||||
|
||||
def __filter_torrents_by_tag(self, torrents: List[Any], exclude_tag: str) -> List[Any]:
|
||||
"""
|
||||
根据标签过滤torrents
|
||||
根据标签过滤torrents,排除标签格式为逗号分隔的字符串,例如 "MOVIEPILOT, H&R"
|
||||
"""
|
||||
# 如果排除标签字符串为空,则返回原始列表
|
||||
if not exclude_tag:
|
||||
return torrents
|
||||
|
||||
# 将 exclude_tag 字符串分割成一个集合,并去除每个标签两端的空白,忽略空白标签并自动去重
|
||||
exclude_tags = set(tag.strip() for tag in exclude_tag.split(',') if tag.strip())
|
||||
|
||||
filter_torrents = []
|
||||
for torrent in torrents:
|
||||
# 使用 __get_label 方法获取每个 torrent 的标签列表
|
||||
labels = self.__get_label(torrent)
|
||||
# 如果排除的标签不在这个列表中,则添加到过滤后的列表
|
||||
if exclude_tag not in labels:
|
||||
# 检查是否有任何一个排除标签存在于标签列表中
|
||||
if not any(exclude in labels for exclude in exclude_tags):
|
||||
filter_torrents.append(torrent)
|
||||
return filter_torrents
|
||||
|
||||
@@ -3766,7 +3785,8 @@ class BrushFlow(_PluginBase):
|
||||
for key in set(self._subscribe_infos) - current_keys:
|
||||
del self._subscribe_infos[key]
|
||||
|
||||
logger.info(f"订阅标题匹配完成,当前订阅的标题集合为:{self._subscribe_infos}")
|
||||
logger.info("已订阅标题匹配完成")
|
||||
logger.debug(f"当前订阅的标题集合为:{self._subscribe_infos}")
|
||||
unique_titles = {title for titles in self._subscribe_infos.values() for title in titles}
|
||||
return unique_titles
|
||||
|
||||
|
||||
Reference in New Issue
Block a user