Merge pull request #486 from InfinityPacer/main

This commit is contained in:
jxxghp
2024-10-10 22:48:37 +08:00
committed by GitHub
5 changed files with 189 additions and 122 deletions

View File

@@ -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对话。",

View File

@@ -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")

View File

@@ -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()]
}
}
]

View File

@@ -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
@@ -20,7 +18,7 @@ class MediaServerMsg(_PluginBase):
# 插件图标
plugin_icon = "mediaplay.png"
# 插件版本
plugin_version = "1.3"
plugin_version = "1.4"
# 插件作者
plugin_author = "jxxghp"
# 作者主页
@@ -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=moviepilot3001端口其中 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":
# 停止播放消息,添加到过期字典

View File

@@ -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