From 762d3f8ed8fec5e4d98f2792990c794d7747d4f3 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Thu, 2 May 2024 16:39:56 +0800 Subject: [PATCH 01/10] =?UTF-8?q?fix=20brushflow=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=AB=99=E7=82=B9=E5=88=B7=E6=B5=81=E5=88=B0?= =?UTF-8?q?=E7=9B=B8=E5=90=8C=E7=A7=8D=E5=AD=90=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=95=B0=E6=8D=AE=E9=A1=B5=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E9=97=AA=E7=83=81=EF=BC=8C=E9=83=A8=E5=88=86=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- plugins/brushflow/__init__.py | 75 +++++++++++++++++++++++------------ 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 33b78e9..23c25da 100644 --- a/package.json +++ b/package.json @@ -298,11 +298,12 @@ "name": "站点刷流", "description": "自动托管刷流,将会提高对应站点的访问频率。", "labels": "刷流", - "version": "2.9", + "version": "3.0", "icon": "brush.jpg", "author": "jxxghp,InfinityPacer", "level": 2, "history": { + "v3.0": "优化不同站点刷流到相同种子的逻辑,修复数据页滚动闪烁,部分日志优化", "v2.9": "优化动态删除消息推送,优化配置页UI显示及部分配置项,支持配置种子分类以及开启自动分类管理,取消单独适配站点时区逻辑,可通过配置项「pubtime」自行适配", "v2.8": "优化UI显示以及提升性能", "v2.7": "动态删除种子规则调整(请注意查阅插件文档),站点独立配置样式优化、日志优化,修复部分配置项无法配置小数的问题,修复部分场景可能导致重复下载的问题", diff --git a/plugins/brushflow/__init__.py b/plugins/brushflow/__init__.py index 555aee0..57ae976 100644 --- a/plugins/brushflow/__init__.py +++ b/plugins/brushflow/__init__.py @@ -10,6 +10,9 @@ from typing import Any, List, Dict, Tuple, Optional, Union, Set from urllib.parse import urlparse, parse_qs, unquote import pytz +from app.helper.sites import SitesHelper +from apscheduler.schedulers.background import BackgroundScheduler + from app import schemas from app.chain.torrents import TorrentsChain from app.core.config import settings @@ -17,7 +20,6 @@ from app.core.context import MediaInfo from app.core.metainfo import MetaInfo from app.db.site_oper import SiteOper from app.db.subscribe_oper import SubscribeOper -from app.helper.sites import SitesHelper from app.log import logger from app.modules.qbittorrent import Qbittorrent from app.modules.transmission import Transmission @@ -25,7 +27,6 @@ from app.plugins import _PluginBase from app.schemas import NotificationType, TorrentInfo, MediaType from app.utils.http import RequestUtils from app.utils.string import StringUtils -from apscheduler.schedulers.background import BackgroundScheduler lock = threading.Lock() @@ -146,9 +147,10 @@ class BrushConfig: @staticmethod def get_demo_site_config() -> str: - desc = ("// 以下为配置示例,请参考:https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md 进行配置\n" - "// 如与全局保持一致的配置项,请勿在站点配置中配置\n" - "// 注意无关内容需使用 // 注释\n") + desc = ( + "// 以下为配置示例,请参考:https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/plugins/brushflowlowfreq/README.md 进行配置\n" + "// 如与全局保持一致的配置项,请勿在站点配置中配置\n" + "// 注意无关内容需使用 // 注释\n") config = """[{ "sitename": "站点1", "seed_time": 96, @@ -249,7 +251,7 @@ class BrushFlow(_PluginBase): # 插件图标 plugin_icon = "brush.jpg" # 插件版本 - plugin_version = "2.9" + plugin_version = "3.0" # 插件作者 plugin_author = "jxxghp,InfinityPacer" # 作者主页 @@ -1239,7 +1241,7 @@ class BrushFlow(_PluginBase): "component": "VSwitch", "props": { "model": "dialog_closed", - "label": "设置站点" + "label": "打开站点配置窗口" } } ] @@ -1342,15 +1344,20 @@ class BrushFlow(_PluginBase): 'content': [ { 'component': 'span', - 'text': '部分配置项以及细节请参考:' + 'text': '注意:详细配置说明以及刷流规则请参考:' }, { 'component': 'a', 'props': { - 'href': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md', + 'href': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/plugins/brushflowlowfreq/README.md', 'target': '_blank' }, - 'text': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md' + 'content': [ + { + 'component': 'u', + 'text': 'README' + } + ] } ] } @@ -1449,10 +1456,15 @@ class BrushFlow(_PluginBase): { 'component': 'a', 'props': { - 'href': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md', + 'href': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/plugins/brushflowlowfreq/README.md', 'target': '_blank' }, - 'text': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md' + 'content': [ + { + 'component': 'u', + 'text': 'README' + } + ] } ] } @@ -1551,6 +1563,11 @@ class BrushFlow(_PluginBase): return [ { 'component': 'VRow', + 'props': { + 'style': { + 'overflow': 'hidden', + } + }, 'content': [ # 总上传量 { @@ -2149,6 +2166,12 @@ class BrushFlow(_PluginBase): torrent_tasks.values()): return False, "重复种子" + # 不同站点如果遇到相同种子,判断前一个种子是否已经在做种,否则排除处理 + if torrent.title: + if any(torrent.site_name != f"{task.get('site_name')}" and torrent.title == f"{task.get('title')}" + and not task.get("seed_time") for task in torrent_tasks.values()): + return False, "其他站点存在尚未下载完成的相同种子" + # 促销条件 if brush_config.freeleech and torrent.downloadvolumefactor != 0: return False, "非免费种子" @@ -2286,15 +2309,15 @@ class BrushFlow(_PluginBase): # 如果配置了动态删除以及删种阈值,则根据动态删种进行分组处理 if brush_config.proxy_delete and brush_config.delete_size_range: logger.info("已开启动态删种,按系统默认动态删种条件开始检查任务") - proxy_delete_hashs = self.__delete_torrent_for_proxy(torrents=check_torrents, - torrent_tasks=torrent_tasks) or [] - need_delete_hashes.extend(proxy_delete_hashs) + 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_hashs = self.__delete_torrent_for_evaluate_conditions(torrents=check_torrents, - torrent_tasks=torrent_tasks) or [] - need_delete_hashes.extend(not_proxy_delete_hashs) + 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: if downloader.delete_torrents(ids=need_delete_hashes, delete_file=True): @@ -2493,7 +2516,7 @@ class BrushFlow(_PluginBase): 根据条件删除种子并获取已删除列表 """ brush_config = self.__get_brush_config() - delete_hashs = [] + delete_hashes = [] for torrent in torrents: torrent_hash = self.__get_hash(torrent) @@ -2512,8 +2535,8 @@ class BrushFlow(_PluginBase): torrent_info=torrent_info, torrent_task=torrent_task) if should_delete: - delete_hashs.append(torrent_hash) - reason = "触发动态删除," + reason if proxy_delete else reason + delete_hashes.append(torrent_hash) + reason = "触发动态删除阈值," + reason if proxy_delete else 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}") @@ -2521,7 +2544,7 @@ class BrushFlow(_PluginBase): if brush_config.log_more: logger.info(f"站点:{site_name},{reason},不删除种子:{torrent_title}|{torrent_desc}") - return delete_hashs + return delete_hashes def __delete_torrent_for_evaluate_proxy_pre_conditions(self, torrents: List[Any], torrent_tasks: Dict[str, dict]) -> List: @@ -2529,7 +2552,7 @@ class BrushFlow(_PluginBase): 根据动态删除前置条件排除H&R种子后删除种子并获取已删除列表 """ brush_config = self.__get_brush_config() - delete_hashs = [] + delete_hashes = [] for torrent in torrents: torrent_hash = self.__get_hash(torrent) @@ -2552,7 +2575,7 @@ class BrushFlow(_PluginBase): should_delete, reason = self.__evaluate_proxy_pre_conditions_for_delete(site_name=site_name, torrent_info=torrent_info) if should_delete: - delete_hashs.append(torrent_hash) + delete_hashes.append(torrent_hash) 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}") @@ -2560,7 +2583,7 @@ class BrushFlow(_PluginBase): if brush_config.log_more: logger.info(f"站点:{site_name},{reason},不删除种子:{torrent_title}|{torrent_desc}") - return delete_hashs + return delete_hashes def __delete_torrent_for_proxy(self, torrents: List[Any], torrent_tasks: Dict[str, dict]) -> List: """ @@ -3557,7 +3580,7 @@ class BrushFlow(_PluginBase): now = datetime.now() return (now - pubdate).total_seconds() // 60 except Exception as e: - print(str(e)) + logger.error(f"发布时间 {pubdate} 获取分钟失败,错误详情: {e}") return 0 @staticmethod From 0cc98b6e98e6e602b5d25c21de41bf84fc117e32 Mon Sep 17 00:00:00 2001 From: luojianquan443 <2569646547@qq.com> Date: Sun, 5 May 2024 15:42:46 +0800 Subject: [PATCH 02/10] =?UTF-8?q?Fix:VCB=E4=BD=9C=E5=93=81=E6=95=B4?= =?UTF-8?q?=E7=90=86=E5=8E=BB=E9=99=A4=E5=A4=96=E9=83=A8=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86=E5=B0=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=A2=9E=E5=BC=BA=E7=A8=B3=E5=AE=9A=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 7 +++-- plugins/vcbanimemonitor/__init__.py | 28 +++++++++-------- plugins/vcbanimemonitor/remeta.py | 38 +++++++++++++++++------- plugins/vcbanimemonitor/requirements.txt | 1 - 4 files changed, 47 insertions(+), 27 deletions(-) delete mode 100644 plugins/vcbanimemonitor/requirements.txt diff --git a/package.json b/package.json index 23c25da..8bfe4ec 100644 --- a/package.json +++ b/package.json @@ -259,10 +259,13 @@ "name": "整理VCB动漫压制组作品", "description": "提高部分VCB-Studio作品的识别准确率,将VCB-Studio的作品统一转移到指定目录同时进行刮削整理", "labels": "文件整理,识别", - "version": "1.7", + "version": "1.7.1", "icon": "vcbmonitor.png", "author": "pixel@qingwa", - "level": 2 + "level": 2, + "history": { + "v1.7.1": "修复偶尔安装失败问题" + } }, "TorrentTransfer": { "name": "自动转移做种", diff --git a/plugins/vcbanimemonitor/__init__.py b/plugins/vcbanimemonitor/__init__.py index a6883d0..56eb939 100644 --- a/plugins/vcbanimemonitor/__init__.py +++ b/plugins/vcbanimemonitor/__init__.py @@ -5,8 +5,8 @@ import threading import time import traceback from pathlib import Path +from time import sleep from typing import List, Tuple, Dict, Any, Optional - import pytz import qbittorrentapi from apscheduler.schedulers.background import BackgroundScheduler @@ -14,12 +14,13 @@ from apscheduler.triggers.cron import CronTrigger from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer from watchdog.observers.polling import PollingObserver - from app import schemas from app.chain.tmdb import TmdbChain from app.chain.transfer import TransferChain from app.core.config import settings from app.core.context import MediaInfo +from app.core.event import eventmanager, Event +from app.core.metainfo import MetaInfoPath from app.db.downloadhistory_oper import DownloadHistoryOper from app.db.transferhistory_oper import TransferHistoryOper from app.log import logger @@ -76,7 +77,7 @@ class VCBAnimeMonitor(_PluginBase): # 插件图标 plugin_icon = "vcbmonitor.png" # 插件版本 - plugin_version = "1.7" + plugin_version = "1.7.1" # 插件作者 plugin_author = "pixel@qingwa" # 作者主页 @@ -155,15 +156,20 @@ class VCBAnimeMonitor(_PluginBase): self._scheduler.add_job(self.send_msg, trigger='interval', seconds=15) self.qb = Qbittorrent() + # 读取目录配置 + monitor_dirs = self._monitor_dirs.split("\n") + if not monitor_dirs: + return + # 启用种子目录监控 if self._torrents_path is not None and Path(self._torrents_path).exists() and self._enabled: # 只取第一个目录作为新的保存 + first_path = monitor_dirs[0] if SystemUtils.is_windows(): - self.new_save_path = self._monitor_dirs.split(':')[0] + ":" + self._monitor_dirs.split(':')[1] + self.new_save_path = first_path.split(':')[0] + ":" + first_path.split(':')[1] else: - self.new_save_path = self._monitor_dirs.split(':')[0] - print(self.new_save_path) - + self.new_save_path = first_path.split(':')[0] + # print(self.new_save_path) try: observer = Observer() self._observer.append(observer) @@ -177,10 +183,6 @@ class VCBAnimeMonitor(_PluginBase): else: logger.info("种子目录为空,不转移qb中正在下载的VCB-Studio文件") - # 读取目录配置 - monitor_dirs = self._monitor_dirs.split("\n") - if not monitor_dirs: - return for mon_path in monitor_dirs: # 格式源目录:目的目录 if not mon_path: @@ -594,6 +596,7 @@ class VCBAnimeMonitor(_PluginBase): def torrent_event(self, event, mon_path: str, text: str): """ 处理种子文件 + :param mon_path: 种子目录 """ evc_path = Path(event.src_path) if not event.is_directory and (evc_path.suffix == ".torrent" or str(evc_path).split('.')[1] == "torrent"): @@ -1009,8 +1012,7 @@ class VCBAnimeMonitor(_PluginBase): 'props': { 'type': 'info', 'variant': 'tonal', - 'text': '核心用法与目录同步插件相同,不同点在于只识别处理VCB-Studio资源,' - '避免与目录同步插件的监控目录相同(否则会同时进行识别)' + 'text': '核心用法与目录同步插件相同,不同点在于只识别处理VCB-Studio资源,\n' '不处理SPs目录下的文件,OVA/OAD集数根据入库顺序累加命名,不保证与TMDB集数匹配' } } diff --git a/plugins/vcbanimemonitor/remeta.py b/plugins/vcbanimemonitor/remeta.py index ea931b0..4624cc7 100644 --- a/plugins/vcbanimemonitor/remeta.py +++ b/plugins/vcbanimemonitor/remeta.py @@ -2,9 +2,6 @@ import concurrent import re from pathlib import Path from typing import List - -import roman - from app.chain.media import MediaChain from app.chain.tmdb import TmdbChain from app.core.metainfo import MetaInfoPath @@ -12,6 +9,26 @@ from app.log import logger from app.schemas import MediaType +def roman_to_int(s) -> int: + """ + :param s: 罗马数字字符串 + 罗马数字转整数 + """ + roman_dict = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + total = 0 + prev_value = 0 + + for char in reversed(s): # 反向遍历罗马数字字符串 + current_value = roman_dict[char] + if current_value >= prev_value: + total += current_value # 如果当前值大于等于前一个值,加上当前值 + else: + total -= current_value # 如果当前值小于前一个值,减去当前值 + prev_value = current_value + + return total + + class ReMeta: # 解析之后的标题: title: str = None @@ -41,7 +58,7 @@ class ReMeta: ] _ova_patterns = [re.compile(r"\[.*?(OVA|OAD).*?]"), re.compile(r"\[\d+\.5]"), - re.compile(r"\[00]")] + re.compile(r"\[00\]")] final_season_patterns = [re.compile('final season', re.IGNORECASE), re.compile('The Final', re.IGNORECASE), @@ -57,13 +74,14 @@ class ReMeta: def handel_file(self, file_path: Path): meta = MetaInfoPath(file_path) self.title = meta.title + self.title = Path(self.title).stem.strip() if 'VCB-Studio' not in meta.title: logger.warn("不属于VCB的作品,不处理!") return None if meta.title.count("[") != 4 and meta.title.count("]") != 4: # 可能是电影,电影只有三组[],因此去除所有[]后只剩下电影名 logger.warn("不符合VCB-Studio的剧集命名规范,跳过剧集模块处理!交给默认处理逻辑") - meta.title = re.sub(r'\[.*?]', '', meta.title).strip() + meta.title = re.sub(r'\[.*?\]', '', meta.title).strip() meta.en_name = meta.title return meta split_title: List[str] | None = self.split_season_ep(self.title) @@ -84,13 +102,12 @@ class ReMeta: return meta # 分离季度部分和集数部分 - @staticmethod - def split_season_ep(pre_title: str): + def split_season_ep(self, pre_title: str): split_ep = re.findall(r"(\[.*?])", pre_title)[1] if not split_ep: logger.warn("未识别出集数位置信息,结束识别!") return None - split_title = re.sub(r"\[.*?]", "", pre_title).strip() + split_title = re.sub(r"\[.*?\]", "", pre_title).strip() logger.info(f"分离出包含季度的部分:{split_title} \n 分离出包含集数的部分: {split_ep}") return [split_title, split_ep] @@ -126,7 +143,7 @@ class ReMeta: match = pattern.search(pre_title) if match: if type(group) == str: - title_season["season"] = int(roman.fromRoman(match.group(int(group)))) + title_season["season"] = roman_to_int(match.group(int(group))) title_season["title"] = re.sub(pattern, "", pre_title).strip() else: title_season["season"] = int(match.group(group)) @@ -142,8 +159,7 @@ class ReMeta: return title_season # 处理存在“Final”字样命名的季度 - @staticmethod - def handle_final_season(title: str) -> int | None: + def handle_final_season(self, title: str) -> int | None: medias = MediaChain().search(title=title)[1] if not medias: logger.warn("没有找到对应的媒体信息!") diff --git a/plugins/vcbanimemonitor/requirements.txt b/plugins/vcbanimemonitor/requirements.txt deleted file mode 100644 index 0eed2d7..0000000 --- a/plugins/vcbanimemonitor/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -roman~=4.1 From c22e8fe365ee2004d0d77f911ffd655b876302dd Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 6 May 2024 10:47:56 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/mergesiteswitch/__init__.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/mergesiteswitch/__init__.py b/plugins/mergesiteswitch/__init__.py index 96456d9..b28bac0 100644 --- a/plugins/mergesiteswitch/__init__.py +++ b/plugins/mergesiteswitch/__init__.py @@ -3,11 +3,12 @@ import os from typing import Any, List, Dict, Tuple from app.core.event import eventmanager, Event -from app.db.models.site import Site +from app.core.plugin import PluginManager from app.db.site_oper import SiteOper from app.db.systemconfig_oper import SystemConfigOper from app.log import logger from app.plugins import _PluginBase +from app.scheduler import Scheduler from app.schemas.types import SystemConfigKey, EventType @@ -687,6 +688,19 @@ class MergeSiteSwitch(_PluginBase): return None return config.get(config_key) + def __reload_plugin_config(self, plugin_id: str, config: dict = None): + """ + 重载插件配置 + """ + if not plugin_id: + return + if not config: + config = self.get_config(plugin_id) + # 重新生效插件 + PluginManager().init_plugin(plugin_id, config) + # 注册插件服务 + Scheduler().update_plugin_job(plugin_id) + def __set_plugin_config_value(self, plugin_id: str, config_key: str, config_value: Any) -> Any: """ 设置插件配置值 @@ -698,6 +712,7 @@ class MergeSiteSwitch(_PluginBase): config = {} config.update({config_key: config_value}) self.update_config(plugin_id=plugin_id, config=config) + self.__reload_plugin_config(plugin_id=plugin_id, config=config) def __get_signin_site_ids(self) -> List[int]: """ From e20ae58163e6d1f1ba23bd65a7972580ce9d3a30 Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 6 May 2024 11:22:00 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=9D=92=E8=9B=99?= =?UTF-8?q?=E8=BE=85=E7=A7=8D=E5=8A=A9=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/mergesiteswitch/__init__.py | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/plugins/mergesiteswitch/__init__.py b/plugins/mergesiteswitch/__init__.py index b28bac0..b925e28 100644 --- a/plugins/mergesiteswitch/__init__.py +++ b/plugins/mergesiteswitch/__init__.py @@ -47,6 +47,8 @@ class MergeSiteSwitch(_PluginBase): __plugin_id_iyuu_auto_seed: str = 'IYUUAutoSeed' # 站点刷流 __plugin_id_brush_flow: str = 'BrushFlow' + # 青蛙辅种助手 + __plugin_id_cross_seed: str = 'CrossSeed' # 配置相关 # 插件缺省配置 @@ -370,6 +372,43 @@ class MergeSiteSwitch(_PluginBase): }] }] }) + # 青蛙辅种助手 + if self.__plugin_id_cross_seed in installed_plugin_ids: + form_content.append({ + 'component': 'VRow', + 'content': [{ + 'component': 'VCol', + 'props': { + 'cols': 12, + 'xxl': 9, 'xl': 9, 'lg': 9, 'md': 9, 'sm': 8, 'xs': 12 + }, + 'content': [{ + 'component': 'VSelect', + 'props': { + 'model': 'cross_seed_sites', + 'label': '插件 / 青蛙辅种助手 / 辅种站点', + 'multiple': True, + 'chips': True, + 'items': site_options, + 'hint': '只有选中的站点才会在辅种中使用。' + } + }] + }, { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'xxl': 3, 'xl': 3, 'lg': 3, 'md': 3, 'sm': 4, 'xs': 12 + }, + 'content': [{ + 'component': 'VSwitch', + 'props': { + 'model': 'cross_seed_follow_enable_sites', + 'label': '跟随启用的站点', + 'hint': '与站点的启用状态保持一致,保存时会立即生效,并在后台监听站点状态变化实时生效。' + } + }] + }] + }) # 提示信息 form_content.append({ 'component': 'VRow', @@ -501,6 +540,12 @@ class MergeSiteSwitch(_PluginBase): """ return self.__check_follow_enable_sites(config_key='brush_flow_follow_enable_sites', plugin_id=self.__plugin_id_brush_flow, installed_plugin_ids=installed_plugin_ids) + def __check_cross_seed_follow_enable_sites(self, installed_plugin_ids: List[str] = None) -> bool: + """ + 判断青蛙辅种站点的跟随按钮是否打开 + """ + return self.__check_follow_enable_sites(config_key='cross_seed_follow_enable_sites', plugin_id=self.__plugin_id_cross_seed, installed_plugin_ids=installed_plugin_ids) + def __check_any_follow_enable_sites(self) -> bool: """ 判断是否开启任意跟随按钮 @@ -565,6 +610,10 @@ class MergeSiteSwitch(_PluginBase): config.update({ 'brush_flow_sites': self.__get_brush_flow_site_ids(), }) + if self.__plugin_id_cross_seed in installed_plugin_ids: + config.update({ + 'cross_seed_sites': self.__get_cross_seed_site_ids(), + }) self.update_config(config=config) return config @@ -589,6 +638,8 @@ class MergeSiteSwitch(_PluginBase): config.update({"iyuu_seed_sites": enable_sites.copy()}) if config.get('brush_flow_follow_enable_sites'): config.update({"brush_flow_sites": enable_sites.copy()}) + if config.get('cross_seed_follow_enable_sites'): + config.update({"cross_seed_sites": enable_sites.copy()}) return config def __pre_config(self, config: dict) -> dict: @@ -622,6 +673,8 @@ class MergeSiteSwitch(_PluginBase): self.__set_iyuu_seed_site_ids(config.get('iyuu_seed_sites')) if self.__plugin_id_brush_flow in installed_plugin_ids: self.__set_brush_flow_site_ids(config.get('brush_flow_sites')) + if self.__plugin_id_cross_seed in installed_plugin_ids: + self.__set_cross_seed_site_ids(config.get('cross_seed_sites')) return config def __get_enable_site_ids(self) -> List[int]: @@ -784,6 +837,20 @@ class MergeSiteSwitch(_PluginBase): self.__set_plugin_config_value(self.__plugin_id_brush_flow, 'brushsites', site_ids) logger.info("刷流站点配置完成") + def __get_cross_seed_site_ids(self) -> List[int]: + """ + 获取青蛙辅种站点IDs + """ + sites = self.__get_plugin_config_value(self.__plugin_id_cross_seed, 'sites') + return sites if sites else [] + + def __set_cross_seed_site_ids(self, site_ids: List[int]): + """ + 设置青蛙辅种站点IDs + """ + self.__set_plugin_config_value(self.__plugin_id_cross_seed, 'sites', site_ids) + logger.info("青蛙辅种站点配置完成") + def __update_search_site_ids_by_site(self, site_id: int, site_status: bool): if site_id == None: return @@ -861,6 +928,17 @@ class MergeSiteSwitch(_PluginBase): site_ids.remove(site_id) self.__set_brush_flow_site_ids(site_ids=site_ids) + def __update_cross_seed_site_ids_by_site(self, site_id: int, site_status: bool): + if site_id == None: + return + site_ids = self.__get_cross_seed_site_ids() or [] + if site_id not in site_ids and site_status: + site_ids.append(site_id) + self.__set_cross_seed_site_ids(site_ids=site_ids) + elif site_id in site_ids and not site_status: + site_ids.remove(site_id) + self.__set_cross_seed_site_ids(site_ids=site_ids) + def __update_site_ids_for_site_event(self, site_id: int, site_status: bool): """ 针对站点事件更新各项配置 @@ -883,6 +961,8 @@ class MergeSiteSwitch(_PluginBase): self.__update_iyuu_seed_site_ids_by_site(site_id=site_id, site_status=site_status) if self.__check_brush_flow_follow_enable_sites(installed_plugin_ids=installed_plugin_ids): self.__update_brush_flow_site_ids_by_site(site_id=site_id, site_status=site_status) + if self.__check_cross_seed_follow_enable_sites(installed_plugin_ids=installed_plugin_ids): + self.__update_cross_seed_site_ids_by_site(site_id=site_id, site_status=site_status) @eventmanager.register(EventType.SiteUpdated) def listen_site_updated_event(self, event: Event = None): From c61988765225dc1995df76e21aad09fd5f2b080e Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 6 May 2024 11:23:50 +0800 Subject: [PATCH 05/10] v1.1 --- package.json | 7 +++++-- plugins/mergesiteswitch/__init__.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8bfe4ec..43242c5 100644 --- a/package.json +++ b/package.json @@ -650,9 +650,12 @@ "name": "聚合站点开关", "description": "统一管理所有与站点相关的开关。", "labels": "系统设置", - "version": "1.0", + "version": "1.1", "icon": "world.png", "author": "hotlcc", - "level": 2 + "level": 2, + "history": { + "v1.1": "优化插件配置生效;支持青蛙辅种助手。" + } } } diff --git a/plugins/mergesiteswitch/__init__.py b/plugins/mergesiteswitch/__init__.py index b925e28..a286915 100644 --- a/plugins/mergesiteswitch/__init__.py +++ b/plugins/mergesiteswitch/__init__.py @@ -20,7 +20,7 @@ class MergeSiteSwitch(_PluginBase): # 插件图标 plugin_icon = "world.png" # 插件版本 - plugin_version = "1.0" + plugin_version = "1.1" # 插件作者 plugin_author = "hotlcc" # 作者主页 From e3174f639a794049d74adfbeab27fe9b9c3279e8 Mon Sep 17 00:00:00 2001 From: xuzhi Date: Mon, 6 May 2024 14:29:34 +0000 Subject: [PATCH 06/10] Update contractcheck to v1.2 --- package.json | 7 +++++-- plugins/contractcheck/__init__.py | 4 ++-- plugins/contractcheck/siteuserinfo/__init__.py | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 43242c5..749c320 100644 --- a/package.json +++ b/package.json @@ -590,10 +590,13 @@ "name": "契约检查", "description": "定时检查保种契约达成情况。", "labels": "做种", - "version": "1.1", + "version": "1.2", "icon": "contract.png", "author": "DzAvril", - "level": 1 + "level": 1, + "history": { + "v1.2": "修复契约检查无数据返回的问题" + } }, "DownloaderHelper": { "name": "下载器助手", diff --git a/plugins/contractcheck/__init__.py b/plugins/contractcheck/__init__.py index a622261..95dd39e 100644 --- a/plugins/contractcheck/__init__.py +++ b/plugins/contractcheck/__init__.py @@ -39,7 +39,7 @@ class ContractCheck(_PluginBase): # 插件图标 plugin_icon = "contract.png" # 插件版本 - plugin_version = "1.1" + plugin_version = "1.2" # 插件作者 plugin_author = "DzAvril" # 作者主页 @@ -713,7 +713,7 @@ class ContractCheck(_PluginBase): else: num_gap = contract_info.num - current_seeding_size[0] is_satisfied = is_size_satisfied and is_num_satisfied - duration = (datetime.now().date() - contract_info.date).days + duration = (datetime.now() - contract_info.date).days if duration < contract_info.duration: duration_gap = contract_info.duration - duration return is_satisfied, size_gap, num_gap, duration_gap diff --git a/plugins/contractcheck/siteuserinfo/__init__.py b/plugins/contractcheck/siteuserinfo/__init__.py index 665a986..d6bd96e 100644 --- a/plugins/contractcheck/siteuserinfo/__init__.py +++ b/plugins/contractcheck/siteuserinfo/__init__.py @@ -69,6 +69,7 @@ class ISiteUserInfo(metaclass=ABCMeta): "UBits": ["UBits"], "听听歌": ["TTG", "WiKi", "DoA", "NGB", "ARiN"], "馒头": ["MTeam", "MTeamTV"], + "朋友": ["FRDS"], } # 错误信息 From 8e7c3c0048f60a2f4775414daff19d9f6fcbf2b1 Mon Sep 17 00:00:00 2001 From: xuzhi Date: Tue, 7 May 2024 02:14:40 +0000 Subject: [PATCH 07/10] Update qbcommand to v1.5 --- package.json | 3 +- plugins/qbcommand/__init__.py | 78 ++++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 749c320..aa4740e 100644 --- a/package.json +++ b/package.json @@ -551,11 +551,12 @@ "name": "QB远程操作", "description": "通过定时任务或交互命令远程操作QB暂停/开始/限速等。", "labels": "下载管理,Qbittorrent", - "version": "1.4", + "version": "1.5", "icon": "Qbittorrent_A.png", "author": "DzAvril", "level": 1, "history": { + "v1.5": "可选特定路径下的做种不会被暂停", "v1.4": "可选某些站点不再做种(暂停做种后不会被恢复)" } }, diff --git a/plugins/qbcommand/__init__.py b/plugins/qbcommand/__init__.py index 89466c2..78f6916 100644 --- a/plugins/qbcommand/__init__.py +++ b/plugins/qbcommand/__init__.py @@ -27,7 +27,7 @@ class QbCommand(_PluginBase): # 插件图标 plugin_icon = "Qbittorrent_A.png" # 插件版本 - plugin_version = "1.4" + plugin_version = "1.5" # 插件作者 plugin_author = "DzAvril" # 作者主页 @@ -60,7 +60,7 @@ class QbCommand(_PluginBase): _op_sites = [] _multi_level_root_domain = ["edu.cn", "com.cn", "net.cn", "org.cn"] _scheduler = None - + _exclude_dirs = "" def init_plugin(self, config: dict = None): self._sites = SitesHelper() self._siteoper = SiteOper() @@ -87,6 +87,7 @@ class QbCommand(_PluginBase): all_sites = [site for site in self._sites.get_indexers() if not site.get("public")] + self.__custom_sites() # 过滤掉没有选中的站点 self._op_sites = [site for site in all_sites if site.get("id") in self._op_site_ids] + self._exclude_dirs = config.get("exclude_dirs") or "" if self._only_pause_once or self._only_resume_once: if self._only_pause_once and self._only_resume_once: @@ -121,6 +122,7 @@ class QbCommand(_PluginBase): "pause_cron": self._pause_cron, "resume_cron": self._resume_cron, "op_site_ids": self._op_site_ids, + "exclude_dirs": self._exclude_dirs, } ) @@ -430,14 +432,6 @@ class QbCommand(_PluginBase): hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = ( self.get_torrents_status(all_torrents) ) - if type == self.TorrentType.DOWNLOADING: - to_be_paused = hash_downloading - elif type == self.TorrentType.UPLOADING: - to_be_paused = hash_uploading - elif type == self.TorrentType.CHECKING: - to_be_paused = hash_checking - else: - to_be_paused = hash_downloading + hash_uploading + hash_checking logger.info( f"暂定任务启动 \n" @@ -461,6 +455,19 @@ class QbCommand(_PluginBase): f"错误数量: {len(hash_error)}\n" f"暂停操作中请稍等...\n", ) + pause_torrents = self.filter_pause_torrents(all_torrents) + hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = ( + self.get_torrents_status(pause_torrents) + ) + if type == self.TorrentType.DOWNLOADING: + to_be_paused = hash_downloading + elif type == self.TorrentType.UPLOADING: + to_be_paused = hash_uploading + elif type == self.TorrentType.CHECKING: + to_be_paused = hash_checking + else: + to_be_paused = hash_downloading + hash_uploading + hash_checking + if len(to_be_paused) > 0: if self._qb.stop_torrents(ids=to_be_paused): logger.info(f"暂停了{len(to_be_paused)}个种子") @@ -501,6 +508,22 @@ class QbCommand(_PluginBase): f"错误数量: {len(hash_error)}\n", ) + def __is_excluded(self, file_path) -> bool: + """ + 是否排除目录 + """ + for exclude_dir in self._exclude_dirs.split("\n"): + if exclude_dir and exclude_dir in str(file_path): + return True + return False + def filter_pause_torrents(self, all_torrents): + torrents = [] + for torrent in all_torrents: + if self.__is_excluded(torrent.get("content_path")): + continue + torrents.append(torrent) + return torrents + @eventmanager.register(EventType.PluginAction) def handle_resume_torrent(self, event: Event): if not self._enabled: @@ -516,7 +539,6 @@ class QbCommand(_PluginBase): return all_torrents = self.get_all_torrents() - all_torrents = self.filter_torrents(all_torrents) hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = ( self.get_torrents_status(all_torrents) ) @@ -542,6 +564,11 @@ class QbCommand(_PluginBase): f"错误数量: {len(hash_error)}\n" f"开始操作中请稍等...\n", ) + + resume_torrents = self.filter_resume_torrents(all_torrents) + hash_downloading, hash_uploading, hash_paused, hash_checking, hash_error = ( + self.get_torrents_status(resume_torrents) + ) if not self._qb.start_torrents(ids=hash_paused): logger.error(f"开始种子失败") if self._notify: @@ -579,7 +606,7 @@ class QbCommand(_PluginBase): f"错误数量: {len(hash_error)}\n", ) - def filter_torrents(self, all_torrents): + def filter_resume_torrents(self, all_torrents): """ 过滤掉不参与保种的种子 """ @@ -644,14 +671,13 @@ class QbCommand(_PluginBase): if self._notify: self.post_message( mtype=NotificationType.SiteMessage, - title=f"【QB开始任务启动】", + title=f"【QB任务状态】", text=f"种子总数: {len(all_torrents)} \n" f"做种数量: {len(hash_uploading)}\n" f"下载数量: {len(hash_downloading)}\n" f"检查数量: {len(hash_checking)}\n" f"暂停数量: {len(hash_paused)}\n" f"错误数量: {len(hash_error)}\n" - f"开始操作中请稍等...\n", ) @eventmanager.register(EventType.PluginAction) @@ -747,7 +773,7 @@ class QbCommand(_PluginBase): elif flag is None and self._enabled and self._enable_upload_limit: flag = self.set_upload_limit(upload_limit) - if flag: + if flag == True: logger.info(f"设置QB限速成功") if self._notify: if upload_limit == 0: @@ -763,7 +789,7 @@ class QbCommand(_PluginBase): title=f"【QB远程操作】", text=text, ) - elif not flag: + elif flag == False: logger.error(f"QB设置限速失败") if self._notify: self.post_message( @@ -1054,6 +1080,26 @@ class QbCommand(_PluginBase): } ], }, + { + "component": "VRow", + "content": [ + { + "component": "VCol", + "props": {"cols": 12}, + "content": [ + { + "component": "VTextarea", + "props": { + "model": "exclude_dirs", + "label": "不暂停保种目录", + "rows": 5, + "placeholder": "该目录下的做种不会暂停,一行一个目录", + }, + } + ], + } + ], + }, { "component": "VRow", "content": [ From 6a30eede499e00e7477f6845e2d3bda571dd0550 Mon Sep 17 00:00:00 2001 From: falling Date: Tue, 7 May 2024 22:30:00 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A7=82=E4=BC=97?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E7=BB=9F=E8=AE=A1=E5=81=9A=E6=80=BB=E6=95=B0?= =?UTF-8?q?=E5=92=8C=E5=81=9A=E7=A7=8D=E4=BD=93=E7=A7=AF=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + plugins/sitestatistic/siteuserinfo/__init__.py | 1 + .../siteuserinfo/nexus_audiences.py | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 plugins/sitestatistic/siteuserinfo/nexus_audiences.py diff --git a/package.json b/package.json index aa4740e..bbe86ae 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "author": "lightolly", "level": 2, "history": { + "v3.1": "修复观众无法统计做总数和做种体积的bug", "v3.0": "适配馒头数据统计,需要升级至v1.8.5+版本,且在站点信息中维护好API Key", "v2.9": "增强API安全性", "v2.8": "修复馒头未读消息统计", diff --git a/plugins/sitestatistic/siteuserinfo/__init__.py b/plugins/sitestatistic/siteuserinfo/__init__.py index f9723f1..7be0b61 100644 --- a/plugins/sitestatistic/siteuserinfo/__init__.py +++ b/plugins/sitestatistic/siteuserinfo/__init__.py @@ -26,6 +26,7 @@ class SiteSchema(Enum): NexusProject = "NexusProject" NexusRabbit = "NexusRabbit" NexusHhanclub = "NexusHhanclub" + NexusAudiences = "NexusAudiences" SmallHorse = "Small Horse" Unit3d = "Unit3d" TorrentLeech = "TorrentLeech" diff --git a/plugins/sitestatistic/siteuserinfo/nexus_audiences.py b/plugins/sitestatistic/siteuserinfo/nexus_audiences.py new file mode 100644 index 0000000..9a1c369 --- /dev/null +++ b/plugins/sitestatistic/siteuserinfo/nexus_audiences.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from urllib.parse import urljoin + +from app.plugins.sitestatistic.siteuserinfo import SITE_BASE_ORDER, SiteSchema +from app.plugins.sitestatistic.siteuserinfo.nexus_php import NexusPhpSiteUserInfo + + +class NexusAudiencesSiteUserInfo(NexusPhpSiteUserInfo): + schema = SiteSchema.NexusAudiences + order = SITE_BASE_ORDER + 5 + + @classmethod + def match(cls, html_text: str) -> bool: + return 'audiences.me' in html_text + + def _parse_seeding_pages(self): + self._torrent_seeding_headers = {"Referer": urljoin(self._base_url, self._user_detail_page)} + super()._parse_seeding_pages() From 4c782567b8ec22424c28e4febacc5bf9a8413e48 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 7 May 2024 22:36:11 +0800 Subject: [PATCH 09/10] fix #270 --- plugins/sitestatistic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sitestatistic/__init__.py b/plugins/sitestatistic/__init__.py index 145bd4f..a9e8767 100644 --- a/plugins/sitestatistic/__init__.py +++ b/plugins/sitestatistic/__init__.py @@ -43,7 +43,7 @@ class SiteStatistic(_PluginBase): # 插件图标 plugin_icon = "statistic.png" # 插件版本 - plugin_version = "3.0" + plugin_version = "3.1" # 插件作者 plugin_author = "lightolly" # 作者主页 From f9d25ed74b251780b7dd187a85f5e2654eff94a4 Mon Sep 17 00:00:00 2001 From: falling Date: Tue, 7 May 2024 23:19:10 +0800 Subject: [PATCH 10/10] Update package.json update version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bbe86ae..14222ce 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "name": "站点数据统计", "description": "自动统计和展示站点数据。", "labels": "站点", - "version": "3.0", + "version": "3.1", "icon": "statistic.png", "author": "lightolly", "level": 2,