koishi-plugin-dew-bot 1.0.251 → 1.0.252
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 +0 -4
- package/lib/index.js +184 -102
- package/lib/plugin/serverHandel/qqCommandMessage.d.ts +1 -1
- package/lib/plugin/serverHandel/qqPageMessage.d.ts +5 -0
- package/lib/plugin/serverHandel/qqStoryMessage.d.ts +6 -0
- package/lib/shared/face/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/index.ts +0 -4
- package/src/plugin/serverHandel/image.ts +11 -4
- package/src/plugin/serverHandel/qqCommandMessage.ts +5 -23
- package/src/plugin/serverHandel/qqPageMessage.ts +55 -21
- package/src/plugin/serverHandel/qqStoryMessage.ts +56 -0
- package/src/plugin/serverHandel/qqTransactionMessage.ts +5 -6
- package/src/plugin/serverHandel/text.ts +11 -5
- package/src/shared/bot/serviceProto.ts +9 -1
- package/src/shared/face/index.ts +2 -0
package/README.md
CHANGED
package/lib/index.js
CHANGED
|
@@ -42,40 +42,6 @@ var import_koishi2 = require("koishi");
|
|
|
42
42
|
// src/plugin/serverHandel/image.ts
|
|
43
43
|
var import_koishi = require("koishi");
|
|
44
44
|
|
|
45
|
-
// src/shared/bot/analysisMsg.ts
|
|
46
|
-
var AnalysisMsg = class {
|
|
47
|
-
static {
|
|
48
|
-
__name(this, "AnalysisMsg");
|
|
49
|
-
}
|
|
50
|
-
parse(data) {
|
|
51
|
-
let msg = "";
|
|
52
|
-
let haveTitle = false;
|
|
53
|
-
for (const item of data.line) {
|
|
54
|
-
switch (item.type) {
|
|
55
|
-
case 0 /* title */:
|
|
56
|
-
haveTitle = true;
|
|
57
|
-
msg += `┄━═${item.content}═━┄
|
|
58
|
-
`;
|
|
59
|
-
break;
|
|
60
|
-
case 1 /* line */:
|
|
61
|
-
msg += `${item.content}
|
|
62
|
-
`;
|
|
63
|
-
break;
|
|
64
|
-
case 2 /* error */:
|
|
65
|
-
msg += `❌出错了!错误原因:${item.content},请反馈至联系开发者
|
|
66
|
-
`;
|
|
67
|
-
break;
|
|
68
|
-
default:
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (haveTitle) {
|
|
73
|
-
msg += "┄━════════━┄";
|
|
74
|
-
}
|
|
75
|
-
return msg;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
45
|
// src/plugin/appearanceCardTemplate.ts
|
|
80
46
|
var escape = /* @__PURE__ */ __name((value) => String(value ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]), "escape");
|
|
81
47
|
function appearanceCardHtml(card, artwork, paper) {
|
|
@@ -689,28 +655,37 @@ var handel_base = class {
|
|
|
689
655
|
}
|
|
690
656
|
};
|
|
691
657
|
|
|
692
|
-
// src/
|
|
693
|
-
var
|
|
658
|
+
// src/shared/bot/analysisMsg.ts
|
|
659
|
+
var AnalysisMsg = class {
|
|
694
660
|
static {
|
|
695
|
-
__name(this, "
|
|
661
|
+
__name(this, "AnalysisMsg");
|
|
696
662
|
}
|
|
697
|
-
|
|
698
|
-
let
|
|
699
|
-
let
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
663
|
+
parse(data) {
|
|
664
|
+
let msg = "";
|
|
665
|
+
let haveTitle = false;
|
|
666
|
+
for (const item of data.line) {
|
|
667
|
+
switch (item.type) {
|
|
668
|
+
case 0 /* title */:
|
|
669
|
+
haveTitle = true;
|
|
670
|
+
msg += `┄━═${item.content}═━┄
|
|
671
|
+
`;
|
|
672
|
+
break;
|
|
673
|
+
case 1 /* line */:
|
|
674
|
+
msg += `${item.content}
|
|
675
|
+
`;
|
|
676
|
+
break;
|
|
677
|
+
case 2 /* error */:
|
|
678
|
+
msg += `❌出错了!错误原因:${item.content},请反馈至联系开发者
|
|
679
|
+
`;
|
|
680
|
+
break;
|
|
681
|
+
default:
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (haveTitle) {
|
|
686
|
+
msg += "┄━════════━┄";
|
|
712
687
|
}
|
|
713
|
-
|
|
688
|
+
return msg;
|
|
714
689
|
}
|
|
715
690
|
};
|
|
716
691
|
|
|
@@ -723,6 +698,12 @@ function compactDisplayText(value) {
|
|
|
723
698
|
return value.trim().replace(/[ \t\u3000]*([·×+|])[ \t\u3000]*/g, "$1").replace(/([\p{Script=Han}\p{Extended_Pictographic}\p{Emoji_Modifier}\p{Regional_Indicator}\uFE0F])[ \t\u3000]+/gu, "$1").replace(/[ \t\u3000]+(?=[\p{Script=Han}\p{Extended_Pictographic}\p{Regional_Indicator}])/gu, "");
|
|
724
699
|
}
|
|
725
700
|
__name(compactDisplayText, "compactDisplayText");
|
|
701
|
+
function renderQQTitle(content) {
|
|
702
|
+
return `**${escapeMarkdown(compactDisplayText(content))}**
|
|
703
|
+
|
|
704
|
+
***`;
|
|
705
|
+
}
|
|
706
|
+
__name(renderQQTitle, "renderQQTitle");
|
|
726
707
|
function compactListLabel(value) {
|
|
727
708
|
const label = compactDisplayText(value);
|
|
728
709
|
return /[📖📚]/u.test(label) ? label.replace(/技能书(?=$|×\d+(?:\.\d+)?(?:||$)||)/g, "") : label;
|
|
@@ -733,6 +714,42 @@ function inlineCommandUrl(command) {
|
|
|
733
714
|
return `mqqapi://aio/inlinecmd?command=${encoded}&enter=true&reply=false`;
|
|
734
715
|
}
|
|
735
716
|
__name(inlineCommandUrl, "inlineCommandUrl");
|
|
717
|
+
function inlineCommandSpans(content) {
|
|
718
|
+
const spans = [];
|
|
719
|
+
let depth = 0, start = 0, labelStart = 0;
|
|
720
|
+
for (let index = 0; index < content.length; index++) {
|
|
721
|
+
if (content[index] === "[") {
|
|
722
|
+
if (depth === 0) {
|
|
723
|
+
start = index > 0 && content[index - 1] === "\\" ? index - 1 : index;
|
|
724
|
+
labelStart = index + 1;
|
|
725
|
+
}
|
|
726
|
+
depth++;
|
|
727
|
+
} else if (content[index] === "]" && depth > 0 && --depth === 0) {
|
|
728
|
+
const label = content.slice(labelStart, index).replace(/\\$/, "");
|
|
729
|
+
if (!label.trim() || /[\[\]\r\n]/.test(label) || /^\d+$/.test(label.trim())) continue;
|
|
730
|
+
const command = label.split(/[++]/, 1)[0].trim();
|
|
731
|
+
if (command) spans.push({ start, end: index + 1, label, command });
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return spans;
|
|
735
|
+
}
|
|
736
|
+
__name(inlineCommandSpans, "inlineCommandSpans");
|
|
737
|
+
function hasInlineCommands(content) {
|
|
738
|
+
return inlineCommandSpans(content).length > 0;
|
|
739
|
+
}
|
|
740
|
+
__name(hasInlineCommands, "hasInlineCommands");
|
|
741
|
+
function renderInlineCommands(content) {
|
|
742
|
+
const parts = [];
|
|
743
|
+
let offset = 0;
|
|
744
|
+
for (const span of inlineCommandSpans(content)) {
|
|
745
|
+
parts.push(escapeMarkdown(content.slice(offset, span.start)));
|
|
746
|
+
parts.push("[" + escapeMarkdown(span.label) + "](" + inlineCommandUrl(span.command) + ")");
|
|
747
|
+
offset = span.end;
|
|
748
|
+
}
|
|
749
|
+
parts.push(escapeMarkdown(content.slice(offset)));
|
|
750
|
+
return parts.join("");
|
|
751
|
+
}
|
|
752
|
+
__name(renderInlineCommands, "renderInlineCommands");
|
|
736
753
|
function pageCommandLines(nav) {
|
|
737
754
|
return [
|
|
738
755
|
...nav.previousCommand ? [nav.previousCommand] : [],
|
|
@@ -746,11 +763,6 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
746
763
|
const listPattern = /^\[(\d+)\]\s*([^\r\n]+)$/;
|
|
747
764
|
const pagePattern = /^第\s*\d+\s*\/\s*\d+\s*页(?:\s*[||]\s*共\s*(\d+)\s*([项条]))?$/;
|
|
748
765
|
const title = data.line.find((item) => item.type === 0 /* title */);
|
|
749
|
-
const summaryLine = data.line.find((item) => item.type === 1 /* line */ && pagePattern.test(item.content));
|
|
750
|
-
const summary = summaryLine && pagePattern.exec(summaryLine.content);
|
|
751
|
-
const listCount = data.line.filter((item) => item.type === 1 /* line */ && listPattern.test(item.content)).length;
|
|
752
|
-
const count = summary?.[1] ?? (nav?.total === 1 && listCount > 0 ? String(listCount) : void 0);
|
|
753
|
-
const countUnit = summary?.[2] ?? "项";
|
|
754
766
|
const isLeaderboardDirectory = !!nav?.entries?.length && /^(?:🏆)?排行榜$/u.test(compactDisplayText(title?.content ?? ""));
|
|
755
767
|
const sections = [];
|
|
756
768
|
const bodyLines = [];
|
|
@@ -773,20 +785,16 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
773
785
|
switch (item.type) {
|
|
774
786
|
case 0 /* title */:
|
|
775
787
|
flush();
|
|
776
|
-
|
|
777
|
-
sections.push(`## ${item.content.includes("🏆") ? "" : "🏆"}${escapeMarkdown(compactDisplayText(item.content))}`);
|
|
778
|
-
sections.push(`> 共${nav.entries.length}个榜单·点击榜名查看`);
|
|
779
|
-
} else {
|
|
780
|
-
sections.push(`**${escapeMarkdown(compactDisplayText(item.content))}${count !== void 0 ? `·${count}${countUnit}` : ""}**`);
|
|
781
|
-
}
|
|
788
|
+
sections.push(renderQQTitle(`${isLeaderboardDirectory && !item.content.includes("🏆") ? "🏆" : ""}${item.content}`));
|
|
782
789
|
break;
|
|
783
790
|
case 1 /* line */: {
|
|
784
791
|
const listEntry = listPattern.exec(item.content);
|
|
785
792
|
if (listEntry) {
|
|
786
793
|
flushBody();
|
|
787
794
|
const command2 = entryCommands.get(lineIndex);
|
|
788
|
-
const
|
|
789
|
-
const
|
|
795
|
+
const content = compactListLabel(listEntry[2]);
|
|
796
|
+
const label = escapeMarkdown(content);
|
|
797
|
+
const name2 = command2 ? `[${label}](${inlineCommandUrl(command2)})` : renderInlineCommands(content);
|
|
790
798
|
listLines.push(`${listEntry[1]}. ${name2}`);
|
|
791
799
|
break;
|
|
792
800
|
}
|
|
@@ -803,17 +811,17 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
803
811
|
const page = pagePattern.exec(item.content);
|
|
804
812
|
if (page && nav) {
|
|
805
813
|
flushBody();
|
|
806
|
-
pageFooter = `**第${nav.current}/${nav.total}
|
|
814
|
+
pageFooter = `**第${nav.current}/${nav.total}页**`;
|
|
807
815
|
hasPageSummary = true;
|
|
808
816
|
break;
|
|
809
817
|
}
|
|
810
818
|
const command = entryCommands.get(lineIndex);
|
|
811
|
-
bodyLines.push(command ? `[${escapeMarkdown(
|
|
819
|
+
bodyLines.push(command ? `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})` : renderInlineCommands(item.content));
|
|
812
820
|
break;
|
|
813
821
|
}
|
|
814
822
|
case 2 /* error */:
|
|
815
823
|
flush();
|
|
816
|
-
sections.push(`❌ 出错了!错误原因:${
|
|
824
|
+
sections.push(`❌ 出错了!错误原因:${renderInlineCommands(item.content)},请反馈至联系开发者`);
|
|
817
825
|
break;
|
|
818
826
|
}
|
|
819
827
|
}
|
|
@@ -824,10 +832,7 @@ function renderQQPageMarkdown(data, showGreeting) {
|
|
|
824
832
|
const nextLink = nav?.nextCommand ? `[${nav.nextCommand === "下一个" ? "下一个" : "下一页"}](${inlineCommandUrl(nav.nextCommand)})` : void 0;
|
|
825
833
|
const helpLink = hasHelp ? `[指令](${inlineCommandUrl("指令")})` : void 0;
|
|
826
834
|
const footer = pageFooter ? [pageFooter, previousLink, nextLink, helpLink].filter(Boolean).join("·") : helpLink ? `更多操作:${helpLink}` : void 0;
|
|
827
|
-
if (footer)
|
|
828
|
-
if (isLeaderboardDirectory) sections.push("***");
|
|
829
|
-
sections.push(footer);
|
|
830
|
-
}
|
|
835
|
+
if (footer) sections.push(footer);
|
|
831
836
|
return sections.join("\n\n") || " ";
|
|
832
837
|
}
|
|
833
838
|
__name(renderQQPageMarkdown, "renderQQPageMarkdown");
|
|
@@ -883,12 +888,12 @@ function renderQQTransactionMarkdown(data, showGreeting) {
|
|
|
883
888
|
for (const item of data.line) {
|
|
884
889
|
if (item.type === 0 /* title */) {
|
|
885
890
|
flush();
|
|
886
|
-
sections.push(
|
|
891
|
+
sections.push(renderQQTitle(item.content));
|
|
887
892
|
continue;
|
|
888
893
|
}
|
|
889
894
|
if (item.type === 2 /* error */) {
|
|
890
895
|
flush();
|
|
891
|
-
sections.push(`❌ 出错了!错误原因:${
|
|
896
|
+
sections.push(`❌ 出错了!错误原因:${renderInlineCommands(item.content)},请反馈至联系开发者`);
|
|
892
897
|
continue;
|
|
893
898
|
}
|
|
894
899
|
if (item.type !== 1 /* line */) continue;
|
|
@@ -908,7 +913,7 @@ function renderQQTransactionMarkdown(data, showGreeting) {
|
|
|
908
913
|
flushBody();
|
|
909
914
|
sections.push(`**${escapeMarkdown(section?.[1] ?? "还缺")}**`);
|
|
910
915
|
} else {
|
|
911
|
-
bodyLines.push(
|
|
916
|
+
bodyLines.push(renderInlineCommands(item.content));
|
|
912
917
|
}
|
|
913
918
|
}
|
|
914
919
|
flush();
|
|
@@ -921,20 +926,6 @@ async function sendQQTransaction(session, data) {
|
|
|
921
926
|
__name(sendQQTransaction, "sendQQTransaction");
|
|
922
927
|
|
|
923
928
|
// src/plugin/serverHandel/qqCommandMessage.ts
|
|
924
|
-
function renderCommandLine(content, commandHelp) {
|
|
925
|
-
if (!commandHelp || !/^\s*\[[^\[\]\r\n]+\]/.test(content)) return escapeMarkdown(content);
|
|
926
|
-
const parts = [];
|
|
927
|
-
let offset = 0;
|
|
928
|
-
for (const match of content.matchAll(/\[([^\[\]\r\n]+)\]/g)) {
|
|
929
|
-
parts.push(escapeMarkdown(content.slice(offset, match.index)));
|
|
930
|
-
const command = match[1].split(/[++]/, 1)[0].trim();
|
|
931
|
-
parts.push(command ? `[${escapeMarkdown(match[1])}](${inlineCommandUrl(command)})` : escapeMarkdown(match[0]));
|
|
932
|
-
offset = match.index + match[0].length;
|
|
933
|
-
}
|
|
934
|
-
parts.push(escapeMarkdown(content.slice(offset)));
|
|
935
|
-
return parts.join("");
|
|
936
|
-
}
|
|
937
|
-
__name(renderCommandLine, "renderCommandLine");
|
|
938
929
|
function renderQQCommandMarkdown(data, showGreeting) {
|
|
939
930
|
const sections = [];
|
|
940
931
|
const bodyLines = [];
|
|
@@ -946,15 +937,15 @@ function renderQQCommandMarkdown(data, showGreeting) {
|
|
|
946
937
|
switch (item.type) {
|
|
947
938
|
case 0 /* title */:
|
|
948
939
|
flushBody();
|
|
949
|
-
sections.push(
|
|
940
|
+
sections.push(renderQQTitle(item.content));
|
|
950
941
|
break;
|
|
951
942
|
case 1 /* line */:
|
|
952
943
|
if (!item.content.trim()) flushBody();
|
|
953
|
-
else bodyLines.push(
|
|
944
|
+
else bodyLines.push(renderInlineCommands(item.content));
|
|
954
945
|
break;
|
|
955
946
|
case 2 /* error */:
|
|
956
947
|
flushBody();
|
|
957
|
-
sections.push(`❌ 出错了!错误原因:${
|
|
948
|
+
sections.push(`❌ 出错了!错误原因:${renderInlineCommands(item.content)},请反馈至联系开发者`);
|
|
958
949
|
break;
|
|
959
950
|
}
|
|
960
951
|
}
|
|
@@ -967,6 +958,57 @@ async function sendQQCommand(session, data) {
|
|
|
967
958
|
}
|
|
968
959
|
__name(sendQQCommand, "sendQQCommand");
|
|
969
960
|
|
|
961
|
+
// src/plugin/serverHandel/qqStoryMessage.ts
|
|
962
|
+
function hasStoryCodeBlock(data) {
|
|
963
|
+
return data.line.some((item) => item.type === 1 /* line */ && item.codeBlock === true);
|
|
964
|
+
}
|
|
965
|
+
__name(hasStoryCodeBlock, "hasStoryCodeBlock");
|
|
966
|
+
function fencedStory(content) {
|
|
967
|
+
const story = content.replace(/\r\n?/g, "\n");
|
|
968
|
+
const longestRun = Math.max(0, ...Array.from(story.matchAll(/`+/g), (match) => match[0].length));
|
|
969
|
+
const fence = "`".repeat(Math.max(3, longestRun + 1));
|
|
970
|
+
return fence + "\n" + story + (story.endsWith("\n") ? "" : "\n") + fence;
|
|
971
|
+
}
|
|
972
|
+
__name(fencedStory, "fencedStory");
|
|
973
|
+
function renderQQStoryMarkdown(data, showGreeting) {
|
|
974
|
+
const sections = [];
|
|
975
|
+
const bodyLines = [];
|
|
976
|
+
const flushBody = /* @__PURE__ */ __name(() => {
|
|
977
|
+
if (bodyLines.length) sections.push(bodyLines.splice(0).join(" \n"));
|
|
978
|
+
}, "flushBody");
|
|
979
|
+
if (showGreeting) sections.push(escapeMarkdown("Ciallo~(∠・ω< )"));
|
|
980
|
+
for (const item of data.line) {
|
|
981
|
+
switch (item.type) {
|
|
982
|
+
case 0 /* title */:
|
|
983
|
+
flushBody();
|
|
984
|
+
sections.push(renderQQTitle(item.content));
|
|
985
|
+
break;
|
|
986
|
+
case 1 /* line */:
|
|
987
|
+
if (item.codeBlock) {
|
|
988
|
+
flushBody();
|
|
989
|
+
sections.push(fencedStory(item.content));
|
|
990
|
+
} else {
|
|
991
|
+
for (const line of item.content.replace(/\r\n?/g, "\n").split("\n")) {
|
|
992
|
+
if (!line.trim()) flushBody();
|
|
993
|
+
else bodyLines.push(renderInlineCommands(line));
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
break;
|
|
997
|
+
case 2 /* error */:
|
|
998
|
+
flushBody();
|
|
999
|
+
sections.push("❌ 出错了!错误原因:" + renderInlineCommands(item.content) + ",请反馈至联系开发者");
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
flushBody();
|
|
1004
|
+
return sections.join("\n\n") || " ";
|
|
1005
|
+
}
|
|
1006
|
+
__name(renderQQStoryMarkdown, "renderQQStoryMarkdown");
|
|
1007
|
+
async function sendQQStory(session, data) {
|
|
1008
|
+
await sendQQMarkdown(session, renderQQStoryMarkdown(data, session.event?.channel?.type === 0));
|
|
1009
|
+
}
|
|
1010
|
+
__name(sendQQStory, "sendQQStory");
|
|
1011
|
+
|
|
970
1012
|
// src/plugin/serverHandel/text.ts
|
|
971
1013
|
var handelr_text = class extends handel_base {
|
|
972
1014
|
static {
|
|
@@ -975,12 +1017,16 @@ var handelr_text = class extends handel_base {
|
|
|
975
1017
|
async start(data) {
|
|
976
1018
|
const content = new AnalysisMsg().parse(data);
|
|
977
1019
|
const session = sessions_default.get(sessionKey(data.botId, data.userId, data.channelId));
|
|
978
|
-
|
|
1020
|
+
const inlineCommands = data.line.some((item) => (item.type === 1 /* line */ || item.type === 2 /* error */) && hasInlineCommands(item.content));
|
|
1021
|
+
const story = hasStoryCodeBlock(data);
|
|
1022
|
+
if ((story || data.commandHelp || data.transaction || data.pageNav || inlineCommands) && canSendQQPage(session, data)) {
|
|
979
1023
|
const sendStartedAt = this.timing ? performance.now() : 0;
|
|
980
1024
|
try {
|
|
981
|
-
if (
|
|
1025
|
+
if (story) await sendQQStory(session, data);
|
|
1026
|
+
else if (data.commandHelp) await sendQQCommand(session, data);
|
|
982
1027
|
else if (data.transaction) await sendQQTransaction(session, data);
|
|
983
|
-
else await sendQQPage(session, data);
|
|
1028
|
+
else if (data.pageNav) await sendQQPage(session, data);
|
|
1029
|
+
else await sendQQCommand(session, data);
|
|
984
1030
|
if (this.timing) {
|
|
985
1031
|
this.timing.delivery = "qq-markdown";
|
|
986
1032
|
this.timing.sendMs = performance.now() - sendStartedAt;
|
|
@@ -989,7 +1035,7 @@ var handelr_text = class extends handel_base {
|
|
|
989
1035
|
} catch (error) {
|
|
990
1036
|
this.ctx.logger.warn("QQ Markdown 发送失败,改用普通文字", error instanceof Error ? error.message : error);
|
|
991
1037
|
}
|
|
992
|
-
const commands = !data.commandHelp && !data.transaction && data.pageNav ? pageCommandLines(data.pageNav) : [];
|
|
1038
|
+
const commands = !story && !data.commandHelp && !data.transaction && data.pageNav ? pageCommandLines(data.pageNav) : [];
|
|
993
1039
|
await this.send(data, commands.length ? `${content.trimEnd()}
|
|
994
1040
|
${commands.join("\n")}` : content);
|
|
995
1041
|
return;
|
|
@@ -998,6 +1044,38 @@ ${commands.join("\n")}` : content);
|
|
|
998
1044
|
}
|
|
999
1045
|
};
|
|
1000
1046
|
|
|
1047
|
+
// src/plugin/serverHandel/image.ts
|
|
1048
|
+
var ImageHandler = class extends handel_base {
|
|
1049
|
+
static {
|
|
1050
|
+
__name(this, "ImageHandler");
|
|
1051
|
+
}
|
|
1052
|
+
async start(data) {
|
|
1053
|
+
let content = "";
|
|
1054
|
+
let rendered = false;
|
|
1055
|
+
const renderStartedAt = this.timing ? performance.now() : 0;
|
|
1056
|
+
try {
|
|
1057
|
+
if (!data.characterCard && !data.itemCard && !data.card && !data.leaderboard && !data.equipmentCard) throw new Error("缺少卡片数据");
|
|
1058
|
+
const image = await renderSkillCard(this.ctx, data.card, data.leaderboard, data.itemCard, data.characterCard, data.equipmentCard);
|
|
1059
|
+
if (this.timing) this.timing.imageBytes = image.length;
|
|
1060
|
+
content = import_koishi.h.image(image, "image/jpeg").toString();
|
|
1061
|
+
rendered = true;
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
this.ctx.logger.warn("卡片绘制失败,使用文字详情", error instanceof Error ? error.message : "unknown");
|
|
1064
|
+
} finally {
|
|
1065
|
+
if (this.timing) this.timing.renderMs = performance.now() - renderStartedAt;
|
|
1066
|
+
}
|
|
1067
|
+
if (!rendered) {
|
|
1068
|
+
const fallback = new handelr_text(data);
|
|
1069
|
+
fallback.set(this.ctx);
|
|
1070
|
+
if (this.timing) fallback.setTiming(this.timing);
|
|
1071
|
+
fallback.send = (message, text, type = "text") => this.send(message, text, type);
|
|
1072
|
+
await fallback.start(data);
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
await this.send(data, content, "image");
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1001
1079
|
// src/plugin/messageQueue.ts
|
|
1002
1080
|
var handlers = {
|
|
1003
1081
|
["text" /* text */]: handelr_text,
|
|
@@ -1062,7 +1140,7 @@ var import_tsrpc = require("tsrpc");
|
|
|
1062
1140
|
|
|
1063
1141
|
// src/shared/bot/serviceProto.ts
|
|
1064
1142
|
var serviceProto = {
|
|
1065
|
-
"version":
|
|
1143
|
+
"version": 14,
|
|
1066
1144
|
"services": [
|
|
1067
1145
|
{
|
|
1068
1146
|
"id": 0,
|
|
@@ -1949,6 +2027,14 @@ var serviceProto = {
|
|
|
1949
2027
|
"type": {
|
|
1950
2028
|
"type": "String"
|
|
1951
2029
|
}
|
|
2030
|
+
},
|
|
2031
|
+
{
|
|
2032
|
+
"id": 2,
|
|
2033
|
+
"name": "codeBlock",
|
|
2034
|
+
"type": {
|
|
2035
|
+
"type": "Boolean"
|
|
2036
|
+
},
|
|
2037
|
+
"optional": true
|
|
1952
2038
|
}
|
|
1953
2039
|
]
|
|
1954
2040
|
},
|
|
@@ -2280,10 +2366,6 @@ var usage = `
|
|
|
2280
2366
|
踏入主神空间,成为轮回者。与伙伴迎接未知的试炼,在生死之间积蓄力量,书写属于你的无限冒险。
|
|
2281
2367
|
|
|
2282
2368
|
无论你熟悉原作,还是初次踏入无限流世界,这场轮回,都有你的位置。
|
|
2283
|
-
|
|
2284
|
-
---
|
|
2285
|
-
|
|
2286
|
-
连接 DEW 游戏服后,在聊天中发送 **帮助**,开启第一场冒险。
|
|
2287
2369
|
`;
|
|
2288
2370
|
var Config = import_koishi2.Schema.object({
|
|
2289
2371
|
服务器地址: import_koishi2.Schema.string().default("ws://dew-v7-test:3021").description("DEW 游戏服的 WebSocket 地址;同机部署可填写 ws://127.0.0.1:3021")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Session } from 'koishi';
|
|
2
2
|
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
3
|
-
/**
|
|
3
|
+
/** Render command help and ordinary prose with clickable bracketed commands. */
|
|
4
4
|
export declare function renderQQCommandMarkdown(data: MsgMessage, showGreeting: boolean): string;
|
|
5
5
|
export declare function sendQQCommand(session: Session, data: MsgMessage): Promise<void>;
|
|
@@ -3,7 +3,12 @@ import { type PageNavData } from '../../shared/face';
|
|
|
3
3
|
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
4
4
|
/** Escape server-provided lines before embedding them in native QQ Markdown. */
|
|
5
5
|
export declare function escapeMarkdown(value: string): string;
|
|
6
|
+
/** Keep native QQ Markdown titles consistent across message types. */
|
|
7
|
+
export declare function renderQQTitle(content: string): string;
|
|
6
8
|
export declare function inlineCommandUrl(command: string): string;
|
|
9
|
+
export declare function hasInlineCommands(content: string): boolean;
|
|
10
|
+
/** Escape surrounding prose while rendering boxed commands as inline links. */
|
|
11
|
+
export declare function renderInlineCommands(content: string): string;
|
|
7
12
|
export declare function pageCommandLines(nav: PageNavData): string[];
|
|
8
13
|
export declare function renderQQPageMarkdown(data: MsgMessage, showGreeting: boolean): string;
|
|
9
14
|
/** Returns false if this is not the matching QQ session or the adapter has no native API. */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Session } from 'koishi';
|
|
2
|
+
import type { MsgMessage } from '../../shared/bot/MsgMessage';
|
|
3
|
+
export declare function hasStoryCodeBlock(data: Pick<MsgMessage, 'line'>): boolean;
|
|
4
|
+
/** Only marked story lines become code blocks; result summaries remain prose. */
|
|
5
|
+
export declare function renderQQStoryMarkdown(data: MsgMessage, showGreeting: boolean): string;
|
|
6
|
+
export declare function sendQQStory(session: Session, data: MsgMessage): Promise<void>;
|
|
@@ -101,6 +101,8 @@ export interface ITitleMessage {
|
|
|
101
101
|
export interface ILineMessage {
|
|
102
102
|
type: MessageType.line;
|
|
103
103
|
content: string;
|
|
104
|
+
/** 原文长故事:支持的平台使用 Markdown 代码块,其余平台按普通文字显示。 */
|
|
105
|
+
codeBlock?: boolean;
|
|
104
106
|
}
|
|
105
107
|
/** 错误消息项 **/
|
|
106
108
|
export interface IErrorMessage {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { h } from 'koishi'
|
|
2
2
|
import { MsgMessage } from '../../shared/bot/MsgMessage'
|
|
3
|
-
import { AnalysisMsg } from '../../shared/bot/analysisMsg'
|
|
4
3
|
import { renderSkillCard } from '../skillCard'
|
|
5
4
|
import handel_base from './handel_base'
|
|
5
|
+
import TextHandler from './text'
|
|
6
6
|
export default class ImageHandler extends handel_base {
|
|
7
7
|
async start(data: MsgMessage) {
|
|
8
|
-
let content
|
|
8
|
+
let content = ''
|
|
9
9
|
let rendered = false
|
|
10
10
|
const renderStartedAt = this.timing ? performance.now() : 0
|
|
11
11
|
try {
|
|
@@ -16,10 +16,17 @@ export default class ImageHandler extends handel_base {
|
|
|
16
16
|
rendered = true
|
|
17
17
|
} catch (error) {
|
|
18
18
|
this.ctx.logger.warn('卡片绘制失败,使用文字详情', error instanceof Error ? error.message : 'unknown')
|
|
19
|
-
content = new AnalysisMsg().parse(data)
|
|
20
19
|
} finally {
|
|
21
20
|
if (this.timing) this.timing.renderMs = performance.now() - renderStartedAt
|
|
22
21
|
}
|
|
23
|
-
|
|
22
|
+
if (!rendered) {
|
|
23
|
+
const fallback = new TextHandler(data)
|
|
24
|
+
fallback.set(this.ctx)
|
|
25
|
+
if (this.timing) fallback.setTiming(this.timing)
|
|
26
|
+
fallback.send = (message, text, type = 'text') => this.send(message, text, type)
|
|
27
|
+
await fallback.start(data)
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
await this.send(data, content, 'image')
|
|
24
31
|
}
|
|
25
32
|
}
|
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
import type { Session } from 'koishi'
|
|
2
2
|
import { MessageType } from '../../shared/face'
|
|
3
3
|
import type { MsgMessage } from '../../shared/bot/MsgMessage'
|
|
4
|
-
import { escapeMarkdown,
|
|
4
|
+
import { escapeMarkdown, renderInlineCommands, renderQQTitle, sendQQMarkdown } from './qqPageMessage'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
// Only explicit command-description rows enable links. Unknown input and
|
|
8
|
-
// other prose remain display text, even when they contain square brackets.
|
|
9
|
-
if (!commandHelp || !/^\s*\[[^\[\]\r\n]+\]/.test(content)) return escapeMarkdown(content)
|
|
10
|
-
const parts: string[] = []
|
|
11
|
-
let offset = 0
|
|
12
|
-
for (const match of content.matchAll(/\[([^\[\]\r\n]+)\]/g)) {
|
|
13
|
-
parts.push(escapeMarkdown(content.slice(offset, match.index)))
|
|
14
|
-
const command = match[1].split(/[++]/, 1)[0].trim()
|
|
15
|
-
parts.push(command
|
|
16
|
-
? `[${escapeMarkdown(match[1])}](${inlineCommandUrl(command)})`
|
|
17
|
-
: escapeMarkdown(match[0]))
|
|
18
|
-
offset = match.index! + match[0].length
|
|
19
|
-
}
|
|
20
|
-
parts.push(escapeMarkdown(content.slice(offset)))
|
|
21
|
-
return parts.join('')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Keep help text intact while making its explicitly boxed commands clickable. */
|
|
6
|
+
/** Render command help and ordinary prose with clickable bracketed commands. */
|
|
25
7
|
export function renderQQCommandMarkdown(data: MsgMessage, showGreeting: boolean): string {
|
|
26
8
|
const sections: string[] = []
|
|
27
9
|
const bodyLines: string[] = []
|
|
@@ -33,15 +15,15 @@ export function renderQQCommandMarkdown(data: MsgMessage, showGreeting: boolean)
|
|
|
33
15
|
switch (item.type) {
|
|
34
16
|
case MessageType.title:
|
|
35
17
|
flushBody()
|
|
36
|
-
sections.push(
|
|
18
|
+
sections.push(renderQQTitle(item.content))
|
|
37
19
|
break
|
|
38
20
|
case MessageType.line:
|
|
39
21
|
if (!item.content.trim()) flushBody()
|
|
40
|
-
else bodyLines.push(
|
|
22
|
+
else bodyLines.push(renderInlineCommands(item.content))
|
|
41
23
|
break
|
|
42
24
|
case MessageType.error:
|
|
43
25
|
flushBody()
|
|
44
|
-
sections.push(`❌ 出错了!错误原因:${
|
|
26
|
+
sections.push(`❌ 出错了!错误原因:${renderInlineCommands(item.content)},请反馈至联系开发者`)
|
|
45
27
|
break
|
|
46
28
|
}
|
|
47
29
|
}
|
|
@@ -35,6 +35,11 @@ function compactDisplayText(value: string): string {
|
|
|
35
35
|
.replace(/[ \t\u3000]+(?=[\p{Script=Han}\p{Extended_Pictographic}\p{Regional_Indicator}])/gu, '')
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/** Keep native QQ Markdown titles consistent across message types. */
|
|
39
|
+
export function renderQQTitle(content: string): string {
|
|
40
|
+
return `**${escapeMarkdown(compactDisplayText(content))}**\n\n***`
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
function compactListLabel(value: string): string {
|
|
39
44
|
const label = compactDisplayText(value)
|
|
40
45
|
// The book icon already identifies skill books. Only shorten the displayed
|
|
@@ -52,6 +57,47 @@ export function inlineCommandUrl(command: string): string {
|
|
|
52
57
|
return `mqqapi://aio/inlinecmd?command=${encoded}&enter=true&reply=false`
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
|
|
61
|
+
type InlineCommandSpan = { start: number; end: number; label: string; command: string }
|
|
62
|
+
|
|
63
|
+
/** Bracketed commands may appear anywhere in prose, including escaped brackets. */
|
|
64
|
+
function inlineCommandSpans(content: string): InlineCommandSpan[] {
|
|
65
|
+
const spans: InlineCommandSpan[] = []
|
|
66
|
+
let depth = 0, start = 0, labelStart = 0
|
|
67
|
+
for (let index = 0; index < content.length; index++) {
|
|
68
|
+
if (content[index] === '[') {
|
|
69
|
+
if (depth === 0) {
|
|
70
|
+
start = index > 0 && content[index - 1] === '\\' ? index - 1 : index
|
|
71
|
+
labelStart = index + 1
|
|
72
|
+
}
|
|
73
|
+
depth++
|
|
74
|
+
} else if (content[index] === ']' && depth > 0 && --depth === 0) {
|
|
75
|
+
const label = content.slice(labelStart, index).replace(/\\$/, '')
|
|
76
|
+
if (!label.trim() || /[\[\]\r\n]/.test(label) || /^\d+$/.test(label.trim())) continue
|
|
77
|
+
const command = label.split(/[++]/, 1)[0].trim()
|
|
78
|
+
if (command) spans.push({ start, end: index + 1, label, command })
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return spans
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function hasInlineCommands(content: string): boolean {
|
|
85
|
+
return inlineCommandSpans(content).length > 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Escape surrounding prose while rendering boxed commands as inline links. */
|
|
89
|
+
export function renderInlineCommands(content: string): string {
|
|
90
|
+
const parts: string[] = []
|
|
91
|
+
let offset = 0
|
|
92
|
+
for (const span of inlineCommandSpans(content)) {
|
|
93
|
+
parts.push(escapeMarkdown(content.slice(offset, span.start)))
|
|
94
|
+
parts.push('[' + escapeMarkdown(span.label) + '](' + inlineCommandUrl(span.command) + ')')
|
|
95
|
+
offset = span.end
|
|
96
|
+
}
|
|
97
|
+
parts.push(escapeMarkdown(content.slice(offset)))
|
|
98
|
+
return parts.join('')
|
|
99
|
+
}
|
|
100
|
+
|
|
55
101
|
export function pageCommandLines(nav: PageNavData): string[] {
|
|
56
102
|
return [
|
|
57
103
|
...(nav.previousCommand ? [nav.previousCommand] : []),
|
|
@@ -65,11 +111,6 @@ export function renderQQPageMarkdown(data: MsgMessage, showGreeting: boolean): s
|
|
|
65
111
|
const listPattern = /^\[(\d+)\]\s*([^\r\n]+)$/
|
|
66
112
|
const pagePattern = /^第\s*\d+\s*\/\s*\d+\s*页(?:\s*[||]\s*共\s*(\d+)\s*([项条]))?$/
|
|
67
113
|
const title = data.line.find(item => item.type === MessageType.title)
|
|
68
|
-
const summaryLine = data.line.find(item => item.type === MessageType.line && pagePattern.test(item.content))
|
|
69
|
-
const summary = summaryLine && pagePattern.exec(summaryLine.content)
|
|
70
|
-
const listCount = data.line.filter(item => item.type === MessageType.line && listPattern.test(item.content)).length
|
|
71
|
-
const count = summary?.[1] ?? (nav?.total === 1 && listCount > 0 ? String(listCount) : undefined)
|
|
72
|
-
const countUnit = summary?.[2] ?? '项'
|
|
73
114
|
const isLeaderboardDirectory = !!nav?.entries?.length
|
|
74
115
|
&& /^(?:🏆)?排行榜$/u.test(compactDisplayText(title?.content ?? ''))
|
|
75
116
|
const sections: string[] = []
|
|
@@ -90,22 +131,18 @@ export function renderQQPageMarkdown(data: MsgMessage, showGreeting: boolean): s
|
|
|
90
131
|
switch (item.type) {
|
|
91
132
|
case MessageType.title:
|
|
92
133
|
flush()
|
|
93
|
-
|
|
94
|
-
sections.push(`## ${item.content.includes('🏆') ? '' : '🏆'}${escapeMarkdown(compactDisplayText(item.content))}`)
|
|
95
|
-
sections.push(`> 共${nav!.entries!.length}个榜单·点击榜名查看`)
|
|
96
|
-
} else {
|
|
97
|
-
sections.push(`**${escapeMarkdown(compactDisplayText(item.content))}${count !== undefined ? `·${count}${countUnit}` : ''}**`)
|
|
98
|
-
}
|
|
134
|
+
sections.push(renderQQTitle(`${isLeaderboardDirectory && !item.content.includes('🏆') ? '🏆' : ''}${item.content}`))
|
|
99
135
|
break
|
|
100
136
|
case MessageType.line: {
|
|
101
137
|
const listEntry = listPattern.exec(item.content)
|
|
102
138
|
if (listEntry) {
|
|
103
139
|
flushBody()
|
|
104
140
|
const command = entryCommands.get(lineIndex)
|
|
105
|
-
const
|
|
141
|
+
const content = compactListLabel(listEntry[2])
|
|
142
|
+
const label = escapeMarkdown(content)
|
|
106
143
|
const name = command
|
|
107
144
|
? `[${label}](${inlineCommandUrl(command)})`
|
|
108
|
-
:
|
|
145
|
+
: renderInlineCommands(content)
|
|
109
146
|
// Keep the numeric marker as Markdown syntax; escape only the item text.
|
|
110
147
|
listLines.push(`${listEntry[1]}. ${name}`)
|
|
111
148
|
break
|
|
@@ -125,19 +162,19 @@ export function renderQQPageMarkdown(data: MsgMessage, showGreeting: boolean): s
|
|
|
125
162
|
const page = pagePattern.exec(item.content)
|
|
126
163
|
if (page && nav) {
|
|
127
164
|
flushBody()
|
|
128
|
-
pageFooter = `**第${nav.current}/${nav.total}
|
|
165
|
+
pageFooter = `**第${nav.current}/${nav.total}页**`
|
|
129
166
|
hasPageSummary = true
|
|
130
167
|
break
|
|
131
168
|
}
|
|
132
169
|
const command = entryCommands.get(lineIndex)
|
|
133
170
|
bodyLines.push(command
|
|
134
|
-
? `[${escapeMarkdown(
|
|
135
|
-
:
|
|
171
|
+
? `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})`
|
|
172
|
+
: renderInlineCommands(item.content))
|
|
136
173
|
break
|
|
137
174
|
}
|
|
138
175
|
case MessageType.error:
|
|
139
176
|
flush()
|
|
140
|
-
sections.push(`❌ 出错了!错误原因:${
|
|
177
|
+
sections.push(`❌ 出错了!错误原因:${renderInlineCommands(item.content)},请反馈至联系开发者`)
|
|
141
178
|
break
|
|
142
179
|
}
|
|
143
180
|
}
|
|
@@ -154,10 +191,7 @@ export function renderQQPageMarkdown(data: MsgMessage, showGreeting: boolean): s
|
|
|
154
191
|
const footer = pageFooter
|
|
155
192
|
? [pageFooter, previousLink, nextLink, helpLink].filter(Boolean).join('·')
|
|
156
193
|
: helpLink ? `更多操作:${helpLink}` : undefined
|
|
157
|
-
if (footer)
|
|
158
|
-
if (isLeaderboardDirectory) sections.push('***')
|
|
159
|
-
sections.push(footer)
|
|
160
|
-
}
|
|
194
|
+
if (footer) sections.push(footer)
|
|
161
195
|
return sections.join('\n\n') || ' '
|
|
162
196
|
}
|
|
163
197
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Session } from 'koishi'
|
|
2
|
+
import { MessageType } from '../../shared/face'
|
|
3
|
+
import type { MsgMessage } from '../../shared/bot/MsgMessage'
|
|
4
|
+
import { escapeMarkdown, renderInlineCommands, renderQQTitle, sendQQMarkdown } from './qqPageMessage'
|
|
5
|
+
|
|
6
|
+
export function hasStoryCodeBlock(data: Pick<MsgMessage, 'line'>): boolean {
|
|
7
|
+
return data.line.some(item => item.type === MessageType.line && item.codeBlock === true)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function fencedStory(content: string): string {
|
|
11
|
+
const story = content.replace(/\r\n?/g, '\n')
|
|
12
|
+
// A story may itself contain backticks. A longer fence keeps its entire text
|
|
13
|
+
// inside the same block without altering the source used by plain fallback.
|
|
14
|
+
const longestRun = Math.max(0, ...Array.from(story.matchAll(/`+/g), match => match[0].length))
|
|
15
|
+
const fence = '`'.repeat(Math.max(3, longestRun + 1))
|
|
16
|
+
return fence + '\n' + story + (story.endsWith('\n') ? '' : '\n') + fence
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Only marked story lines become code blocks; result summaries remain prose. */
|
|
20
|
+
export function renderQQStoryMarkdown(data: MsgMessage, showGreeting: boolean): string {
|
|
21
|
+
const sections: string[] = []
|
|
22
|
+
const bodyLines: string[] = []
|
|
23
|
+
const flushBody = () => {
|
|
24
|
+
if (bodyLines.length) sections.push(bodyLines.splice(0).join(' \n'))
|
|
25
|
+
}
|
|
26
|
+
if (showGreeting) sections.push(escapeMarkdown('Ciallo~(∠・ω< )'))
|
|
27
|
+
for (const item of data.line) {
|
|
28
|
+
switch (item.type) {
|
|
29
|
+
case MessageType.title:
|
|
30
|
+
flushBody()
|
|
31
|
+
sections.push(renderQQTitle(item.content))
|
|
32
|
+
break
|
|
33
|
+
case MessageType.line:
|
|
34
|
+
if (item.codeBlock) {
|
|
35
|
+
flushBody()
|
|
36
|
+
sections.push(fencedStory(item.content))
|
|
37
|
+
} else {
|
|
38
|
+
for (const line of item.content.replace(/\r\n?/g, '\n').split('\n')) {
|
|
39
|
+
if (!line.trim()) flushBody()
|
|
40
|
+
else bodyLines.push(renderInlineCommands(line))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
break
|
|
44
|
+
case MessageType.error:
|
|
45
|
+
flushBody()
|
|
46
|
+
sections.push('❌ 出错了!错误原因:' + renderInlineCommands(item.content) + ',请反馈至联系开发者')
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
flushBody()
|
|
51
|
+
return sections.join('\n\n') || ' '
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function sendQQStory(session: Session, data: MsgMessage): Promise<void> {
|
|
55
|
+
await sendQQMarkdown(session, renderQQStoryMarkdown(data, session.event?.channel?.type === 0))
|
|
56
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Session } from 'koishi'
|
|
2
2
|
import { MessageType } from '../../shared/face'
|
|
3
3
|
import type { MsgMessage } from '../../shared/bot/MsgMessage'
|
|
4
|
-
import { escapeMarkdown, inlineCommandUrl, sendQQMarkdown } from './qqPageMessage'
|
|
4
|
+
import { escapeMarkdown, inlineCommandUrl, renderInlineCommands, renderQQTitle, sendQQMarkdown } from './qqPageMessage'
|
|
5
5
|
|
|
6
6
|
/** Render only explicitly marked transactions; line content never enables this channel. */
|
|
7
7
|
export function renderQQTransactionMarkdown(data: MsgMessage, showGreeting: boolean): string {
|
|
@@ -19,17 +19,16 @@ export function renderQQTransactionMarkdown(data: MsgMessage, showGreeting: bool
|
|
|
19
19
|
for (const item of data.line) {
|
|
20
20
|
if (item.type === MessageType.title) {
|
|
21
21
|
flush()
|
|
22
|
-
sections.push(
|
|
22
|
+
sections.push(renderQQTitle(item.content))
|
|
23
23
|
continue
|
|
24
24
|
}
|
|
25
25
|
if (item.type === MessageType.error) {
|
|
26
26
|
flush()
|
|
27
|
-
sections.push(`❌ 出错了!错误原因:${
|
|
27
|
+
sections.push(`❌ 出错了!错误原因:${renderInlineCommands(item.content)},请反馈至联系开发者`)
|
|
28
28
|
continue
|
|
29
29
|
}
|
|
30
30
|
if (item.type !== MessageType.line) continue
|
|
31
|
-
//
|
|
32
|
-
// material text remain escaped display text rather than executable commands.
|
|
31
|
+
// Keep the common trade actions grouped; other bracketed commands render inline.
|
|
33
32
|
const action = data.transaction && (item.content === '[是]确认交易'
|
|
34
33
|
? { command: '是', label: '确认交易' }
|
|
35
34
|
: item.content === '[否]取消交易' ? { command: '否', label: '取消交易' } : undefined)
|
|
@@ -50,7 +49,7 @@ export function renderQQTransactionMarkdown(data: MsgMessage, showGreeting: bool
|
|
|
50
49
|
} else {
|
|
51
50
|
// Preserve the server's quoted amounts, names and descriptions verbatim
|
|
52
51
|
// apart from Markdown escaping; rendering never recalculates payments.
|
|
53
|
-
bodyLines.push(
|
|
52
|
+
bodyLines.push(renderInlineCommands(item.content))
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
flush()
|
|
@@ -1,21 +1,27 @@
|
|
|
1
|
+
import { MessageType } from '../../shared/face'
|
|
1
2
|
import { AnalysisMsg } from '../../shared/bot/analysisMsg'
|
|
2
3
|
import { MsgMessage } from '../../shared/bot/MsgMessage'
|
|
3
4
|
import sessions, { sessionKey } from '../sessions'
|
|
4
5
|
import handel_base from './handel_base'
|
|
5
|
-
import { canSendQQPage, pageCommandLines, sendQQPage } from './qqPageMessage'
|
|
6
|
+
import { canSendQQPage, hasInlineCommands, pageCommandLines, sendQQPage } from './qqPageMessage'
|
|
6
7
|
import { sendQQTransaction } from './qqTransactionMessage'
|
|
7
8
|
import { sendQQCommand } from './qqCommandMessage'
|
|
9
|
+
import { hasStoryCodeBlock, sendQQStory } from './qqStoryMessage'
|
|
8
10
|
|
|
9
11
|
export default class handelr_text extends handel_base {
|
|
10
12
|
async start(data: MsgMessage) {
|
|
11
13
|
const content = new AnalysisMsg().parse(data)
|
|
12
14
|
const session = sessions.get(sessionKey(data.botId, data.userId, data.channelId))
|
|
13
|
-
|
|
15
|
+
const inlineCommands = data.line.some(item => (item.type === MessageType.line || item.type === MessageType.error) && hasInlineCommands(item.content))
|
|
16
|
+
const story = hasStoryCodeBlock(data)
|
|
17
|
+
if ((story || data.commandHelp || data.transaction || data.pageNav || inlineCommands) && canSendQQPage(session, data)) {
|
|
14
18
|
const sendStartedAt = this.timing ? performance.now() : 0
|
|
15
19
|
try {
|
|
16
|
-
if (
|
|
20
|
+
if (story) await sendQQStory(session, data)
|
|
21
|
+
else if (data.commandHelp) await sendQQCommand(session, data)
|
|
17
22
|
else if (data.transaction) await sendQQTransaction(session, data)
|
|
18
|
-
else await sendQQPage(session, data)
|
|
23
|
+
else if (data.pageNav) await sendQQPage(session, data)
|
|
24
|
+
else await sendQQCommand(session, data)
|
|
19
25
|
if (this.timing) {
|
|
20
26
|
this.timing.delivery = 'qq-markdown'
|
|
21
27
|
this.timing.sendMs = performance.now() - sendStartedAt
|
|
@@ -24,7 +30,7 @@ export default class handelr_text extends handel_base {
|
|
|
24
30
|
} catch (error) {
|
|
25
31
|
this.ctx.logger.warn('QQ Markdown 发送失败,改用普通文字', error instanceof Error ? error.message : error)
|
|
26
32
|
}
|
|
27
|
-
const commands = !data.commandHelp && !data.transaction && data.pageNav ? pageCommandLines(data.pageNav) : []
|
|
33
|
+
const commands = !story && !data.commandHelp && !data.transaction && data.pageNav ? pageCommandLines(data.pageNav) : []
|
|
28
34
|
await this.send(data, commands.length ? `${content.trimEnd()}\n${commands.join('\n')}` : content)
|
|
29
35
|
return
|
|
30
36
|
}
|
|
@@ -20,7 +20,7 @@ export interface ServiceType {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export const serviceProto: ServiceProto<ServiceType> = {
|
|
23
|
-
"version":
|
|
23
|
+
"version": 14,
|
|
24
24
|
"services": [
|
|
25
25
|
{
|
|
26
26
|
"id": 0,
|
|
@@ -907,6 +907,14 @@ export const serviceProto: ServiceProto<ServiceType> = {
|
|
|
907
907
|
"type": {
|
|
908
908
|
"type": "String"
|
|
909
909
|
}
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
"id": 2,
|
|
913
|
+
"name": "codeBlock",
|
|
914
|
+
"type": {
|
|
915
|
+
"type": "Boolean"
|
|
916
|
+
},
|
|
917
|
+
"optional": true
|
|
910
918
|
}
|
|
911
919
|
]
|
|
912
920
|
},
|