From f9b5b2bb7c5b54baef8677935bd017d8320f6bf2 Mon Sep 17 00:00:00 2001 From: honue Date: Thu, 15 Feb 2024 14:38:28 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=89=A7=E5=90=8D?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- plugins/downloadsitetag/__init__.py | 35 ++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index d0a5084..7fd1df7 100644 --- a/package.json +++ b/package.json @@ -338,7 +338,7 @@ "DownloadSiteTag": { "name": "下载任务分类与标签", "description": "自动给下载任务分类与打站点标签", - "version": "1.1", + "version": "1.2", "icon": "Youtube-dl_B.png", "author": "叮叮当", "level": 1 diff --git a/plugins/downloadsitetag/__init__.py b/plugins/downloadsitetag/__init__.py index 60b3d17..4e78332 100644 --- a/plugins/downloadsitetag/__init__.py +++ b/plugins/downloadsitetag/__init__.py @@ -18,7 +18,7 @@ class DownloadSiteTag(_PluginBase): # 插件图标 plugin_icon = "Youtube-dl_B.png" # 插件版本 - plugin_version = "1.1" + plugin_version = "1.2" # 插件作者 plugin_author = "叮叮当" # 作者主页 @@ -34,6 +34,7 @@ class DownloadSiteTag(_PluginBase): downloader_name = None downloader_example = None _enabled = False + _enabled_media_tag = False _enabled_tag = True _enabled_category = False _category_movie = None @@ -44,6 +45,7 @@ class DownloadSiteTag(_PluginBase): # 读取配置 if config: self._enabled = config.get("enabled") + self._enabled_media_tag = config.get("enabled_media_tag") self._enabled_tag = config.get("enabled_tag") self._enabled_category = config.get("enabled_category") self._category_movie = config.get("category_movie") or "电影" @@ -93,6 +95,9 @@ class DownloadSiteTag(_PluginBase): # 设置标签, 如果勾选开关的话 if self._enabled_tag: self.downloader_example.set_torrents_tag(ids=_hash, tags=[_torrent.site_name]) + # 设置媒体标题标签, 如果勾选开关的话 + if self._enabled_media_tag: + self.downloader_example.set_torrents_tag(ids=_hash, tags=[_media.title]) # 设置分类, 如果勾选开关的话 if self._enabled_category: if _media.type == MediaType.MOVIE: @@ -114,8 +119,11 @@ class DownloadSiteTag(_PluginBase): # 设置标签, 如果勾选开关的话 if self._enabled_tag: self.downloader_example.set_torrent_tag(ids=_hash, tags=[_torrent.site_name]) + # 设置媒体标题标签, 如果勾选开关的话 + if self._enabled_media_tag: + self.downloader_example.set_torrent_tag(ids=_hash, tags=[_media.title]) logger.warn( - f"[DownloadSiteTag] 当前下载器: {self.downloader_name}{(' TAG: ' + _torrent.site_name) if self._enabled_tag else ''}{(' CAT: ' + _media_type) if _media_type else ''}") + f"[DownloadSiteTag] 当前下载器: {self.downloader_name}{(' TAG: ' + _torrent.site_name) if self._enabled_tag else ''}{(' MEDIA_TAG: ' + _media.title) if self._enabled_media_tag else ''}{(' CAT: ' + _media_type) if _media_type else ''}") def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: """ @@ -132,7 +140,7 @@ class DownloadSiteTag(_PluginBase): 'component': 'VCol', 'props': { 'cols': 12, - 'md': 4 + 'md': 3 }, 'content': [ { @@ -148,7 +156,7 @@ class DownloadSiteTag(_PluginBase): 'component': 'VCol', 'props': { 'cols': 12, - 'md': 4 + 'md': 3 }, 'content': [ { @@ -164,7 +172,23 @@ class DownloadSiteTag(_PluginBase): 'component': 'VCol', 'props': { 'cols': 12, - 'md': 4 + 'md': 3 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled_media_tag', + 'label': '自动剧名标签', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 3 }, 'content': [ { @@ -288,6 +312,7 @@ class DownloadSiteTag(_PluginBase): ], { "enabled": False, "enabled_tag": True, + "enabled_media_tag": False, "enabled_category": False, "category_movie": "电影", "category_tv": "电视", From 70ec5ff76e6d7a90f1e918d141c152be45a4cd3a Mon Sep 17 00:00:00 2001 From: honue Date: Thu, 15 Feb 2024 14:41:59 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- plugins/downloadsitetag/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7fd1df7..1ea4469 100644 --- a/package.json +++ b/package.json @@ -337,7 +337,7 @@ }, "DownloadSiteTag": { "name": "下载任务分类与标签", - "description": "自动给下载任务分类与打站点标签", + "description": "自动给下载任务分类与打站点标签、剧集名称标签", "version": "1.2", "icon": "Youtube-dl_B.png", "author": "叮叮当", diff --git a/plugins/downloadsitetag/__init__.py b/plugins/downloadsitetag/__init__.py index 4e78332..063aaa9 100644 --- a/plugins/downloadsitetag/__init__.py +++ b/plugins/downloadsitetag/__init__.py @@ -14,7 +14,7 @@ class DownloadSiteTag(_PluginBase): # 插件名称 plugin_name = "下载任务分类与标签" # 插件描述 - plugin_desc = "自动给下载任务分类与打站点标签" + plugin_desc = "自动给下载任务分类与打站点标签、剧集名称标签" # 插件图标 plugin_icon = "Youtube-dl_B.png" # 插件版本 From ef6ca3e8bdfd3737e74109de68a5383bfb021d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AE=E5=8F=AE=E5=BD=93?= <604054726@qq.com> Date: Sat, 17 Feb 2024 23:25:24 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=8E=86=E5=8F=B2=E7=9A=84=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E4=B8=8E=E5=88=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- plugins/downloadsitetag/__init__.py | 269 ++++++++++++++++++++++------ 2 files changed, 214 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index a12fc8a..ccd6475 100644 --- a/package.json +++ b/package.json @@ -338,7 +338,7 @@ "DownloadSiteTag": { "name": "下载任务分类与标签", "description": "自动给下载任务分类与打站点标签、剧集名称标签", - "version": "1.2", + "version": "1.3", "icon": "Youtube-dl_B.png", "author": "叮叮当", "level": 1 diff --git a/plugins/downloadsitetag/__init__.py b/plugins/downloadsitetag/__init__.py index 063aaa9..7c220e9 100644 --- a/plugins/downloadsitetag/__init__.py +++ b/plugins/downloadsitetag/__init__.py @@ -8,7 +8,8 @@ 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.modules.themoviedb.tmdbapi import TmdbHelper class DownloadSiteTag(_PluginBase): # 插件名称 @@ -18,7 +19,7 @@ class DownloadSiteTag(_PluginBase): # 插件图标 plugin_icon = "Youtube-dl_B.png" # 插件版本 - plugin_version = "1.2" + plugin_version = "1.3" # 插件作者 plugin_author = "叮叮当" # 作者主页 @@ -29,11 +30,16 @@ class DownloadSiteTag(_PluginBase): plugin_order = 2 # 可使用的用户级别 auth_level = 1 + # 日志前缀 + LOG_TAG = "[DownloadSiteTag] " # 私有属性 - downloader_name = None - downloader_example = None + downloader_qb = None + downloader_tr = None + downloadhistory_oper = None + tmdb_helper = None _enabled = False + _onlyonce = False _enabled_media_tag = False _enabled_tag = True _enabled_category = False @@ -42,15 +48,28 @@ class DownloadSiteTag(_PluginBase): _category_anime = None def init_plugin(self, config: dict = None): + self.downloader_qb = Qbittorrent() + self.downloader_tr = Transmission() + self.downloadhistory_oper = DownloadHistoryOper() + self.tmdb_helper = TmdbHelper() # 读取配置 if config: self._enabled = config.get("enabled") + self._onlyonce = config.get("onlyonce") self._enabled_media_tag = config.get("enabled_media_tag") self._enabled_tag = config.get("enabled_tag") self._enabled_category = config.get("enabled_category") 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 self._onlyonce: + # 执行一次, 关闭onlyonce + self._onlyonce = False + config.update({"onlyonce": self._onlyonce}) + self.update_config(config) + # 补全下载历史的标签与分类 + self._complemented_history() def get_state(self) -> bool: return self._enabled @@ -62,6 +81,161 @@ class DownloadSiteTag(_PluginBase): def get_api(self) -> List[Dict[str, Any]]: pass + def _complemented_history(self): + """ + 补全下载历史的标签与分类 + """ + for DOWNLOADER in ["qbittorrent", "transmission"]: + logger.info(f"{self.LOG_TAG}开始扫描下载器 {DOWNLOADER} ...") + # 获取下载器中的种子 + downloader_obj = self._get_downloader(DOWNLOADER) + if not downloader_obj: + logger.error(f"{self.LOG_TAG} 获取下载器失败 {DOWNLOADER}") + continue + torrents, error = downloader_obj.get_torrents() + # 如果下载器获取种子发生错误 或 没有种子 则跳过 + if error or not torrents: + continue + elif torrents: + logger.info(f"{self.LOG_TAG}下载器 {DOWNLOADER} 种子数:{len(torrents)}") + for torrent in torrents: + # 获取种子hash + _hash = self._get_hash(torrent=torrent, dl_type=DOWNLOADER) + if not _hash: + continue + # 提取种子hash对应的下载历史 + history = self.downloadhistory_oper.get_by_hash(_hash) + if not history: + continue + # 获取种子当前标签 + torrent_tags = self._get_label(torrent=torrent, dl_type=DOWNLOADER) + torrent_cat = self._get_category(torrent=torrent, dl_type=DOWNLOADER) + # 按设置生成需要写入的标签与分类 + _tags = [] + _cat = None + tmdbid = history.tmdbid + mtype = history.type + # 站点标签, 如果勾选开关的话 + if self._enabled_tag and history.torrent_site: + _tags.append(history.torrent_site) + # 媒体标题标签, 如果勾选开关的话 + if self._enabled_media_tag and history.title: + _tags.append(history.title) + # 分类, 如果勾选开关的话 + if DOWNLOADER == "qbittorrent" and self._enabled_category: + # 如果是电视剧 需要区分是否动漫 + genre_ids = None + if mtype == MediaType.TV: + # tmdb_id获取tmdb信息 + tmdb_info = self.tmdb_helper.get_info(mtype=mtype, tmdbid=tmdbid) + if tmdb_info: + genre_ids = tmdb_info.get("genre_ids") + _cat = self._genre_ids_get_cat(mtype, genre_ids) + + # 去除种子已经存在的标签 + if _tags and torrent_tags: + _tags = list(set(_tags) - set(torrent_tags)) + # 如果分类一样, 那么不需要修改 + if _cat == torrent_cat: + _cat = None + # 判断当前种子是否不需要修改 + if not _cat and not _tags: + continue + # 执行通用方法, 设置种子标签与分类 + self._set_torrent_info(DOWNLOADER=DOWNLOADER, _hash=_hash, _tags=_tags, _cat=_cat, _original_tags=torrent_tags) + + def _genre_ids_get_cat(self, mtype, genre_ids = None): + """ + 根据genre_ids判断是否<动漫>分类 + """ + _cat = None + if mtype == MediaType.MOVIE: + # 电影 + _cat = self._category_movie + elif mtype: + ANIME_GENREIDS = settings.ANIME_GENREIDS + if genre_ids \ + and set(genre_ids).intersection(set(ANIME_GENREIDS)): + # 动漫 + _cat = self._category_anime + else: + # 电视剧 + _cat = self._category_tv + return _cat + + def _get_downloader(self, dtype: str): + """ + 根据类型返回下载器实例 + """ + if dtype == "qbittorrent": + return self.downloader_qb + elif dtype == "transmission": + return self.downloader_tr + else: + return None + + def _get_hash(self, torrent: Any, dl_type: str): + """ + 获取种子hash + """ + try: + return torrent.get("hash") if dl_type == "qbittorrent" else torrent.hashString + except Exception as e: + print(str(e)) + return "" + + def _get_label(self, torrent: Any, dl_type: str): + """ + 获取种子标签 + """ + try: + return [str(tag).strip() for tag in torrent.get("tags").split(',')] \ + if dl_type == "qbittorrent" else torrent.labels or [] + except Exception as e: + print(str(e)) + return [] + + def _get_category(self, torrent: Any, dl_type: str): + """ + 获取种子分类 + """ + try: + return torrent.get("category") if dl_type == "qbittorrent" else None + except Exception as e: + print(str(e)) + return None + + def _set_torrent_info(self, DOWNLOADER: str, _hash: str, _tags: list, _cat: str, _original_tags: list = None): + """ + 设置种子标签与分类 + """ + # 当前下载器 + downloader_obj = self._get_downloader(DOWNLOADER) + # 判断是否可执行 + if DOWNLOADER and downloader_obj and _hash: + # 下载器api不通用, 因此需分开处理 + if DOWNLOADER == "qbittorrent": + # 设置标签 + if _tags: + downloader_obj.set_torrents_tag(ids=_hash, tags=_tags) + # 设置分类 + if _cat: + downloader_obj.qbc.torrents_set_category(category=_cat, torrent_hashes=_hash) + else: + # 设置标签 + if _tags: + # _original_tags = None表示为指定, 因此需要获取原始标签 + if _original_tags == None: + torrent = downloader_obj.trc.get_torrent(torrent_id=_hash) + if torrent: + _original_tags = self._get_label(torrent=torrent, dl_type=DOWNLOADER) + # 如果原始标签不是空的, 那么合并原始标签 + 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} {(' TAG: ' + ','.join(_tags)) if _tags else ''} {(' CAT: ' + _cat) if _cat else ''}") + @eventmanager.register(EventType.DownloadAdded) def DownloadAdded(self, event: Event): """ @@ -72,58 +246,25 @@ class DownloadSiteTag(_PluginBase): if not event.event_data: return + + context: Context = event.event_data.get("context") + _hash = event.event_data.get("hash") + _torrent = context.torrent_info + _media = context.media_info + _tags = [] + _cat = None + # 站点标签, 如果勾选开关的话 + if self._enabled_tag: + _tags.append(_torrent.site_name) + # 媒体标题标签, 如果勾选开关的话 + if self._enabled_media_tag: + _tags.append(_media.title) + # 分类, 如果勾选开关的话 + if self._enabled_category: + _cat = self._genre_ids_get_cat(_media.type, _media.genre_ids) + # 执行通用方法, 设置种子标签与分类 + self._set_torrent_info(DOWNLOADER=settings.DOWNLOADER, _hash=_hash, _tags=_tags, _cat=_cat) - DOWNLOADER = getattr(settings, "DOWNLOADER") - if self.downloader_name != DOWNLOADER: - if DOWNLOADER == "qbittorrent": - self.downloader_example = Qbittorrent() - self.downloader_name = DOWNLOADER - elif DOWNLOADER == "transmission": - self.downloader_example = Transmission() - self.downloader_name = DOWNLOADER - else: - self.downloader_example = None - self.downloader_name = None - if self.downloader_name and self.downloader_example: - context: Context = event.event_data.get("context") - _hash = event.event_data.get("hash") - _torrent = context.torrent_info - _media = context.media_info - _media_type = None - - if self.downloader_name == "qbittorrent": - # 设置标签, 如果勾选开关的话 - if self._enabled_tag: - self.downloader_example.set_torrents_tag(ids=_hash, tags=[_torrent.site_name]) - # 设置媒体标题标签, 如果勾选开关的话 - if self._enabled_media_tag: - self.downloader_example.set_torrents_tag(ids=_hash, tags=[_media.title]) - # 设置分类, 如果勾选开关的话 - if self._enabled_category: - if _media.type == MediaType.MOVIE: - # 电影 - _media_type = self._category_movie - else: - ANIME_GENREIDS = getattr(settings, "ANIME_GENREIDS") - if _media.genre_ids \ - and set(_media.genre_ids).intersection(set(ANIME_GENREIDS)): - # 动漫 - _media_type = self._category_anime - else: - # 电视剧 - _media_type = self._category_tv - # 使用qbapi进行设置 - if _media_type: - self.downloader_example.qbc.torrents_set_category(category=_media_type, torrent_hashes=_hash) - else: - # 设置标签, 如果勾选开关的话 - if self._enabled_tag: - self.downloader_example.set_torrent_tag(ids=_hash, tags=[_torrent.site_name]) - # 设置媒体标题标签, 如果勾选开关的话 - if self._enabled_media_tag: - self.downloader_example.set_torrent_tag(ids=_hash, tags=[_media.title]) - logger.warn( - f"[DownloadSiteTag] 当前下载器: {self.downloader_name}{(' TAG: ' + _torrent.site_name) if self._enabled_tag else ''}{(' MEDIA_TAG: ' + _media.title) if self._enabled_media_tag else ''}{(' CAT: ' + _media_type) if _media_type else ''}") def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: """ @@ -265,6 +406,21 @@ class DownloadSiteTag(_PluginBase): } ] }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'onlyonce', + 'label': '立即执行一次: 补全下载历史的标签与分类', + } + } + ] + }, { 'component': 'VRow', 'content': [ @@ -300,7 +456,7 @@ class DownloadSiteTag(_PluginBase): 'props': { 'type': 'info', 'variant': 'tonal', - 'text': '注意:分类功能只支持qbittorrent下载器' + 'text': '注意:分类只支持qb, 并提前在qb创建好分类' } } ] @@ -311,6 +467,7 @@ class DownloadSiteTag(_PluginBase): } ], { "enabled": False, + "onlyonce": False, "enabled_tag": True, "enabled_media_tag": False, "enabled_category": False, From 7983c4324f9b73923ee9971f411ce6ead8ea0dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AE=E5=8F=AE=E5=BD=93?= <604054726@qq.com> Date: Sat, 17 Feb 2024 23:32:35 +0800 Subject: [PATCH 4/8] =?UTF-8?q?fix=20=E5=A4=87=E6=B3=A8=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/downloadsitetag/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/downloadsitetag/__init__.py b/plugins/downloadsitetag/__init__.py index 7c220e9..b0d88cb 100644 --- a/plugins/downloadsitetag/__init__.py +++ b/plugins/downloadsitetag/__init__.py @@ -96,7 +96,7 @@ class DownloadSiteTag(_PluginBase): # 如果下载器获取种子发生错误 或 没有种子 则跳过 if error or not torrents: continue - elif torrents: + else: logger.info(f"{self.LOG_TAG}下载器 {DOWNLOADER} 种子数:{len(torrents)}") for torrent in torrents: # 获取种子hash @@ -224,7 +224,7 @@ class DownloadSiteTag(_PluginBase): else: # 设置标签 if _tags: - # _original_tags = None表示为指定, 因此需要获取原始标签 + # _original_tags = None表示未指定, 因此需要获取原始标签 if _original_tags == None: torrent = downloader_obj.trc.get_torrent(torrent_id=_hash) if torrent: From 7aaa6727e679420685d665759d8eec15241cfae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AE=E5=8F=AE=E5=BD=93?= <604054726@qq.com> Date: Sun, 18 Feb 2024 00:13:18 +0800 Subject: [PATCH 5/8] =?UTF-8?q?fix=20=E5=AA=92=E4=BD=93=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E7=9A=84=E9=97=AE=E9=A2=98/=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E8=AE=BE=E7=BD=AE=E6=97=B6=E8=A2=AB=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=8D=A1=E4=BD=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/downloadsitetag/__init__.py | 43 ++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/plugins/downloadsitetag/__init__.py b/plugins/downloadsitetag/__init__.py index b0d88cb..4aa089a 100644 --- a/plugins/downloadsitetag/__init__.py +++ b/plugins/downloadsitetag/__init__.py @@ -1,3 +1,5 @@ +import datetime +import pytz from typing import List, Tuple, Dict, Any from app.core.context import Context @@ -10,6 +12,7 @@ from app.modules.qbittorrent import Qbittorrent from app.modules.transmission import Transmission from app.db.downloadhistory_oper import DownloadHistoryOper from app.modules.themoviedb.tmdbapi import TmdbHelper +from apscheduler.schedulers.background import BackgroundScheduler class DownloadSiteTag(_PluginBase): # 插件名称 @@ -38,6 +41,7 @@ class DownloadSiteTag(_PluginBase): downloader_tr = None downloadhistory_oper = None tmdb_helper = None + _scheduler = None _enabled = False _onlyonce = False _enabled_media_tag = False @@ -63,13 +67,26 @@ class DownloadSiteTag(_PluginBase): self._category_tv = config.get("category_tv") or "电视" self._category_anime = config.get("category_anime") or "动漫" + # 停止现有任务 + self.stop_service() + if self._onlyonce: + # 创建定时任务控制器 + self._scheduler = BackgroundScheduler(timezone=settings.TZ) # 执行一次, 关闭onlyonce self._onlyonce = False config.update({"onlyonce": self._onlyonce}) self.update_config(config) - # 补全下载历史的标签与分类 - self._complemented_history() + # 添加 补全下载历史的标签与分类 任务 + self._scheduler.add_job(func= self._complemented_history, trigger='date', + run_date=datetime.datetime.now( + tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3) + ) + + if self._scheduler and self._scheduler.get_jobs(): + # 启动服务 + self._scheduler.print_jobs() + self._scheduler.start() def get_state(self) -> bool: return self._enabled @@ -85,6 +102,7 @@ class DownloadSiteTag(_PluginBase): """ 补全下载历史的标签与分类 """ + logger.info(f"{self.LOG_TAG}开始执行: 补全下载历史的标签与分类 ...") for DOWNLOADER in ["qbittorrent", "transmission"]: logger.info(f"{self.LOG_TAG}开始扫描下载器 {DOWNLOADER} ...") # 获取下载器中的种子 @@ -122,10 +140,10 @@ class DownloadSiteTag(_PluginBase): if self._enabled_media_tag and history.title: _tags.append(history.title) # 分类, 如果勾选开关的话 - if DOWNLOADER == "qbittorrent" and self._enabled_category: + if DOWNLOADER == "qbittorrent" and self._enabled_category and not torrent_cat: # 如果是电视剧 需要区分是否动漫 genre_ids = None - if mtype == MediaType.TV: + if mtype == MediaType.TV or mtype == MediaType.TV.value: # tmdb_id获取tmdb信息 tmdb_info = self.tmdb_helper.get_info(mtype=mtype, tmdbid=tmdbid) if tmdb_info: @@ -144,12 +162,14 @@ class DownloadSiteTag(_PluginBase): # 执行通用方法, 设置种子标签与分类 self._set_torrent_info(DOWNLOADER=DOWNLOADER, _hash=_hash, _tags=_tags, _cat=_cat, _original_tags=torrent_tags) + logger.info(f"{self.LOG_TAG}执行完成: 补全下载历史的标签与分类 ...") + def _genre_ids_get_cat(self, mtype, genre_ids = None): """ 根据genre_ids判断是否<动漫>分类 """ _cat = None - if mtype == MediaType.MOVIE: + if mtype == MediaType.MOVIE or mtype == MediaType.MOVIE.value: # 电影 _cat = self._category_movie elif mtype: @@ -481,6 +501,15 @@ class DownloadSiteTag(_PluginBase): def stop_service(self): """ - 退出插件 + 停止服务 """ - pass + try: + if self._scheduler: + self._scheduler.remove_all_jobs() + if self._scheduler.running: + self._event.set() + self._scheduler.shutdown() + self._event.clear() + self._scheduler = None + except Exception as e: + print(str(e)) From bd9066271d1fbe65d817027a8396de1dfcf97e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AE=E5=8F=AE=E5=BD=93?= <604054726@qq.com> Date: Sun, 18 Feb 2024 13:12:12 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=88=B7=E6=B5=81=E4=B8=8E=E8=BE=85=E7=A7=8D=E7=9A=84=E7=A7=8D?= =?UTF-8?q?=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- plugins/downloadsitetag/__init__.py | 131 ++++++++++++++++++++++++---- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index ccd6475..86c5be3 100644 --- a/package.json +++ b/package.json @@ -338,7 +338,7 @@ "DownloadSiteTag": { "name": "下载任务分类与标签", "description": "自动给下载任务分类与打站点标签、剧集名称标签", - "version": "1.3", + "version": "1.5", "icon": "Youtube-dl_B.png", "author": "叮叮当", "level": 1 diff --git a/plugins/downloadsitetag/__init__.py b/plugins/downloadsitetag/__init__.py index 4aa089a..df9d6e2 100644 --- a/plugins/downloadsitetag/__init__.py +++ b/plugins/downloadsitetag/__init__.py @@ -11,8 +11,11 @@ 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 from app.modules.themoviedb.tmdbapi import TmdbHelper from apscheduler.schedulers.background import BackgroundScheduler +from app.helper.sites import SitesHelper +from app.utils.string import StringUtils class DownloadSiteTag(_PluginBase): # 插件名称 @@ -22,7 +25,7 @@ class DownloadSiteTag(_PluginBase): # 插件图标 plugin_icon = "Youtube-dl_B.png" # 插件版本 - plugin_version = "1.3" + plugin_version = "1.5" # 插件作者 plugin_author = "叮叮当" # 作者主页 @@ -103,6 +106,8 @@ class DownloadSiteTag(_PluginBase): 补全下载历史的标签与分类 """ logger.info(f"{self.LOG_TAG}开始执行: 补全下载历史的标签与分类 ...") + # 记录处理的种子, 供辅种(无下载历史)使用 + dispose_history = {} for DOWNLOADER in ["qbittorrent", "transmission"]: logger.info(f"{self.LOG_TAG}开始扫描下载器 {DOWNLOADER} ...") # 获取下载器中的种子 @@ -116,39 +121,68 @@ class DownloadSiteTag(_PluginBase): continue else: logger.info(f"{self.LOG_TAG}下载器 {DOWNLOADER} 种子数:{len(torrents)}") + # 按添加时间进行排序, 时间靠前的按大小和名称加入处理历史, 判定为原始种子, 其他为辅种 + torrents = self._torrents_sort(torrents=torrents, dl_type=DOWNLOADER) for torrent in torrents: + # 获取已处理种子的key (size, name) + _key = self._torrent_key(torrent=torrent, dl_type=DOWNLOADER) # 获取种子hash _hash = self._get_hash(torrent=torrent, dl_type=DOWNLOADER) if not _hash: continue # 提取种子hash对应的下载历史 - history = self.downloadhistory_oper.get_by_hash(_hash) + history: DownloadHistory = self.downloadhistory_oper.get_by_hash(_hash) if not history: - continue + # 如果找到已处理种子的历史, 表明当前种子是辅种, 否则创建一个空DownloadHistory + if _key and _key in dispose_history: + history = dispose_history[_key] + # 因为辅种站点必定不同, 所以需要更新站点名字 history.torrent_site + history.torrent_site = None + else: + history = DownloadHistory( + torrent_site=None, + title=None, + type=None, + tmdbid=None) + else: + # 加入历史记录 + if _key: + dispose_history[_key] = history + # 如果站点名称为空, 尝试通过trackers识别 + if not history.torrent_site: + trackers = self._get_trackers(torrent=torrent, dl_type=DOWNLOADER) + for tracker in trackers: + domain = StringUtils.get_url_domain(tracker) + site_info = SitesHelper().get_indexer(domain) + if site_info: + history.torrent_site = site_info.get("name") + break + # 如果通过tracker还是无法获取站点名称, 且tmdbid, type, title都是空的, 那么跳过当前种子 + if not history.torrent_site and not history.tmdbid and not history.type and not history.title: + continue # 获取种子当前标签 torrent_tags = self._get_label(torrent=torrent, dl_type=DOWNLOADER) torrent_cat = self._get_category(torrent=torrent, dl_type=DOWNLOADER) # 按设置生成需要写入的标签与分类 _tags = [] _cat = None - tmdbid = history.tmdbid - mtype = history.type - # 站点标签, 如果勾选开关的话 + # 站点标签, 如果勾选开关的话 因允许torrent_site为空时运行到此, 因此需要判断torrent_site不为空 if self._enabled_tag and history.torrent_site: _tags.append(history.torrent_site) - # 媒体标题标签, 如果勾选开关的话 + # 媒体标题标签, 如果勾选开关的话 因允许title为空时运行到此, 因此需要判断title不为空 if self._enabled_media_tag and history.title: _tags.append(history.title) - # 分类, 如果勾选开关的话 - if DOWNLOADER == "qbittorrent" and self._enabled_category and not torrent_cat: + # 分类, 如果勾选开关的话 因允许mtype为空时运行到此, 因此需要判断mtype不为空。为防止不必要的识别, 种子已经存在分类torrent_cat时 也不执行 + if DOWNLOADER == "qbittorrent" and self._enabled_category and not torrent_cat and history.type: # 如果是电视剧 需要区分是否动漫 genre_ids = None - if mtype == MediaType.TV or mtype == MediaType.TV.value: + # 因允许tmdbid为空时运行到此, 因此需要判断tmdbid不为空 + if history.tmdbid and (history.type == MediaType.TV or history.type == MediaType.TV.value): # tmdb_id获取tmdb信息 - tmdb_info = self.tmdb_helper.get_info(mtype=mtype, tmdbid=tmdbid) + tmdb_info = self.tmdb_helper.get_info(mtype=history.type, tmdbid=history.tmdbid) if tmdb_info: genre_ids = tmdb_info.get("genre_ids") - _cat = self._genre_ids_get_cat(mtype, genre_ids) + _cat = self._genre_ids_get_cat(history.type, genre_ids) # 去除种子已经存在的标签 if _tags and torrent_tags: @@ -194,6 +228,33 @@ class DownloadSiteTag(_PluginBase): else: return None + def _torrent_key(self, torrent: Any, dl_type: str): + """ + 按种子大小和时间返回key + """ + size = None + name = None + if dl_type == "qbittorrent": + size = torrent.get('size') + name = torrent.get('name') + else: + size = torrent.total_size + name = torrent.name + if not size or not name: + return None + else: + return (size, name) + + def _torrents_sort(self, torrents: Any, dl_type: str): + """ + 按种子添加时间排序 + """ + if dl_type == "qbittorrent": + torrents = sorted(torrents, key=lambda x: x.get("added_on"), reverse=False) + else: + torrents = sorted(torrents, key=lambda x: x.added_date, reverse=False) + return torrents + def _get_hash(self, torrent: Any, dl_type: str): """ 获取种子hash @@ -204,12 +265,53 @@ class DownloadSiteTag(_PluginBase): print(str(e)) return "" + def _get_trackers(self, torrent: Any, dl_type: str): + """ + 获取种子trackers + """ + try: + if dl_type == "qbittorrent": + """ + url 字符串 跟踪器网址 + status 整数 跟踪器状态。有关可能的值,请参阅下表 + tier 整数 跟踪器优先级。较低级别的跟踪器在较高级别的跟踪器之前试用。当特殊条目(如 DHT)不存在时,层号用作占位符时,层号有效。>= 0< 0tier + num_peers 整数 跟踪器报告的当前 torrent 的对等体数量 + num_seeds 整数 当前种子的种子数,由跟踪器报告 + num_leeches 整数 当前种子的水蛭数量,如跟踪器报告的那样 + num_downloaded 整数 跟踪器报告的当前 torrent 的已完成下载次数 + msg 字符串 跟踪器消息(无法知道此消息是什么 - 由跟踪器管理员决定) + """ + return [tracker.get("url") for tracker in (torrent.trackers or []) if tracker.get("tier", -1) >= 0 and tracker.get("url")] + else: + """ + class Tracker(Container): + @property + def id(self) -> int: + return self.fields["id"] + + @property + def announce(self) -> str: + return self.fields["announce"] + + @property + def scrape(self) -> str: + return self.fields["scrape"] + + @property + def tier(self) -> int: + return self.fields["tier"] + """ + return [tracker.announce for tracker in (torrent.trackers or []) if tracker.tier >= 0 and tracker.announce] + except Exception as e: + print(str(e)) + return [] + def _get_label(self, torrent: Any, dl_type: str): """ 获取种子标签 """ try: - return [str(tag).strip() for tag in torrent.get("tags").split(',')] \ + return [str(tag).strip() for tag in torrent.get("tags", "").split(',')] \ if dl_type == "qbittorrent" else torrent.labels or [] except Exception as e: print(str(e)) @@ -253,8 +355,7 @@ class DownloadSiteTag(_PluginBase): 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} {(' TAG: ' + ','.join(_tags)) if _tags else ''} {(' CAT: ' + _cat) if _cat else ''}") + logger.warn(f"{self.LOG_TAG}下载器: {DOWNLOADER} 种子id: {_hash} {(' 标签: ' + ','.join(_tags)) if _tags else ''} {(' 分类: ' + _cat) if _cat else ''}") @eventmanager.register(EventType.DownloadAdded) def DownloadAdded(self, event: Event): From 73ba6c6e7d53fd83385c3f70ccb3b3041e9df05d Mon Sep 17 00:00:00 2001 From: Edward <73746306+WangEdward@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:51:19 +0800 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=AB=99?= =?UTF-8?q?=E7=82=B9=E5=88=B7=E6=96=B0=E4=BA=8C=E6=AC=A1=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/siterefresh/__init__.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/siterefresh/__init__.py b/plugins/siterefresh/__init__.py index 90e6998..c521da3 100644 --- a/plugins/siterefresh/__init__.py +++ b/plugins/siterefresh/__init__.py @@ -17,7 +17,7 @@ class SiteRefresh(_PluginBase): # 插件图标 plugin_icon = "Chrome_A.png" # 插件版本 - plugin_version = "1.0" + plugin_version = "1.1" # 插件作者 plugin_author = "thsrite" # 作者主页 @@ -83,12 +83,11 @@ class SiteRefresh(_PluginBase): if not site_conf: continue site_confs = str(site_conf).split("|") - if len(site_confs) == 3: - siteurl = site_confs[0] - siteuser = site_confs[1] - sitepwd = site_confs[2] - else: - logger.error(f"{site_conf}配置有误,已跳过") + try: + siteurl, siteuser, sitepwd, *sitecode = site_confs + sitecode = str(sitecode[0]) if sitecode else "" + except Exception as e: + logger.error(f"{site_conf}配置有误:{e},已跳过") continue # 判断是否是目标域名 @@ -100,7 +99,8 @@ class SiteRefresh(_PluginBase): if siteurl and siteuser and sitepwd: state, messages = SiteChain().update_cookie(site_info=site, username=siteuser, - password=sitepwd) + password=sitepwd, + two_step_code=sitecode) if state: logger.info(f"站点{site_name}自动更新Cookie和Ua成功") else: @@ -181,7 +181,7 @@ class SiteRefresh(_PluginBase): 'label': '站点配置', 'rows': 5, 'placeholder': '每一行一个站点,配置方式:\n' - '域名domain|用户名|用户密码\n' + '域名domain|用户名|用户密码(|二次验证秘钥)\n' } } ] From 4d39cdab867c52d51ca119d9b6eb83bee585f9c7 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 19 Feb 2024 13:38:53 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 86c5be3..29e1eff 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "SiteRefresh": { "name": "站点自动更新", "description": "使用浏览器模拟登录站点获取Cookie和UA。", - "version": "1.0", + "version": "1.1", "icon": "Chrome_A.png", "author": "thsrite", "level": 2