const querystring = require('node:querystring'); const got = require('got'); const timeout = 15000; const push_config = { HITOKOTO: true, // 启用一言(随机句子) BARK_PUSH: '', // bark IP 或设备码,例:https://api.day.app/DxHcxxxxxRxxxxxxcm/ BARK_ARCHIVE: '', // bark 推送是否存档 BARK_GROUP: '', // bark 推送分组 BARK_SOUND: '', // bark 推送声音 BARK_ICON: '', // bark 推送图标 BARK_LEVEL: '', // bark 推送时效性 BARK_URL: '', // bark 推送跳转URL DD_BOT_SECRET: '', // 钉钉机器人的 DD_BOT_SECRET DD_BOT_TOKEN: '', // 钉钉机器人的 DD_BOT_TOKEN FSKEY: '', // 飞书机器人的 FSKEY // 推送到个人QQ:http://127.0.0.1/send_private_msg // 群:http://127.0.0.1/send_group_msg GOBOT_URL: '', // go-cqhttp // 推送到个人QQ 填入 user_id=个人QQ // 群 填入 group_id=QQ群 GOBOT_QQ: '', // go-cqhttp 的推送群或用户 GOBOT_TOKEN: '', // go-cqhttp 的 access_token GOTIFY_URL: '', // gotify地址,如https://push.example.de:8080 GOTIFY_TOKEN: '', // gotify的消息应用token GOTIFY_PRIORITY: 0, // 推送消息优先级,默认为0 IGOT_PUSH_KEY: '', // iGot 聚合推送的 IGOT_PUSH_KEY,例如:https://push.hellyw.com/XXXXXXXX PUSH_KEY: '', // server 酱的 PUSH_KEY,兼容旧版与 Turbo 版 DEER_KEY: '', // PushDeer 的 PUSHDEER_KEY DEER_URL: '', // PushDeer 的 PUSHDEER_URL CHAT_URL: '', // synology chat url CHAT_TOKEN: '', // synology chat token // 官方文档:http://www.pushplus.plus/ PUSH_PLUS_TOKEN: '', // push+ 微信推送的用户令牌 PUSH_PLUS_USER: '', // push+ 微信推送的群组编码 // 微加机器人,官方网站:https://www.weplusbot.com/ WE_PLUS_BOT_TOKEN: '', // 微加机器人的用户令牌 WE_PLUS_BOT_RECEIVER: '', // 微加机器人的消息接收人 WE_PLUS_BOT_VERSION: 'pro', //微加机器人调用版本,pro和personal;为空默认使用pro(专业版),个人版填写:personal QMSG_KEY: '', // qmsg 酱的 QMSG_KEY QMSG_TYPE: '', // qmsg 酱的 QMSG_TYPE QYWX_ORIGIN: 'https://qyapi.weixin.qq.com', // 企业微信代理地址 /* 此处填你企业微信应用消息的值(详见文档 https://work.weixin.qq.com/api/doc/90000/90135/90236) 环境变量名 QYWX_AM依次填入 corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcff56746d9adwers,B-791548lnzXBE6_BWfxdf3kSTMJr9vFEPKAbh6WERQ,mingcheng,1000001,2COXgjH2UIfERF2zxrtUOKgQ9XklUqMdGSWLBoW_lSDAdafat 可选推送消息类型(推荐使用图文消息(mpnews)): - 文本卡片消息: 0 (数字零) - 文本消息: 1 (数字一) - 图文消息(mpnews): 素材库图片id, 可查看此教程(http://note.youdao.com/s/HMiudGkb)或者(https://note.youdao.com/ynoteshare1/index.html?id=1a0c8aff284ad28cbd011b29b3ad0191&type=note) */ QYWX_AM: '', // 企业微信应用 QYWX_KEY: '', // 企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa TG_BOT_TOKEN: '', // tg 机器人的 TG_BOT_TOKEN,例:1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ TG_USER_ID: '', // tg 机器人的 TG_USER_ID,例:1434078534 TG_API_HOST: 'https://api.telegram.org', // tg 代理 api TG_PROXY_AUTH: '', // tg 代理认证参数 TG_PROXY_HOST: '', // tg 机器人的 TG_PROXY_HOST TG_PROXY_PORT: '', // tg 机器人的 TG_PROXY_PORT AIBOTK_KEY: '', // 智能微秘书 个人中心的apikey 文档地址:http://wechat.aibotk.com/docs/about AIBOTK_TYPE: '', // 智能微秘书 发送目标 room 或 contact AIBOTK_NAME: '', // 智能微秘书 发送群名 或者好友昵称和type要对应好 SMTP_SERVICE: '', // 邮箱服务名称,比如 126、163、Gmail、QQ 等,支持列表 https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json SMTP_EMAIL: '', // SMTP 收发件邮箱,通知将会由自己发给自己 SMTP_PASSWORD: '', // SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定 SMTP_NAME: '', // SMTP 收发件人姓名,可随意填写 PUSHME_KEY: '', // 官方文档:https://push.i-i.me,PushMe 酱的 PUSHME_KEY // CHRONOCAT API https://chronocat.vercel.app/install/docker/official/ CHRONOCAT_QQ: '', // 个人: user_id=个人QQ 群则填入 group_id=QQ群 多个用英文;隔开同时支持个人和群 CHRONOCAT_TOKEN: '', // 填写在CHRONOCAT文件生成的访问密钥 CHRONOCAT_URL: '', // Red 协议连接地址 例: http://127.0.0.1:16530 WEBHOOK_URL: '', // 自定义通知 请求地址 WEBHOOK_BODY: '', // 自定义通知 请求体 WEBHOOK_HEADERS: '', // 自定义通知 请求头 WEBHOOK_METHOD: '', // 自定义通知 请求方法 WEBHOOK_CONTENT_TYPE: '', // 自定义通知 content-type }; for (const key in push_config) { const v = process.env[key]; if (v) { push_config[key] = v; } } const $ = { post: (params, callback) => { const { url, ...others } = params; got.post(url, others).then( (res) => { let body = res.body; try { body = JSON.parse(body); } catch (error) {} callback(null, res, body); }, (err) => { callback(err?.response?.body || err); }, ); }, get: (params, callback) => { const { url, ...others } = params; got.get(url, others).then( (res) => { let body = res.body; try { body = JSON.parse(body); } catch (error) {} callback(null, res, body); }, (err) => { callback(err?.response?.body || err); }, ); }, logErr: console.log, }; async function one() { const url = 'https://v1.hitokoto.cn/'; const res = await got.get(url); const body = JSON.parse(res.body); return `${body.hitokoto} ----${body.from}`; } function gotifyNotify(text, desp) { return new Promise((resolve) => { const { GOTIFY_URL, GOTIFY_TOKEN, GOTIFY_PRIORITY } = push_config; if (GOTIFY_URL && GOTIFY_TOKEN) { const options = { url: `${GOTIFY_URL}/message?token=${GOTIFY_TOKEN}`, body: `title=${encodeURIComponent(text)}&message=${encodeURIComponent( desp, )}&priority=${GOTIFY_PRIORITY}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('Gotify 发送通知调用API失败😞\n', err); } else { if (data.id) { console.log('Gotify 发送通知消息成功🎉\n'); } else { console.log(`Gotify 发送通知调用API失败😞 ${data.message}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(); } }); } else { resolve(); } }); } function gobotNotify(text, desp) { return new Promise((resolve) => { const { GOBOT_URL, GOBOT_TOKEN, GOBOT_QQ } = push_config; if (GOBOT_URL) { const options = { url: `${GOBOT_URL}?access_token=${GOBOT_TOKEN}&${GOBOT_QQ}`, json: { message: `${text}\n${desp}` }, headers: { 'Content-Type': 'application/json', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('Go-cqhttp 通知调用API失败😞\n', err); } else { 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 发送通知消息异常 ${JSON.stringify(data)}`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function serverNotify(text, desp) { return new Promise((resolve) => { const { PUSH_KEY } = push_config; if (PUSH_KEY) { // 微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 desp = desp.replace(/[\n\r]/g, '\n\n'); const options = { url: PUSH_KEY.includes('SCT') ? `https://sctapi.ftqq.com/${PUSH_KEY}.send` : `https://sc.ftqq.com/${PUSH_KEY}.send`, body: `text=${text}&desp=${desp}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('Server 酱发送通知调用API失败😞\n', err); } else { // 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 酱发送通知消息异常 ${JSON.stringify(data)}`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function pushDeerNotify(text, desp) { return new Promise((resolve) => { const { DEER_KEY, DEER_URL } = push_config; if (DEER_KEY) { // PushDeer 建议对消息内容进行 urlencode desp = encodeURI(desp); const options = { url: DEER_URL || `https://api2.pushdeer.com/message/push`, body: `pushkey=${DEER_KEY}&text=${text}&desp=${desp}&type=markdown`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('PushDeer 通知调用API失败😞\n', err); } else { // 通过返回的result的长度来判断是否成功 if ( data.content.result.length !== undefined && data.content.result.length > 0 ) { console.log('PushDeer 发送通知消息成功🎉\n'); } else { console.log( `PushDeer 发送通知消息异常😞 ${JSON.stringify(data)}`, ); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function chatNotify(text, desp) { return new Promise((resolve) => { const { CHAT_URL, CHAT_TOKEN } = push_config; 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('Chat 发送通知调用API失败😞\n', err); } else { if (data.success) { console.log('Chat 发送通知消息成功🎉\n'); } else { console.log(`Chat 发送通知消息异常 ${JSON.stringify(data)}`); } } } catch (e) { $.logErr(e); } finally { resolve(data); } }); } else { resolve(); } }); } function barkNotify(text, desp, params = {}) { return new Promise((resolve) => { let { BARK_PUSH, BARK_ICON, BARK_SOUND, BARK_GROUP, BARK_LEVEL, BARK_ARCHIVE, BARK_URL, } = push_config; if (BARK_PUSH) { // 兼容BARK本地用户只填写设备码的情况 if (!BARK_PUSH.startsWith('http')) { BARK_PUSH = `https://api.day.app/${BARK_PUSH}`; } const options = { url: `${BARK_PUSH}`, json: { title: text, body: desp, icon: BARK_ICON, sound: BARK_SOUND, group: BARK_GROUP, isArchive: BARK_ARCHIVE, level: BARK_LEVEL, url: BARK_URL, ...params, }, headers: { 'Content-Type': 'application/json', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('Bark APP 发送通知调用API失败😞\n', err); } else { if (data.code === 200) { console.log('Bark APP 发送通知消息成功🎉\n'); } else { console.log(`Bark APP 发送通知消息异常 ${data.message}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(); } }); } else { resolve(); } }); } function tgBotNotify(text, desp) { return new Promise((resolve) => { const { TG_BOT_TOKEN, TG_USER_ID, TG_PROXY_HOST, TG_PROXY_PORT, TG_API_HOST, TG_PROXY_AUTH, } = push_config; if (TG_BOT_TOKEN && TG_USER_ID) { const options = { url: `${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`, json: { chat_id: `${TG_USER_ID}`, text: `${text}\n\n${desp}`, disable_web_page_preview: true, }, headers: { 'Content-Type': 'application/json', }, timeout, }; if (TG_PROXY_HOST && TG_PROXY_PORT) { const { HttpProxyAgent, HttpsProxyAgent } = require('hpagent'); const options = { keepAlive: true, keepAliveMsecs: 1000, maxSockets: 256, maxFreeSockets: 256, proxy: `http://${TG_PROXY_AUTH}${TG_PROXY_HOST}:${TG_PROXY_PORT}`, }; const httpAgent = new HttpProxyAgent(options); const httpsAgent = new HttpsProxyAgent(options); const agent = { http: httpAgent, https: httpsAgent, }; Object.assign(options, { agent }); } $.post(options, (err, resp, data) => { try { if (err) { console.log('Telegram 发送通知消息失败😞\n', err); } else { if (data.ok) { console.log('Telegram 发送通知消息成功🎉。\n'); } else if (data.error_code === 400) { console.log( '请主动给bot发送一条消息并检查接收用户ID是否正确。\n', ); } else if (data.error_code === 401) { console.log('Telegram bot token 填写错误。\n'); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function ddBotNotify(text, desp) { return new Promise((resolve) => { const { DD_BOT_TOKEN, DD_BOT_SECRET } = push_config; const options = { url: `https://oapi.dingtalk.com/robot/send?access_token=${DD_BOT_TOKEN}`, json: { msgtype: 'text', text: { content: `${text}\n\n${desp}`, }, }, headers: { 'Content-Type': 'application/json', }, timeout, }; if (DD_BOT_TOKEN && DD_BOT_SECRET) { const crypto = require('crypto'); const dateNow = Date.now(); const hmac = crypto.createHmac('sha256', DD_BOT_SECRET); hmac.update(`${dateNow}\n${DD_BOT_SECRET}`); const result = encodeURIComponent(hmac.digest('base64')); options.url = `${options.url}×tamp=${dateNow}&sign=${result}`; $.post(options, (err, resp, data) => { try { if (err) { console.log('钉钉发送通知消息失败😞\n', err); } else { if (data.errcode === 0) { console.log('钉钉发送通知消息成功🎉\n'); } else { console.log(`钉钉发送通知消息异常 ${data.errmsg}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else if (DD_BOT_TOKEN) { $.post(options, (err, resp, data) => { try { if (err) { console.log('钉钉发送通知消息失败😞\n', err); } else { if (data.errcode === 0) { console.log('钉钉发送通知消息成功🎉\n'); } else { console.log(`钉钉发送通知消息异常 ${data.errmsg}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function qywxBotNotify(text, desp) { return new Promise((resolve) => { const { QYWX_ORIGIN, QYWX_KEY } = push_config; const options = { url: `${QYWX_ORIGIN}/cgi-bin/webhook/send?key=${QYWX_KEY}`, json: { msgtype: 'text', text: { content: `${text}\n\n${desp}`, }, }, headers: { 'Content-Type': 'application/json', }, timeout, }; if (QYWX_KEY) { $.post(options, (err, resp, data) => { try { if (err) { console.log('企业微信发送通知消息失败😞\n', err); } else { if (data.errcode === 0) { console.log('企业微信发送通知消息成功🎉。\n'); } else { console.log(`企业微信发送通知消息异常 ${data.errmsg}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function ChangeUserId(desp) { const { QYWX_AM } = push_config; const QYWX_AM_AY = QYWX_AM.split(','); if (QYWX_AM_AY[2]) { const userIdTmp = QYWX_AM_AY[2].split('|'); let userId = ''; for (let i = 0; i < userIdTmp.length; i++) { const count = '账号' + (i + 1); const count2 = '签到号 ' + (i + 1); if (desp.match(count2)) { userId = userIdTmp[i]; } } if (!userId) userId = QYWX_AM_AY[2]; return userId; } else { return '@all'; } } async function qywxamNotify(text, desp) { const MAX_LENGTH = 900; if (desp.length > MAX_LENGTH) { let d = desp.substr(0, MAX_LENGTH) + '\n==More=='; await do_qywxamNotify(text, d); await qywxamNotify(text, desp.substr(MAX_LENGTH)); } else { return await do_qywxamNotify(text, desp); } } function do_qywxamNotify(text, desp) { return new Promise((resolve) => { const { QYWX_AM, QYWX_ORIGIN } = push_config; if (QYWX_AM) { const QYWX_AM_AY = QYWX_AM.split(','); const options_accesstoken = { url: `${QYWX_ORIGIN}/cgi-bin/gettoken`, json: { corpid: `${QYWX_AM_AY[0]}`, corpsecret: `${QYWX_AM_AY[1]}`, }, headers: { 'Content-Type': 'application/json', }, timeout, }; $.post(options_accesstoken, (err, resp, json) => { let html = desp.replace(/\n/g, '
'); let accesstoken = json.access_token; let options; switch (QYWX_AM_AY[4]) { case '0': options = { msgtype: 'textcard', textcard: { title: `${text}`, description: `${desp}`, url: 'https://github.com/whyour/qinglong', btntxt: '更多', }, }; break; case '1': options = { msgtype: 'text', text: { content: `${text}\n\n${desp}`, }, }; break; default: options = { msgtype: 'mpnews', mpnews: { articles: [ { title: `${text}`, thumb_media_id: `${QYWX_AM_AY[4]}`, author: `智能助手`, content_source_url: ``, content: `${html}`, digest: `${desp}`, }, ], }, }; } if (!QYWX_AM_AY[4]) { // 如不提供第四个参数,则默认进行文本消息类型推送 options = { msgtype: 'text', text: { content: `${text}\n\n${desp}`, }, }; } options = { url: `${QYWX_ORIGIN}/cgi-bin/message/send?access_token=${accesstoken}`, json: { touser: `${ChangeUserId(desp)}`, agentid: `${QYWX_AM_AY[3]}`, safe: '0', ...options, }, headers: { 'Content-Type': 'application/json', }, }; $.post(options, (err, resp, data) => { try { if (err) { console.log( '成员ID:' + ChangeUserId(desp) + '企业微信应用消息发送通知消息失败😞\n', err, ); } else { if (data.errcode === 0) { console.log( '成员ID:' + ChangeUserId(desp) + '企业微信应用消息发送通知消息成功🎉。\n', ); } else { console.log( `企业微信应用消息发送通知消息异常 ${data.errmsg}\n`, ); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); }); } else { resolve(); } }); } function iGotNotify(text, desp, params = {}) { return new Promise((resolve) => { const { IGOT_PUSH_KEY } = push_config; if (IGOT_PUSH_KEY) { // 校验传入的IGOT_PUSH_KEY是否有效 const IGOT_PUSH_KEY_REGX = new RegExp('^[a-zA-Z0-9]{24}$'); if (!IGOT_PUSH_KEY_REGX.test(IGOT_PUSH_KEY)) { console.log('您所提供的 IGOT_PUSH_KEY 无效\n'); resolve(); return; } const options = { url: `https://push.hellyw.com/${IGOT_PUSH_KEY.toLowerCase()}`, body: `title=${text}&content=${desp}&${querystring.stringify(params)}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('IGot 发送通知调用API失败😞\n', err); } else { if (data.ret === 0) { console.log('IGot 发送通知消息成功🎉\n'); } else { console.log(`IGot 发送通知消息异常 ${data.errMsg}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function pushPlusNotify(text, desp) { return new Promise((resolve) => { const { PUSH_PLUS_TOKEN, PUSH_PLUS_USER } = push_config; if (PUSH_PLUS_TOKEN) { desp = desp.replace(/[\n\r]/g, '
'); // 默认为html, 不支持plaintext const body = { token: `${PUSH_PLUS_TOKEN}`, title: `${text}`, content: `${desp}`, topic: `${PUSH_PLUS_USER}`, }; const options = { url: `https://www.pushplus.plus/send`, body: JSON.stringify(body), headers: { 'Content-Type': ' application/json', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log( `Push+ 发送${ PUSH_PLUS_USER ? '一对多' : '一对一' }通知消息失败😞\n`, err, ); } else { if (data.code === 200) { console.log( `Push+ 发送${ PUSH_PLUS_USER ? '一对多' : '一对一' }通知消息完成🎉\n`, ); } else { console.log( `Push+ 发送${ PUSH_PLUS_USER ? '一对多' : '一对一' }通知消息异常 ${data.msg}\n`, ); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function wePlusBotNotify(text, desp) { return new Promise((resolve) => { const { WE_PLUS_BOT_TOKEN, WE_PLUS_BOT_RECEIVER, WE_PLUS_BOT_VERSION } = push_config; if (WE_PLUS_BOT_TOKEN) { let template = 'txt'; if (desp.length > 800) { desp = desp.replace(/[\n\r]/g, '
'); template = 'html'; } const body = { token: `${WE_PLUS_BOT_TOKEN}`, title: `${text}`, content: `${desp}`, template: `${template}`, receiver: `${WE_PLUS_BOT_RECEIVER}`, version: `${WE_PLUS_BOT_VERSION}`, }; const options = { url: `https://www.weplusbot.com/send`, body: JSON.stringify(body), headers: { 'Content-Type': ' application/json', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log(`微加机器人发送通知消息失败😞\n`, err); } else { if (data.code === 200) { console.log(`微加机器人发送通知消息完成🎉\n`); } else { console.log(`微加机器人发送通知消息异常 ${data.msg}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function aibotkNotify(text, desp) { return new Promise((resolve) => { const { AIBOTK_KEY, AIBOTK_TYPE, AIBOTK_NAME } = push_config; 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', err); } else { 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) => { const { FSKEY } = push_config; 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', err); } else { if (data.StatusCode === 0 || data.code === 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) { const { SMTP_EMAIL, SMTP_PASSWORD, SMTP_SERVICE, SMTP_NAME } = push_config; if (![SMTP_EMAIL, SMTP_PASSWORD].every(Boolean) || !SMTP_SERVICE) { return; } try { const nodemailer = require('nodemailer'); const transporter = nodemailer.createTransport({ service: SMTP_SERVICE, 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, html: `${desp.replace(/\n/g, '
')}`, }); transporter.close(); if (info.messageId) { console.log('SMTP 发送通知消息成功🎉\n'); return true; } console.log('SMTP 发送通知消息失败😞\n'); } catch (e) { console.log('SMTP 发送通知消息出现异常😞\n', e); } } function pushMeNotify(text, desp, params = {}) { return new Promise((resolve) => { const { PUSHME_KEY, PUSHME_URL } = push_config; if (PUSHME_KEY) { const options = { url: PUSHME_URL || 'https://push.i-i.me', json: { push_key: PUSHME_KEY, title: text, content: desp, ...params }, headers: { 'Content-Type': 'application/json', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('PushMe 发送通知调用API失败😞\n', err); } else { if (data === 'success') { console.log('PushMe 发送通知消息成功🎉\n'); } else { console.log(`PushMe 发送通知消息异常 ${data}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function chronocatNotify(title, desp) { return new Promise((resolve) => { const { CHRONOCAT_TOKEN, CHRONOCAT_QQ, CHRONOCAT_URL } = push_config; if (!CHRONOCAT_TOKEN || !CHRONOCAT_QQ || !CHRONOCAT_URL) { resolve(); return; } const user_ids = CHRONOCAT_QQ.match(/user_id=(\d+)/g)?.map( (match) => match.split('=')[1], ); const group_ids = CHRONOCAT_QQ.match(/group_id=(\d+)/g)?.map( (match) => match.split('=')[1], ); const url = `${CHRONOCAT_URL}/api/message/send`; const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${CHRONOCAT_TOKEN}`, }; for (const [chat_type, ids] of [ [1, user_ids], [2, group_ids], ]) { if (!ids) { continue; } for (const chat_id of ids) { const data = { peer: { chatType: chat_type, peerUin: chat_id, }, elements: [ { elementType: 1, textElement: { content: `${title}\n\n${desp}`, }, }, ], }; const options = { url: url, json: data, headers, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('Chronocat 发送QQ通知消息失败😞\n', err); } else { if (chat_type === 1) { console.log(`Chronocat 个人消息 ${ids}推送成功🎉`); } else { console.log(`Chronocat 群消息 ${ids}推送成功🎉`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } } }); } function qmsgNotify(text, desp) { return new Promise((resolve) => { const { QMSG_KEY, QMSG_TYPE } = push_config; if (QMSG_KEY && QMSG_TYPE) { const options = { url: `https://qmsg.zendee.cn/${QMSG_TYPE}/${QMSG_KEY}`, body: `msg=${text}\n\n${desp.replace('----', '-')}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, timeout, }; $.post(options, (err, resp, data) => { try { if (err) { console.log('Qmsg 发送通知调用API失败😞\n', err); } else { if (data.code === 0) { console.log('Qmsg 发送通知消息成功🎉\n'); } else { console.log(`Qmsg 发送通知消息异常 ${data}\n`); } } } catch (e) { $.logErr(e, resp); } finally { resolve(data); } }); } else { resolve(); } }); } function webhookNotify(text, desp) { return new Promise((resolve) => { const { WEBHOOK_URL, WEBHOOK_BODY, WEBHOOK_HEADERS, WEBHOOK_CONTENT_TYPE, WEBHOOK_METHOD, } = push_config; if ( !WEBHOOK_METHOD || !WEBHOOK_URL || (!WEBHOOK_URL.includes('$title') && !WEBHOOK_BODY.includes('$title')) ) { resolve(); return; } const headers = parseHeaders(WEBHOOK_HEADERS); const body = parseBody(WEBHOOK_BODY, WEBHOOK_CONTENT_TYPE, (v) => v ?.replaceAll('$title', text?.replaceAll('\n', '\\n')) ?.replaceAll('$content', desp?.replaceAll('\n', '\\n')), ); const bodyParam = formatBodyFun(WEBHOOK_CONTENT_TYPE, body); const options = { method: WEBHOOK_METHOD, headers, allowGetBody: true, ...bodyParam, timeout, retry: 1, }; const formatUrl = WEBHOOK_URL.replaceAll( '$title', encodeURIComponent(text), ).replaceAll('$content', encodeURIComponent(desp)); got(formatUrl, options).then((resp) => { try { if (resp.statusCode !== 200) { console.log(`自定义发送通知消息失败😞 ${resp.body}\n`); } else { console.log(`自定义发送通知消息成功🎉 ${resp.body}\n`); } } catch (e) { $.logErr(e, resp); } finally { resolve(resp.body); } }); }); } function parseString(input, valueFormatFn) { const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g; const matches = {}; let match; while ((match = regex.exec(input)) !== null) { const [, key, value] = match; const _key = key.trim(); if (!_key || matches[_key]) { continue; } let _value = value.trim(); try { _value = valueFormatFn ? valueFormatFn(_value) : _value; const jsonValue = JSON.parse(_value); matches[_key] = jsonValue; } catch (error) { matches[_key] = _value; } } return matches; } 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, valueFormatFn) { if (contentType === 'text/plain' || !body) { return valueFormatFn && body ? valueFormatFn(body) : body; } const parsed = parseString(body, valueFormatFn); 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': case 'text/plain': return { body }; } return {}; } /** * sendNotify 推送通知功能 * @param text 通知头 * @param desp 通知体 * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } * @returns {Promise} */ async function sendNotify(text, desp, params = {}) { // 根据标题跳过一些消息推送,环境变量: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; } } if (push_config.HITOKOTO !== 'false') { desp += '\n\n' + (await one()); } await Promise.all([ serverNotify(text, desp), // 微信server酱 pushPlusNotify(text, desp), // pushplus wePlusBotNotify(text, desp), // 微加机器人 barkNotify(text, desp, params), // iOS Bark APP tgBotNotify(text, desp), // telegram 机器人 ddBotNotify(text, desp), // 钉钉机器人 qywxBotNotify(text, desp), // 企业微信机器人 qywxamNotify(text, desp), // 企业微信应用消息推送 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 邮件 pushMeNotify(text, desp, params), // PushMe chronocatNotify(text, desp), // Chronocat webhookNotify(text, desp), // 自定义通知 qmsgNotify(text, desp), // 自定义通知 ]); } module.exports = { sendNotify, };