From 465fef34bd0e8149c7f3d2871278a54467404fe0 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:32:18 +0800 Subject: [PATCH 1/3] style: keep consistent code style and formatting --- plugins.v2/brushflow/__init__.py | 102 +++++++++++----------- plugins.v2/downloadsitetag/__init__.py | 66 +++++++------- plugins.v2/mediaserverrefresh/__init__.py | 16 ++-- 3 files changed, 87 insertions(+), 97 deletions(-) diff --git a/plugins.v2/brushflow/__init__.py b/plugins.v2/brushflow/__init__.py index 8d0af67..0ec911c 100644 --- a/plugins.v2/brushflow/__init__.py +++ b/plugins.v2/brushflow/__init__.py @@ -259,11 +259,11 @@ class BrushFlow(_PluginBase): auth_level = 2 # 私有属性 - siteshelper = None - siteoper = None - torrentschain = None - subscribeoper = None - downloaderhelper = None + sites_helper = None + site_oper = None + torrents_chain = None + subscribe_oper = None + downloader_helper = None # 刷流配置 _brush_config = None # Brush任务是否启动 @@ -280,40 +280,14 @@ class BrushFlow(_PluginBase): # tabs _tabs = None - # Property - - @property - def service_info(self) -> Optional[ServiceInfo]: - """ - 服务信息 - """ - brush_config = self.__get_brush_config() - service = self.downloaderhelper.get_service(name=brush_config.downloader) - if not service: - self.__log_and_notify_error("站点刷流任务出错,获取下载器实例失败,请检查配置") - return None - - if service.instance.is_inactive(): - self.__log_and_notify_error("站点刷流任务出错,下载器未连接") - return None - - return service - - @property - def downloader(self) -> Optional[Union[Qbittorrent, Transmission]]: - """ - 下载器实例 - """ - return self.service_info.instance if self.service_info else None - # endregion def init_plugin(self, config: dict = None): - self.siteshelper = SitesHelper() - self.siteoper = SiteOper() - self.torrentschain = TorrentsChain() - self.subscribeoper = SubscribeOper() - self.downloaderhelper = DownloaderHelper() + self.sites_helper = SitesHelper() + self.site_oper = SiteOper() + self.torrents_chain = TorrentsChain() + self.subscribe_oper = SubscribeOper() + self.downloader_helper = DownloaderHelper() self._task_brush_enable = False if not config: @@ -335,7 +309,7 @@ class BrushFlow(_PluginBase): # 这里先过滤掉已删除的站点并保存,特别注意的是,这里保留了界面选择站点时的顺序,以便后续站点随机刷流或顺序刷流 if brush_config.brushsites: - site_id_to_public_status = {site.get("id"): site.get("public") for site in self.siteshelper.get_indexers()} + site_id_to_public_status = {site.get("id"): site.get("public") for site in self.sites_helper.get_indexers()} brush_config.brushsites = [ site_id for site_id in brush_config.brushsites if site_id in site_id_to_public_status and not site_id_to_public_status[site_id] @@ -401,6 +375,30 @@ class BrushFlow(_PluginBase): self._scheduler.print_jobs() self._scheduler.start() + @property + def service_info(self) -> Optional[ServiceInfo]: + """ + 服务信息 + """ + brush_config = self.__get_brush_config() + service = self.downloader_helper.get_service(name=brush_config.downloader) + if not service: + self.__log_and_notify_error("站点刷流任务出错,获取下载器实例失败,请检查配置") + return None + + if service.instance.is_inactive(): + self.__log_and_notify_error("站点刷流任务出错,下载器未连接") + return None + + return service + + @property + def downloader(self) -> Optional[Union[Qbittorrent, Transmission]]: + """ + 下载器实例 + """ + return self.service_info.instance if self.service_info else None + def get_state(self) -> bool: brush_config = self.__get_brush_config() return True if brush_config and brush_config.enabled else False @@ -795,10 +793,10 @@ class BrushFlow(_PluginBase): # 站点选项 site_options = [{"title": site.get("name"), "value": site.get("id")} - for site in self.siteshelper.get_indexers()] + for site in self.sites_helper.get_indexers()] # 下载器选项 downloader_options = [{"title": config.name, "value": config.name} - for config in self.downloaderhelper.get_configs().values()] + for config in self.downloader_helper.get_configs().values()] return [ { 'component': 'VForm', @@ -1908,7 +1906,7 @@ class BrushFlow(_PluginBase): # 获取所有站点的信息,并过滤掉不存在的站点 site_infos = [] for siteid in brush_config.brushsites: - siteinfo = self.siteoper.get(siteid) + siteinfo = self.site_oper.get(siteid) if siteinfo: site_infos.append(siteinfo) @@ -1943,13 +1941,13 @@ class BrushFlow(_PluginBase): """ 针对站点进行刷流 """ - siteinfo = self.siteoper.get(siteid) + siteinfo = self.site_oper.get(siteid) if not siteinfo: logger.warn(f"站点不存在:{siteid}") return True logger.info(f"开始获取站点 {siteinfo.name} 的新种子 ...") - torrents = self.torrentschain.browse(domain=siteinfo.domain) + torrents = self.torrents_chain.browse(domain=siteinfo.domain) if not torrents: logger.info(f"站点 {siteinfo.name} 没有获取到种子") return True @@ -2314,7 +2312,7 @@ class BrushFlow(_PluginBase): if need_delete_hashes: # 如果是QB,则重新汇报Tracker - if self.downloaderhelper.is_qbittorrent(service=self.service_info): + if self.downloader_helper.is_qbittorrent(service=self.service_info): self.__qb_torrents_reannounce(torrent_hashes=need_delete_hashes) # 删除种子 if downloader.delete_torrents(ids=need_delete_hashes, delete_file=True): @@ -2356,7 +2354,7 @@ class BrushFlow(_PluginBase): seeding_torrents_dict: Dict[str, Any]): brush_config = self.__get_brush_config() - if not self.downloaderhelper.is_qbittorrent(service=self.service_info): + if not self.downloader_helper.is_qbittorrent(service=self.service_info): logger.info("同步种子刷流标签记录目前仅支持qbittorrent") return @@ -3045,7 +3043,7 @@ class BrushFlow(_PluginBase): if not downloader: return None - if self.downloaderhelper.is_qbittorrent(service=self.service_info): + if self.downloader_helper.is_qbittorrent(service=self.service_info): # 限速值转为bytes up_speed = up_speed * 1024 if up_speed else None down_speed = down_speed * 1024 if down_speed else None @@ -3079,7 +3077,7 @@ class BrushFlow(_PluginBase): return torrent_hash return None - elif self.downloaderhelper.is_transmission(service=self.service_info): + elif self.downloader_helper.is_transmission(service=self.service_info): # 如果开启代理下载以及种子地址不是磁力地址,则请求种子到内存再传入下载器 if not torrent_content.startswith("magnet"): response = RequestUtils(cookies=cookies, @@ -3127,7 +3125,7 @@ class BrushFlow(_PluginBase): 获取种子hash """ try: - return torrent.get("hash") if self.downloaderhelper.is_qbittorrent(service=self.service_info) \ + return torrent.get("hash") if self.downloader_helper.is_qbittorrent(service=self.service_info) \ else torrent.hashString except Exception as e: print(str(e)) @@ -3144,7 +3142,7 @@ class BrushFlow(_PluginBase): all_hashes = [] for torrent in torrents: # 根据下载器类型获取Hash值 - hash_value = torrent.get("hash") if self.downloaderhelper.is_qbittorrent(service=self.service_info) \ + hash_value = torrent.get("hash") if self.downloader_helper.is_qbittorrent(service=self.service_info) \ else torrent.hashString if hash_value: all_hashes.append(hash_value) @@ -3159,7 +3157,7 @@ class BrushFlow(_PluginBase): """ try: return [str(tag).strip() for tag in torrent.get("tags").split(',')] \ - if self.downloaderhelper.is_qbittorrent(service=self.service_info) else torrent.labels or [] + if self.downloader_helper.is_qbittorrent(service=self.service_info) else torrent.labels or [] except Exception as e: print(str(e)) return [] @@ -3170,7 +3168,7 @@ class BrushFlow(_PluginBase): """ date_now = int(time.time()) # QB - if self.downloaderhelper.is_qbittorrent(service=self.service_info): + if self.downloader_helper.is_qbittorrent(service=self.service_info): """ { "added_on": 1693359031, @@ -3551,7 +3549,7 @@ class BrushFlow(_PluginBase): if not self._subscribe_infos: self._subscribe_infos = {} - subscribes = self.subscribeoper.list() + subscribes = self.subscribe_oper.list() if subscribes: # 遍历订阅 for subscribe in subscribes: @@ -3807,7 +3805,7 @@ class BrushFlow(_PluginBase): # 使用StringUtils工具类获取tracker的域名 domain = StringUtils.get_url_domain(tracker) - site_info = self.siteshelper.get_indexer(domain) + site_info = self.sites_helper.get_indexer(domain) if site_info: return site_info.get("id"), site_info.get("name") diff --git a/plugins.v2/downloadsitetag/__init__.py b/plugins.v2/downloadsitetag/__init__.py index 4a93b21..4c18550 100644 --- a/plugins.v2/downloadsitetag/__init__.py +++ b/plugins.v2/downloadsitetag/__init__.py @@ -21,8 +21,6 @@ from app.utils.string import StringUtils class DownloadSiteTag(_PluginBase): - # region 全局定义 - # 插件名称 plugin_name = "下载任务分类与标签" # 插件描述 @@ -49,7 +47,7 @@ class DownloadSiteTag(_PluginBase): # 私有属性 downloadhistory_oper = None sites_helper = None - downloaderhelper = None + downloader_helper = None _scheduler = None _enabled = False _onlyonce = False @@ -65,40 +63,9 @@ class DownloadSiteTag(_PluginBase): _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.downloadhistory_oper = DownloadHistoryOper() - self.downloaderhelper = DownloaderHelper() + self.downloader_helper = DownloaderHelper() self.sites_helper = SitesHelper() # 读取配置 if config: @@ -137,6 +104,33 @@ class DownloadSiteTag(_PluginBase): self._scheduler.print_jobs() self._scheduler.start() + @property + def service_infos(self) -> Optional[Dict[str, ServiceInfo]]: + """ + 服务信息 + """ + if not self._downloaders: + logger.warning("尚未配置下载器,请检查配置") + return None + + services = self.downloader_helper.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 + def get_state(self) -> bool: return self._enabled @@ -668,7 +662,7 @@ class DownloadSiteTag(_PluginBase): 'model': 'downloaders', 'label': '下载器', 'items': [{"title": config.name, "value": config.name} - for config in self.downloaderhelper.get_configs().values()] + for config in self.downloader_helper.get_configs().values()] } } ] diff --git a/plugins.v2/mediaserverrefresh/__init__.py b/plugins.v2/mediaserverrefresh/__init__.py index 75b1b53..edd6cab 100644 --- a/plugins.v2/mediaserverrefresh/__init__.py +++ b/plugins.v2/mediaserverrefresh/__init__.py @@ -31,13 +31,18 @@ class MediaServerRefresh(_PluginBase): # 可使用的用户级别 auth_level = 1 - mediaserver_helper = None # 私有属性 + mediaserver_helper = None _enabled = False _delay = 0 _mediaservers = None - # Property + def init_plugin(self, config: dict = None): + self.mediaserver_helper = MediaServerHelper() + if config: + self._enabled = config.get("enabled") + self._delay = config.get("delay") or 0 + self._mediaservers = config.get("mediaservers") or [] @property def service_infos(self) -> Optional[Dict[str, ServiceInfo]]: @@ -66,13 +71,6 @@ class MediaServerRefresh(_PluginBase): return active_services - def init_plugin(self, config: dict = None): - self.mediaserver_helper = MediaServerHelper() - if config: - self._enabled = config.get("enabled") - self._delay = config.get("delay") or 0 - self._mediaservers = config.get("mediaservers") or [] - def get_state(self) -> bool: return self._enabled From 96e0a8e9fd9edaf9fc64b1df9f66c12ca613859d Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:08:27 +0800 Subject: [PATCH 2/3] feat(MediaServerMsg): add support for v2 plugin --- plugins.v2/mediaservermsg/__init__.py | 113 ++++++++++++++++++++------ 1 file changed, 89 insertions(+), 24 deletions(-) diff --git a/plugins.v2/mediaservermsg/__init__.py b/plugins.v2/mediaservermsg/__init__.py index 315f1d1..2449962 100644 --- a/plugins.v2/mediaservermsg/__init__.py +++ b/plugins.v2/mediaservermsg/__init__.py @@ -1,13 +1,11 @@ import time -from typing import Any, List, Dict, Tuple +from typing import Any, List, Dict, Tuple, Optional from app.core.event import eventmanager, Event +from app.helper.mediaserver import MediaServerHelper from app.log import logger -from app.modules.emby import Emby -from app.modules.jellyfin import Jellyfin -from app.modules.plex import Plex from app.plugins import _PluginBase -from app.schemas import WebhookEventInfo +from app.schemas import WebhookEventInfo, ServiceInfo from app.schemas.types import EventType, MediaType, MediaImageType, NotificationType from app.utils.web import WebUtils @@ -32,13 +30,11 @@ class MediaServerMsg(_PluginBase): # 可使用的用户级别 auth_level = 1 - # 对像 - plex = None - emby = None - jellyfin = None - # 私有属性 + mediaserver_helper = None _enabled = False + _add_play_link = False + _mediaservers = None _types = [] _webhook_msg_keys = {} @@ -63,13 +59,38 @@ class MediaServerMsg(_PluginBase): } def init_plugin(self, config: dict = None): + self.mediaserver_helper = MediaServerHelper() if config: self._enabled = config.get("enabled") self._types = config.get("types") or [] - if self._enabled: - self.emby = Emby() - self.plex = Plex() - self.jellyfin = Jellyfin() + self._mediaservers = config.get("mediaservers") or [] + self._add_play_link = config.get("add_play_link", False) + + def service_infos(self, type_filter: Optional[str] = None) -> Optional[Dict[str, ServiceInfo]]: + """ + 服务信息 + """ + if not self._mediaservers: + logger.warning("尚未配置媒体服务器,请检查配置") + return None + + services = self.mediaserver_helper.get_services(type_filter=type_filter, name_filters=self._mediaservers) + 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 def get_state(self) -> bool: return self._enabled @@ -116,6 +137,47 @@ class MediaServerMsg(_PluginBase): } } ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'add_play_link', + 'label': '添加播放链接', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'multiple': True, + 'chips': True, + 'clearable': True, + 'model': 'mediaservers', + 'label': '媒体服务器', + 'items': [{"title": config.name, "value": config.name} + for config in self.mediaserver_helper.get_configs().values()] + } + } + ] } ] }, @@ -156,7 +218,7 @@ class MediaServerMsg(_PluginBase): 'props': { 'type': 'info', 'variant': 'tonal', - 'text': '需要设置媒体服务器Webhook,回调相对路径为 /api/v1/webhook?token=moviepilot(3001端口),其中 moviepilot 为设置的 API_TOKEN。' + 'text': '需要设置媒体服务器Webhook,回调相对路径为 /api/v1/webhook?token=API_TOKEN&source=媒体服务器名(3001端口),其中 API_TOKEN 为设置的 API_TOKEN。' } } ] @@ -253,15 +315,18 @@ class MediaServerMsg(_PluginBase): if not image_url: image_url = self._webhook_images.get(event_info.channel) - # 获取链接地址 - if event_info.channel == "emby": - play_link = self.emby.get_play_url(event_info.item_id) - elif event_info.channel == "plex": - play_link = self.plex.get_play_url(event_info.item_id) - elif event_info.channel == "jellyfin": - play_link = self.jellyfin.get_play_url(event_info.item_id) - else: - play_link = None + play_link = None + if self._add_play_link: + if event_info.server_name: + service = self.service_infos().get(event_info.server_name) + if service: + play_link = service.instance.get_play_url(event_info.item_id) + elif event_info.channel: + services = self.mediaserver_helper.get_services(type_filter=event_info.channel) + for service in services.values(): + play_link = service.instance.get_play_url(event_info.item_id) + if play_link: + break if str(event_info.event) == "playback.stop": # 停止播放消息,添加到过期字典 From c53d1e666276a6f8fc2b6455335aaf807662ac42 Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Thu, 10 Oct 2024 22:18:08 +0800 Subject: [PATCH 3/3] feat(MediaServerMsg): v1.4 --- package.v2.json | 12 ++++++++++++ plugins.v2/mediaservermsg/__init__.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/package.v2.json b/package.v2.json index 1dd5632..9d33f37 100644 --- a/package.v2.json +++ b/package.v2.json @@ -59,6 +59,18 @@ "v1.3": "MoviePilot V2 版本媒体库服务器刷新插件" } }, + "MediaServerMsg": { + "name": "媒体库服务器通知", + "description": "发送Emby/Jellyfin/Plex服务器的播放、入库等通知消息。", + "labels": "消息通知,媒体库", + "version": "1.4", + "icon": "mediaplay.png", + "author": "jxxghp", + "level": 1, + "history": { + "v1.4": "MoviePilot V2 版本媒体库服务器通知插件" + } + }, "ChatGPT": { "name": "ChatGPT", "description": "消息交互支持与ChatGPT对话。", diff --git a/plugins.v2/mediaservermsg/__init__.py b/plugins.v2/mediaservermsg/__init__.py index 2449962..f927b6f 100644 --- a/plugins.v2/mediaservermsg/__init__.py +++ b/plugins.v2/mediaservermsg/__init__.py @@ -18,7 +18,7 @@ class MediaServerMsg(_PluginBase): # 插件图标 plugin_icon = "mediaplay.png" # 插件版本 - plugin_version = "1.3" + plugin_version = "1.4" # 插件作者 plugin_author = "jxxghp" # 作者主页