@alemonjs/discord 2.1.0 → 2.1.2
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/README.md +5 -0
- package/lib/config.d.ts +1 -0
- package/lib/format.d.ts +4 -0
- package/lib/format.js +78 -0
- package/lib/send.js +92 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,11 @@ discord:
|
|
|
37
37
|
# ws 代理
|
|
38
38
|
websocket_proxy: 'http://localhost:7890'
|
|
39
39
|
# request_proxy: 'http://localhost:7890'
|
|
40
|
+
# 隐藏不支持的消息类型(可选,默认: false)
|
|
41
|
+
# 开启后,转为文本时不可读内容(如 [视频]、[音频]、[图片]、[附件] 等占位符)将被置空
|
|
42
|
+
# 可读内容(如标题、按钮文本、链接等)仍会保留为纯文本
|
|
43
|
+
# 转换后内容为空时,将跳过发送并输出 info 日志
|
|
44
|
+
hideUnsupported: true
|
|
40
45
|
|
|
41
46
|
```
|
|
42
47
|
|
package/lib/config.d.ts
CHANGED
package/lib/format.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DataEnums, DataMarkDown } from 'alemonjs';
|
|
2
|
+
export declare const markdownToDiscordText: (items: DataMarkDown["value"]) => string;
|
|
3
|
+
export declare const markdownRawToDiscordText: (raw: string, hideUnsupported?: boolean) => string;
|
|
4
|
+
export declare const dataEnumToDiscordText: (item: DataEnums, hideUnsupported?: boolean) => string;
|
package/lib/format.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const markdownToDiscordText = (items) => {
|
|
2
|
+
return items
|
|
3
|
+
.map(item => {
|
|
4
|
+
switch (item.type) {
|
|
5
|
+
case 'MD.text':
|
|
6
|
+
return item.value;
|
|
7
|
+
case 'MD.title':
|
|
8
|
+
return `# ${item.value}\n`;
|
|
9
|
+
case 'MD.subtitle':
|
|
10
|
+
return `## ${item.value}\n`;
|
|
11
|
+
case 'MD.bold':
|
|
12
|
+
return `**${item.value}**`;
|
|
13
|
+
case 'MD.italic':
|
|
14
|
+
case 'MD.italicStar':
|
|
15
|
+
return `*${item.value}*`;
|
|
16
|
+
case 'MD.strikethrough':
|
|
17
|
+
return `~~${item.value}~~`;
|
|
18
|
+
case 'MD.link': {
|
|
19
|
+
const v = item.value;
|
|
20
|
+
return `[${v.text}](${v.url})`;
|
|
21
|
+
}
|
|
22
|
+
case 'MD.image':
|
|
23
|
+
return ``;
|
|
24
|
+
case 'MD.list':
|
|
25
|
+
return (item.value
|
|
26
|
+
.map(li => {
|
|
27
|
+
if (typeof li.value === 'object') {
|
|
28
|
+
return `${li.value.index}. ${li.value.text ?? ''}`;
|
|
29
|
+
}
|
|
30
|
+
return `- ${li.value}`;
|
|
31
|
+
})
|
|
32
|
+
.join('\n') + '\n');
|
|
33
|
+
case 'MD.blockquote':
|
|
34
|
+
return `> ${item.value}\n`;
|
|
35
|
+
case 'MD.divider':
|
|
36
|
+
return '---\n';
|
|
37
|
+
case 'MD.newline':
|
|
38
|
+
return '\n';
|
|
39
|
+
case 'MD.code': {
|
|
40
|
+
const lang = item?.options?.language || '';
|
|
41
|
+
return `\`\`\`${lang}\n${item.value}\n\`\`\`\n`;
|
|
42
|
+
}
|
|
43
|
+
case 'MD.mention':
|
|
44
|
+
if (item.value === 'everyone') {
|
|
45
|
+
return '@everyone';
|
|
46
|
+
}
|
|
47
|
+
return `<@${item.value ?? ''}>`;
|
|
48
|
+
case 'MD.content':
|
|
49
|
+
return item.value;
|
|
50
|
+
case 'MD.button':
|
|
51
|
+
return `[${item.value}]`;
|
|
52
|
+
default:
|
|
53
|
+
return String(item?.value ?? '');
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.join('');
|
|
57
|
+
};
|
|
58
|
+
const markdownRawToDiscordText = (raw, hideUnsupported) => {
|
|
59
|
+
let text = raw;
|
|
60
|
+
text = text.replace(/!\[([^\]]*)\]\(([^)]*)\)/g, hideUnsupported ? '' : '[$1]($2)');
|
|
61
|
+
return text;
|
|
62
|
+
};
|
|
63
|
+
const dataEnumToDiscordText = (item, hideUnsupported) => {
|
|
64
|
+
switch (item.type) {
|
|
65
|
+
case 'MarkdownOriginal':
|
|
66
|
+
return markdownRawToDiscordText(String(item.value), hideUnsupported);
|
|
67
|
+
case 'Attachment':
|
|
68
|
+
return hideUnsupported ? '' : `[附件${item.options?.filename ? ': ' + item.options.filename : ''}]`;
|
|
69
|
+
case 'Audio':
|
|
70
|
+
return hideUnsupported ? '' : '[音频]';
|
|
71
|
+
case 'Video':
|
|
72
|
+
return hideUnsupported ? '' : '[视频]';
|
|
73
|
+
default:
|
|
74
|
+
return '';
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export { dataEnumToDiscordText, markdownRawToDiscordText, markdownToDiscordText };
|
package/lib/send.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createResult, ResultCode } from 'alemonjs';
|
|
2
2
|
import { readFileSync } from 'fs';
|
|
3
|
+
import { dataEnumToDiscordText } from './format.js';
|
|
4
|
+
import { getDiscordConfig } from './config.js';
|
|
3
5
|
|
|
4
6
|
const ImageURLToBuffer = async (url) => {
|
|
5
7
|
const arrayBuffer = await fetch(url).then(res => res.arrayBuffer());
|
|
@@ -23,15 +25,88 @@ const createButtonsData = (rows) => {
|
|
|
23
25
|
};
|
|
24
26
|
});
|
|
25
27
|
};
|
|
28
|
+
const buildDiscordMdContent = (mds) => {
|
|
29
|
+
let contentMd = '';
|
|
30
|
+
if (mds && mds.length > 0) {
|
|
31
|
+
mds.forEach(item => {
|
|
32
|
+
if (item.type === 'Markdown') {
|
|
33
|
+
const md = item.value;
|
|
34
|
+
md.forEach(line => {
|
|
35
|
+
if (line.type === 'MD.text') {
|
|
36
|
+
contentMd += line.value;
|
|
37
|
+
}
|
|
38
|
+
else if (line.type === 'MD.blockquote') {
|
|
39
|
+
contentMd += `> ${line.value}\n`;
|
|
40
|
+
}
|
|
41
|
+
else if (line.type === 'MD.bold') {
|
|
42
|
+
contentMd += `**${line.value}**`;
|
|
43
|
+
}
|
|
44
|
+
else if (line.type === 'MD.italic') {
|
|
45
|
+
contentMd += `*${line.value}*`;
|
|
46
|
+
}
|
|
47
|
+
else if (line.type === 'MD.divider') {
|
|
48
|
+
contentMd += '---\n';
|
|
49
|
+
}
|
|
50
|
+
else if (line.type === 'MD.image') {
|
|
51
|
+
contentMd += ``;
|
|
52
|
+
}
|
|
53
|
+
else if (line.type === 'MD.italicStar') {
|
|
54
|
+
contentMd += `*${line.value}*`;
|
|
55
|
+
}
|
|
56
|
+
else if (line.type === 'MD.link') {
|
|
57
|
+
contentMd += `[${line.value.text}](${line.value.url})`;
|
|
58
|
+
}
|
|
59
|
+
else if (line.type === 'MD.list') {
|
|
60
|
+
const listStr = line.value.map(listItem => {
|
|
61
|
+
if (typeof listItem.value === 'object') {
|
|
62
|
+
return `\n${listItem.value.index}. ${listItem.value.text}`;
|
|
63
|
+
}
|
|
64
|
+
return `\n- ${listItem.value}`;
|
|
65
|
+
});
|
|
66
|
+
contentMd += `${listStr.join('')}\n`;
|
|
67
|
+
}
|
|
68
|
+
else if (line.type === 'MD.newline') {
|
|
69
|
+
contentMd += '\n';
|
|
70
|
+
}
|
|
71
|
+
else if (line.type === 'MD.strikethrough') {
|
|
72
|
+
contentMd += `~~${line.value}~~`;
|
|
73
|
+
}
|
|
74
|
+
else if (line.type === 'MD.subtitle') {
|
|
75
|
+
contentMd += `## ${line.value}\n`;
|
|
76
|
+
}
|
|
77
|
+
else if (line.type === 'MD.title') {
|
|
78
|
+
contentMd += `# ${line.value}\n`;
|
|
79
|
+
}
|
|
80
|
+
else if (line.type === 'MD.code') {
|
|
81
|
+
const language = line?.options?.language || '';
|
|
82
|
+
contentMd += `\`\`\`${language}\n${line.value}\n\`\`\`\n`;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const value = line['value'] || '';
|
|
86
|
+
contentMd += String(value);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return contentMd;
|
|
93
|
+
};
|
|
26
94
|
const sendchannel = async (client, param, val) => {
|
|
27
95
|
try {
|
|
28
96
|
if (!val || val.length <= 0) {
|
|
29
97
|
return [];
|
|
30
98
|
}
|
|
31
|
-
const
|
|
99
|
+
const channelId = param?.channel_id ?? '';
|
|
32
100
|
const images = val.filter(item => item.type === 'Image' || item.type === 'ImageURL' || item.type === 'ImageFile');
|
|
33
101
|
const buttons = val.filter(item => item.type === 'BT.group');
|
|
34
102
|
const mds = val.filter(item => item.type === 'Markdown');
|
|
103
|
+
const nativeTypes = new Set(['Image', 'ImageURL', 'ImageFile', 'BT.group', 'Markdown', 'Mention', 'Text', 'Link']);
|
|
104
|
+
const unsupportedItems = val.filter(item => !nativeTypes.has(item.type));
|
|
105
|
+
const hide = getDiscordConfig().hideUnsupported === true;
|
|
106
|
+
const fallbackText = unsupportedItems
|
|
107
|
+
.map(item => dataEnumToDiscordText(item, hide))
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.join('\n');
|
|
35
110
|
const content = val
|
|
36
111
|
.filter(item => item.type === 'Mention' || item.type === 'Text' || item.type === 'Link')
|
|
37
112
|
.map(item => {
|
|
@@ -67,6 +142,12 @@ const sendchannel = async (client, param, val) => {
|
|
|
67
142
|
}
|
|
68
143
|
})
|
|
69
144
|
.join('');
|
|
145
|
+
const contentMd = buildDiscordMdContent(mds);
|
|
146
|
+
const finalContent = [content, contentMd, fallbackText].filter(Boolean).join('\n');
|
|
147
|
+
if (hide && !finalContent && images.length <= 0 && buttons.length <= 0) {
|
|
148
|
+
logger.info('[discord] hideUnsupported: 消息内容转换后为空,跳过发送');
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
70
151
|
if (images.length > 0) {
|
|
71
152
|
let bufferData = null;
|
|
72
153
|
for (let i = 0; i < images.length; i++) {
|
|
@@ -101,74 +182,11 @@ const sendchannel = async (client, param, val) => {
|
|
|
101
182
|
bufferData = readFileSync(item.value);
|
|
102
183
|
}
|
|
103
184
|
}
|
|
104
|
-
const res = await client.channelsMessagesForm(
|
|
105
|
-
content:
|
|
185
|
+
const res = await client.channelsMessagesForm(channelId, {
|
|
186
|
+
content: finalContent
|
|
106
187
|
}, bufferData);
|
|
107
188
|
return [createResult(ResultCode.Ok, '完成', res)];
|
|
108
189
|
}
|
|
109
|
-
let contentMd = '';
|
|
110
|
-
if (mds && mds.length > 0) {
|
|
111
|
-
mds.forEach(item => {
|
|
112
|
-
if (item.type === 'Markdown') {
|
|
113
|
-
const md = item.value;
|
|
114
|
-
md.forEach(line => {
|
|
115
|
-
if (line.type === 'MD.text') {
|
|
116
|
-
contentMd += line.value;
|
|
117
|
-
}
|
|
118
|
-
else if (line.type === 'MD.blockquote') {
|
|
119
|
-
contentMd += `> ${line.value}\n`;
|
|
120
|
-
}
|
|
121
|
-
else if (line.type === 'MD.bold') {
|
|
122
|
-
contentMd += `**${line.value}**`;
|
|
123
|
-
}
|
|
124
|
-
else if (line.type === 'MD.italic') {
|
|
125
|
-
contentMd += `*${line.value}*`;
|
|
126
|
-
}
|
|
127
|
-
else if (line.type === 'MD.divider') {
|
|
128
|
-
contentMd += '---\n';
|
|
129
|
-
}
|
|
130
|
-
else if (line.type === 'MD.image') {
|
|
131
|
-
contentMd += ``;
|
|
132
|
-
}
|
|
133
|
-
else if (line.type === 'MD.italicStar') {
|
|
134
|
-
contentMd += `*${line.value}*`;
|
|
135
|
-
}
|
|
136
|
-
else if (line.type === 'MD.link') {
|
|
137
|
-
contentMd += `[${typeof line.value === 'object' ? line.value.text : line.value}](${typeof line.value === 'object' ? line.value.url : line.value})`;
|
|
138
|
-
}
|
|
139
|
-
else if (line.type === 'MD.list') {
|
|
140
|
-
const listStr = line.value.map(listItem => {
|
|
141
|
-
if (typeof listItem.value === 'object') {
|
|
142
|
-
return `\n${listItem.value.index}. ${listItem.value.text}`;
|
|
143
|
-
}
|
|
144
|
-
return `\n- ${listItem.value}`;
|
|
145
|
-
});
|
|
146
|
-
contentMd += `${listStr.join('')}\n`;
|
|
147
|
-
}
|
|
148
|
-
else if (line.type === 'MD.newline') {
|
|
149
|
-
contentMd += '\n';
|
|
150
|
-
}
|
|
151
|
-
else if (line.type === 'MD.strikethrough') {
|
|
152
|
-
contentMd += `~~${line.value}~~`;
|
|
153
|
-
}
|
|
154
|
-
else if (line.type === 'MD.subtitle') {
|
|
155
|
-
contentMd += `## ${line.value}\n`;
|
|
156
|
-
}
|
|
157
|
-
else if (line.type === 'MD.title') {
|
|
158
|
-
contentMd += `# ${line.value}\n`;
|
|
159
|
-
}
|
|
160
|
-
else if (line.type === 'MD.code') {
|
|
161
|
-
const language = line?.options?.language || '';
|
|
162
|
-
contentMd += `\`\`\`${language}\n${line.value}\n\`\`\`\n`;
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
const value = line['value'] || '';
|
|
166
|
-
contentMd += String(value);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
190
|
if (buttons && buttons.length > 0) {
|
|
173
191
|
let components = null;
|
|
174
192
|
buttons.forEach(item => {
|
|
@@ -176,17 +194,20 @@ const sendchannel = async (client, param, val) => {
|
|
|
176
194
|
return;
|
|
177
195
|
}
|
|
178
196
|
const rows = item.value;
|
|
197
|
+
if (typeof rows === 'string') {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
179
200
|
components = createButtonsData(rows);
|
|
180
201
|
});
|
|
181
|
-
const res = await client.channelsMessages(
|
|
182
|
-
content:
|
|
202
|
+
const res = await client.channelsMessages(channelId, {
|
|
203
|
+
content: finalContent,
|
|
183
204
|
components: components
|
|
184
205
|
});
|
|
185
206
|
return [createResult(ResultCode.Ok, '完成', res)];
|
|
186
207
|
}
|
|
187
|
-
if (
|
|
188
|
-
const res = await client.channelsMessagesForm(
|
|
189
|
-
content:
|
|
208
|
+
if (finalContent) {
|
|
209
|
+
const res = await client.channelsMessagesForm(channelId, {
|
|
210
|
+
content: finalContent
|
|
190
211
|
});
|
|
191
212
|
return [createResult(ResultCode.Ok, '完成', res)];
|
|
192
213
|
}
|