From b340ccbb18ddf9557954f676947f2f49ad08f0fe Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:56:53 +0800 Subject: [PATCH 1/2] feat(DownloadSiteTag): add support for v2 plugin --- plugins.v2/downloadsitetag/__init__.py | 163 +++++++++++++++++-------- 1 file changed, 113 insertions(+), 50 deletions(-) diff --git a/plugins.v2/downloadsitetag/__init__.py b/plugins.v2/downloadsitetag/__init__.py index 6c473e2..804a99c 100644 --- a/plugins.v2/downloadsitetag/__init__.py +++ b/plugins.v2/downloadsitetag/__init__.py @@ -1,25 +1,28 @@ import datetime -import pytz import threading from typing import List, Tuple, Dict, Any, Optional -from app.core.context import Context -from app.core.event import eventmanager, Event -from app.schemas.types import EventType, MediaType -from app.core.config import settings -from app.log import logger -from app.plugins import _PluginBase -from app.modules.qbittorrent import Qbittorrent -from app.modules.transmission import Transmission -from app.db.downloadhistory_oper import DownloadHistoryOper -from app.db.models.downloadhistory import DownloadHistory +import pytz +from app.helper.sites import SitesHelper from apscheduler.schedulers.background import BackgroundScheduler from apscheduler.triggers.cron import CronTrigger -from app.helper.sites import SitesHelper + +from app.core.config import settings +from app.core.context import Context +from app.core.event import eventmanager, Event +from app.db.downloadhistory_oper import DownloadHistoryOper +from app.db.models.downloadhistory import DownloadHistory +from app.helper.downloader import DownloaderHelper +from app.log import logger +from app.plugins import _PluginBase +from app.schemas import ServiceInfo +from app.schemas.types import EventType, MediaType from app.utils.string import StringUtils class DownloadSiteTag(_PluginBase): + # region 全局定义 + # 插件名称 plugin_name = "下载任务分类与标签" # 插件描述 @@ -44,10 +47,9 @@ class DownloadSiteTag(_PluginBase): # 退出事件 _event = threading.Event() # 私有属性 - downloader_qb = None - downloader_tr = None downloadhistory_oper = None sites_helper = None + downloaderhelper = None _scheduler = None _enabled = False _onlyonce = False @@ -61,11 +63,42 @@ class DownloadSiteTag(_PluginBase): _category_movie = None _category_tv = None _category_anime = None + _downloaders = None + + # Property + + @property + def service_infos(self) -> Optional[Dict[str, ServiceInfo]]: + """ + 服务信息 + """ + if not self._downloaders: + logger.warning("尚未配置下载器,请检查配置") + return None + + services = self.downloaderhelper.get_services(name_filters=self._downloaders) + if not services: + logger.warning("获取下载器实例失败,请检查配置") + return None + + active_services = {} + for service_name, service_info in services.items(): + if service_info.instance.is_inactive(): + logger.warning(f"下载器 {service_name} 未连接,请检查配置") + else: + active_services[service_name] = service_info + + if not active_services: + logger.warning("没有已连接的下载器,请检查配置") + return None + + return active_services + + # endregion def init_plugin(self, config: dict = None): - self.downloader_qb = Qbittorrent() - self.downloader_tr = Transmission() self.downloadhistory_oper = DownloadHistoryOper() + self.downloaderhelper = DownloaderHelper() self.sites_helper = SitesHelper() # 读取配置 if config: @@ -81,14 +114,7 @@ class DownloadSiteTag(_PluginBase): self._category_movie = config.get("category_movie") or "电影" self._category_tv = config.get("category_tv") or "电视" self._category_anime = config.get("category_anime") or "动漫" - if not ("interval_cron" in config): - # 新版本v1.6更新插件配置默认配置 - config["interval"] = self._interval - config["interval_cron"] = self._interval_cron - config["interval_time"] = self._interval_time - config["interval_unit"] = self._interval_unit - self.update_config(config) - logger.warn(f"{self.LOG_TAG}新版本v{self.plugin_version} 配置修正 ...") + self._downloaders = config.get("downloaders") # 停止现有任务 self.stop_service() @@ -179,6 +205,8 @@ class DownloadSiteTag(_PluginBase): """ 补全下载历史的标签与分类 """ + if not self.service_infos: + return logger.info(f"{self.LOG_TAG}开始执行 ...") # 记录处理的种子, 供辅种(无下载历史)使用 dispose_history = {} @@ -192,21 +220,21 @@ class DownloadSiteTag(_PluginBase): "agsvpt.trackers.work": "agsvpt.com", "tracker.cinefiles.info": "audiences.me", } - for DOWNLOADER in ["qbittorrent", "transmission"]: - logger.info(f"{self.LOG_TAG}开始扫描下载器 {DOWNLOADER} ...") + for name, service in self.service_infos.items(): + logger.info(f"{self.LOG_TAG}开始扫描下载器 {name} ...") # 获取下载器中的种子 - downloader_obj = self._get_downloader(DOWNLOADER) + downloader_obj = service.instance if not downloader_obj: - logger.error(f"{self.LOG_TAG} 获取下载器失败 {DOWNLOADER}") + logger.error(f"{self.LOG_TAG} 获取下载器失败 {name}") continue torrents, error = downloader_obj.get_torrents() # 如果下载器获取种子发生错误 或 没有种子 则跳过 if error or not torrents: continue - logger.info(f"{self.LOG_TAG}按时间重新排序 {DOWNLOADER} 种子数:{len(torrents)}") + logger.info(f"{self.LOG_TAG}按时间重新排序 {name} 种子数:{len(torrents)}") # 按添加时间进行排序, 时间靠前的按大小和名称加入处理历史, 判定为原始种子, 其他为辅种 - torrents = self._torrents_sort(torrents=torrents, dl_type=DOWNLOADER) - logger.info(f"{self.LOG_TAG}下载器 {DOWNLOADER} 分析种子信息中 ...") + torrents = self._torrents_sort(torrents=torrents, dl_type=service.type) + logger.info(f"{self.LOG_TAG}下载器 {name} 分析种子信息中 ...") for torrent in torrents: try: if self._event.is_set(): @@ -214,14 +242,14 @@ class DownloadSiteTag(_PluginBase): f"{self.LOG_TAG}停止服务") return # 获取已处理种子的key (size, name) - _key = self._torrent_key(torrent=torrent, dl_type=DOWNLOADER) + _key = self._torrent_key(torrent=torrent, dl_type=service.type) # 获取种子hash - _hash = self._get_hash(torrent=torrent, dl_type=DOWNLOADER) + _hash = self._get_hash(torrent=torrent, dl_type=service.type) if not _hash: continue # 获取种子当前标签 - torrent_tags = self._get_label(torrent=torrent, dl_type=DOWNLOADER) - torrent_cat = self._get_category(torrent=torrent, dl_type=DOWNLOADER) + torrent_tags = self._get_label(torrent=torrent, dl_type=service.type) + torrent_cat = self._get_category(torrent=torrent, dl_type=service.type) # 提取种子hash对应的下载历史 history: DownloadHistory = self.downloadhistory_oper.get_by_hash(_hash) if not history: @@ -241,7 +269,7 @@ class DownloadSiteTag(_PluginBase): history.torrent_site = None # 如果站点名称为空, 尝试通过trackers识别 elif not history.torrent_site: - trackers = self._get_trackers(torrent=torrent, dl_type=DOWNLOADER) + trackers = self._get_trackers(torrent=torrent, dl_type=service.type) for tracker in trackers: # 检查tracker是否包含特定的关键字,并进行相应的映射 for key, mapped_domain in tracker_mappings.items(): @@ -267,7 +295,7 @@ class DownloadSiteTag(_PluginBase): if self._enabled_media_tag and history.title: _tags.append(history.title) # 分类, 如果勾选开关的话 因允许mtype为空时运行到此, 因此需要判断mtype不为空。为防止不必要的识别, 种子已经存在分类torrent_cat时 也不执行 - if DOWNLOADER == "qbittorrent" and self._enabled_category and not torrent_cat and history.type: + if service.type == "qbittorrent" and self._enabled_category and not torrent_cat and history.type: # 如果是电视剧 需要区分是否动漫 genre_ids = None # 因允许tmdbid为空时运行到此, 因此需要判断tmdbid不为空 @@ -289,7 +317,7 @@ class DownloadSiteTag(_PluginBase): if not _cat and not _tags: continue # 执行通用方法, 设置种子标签与分类 - self._set_torrent_info(DOWNLOADER=DOWNLOADER, _hash=_hash, _torrent=torrent, _tags=_tags, _cat=_cat, + self._set_torrent_info(service=service, _hash=_hash, _torrent=torrent, _tags=_tags, _cat=_cat, _original_tags=torrent_tags) except Exception as e: logger.error( @@ -432,15 +460,16 @@ class DownloadSiteTag(_PluginBase): print(str(e)) return None - def _set_torrent_info(self, DOWNLOADER: str, _hash: str, _torrent: Any = None, _tags=None, _cat: str = None, + def _set_torrent_info(self, service: ServiceInfo, _hash: str, _torrent: Any = None, _tags=None, _cat: str = None, _original_tags: list = None): """ 设置种子标签与分类 """ - # 当前下载器 + if not service or not service.instance: + return if _tags is None: _tags = [] - downloader_obj = self._get_downloader(DOWNLOADER) + downloader_obj = service.instance if not _torrent: _torrent, error = downloader_obj.get_torrents(ids=_hash) if not _torrent or error: @@ -451,9 +480,9 @@ class DownloadSiteTag(_PluginBase): f"{self.LOG_TAG}设置种子标签与分类: {_hash} 查询到 {len(_torrent)} 个种子") _torrent = _torrent[0] # 判断是否可执行 - if DOWNLOADER and downloader_obj and _hash and _torrent: + if _hash and _torrent: # 下载器api不通用, 因此需分开处理 - if DOWNLOADER == "qbittorrent": + if service.type == "qbittorrent": # 设置标签 if _tags: downloader_obj.set_torrents_tag(ids=_hash, tags=_tags) @@ -463,7 +492,7 @@ class DownloadSiteTag(_PluginBase): try: _torrent.setCategory(category=_cat) except Exception as e: - logger.warn(f"下载器 {DOWNLOADER} 种子id: {_hash} 设置分类 {_cat} 失败:{str(e)}, " + logger.warn(f"下载器 {service.name} 种子id: {_hash} 设置分类 {_cat} 失败:{str(e)}, " f"尝试创建分类再设置 ...") downloader_obj.qbc.torrents_createCategory(name=_cat) _torrent.setCategory(category=_cat) @@ -472,16 +501,16 @@ class DownloadSiteTag(_PluginBase): if _tags: # _original_tags = None表示未指定, 因此需要获取原始标签 if _original_tags is None: - _original_tags = self._get_label(torrent=_torrent, dl_type=DOWNLOADER) + _original_tags = self._get_label(torrent=_torrent, dl_type=service.type) # 如果原始标签不是空的, 那么合并原始标签 if _original_tags: _tags = list(set(_original_tags).union(set(_tags))) downloader_obj.set_torrent_tag(ids=_hash, tags=_tags) logger.warn( - f"{self.LOG_TAG}下载器: {DOWNLOADER} 种子id: {_hash} {(' 标签: ' + ','.join(_tags)) if _tags else ''} {(' 分类: ' + _cat) if _cat else ''}") + f"{self.LOG_TAG}下载器: {service.name} 种子id: {_hash} {(' 标签: ' + ','.join(_tags)) if _tags else ''} {(' 分类: ' + _cat) if _cat else ''}") @eventmanager.register(EventType.DownloadAdded) - def DownloadAdded(self, event: Event): + def download_added(self, event: Event): """ 添加下载事件 """ @@ -492,6 +521,16 @@ class DownloadSiteTag(_PluginBase): return try: + downloader = event.event_data.get("downloader") + if not downloader: + logger.info("触发添加下载事件,但没有获取到下载器信息,跳过后续处理") + return + + service = self.service_infos.get(downloader) + if not service: + logger.info(f"触发添加下载事件,但没有监听下载器 {downloader},跳过后续处理") + return + context: Context = event.event_data.get("context") _hash = event.event_data.get("hash") _torrent = context.torrent_info @@ -509,7 +548,7 @@ class DownloadSiteTag(_PluginBase): _cat = self._genre_ids_get_cat(_media.type, _media.genre_ids) if _hash and (_tags or _cat): # 执行通用方法, 设置种子标签与分类 - self._set_torrent_info(DOWNLOADER=settings.DEFAULT_DOWNLOADER, _hash=_hash, _tags=_tags, _cat=_cat) + self._set_torrent_info(service=service, _hash=_hash, _tags=_tags, _cat=_cat) except Exception as e: logger.error( f"{self.LOG_TAG}分析下载事件时发生了错误: {str(e)}") @@ -597,8 +636,7 @@ class DownloadSiteTag(_PluginBase): { 'component': 'VCol', 'props': { - 'cols': 12, - 'md': 12 + 'cols': 12 }, 'content': [ { @@ -612,6 +650,31 @@ class DownloadSiteTag(_PluginBase): } ] }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'multiple': True, + 'chips': True, + 'clearable': True, + 'model': 'downloaders', + 'label': '下载器', + 'items': [{"title": config.name, "value": config.name} + for config in self.downloaderhelper.get_configs().values()] + } + } + ] + } + ] + }, { 'component': 'VRow', 'content': [ From fa2e8398d7c5d9c1eca4ff6e32520c795b640093 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:57:07 +0800 Subject: [PATCH 2/2] feat(DownloadSiteTag): v2.2 --- package.v2.json | 12 ++++++++++++ plugins.v2/downloadsitetag/__init__.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/package.v2.json b/package.v2.json index b3d55c3..87b8990 100644 --- a/package.v2.json +++ b/package.v2.json @@ -34,5 +34,17 @@ "history": { "v2.5": "MoviePilot V2 版本站点自动签到插件" } + }, + "DownloadSiteTag": { + "name": "下载任务分类与标签", + "description": "自动给下载任务分类与打站点标签、剧集名称标签", + "labels": "下载管理", + "version": "2.2", + "icon": "Youtube-dl_B.png", + "author": "叮叮当", + "level": 1, + "history": { + "v2.2": "MoviePilot V2 版本下载任务分类与标签插件" + } } } \ No newline at end of file diff --git a/plugins.v2/downloadsitetag/__init__.py b/plugins.v2/downloadsitetag/__init__.py index 804a99c..4a93b21 100644 --- a/plugins.v2/downloadsitetag/__init__.py +++ b/plugins.v2/downloadsitetag/__init__.py @@ -30,7 +30,7 @@ class DownloadSiteTag(_PluginBase): # 插件图标 plugin_icon = "Youtube-dl_B.png" # 插件版本 - plugin_version = "2.1" + plugin_version = "2.2" # 插件作者 plugin_author = "叮叮当" # 作者主页