diff --git a/sendNotify.js b/sendNotify.js index 437f13a..fbc450d 100644 --- a/sendNotify.js +++ b/sendNotify.js @@ -8,8 +8,6 @@ * @param desp 通知体 * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } * @param author 作者仓库等信息 例:`本通知 By:https://github.com/whyour/qinglong` - * @魔改:smallfawn https://github.com/smallfawn/QLScriptPublic 参考:ccwav https://github.com/ccwav/QLScript2 - * @魔改位置 sendNotify函数 黑白名单模式 */ const querystring = require('querystring'); @@ -36,12 +34,23 @@ let GOBOT_QQ = ''; // 如果GOBOT_URL设置 /send_private_msg 则需要填入 us //(环境变量名 PUSH_KEY) let SCKEY = ''; +// =======================================PushDeer通知设置区域=========================================== +//此处填你申请的PushDeer KEY. +//(环境变量名 DEER_KEY) +let PUSHDEER_KEY = ''; +let PUSHDEER_URL = ''; + +// =======================================Synology Chat通知设置区域=========================================== +//此处填你申请的CHAT_URL与CHAT_TOKEN +//(环境变量名 CHAT_URL CHAT_TOKEN) +let CHAT_URL = ''; +let CHAT_TOKEN = ''; + // =======================================Bark App通知设置区域=========================================== //此处填你BarkAPP的信息(IP/设备码,例如:https://api.day.app/XXXXXXXX) let BARK_PUSH = ''; //BARK app推送图标,自定义推送图标(需iOS15或以上) -let BARK_ICON = - 'https://img.gejiba.com/images/a3f551e09ac19add4c49ec16228729c5.png'; +let BARK_ICON = 'https://qn.whyour.cn/logo.png'; //BARK app推送铃声,铃声列表去APP查看复制填写 let BARK_SOUND = ''; //BARK app推送消息的分组, 默认为"QingLong" @@ -67,6 +76,10 @@ let DD_BOT_TOKEN = ''; //密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串 let DD_BOT_SECRET = ''; +// =======================================企业微信基础设置=========================================== +// 企业微信反向代理地址 +//(环境变量名 QYWX_ORIGIN) +let QYWX_ORIGIN = ''; // =======================================企业微信机器人通知设置区域=========================================== //此处填你企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa //(环境变量名 QYWX_KEY) @@ -95,6 +108,39 @@ let IGOT_PUSH_KEY = ''; let PUSH_PLUS_TOKEN = ''; let PUSH_PLUS_USER = ''; +// =======================================Cool Push设置区域======================================= +//官方文档:https://cp.xuthus.cc/docs +//QQ_SKEY: Cool Push登录授权后推送消息的调用代码Skey +//QQ_MODE: 推送模式详情请登录获取QQ_SKEY后见https://cp.xuthus.cc/feat +let QQ_SKEY = ''; +let QQ_MODE = ''; + +// =======================================智能微秘书设置区域======================================= +//官方文档:http://wechat.aibotk.com/docs/about +//AIBOTK_KEY: 填写智能微秘书个人中心的apikey +//AIBOTK_TYPE:填写发送的目标 room 或 contact, 填其他的不生效 +//AIBOTK_NAME: 填写群名或用户昵称,和上面的type类型要对应 +let AIBOTK_KEY = ''; +let AIBOTK_TYPE = ''; +let AIBOTK_NAME = ''; + +// =======================================飞书机器人设置区域======================================= +//官方文档:https://www.feishu.cn/hc/zh-CN/articles/360024984973 +//FSKEY 飞书机器人的 FSKEY +let FSKEY = ''; + +// =======================================SMTP 邮件设置区域======================================= +// SMTP_SERVER: 填写 SMTP 发送邮件服务器,形如 smtp.exmail.qq.com:465 +// SMTP_SSL: 填写 SMTP 发送邮件服务器是否使用 SSL,内容应为 true 或 false +// SMTP_EMAIL: 填写 SMTP 收发件邮箱,通知将会由自己发给自己 +// SMTP_PASSWORD: 填写 SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定 +// SMTP_NAME: 填写 SMTP 收发件人姓名,可随意填写 +let SMTP_SERVER = ''; +let SMTP_SSL = 'false'; +let SMTP_EMAIL = ''; +let SMTP_PASSWORD = ''; +let SMTP_NAME = ''; + //==========================云端环境变量的判断与接收========================= if (process.env.GOTIFY_URL) { GOTIFY_URL = process.env.GOTIFY_URL; @@ -120,6 +166,19 @@ if (process.env.PUSH_KEY) { SCKEY = process.env.PUSH_KEY; } +if (process.env.DEER_KEY) { + PUSHDEER_KEY = process.env.DEER_KEY; + PUSHDEER_URL = process.env.DEER_URL; +} + +if (process.env.CHAT_URL) { + CHAT_URL = process.env.CHAT_URL; +} + +if (process.env.CHAT_TOKEN) { + CHAT_TOKEN = process.env.CHAT_TOKEN; +} + if (process.env.QQ_SKEY) { QQ_SKEY = process.env.QQ_SKEY; } @@ -175,6 +234,12 @@ if (process.env.DD_BOT_TOKEN) { } } +if (process.env.QYWX_ORIGIN) { + QYWX_ORIGIN = process.env.QYWX_ORIGIN; +} else { + QYWX_ORIGIN = 'https://qyapi.weixin.qq.com'; +} + if (process.env.QYWX_KEY) { QYWX_KEY = process.env.QYWX_KEY; } @@ -193,12 +258,40 @@ if (process.env.PUSH_PLUS_TOKEN) { if (process.env.PUSH_PLUS_USER) { PUSH_PLUS_USER = process.env.PUSH_PLUS_USER; } + +if (process.env.AIBOTK_KEY) { + AIBOTK_KEY = process.env.AIBOTK_KEY; +} +if (process.env.AIBOTK_TYPE) { + AIBOTK_TYPE = process.env.AIBOTK_TYPE; +} +if (process.env.AIBOTK_NAME) { + AIBOTK_NAME = process.env.AIBOTK_NAME; +} + +if (process.env.FSKEY) { + FSKEY = process.env.FSKEY; +} + +if (process.env.SMTP_SERVER) { + SMTP_SERVER = process.env.SMTP_SERVER; +} +if (process.env.SMTP_SSL) { + SMTP_SSL = process.env.SMTP_SSL; +} +if (process.env.SMTP_EMAIL) { + SMTP_EMAIL = process.env.SMTP_EMAIL; +} +if (process.env.SMTP_PASSWORD) { + SMTP_PASSWORD = process.env.SMTP_PASSWORD; +} +if (process.env.SMTP_NAME) { + SMTP_NAME = process.env.SMTP_NAME; +} //==========================云端环境变量的判断与接收========================= /** * sendNotify 推送通知功能 - * 魔改:smallfawn https://github.com/smallfawn 增加黑白名单模式 - * 变量值 smallfawnPushWhite白名单 smallfawnPushBlack黑名单 不写默认通知 黑白名单二选一 * @param text 通知头 * @param desp 通知体 * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } @@ -281,6 +374,16 @@ async function sendNotify( async function push() { //提供6种通知 desp += author; //增加作者信息,防止被贩卖等 + + // 根据标题跳过一些消息推送,环境变量:SKIP_PUSH_TITLE 用回车分隔 + let skipTitle = process.env.SKIP_PUSH_TITLE; + if (skipTitle) { + if (skipTitle.split('\n').includes(text)) { + console.info(text + '在SKIP_PUSH_TITLE环境变量内,跳过推送!'); + return; + } + } + await Promise.all([ serverNotify(text, desp), //微信server酱 pushPlusNotify(text, desp), //pushplus(推送加) @@ -296,14 +399,14 @@ async function sendNotify( iGotNotify(text, desp, params), //iGot gobotNotify(text, desp), //go-cqhttp gotifyNotify(text, desp), //gotify + ChatNotify(text, desp), //synolog chat + PushDeerNotify(text, desp), //PushDeer + aibotkNotify(text, desp), //智能微秘书 + fsBotNotify(text, desp), //飞书机器人 + smtpNotify(text, desp), //SMTP 邮件 ]); } - - - - - } function gotifyNotify(text, desp) { @@ -343,7 +446,7 @@ function gotifyNotify(text, desp) { }); } -function gobotNotify(text, desp, time = 2100) { +function gobotNotify(text, desp) { return new Promise((resolve) => { if (GOBOT_URL) { const options = { @@ -354,38 +457,34 @@ function gobotNotify(text, desp, time = 2100) { }, timeout, }; - setTimeout(() => { - $.post(options, (err, resp, data) => { - try { - if (err) { - console.log('发送go-cqhttp通知调用API失败!!\n'); - console.log(err); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送go-cqhttp通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + if (data.retcode === 0) { + console.log('go-cqhttp发送通知消息成功🎉\n'); + } else if (data.retcode === 100) { + console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); } else { - data = JSON.parse(data); - if (data.retcode === 0) { - console.log('go-cqhttp发送通知消息成功🎉\n'); - } else if (data.retcode === 100) { - console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); - } else { - console.log( - `go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`, - ); - } + console.log(`go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`); } - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(data); } - }); - }, time); + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); } else { resolve(); } }); } -function serverNotify(text, desp, time = 2100) { +function serverNotify(text, desp) { return new Promise((resolve) => { if (SCKEY) { //微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 @@ -400,101 +499,63 @@ function serverNotify(text, desp, time = 2100) { }, timeout, }; - setTimeout(() => { - $.post(options, (err, resp, data) => { - try { - if (err) { - console.log('发送通知调用API失败!!\n'); - console.log(err); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + //server酱和Server酱·Turbo版的返回json格式不太一样 + if (data.errno === 0 || data.data.errno === 0) { + console.log('server酱发送通知消息成功🎉\n'); + } else if (data.errno === 1024) { + // 一分钟内发送相同的内容会触发 + console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); } else { - data = JSON.parse(data); - //server酱和Server酱·Turbo版的返回json格式不太一样 - if (data.errno === 0 || data.data.errno === 0) { - console.log('server酱发送通知消息成功🎉\n'); - } else if (data.errno === 1024) { - // 一分钟内发送相同的内容会触发 - console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); - } else { - console.log( - `server酱发送通知消息异常\n${JSON.stringify(data)}`, - ); - } + console.log(`server酱发送通知消息异常\n${JSON.stringify(data)}`); } - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(data); } - }); - }, time); + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); } else { resolve(); } }); } -function CoolPush(text, desp) { +function PushDeerNotify(text, desp) { return new Promise((resolve) => { - if (QQ_SKEY) { - let options = { - url: `https://push.xuthus.cc/${QQ_MODE}/${QQ_SKEY}`, + if (PUSHDEER_KEY) { + // PushDeer 建议对消息内容进行 urlencode + desp = encodeURI(desp); + const options = { + url: PUSHDEER_URL || `https://api2.pushdeer.com/message/push`, + body: `pushkey=${PUSHDEER_KEY}&text=${text}&desp=${desp}&type=markdown`, headers: { - 'Content-Type': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', }, + timeout, }; - - // 已知敏感词 - text = text.replace(/京豆/g, '豆豆'); - desp = desp.replace(/京豆/g, ''); - desp = desp.replace(/🐶/g, ''); - desp = desp.replace(/红包/g, 'H包'); - - switch (QQ_MODE) { - case 'email': - options.json = { - t: text, - c: desp, - }; - break; - default: - options.body = `${text}\n\n${desp}`; - } - - let pushMode = function (t) { - switch (t) { - case 'send': - return '个人'; - case 'group': - return 'QQ群'; - case 'wx': - return '微信'; - case 'ww': - return '企业微信'; - case 'email': - return '邮件'; - default: - return '未知方式'; - } - }; - $.post(options, (err, resp, data) => { try { if (err) { - console.log(`发送${pushMode(QQ_MODE)}通知调用API失败!!\n`); + console.log('发送通知调用API失败!!\n'); console.log(err); } else { data = JSON.parse(data); - if (data.code === 200) { - console.log(`酷推发送${pushMode(QQ_MODE)}通知消息成功🎉\n`); - } else if (data.code === 400) { - console.log( - `QQ酷推(Cool Push)发送${pushMode(QQ_MODE)}推送失败:${data.msg - }\n`, - ); - } else if (data.code === 503) { - console.log(`QQ酷推出错,${data.message}:${data.data}\n`); + // 通过返回的result的长度来判断是否成功 + if ( + data.content.result.length !== undefined && + data.content.result.length > 0 + ) { + console.log('PushDeer发送通知消息成功🎉\n'); } else { - console.log(`酷推推送异常: ${JSON.stringify(data)}`); + console.log(`PushDeer发送通知消息异常\n${JSON.stringify(data)}`); } } } catch (e) { @@ -509,13 +570,50 @@ function CoolPush(text, desp) { }); } +function ChatNotify(text, desp) { + return new Promise((resolve) => { + if (CHAT_URL && CHAT_TOKEN) { + // 对消息内容进行 urlencode + desp = encodeURI(desp); + const options = { + url: `${CHAT_URL}${CHAT_TOKEN}`, + body: `payload={"text":"${text}\n${desp}"}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + if (data.success) { + console.log('Chat发送通知消息成功🎉\n'); + } else { + console.log(`Chat发送通知消息异常\n${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + function BarkNotify(text, desp, params = {}) { return new Promise((resolve) => { if (BARK_PUSH) { const options = { url: `${BARK_PUSH}/${encodeURIComponent(text)}/${encodeURIComponent( desp, - )}?icon=${BARK_ICON}?sound=${BARK_SOUND}&group=${BARK_GROUP}&${querystring.stringify( + )}?icon=${BARK_ICON}&sound=${BARK_SOUND}&group=${BARK_GROUP}&${querystring.stringify( params, )}`, headers: { @@ -553,9 +651,13 @@ function tgBotNotify(text, desp) { if (TG_BOT_TOKEN && TG_USER_ID) { const options = { url: `https://${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`, - body: `chat_id=${TG_USER_ID}&text=${text}\n\n${desp}&disable_web_page_preview=true`, + json: { + chat_id: `${TG_USER_ID}`, + text: `${text}\n\n${desp}`, + disable_web_page_preview: true, + }, headers: { - 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Type': 'application/json', }, timeout, }; @@ -607,7 +709,7 @@ function ddBotNotify(text, desp) { json: { msgtype: 'text', text: { - content: ` ${text}\n\n${desp}`, + content: `${text}\n\n${desp}`, }, }, headers: { @@ -670,11 +772,11 @@ function ddBotNotify(text, desp) { function qywxBotNotify(text, desp) { return new Promise((resolve) => { const options = { - url: `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${QYWX_KEY}`, + url: `${QYWX_ORIGIN}/cgi-bin/webhook/send?key=${QYWX_KEY}`, json: { msgtype: 'text', text: { - content: ` ${text}\n\n${desp}`, + content: `${text}\n\n${desp}`, }, }, headers: { @@ -732,7 +834,7 @@ function qywxamNotify(text, desp) { if (QYWX_AM) { const QYWX_AM_AY = QYWX_AM.split(','); const options_accesstoken = { - url: `https://qyapi.weixin.qq.com/cgi-bin/gettoken`, + url: `${QYWX_ORIGIN}/cgi-bin/gettoken`, json: { corpid: `${QYWX_AM_AY[0]}`, corpsecret: `${QYWX_AM_AY[1]}`, @@ -743,9 +845,9 @@ function qywxamNotify(text, desp) { timeout, }; $.post(options_accesstoken, (err, resp, data) => { - html = desp.replace(/\n/g, '
'); - var json = JSON.parse(data); - accesstoken = json.access_token; + let html = desp.replace(/\n/g, '
'); + let json = JSON.parse(data); + let accesstoken = json.access_token; let options; switch (QYWX_AM_AY[4]) { @@ -797,7 +899,7 @@ function qywxamNotify(text, desp) { }; } options = { - url: `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accesstoken}`, + url: `${QYWX_ORIGIN}/cgi-bin/message/send?access_token=${accesstoken}`, json: { touser: `${ChangeUserId(desp)}`, agentid: `${QYWX_AM_AY[3]}`, @@ -938,6 +1040,150 @@ function pushPlusNotify(text, desp) { }); } +function aibotkNotify(text, desp) { + return new Promise((resolve) => { + if (AIBOTK_KEY && AIBOTK_TYPE && AIBOTK_NAME) { + let json = {}; + let url = ''; + switch (AIBOTK_TYPE) { + case 'room': + url = 'https://api-bot.aibotk.com/openapi/v1/chat/room'; + json = { + apiKey: `${AIBOTK_KEY}`, + roomName: `${AIBOTK_NAME}`, + message: { + type: 1, + content: `【青龙快讯】\n\n${text}\n${desp}`, + }, + }; + break; + case 'contact': + url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact'; + json = { + apiKey: `${AIBOTK_KEY}`, + name: `${AIBOTK_NAME}`, + message: { + type: 1, + content: `【青龙快讯】\n\n${text}\n${desp}`, + }, + }; + break; + } + const options = { + url: url, + json, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('智能微秘书发送通知消息失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + if (data.code === 0) { + console.log('智能微秘书发送通知消息成功🎉。\n'); + } else { + console.log(`${data.error}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function fsBotNotify(text, desp) { + return new Promise((resolve) => { + if (FSKEY) { + const options = { + url: `https://open.feishu.cn/open-apis/bot/v2/hook/${FSKEY}`, + json: { msg_type: 'text', content: { text: `${text}\n\n${desp}` } }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + if (data.StatusCode === 0) { + console.log('飞书发送通知消息成功🎉\n'); + } else { + console.log(`${data.msg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +async function smtpNotify(text, desp) { + if (![SMTP_SERVER, SMTP_EMAIL, SMTP_PASSWORD].every(Boolean)) { + return; + } + + try { + const nodemailer = require('nodemailer'); + const transporter = nodemailer.createTransport( + `${SMTP_SSL === 'true' ? 'smtps:' : 'smtp:'}//${SMTP_SERVER}`, + { + auth: { + user: SMTP_EMAIL, + pass: SMTP_PASSWORD, + }, + }, + ); + + const addr = SMTP_NAME ? `"${SMTP_NAME}" <${SMTP_EMAIL}>` : SMTP_EMAIL; + const info = await transporter.sendMail({ + from: addr, + to: addr, + subject: text, + text: desp, + }); + + if (!!info.messageId) { + console.log('SMTP发送通知消息成功🎉\n'); + return true; + } + console.log('SMTP发送通知消息失败!!\n'); + } catch (e) { + console.log('SMTP发送通知消息出现错误!!\n'); + console.log(e); + } +} + +function smtpNotify(text, desp) { + return new Promise((resolve) => { + if (SMTP_SERVER && SMTP_SSL && SMTP_EMAIL && SMTP_PASSWORD && SMTP_NAME) { + // todo: Node.js并没有内置的 smtp 实现,需要调用外部库,因为不清楚这个文件的模块依赖情况,所以留给有缘人实现 + } else { + resolve(); + } + }); +} + module.exports = { sendNotify, BARK_PUSH,