mirror of
https://github.com/jxxghp/MoviePilot-Plugins.git
synced 2026-03-27 10:05:57 +00:00
Merge pull request #168 from InfinityPacer/feature_dev
This commit is contained in:
@@ -226,7 +226,7 @@
|
||||
"BrushFlow": {
|
||||
"name": "站点刷流",
|
||||
"description": "自动托管刷流,将会提高对应站点的访问频率。",
|
||||
"version": "2.2",
|
||||
"version": "2.3",
|
||||
"icon": "brush.jpg",
|
||||
"author": "jxxghp,InfinityPacer",
|
||||
"level": 2
|
||||
|
||||
@@ -7,6 +7,7 @@ import time
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Event
|
||||
from typing import Any, List, Dict, Tuple, Optional, Union, Set
|
||||
from urllib.parse import urlparse, parse_qs, unquote
|
||||
|
||||
import pytz
|
||||
from app import schemas
|
||||
@@ -184,7 +185,7 @@ class BrushFlow(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "brush.jpg"
|
||||
# 插件版本
|
||||
plugin_version = "2.2"
|
||||
plugin_version = "2.3"
|
||||
# 插件作者
|
||||
plugin_author = "jxxghp,InfinityPacer"
|
||||
# 作者主页
|
||||
@@ -1267,6 +1268,10 @@ class BrushFlow(_PluginBase):
|
||||
'component': 'td',
|
||||
'text': "是" if data.get("hit_and_run") else "否"
|
||||
},
|
||||
{
|
||||
'component': 'td',
|
||||
'text': f"{data.get('seeding_time') / 3600:.1f}" if data.get('seeding_time') else "N/A"
|
||||
},
|
||||
{
|
||||
'component': 'td',
|
||||
'props': {
|
||||
@@ -1631,6 +1636,13 @@ class BrushFlow(_PluginBase):
|
||||
},
|
||||
'text': 'HR'
|
||||
},
|
||||
{
|
||||
'component': 'th',
|
||||
'props': {
|
||||
'class': 'text-start ps-4'
|
||||
},
|
||||
'text': '做种时间'
|
||||
},
|
||||
{
|
||||
'component': 'th',
|
||||
'props': {
|
||||
@@ -1818,6 +1830,7 @@ class BrushFlow(_PluginBase):
|
||||
"ratio": 0,
|
||||
"downloaded": 0,
|
||||
"uploaded": 0,
|
||||
"seeding_time": 0,
|
||||
"deleted": False,
|
||||
"time": time.time()
|
||||
}
|
||||
@@ -1928,9 +1941,9 @@ class BrushFlow(_PluginBase):
|
||||
if brush_config.size:
|
||||
sizes = [float(size) * 1024 ** 3 for size in brush_config.size.split("-")]
|
||||
if len(sizes) == 1 and torrent.size < sizes[0]:
|
||||
return False, "种子大小不符合条件"
|
||||
return False, f"种子大小 {self.__bytes_to_gb(torrent.size):.1f} GB,不符合条件"
|
||||
elif len(sizes) > 1 and not sizes[0] <= torrent.size <= sizes[1]:
|
||||
return False, "种子大小不在指定范围内"
|
||||
return False, f"种子大小 {self.__bytes_to_gb(torrent.size):.1f} GB,不在指定范围内"
|
||||
|
||||
# 做种人数
|
||||
if brush_config.seeder:
|
||||
@@ -1939,12 +1952,12 @@ class BrushFlow(_PluginBase):
|
||||
if len(seeders_range) == 1:
|
||||
# 当做种人数大于该数字时,不符合条件
|
||||
if torrent.seeders > seeders_range[0]:
|
||||
return False, "做种人数超过单个指定值"
|
||||
return False, f"做种人数 {torrent.seeders},超过单个指定值"
|
||||
# 如果指定了一个范围
|
||||
elif len(seeders_range) > 1:
|
||||
# 检查做种人数是否在指定的范围内(包括边界)
|
||||
if not (seeders_range[0] <= torrent.seeders <= seeders_range[1]):
|
||||
return False, "做种人数不在指定范围内"
|
||||
return False, f"做种人数 {torrent.seeders},不在指定范围内"
|
||||
|
||||
# 发布时间
|
||||
pubdate_minutes = self.__get_pubminutes(torrent.pubdate)
|
||||
@@ -1954,11 +1967,11 @@ class BrushFlow(_PluginBase):
|
||||
if len(pubtimes) == 1:
|
||||
# 单个值:选择发布时间小于等于该值的种子
|
||||
if pubdate_minutes > pubtimes[0]:
|
||||
return False, "发布时间不符合条件"
|
||||
return False, f"发布时间 {pubdate_minutes:.0f} 分钟前,不符合条件"
|
||||
else:
|
||||
# 范围值:选择发布时间在范围内的种子
|
||||
if not (pubtimes[0] <= pubdate_minutes <= pubtimes[1]):
|
||||
return False, "发布时间不在指定范围内"
|
||||
return False, f"发布时间 {pubdate_minutes:.0f} 分钟前,不在指定范围内"
|
||||
|
||||
return True, None
|
||||
|
||||
@@ -2024,20 +2037,22 @@ class BrushFlow(_PluginBase):
|
||||
# 先更新刷流任务的最新状态,上下传,分享率
|
||||
self.__update_torrent_tasks_state(torrents=check_torrents, torrent_tasks=torrent_tasks)
|
||||
|
||||
# 排除MoviePilot种子
|
||||
if check_torrents and brush_config.except_tags:
|
||||
check_torrents = self.__filter_torrents_by_tag(torrents=check_torrents,
|
||||
exclude_tag=settings.TORRENT_TAG)
|
||||
|
||||
# 先通过获取的全量种子,判断已经被删除,但是任务记录中还没有被标记删除的种子
|
||||
undeleted_hashes = self.__get_undeleted_torrents_missing_in_downloader(torrent_tasks, torrent_check_hashes,
|
||||
check_torrents) or []
|
||||
|
||||
# 这里提前把已经被删除的种子进行标记,避免开启动态删除种子统计体积有时差
|
||||
if undeleted_hashes:
|
||||
for torrent_hash in undeleted_hashes:
|
||||
torrent_tasks[torrent_hash]["deleted"] = True
|
||||
|
||||
# 排除MoviePilot种子
|
||||
if check_torrents and brush_config.except_tags:
|
||||
check_torrents = self.__filter_torrents_by_tag(torrents=check_torrents,
|
||||
exclude_tag=settings.TORRENT_TAG)
|
||||
|
||||
need_delete_hashes = []
|
||||
|
||||
# 如果配置了删种阈值,则根据动态删种进行分组处理
|
||||
if brush_config.proxy_delete and brush_config.delete_size_range:
|
||||
logger.info("已开启动态删种,按系统默认动态删种条件开始检查任务")
|
||||
@@ -2080,6 +2095,7 @@ class BrushFlow(_PluginBase):
|
||||
"downloaded": torrent_info.get("downloaded"),
|
||||
"uploaded": torrent_info.get("uploaded"),
|
||||
"ratio": torrent_info.get("ratio"),
|
||||
"seeding_time": torrent_info.get("seeding_time"),
|
||||
})
|
||||
|
||||
def __update_seeding_tasks_based_on_tags(self, torrent_tasks: Dict[str, dict], unmanaged_tasks: Dict[str, dict],
|
||||
@@ -2274,7 +2290,7 @@ class BrushFlow(_PluginBase):
|
||||
torrent_info_map[self.__get_hash(torrent)].get("total_size", 0) for torrent in proxy_delete_torrents if
|
||||
self.__get_hash(torrent) in proxy_delete_hashes)
|
||||
|
||||
# 在完成初始删除步骤后,如果总体积仍然超过最小阈值,则进一步找到已完成种子并排除HR种子后按加入时间正序进行删除
|
||||
# 在完成初始删除步骤后,如果总体积仍然超过最小阈值,则进一步找到已完成种子并排除HR种子后按做种时间正序进行删除
|
||||
if total_torrent_size > min_size:
|
||||
# 重新计算当前的种子列表,排除已删除的种子
|
||||
remaining_hashes = list(
|
||||
@@ -2285,10 +2301,10 @@ class BrushFlow(_PluginBase):
|
||||
remaining_hashes = {self.__get_hash(torrent) for torrent in completed_torrents}
|
||||
remaining_torrents = [(_hash, torrent_info_map[_hash]) for _hash in remaining_hashes]
|
||||
|
||||
# 准备一个列表,用于存放满足条件的种子,即非HR种子且有明确加入时间
|
||||
filtered_torrents = [(_hash, info['add_on']) for _hash, info in remaining_torrents if
|
||||
# 准备一个列表,用于存放满足条件的种子,即非HR种子且有明确做种时间
|
||||
filtered_torrents = [(_hash, info['seeding_time']) for _hash, info in remaining_torrents if
|
||||
not torrent_tasks[_hash].get("hit_and_run", False)]
|
||||
sorted_torrents = sorted(filtered_torrents, key=lambda x: x[1])
|
||||
sorted_torrents = sorted(filtered_torrents, key=lambda x: x[1], reverse=True)
|
||||
|
||||
# 进行额外的删除操作,直到满足最小阈值或没有更多种子可删除
|
||||
for torrent_hash, _ in sorted_torrents:
|
||||
@@ -2305,10 +2321,13 @@ class BrushFlow(_PluginBase):
|
||||
site_name = torrent_task.get("site_name", "")
|
||||
torrent_title = torrent_task.get("title", "")
|
||||
torrent_desc = torrent_task.get("description", "")
|
||||
reason = "触发动态删除,系统自动删除"
|
||||
self.__send_delete_message(site_name=site_name, torrent_title=torrent_title, torrent_desc=torrent_desc,
|
||||
reason=reason)
|
||||
logger.info(f"站点:{site_name},{reason},删除种子:{torrent_title}|{torrent_desc}")
|
||||
seeding_time = torrent_task.get("seeding_time", 0)
|
||||
if seeding_time:
|
||||
reason = f"触发动态删除,做种时间 {seeding_time / 3600:.1f} 小时,系统自动删除"
|
||||
self.__send_delete_message(site_name=site_name, torrent_title=torrent_title,
|
||||
torrent_desc=torrent_desc,
|
||||
reason=reason)
|
||||
logger.info(f"站点:{site_name},{reason},删除种子:{torrent_title}|{torrent_desc}")
|
||||
|
||||
msg = f"已完成 {len(need_delete_hashes)} 个种子删除,当前做种体积 {self.__bytes_to_gb(total_torrent_size):.1f} GB"
|
||||
self.post_message(mtype=NotificationType.SiteMessage, title="【刷流任务种子删除】", text=msg)
|
||||
@@ -2347,11 +2366,7 @@ class BrushFlow(_PluginBase):
|
||||
"""
|
||||
torrent_info = self.__get_torrent_info(torrent=torrent)
|
||||
|
||||
trackers = [tracker.get("url") for tracker in (torrent.trackers or []) if
|
||||
tracker.get("tier", -1) >= 0 and tracker.get("url")]
|
||||
trackers.append(torrent_info.get("tracker"))
|
||||
|
||||
site_id, site_name = self.__get_site_by_tracker(trackers=trackers)
|
||||
site_id, site_name = self.__get_site_by_torrent(torrent=torrent)
|
||||
|
||||
torrent_task = {
|
||||
"site": site_id,
|
||||
@@ -2627,7 +2642,7 @@ class BrushFlow(_PluginBase):
|
||||
data = data.get(key)
|
||||
if not data:
|
||||
return None
|
||||
# logger.info(f"获取到下载地址:{data}")
|
||||
logger.info(f"获取到下载地址:{data}")
|
||||
return data
|
||||
return None
|
||||
|
||||
@@ -2649,11 +2664,14 @@ class BrushFlow(_PluginBase):
|
||||
download_dir = brush_config.save_path or None
|
||||
# 获取下载链接
|
||||
torrent_content = torrent.enclosure
|
||||
# 部分站点下载种子不需要传递Cookie
|
||||
need_download_cookie = True
|
||||
if torrent_content.startswith("["):
|
||||
torrent_content = self.__get_redict_url(url=torrent_content,
|
||||
proxies=settings.PROXY if torrent.site_proxy else None,
|
||||
ua=torrent.site_ua,
|
||||
cookie=torrent.site_cookie)
|
||||
need_download_cookie = False
|
||||
if not torrent_content:
|
||||
logger.error(f"获取下载链接失败:{torrent.title}")
|
||||
return None
|
||||
@@ -2668,7 +2686,7 @@ class BrushFlow(_PluginBase):
|
||||
tag = StringUtils.generate_random_str(10)
|
||||
# 如果开启代理下载以及种子地址不是磁力地址,则请求种子到内存再传入下载器
|
||||
if brush_config.proxy_download and not torrent_content.startswith("magnet"):
|
||||
response = RequestUtils(cookies=torrent.site_cookie,
|
||||
response = RequestUtils(cookies=torrent.site_cookie if need_download_cookie else None,
|
||||
proxies=settings.PROXY if torrent.site_proxy else None,
|
||||
ua=torrent.site_ua).get_res(url=torrent_content)
|
||||
if response and response.ok:
|
||||
@@ -2678,7 +2696,7 @@ class BrushFlow(_PluginBase):
|
||||
if torrent_content:
|
||||
state = self.qb.add_torrent(content=torrent_content,
|
||||
download_dir=download_dir,
|
||||
cookie=torrent.site_cookie,
|
||||
cookie=torrent.site_cookie if need_download_cookie else None,
|
||||
tag=["已整理", brush_config.brush_tag, tag],
|
||||
upload_limit=up_speed,
|
||||
download_limit=down_speed)
|
||||
@@ -2699,7 +2717,7 @@ class BrushFlow(_PluginBase):
|
||||
return None
|
||||
# 如果开启代理下载以及种子地址不是磁力地址,则请求种子到内存再传入下载器
|
||||
if brush_config.proxy_download and not torrent_content.startswith("magnet"):
|
||||
response = RequestUtils(cookies=torrent.site_cookie,
|
||||
response = RequestUtils(cookies=torrent.site_cookie if need_download_cookie else None,
|
||||
proxies=settings.PROXY if torrent.site_proxy else None,
|
||||
ua=torrent.site_ua).get_res(url=torrent_content)
|
||||
if response and response.ok:
|
||||
@@ -2709,7 +2727,7 @@ class BrushFlow(_PluginBase):
|
||||
if torrent_content:
|
||||
torrent = self.tr.add_torrent(content=torrent_content,
|
||||
download_dir=download_dir,
|
||||
cookie=torrent.site_cookie,
|
||||
cookie=torrent.site_cookie if need_download_cookie else None,
|
||||
labels=["已整理", brush_config.brush_tag])
|
||||
if not torrent:
|
||||
return None
|
||||
@@ -3313,10 +3331,26 @@ class BrushFlow(_PluginBase):
|
||||
# 情况2: 时间段跨越午夜
|
||||
return now >= start_time or now <= end_time
|
||||
|
||||
def __get_site_by_tracker(self, trackers: list[str]) -> Tuple[int, str]:
|
||||
def __get_site_by_torrent(self, torrent: Any) -> Tuple[int, str]:
|
||||
"""
|
||||
根据tracker获取站点信息
|
||||
"""
|
||||
trackers = []
|
||||
try:
|
||||
tracker_url = torrent.get("tracker")
|
||||
if tracker_url:
|
||||
trackers.append(tracker_url)
|
||||
|
||||
magnet_link = torrent.get("magnet_uri")
|
||||
if magnet_link:
|
||||
query_params = parse_qs(urlparse(magnet_link).query)
|
||||
encoded_tracker_urls = query_params.get('tr', [])
|
||||
# 解码tracker URLs然后扩展到trackers列表中
|
||||
decoded_tracker_urls = [unquote(url) for url in encoded_tracker_urls]
|
||||
trackers.extend(decoded_tracker_urls)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
domain = "未知"
|
||||
if not trackers:
|
||||
return 0, domain
|
||||
@@ -3329,6 +3363,8 @@ class BrushFlow(_PluginBase):
|
||||
}
|
||||
|
||||
for tracker in trackers:
|
||||
if not tracker:
|
||||
continue
|
||||
# 检查tracker是否包含特定的关键字,并进行相应的映射
|
||||
for key, mapped_domain in tracker_mappings.items():
|
||||
if key in tracker:
|
||||
|
||||
Reference in New Issue
Block a user