From b64ad36a101d3580e01d2f7830b136d55875503b Mon Sep 17 00:00:00 2001 From: Allen Date: Tue, 23 Apr 2024 04:33:06 +0000 Subject: [PATCH 1/6] fixbug --- package.json | 2 +- plugins/pluginautoupgrade/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c58213b..f14a5ee 100644 --- a/package.json +++ b/package.json @@ -529,7 +529,7 @@ "PluginAutoUpgrade": { "name": "插件自动升级", "description": "定时检测、升级插件。", - "version": "1.2", + "version": "1.3", "icon": "PluginAutoUpgrade.png", "author": "hotlcc", "level": 1 diff --git a/plugins/pluginautoupgrade/__init__.py b/plugins/pluginautoupgrade/__init__.py index 3649512..16600fa 100644 --- a/plugins/pluginautoupgrade/__init__.py +++ b/plugins/pluginautoupgrade/__init__.py @@ -23,7 +23,7 @@ class PluginAutoUpgrade(_PluginBase): # 插件图标 plugin_icon = "PluginAutoUpgrade.png" # 插件版本 - plugin_version = "1.2" + plugin_version = "1.3" # 插件作者 plugin_author = "hotlcc" # 作者主页 @@ -552,7 +552,7 @@ class PluginAutoUpgrade(_PluginBase): if not installed_local_plugin: return None success, message = self.__install_plugin(plugin_id=online_plugin.id, repo_url=online_plugin.repo_url, force=True) - logger.info(f"插件升级结果: plugin_name = {online_plugin.plugin_name}, plugin_version = v{installed_local_plugin.plugin_version} -> v{online_plugin.plugin_version}, success = {response.success}, message = {response.message}") + logger.info(f"插件升级结果: plugin_name = {online_plugin.plugin_name}, plugin_version = v{installed_local_plugin.plugin_version} -> v{online_plugin.plugin_version}, success = {success}, message = {message}") return { 'success': success, 'message': message, From 7535e588f161d803ec0d193ec5e53fc60679f2cc Mon Sep 17 00:00:00 2001 From: Allen Date: Tue, 23 Apr 2024 05:45:15 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=E6=8F=92=E4=BB=B6=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8D=87=E7=BA=A7page=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- plugins/pluginautoupgrade/__init__.py | 54 ++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index f14a5ee..9a7caeb 100644 --- a/package.json +++ b/package.json @@ -529,7 +529,7 @@ "PluginAutoUpgrade": { "name": "插件自动升级", "description": "定时检测、升级插件。", - "version": "1.3", + "version": "1.4", "icon": "PluginAutoUpgrade.png", "author": "hotlcc", "level": 1 diff --git a/plugins/pluginautoupgrade/__init__.py b/plugins/pluginautoupgrade/__init__.py index 16600fa..1caf489 100644 --- a/plugins/pluginautoupgrade/__init__.py +++ b/plugins/pluginautoupgrade/__init__.py @@ -23,7 +23,7 @@ class PluginAutoUpgrade(_PluginBase): # 插件图标 plugin_icon = "PluginAutoUpgrade.png" # 插件版本 - plugin_version = "1.3" + plugin_version = "1.4" # 插件作者 plugin_author = "hotlcc" # 作者主页 @@ -248,21 +248,33 @@ class PluginAutoUpgrade(_PluginBase): 'content': [{ 'component': 'td', 'props': { - 'class': 'whitespace-nowrap break-keep text-high-emphasis' + 'class': 'whitespace-nowrap' }, 'text': item.get('datetime_str') }, { 'component': 'td', + 'props': { + 'class': 'whitespace-nowrap' + }, 'text': item.get('plugin_name') }, { 'component': 'td', + 'props': { + 'class': 'whitespace-nowrap' + }, 'text': f'v{item.get("old_plugin_version")}' }, { 'component': 'td', + 'props': { + 'class': 'whitespace-nowrap' + }, 'text': f'v{item.get("new_plugin_version")}' }, { 'component': 'td', 'text': item.get('info') + }, { + 'component': 'td', + 'text': item.get('upgrade_info') }] } for item in page_data if item] else: @@ -274,7 +286,7 @@ class PluginAutoUpgrade(_PluginBase): 'content': [{ 'component': 'td', 'props': { - 'colspan': '5', + 'colspan': '6', 'class': 'text-center' }, 'text': '暂无数据' @@ -292,7 +304,7 @@ class PluginAutoUpgrade(_PluginBase): 'props': { 'class': 'text-start ps-4' }, - 'text': '升级时间' + 'text': '时间' }, { 'component': 'th', 'props': { @@ -304,19 +316,25 @@ class PluginAutoUpgrade(_PluginBase): 'props': { 'class': 'text-start ps-4' }, - 'text': '升级前版本' + 'text': '旧版本' }, { 'component': 'th', 'props': { 'class': 'text-start ps-4' }, - 'text': '升级后版本' + 'text': '新版本' }, { 'component': 'th', 'props': { 'class': 'text-start ps-4' }, - 'text': '结果' + 'text': '执行结果' + }, { + 'component': 'th', + 'props': { + 'class': 'text-start ps-4' + }, + 'text': '升级描述' }] }, { 'component': 'tbody', @@ -560,7 +578,8 @@ class PluginAutoUpgrade(_PluginBase): 'plugin_name': online_plugin.plugin_name, 'new_plugin_version': online_plugin.plugin_version, 'old_plugin_version': installed_local_plugin.plugin_version, - 'datetime_str': datetime.now().strftime("%Y-%m-%d %H:%M:%S") + 'datetime_str': datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + 'upgrade_info': self.__extract_upgrade_history(online_plugin) } def __send_notify(self, results: List[Dict[str, Any]]): @@ -592,7 +611,7 @@ class PluginAutoUpgrade(_PluginBase): else: text += f"{result.get('message')}\n" return text - + def __save_upgrade_records(self, records: List[Dict[str, Any]]): """ 保存升级记录 @@ -628,3 +647,20 @@ class PluginAutoUpgrade(_PluginBase): # 按时间倒序 page_data = sorted(page_data, key=lambda item: item.get("datetime_str"), reverse=True) return page_data + + @staticmethod + def __extract_upgrade_history(plugin: schemas.Plugin, version: str = None) -> str: + """ + 提取指定版本的升级历史信息 + """ + if not plugin or not plugin.history: + return None + if not version: + version = plugin.plugin_version + if not version: + return None + version_history = plugin.history.get(f'v{version}') + if not version_history: + # 兼容处理 + version_history = plugin.history.get(version) + return version_history From 2af33394776deb48f130f8bdd5fdeb533fc9af73 Mon Sep 17 00:00:00 2001 From: ljmeng Date: Wed, 24 Apr 2024 00:31:40 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=E9=9D=92=E8=9B=99=E8=BE=85?= =?UTF-8?q?=E7=A7=8D=E6=8F=92=E4=BB=B6=E6=94=AF=E6=8C=81=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +++-- plugins/crossseed/__init__.py | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9a7caeb..9f6b98a 100644 --- a/package.json +++ b/package.json @@ -201,12 +201,13 @@ "CrossSeed": { "name": "青蛙辅种助手", "description": "参考ReseedPuppy和IYUU辅种插件实现自动辅种,支持站点:青蛙、AGSVPT、麒麟、UBits、聆音、憨憨等。", - "version": "2.2", + "version": "2.3", "icon": "qingwa.png", "author": "233@qingwa", "level": 2, "history": { - "v2.2": "站点停用后会同步暂停对该站点的辅种" + "v2.2": "站点停用后会同步暂停对该站点的辅种", + "v2.3": "站点辅种支持代理" } }, "VCBAnimeMonitor": { diff --git a/plugins/crossseed/__init__.py b/plugins/crossseed/__init__.py index c33fb51..d05f63a 100644 --- a/plugins/crossseed/__init__.py +++ b/plugins/crossseed/__init__.py @@ -154,7 +154,11 @@ class CrossSeedHelper(object): remote_torrent_infos = [] try: response = requests.post( - site.get_api_url(), headers=headers, json=data, timeout=10 + site.get_api_url(), + headers=headers, + json=data, + timeout=10, + proxies=settings.PROXY if site.proxy else None, ) response.raise_for_status() rsp_body = response.json() @@ -177,7 +181,7 @@ class CrossSeed(_PluginBase): # 插件图标 plugin_icon = "qingwa.png" # 插件版本 - plugin_version = "2.2" + plugin_version = "2.3" # 插件作者 plugin_author = "233@qingwa" # 作者主页 From d9a421893ec67da9402575a1c8aa4368240a661b Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:11:27 +0800 Subject: [PATCH 4/6] fix brushflow --- plugins/brushflow/__init__.py | 1457 +++++++++++++++++++-------------- 1 file changed, 861 insertions(+), 596 deletions(-) diff --git a/plugins/brushflow/__init__.py b/plugins/brushflow/__init__.py index e879738..1ded69e 100644 --- a/plugins/brushflow/__init__.py +++ b/plugins/brushflow/__init__.py @@ -73,6 +73,8 @@ class BrushConfig: 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") + self.auto_qb_category = config.get("auto_qb_category", False) self.brush_tag = "刷流" # 站点独立配置 @@ -80,8 +82,12 @@ class BrushConfig: self.site_config = config.get("site_config", "[]") self.group_site_configs = {} - if self.enable_site_config and process_site_config: - self.__initialize_site_config() + # 如果开启了独立站点配置,那么则初始化,否则判断配置是否为空,如果为空,则恢复默认配置 + if process_site_config: + if self.enable_site_config: + self.__initialize_site_config() + elif not self.site_config: + self.site_config = self.get_demo_site_config() def __initialize_site_config(self): if not self.site_config: @@ -109,7 +115,9 @@ class BrushConfig: "seed_inactivetime", "save_path", "proxy_download", - "proxy_delete" + "proxy_delete", + "qb_category", + "auto_qb_category", # 当新增支持字段时,仅在此处添加字段名 } try: @@ -139,6 +147,7 @@ class BrushConfig: @staticmethod def get_demo_site_config() -> str: desc = ("// 以下为配置示例,请参考:https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md 进行配置\n" + "// 如与全局保持一致的配置项,请勿在站点配置中配置\n" "// 注意无关内容需使用 // 注释\n") config = """[{ "sitename": "站点1", @@ -172,7 +181,9 @@ class BrushConfig: "seed_inactivetime": "", "save_path": "/downloads/site1", "proxy_download": false, - "proxy_delete": false + "proxy_delete": false, + "qb_category": "刷流", + "auto_qb_category": true }]""" return desc + config @@ -238,7 +249,7 @@ class BrushFlow(_PluginBase): # 插件图标 plugin_icon = "brush.jpg" # 插件版本 - plugin_version = "2.8" + plugin_version = "2.9" # 插件作者 plugin_author = "jxxghp,InfinityPacer" # 作者主页 @@ -270,6 +281,8 @@ class BrushFlow(_PluginBase): # 退出事件 _event = Event() _scheduler = None + # tabs + _tabs = None # endregion @@ -285,6 +298,8 @@ class BrushFlow(_PluginBase): logger.info("站点刷流任务出错,无法获取插件配置") return False + self._tabs = config.get("_tabs", None) + # 如果配置校验没有通过,那么这里修改配置文件后退出 if not self.__validate_and_fix_config(config=config): self._brush_config = BrushConfig(config=config) @@ -437,61 +452,6 @@ class BrushFlow(_PluginBase): { 'component': 'VForm', 'content': [ - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - }, - 'content': [ - { - 'component': 'VAlert', - 'props': { - 'type': 'success', - 'variant': 'tonal' - }, - 'content': [ - { - 'component': 'span', - 'text': '部分配置项以及细节请参考:' - }, - { - 'component': 'a', - 'props': { - 'href': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md', - 'target': '_blank' - }, - 'text': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md' - } - ] - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - }, - 'content': [ - { - 'component': 'VAlert', - 'props': { - 'type': 'error', - 'variant': 'tonal', - 'text': '注意:排除H&R并不保证能完全适配所有站点(部分站点在列表页不显示H&R标志,但实际上是有H&R的),请注意核对使用!' - } - } - ] - } - ] - }, { 'component': 'VRow', 'content': [ @@ -551,7 +511,7 @@ class BrushFlow(_PluginBase): { 'component': 'VCol', 'props': { - "cols": 12 + 'cols': 12 }, 'content': [ { @@ -601,225 +561,9 @@ class BrushFlow(_PluginBase): { 'component': 'VTextField', 'props': { - 'model': 'disksize', - 'label': '保种体积(GB)', - 'placeholder': '如:500,达到后停止新增任务' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'freeleech', - 'label': '促销', - 'items': [ - {'title': '全部(包括普通)', 'value': ''}, - {'title': '免费', 'value': 'free'}, - {'title': '2X免费', 'value': '2xfree'}, - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'hr', - 'label': '排除H&R', - 'items': [ - {'title': '是', 'value': 'yes'}, - {'title': '否', 'value': 'no'}, - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'maxupspeed', - 'label': '总上传带宽(KB/s)', - 'placeholder': '达到后停止新增任务' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'maxdlspeed', - 'label': '总下载带宽(KB/s)', - 'placeholder': '达到后停止新增任务' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'maxdlcount', - 'label': '同时下载任务数', - 'placeholder': '达到后停止新增任务' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'include', - 'label': '包含规则', - 'placeholder': '支持正式表达式' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'exclude', - 'label': '排除规则', - 'placeholder': '支持正式表达式' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'size', - 'label': '种子大小(GB)', - 'placeholder': '如:5 或 5-10' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'seeder', - 'label': '做种人数', - 'placeholder': '如:5 或 5-10' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'pubtime', - 'label': '发布时间(分钟)', - 'placeholder': '如:5 或 5-10' - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'seed_time', - 'label': '做种时间(小时)', - 'placeholder': '达到后删除任务' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'hr_seed_time', - 'label': 'H&R做种时间(小时)', - 'placeholder': '达到后删除任务' + 'model': 'active_time_range', + 'label': '开启时间段', + 'placeholder': '如:00:00-08:00' } } ] @@ -840,157 +584,775 @@ class BrushFlow(_PluginBase): } } ] + } + ] + }, + { + 'component': 'VTabs', + 'props': { + 'model': '_tabs', + 'style': { + 'margin-top': '8px', + 'margin-bottom': '16px' }, + 'stacked': True, + 'fixed-tabs': True + }, + 'content': [ { - 'component': 'VCol', + 'component': 'VTab', 'props': { - "cols": 12, - "md": 4 + 'value': 'base_tab' + }, + 'text': '基本配置' + }, { + 'component': 'VTab', + 'props': { + 'value': 'download_tab' + }, + 'text': '选种规则' + }, { + 'component': 'VTab', + 'props': { + 'value': 'delete_tab' + }, + 'text': '删除规则' + }, { + 'component': 'VTab', + 'props': { + 'value': 'other_tab' + }, + 'text': '更多配置' + } + ] + }, + { + 'component': 'VWindow', + 'props': { + 'model': '_tabs' + # VWindow设置paddnig会导致切换Tab时页面高度变动,调整为修改VRow的方案 + # 'style': { + # 'padding-top': '24px', + # 'padding-bottom': '24px', + # }, + }, + 'content': [ + { + 'component': 'VWindowItem', + 'props': { + 'value': 'base_tab' }, 'content': [ { - 'component': 'VTextField', + 'component': 'VRow', 'props': { - 'model': 'seed_ratio', - 'label': '分享率', - 'placeholder': '达到后删除任务' - } + 'style': { + 'margin-top': '0px' + } + }, + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'maxdlcount', + 'label': '同时下载任务数', + 'placeholder': '达到后停止新增任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'disksize', + 'label': '保种体积(GB)', + 'placeholder': '如:500,达到后停止新增任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'qb_category', + 'label': '种子分类', + 'placeholder': '仅支持qBittorrent,需提前创建' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'maxupspeed', + 'label': '总上传带宽(KB/s)', + 'placeholder': '达到后停止新增任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'maxdlspeed', + 'label': '总下载带宽(KB/s)', + 'placeholder': '达到后停止新增任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'save_path', + 'label': '保存目录', + 'placeholder': '留空自动' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'up_speed', + 'label': '单任务上传限速(KB/s)', + 'placeholder': '种子上传限速' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'dl_speed', + 'label': '单任务下载限速(KB/s)', + 'placeholder': '种子下载限速' + } + } + ] + } + ] } ] }, { - 'component': 'VCol', + 'component': 'VWindowItem', 'props': { - "cols": 12, - "md": 4 + 'value': 'download_tab' }, 'content': [ { - 'component': 'VTextField', + 'component': 'VRow', 'props': { - 'model': 'seed_size', - 'label': '上传量(GB)', - 'placeholder': '达到后删除任务' - } + 'style': { + 'margin-top': '0px' + } + }, + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'hr', + 'label': '排除H&R', + 'items': [ + {'title': '是', 'value': 'yes'}, + {'title': '否', 'value': 'no'}, + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'freeleech', + 'label': '促销', + 'items': [ + {'title': '全部(包括普通)', 'value': ''}, + {'title': '免费', 'value': 'free'}, + {'title': '2X免费', 'value': '2xfree'}, + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'pubtime', + 'label': '发布时间(分钟)', + 'placeholder': '如:5 或 5-10' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'size', + 'label': '种子大小(GB)', + 'placeholder': '如:5 或 5-10' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'seeder', + 'label': '做种人数', + 'placeholder': '如:5 或 5-10' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'include', + 'label': '包含规则', + 'placeholder': '支持正式表达式' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'exclude', + 'label': '排除规则', + 'placeholder': '支持正式表达式' + } + } + ] + } + ] } ] }, { - 'component': 'VCol', + 'component': 'VWindowItem', 'props': { - "cols": 12, - "md": 4 + 'value': 'delete_tab' }, 'content': [ { - 'component': 'VTextField', + 'component': 'VRow', 'props': { - 'model': 'download_time', - 'label': '下载超时时间(小时)', - 'placeholder': '达到后删除任务' - } + 'style': { + 'margin-top': '0px' + } + }, + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'seed_time', + 'label': '做种时间(小时)', + 'placeholder': '达到后删除任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'hr_seed_time', + 'label': 'H&R做种时间(小时)', + 'placeholder': '达到后删除任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'seed_ratio', + 'label': '分享率', + 'placeholder': '达到后删除任务' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'seed_size', + 'label': '上传量(GB)', + 'placeholder': '达到后删除任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'seed_avgspeed', + 'label': '平均上传速度(KB/s)', + 'placeholder': '低于时删除任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'download_time', + 'label': '下载超时时间(小时)', + 'placeholder': '达到后删除任务' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + "cols": 12, + "md": 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'seed_inactivetime', + 'label': '未活动时间(分钟) ', + 'placeholder': '超过时删除任务' + } + } + ] + } + ] } ] }, { - 'component': 'VCol', + 'component': 'VWindowItem', 'props': { - "cols": 12, - "md": 4 + 'value': 'other_tab' }, 'content': [ { - 'component': 'VTextField', + 'component': 'VRow', 'props': { - 'model': 'seed_avgspeed', - 'label': '平均上传速度(KB/s)', - 'placeholder': '低于时删除任务' - } + 'style': { + 'margin-top': '-16px' + } + }, + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'brush_sequential', + 'label': '站点顺序刷流', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'except_tags', + 'label': '删种排除MoviePilot任务', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'except_subscribe', + 'label': '排除订阅(实验性功能)', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'clear_task', + 'label': '清除统计数据', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'archive_task', + 'label': '归档已删除种子', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'proxy_delete', + 'label': '动态删除种子(实验性功能)', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + "content": [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enable_site_config', + 'label': '站点独立配置', + } + } + ] + }, + { + "component": "VCol", + "props": { + "cols": 12, + "md": 4 + }, + "content": [ + { + "component": "VSwitch", + "props": { + "model": "dialog_closed", + "label": "设置站点" + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'proxy_download', + 'label': '代理下载种子', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + "content": [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'downloader_monitor', + 'label': '下载器监控', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'auto_qb_category', + 'label': '自动分类管理', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'log_more', + 'label': '记录更多日志', + } + } + ] + } + ] } ] + } + ] + }, + { + 'component': 'VRow', + 'props': { + 'style': { + 'margin-top': '12px' }, + }, + 'content': [ { 'component': 'VCol', 'props': { - "cols": 12, - "md": 4 + 'cols': 12, }, 'content': [ { - 'component': 'VTextField', + 'component': 'VAlert', 'props': { - 'model': 'seed_inactivetime', - 'label': '未活动时间(分钟) ', - 'placeholder': '超过时删除任务' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'up_speed', - 'label': '单任务上传限速(KB/s)', - 'placeholder': '种子上传限速' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'dl_speed', - 'label': '单任务下载限速(KB/s)', - 'placeholder': '种子下载限速' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'save_path', - 'label': '保存目录', - 'placeholder': '留空自动' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - "cols": 12, - "md": 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'active_time_range', - 'label': '开启时间段', - 'placeholder': '如:00:00-08:00' - } + 'type': 'success', + 'variant': 'tonal' + }, + 'content': [ + { + 'component': 'span', + 'text': '部分配置项以及细节请参考:' + }, + { + 'component': 'a', + 'props': { + 'href': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md', + 'target': '_blank' + }, + 'text': 'https://github.com/InfinityPacer/MoviePilot-Plugins/blob/main/README.md' + } + ] } ] } @@ -1003,190 +1365,14 @@ class BrushFlow(_PluginBase): 'component': 'VCol', 'props': { 'cols': 12, - 'md': 4 }, 'content': [ { - 'component': 'VSwitch', + 'component': 'VAlert', 'props': { - 'model': 'brush_sequential', - 'label': '站点顺序刷流', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'except_tags', - 'label': '删种排除MoviePilot任务', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'except_subscribe', - 'label': '排除订阅(实验性功能)', - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'clear_task', - 'label': '清除统计数据', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'archive_task', - 'label': '归档已删除种子', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'proxy_delete', - 'label': '动态删除种子(实验性功能)', - } - } - ] - } - ] - }, - { - 'component': 'VRow', - "content": [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'enable_site_config', - 'label': '站点独立配置', - } - } - ] - }, - { - "component": "VCol", - "props": { - "cols": 12, - "md": 4, - # "class": "d-flex justify-end" - }, - "content": [ - { - "component": "VSwitch", - "props": { - "model": "dialog_closed", - "label": "设置站点" - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'proxy_download', - 'label': '代理下载种子', - } - } - ] - } - ] - }, - { - 'component': 'VRow', - "content": [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'downloader_monitor', - 'label': '下载器监控', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'log_more', - 'label': '记录更多日志', + 'type': 'error', + 'variant': 'tonal', + 'text': '注意:排除H&R并不保证能完全适配所有站点(部分站点在列表页不显示H&R标志,但实际上是有H&R的),请注意核对使用!' } } ] @@ -1298,6 +1484,7 @@ class BrushFlow(_PluginBase): "enable_site_config": False, "log_more": False, "downloader_monitor": False, + "auto_qb_category": False, "site_config": BrushConfig.get_demo_site_config() } @@ -2008,17 +2195,18 @@ class BrushFlow(_PluginBase): # 发布时间 pubdate_minutes = self.__get_pubminutes(torrent.pubdate) - pubdate_minutes = self.__adjust_site_pubminutes(pubdate_minutes, torrent) + # 已支持独立站点配置,取消单独适配站点时区逻辑,可通过配置项「pubtime」自行适配 + # pubdate_minutes = self.__adjust_site_pubminutes(pubdate_minutes, torrent) if brush_config.pubtime: pubtimes = [float(n) for n in brush_config.pubtime.split("-")] if len(pubtimes) == 1: # 单个值:选择发布时间小于等于该值的种子 if pubdate_minutes > pubtimes[0]: - return False, f"发布时间 {pubdate_minutes:.0f} 分钟前,不符合条件" + return False, f"发布时间 {torrent.pubdate},{pubdate_minutes:.0f} 分钟前,不符合条件" else: # 范围值:选择发布时间在范围内的种子 if not (pubtimes[0] <= pubdate_minutes <= pubtimes[1]): - return False, f"发布时间 {pubdate_minutes:.0f} 分钟前,不在指定范围内" + return False, f"发布时间 {torrent.pubdate},{pubdate_minutes:.0f} 分钟前,不在指定范围内" return True, None @@ -2420,6 +2608,9 @@ class BrushFlow(_PluginBase): min_size = sizes[0] # 至少需要达到的做种体积 max_size = sizes[1] if len(sizes) > 1 else sizes[0] # 触发删除操作的做种体积上限 + # 判断是否为区间删除 + proxy_size_range = len(sizes) > 1 + # 当总体积未超过最大阈值时,不需要执行删除操作 if total_torrent_size < max_size: logger.info( @@ -2489,18 +2680,24 @@ class BrushFlow(_PluginBase): torrent_desc = torrent_task.get("description", "") 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) + reason = (f"触发动态删除阈值,系统自动删除,做种时间 {seeding_time / 3600:.1f} 小时," + f"当前做种体积 {self.__bytes_to_gb(total_torrent_size):.1f} GB") + # 如果是区间删除,一次性删除的数据过多,取消消息推送 + if not proxy_size_range: + 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}") delete_sites = {torrent_tasks[hash_key].get('site_name', '') for hash_key in need_delete_hashes if hash_key in torrent_tasks} msg = (f"站点:{','.join(delete_sites)}\n内容:已完成 {len(need_delete_hashes)} 个种子删除," - f"当前做种体积 {self.__bytes_to_gb(total_torrent_size):.1f} GB\n原因:触发动态删除") + f"当前做种体积 {self.__bytes_to_gb(total_torrent_size):.1f} GB\n原因:触发动态删除阈值,系统自动删除") logger.info(msg) - self.__send_message(title="【刷流任务状态更新】", text=msg) + + # 如果是区间删除,这里则进行统一推送 + if proxy_size_range: + self.__send_message(title="【刷流任务种子删除】", text=msg) # 返回所有需要删除的种子的哈希列表 return need_delete_hashes @@ -2740,8 +2937,11 @@ class BrushFlow(_PluginBase): "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, + "auto_qb_category": brush_config.auto_qb_category, "enable_site_config": brush_config.enable_site_config, - "site_config": brush_config.site_config + "site_config": brush_config.site_config, + "_tabs": self._tabs } # 使用update_config方法或其等效方法更新配置 @@ -2851,14 +3051,17 @@ class BrushFlow(_PluginBase): download_dir = brush_config.save_path or None # 获取下载链接 torrent_content = torrent.enclosure - # 部分站点下载种子不需要传递Cookie - need_download_cookie = True + # proxies + proxies = settings.PROXY if torrent.site_proxy else None + # cookie + cookies = torrent.site_cookie if torrent_content.startswith("["): torrent_content = self.__get_redict_url(url=torrent_content, - proxies=settings.PROXY if torrent.site_proxy else None, + proxies=proxies, ua=torrent.site_ua, - cookie=torrent.site_cookie) - need_download_cookie = False + cookie=cookies) + # 目前馒头请求实际种子时,不能传入Cookie + cookies = None if not torrent_content: logger.error(f"获取下载链接失败:{torrent.title}") return None @@ -2873,20 +3076,22 @@ 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 if need_download_cookie else None, - proxies=settings.PROXY if torrent.site_proxy else None, + response = RequestUtils(cookies=cookies, + proxies=proxies, ua=torrent.site_ua).get_res(url=torrent_content) if response and response.ok: torrent_content = response.content else: logger.error('尝试通过MP下载种子失败,继续尝试传递种子地址到下载器进行下载') if torrent_content: - state = self.qb.add_torrent(content=torrent_content, - download_dir=download_dir, - cookie=torrent.site_cookie if need_download_cookie else None, - tag=["已整理", brush_config.brush_tag, tag], - upload_limit=up_speed, - download_limit=down_speed) + state = self.__qb_add_torrent(content=torrent_content, + download_dir=download_dir, + cookie=cookies, + tag=["已整理", brush_config.brush_tag, tag], + category=brush_config.qb_category, + is_auto=brush_config.auto_qb_category, + upload_limit=up_speed, + download_limit=down_speed) if not state: return None else: @@ -2904,8 +3109,8 @@ class BrushFlow(_PluginBase): return None # 如果开启代理下载以及种子地址不是磁力地址,则请求种子到内存再传入下载器 if brush_config.proxy_download and not torrent_content.startswith("magnet"): - response = RequestUtils(cookies=torrent.site_cookie if need_download_cookie else None, - proxies=settings.PROXY if torrent.site_proxy else None, + response = RequestUtils(cookies=cookies, + proxies=proxies, ua=torrent.site_ua).get_res(url=torrent_content) if response and response.ok: torrent_content = response.content @@ -2914,7 +3119,7 @@ class BrushFlow(_PluginBase): if torrent_content: torrent = self.tr.add_torrent(content=torrent_content, download_dir=download_dir, - cookie=torrent.site_cookie if need_download_cookie else None, + cookie=cookies, labels=["已整理", brush_config.brush_tag]) if not torrent: return None @@ -2926,6 +3131,66 @@ class BrushFlow(_PluginBase): return torrent.hashString return None + def __qb_add_torrent(self, + content: Union[str, bytes], + is_paused: bool = False, + download_dir: str = None, + tag: Union[str, list] = None, + category: str = None, + cookie=None, + is_auto=False, + **kwargs + ) -> bool: + """ + 添加种子 + :param content: 种子urls或文件内容 + :param is_paused: 添加后暂停 + :param tag: 标签 + :param category: 种子分类 + :param download_dir: 下载路径 + :param cookie: 站点Cookie用于辅助下载种子 + :return: bool + """ + if not self.qb.qbc or not content: + return False + + # 下载内容 + if isinstance(content, str): + urls = content + torrent_files = None + else: + urls = None + torrent_files = content + + # 保存目录 + if download_dir: + save_path = download_dir + else: + save_path = None + + # 标签 + if tag: + tags = tag + else: + tags = None + + try: + # 添加下载 + qbc_ret = self.qb.qbc.torrents_add(urls=urls, + torrent_files=torrent_files, + save_path=save_path, + is_paused=is_paused, + tags=tags, + use_auto_torrent_management=is_auto, + is_sequential_download=settings.QB_SEQUENTIAL, + cookie=cookie, + category=category, + **kwargs) + return True if qbc_ret and str(qbc_ret).find("Ok") != -1 else False + except Exception as err: + logger.error(f"添加种子出错:{str(err)}") + return False + def __get_hash(self, torrent: Any): """ 获取种子hash @@ -3272,10 +3537,10 @@ class BrushFlow(_PluginBase): 获取正在下载的任务数量 """ brush_config = self.__get_brush_config() - downlader = self.__get_downloader(brush_config.downloader) - if not downlader: + downloader = self.__get_downloader(brush_config.downloader) + if not downloader: return 0 - torrents = downlader.get_downloading_torrents() + torrents = downloader.get_downloading_torrents() return len(torrents) or 0 @staticmethod From f4065382263dd773c164cfa3a2679ee7809003b0 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:11:52 +0800 Subject: [PATCH 5/6] fix brushflow 2.9 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 55ee9d7..59ec75d 100644 --- a/package.json +++ b/package.json @@ -241,11 +241,12 @@ "BrushFlow": { "name": "站点刷流", "description": "自动托管刷流,将会提高对应站点的访问频率。", - "version": "2.8", + "version": "2.9", "icon": "brush.jpg", "author": "jxxghp,InfinityPacer", "level": 2, "history": { + "v2.9": "优化动态删除消息推送,优化配置页UI显示及部分配置项,支持配置种子分类以及开启自动分类管理,取消单独适配站点时区逻辑,可通过配置项「pubtime」自行适配", "v2.8": "优化UI显示以及提升性能", "v2.7": "动态删除种子规则调整(请注意查阅插件文档),站点独立配置样式优化、日志优化,修复部分配置项无法配置小数的问题,修复部分场景可能导致重复下载的问题", "v2.6": "修复排除订阅功能", From 99a1601d12e859d4b2903f71dfd92bc29bf62ce3 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:30:10 +0800 Subject: [PATCH 6/6] fix brushflow #6 --- plugins/brushflow/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/brushflow/__init__.py b/plugins/brushflow/__init__.py index 1ded69e..555aee0 100644 --- a/plugins/brushflow/__init__.py +++ b/plugins/brushflow/__init__.py @@ -2952,15 +2952,16 @@ class BrushFlow(_PluginBase): 根据下载器类型初始化下载器实例 """ brush_config = self.__get_brush_config() + self.qb = Qbittorrent() + self.tr = Transmission() if brush_config.downloader == "qbittorrent": - self.qb = Qbittorrent() if self.qb.is_inactive(): self.__log_and_notify_error("站点刷流任务出错:Qbittorrent未连接") return False elif brush_config.downloader == "transmission": - self.tr = Transmission() + if self.tr.is_inactive(): self.__log_and_notify_error("站点刷流任务出错:Transmission未连接") return False