Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
],
'no-console': 'off',
'no-unused-vars': 'off',
'no-param-reassign': 'off',
},
settings: {
'import/resolver': {
Expand Down
49 changes: 47 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Twikoo 评论系统对不同的消息推送平台做了大量的适配工作,

## 支持的消息推送平台

- Webhook
- [Qmsg](https://qmsg.zendee.cn/)
- [Server 酱](https://sct.ftqq.com/r/13235)
- [Push Plus](https://www.pushplus.plus/)
Expand All @@ -39,7 +40,6 @@ Twikoo 评论系统对不同的消息推送平台做了大量的适配工作,

- 阿里云短信
- 腾讯云短信
- 自定义 Webhook

## 使用方法

Expand Down Expand Up @@ -71,14 +71,27 @@ console.log(result);

| 参数 | 必填 | 默认 | 说明 |
| ---- | ---- | ---- | ---- |
| 平台名称 | ✅ | 无 | 字符串,平台名称的缩写,支持:`qmsg`、`serverchan`、`pushplus`、`pushplushxtrip`、`dingtalk`、`wecom`、`bark`、`gocqhttp`、`atri`、`pushdeer`、`igot`、`telegram`、`feishu`、`ifttt`、`wecombot`、`discord`, `wxpusher` |
| 平台名称 | ✅ | 无 | 字符串,平台名称的缩写,支持:`webhook`、`qmsg`、`serverchan`、`pushplus`、`pushplushxtrip`、`dingtalk`、`wecom`、`bark`、`gocqhttp`、`atri`、`pushdeer`、`igot`、`telegram`、`feishu`、`ifttt`、`wecombot`、`discord`, `wxpusher` |
| token | ✅ | 无 | 平台用户身份标识,通常情况下是一串数字和字母组合,详情和示例见下方详细说明 |
| title | | 内容第一行 | 可选,消息标题,如果推送平台不支持消息标题,则会拼接在正文首行 |
| content | ✅ | 无 | Markdown 格式的推送内容,如果推送平台不支持 Markdown,pushoo 会自动转换成支持的格式 |
| options | ❌ | 无 | 用于推送时的一些额外配置。类型`NoticeOptions` |

```typescript
interface NoticeOptions {
/**
* webhook通知方式的参数配置
*/
webhook?: {
/**
* url 发送通知的地址
*/
url: string;
/**
* method 请求方法,默认为 POST
*/
method?: 'GET' | 'POST';
};
/**
* bark通知方式的参数配置
*/
Expand Down Expand Up @@ -122,6 +135,38 @@ interface NoticeOptions {

## 详细说明

### 💬 Webhook <sub>缩写: `webhook`</sub>

Webhook 是一种用户定义的 HTTP 回调,通常用于将实时数据推送到指定的 URL。pushoo 可以通过 Webhook 方式将消息推送到你自定义的后端。

示例调用:

```js
let respond = await pushoo('webhook', {
token: '', // 可选,暂不支持签名
title: '', // 可选
content: '推送内容',
options: {
webhook: {
url: 'https://example.com/webhook-endpoint',
method: 'POST' // 可选,默认为 POST,也可以设置为 GET
}
}
});
```

特别地,为兼容 Twikoo 中现有的使用方式,可以直接把平台名称设置为 Webhook 的 URL 地址(以 `http://` 或 `https://` 开头),无需传入 `options`。

```js
let respond = await pushoo('https://example.com/webhook-endpoint', {
token: '', // 可选
title: '', // 可选
content: '推送内容'
});
```

此时如果 URL 的末尾为 `:GET` 则使用 GET 方法发送请求(实际 URL 自动去掉 `:GET`),否则默认使用 POST 方法发送请求。

### 💬 [Qmsg](https://qmsg.zendee.cn/) <sub>缩写: `qmsg`</sub>

Qmsg 酱是 Zendee 提供的第三方 QQ 消息推送服务,免费,消息以 QQ 消息的形式推送,支持私聊推送和群推送。请注意,为避免 Qmsg 酱被 Tencent 冻结,pushoo 会自动删除消息中的网址和 IP 地址。
Expand Down
57 changes: 56 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import { marked } from 'marked';
import markdownToTxt from 'markdown-to-txt';

export interface NoticeOptions {
/**
* Webhook通知方式的参数配置
*/
webhook?: {
/**
* url 发送通知的地址
*/
url: string;
/**
* method 请求方法,默认为 POST
*/
method?: 'GET' | 'POST';
};
/**
* bark通知方式的参数配置
*/
Expand Down Expand Up @@ -77,6 +90,7 @@ export interface CommonOptions {
}

export type ChannelType =
| 'webhook'
| 'qmsg'
| 'serverchan'
| 'serverchain'
Expand Down Expand Up @@ -129,6 +143,37 @@ function removeUrlAndIp(content: string) {
.replace(mailRegExp, '');
}

/**
* 自定义 Webhook 推送
*/
async function noticeWebhook(options: CommonOptions) {
checkParameters(options, ['content']);
const method = options?.options?.webhook?.method || 'POST';
const url = options?.options?.webhook?.url;
if (!url) {
throw new Error('Webhook url is required');
}
if (method === 'GET') {
const params = new URLSearchParams({
...(options.token ? { token: options.token } : {}),
...(options.title ? { title: options.title } : {}),
content: options.content,
});
const response = await axios.get(url, { params });
return response.data;
}
if (method === 'POST') {
const payload: Record<string, any> = {
...(options.token && { token: options.token }),
...(options.title && { title: options.title }),
content: options.content,
};
const response = await axios.post(url, payload);
return response.data;
}
throw new Error(`Unsupported Webhook request method: ${method}`);
}

/**
* https://qmsg.zendee.cn/
*/
Expand Down Expand Up @@ -646,10 +691,11 @@ async function noticeJoin(options: CommonOptions) {
return response.data;
}

async function notice(channel: ChannelType, options: CommonOptions) {
async function notice(channel: ChannelType | string, options: CommonOptions) {
try {
let data: any;
const noticeFn = {
webhook: noticeWebhook,
qmsg: noticeQmsg,
serverchan: noticeServerChan,
serverchain: noticeServerChan,
Expand All @@ -673,6 +719,15 @@ async function notice(channel: ChannelType, options: CommonOptions) {
}[channel.toLowerCase()];
if (noticeFn) {
data = await noticeFn(options);
} else if (typeof channel === 'string' && (channel.startsWith('http://') || channel.startsWith('https://'))) {
options.options = options.options || {};
options.options.webhook = { url: channel };
if (channel.endsWith(':GET')) {
// hack: 如果 URL 以 :GET 结尾,则使用 GET 方法
options.options.webhook.method = 'GET';
options.options.webhook.url = channel.slice(0, -4);
}
data = await noticeWebhook(options);
} else {
throw new Error(`<${channel}> is not supported`);
}
Expand Down