@alemonjs/qq-bot 2.1.0 → 2.1.1

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 CHANGED
@@ -44,4 +44,6 @@ qq-bot:
44
44
  # 4) 域名代理模式
45
45
  # base_url_gateway: https://[your addr]
46
46
  # base_url_app_access_token: https://[your addr]
47
+ # 启动md强制转换为text,特别是当没有md权限,但使用了md数据格式时
48
+ markdownToText: true
47
49
  ```
package/lib/config.d.ts CHANGED
@@ -3,6 +3,7 @@ export declare const platform = "qq-bot";
3
3
  export type Options = {
4
4
  master_key?: string[];
5
5
  master_id?: string[];
6
+ markdownToText?: boolean;
6
7
  } & sdkOptions;
7
8
  export declare const getQQBotConfig: () => Options;
8
9
  export declare const getMaster: (UserId: string) => readonly [boolean, string];
@@ -0,0 +1,5 @@
1
+ import type { DataEnums, DataMarkDown } from 'alemonjs';
2
+ export declare const markdownToText: (items: DataMarkDown["value"]) => string;
3
+ export declare const buttonsToText: (rows: any[]) => string;
4
+ export declare const markdownRawToText: (raw: string) => string;
5
+ export declare const dataEnumToText: (item: DataEnums) => string;
package/lib/format.js ADDED
@@ -0,0 +1,94 @@
1
+ const markdownToText = (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
+ case 'MD.italic':
13
+ case 'MD.italicStar':
14
+ case 'MD.strikethrough':
15
+ return item.value;
16
+ case 'MD.link': {
17
+ const v = item.value;
18
+ return `${v.text}( ${v.url} )`;
19
+ }
20
+ case 'MD.image':
21
+ return '[图片]';
22
+ case 'MD.list':
23
+ return (item.value
24
+ .map(li => {
25
+ if (typeof li.value === 'object') {
26
+ return `${li.value.index}. ${li.value.text ?? ''}`;
27
+ }
28
+ return `· ${li.value}`;
29
+ })
30
+ .join('\n') + '\n');
31
+ case 'MD.blockquote':
32
+ return `> ${item.value}\n`;
33
+ case 'MD.divider':
34
+ return '————————\n';
35
+ case 'MD.newline':
36
+ return '\n';
37
+ case 'MD.code':
38
+ return item.value;
39
+ case 'MD.mention':
40
+ if (item.value === 'everyone') {
41
+ return '@全体成员';
42
+ }
43
+ return `@${item.value ?? ''}`;
44
+ case 'MD.content':
45
+ return item.value;
46
+ case 'MD.button':
47
+ return `[${item.value}]`;
48
+ default:
49
+ return String(item?.value ?? '');
50
+ }
51
+ })
52
+ .join('');
53
+ };
54
+ const buttonsToText = (rows) => {
55
+ return rows
56
+ .map((row) => row.value.map((btn) => `[${btn.value}]`).join(' '))
57
+ .join('\n');
58
+ };
59
+ const markdownRawToText = (raw) => {
60
+ let text = raw;
61
+ text = text.replace(/!\[([^\]]*)\]\([^)]*\)/g, '[图片]');
62
+ text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1');
63
+ text = text.replace(/^#{1,6}\s+/gm, '');
64
+ text = text.replace(/(\*{3}|_{3})([^*_]+)\1/g, '$2');
65
+ text = text.replace(/(\*{2}|_{2})([^*_]+)\1/g, '$2');
66
+ text = text.replace(/(?<!\*)\*(?!\*)([^*]+)(?<!\*)\*(?!\*)/g, '$1');
67
+ text = text.replace(/(?<!_)_(?!_)([^_]+)(?<!_)_(?!_)/g, '$1');
68
+ text = text.replace(/~~([^~]+)~~/g, '$1');
69
+ text = text.replace(/`([^`]+)`/g, '$1');
70
+ text = text.replace(/```[\s\S]*?```/g, match => {
71
+ return match.replace(/```\w*\n?/g, '').trim();
72
+ });
73
+ text = text.replace(/^>\s+/gm, '');
74
+ text = text.replace(/^[-*_]{3,}\s*$/gm, '————————');
75
+ text = text.replace(/^[\s]*[-*+]\s+/gm, '· ');
76
+ text = text.replace(/^[\s]*(\d+)\.\s+/gm, '$1. ');
77
+ return text.trim();
78
+ };
79
+ const dataEnumToText = (item) => {
80
+ switch (item.type) {
81
+ case 'MarkdownOriginal':
82
+ return markdownRawToText(String(item.value));
83
+ case 'Attachment':
84
+ return `[附件${item.options?.filename ? ': ' + item.options.filename : ''}]`;
85
+ case 'Audio':
86
+ return '[音频]';
87
+ case 'Video':
88
+ return '[视频]';
89
+ default:
90
+ return '';
91
+ }
92
+ };
93
+
94
+ export { buttonsToText, dataEnumToText, markdownRawToText, markdownToText };
package/lib/sends.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { createResult, ResultCode } from 'alemonjs';
3
3
  import axios from 'axios';
4
+ import { dataEnumToText, markdownToText, buttonsToText } from './format.js';
5
+ import { getQQBotConfig } from './config.js';
4
6
 
5
7
  const MAX_BUTTON_ROWS = 5;
6
8
  const MAX_BUTTONS_PER_ROW = 5;
@@ -162,7 +164,13 @@ const formatMention = (item, mode) => {
162
164
  return '';
163
165
  };
164
166
  const extractContent = (val, mode) => {
165
- return val
167
+ const nativeTypes = new Set([
168
+ 'Mention', 'Text', 'Link',
169
+ 'Image', 'ImageFile', 'ImageURL',
170
+ 'Markdown', 'BT.group', 'ButtonTemplate',
171
+ 'Ark.list', 'Ark.Card', 'Ark.BigCard'
172
+ ]);
173
+ const nativeText = val
166
174
  .filter(item => item.type === 'Mention' || item.type === 'Text' || item.type === 'Link')
167
175
  .map(item => {
168
176
  if (item.type === 'Link') {
@@ -177,6 +185,12 @@ const extractContent = (val, mode) => {
177
185
  return '';
178
186
  })
179
187
  .join('');
188
+ const fallbackText = val
189
+ .filter(item => !nativeTypes.has(item.type))
190
+ .map(item => dataEnumToText(item))
191
+ .filter(Boolean)
192
+ .join('\n');
193
+ return [nativeText, fallbackText].filter(Boolean).join('\n');
180
194
  };
181
195
  const buildBaseParams = (tag, messageId, interactionTag) => {
182
196
  if (tag === interactionTag) {
@@ -288,23 +302,53 @@ const resolveRichMediaUrl = async (images, uploadMedia) => {
288
302
  }
289
303
  return undefined;
290
304
  };
305
+ const flattenMdToText = (content, val) => {
306
+ const mdItems = val.filter(item => item.type === 'Markdown');
307
+ const btnItems = val.filter(item => item.type === 'BT.group');
308
+ const parts = [content];
309
+ for (const item of mdItems) {
310
+ if (item.type === 'Markdown' && typeof item.value !== 'string') {
311
+ parts.push(markdownToText(item.value));
312
+ }
313
+ }
314
+ for (const item of btnItems) {
315
+ if (item.type === 'BT.group' && typeof item.value !== 'string') {
316
+ parts.push(buttonsToText(item.value));
317
+ }
318
+ }
319
+ return parts.filter(Boolean).join('\n');
320
+ };
291
321
  const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMessage, label) => {
322
+ const config = getQQBotConfig();
323
+ const mdToText = config.markdownToText === true;
292
324
  const images = filterImages(val);
293
325
  if (images.length > 0) {
294
326
  const url = await resolveRichMediaUrl(images, uploadMedia);
295
327
  if (!url) {
296
328
  return [createResult(ResultCode.Fail, '图片上传失败', null)];
297
329
  }
330
+ const imgContent = flattenMdToText(content, val);
298
331
  const res = await sendMessage({
299
- content,
332
+ content: imgContent,
300
333
  media: { file_info: url },
301
334
  msg_type: 7,
302
335
  ...baseParams
303
336
  });
304
337
  return [createResult(ResultCode.Ok, label, { id: res.id })];
305
338
  }
339
+ if (mdToText) {
340
+ const textContent = flattenMdToText(content, val);
341
+ if (textContent) {
342
+ const res = await sendMessage({ content: textContent, msg_type: 0, ...baseParams });
343
+ return [createResult(ResultCode.Ok, label, { id: res.id })];
344
+ }
345
+ return [];
346
+ }
306
347
  const mdParams = buildMdAndButtonsParams(val);
307
348
  if (mdParams) {
349
+ if (mdParams.markdown?.content && content) {
350
+ mdParams.markdown.content = content + '\n' + mdParams.markdown.content;
351
+ }
308
352
  const res = await sendMessage({ content, msg_type: 2, ...mdParams, ...baseParams });
309
353
  return [createResult(ResultCode.Ok, label, { id: res.id })];
310
354
  }
@@ -346,14 +390,28 @@ const resolveImageBuffer = async (images) => {
346
390
  return null;
347
391
  };
348
392
  const sendGuildMessage = async (content, val, baseParams, sendMessage, label) => {
393
+ const config = getQQBotConfig();
394
+ const mdToText = config.markdownToText === true;
349
395
  const images = filterImages(val);
350
396
  if (images.length > 0) {
351
397
  const imageBuffer = await resolveImageBuffer(images);
352
- const res = await sendMessage({ content, ...baseParams }, imageBuffer);
398
+ const imgContent = flattenMdToText(content, val);
399
+ const res = await sendMessage({ content: imgContent, ...baseParams }, imageBuffer);
353
400
  return [createResult(ResultCode.Ok, label, { id: res?.id })];
354
401
  }
402
+ if (mdToText) {
403
+ const textContent = flattenMdToText(content, val);
404
+ if (textContent) {
405
+ const res = await sendMessage({ content: textContent, ...baseParams });
406
+ return [createResult(ResultCode.Ok, label, { id: res?.id })];
407
+ }
408
+ return [];
409
+ }
355
410
  const mdParams = buildMdAndButtonsParams(val);
356
411
  if (mdParams) {
412
+ if (mdParams.markdown?.content && content) {
413
+ mdParams.markdown.content = content + '\n' + mdParams.markdown.content;
414
+ }
357
415
  const res = await sendMessage({ content: '', ...mdParams, ...baseParams });
358
416
  return [createResult(ResultCode.Ok, label, { id: res.id })];
359
417
  }
package/lib/types.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ export type DataArkListTip = {
2
+ type: 'Ark.listTip';
3
+ value: {
4
+ desc: string;
5
+ prompt: string;
6
+ };
7
+ };
8
+ export type DataArkListItem = {
9
+ type: 'Ark.listItem';
10
+ value: string | {
11
+ title: string;
12
+ link: string;
13
+ };
14
+ };
15
+ export type DataArkListContent = {
16
+ type: 'Ark.listContent';
17
+ value: DataArkListItem[];
18
+ };
19
+ export type DataArkList = {
20
+ type: 'Ark.list';
21
+ value: [DataArkListTip, DataArkListContent];
22
+ };
23
+ export type DataArkCard = {
24
+ type: 'Ark.Card';
25
+ value: {
26
+ title: string;
27
+ cover: string;
28
+ link: string;
29
+ subtitle: string;
30
+ decs: string;
31
+ prompt: string;
32
+ metadecs: string;
33
+ };
34
+ };
35
+ export type DataArkBigCard = {
36
+ type: 'Ark.BigCard';
37
+ value: {
38
+ title: string;
39
+ subtitle: string;
40
+ cover: string;
41
+ link: string;
42
+ prompt: string;
43
+ };
44
+ };
45
+ export type DataButtonTemplate = {
46
+ type: 'ButtonTemplate';
47
+ value: string;
48
+ };
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alemonjs/qq-bot",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "阿柠檬qq-bot平台连接",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",