vault backup: 2026-11-09 09:52:30
This commit is contained in:
1 parent
5022dc27b2
commit
d58a4b3fa9
4 files changed
+88
-8
No files matched your search
Vendored
+2
-2
@@ -199,6 +199,8 @@
|
|||||||
},
|
},
|
||||||
"active": "b10e6fd1a0b41e79",
|
"active": "b10e6fd1a0b41e79",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
|
"小鱼/闲鱼消息通知/watch.log",
|
||||||
|
"小鱼/闲鱼消息通知/send-mail.ps1",
|
||||||
"小鱼/闲鱼消息通知/throttle-test.js",
|
"小鱼/闲鱼消息通知/throttle-test.js",
|
||||||
"小鱼/闲鱼消息通知/README.md",
|
"小鱼/闲鱼消息通知/README.md",
|
||||||
"小鱼/闲鱼消息通知/stop-watch.bat",
|
"小鱼/闲鱼消息通知/stop-watch.bat",
|
||||||
@@ -238,8 +240,6 @@
|
|||||||
"AndroidManifest.xml",
|
"AndroidManifest.xml",
|
||||||
"思睿/vocab_audio_output/audio/Day17.wav",
|
"思睿/vocab_audio_output/audio/Day17.wav",
|
||||||
"思睿/vocab_audio_output/audio/Day18.wav",
|
"思睿/vocab_audio_output/audio/Day18.wav",
|
||||||
"思睿/vocab_audio_output/audio/Day22.wav",
|
|
||||||
"妹妹/妹妹身高.md.tmp.19184.32689a71f9b9",
|
|
||||||
"思睿/身高/第一医院/报告/20261019报告/extracted_images/血常规 20261019_p1_img2.png",
|
"思睿/身高/第一医院/报告/20261019报告/extracted_images/血常规 20261019_p1_img2.png",
|
||||||
"思睿/身高/第一医院/报告/20261019报告/extracted_images/血常规 20261019_p1_img1.png",
|
"思睿/身高/第一医院/报告/20261019报告/extracted_images/血常规 20261019_p1_img1.png",
|
||||||
"思睿/身高/第一医院/报告/20261019报告/extracted_images/胰岛素测定 20261019_p1_img2.png",
|
"思睿/身高/第一医院/报告/20261019报告/extracted_images/胰岛素测定 20261019_p1_img2.png",
|
||||||
|
|||||||
+24
-2
@@ -48,15 +48,37 @@ webhook 的 URL 本身就是密码:拿到 URL 的任何人都能往你群里
|
|||||||
- 只想要本地弹窗/声音:默认即可。
|
- 只想要本地弹窗/声音:默认即可。
|
||||||
- 想推到手机/群里:编辑 `config.json` 的 `webhooks` 数组,加一条即可,支持:
|
- 想推到手机/群里:编辑 `config.json` 的 `webhooks` 数组,加一条即可,支持:
|
||||||
|
|
||||||
| type | url 说明 |
|
| type | 说明 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `feishu` | 飞书群 → 添加自定义机器人,复制 webhook 地址 |
|
| `feishu` | 飞书群 → 添加自定义机器人,复制 webhook 地址 |
|
||||||
| `wecom` | 企业微信群机器人地址 |
|
| `wecom` | 企业微信群机器人地址(群内至少要有两人,或管理员建应用) |
|
||||||
|
| `wecomapp` | **企业微信自建应用**:推给自己单聊,最干净。需管理员后台建应用,填 `corpid`/`corpsecret`/`agentid`,`touser` 填你的企微 UserID |
|
||||||
| `dingtalk` | 钉钉自定义机器人地址 |
|
| `dingtalk` | 钉钉自定义机器人地址 |
|
||||||
| `bark` | `https://api.day.app/你的KEY`(iPhone 锁屏推送,推荐) |
|
| `bark` | `https://api.day.app/你的KEY`(iPhone 锁屏推送,推荐) |
|
||||||
|
| `ntfy` | ntfy 主题地址,如 `https://ntfy.sh/你的主题` |
|
||||||
|
| `email` | 邮件(QQ/163 SMTP),微信有邮件提醒,等于推到手机 |
|
||||||
| `serverchan` | `https://sctapi.ftqq.com/你的KEY.send` |
|
| `serverchan` | `https://sctapi.ftqq.com/你的KEY.send` |
|
||||||
| `custom` | 任意 URL,可选 `method`/`headers`/`body`,body 里可用 `{{title}}` `{{text}}` |
|
| `custom` | 任意 URL,可选 `method`/`headers`/`body`,body 里可用 `{{title}}` `{{text}}` |
|
||||||
|
|
||||||
|
邮件示例(QQ 邮箱要先去设置里开 SMTP 并拿**授权码**,不是登录密码):
|
||||||
|
|
||||||
|
```json
|
||||||
|
"webhooks": [
|
||||||
|
{ "type": "email", "smtp": "smtp.qq.com", "port": 465,
|
||||||
|
"from": "你的QQ号@qq.com", "to": "你的QQ号@qq.com", "passEnv": "MAIL_PASS" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
企微自建应用示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"webhooks": [
|
||||||
|
{ "type": "wecomapp", "corpid": "ww1234abcd", "corpsecret": "env:WECOM_APP_SECRET",
|
||||||
|
"agentid": 1000002, "touser": "你的UserID" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
+44
-4
@@ -27,12 +27,52 @@ async function postJson(url, payload, headers = {}) {
|
|||||||
async function sendWebhook(hook, title, text, extra) {
|
async function sendWebhook(hook, title, text, extra) {
|
||||||
const type = (hook.type || 'custom').toLowerCase();
|
const type = (hook.type || 'custom').toLowerCase();
|
||||||
// url 支持 "env:变量名" —— 密钥不落在配置文件里(Obsidian 库会同步/进 Git)
|
// url 支持 "env:变量名" —— 密钥不落在配置文件里(Obsidian 库会同步/进 Git)
|
||||||
const url = typeof hook.url === 'string' && hook.url.startsWith('env:')
|
const rawUrl = hook.url;
|
||||||
? process.env[hook.url.slice(4)]
|
const url = typeof rawUrl === 'string' && rawUrl.startsWith('env:')
|
||||||
: hook.url;
|
? process.env[rawUrl.slice(4)]
|
||||||
if (!url) throw new Error('webhook.url 为空(或 env: 指定的环境变量未设置)');
|
: rawUrl;
|
||||||
|
const needsUrl = !['wecomapp', 'email'].includes(type);
|
||||||
|
if (needsUrl && !url) throw new Error('webhook.url 为空(或 env: 指定的环境变量未设置)');
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case 'wecomapp': { // 企业微信自建应用:推给自己单聊,需管理员在后台建应用
|
||||||
|
const secret = hook.corpsecret && hook.corpsecret.startsWith('env:')
|
||||||
|
? process.env[hook.corpsecret.slice(4)]
|
||||||
|
: hook.corpsecret;
|
||||||
|
if (!hook.corpid || !secret || !hook.agentid) throw new Error('wecomapp 需要 corpid / corpsecret / agentid');
|
||||||
|
const tr = await fetch(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${encodeURIComponent(hook.corpid)}&corpsecret=${encodeURIComponent(secret)}`, { signal: AbortSignal.timeout(10000) });
|
||||||
|
const tj = await tr.json();
|
||||||
|
if (!tj.access_token) throw new Error(`gettoken 失败: ${tj.errcode} ${tj.errmsg}`);
|
||||||
|
return postJson(`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${tj.access_token}`, {
|
||||||
|
touser: hook.touser || '@all',
|
||||||
|
msgtype: 'text',
|
||||||
|
agentid: Number(hook.agentid),
|
||||||
|
text: { content: `${title}\n${text}` },
|
||||||
|
safe: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'email': { // 邮件:QQ/163 等 SMTP,微信里能收到邮件提醒
|
||||||
|
const pass = hook.passEnv ? process.env[hook.passEnv] : hook.pass;
|
||||||
|
if (!hook.smtp || !hook.from || !hook.to) throw new Error('email 需要 smtp / from / to');
|
||||||
|
if (!pass) throw new Error('email 缺少密码/授权码');
|
||||||
|
const ps1 = path.join(__dirname, 'send-mail.ps1');
|
||||||
|
const args = [
|
||||||
|
'-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ps1,
|
||||||
|
'-Smtp', hook.smtp, '-Port', String(hook.port || 465),
|
||||||
|
'-From', hook.from, '-To', hook.to,
|
||||||
|
'-User', hook.user || hook.from, '-Pass', pass,
|
||||||
|
'-Subject', title, '-Body', text
|
||||||
|
];
|
||||||
|
const code = await new Promise((res, rej) => {
|
||||||
|
try {
|
||||||
|
execFile('powershell', args, { windowsHide: true }, (err) => res(err ? (err.code ?? 1) : 0));
|
||||||
|
} catch (e) { rej(e); }
|
||||||
|
});
|
||||||
|
if (code !== 0) throw new Error(`Send-MailMessage 失败 (exit ${code})`);
|
||||||
|
return { status: 200, text: 'smtp ok' };
|
||||||
|
}
|
||||||
|
|
||||||
case 'feishu': // 飞书自定义机器人
|
case 'feishu': // 飞书自定义机器人
|
||||||
return postJson(url, { msg_type: 'text', content: { text: `${title}\n${text}` } });
|
return postJson(url, { msg_type: 'text', content: { text: `${title}\n${text}` } });
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$Smtp,
|
||||||
|
[int]$Port = 465,
|
||||||
|
[Parameter(Mandatory = $true)][string]$From,
|
||||||
|
[Parameter(Mandatory = $true)][string]$To,
|
||||||
|
[Parameter(Mandatory = $true)][string]$User,
|
||||||
|
[Parameter(Mandatory = $true)][string]$Pass,
|
||||||
|
[Parameter(Mandatory = $true)][string]$Subject,
|
||||||
|
[Parameter(Mandatory = $true)][string]$Body
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$secure = ConvertTo-SecureString $Pass -AsPlainText -Force
|
||||||
|
$cred = New-Object System.Management.Automation.PSCredential($User, $secure)
|
||||||
|
|
||||||
|
Send-MailMessage -SmtpServer $Smtp -Port $Port -UseSsl `
|
||||||
|
-From $From -To $To -Subject $Subject -Body $Body `
|
||||||
|
-Encoding UTF8 -Credential $cred
|
||||||
Reference in new issue
Block a user