@karinjs/adapter-qqbot 1.2.8 → 1.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/comment/config.json +3 -0
- package/config/config/config.yaml +53 -0
- package/lib/cli/pr.d.ts +2 -0
- package/lib/cli/pr.js +73 -0
- package/lib/core/adapter/adapter.d.ts +91 -0
- package/lib/core/adapter/adapter.js +144 -0
- package/lib/core/adapter/handler.d.ts +49 -0
- package/lib/core/adapter/handler.js +140 -0
- package/lib/core/adapter/markdown.d.ts +38 -0
- package/lib/core/adapter/markdown.js +220 -0
- package/lib/core/adapter/normal.d.ts +30 -0
- package/lib/core/adapter/normal.js +263 -0
- package/lib/core/api/index.d.ts +167 -0
- package/lib/core/api/index.js +180 -0
- package/lib/core/api/sign.d.ts +22 -0
- package/lib/core/api/sign.js +40 -0
- package/lib/core/api/types.d.ts +236 -0
- package/lib/core/event/conver.d.ts +10 -0
- package/lib/core/event/conver.js +57 -0
- package/lib/core/event/index.d.ts +9 -0
- package/lib/core/event/index.js +98 -0
- package/lib/core/event/message.d.ts +27 -0
- package/lib/core/event/message.js +95 -0
- package/lib/core/event/notice.d.ts +50 -0
- package/lib/core/event/notice.js +133 -0
- package/lib/{types/event.d.ts → core/event/types.d.ts} +255 -14
- package/lib/core/internal/axios.d.ts +25 -0
- package/lib/core/internal/axios.js +46 -0
- package/lib/core/internal/sign.d.ts +22 -0
- package/lib/core/internal/sign.js +40 -0
- package/lib/core/webhook/c2c.d.ts +2 -0
- package/lib/core/webhook/c2c.js +14 -0
- package/lib/core/webhook/http.d.ts +2 -0
- package/lib/core/webhook/http.js +35 -0
- package/lib/core/webhook/index.d.ts +17 -0
- package/lib/core/webhook/index.js +87 -0
- package/lib/core/webhook/ws.d.ts +2 -0
- package/lib/core/webhook/ws.js +79 -0
- package/lib/index.d.ts +1 -3
- package/lib/index.js +5 -7
- package/lib/root.d.ts +5 -0
- package/lib/root.js +9 -0
- package/lib/types/config.d.ts +53 -0
- package/lib/utils/common.d.ts +75 -61
- package/lib/utils/common.js +190 -202
- package/lib/utils/config.d.ts +5 -130
- package/lib/utils/config.js +50 -172
- package/lib/utils/dir.d.ts +1 -5
- package/lib/utils/dir.js +1 -10
- package/lib/utils/index.d.ts +4 -3
- package/lib/utils/index.js +4 -3
- package/package.json +41 -23
- package/config/config.yaml +0 -69
- package/lib/core/api.d.ts +0 -166
- package/lib/core/api.js +0 -429
- package/lib/core/index.d.ts +0 -92
- package/lib/core/index.js +0 -343
- package/lib/core/intents.d.ts +0 -6
- package/lib/core/intents.js +0 -57
- package/lib/core/markdown.d.ts +0 -23
- package/lib/core/markdown.js +0 -265
- package/lib/types/index.d.ts +0 -3
- package/lib/types/index.js +0 -3
- package/lib/types/media.d.ts +0 -100
- package/lib/types/message.d.ts +0 -85
- /package/lib/{types/event.js → core/api/types.js} +0 -0
- /package/lib/{types/media.js → core/event/types.js} +0 -0
- /package/lib/types/{message.js → config.js} +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 全局默认配置 以下所有配置均可在账号配置中单独配置
|
|
2
|
+
default:
|
|
3
|
+
# 机器人ID
|
|
4
|
+
appId: string
|
|
5
|
+
# 机器人密钥
|
|
6
|
+
secret: string
|
|
7
|
+
# 正式环境api
|
|
8
|
+
prodApi: https://api.sgroup.qq.com
|
|
9
|
+
# 沙盒api
|
|
10
|
+
sandboxApi: https://sandbox.api.sgroup.qq.com
|
|
11
|
+
# 调用凭证的Api
|
|
12
|
+
tokenApi: https://bots.qq.com/app/getAppAccessToken
|
|
13
|
+
# 是否开启沙盒环境
|
|
14
|
+
sandbox: false
|
|
15
|
+
# 开启QQ场景能力
|
|
16
|
+
qqEnable: true
|
|
17
|
+
# 开启频道场景能力
|
|
18
|
+
guildEnable: true
|
|
19
|
+
# 频道场景模式 0-公域 1-私域
|
|
20
|
+
guildMode: 0
|
|
21
|
+
# 文本中的url转二维码白名单 配置后将不转换这些url为二维码
|
|
22
|
+
exclude: []
|
|
23
|
+
# 接受到消息后对文本进行表达式处理
|
|
24
|
+
regex: [
|
|
25
|
+
{
|
|
26
|
+
# 表达式
|
|
27
|
+
reg: "^#",
|
|
28
|
+
# 替换为
|
|
29
|
+
rep: "",
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
# markdown配置
|
|
33
|
+
markdown:
|
|
34
|
+
# 发送模式 0-关闭MD 1-原生MD 3-旧图文模板MD 4-纯文模板MD 5-自定义处理
|
|
35
|
+
mode: 0
|
|
36
|
+
# 模板ID
|
|
37
|
+
id: ""
|
|
38
|
+
kv:
|
|
39
|
+
- text_start
|
|
40
|
+
- img_dec
|
|
41
|
+
- img_url
|
|
42
|
+
- text_end
|
|
43
|
+
|
|
44
|
+
# 事件接收配置
|
|
45
|
+
event:
|
|
46
|
+
# 接收方式 0-关闭 1-webhook 2-http 3-ws
|
|
47
|
+
type: 0
|
|
48
|
+
# ws服务器地址
|
|
49
|
+
wsUrl: ws://example.com/webhook
|
|
50
|
+
# ws服务器token
|
|
51
|
+
wsToken: your_token
|
|
52
|
+
# http鉴权token
|
|
53
|
+
httpToken: your_token
|
package/lib/cli/pr.d.ts
ADDED
package/lib/cli/pr.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
/**
|
|
4
|
+
* @description 获取package.json路径
|
|
5
|
+
*/
|
|
6
|
+
const getPkgPath = () => process.cwd() + '/package.json';
|
|
7
|
+
/**
|
|
8
|
+
* @description 读取package.json
|
|
9
|
+
*/
|
|
10
|
+
const readPkg = () => JSON.parse(fs.readFileSync(getPkgPath(), 'utf-8'));
|
|
11
|
+
/**
|
|
12
|
+
* @description 写入package.json
|
|
13
|
+
* @param pkg package.json
|
|
14
|
+
*/
|
|
15
|
+
const writePkg = (pkg) => fs.writeFileSync(getPkgPath(), JSON.stringify(pkg, null, 2));
|
|
16
|
+
/**
|
|
17
|
+
* @description 构建pr版本号 <主版本号>.<次版本号>.<修订号>-<预发布标识>.<PR标识>.<PR编号>.<工作流唯一编号>-<时间戳>
|
|
18
|
+
|
|
19
|
+
* @param pkg package.json
|
|
20
|
+
*/
|
|
21
|
+
const updateVersion = (pkg) => {
|
|
22
|
+
const list = pkg.version.split('.');
|
|
23
|
+
// 1.0.0 => 1.0.1-beta.pr.pr编号.工作流唯一编号-时间戳 => 1.0.1-beta.pr.184-1631537630
|
|
24
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
25
|
+
list[2] = `${Number(list[2]) + 1}-beta.pr.${process.env.PR_NUMBER}.${process.env.GITHUB_RUN_ATTEMPT || 1}-${timestamp}`;
|
|
26
|
+
pkg.version = list.join('.');
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* @description 设置环境变量
|
|
30
|
+
* @param pkg package.json
|
|
31
|
+
*/
|
|
32
|
+
const setEnvVariables = (pkg) => {
|
|
33
|
+
fs.appendFileSync(process.env.GITHUB_ENV, `PKG_NAME=${pkg.name}\nPKG_VERSION=${pkg.version}\n`);
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* @description 更新版本号并设置环境变量
|
|
37
|
+
*/
|
|
38
|
+
const version = () => {
|
|
39
|
+
const pkg = readPkg();
|
|
40
|
+
updateVersion(pkg);
|
|
41
|
+
writePkg(pkg);
|
|
42
|
+
setEnvVariables(pkg);
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* @description 删除devDependencies和peerDependencies
|
|
46
|
+
*/
|
|
47
|
+
const clean = () => {
|
|
48
|
+
const pkg = readPkg();
|
|
49
|
+
delete pkg.devDependencies;
|
|
50
|
+
delete pkg.peerDependencies;
|
|
51
|
+
writePkg(pkg);
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* @description 执行所有操作
|
|
55
|
+
*/
|
|
56
|
+
const all = () => {
|
|
57
|
+
const pkg = readPkg();
|
|
58
|
+
updateVersion(pkg);
|
|
59
|
+
delete pkg.devDependencies;
|
|
60
|
+
delete pkg.peerDependencies;
|
|
61
|
+
writePkg(pkg);
|
|
62
|
+
setEnvVariables(pkg);
|
|
63
|
+
};
|
|
64
|
+
const cmd = process.argv[2];
|
|
65
|
+
if (cmd === 'version') {
|
|
66
|
+
version();
|
|
67
|
+
}
|
|
68
|
+
else if (cmd === 'clean') {
|
|
69
|
+
clean();
|
|
70
|
+
}
|
|
71
|
+
else if (cmd === 'all') {
|
|
72
|
+
all();
|
|
73
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import FormData from 'form-data';
|
|
2
|
+
import { QQBotApi } from '@/core/api';
|
|
3
|
+
import { AdapterBase } from 'node-karin';
|
|
4
|
+
import type { SendGuildMsg, SendGuildResponse, SendQQMsg, SendQQMsgResponse } from '@/core/api/types';
|
|
5
|
+
import type { LoggerLevel, ButtonElement, KeyboardElement, MarkdownElement, MarkdownTplElement, SendMsgResults, Contact } from 'node-karin';
|
|
6
|
+
/** 发送函数所需参数 */
|
|
7
|
+
export type Options<T extends 'qq' | 'guild'> = T extends 'qq' ? SendQQMsg : SendGuildMsg | FormData;
|
|
8
|
+
/** QQ发送消息函数类型 */
|
|
9
|
+
export type QQSend = (peer: string, item: SendQQMsg) => Promise<SendQQMsgResponse>;
|
|
10
|
+
/** 频道发送消息函数类型 */
|
|
11
|
+
export type GuildSend = (peer: string, subPeer: string, item: SendGuildMsg | FormData) => Promise<SendGuildResponse>;
|
|
12
|
+
export type Pasmsg<T extends 'qq' | 'guild'> = {
|
|
13
|
+
type: 'msg' | 'event';
|
|
14
|
+
msg_id: string;
|
|
15
|
+
msg_seq: T extends 'qq' ? number : never;
|
|
16
|
+
};
|
|
17
|
+
export interface Grouping<T extends 'qq' | 'guild'> {
|
|
18
|
+
/** 文本 */
|
|
19
|
+
content: string[];
|
|
20
|
+
/** 图片 QQ专属 */
|
|
21
|
+
image: string[];
|
|
22
|
+
/** 单行按钮 */
|
|
23
|
+
button: ButtonElement[];
|
|
24
|
+
/** 多行按钮 */
|
|
25
|
+
keyboard: KeyboardElement[];
|
|
26
|
+
/** markdown */
|
|
27
|
+
markdown: MarkdownElement[];
|
|
28
|
+
/** markdown模板 */
|
|
29
|
+
markdownTpl: MarkdownTplElement[];
|
|
30
|
+
/** 频道专属 图片url */
|
|
31
|
+
imageUrls: string[];
|
|
32
|
+
/** 频道专属 图片file */
|
|
33
|
+
imageFiles: string[];
|
|
34
|
+
/** 引用回复 频道专属 */
|
|
35
|
+
reply: {
|
|
36
|
+
message_id: string;
|
|
37
|
+
};
|
|
38
|
+
/** pasmsg */
|
|
39
|
+
pasmsg: Pasmsg<T>;
|
|
40
|
+
/** 代发送列表 */
|
|
41
|
+
list: Array<Options<T>>;
|
|
42
|
+
/**
|
|
43
|
+
* 处理按钮、markdown
|
|
44
|
+
* 统一格式后推入待发送消息列表
|
|
45
|
+
* @param type 构建类型
|
|
46
|
+
* @param list 分类列表
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
markdownToButton: (type: T, list: Grouping<T>) => void;
|
|
50
|
+
}
|
|
51
|
+
export declare abstract class AdapterQQBot extends AdapterBase {
|
|
52
|
+
super: QQBotApi;
|
|
53
|
+
constructor(QQBot: QQBotApi);
|
|
54
|
+
logger(level: LoggerLevel, ...args: any[]): void;
|
|
55
|
+
/**
|
|
56
|
+
* 被动消息结构
|
|
57
|
+
* @param type 消息类型
|
|
58
|
+
*/
|
|
59
|
+
pasmsg<T extends 'qq' | 'guild'>(type: T): Pasmsg<T>;
|
|
60
|
+
/**
|
|
61
|
+
* 撤回消息
|
|
62
|
+
* @param contact 联系人
|
|
63
|
+
* @param messageId 消息id
|
|
64
|
+
* @returns 撤回结果
|
|
65
|
+
*/
|
|
66
|
+
recallMsg(contact: Contact, messageId: string): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* 初始化消息分类对象
|
|
69
|
+
*/
|
|
70
|
+
initList<T extends 'qq' | 'guild'>(type: T): Grouping<T>;
|
|
71
|
+
/**
|
|
72
|
+
* 初始化发送消息返回值
|
|
73
|
+
*/
|
|
74
|
+
initSendMsgResults(): SendMsgResults;
|
|
75
|
+
/**
|
|
76
|
+
* 处理返回值
|
|
77
|
+
* @param data 返回值
|
|
78
|
+
*/
|
|
79
|
+
handleResponse(data: SendMsgResults): SendMsgResults;
|
|
80
|
+
/**
|
|
81
|
+
* - 处理按钮、markdown
|
|
82
|
+
* - 统一格式后推入待发送消息列表
|
|
83
|
+
* @param type 消息类型
|
|
84
|
+
* @param button 按钮
|
|
85
|
+
* @param keyboard 键盘
|
|
86
|
+
* @param markdown markdown
|
|
87
|
+
* @param markdownTpl markdown模板
|
|
88
|
+
* @returns 消息列表
|
|
89
|
+
*/
|
|
90
|
+
markdownToButton<T extends 'qq' | 'guild'>(type: T, list: Grouping<T>): void;
|
|
91
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { random } from '@/utils/common';
|
|
2
|
+
import { AdapterBase, logger, karinToQQBot } from 'node-karin';
|
|
3
|
+
export class AdapterQQBot extends AdapterBase {
|
|
4
|
+
super;
|
|
5
|
+
constructor(QQBot) {
|
|
6
|
+
super();
|
|
7
|
+
this.super = QQBot;
|
|
8
|
+
this.adapter.name = '@karinjs/qqbot';
|
|
9
|
+
this.adapter.protocol = 'qqbot';
|
|
10
|
+
this.adapter.platform = 'qq';
|
|
11
|
+
this.adapter.standard = 'other';
|
|
12
|
+
}
|
|
13
|
+
logger(level, ...args) {
|
|
14
|
+
logger.bot(level, this.selfId, ...args);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 被动消息结构
|
|
18
|
+
* @param type 消息类型
|
|
19
|
+
*/
|
|
20
|
+
pasmsg(type) {
|
|
21
|
+
if (type === 'qq') {
|
|
22
|
+
return { type: 'msg', msg_id: '', msg_seq: random(1, 9999999) };
|
|
23
|
+
}
|
|
24
|
+
return { type: 'msg', msg_id: '' };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 撤回消息
|
|
28
|
+
* @param contact 联系人
|
|
29
|
+
* @param messageId 消息id
|
|
30
|
+
* @returns 撤回结果
|
|
31
|
+
*/
|
|
32
|
+
async recallMsg(contact, messageId) {
|
|
33
|
+
try {
|
|
34
|
+
if (contact.scene === 'friend') {
|
|
35
|
+
await this.super.recallMsg('user', contact.peer, messageId);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (contact.scene === 'group') {
|
|
39
|
+
await this.super.recallMsg('group', contact.peer, messageId);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (contact.scene === 'direct') {
|
|
43
|
+
await this.super.recallMsg('dms', contact.peer, messageId);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (contact.scene === 'guild') {
|
|
47
|
+
await this.super.recallMsg('channels', contact.peer, messageId);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 初始化消息分类对象
|
|
58
|
+
*/
|
|
59
|
+
initList(type) {
|
|
60
|
+
const list = {
|
|
61
|
+
content: [],
|
|
62
|
+
image: [],
|
|
63
|
+
button: [],
|
|
64
|
+
keyboard: [],
|
|
65
|
+
markdown: [],
|
|
66
|
+
markdownTpl: [],
|
|
67
|
+
imageUrls: [],
|
|
68
|
+
imageFiles: [],
|
|
69
|
+
reply: { message_id: '' },
|
|
70
|
+
pasmsg: this.pasmsg(type),
|
|
71
|
+
list: [],
|
|
72
|
+
markdownToButton: (type, list) => this.markdownToButton(type, list)
|
|
73
|
+
};
|
|
74
|
+
return list;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 初始化发送消息返回值
|
|
78
|
+
*/
|
|
79
|
+
initSendMsgResults() {
|
|
80
|
+
return {
|
|
81
|
+
messageId: '',
|
|
82
|
+
message_id: '',
|
|
83
|
+
time: 0,
|
|
84
|
+
messageTime: 0,
|
|
85
|
+
rawData: []
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 处理返回值
|
|
90
|
+
* @param data 返回值
|
|
91
|
+
*/
|
|
92
|
+
handleResponse(data) {
|
|
93
|
+
const { id, timestamp } = data.rawData[0];
|
|
94
|
+
data.messageId = id;
|
|
95
|
+
data.message_id = id;
|
|
96
|
+
data.messageTime = timestamp;
|
|
97
|
+
data.messageTime = typeof timestamp === 'string' ? new Date(timestamp).getTime() : timestamp;
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* - 处理按钮、markdown
|
|
102
|
+
* - 统一格式后推入待发送消息列表
|
|
103
|
+
* @param type 消息类型
|
|
104
|
+
* @param button 按钮
|
|
105
|
+
* @param keyboard 键盘
|
|
106
|
+
* @param markdown markdown
|
|
107
|
+
* @param markdownTpl markdown模板
|
|
108
|
+
* @returns 消息列表
|
|
109
|
+
*/
|
|
110
|
+
markdownToButton(type, list) {
|
|
111
|
+
/** 统一按钮 */
|
|
112
|
+
const rows = [];
|
|
113
|
+
if (list.button.length) {
|
|
114
|
+
list.button.forEach((v) => {
|
|
115
|
+
rows.push(...karinToQQBot(v));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (list.keyboard.length) {
|
|
119
|
+
list.keyboard.forEach((v) => {
|
|
120
|
+
rows.push(...karinToQQBot(v));
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
list.markdown.forEach((v) => {
|
|
124
|
+
const item = type === 'guild' ? this.super.GuildMsgOptions('markdown', { content: v.markdown }) : this.super.QQdMsgOptions('markdown', { content: v.markdown });
|
|
125
|
+
if (rows.length)
|
|
126
|
+
item.keyboard = { content: { rows } };
|
|
127
|
+
list.list.push(item);
|
|
128
|
+
});
|
|
129
|
+
list.markdownTpl.forEach((v) => {
|
|
130
|
+
const item = type === 'guild'
|
|
131
|
+
? this.super.GuildMsgOptions('markdown', {
|
|
132
|
+
custom_template_id: v.templateId,
|
|
133
|
+
params: v.params
|
|
134
|
+
})
|
|
135
|
+
: this.super.QQdMsgOptions('markdown', {
|
|
136
|
+
custom_template_id: v.templateId,
|
|
137
|
+
params: v.params
|
|
138
|
+
});
|
|
139
|
+
if (rows.length)
|
|
140
|
+
item.keyboard = { content: { rows } };
|
|
141
|
+
list.list.push(item);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Contact, SendMsgResults } from 'node-karin';
|
|
2
|
+
import type { QQSend, Grouping, Options, GuildSend } from '@/core/adapter/adapter';
|
|
3
|
+
import { AdapterQQBotMarkdown } from '@/core/adapter/markdown';
|
|
4
|
+
export interface RawMarkdown {
|
|
5
|
+
/**
|
|
6
|
+
* 频道场景原生Markdown
|
|
7
|
+
* @param type 场景类型
|
|
8
|
+
* @param ctx 适配器实例
|
|
9
|
+
* @param list 分类列表
|
|
10
|
+
* @param contact 发送目标
|
|
11
|
+
* @param pasmsg 将消息转为被动消息 主动事件无法使用
|
|
12
|
+
* @param send 发送消息函数
|
|
13
|
+
*/
|
|
14
|
+
(type: 'guild', ctx: AdapterQQBotMarkdown, list: Grouping<'guild'>, contact: Contact<'guild' | 'direct'>, pasmsg: (item: Options<'guild'>) => void, send: GuildSend): Promise<SendMsgResults>;
|
|
15
|
+
/**
|
|
16
|
+
* QQ场景原生Markdown
|
|
17
|
+
* @param type 场景类型
|
|
18
|
+
* @param ctx 适配器实例
|
|
19
|
+
* @param list 分类列表
|
|
20
|
+
* @param contact 发送目标
|
|
21
|
+
* @param pasmsg 将消息转为被动消息 主动事件无法使用
|
|
22
|
+
* @param send 发送消息函数
|
|
23
|
+
*/
|
|
24
|
+
(type: 'qq', ctx: AdapterQQBotMarkdown, list: Grouping<'qq'>, contact: Contact<'friend' | 'group'>, pasmsg: (item: Options<'qq'>) => void, send: QQSend): Promise<SendMsgResults>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 原生Markdown
|
|
28
|
+
* @param ctx 适配器实例
|
|
29
|
+
* @param list 分类列表
|
|
30
|
+
* @param contact 发送目标
|
|
31
|
+
* @param pasmsg 将消息转为被动消息 主动事件无法使用
|
|
32
|
+
* @param send 发送函数
|
|
33
|
+
*/
|
|
34
|
+
export declare const rawMarkdown: RawMarkdown;
|
|
35
|
+
/**
|
|
36
|
+
* 图文模板
|
|
37
|
+
* @param ctx 适配器实例
|
|
38
|
+
* @param list 分类列表
|
|
39
|
+
* @param contact 发送目标
|
|
40
|
+
* @param pasmsg 将消息转为被动消息 主动事件无法使用
|
|
41
|
+
* @param send 发送函数
|
|
42
|
+
*/
|
|
43
|
+
export declare const GraphicTemplateMarkdown: RawMarkdown;
|
|
44
|
+
/**
|
|
45
|
+
* 纯文模板
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* 自定义处理
|
|
49
|
+
*/
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { escapeMarkdown, getImageSize } from '@/utils/common';
|
|
2
|
+
import { common, fileToUrl, segment } from 'node-karin';
|
|
3
|
+
/**
|
|
4
|
+
* 原生Markdown
|
|
5
|
+
* @param ctx 适配器实例
|
|
6
|
+
* @param list 分类列表
|
|
7
|
+
* @param contact 发送目标
|
|
8
|
+
* @param pasmsg 将消息转为被动消息 主动事件无法使用
|
|
9
|
+
* @param send 发送函数
|
|
10
|
+
*/
|
|
11
|
+
export const rawMarkdown = async (type, ctx, list, contact, pasmsg, send) => {
|
|
12
|
+
await Promise.all(list.image.map(async (file) => {
|
|
13
|
+
if (file.startsWith('http')) {
|
|
14
|
+
const { width, height } = await getImageSize(file);
|
|
15
|
+
list.content.push(``);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const { url, width, height } = await fileToUrl('image', file, 'image.jpg');
|
|
19
|
+
list.content.push(``);
|
|
20
|
+
}));
|
|
21
|
+
/** 将文本转为markdown */
|
|
22
|
+
list.markdown.push(segment.markdown(list.content.join('')));
|
|
23
|
+
/** 处理Markdown、按钮 */
|
|
24
|
+
list.markdownToButton(type, list);
|
|
25
|
+
/** 返回值 */
|
|
26
|
+
const rawData = ctx.initSendMsgResults();
|
|
27
|
+
if (type === 'qq') {
|
|
28
|
+
if (!list.list.length) {
|
|
29
|
+
const options = ctx.super.QQdMsgOptions('text', '不支持发送的消息类型');
|
|
30
|
+
list.list.push(options);
|
|
31
|
+
}
|
|
32
|
+
for (const item of list.list) {
|
|
33
|
+
pasmsg(item);
|
|
34
|
+
const res = await send(contact.peer, item);
|
|
35
|
+
rawData.rawData.push(res);
|
|
36
|
+
}
|
|
37
|
+
return ctx.handleResponse(rawData);
|
|
38
|
+
}
|
|
39
|
+
if (!list.list.length) {
|
|
40
|
+
const options = ctx.super.GuildMsgOptions('text', '不支持发送的消息类型');
|
|
41
|
+
list.list.push(options);
|
|
42
|
+
}
|
|
43
|
+
for (const item of list.list) {
|
|
44
|
+
pasmsg(item);
|
|
45
|
+
const res = await send(contact.peer, contact.subPeer, item);
|
|
46
|
+
rawData.rawData.push(res);
|
|
47
|
+
}
|
|
48
|
+
return ctx.handleResponse(rawData);
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* 图文模板
|
|
52
|
+
* @param ctx 适配器实例
|
|
53
|
+
* @param list 分类列表
|
|
54
|
+
* @param contact 发送目标
|
|
55
|
+
* @param pasmsg 将消息转为被动消息 主动事件无法使用
|
|
56
|
+
* @param send 发送函数
|
|
57
|
+
*/
|
|
58
|
+
export const GraphicTemplateMarkdown = async (type, ctx, list, contact, pasmsg, send) => {
|
|
59
|
+
/**
|
|
60
|
+
* 构建模板键值对
|
|
61
|
+
* @param index 索引
|
|
62
|
+
* @param value 值
|
|
63
|
+
*/
|
|
64
|
+
const KV = (index, value) => {
|
|
65
|
+
return { key: kv[index], values: [value] };
|
|
66
|
+
};
|
|
67
|
+
/** 构建模板 */
|
|
68
|
+
const tpl = (content, desc, url) => {
|
|
69
|
+
if (desc && url) {
|
|
70
|
+
return segment.markdownTpl(id, [KV(0, content), KV(1, desc), KV(2, url)]);
|
|
71
|
+
}
|
|
72
|
+
if (desc) {
|
|
73
|
+
return segment.markdownTpl(id, [KV(1, content), KV(2, desc)]);
|
|
74
|
+
}
|
|
75
|
+
return segment.markdownTpl(id, [KV(0, content)]);
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* 图片转换
|
|
79
|
+
* @param file 图片文件
|
|
80
|
+
* @returns 图片链接 | 图片宽度 | 图片高度
|
|
81
|
+
*/
|
|
82
|
+
const imageHandler = async (file) => {
|
|
83
|
+
if (file.startsWith('http')) {
|
|
84
|
+
const { width, height } = await getImageSize(file);
|
|
85
|
+
return { url: file, width, height };
|
|
86
|
+
}
|
|
87
|
+
const data = await fileToUrl('image', file, 'image.jpg');
|
|
88
|
+
return data;
|
|
89
|
+
};
|
|
90
|
+
const { kv, id } = ctx._config.markdown;
|
|
91
|
+
/** 文本内容 */
|
|
92
|
+
const content = escapeMarkdown(list.content.join(''));
|
|
93
|
+
/** 处理第一张图片 一段文本可以跟一个图片 */
|
|
94
|
+
const img = list.image.shift();
|
|
95
|
+
if (img) {
|
|
96
|
+
const { url, width, height } = await imageHandler(img);
|
|
97
|
+
list.markdownTpl.push(tpl(content, `karin #${width}px #${height}px`, url));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
list.markdownTpl.push(tpl(content));
|
|
101
|
+
}
|
|
102
|
+
/** 处理剩下的图片 单独发送 */
|
|
103
|
+
await Promise.all(list.image.map(async (file, index) => {
|
|
104
|
+
await common.sleep(index * 100); // 简单的睡眠 防止乱序
|
|
105
|
+
const { url, width, height } = await imageHandler(file);
|
|
106
|
+
list.markdownTpl.push(tpl(`karin #${width}px #${height}px`, url));
|
|
107
|
+
}));
|
|
108
|
+
/** 处理Markdown、按钮 */
|
|
109
|
+
list.markdownToButton(type, list);
|
|
110
|
+
/** 返回值 */
|
|
111
|
+
const rawData = ctx.initSendMsgResults();
|
|
112
|
+
if (type === 'qq') {
|
|
113
|
+
if (!list.list.length) {
|
|
114
|
+
const options = ctx.super.QQdMsgOptions('text', '不支持发送的消息类型');
|
|
115
|
+
list.list.push(options);
|
|
116
|
+
}
|
|
117
|
+
for (const item of list.list) {
|
|
118
|
+
pasmsg(item);
|
|
119
|
+
const res = await send(contact.peer, item);
|
|
120
|
+
rawData.rawData.push(res);
|
|
121
|
+
}
|
|
122
|
+
return ctx.handleResponse(rawData);
|
|
123
|
+
}
|
|
124
|
+
if (!list.list.length) {
|
|
125
|
+
const options = ctx.super.GuildMsgOptions('text', '不支持发送的消息类型');
|
|
126
|
+
list.list.push(options);
|
|
127
|
+
}
|
|
128
|
+
for (const item of list.list) {
|
|
129
|
+
pasmsg(item);
|
|
130
|
+
const res = await send(contact.peer, contact.subPeer, item);
|
|
131
|
+
rawData.rawData.push(res);
|
|
132
|
+
}
|
|
133
|
+
return ctx.handleResponse(rawData);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* 纯文模板
|
|
137
|
+
*/
|
|
138
|
+
/**
|
|
139
|
+
* 自定义处理
|
|
140
|
+
*/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AdapterQQBot } from '@/core/adapter/adapter';
|
|
2
|
+
import type { QQBotApi } from '@/core/api';
|
|
3
|
+
import type { Contact, ElementTypes, Message, SendMsgResults } from 'node-karin';
|
|
4
|
+
import type { RawMarkdown } from '@/core/adapter/handler';
|
|
5
|
+
import type { Config } from '@/types/config';
|
|
6
|
+
type Cfg = Config[string];
|
|
7
|
+
/** markdown */
|
|
8
|
+
export declare class AdapterQQBotMarkdown extends AdapterQQBot {
|
|
9
|
+
_config: Cfg;
|
|
10
|
+
markdown: RawMarkdown;
|
|
11
|
+
constructor(QQBot: QQBotApi, markdown: RawMarkdown, config: Cfg);
|
|
12
|
+
srcReply(e: Message, elements: ElementTypes[]): Promise<SendMsgResults>;
|
|
13
|
+
sendMsg(contact: Contact, elements: Array<ElementTypes>, retryCount?: number): Promise<SendMsgResults>;
|
|
14
|
+
/**
|
|
15
|
+
* 处理文本 将文本中的链接转为二维码
|
|
16
|
+
* @param text 文本
|
|
17
|
+
* @returns 处理后的文本和二维码 二维码为不带`base64://`的字符串
|
|
18
|
+
*/
|
|
19
|
+
hendleText(text: string): Promise<{
|
|
20
|
+
text: string;
|
|
21
|
+
qr: string | null;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* 发送QQ私聊、群聊消息
|
|
25
|
+
* @param contact 联系人
|
|
26
|
+
* @param elements 消息元素
|
|
27
|
+
* @param retryCount 重试次数
|
|
28
|
+
*/
|
|
29
|
+
sendQQMsg(contact: Contact<'friend'> | Contact<'group'>, elements: Array<ElementTypes>, retryCount?: number): Promise<SendMsgResults>;
|
|
30
|
+
/**
|
|
31
|
+
* 发送频道消息
|
|
32
|
+
* @param contact 联系人
|
|
33
|
+
* @param elements 消息元素
|
|
34
|
+
* @param retryCount 重试次数
|
|
35
|
+
*/
|
|
36
|
+
sendGuildMsg(contact: Contact<'guild' | 'direct'>, elements: Array<ElementTypes>, retryCount?: number): Promise<SendMsgResults>;
|
|
37
|
+
}
|
|
38
|
+
export {};
|