mirror of
https://github.com/d0zingcat/MoviePilot-Plugins.git
synced 2026-05-13 15:09:12 +00:00
add dingdingmsg
This commit is contained in:
BIN
icons/Dingding_A.png
Normal file
BIN
icons/Dingding_A.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
10
package.json
10
package.json
@@ -840,5 +840,15 @@
|
||||
"v1.1": "支持将极影视评分修改为豆瓣评分",
|
||||
"v1.0": "同步极影视在看/已看状态到豆瓣"
|
||||
}
|
||||
},
|
||||
"DingdingMsg": {
|
||||
"name": "钉钉机器人",
|
||||
"description": "支持使用钉钉机器人发送消息通知。",
|
||||
"labels": "消息通知,钉钉机器人",
|
||||
"version": "1.12",
|
||||
"icon": "Dingding_A.png",
|
||||
"author": "nnlegenda",
|
||||
"level": 1,
|
||||
"v2": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 版本下载任务分类与标签插件"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = "下载任务分类与标签"
|
||||
# 插件描述
|
||||
@@ -27,7 +30,7 @@ class DownloadSiteTag(_PluginBase):
|
||||
# 插件图标
|
||||
plugin_icon = "Youtube-dl_B.png"
|
||||
# 插件版本
|
||||
plugin_version = "2.1"
|
||||
plugin_version = "2.2"
|
||||
# 插件作者
|
||||
plugin_author = "叮叮当"
|
||||
# 作者主页
|
||||
@@ -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)
|
||||
# 分类, 如果勾选开关的话 <tr暂不支持> 因允许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': [
|
||||
|
||||
269
plugins/dingdingmsg/__init__.py
Normal file
269
plugins/dingdingmsg/__init__.py
Normal file
@@ -0,0 +1,269 @@
|
||||
import re
|
||||
import time
|
||||
import hmac
|
||||
import hashlib
|
||||
import base64
|
||||
import urllib.parse
|
||||
|
||||
from app.plugins import _PluginBase
|
||||
from app.core.event import eventmanager, Event
|
||||
from app.schemas.types import EventType, NotificationType
|
||||
from app.utils.http import RequestUtils
|
||||
from typing import Any, List, Dict, Tuple
|
||||
from app.log import logger
|
||||
|
||||
|
||||
class DingdingMsg(_PluginBase):
|
||||
# 插件名称
|
||||
plugin_name = "钉钉机器人"
|
||||
# 插件描述
|
||||
plugin_desc = "支持使用钉钉机器人发送消息通知。"
|
||||
# 插件图标
|
||||
plugin_icon = "Dingding_A.png"
|
||||
# 插件版本
|
||||
plugin_version = "1.12"
|
||||
# 插件作者
|
||||
plugin_author = "nnlegenda"
|
||||
# 作者主页
|
||||
author_url = "https://github.com/nnlegenda"
|
||||
# 插件配置项ID前缀
|
||||
plugin_config_prefix = "dingdingmsg_"
|
||||
# 加载顺序
|
||||
plugin_order = 25
|
||||
# 可使用的用户级别
|
||||
auth_level = 1
|
||||
|
||||
# 私有属性
|
||||
_enabled = False
|
||||
_token = None
|
||||
_secret = None
|
||||
_msgtypes = []
|
||||
|
||||
def init_plugin(self, config: dict = None):
|
||||
if config:
|
||||
self._enabled = config.get("enabled")
|
||||
self._token = config.get("token")
|
||||
self._secret = config.get("secret")
|
||||
self._msgtypes = config.get("msgtypes") or []
|
||||
|
||||
def get_state(self) -> bool:
|
||||
return self._enabled and (True if self._token else False) and (True if self._secret else False)
|
||||
|
||||
@staticmethod
|
||||
def get_command() -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_api(self) -> List[Dict[str, Any]]:
|
||||
pass
|
||||
|
||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||
"""
|
||||
拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构
|
||||
"""
|
||||
# 编历 NotificationType 枚举,生成消息类型选项
|
||||
MsgTypeOptions = []
|
||||
for item in NotificationType:
|
||||
MsgTypeOptions.append({
|
||||
"title": item.value,
|
||||
"value": item.name
|
||||
})
|
||||
return [
|
||||
{
|
||||
'component': 'VForm',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12,
|
||||
'md': 6
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSwitch',
|
||||
'props': {
|
||||
'model': 'enabled',
|
||||
'label': '启用插件',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'token',
|
||||
'label': '钉钉机器人token',
|
||||
'placeholder': 'xxxxxx',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VTextField',
|
||||
'props': {
|
||||
'model': 'secret',
|
||||
'label': '加签',
|
||||
'placeholder': 'SECxxx',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'component': 'VRow',
|
||||
'content': [
|
||||
{
|
||||
'component': 'VCol',
|
||||
'props': {
|
||||
'cols': 12
|
||||
},
|
||||
'content': [
|
||||
{
|
||||
'component': 'VSelect',
|
||||
'props': {
|
||||
'multiple': True,
|
||||
'chips': True,
|
||||
'model': 'msgtypes',
|
||||
'label': '消息类型',
|
||||
'items': MsgTypeOptions
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
], {
|
||||
"enabled": False,
|
||||
'token': '',
|
||||
'msgtypes': []
|
||||
}
|
||||
|
||||
def get_page(self) -> List[dict]:
|
||||
pass
|
||||
|
||||
@eventmanager.register(EventType.NoticeMessage)
|
||||
def send(self, event: Event):
|
||||
"""
|
||||
消息发送事件
|
||||
"""
|
||||
if not self.get_state():
|
||||
return
|
||||
|
||||
if not event.event_data:
|
||||
return
|
||||
|
||||
msg_body = event.event_data
|
||||
# 渠道
|
||||
channel = msg_body.get("channel")
|
||||
if channel:
|
||||
return
|
||||
# 类型
|
||||
msg_type: NotificationType = msg_body.get("type")
|
||||
# 标题
|
||||
title = msg_body.get("title")
|
||||
# 文本
|
||||
text = msg_body.get("text")
|
||||
# 封面
|
||||
cover = msg_body.get("image")
|
||||
|
||||
if not title and not text:
|
||||
logger.warn("标题和内容不能同时为空")
|
||||
return
|
||||
|
||||
if (msg_type and self._msgtypes
|
||||
and msg_type.name not in self._msgtypes):
|
||||
logger.info(f"消息类型 {msg_type.value} 未开启消息发送")
|
||||
return
|
||||
|
||||
sc_url = self.url_sign(self._token, self._secret)
|
||||
|
||||
try:
|
||||
|
||||
if text:
|
||||
# 对text进行Markdown特殊字符转义
|
||||
text = re.sub(r"([_`])", r"\\\1", text)
|
||||
else:
|
||||
text = ""
|
||||
|
||||
if cover:
|
||||
data = {
|
||||
"msgtype": "markdown",
|
||||
"markdown": {
|
||||
"title": title,
|
||||
"text": "### %s\n\n"
|
||||
"\n\n"
|
||||
"> %s\n\n > MoviePilot %s\n" % (title, cover, text, msg_type.value)
|
||||
}
|
||||
}
|
||||
else:
|
||||
data = {
|
||||
"msgtype": "markdown",
|
||||
"markdown": {
|
||||
"title": title,
|
||||
"text": "### %s\n\n"
|
||||
"> %s\n\n > MoviePilot %s\n" % (title, text, msg_type.value)
|
||||
}
|
||||
}
|
||||
res = RequestUtils(content_type="application/json").post_res(sc_url, json=data)
|
||||
if res and res.status_code == 200:
|
||||
ret_json = res.json()
|
||||
errno = ret_json.get('errcode')
|
||||
error = ret_json.get('errmsg')
|
||||
if errno == 0:
|
||||
logger.info("钉钉机器人消息发送成功")
|
||||
else:
|
||||
logger.warn(f"钉钉机器人消息发送失败,错误码:{errno},错误原因:{error}")
|
||||
elif res is not None:
|
||||
logger.warn(f"钉钉机器人消息发送失败,错误码:{res.status_code},错误原因:{res.reason}")
|
||||
else:
|
||||
logger.warn("钉钉机器人消息发送失败,未获取到返回信息")
|
||||
except Exception as msg_e:
|
||||
logger.error(f"钉钉机器人消息发送失败,{str(msg_e)}")
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
退出插件
|
||||
"""
|
||||
pass
|
||||
|
||||
def url_sign(self, access_token: str, secret: str) -> str:
|
||||
"""
|
||||
加签
|
||||
"""
|
||||
# 生成时间戳和签名
|
||||
timestamp = str(round(time.time() * 1000))
|
||||
secret_enc = secret.encode('utf-8')
|
||||
string_to_sign = '{}\n{}'.format(timestamp, secret)
|
||||
string_to_sign_enc = string_to_sign.encode('utf-8')
|
||||
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
|
||||
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
|
||||
# 组合请求的完整 URL
|
||||
full_url = f'https://oapi.dingtalk.com/robot/send?access_token={access_token}×tamp={timestamp}&sign={sign}'
|
||||
return full_url
|
||||
Reference in New Issue
Block a user