mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36:06 +08:00
脚本推送增加自定义 webhook 方式
This commit is contained in:
parent
bd004a0489
commit
533e12a796
165
sample/notify.js
165
sample/notify.js
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
const querystring = require('querystring');
|
||||
const got = require('got');
|
||||
const $ = new Env();
|
||||
const timeout = 15000; //超时时间(单位毫秒)
|
||||
// =======================================gotify通知设置区域==============================================
|
||||
|
@ -159,6 +160,14 @@ let CHRONOCAT_URL = ''; // CHRONOCAT Red协议连接地址
|
|||
let CHRONOCAT_TOKEN = ''; //CHRONOCAT 生成的访问密钥
|
||||
let CHRONOCAT_QQ = ''; // 个人:user_id=个人QQ 群则填入group_id=QQ群 多个用英文;隔开同时支持个人和群 如:user_id=xxx;group_id=xxxx;group_id=xxxxx
|
||||
|
||||
// =======================================自定义通知设置区域=======================================
|
||||
// 自定义通知 接收回调的URL
|
||||
let WEBHOOK_URL = '';
|
||||
let WEBHOOK_BODY = '';
|
||||
let WEBHOOK_HEADERS = '';
|
||||
let WEBHOOK_METHOD = '';
|
||||
let WEBHOOK_CONTENT_TYPE = '';
|
||||
|
||||
//==========================云端环境变量的判断与接收=========================
|
||||
if (process.env.GOTIFY_URL) {
|
||||
GOTIFY_URL = process.env.GOTIFY_URL;
|
||||
|
@ -325,6 +334,22 @@ if (process.env.CHRONOCAT_QQ) {
|
|||
if (process.env.CHRONOCAT_TOKEN) {
|
||||
CHRONOCAT_TOKEN = process.env.CHRONOCAT_TOKEN;
|
||||
}
|
||||
|
||||
if (process.env.WEBHOOK_URL) {
|
||||
WEBHOOK_URL = process.env.WEBHOOK_URL;
|
||||
}
|
||||
if (process.env.WEBHOOK_BODY) {
|
||||
WEBHOOK_BODY = process.env.WEBHOOK_BODY;
|
||||
}
|
||||
if (process.env.WEBHOOK_HEADERS) {
|
||||
WEBHOOK_HEADERS = process.env.WEBHOOK_HEADERS;
|
||||
}
|
||||
if (process.env.WEBHOOK_METHOD) {
|
||||
WEBHOOK_METHOD = process.env.WEBHOOK_METHOD;
|
||||
}
|
||||
if (process.env.WEBHOOK_CONTENT_TYPE) {
|
||||
WEBHOOK_CONTENT_TYPE = process.env.WEBHOOK_CONTENT_TYPE;
|
||||
}
|
||||
//==========================云端环境变量的判断与接收=========================
|
||||
|
||||
/**
|
||||
|
@ -375,6 +400,7 @@ async function sendNotify(
|
|||
smtpNotify(text, desp), //SMTP 邮件
|
||||
PushMeNotify(text, desp, params), //PushMe
|
||||
ChronocatNotify(text, desp), // Chronocat
|
||||
webhookNotify(text, desp), //自定义通知
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1266,6 +1292,145 @@ function ChronocatNotify(title, desp) {
|
|||
});
|
||||
}
|
||||
|
||||
function webhookNotify(text, desp) {
|
||||
return new Promise((resolve) => {
|
||||
const { formatBody, formatUrl } = formatNotifyContentFun(
|
||||
WEBHOOK_URL,
|
||||
WEBHOOK_BODY,
|
||||
text,
|
||||
desp,
|
||||
);
|
||||
if (!formatUrl && !formatBody) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const headers = parseHeaders(WEBHOOK_HEADERS);
|
||||
const body = parseBody(formatBody, WEBHOOK_CONTENT_TYPE);
|
||||
const bodyParam = formatBodyFun(WEBHOOK_CONTENT_TYPE, body);
|
||||
const options = {
|
||||
method: WEBHOOK_METHOD,
|
||||
headers,
|
||||
allowGetBody: true,
|
||||
...bodyParam,
|
||||
timeout,
|
||||
retry: 1,
|
||||
};
|
||||
|
||||
if (WEBHOOK_METHOD) {
|
||||
got(formatUrl, options).then((resp) => {
|
||||
try {
|
||||
if (resp.statusCode !== 200) {
|
||||
console.log('自定义发送通知消息失败!!\n');
|
||||
console.log(resp.body);
|
||||
} else {
|
||||
console.log('自定义发送通知消息成功🎉。\n');
|
||||
console.log(resp.body);
|
||||
}
|
||||
} catch (e) {
|
||||
$.logErr(e, resp);
|
||||
} finally {
|
||||
resolve(resp.body);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseHeaders(headers) {
|
||||
if (!headers) return {};
|
||||
|
||||
const parsed = {};
|
||||
let key;
|
||||
let val;
|
||||
let i;
|
||||
|
||||
headers &&
|
||||
headers.split('\n').forEach(function parser(line) {
|
||||
i = line.indexOf(':');
|
||||
key = line.substring(0, i).trim().toLowerCase();
|
||||
val = line.substring(i + 1).trim();
|
||||
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
|
||||
});
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parseBody(body, contentType) {
|
||||
if (!body) return '';
|
||||
|
||||
const parsed = {};
|
||||
let key;
|
||||
let val;
|
||||
let i;
|
||||
|
||||
body &&
|
||||
body.split('\n').forEach(function parser(line) {
|
||||
i = line.indexOf(':');
|
||||
key = line.substring(0, i).trim().toLowerCase();
|
||||
val = line.substring(i + 1).trim();
|
||||
|
||||
if (!key || parsed[key]) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const jsonValue = JSON.parse(val);
|
||||
parsed[key] = jsonValue;
|
||||
} catch (error) {
|
||||
parsed[key] = val;
|
||||
}
|
||||
});
|
||||
|
||||
switch (contentType) {
|
||||
case 'multipart/form-data':
|
||||
return Object.keys(parsed).reduce((p, c) => {
|
||||
p.append(c, parsed[c]);
|
||||
return p;
|
||||
}, new FormData());
|
||||
case 'application/x-www-form-urlencoded':
|
||||
return Object.keys(parsed).reduce((p, c) => {
|
||||
return p ? `${p}&${c}=${parsed[c]}` : `${c}=${parsed[c]}`;
|
||||
});
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function formatBodyFun(contentType, body) {
|
||||
if (!body) return {};
|
||||
switch (contentType) {
|
||||
case 'application/json':
|
||||
return { json: body };
|
||||
case 'multipart/form-data':
|
||||
return { form: body };
|
||||
case 'application/x-www-form-urlencoded':
|
||||
return { body };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
function formatNotifyContentFun(url, body, title, content) {
|
||||
if (!url.includes('$title') && !body.includes('$title')) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
formatUrl: url
|
||||
.replaceAll('$title', encodeURIComponent(title))
|
||||
.replaceAll('$content', encodeURIComponent(content)),
|
||||
formatBody: body
|
||||
.replaceAll('$title', title)
|
||||
.replaceAll('$content', content),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sendNotify,
|
||||
BARK_PUSH,
|
||||
|
|
164
sample/notify.py
164
sample/notify.py
|
@ -101,10 +101,17 @@ push_config = {
|
|||
'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
|
||||
'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写
|
||||
|
||||
'PUSHME_KEY': '', # PushMe 酱的 PUSHME_KEY
|
||||
'CHRONOCAT_QQ': '', # qq号
|
||||
'CHRONOCAT_TOKEN': '', # CHRONOCAT 的token
|
||||
'CHRONOCAT_URL': '' # CHRONOCAT的url地址
|
||||
'PUSHME_KEY': '', # PushMe 酱的 PUSHME_KEY
|
||||
|
||||
'CHRONOCAT_QQ': '', # qq号
|
||||
'CHRONOCAT_TOKEN': '', # CHRONOCAT 的token
|
||||
'CHRONOCAT_URL': '', # CHRONOCAT的url地址
|
||||
|
||||
'WEBHOOK_URL': '', # 自定义通知 请求地址
|
||||
'WEBHOOK_BODY': '', # 自定义通知 请求体
|
||||
'WEBHOOK_HEADERS': '', # 自定义通知 请求头
|
||||
'WEBHOOK_METHOD': '', # 自定义通知 请求方法
|
||||
'WEBHOOK_CONTENT_TYPE': '' # 自定义通知 content-type
|
||||
}
|
||||
notify_function = []
|
||||
# fmt: on
|
||||
|
@ -449,7 +456,9 @@ class WeCom:
|
|||
return data["access_token"]
|
||||
|
||||
def send_text(self, message, touser="@all"):
|
||||
send_url = f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
|
||||
send_url = (
|
||||
f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
|
||||
)
|
||||
send_values = {
|
||||
"touser": touser,
|
||||
"msgtype": "text",
|
||||
|
@ -463,7 +472,9 @@ class WeCom:
|
|||
return respone["errmsg"]
|
||||
|
||||
def send_mpnews(self, title, message, media_id, touser="@all"):
|
||||
send_url = f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
|
||||
send_url = (
|
||||
f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
|
||||
)
|
||||
send_values = {
|
||||
"touser": touser,
|
||||
"msgtype": "mpnews",
|
||||
|
@ -646,6 +657,7 @@ def smtp(title: str, content: str) -> None:
|
|||
except Exception as e:
|
||||
print(f"SMTP 邮件 推送失败!{e}")
|
||||
|
||||
|
||||
def pushme(title: str, content: str) -> None:
|
||||
"""
|
||||
使用 PushMe 推送消息。
|
||||
|
@ -667,12 +679,16 @@ def pushme(title: str, content: str) -> None:
|
|||
else:
|
||||
print(f"PushMe 推送失败!{response.status_code} {response.text}")
|
||||
|
||||
|
||||
def chronocat(title: str, content: str) -> None:
|
||||
"""
|
||||
使用 CHRONOCAT 推送消息。
|
||||
"""
|
||||
if not push_config.get("CHRONOCAT_URL") or not push_config.get("CHRONOCAT_QQ") or not push_config.get(
|
||||
"CHRONOCAT_TOKEN"):
|
||||
if (
|
||||
not push_config.get("CHRONOCAT_URL")
|
||||
or not push_config.get("CHRONOCAT_QQ")
|
||||
or not push_config.get("CHRONOCAT_TOKEN")
|
||||
):
|
||||
print("CHRONOCAT 服务的 CHRONOCAT_URL 或 CHRONOCAT_QQ 未设置!!\n取消推送")
|
||||
return
|
||||
|
||||
|
@ -683,8 +699,8 @@ def chronocat(title: str, content: str) -> None:
|
|||
|
||||
url = f'{push_config.get("CHRONOCAT_URL")}/api/message/send'
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f'Bearer {push_config.get("CHRONOCAT_TOKEN")}'
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f'Bearer {push_config.get("CHRONOCAT_TOKEN")}',
|
||||
}
|
||||
|
||||
for chat_type, ids in [(1, user_ids), (2, group_ids)]:
|
||||
|
@ -692,32 +708,128 @@ def chronocat(title: str, content: str) -> None:
|
|||
continue
|
||||
for chat_id in ids:
|
||||
data = {
|
||||
"peer": {
|
||||
"chatType": chat_type,
|
||||
"peerUin": chat_id
|
||||
},
|
||||
"peer": {"chatType": chat_type, "peerUin": chat_id},
|
||||
"elements": [
|
||||
{
|
||||
"elementType": 1,
|
||||
"textElement": {
|
||||
"content": f'{title}\n\n{content}'
|
||||
}
|
||||
"textElement": {"content": f"{title}\n\n{content}"},
|
||||
}
|
||||
]
|
||||
],
|
||||
}
|
||||
response = requests.post(url, headers=headers, data=json.dumps(data))
|
||||
if response.status_code == 200:
|
||||
if chat_type == 1:
|
||||
print(f'QQ个人消息:{ids}推送成功!')
|
||||
print(f"QQ个人消息:{ids}推送成功!")
|
||||
else:
|
||||
print(f'QQ群消息:{ids}推送成功!')
|
||||
print(f"QQ群消息:{ids}推送成功!")
|
||||
else:
|
||||
if chat_type == 1:
|
||||
print(f'QQ个人消息:{ids}推送失败!')
|
||||
print(f"QQ个人消息:{ids}推送失败!")
|
||||
else:
|
||||
print(f'QQ群消息:{ids}推送失败!')
|
||||
print(f"QQ群消息:{ids}推送失败!")
|
||||
|
||||
|
||||
def parse_headers(headers):
|
||||
if not headers:
|
||||
return {}
|
||||
|
||||
parsed = {}
|
||||
lines = headers.split("\n")
|
||||
|
||||
for line in lines:
|
||||
i = line.find(":")
|
||||
if i == -1:
|
||||
continue
|
||||
|
||||
key = line[:i].strip().lower()
|
||||
val = line[i + 1 :].strip()
|
||||
parsed[key] = parsed.get(key, "") + ", " + val if key in parsed else val
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_body(body, content_type):
|
||||
if not body:
|
||||
return ""
|
||||
|
||||
parsed = {}
|
||||
lines = body.split("\n")
|
||||
|
||||
for line in lines:
|
||||
i = line.find(":")
|
||||
if i == -1:
|
||||
continue
|
||||
|
||||
key = line[:i].strip().lower()
|
||||
val = line[i + 1 :].strip()
|
||||
|
||||
if not key or key in parsed:
|
||||
continue
|
||||
|
||||
try:
|
||||
json_value = json.loads(val)
|
||||
parsed[key] = json_value
|
||||
except:
|
||||
parsed[key] = val
|
||||
|
||||
if content_type == "application/x-www-form-urlencoded":
|
||||
data = urlencode(parsed, doseq=True)
|
||||
return data
|
||||
|
||||
if content_type == "application/json":
|
||||
data = json.dumps(parsed)
|
||||
return data
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def format_notify_content(url, body, title, content):
|
||||
if "$title" not in url and "$title" not in body:
|
||||
return {}
|
||||
|
||||
formatted_url = url.replace("$title", urllib.parse.quote_plus(title)).replace(
|
||||
"$content", urllib.parse.quote_plus(content)
|
||||
)
|
||||
formatted_body = body.replace("$title", title).replace("$content", content)
|
||||
|
||||
return formatted_url, formatted_body
|
||||
|
||||
|
||||
def custom_notify(title: str, content: str) -> None:
|
||||
"""
|
||||
通过 自定义通知 推送消息。
|
||||
"""
|
||||
if not push_config.get("WEBHOOK_URL") or not push_config.get("WEBHOOK_METHOD"):
|
||||
print("自定义通知的 WEBHOOK_URL 或 WEBHOOK_METHOD 未设置!!\n取消推送")
|
||||
return
|
||||
|
||||
print("自定义通知服务启动")
|
||||
|
||||
WEBHOOK_URL = push_config.get("WEBHOOK_URL")
|
||||
WEBHOOK_METHOD = push_config.get("WEBHOOK_METHOD")
|
||||
WEBHOOK_CONTENT_TYPE = push_config.get("WEBHOOK_CONTENT_TYPE")
|
||||
WEBHOOK_BODY = push_config.get("WEBHOOK_BODY")
|
||||
WEBHOOK_HEADERS = push_config.get("WEBHOOK_HEADERS")
|
||||
|
||||
formatUrl, formatBody = format_notify_content(
|
||||
WEBHOOK_URL, WEBHOOK_BODY, title, content
|
||||
)
|
||||
|
||||
if not formatUrl and not formatBody:
|
||||
print("请求头或者请求体中必须包含 $title 和 $content")
|
||||
return
|
||||
|
||||
headers = parse_headers(WEBHOOK_HEADERS)
|
||||
body = parse_body(formatBody, WEBHOOK_CONTENT_TYPE)
|
||||
response = requests.request(
|
||||
method=WEBHOOK_METHOD, url=formatUrl, headers=headers, timeout=15, data=body
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("自定义通知推送成功!")
|
||||
else:
|
||||
print(f"自定义通知推送失败!{response.status_code} {response.text}")
|
||||
|
||||
|
||||
def one() -> str:
|
||||
"""
|
||||
|
@ -775,6 +887,14 @@ if (
|
|||
notify_function.append(smtp)
|
||||
if push_config.get("PUSHME_KEY"):
|
||||
notify_function.append(pushme)
|
||||
if (
|
||||
push_config.get("CHRONOCAT_URL")
|
||||
and push_config.get("CHRONOCAT_QQ")
|
||||
and push_config.get("CHRONOCAT_TOKEN")
|
||||
):
|
||||
notify_function.append(chronocat)
|
||||
if push_config.get("WEBHOOK_URL") and push_config.get("WEBHOOK_METHOD"):
|
||||
notify_function.append(custom_notify)
|
||||
|
||||
|
||||
def send(title: str, content: str) -> None:
|
||||
|
|
Loading…
Reference in New Issue
Block a user