koishi-plugin-onebot-info-image 0.2.0-alpha.8 → 0.3.1-beta.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/dist/index.js +1 -0
- package/dist/style.css +1 -0
- package/docs/napcat_al_flat.png +0 -0
- package/docs/napcat_aui_flat.png +0 -0
- package/lib/data_server.d.ts +37 -0
- package/lib/index.d.ts +9 -3
- package/lib/index.js +1071 -47
- package/lib/renderUserInfo.d.ts +4 -1
- package/lib/type.d.ts +4 -0
- package/package.json +10 -3
- package/readme.md +23 -7
- package/lib/renderAdminList.d.ts +0 -3
- package/lib/utils.d.ts +0 -27
package/lib/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
8
|
var __export = (target, all) => {
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -34,11 +44,15 @@ var import_path2 = require("path");
|
|
|
34
44
|
// src/type.ts
|
|
35
45
|
var IMAGE_STYLES = {
|
|
36
46
|
SOURCE_HAN_SERIF_SC: "思源宋体SourceHanSerifSC",
|
|
37
|
-
LXGW_WENKAI: "落霞孤鹜文楷LXGWWenKai"
|
|
47
|
+
LXGW_WENKAI: "落霞孤鹜文楷LXGWWenKai",
|
|
48
|
+
FLAT_MINIMAL: "扁平化简约FlatMinimal"
|
|
38
49
|
};
|
|
50
|
+
var IMAGE_STYLE_KEY_ARR = Object.keys(IMAGE_STYLES);
|
|
39
51
|
var FONT_FILES = {
|
|
40
52
|
[IMAGE_STYLES.SOURCE_HAN_SERIF_SC]: "SourceHanSerifSC-Medium.otf",
|
|
41
|
-
[IMAGE_STYLES.LXGW_WENKAI]: "LXGWWenKaiMono-Regular.ttf"
|
|
53
|
+
[IMAGE_STYLES.LXGW_WENKAI]: "LXGWWenKaiMono-Regular.ttf",
|
|
54
|
+
[IMAGE_STYLES.FLAT_MINIMAL]: "LXGWWenKaiMono-Regular.ttf"
|
|
55
|
+
// 扁平化样式使用文楷字体
|
|
42
56
|
};
|
|
43
57
|
var IMAGE_TYPES = {
|
|
44
58
|
PNG: "png",
|
|
@@ -71,8 +85,13 @@ function convertToUnifiedUserInfo(userInfo, onebotImplName) {
|
|
|
71
85
|
unfriendly: userInfo.unfriendly || false,
|
|
72
86
|
card_changeable: userInfo.card_changeable || false,
|
|
73
87
|
// Lagrange 特有字段
|
|
74
|
-
sign: userInfo.sign || "",
|
|
75
|
-
q_id: userInfo.q_id || "",
|
|
88
|
+
sign: userInfo.sign || userInfo.longNick || userInfo.long_nick || "",
|
|
89
|
+
q_id: userInfo.q_id || userInfo.qid || "",
|
|
90
|
+
// 同时支持 q_id 和 qid 两种格式
|
|
91
|
+
qid: userInfo.qid || userInfo.q_id || "",
|
|
92
|
+
// 同时支持 qid 和 q_id 两种格式
|
|
93
|
+
longNick: userInfo.longNick || userInfo.long_nick || "",
|
|
94
|
+
long_nick: userInfo.long_nick || userInfo.longNick || "",
|
|
76
95
|
RegisterTime: userInfo.RegisterTime || "",
|
|
77
96
|
Business: userInfo.Business || [],
|
|
78
97
|
status: userInfo.status || {},
|
|
@@ -348,7 +367,7 @@ var formatMsTimestamp = /* @__PURE__ */ __name((timestamp) => {
|
|
|
348
367
|
const date = new Date(timestamp);
|
|
349
368
|
return date.toLocaleString("zh-CN");
|
|
350
369
|
}, "formatMsTimestamp");
|
|
351
|
-
var getSourceHanSerifSCStyleUserInfoHtmlStr = /* @__PURE__ */ __name(async (userInfo, contextInfo, avatarBase64, groupAvatarBase64, fontBase64, enableDarkMode) => {
|
|
370
|
+
var getSourceHanSerifSCStyleUserInfoHtmlStr = /* @__PURE__ */ __name(async (userInfo, contextInfo, avatarBase64, groupAvatarBase64, fontBase64, enableDarkMode, hidePhoneNumber = true) => {
|
|
352
371
|
const timestamp = generateTimestamp();
|
|
353
372
|
const backgroundStyle = avatarBase64 ? `background-image: url(data:image/jpeg;base64,${avatarBase64});` : `background-color: #f0f2f5;`;
|
|
354
373
|
const getValue = /* @__PURE__ */ __name((value, fallback = '<span class="unknown">未知</span>') => value && value !== "-" ? value : fallback, "getValue");
|
|
@@ -397,11 +416,11 @@ var getSourceHanSerifSCStyleUserInfoHtmlStr = /* @__PURE__ */ __name(async (user
|
|
|
397
416
|
getInfoItem("性别", getSex(userInfo.sex)),
|
|
398
417
|
getInfoItem("年龄", getValue(userInfo.age)),
|
|
399
418
|
getInfoItem("QQ等级", getValue(userInfo.qq_level || userInfo.level)),
|
|
400
|
-
getInfoItem("QID", getValue(userInfo.q_id)),
|
|
419
|
+
getInfoItem("QID", getValue(userInfo.q_id || userInfo.qid)),
|
|
401
420
|
getInfoItem("注册时间", formatMsTimestamp(userInfo.RegisterTime)),
|
|
402
|
-
getInfoItem("个性签名", getValue(userInfo.sign || userInfo.longNick), true),
|
|
421
|
+
getInfoItem("个性签名", getValue(userInfo.sign || userInfo.longNick || userInfo.long_nick), true),
|
|
403
422
|
getInfoItem("邮箱", getValue(userInfo.eMail || userInfo.email)),
|
|
404
|
-
getInfoItem("电话", getValue(userInfo.phoneNum || userInfo.phone)),
|
|
423
|
+
getInfoItem("电话", hidePhoneNumber ? '<span class="unknown">已隐藏</span>' : getValue(userInfo.phoneNum || userInfo.phone)),
|
|
405
424
|
getInfoItem("地址信息", getLocationString(userInfo), true),
|
|
406
425
|
`
|
|
407
426
|
<div class="two-column-row">
|
|
@@ -528,7 +547,441 @@ var getSourceHanSerifSCStyleUserInfoHtmlStr = /* @__PURE__ */ __name(async (user
|
|
|
528
547
|
</body>
|
|
529
548
|
</html>`;
|
|
530
549
|
}, "getSourceHanSerifSCStyleUserInfoHtmlStr");
|
|
531
|
-
var
|
|
550
|
+
var getFlatMinimalUserInfoHtmlStr = /* @__PURE__ */ __name(async (userInfo, contextInfo, avatarBase64, groupAvatarBase64, fontBase64, enableDarkMode, hidePhoneNumber = true) => {
|
|
551
|
+
const isGroup = contextInfo.isGroup;
|
|
552
|
+
const isDarkMode = enableDarkMode;
|
|
553
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", {
|
|
554
|
+
year: "numeric",
|
|
555
|
+
month: "2-digit",
|
|
556
|
+
day: "2-digit",
|
|
557
|
+
hour: "2-digit",
|
|
558
|
+
minute: "2-digit",
|
|
559
|
+
second: "2-digit",
|
|
560
|
+
hour12: false
|
|
561
|
+
});
|
|
562
|
+
const colors = isDarkMode ? {
|
|
563
|
+
// 黑色背景配色:亮蓝、亮绿、亮橙
|
|
564
|
+
background: "#0a0a0a",
|
|
565
|
+
cardBackground: "#1a1a1a",
|
|
566
|
+
textPrimary: "#ffffff",
|
|
567
|
+
textSecondary: "#b0b0b0",
|
|
568
|
+
primary: "#00d4ff",
|
|
569
|
+
// 亮蓝色
|
|
570
|
+
secondary: "#00ff88",
|
|
571
|
+
// 亮绿色
|
|
572
|
+
accent: "#ff8800",
|
|
573
|
+
// 亮橙色
|
|
574
|
+
border: "#333333",
|
|
575
|
+
hover: "#2a2a2a"
|
|
576
|
+
} : {
|
|
577
|
+
// 白色背景配色:黑、蓝、灰
|
|
578
|
+
background: "#f5f7fa",
|
|
579
|
+
cardBackground: "#ffffff",
|
|
580
|
+
textPrimary: "#2c3e50",
|
|
581
|
+
// 深蓝灰
|
|
582
|
+
textSecondary: "#6c757d",
|
|
583
|
+
// 中性灰
|
|
584
|
+
primary: "#007bff",
|
|
585
|
+
// 蓝色
|
|
586
|
+
secondary: "#34495e",
|
|
587
|
+
// 深灰蓝
|
|
588
|
+
accent: "#6c757d",
|
|
589
|
+
// 灰色
|
|
590
|
+
border: "#e0e6ed",
|
|
591
|
+
hover: "#f8f9fa"
|
|
592
|
+
};
|
|
593
|
+
const getShengXiao = /* @__PURE__ */ __name((num) => ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"][num] || "", "getShengXiao");
|
|
594
|
+
const getConstellation = /* @__PURE__ */ __name((num) => ["摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座"][num - 1] || "", "getConstellation");
|
|
595
|
+
const getBloodType = /* @__PURE__ */ __name((num) => ["O", "A", "B", "AB"][num] || "", "getBloodType");
|
|
596
|
+
const formatAddress = /* @__PURE__ */ __name((user) => {
|
|
597
|
+
const parts = [user.country, user.province, user.city, user.postCode].filter((part) => part && part !== "0" && part !== "-");
|
|
598
|
+
let locationStr = parts.length > 0 ? parts.join("-") : "";
|
|
599
|
+
if (user.address && user.address !== locationStr) {
|
|
600
|
+
locationStr = locationStr ? `${locationStr} ${user.address}` : user.address;
|
|
601
|
+
}
|
|
602
|
+
return locationStr || '<span class="unknown">未知</span>';
|
|
603
|
+
}, "formatAddress");
|
|
604
|
+
const getGroupRole = /* @__PURE__ */ __name((role) => {
|
|
605
|
+
switch (role) {
|
|
606
|
+
case "owner":
|
|
607
|
+
return "群主";
|
|
608
|
+
case "admin":
|
|
609
|
+
return "管理员";
|
|
610
|
+
case "member":
|
|
611
|
+
return "成员";
|
|
612
|
+
default:
|
|
613
|
+
return '<span class="unknown">未知</span>';
|
|
614
|
+
}
|
|
615
|
+
}, "getGroupRole");
|
|
616
|
+
return `<!DOCTYPE html><html><head><style>
|
|
617
|
+
${fontBase64 ? `@font-face{font-family:'CustomFont';src:url('data:font/truetype;charset=utf-8;base64,${fontBase64}') format('truetype');font-weight:400;font-style:normal;font-display:swap;}` : ""}
|
|
618
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
619
|
+
body {
|
|
620
|
+
font-family: ${fontBase64 ? "'CustomFont'," : ""} -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", sans-serif;
|
|
621
|
+
background: ${colors.background};
|
|
622
|
+
color: ${colors.textPrimary};
|
|
623
|
+
width: 999px;
|
|
624
|
+
height: 999px;
|
|
625
|
+
display: flex;
|
|
626
|
+
align-items: center;
|
|
627
|
+
justify-content: center;
|
|
628
|
+
padding: 16px;
|
|
629
|
+
overflow: hidden;
|
|
630
|
+
}
|
|
631
|
+
.main-container {
|
|
632
|
+
width: 100%;
|
|
633
|
+
max-width: 970px;
|
|
634
|
+
height: 100%;
|
|
635
|
+
display: flex;
|
|
636
|
+
flex-direction: column;
|
|
637
|
+
gap: 10px;
|
|
638
|
+
}
|
|
639
|
+
.header {
|
|
640
|
+
background: ${colors.cardBackground};
|
|
641
|
+
border: 2px solid ${colors.border};
|
|
642
|
+
border-radius: 18px;
|
|
643
|
+
padding: 14px 20px;
|
|
644
|
+
text-align: center;
|
|
645
|
+
box-shadow: 0 4px 16px rgba(0,0,0,${isDarkMode ? "0.4" : "0.08"});
|
|
646
|
+
}
|
|
647
|
+
.title {
|
|
648
|
+
font-size: 34px;
|
|
649
|
+
font-weight: 700;
|
|
650
|
+
color: ${colors.primary};
|
|
651
|
+
margin-bottom: 4px;
|
|
652
|
+
letter-spacing: 2px;
|
|
653
|
+
}
|
|
654
|
+
.subtitle {
|
|
655
|
+
font-size: 19px;
|
|
656
|
+
color: ${colors.textSecondary};
|
|
657
|
+
font-weight: 500;
|
|
658
|
+
}
|
|
659
|
+
.content {
|
|
660
|
+
display: flex;
|
|
661
|
+
gap: 10px;
|
|
662
|
+
flex: 1;
|
|
663
|
+
min-height: 0;
|
|
664
|
+
}
|
|
665
|
+
.left-panel {
|
|
666
|
+
flex: 0 0 270px;
|
|
667
|
+
display: flex;
|
|
668
|
+
flex-direction: column;
|
|
669
|
+
gap: 10px;
|
|
670
|
+
}
|
|
671
|
+
.avatar-card {
|
|
672
|
+
background: ${colors.cardBackground};
|
|
673
|
+
border: 2px solid ${colors.border};
|
|
674
|
+
border-radius: 18px;
|
|
675
|
+
padding: 16px 14px;
|
|
676
|
+
text-align: center;
|
|
677
|
+
box-shadow: 0 4px 16px rgba(0,0,0,${isDarkMode ? "0.4" : "0.08"});
|
|
678
|
+
flex: 1;
|
|
679
|
+
display: flex;
|
|
680
|
+
flex-direction: column;
|
|
681
|
+
justify-content: center;
|
|
682
|
+
align-items: center;
|
|
683
|
+
}
|
|
684
|
+
.avatar {
|
|
685
|
+
width: 130px;
|
|
686
|
+
height: 130px;
|
|
687
|
+
border-radius: 65px;
|
|
688
|
+
object-fit: cover;
|
|
689
|
+
border: 4px solid ${colors.primary};
|
|
690
|
+
margin-bottom: 14px;
|
|
691
|
+
display: block;
|
|
692
|
+
box-shadow: 0 8px 24px rgba(0,0,0,${isDarkMode ? "0.5" : "0.15"});
|
|
693
|
+
}
|
|
694
|
+
.avatar-placeholder {
|
|
695
|
+
width: 130px;
|
|
696
|
+
height: 130px;
|
|
697
|
+
border-radius: 65px;
|
|
698
|
+
background: linear-gradient(135deg, ${colors.primary}, ${colors.secondary});
|
|
699
|
+
margin-bottom: 14px;
|
|
700
|
+
}
|
|
701
|
+
.user-name {
|
|
702
|
+
font-size: 26px;
|
|
703
|
+
font-weight: 700;
|
|
704
|
+
color: ${colors.textPrimary};
|
|
705
|
+
margin-bottom: 8px;
|
|
706
|
+
letter-spacing: 1px;
|
|
707
|
+
}
|
|
708
|
+
.user-id {
|
|
709
|
+
font-size: 17px;
|
|
710
|
+
color: ${colors.textSecondary};
|
|
711
|
+
background: ${colors.primary}25;
|
|
712
|
+
padding: 6px 12px;
|
|
713
|
+
border-radius: 12px;
|
|
714
|
+
display: inline-block;
|
|
715
|
+
font-weight: 600;
|
|
716
|
+
border: 1px solid ${colors.primary}40;
|
|
717
|
+
}
|
|
718
|
+
.group-card {
|
|
719
|
+
background: ${colors.cardBackground};
|
|
720
|
+
border: 2px solid ${colors.border};
|
|
721
|
+
border-radius: 18px;
|
|
722
|
+
padding: 12px;
|
|
723
|
+
box-shadow: 0 4px 16px rgba(0,0,0,${isDarkMode ? "0.4" : "0.08"});
|
|
724
|
+
flex: 0.618;
|
|
725
|
+
}
|
|
726
|
+
.group-header {
|
|
727
|
+
display: flex;
|
|
728
|
+
align-items: center;
|
|
729
|
+
gap: 12px;
|
|
730
|
+
margin-bottom: 12px;
|
|
731
|
+
padding-bottom: 10px;
|
|
732
|
+
border-bottom: 1px solid ${colors.border};
|
|
733
|
+
}
|
|
734
|
+
.group-avatar {
|
|
735
|
+
width: 58px;
|
|
736
|
+
height: 58px;
|
|
737
|
+
border-radius: 14px;
|
|
738
|
+
object-fit: cover;
|
|
739
|
+
border: 3px solid ${colors.secondary};
|
|
740
|
+
box-shadow: 0 4px 12px rgba(0,0,0,${isDarkMode ? "0.4" : "0.1"});
|
|
741
|
+
}
|
|
742
|
+
.group-info {
|
|
743
|
+
flex: 1;
|
|
744
|
+
}
|
|
745
|
+
.group-name {
|
|
746
|
+
font-size: 18px;
|
|
747
|
+
font-weight: 700;
|
|
748
|
+
color: ${colors.textPrimary};
|
|
749
|
+
margin-bottom: 3px;
|
|
750
|
+
}
|
|
751
|
+
.group-id {
|
|
752
|
+
font-size: 14px;
|
|
753
|
+
color: ${colors.textSecondary};
|
|
754
|
+
font-weight: 500;
|
|
755
|
+
}
|
|
756
|
+
.group-member-count {
|
|
757
|
+
font-size: 13px;
|
|
758
|
+
color: ${colors.accent};
|
|
759
|
+
margin-top: 3px;
|
|
760
|
+
font-weight: 600;
|
|
761
|
+
}
|
|
762
|
+
.group-details {
|
|
763
|
+
display: grid;
|
|
764
|
+
grid-template-columns: 1fr 1fr;
|
|
765
|
+
gap: 6px;
|
|
766
|
+
}
|
|
767
|
+
.group-detail-item {
|
|
768
|
+
text-align: center;
|
|
769
|
+
background: ${colors.background};
|
|
770
|
+
padding: 6px 4px;
|
|
771
|
+
border-radius: 10px;
|
|
772
|
+
border: 1px solid ${colors.border};
|
|
773
|
+
}
|
|
774
|
+
.group-detail-label {
|
|
775
|
+
font-size: 11px;
|
|
776
|
+
color: ${colors.textSecondary};
|
|
777
|
+
margin-bottom: 2px;
|
|
778
|
+
font-weight: 500;
|
|
779
|
+
}
|
|
780
|
+
.group-detail-value {
|
|
781
|
+
font-size: 14px;
|
|
782
|
+
color: ${colors.textPrimary};
|
|
783
|
+
font-weight: 600;
|
|
784
|
+
word-break: break-all;
|
|
785
|
+
}
|
|
786
|
+
.right-panel {
|
|
787
|
+
flex: 1;
|
|
788
|
+
display: flex;
|
|
789
|
+
flex-direction: column;
|
|
790
|
+
}
|
|
791
|
+
.info-card {
|
|
792
|
+
background: ${colors.cardBackground};
|
|
793
|
+
border: 2px solid ${colors.border};
|
|
794
|
+
border-radius: 18px;
|
|
795
|
+
padding: 16px;
|
|
796
|
+
flex: 1;
|
|
797
|
+
box-shadow: 0 4px 16px rgba(0,0,0,${isDarkMode ? "0.4" : "0.08"});
|
|
798
|
+
overflow-y: auto;
|
|
799
|
+
display: flex;
|
|
800
|
+
flex-direction: column;
|
|
801
|
+
}
|
|
802
|
+
.info-grid {
|
|
803
|
+
display: grid;
|
|
804
|
+
grid-template-columns: repeat(2, 1fr);
|
|
805
|
+
gap: 10px;
|
|
806
|
+
flex: 1;
|
|
807
|
+
align-content: start;
|
|
808
|
+
}
|
|
809
|
+
.info-item {
|
|
810
|
+
background: ${colors.background};
|
|
811
|
+
border: 1px solid ${colors.border};
|
|
812
|
+
border-radius: 10px;
|
|
813
|
+
padding: 10px 12px;
|
|
814
|
+
transition: all 0.25s ease;
|
|
815
|
+
display: flex;
|
|
816
|
+
flex-direction: column;
|
|
817
|
+
justify-content: center;
|
|
818
|
+
min-height: 52px;
|
|
819
|
+
}
|
|
820
|
+
.info-item:hover {
|
|
821
|
+
background: ${colors.hover};
|
|
822
|
+
transform: translateY(-2px);
|
|
823
|
+
box-shadow: 0 4px 16px rgba(0,0,0,${isDarkMode ? "0.5" : "0.12"});
|
|
824
|
+
border-color: ${colors.primary}50;
|
|
825
|
+
}
|
|
826
|
+
.info-item.full-width {
|
|
827
|
+
grid-column: 1 / -1;
|
|
828
|
+
}
|
|
829
|
+
.info-label {
|
|
830
|
+
font-size: 13px;
|
|
831
|
+
color: ${colors.textSecondary};
|
|
832
|
+
font-weight: 600;
|
|
833
|
+
margin-bottom: 4px;
|
|
834
|
+
text-transform: uppercase;
|
|
835
|
+
letter-spacing: 0.5px;
|
|
836
|
+
}
|
|
837
|
+
.info-value {
|
|
838
|
+
font-size: 18px;
|
|
839
|
+
color: ${colors.textPrimary};
|
|
840
|
+
font-weight: 600;
|
|
841
|
+
line-height: 1.35;
|
|
842
|
+
word-break: break-all;
|
|
843
|
+
}
|
|
844
|
+
.unknown {
|
|
845
|
+
color: ${colors.textSecondary};
|
|
846
|
+
font-style: italic;
|
|
847
|
+
opacity: 0.7;
|
|
848
|
+
}
|
|
849
|
+
.timestamp {
|
|
850
|
+
position: fixed;
|
|
851
|
+
top: 12px;
|
|
852
|
+
left: 12px;
|
|
853
|
+
font-size: 13px;
|
|
854
|
+
color: ${colors.textSecondary};
|
|
855
|
+
opacity: 0.5;
|
|
856
|
+
font-family: 'Courier New', monospace;
|
|
857
|
+
z-index: 1000;
|
|
858
|
+
}
|
|
859
|
+
.primary-accent { color: ${colors.primary}; }
|
|
860
|
+
.secondary-accent { color: ${colors.secondary}; }
|
|
861
|
+
.accent-color { color: ${colors.accent}; }
|
|
862
|
+
</style></head><body>
|
|
863
|
+
<div class="main-container">
|
|
864
|
+
<div class="header">
|
|
865
|
+
<div class="title">${isGroup ? "群员信息" : "用户信息"}</div>
|
|
866
|
+
<div class="subtitle">详细资料</div>
|
|
867
|
+
</div>
|
|
868
|
+
|
|
869
|
+
<div class="content">
|
|
870
|
+
<div class="left-panel">
|
|
871
|
+
<div class="avatar-card">
|
|
872
|
+
${avatarBase64 ? `<img class="avatar" src="data:image/jpeg;base64,${avatarBase64}" alt="用户头像">` : '<div class="avatar-placeholder"></div>'}
|
|
873
|
+
<div class="user-name">${userInfo.nickname || "未知昵称"}</div>
|
|
874
|
+
<div class="user-id">QQ: ${userInfo.user_id}</div>
|
|
875
|
+
</div>
|
|
876
|
+
|
|
877
|
+
${isGroup ? `
|
|
878
|
+
<div class="group-card">
|
|
879
|
+
<div class="group-header">
|
|
880
|
+
${groupAvatarBase64 ? `<img class="group-avatar" src="data:image/jpeg;base64,${groupAvatarBase64}" alt="群头像">` : ""}
|
|
881
|
+
<div class="group-info">
|
|
882
|
+
<div class="group-name">${contextInfo.groupName || "未知群名"}</div>
|
|
883
|
+
<div class="group-id">群号: ${contextInfo.groupId}</div>
|
|
884
|
+
${contextInfo.memberCount ? `<div class="group-member-count">成员: ${contextInfo.memberCount}${contextInfo.maxMemberCount ? `/${contextInfo.maxMemberCount}` : ""}</div>` : ""}
|
|
885
|
+
</div>
|
|
886
|
+
</div>
|
|
887
|
+
<div class="group-details">
|
|
888
|
+
<div class="group-detail-item">
|
|
889
|
+
<div class="group-detail-label">群名片</div>
|
|
890
|
+
<div class="group-detail-value">${userInfo.card || "未设置"}</div>
|
|
891
|
+
</div>
|
|
892
|
+
<div class="group-detail-item">
|
|
893
|
+
<div class="group-detail-label">群角色</div>
|
|
894
|
+
<div class="group-detail-value primary-accent">${getGroupRole(userInfo.role)}</div>
|
|
895
|
+
</div>
|
|
896
|
+
<div class="group-detail-item">
|
|
897
|
+
<div class="group-detail-label">群等级</div>
|
|
898
|
+
<div class="group-detail-value secondary-accent">${userInfo.group_level || "未知"}</div>
|
|
899
|
+
</div>
|
|
900
|
+
<div class="group-detail-item">
|
|
901
|
+
<div class="group-detail-label">专属头衔</div>
|
|
902
|
+
<div class="group-detail-value accent-color">${userInfo.title || "无"}</div>
|
|
903
|
+
</div>
|
|
904
|
+
<div class="group-detail-item">
|
|
905
|
+
<div class="group-detail-label">加群时间</div>
|
|
906
|
+
<div class="group-detail-value">${userInfo.join_time ? `${new Date(userInfo.join_time).toLocaleDateString("zh-CN")}<br>${new Date(userInfo.join_time).toLocaleTimeString("zh-CN")}` : '<span class="unknown">未知</span>'}</div>
|
|
907
|
+
</div>
|
|
908
|
+
<div class="group-detail-item">
|
|
909
|
+
<div class="group-detail-label">最后发言</div>
|
|
910
|
+
<div class="group-detail-value">${userInfo.last_sent_time ? `${new Date(userInfo.last_sent_time).toLocaleDateString("zh-CN")}<br>${new Date(userInfo.last_sent_time).toLocaleTimeString("zh-CN")}` : '<span class="unknown">未知</span>'}</div>
|
|
911
|
+
</div>
|
|
912
|
+
</div>
|
|
913
|
+
</div>
|
|
914
|
+
` : ""}
|
|
915
|
+
</div>
|
|
916
|
+
|
|
917
|
+
<div class="right-panel">
|
|
918
|
+
<div class="info-card">
|
|
919
|
+
<div class="info-grid">
|
|
920
|
+
<div class="info-item">
|
|
921
|
+
<div class="info-label">性别</div>
|
|
922
|
+
<div class="info-value">${userInfo.sex === "male" ? "男" : userInfo.sex === "female" ? "女" : '<span class="unknown">未知</span>'}</div>
|
|
923
|
+
</div>
|
|
924
|
+
<div class="info-item">
|
|
925
|
+
<div class="info-label">年龄</div>
|
|
926
|
+
<div class="info-value">${userInfo.age || '<span class="unknown">未知</span>'}</div>
|
|
927
|
+
</div>
|
|
928
|
+
<div class="info-item">
|
|
929
|
+
<div class="info-label">QQ等级</div>
|
|
930
|
+
<div class="info-value primary-accent">${userInfo.qq_level || userInfo.level || '<span class="unknown">未知</span>'}</div>
|
|
931
|
+
</div>
|
|
932
|
+
<div class="info-item">
|
|
933
|
+
<div class="info-label">QID</div>
|
|
934
|
+
<div class="info-value">${userInfo.q_id || userInfo.qid || '<span class="unknown">未知</span>'}</div>
|
|
935
|
+
</div>
|
|
936
|
+
${userInfo.sign || userInfo.longNick || userInfo.long_nick ? `
|
|
937
|
+
<div class="info-item full-width">
|
|
938
|
+
<div class="info-label">个性签名</div>
|
|
939
|
+
<div class="info-value">${userInfo.sign || userInfo.longNick || userInfo.long_nick}</div>
|
|
940
|
+
</div>
|
|
941
|
+
` : ""}
|
|
942
|
+
${userInfo.RegisterTime ? `
|
|
943
|
+
<div class="info-item full-width">
|
|
944
|
+
<div class="info-label">注册时间</div>
|
|
945
|
+
<div class="info-value">${new Date(userInfo.RegisterTime).toLocaleString("zh-CN")}</div>
|
|
946
|
+
</div>
|
|
947
|
+
` : ""}
|
|
948
|
+
<div class="info-item full-width">
|
|
949
|
+
<div class="info-label">邮箱</div>
|
|
950
|
+
<div class="info-value">${(userInfo.eMail || userInfo.email) && userInfo.eMail !== "-" ? userInfo.eMail || userInfo.email : '<span class="unknown">未知</span>'}</div>
|
|
951
|
+
</div>
|
|
952
|
+
<div class="info-item full-width">
|
|
953
|
+
<div class="info-label">电话</div>
|
|
954
|
+
<div class="info-value">${hidePhoneNumber ? '<span class="unknown">已隐藏</span>' : userInfo.phoneNum && userInfo.phoneNum !== "-" ? userInfo.phoneNum : '<span class="unknown">未知</span>'}</div>
|
|
955
|
+
</div>
|
|
956
|
+
<div class="info-item full-width">
|
|
957
|
+
<div class="info-label">地址信息</div>
|
|
958
|
+
<div class="info-value">${formatAddress(userInfo)}</div>
|
|
959
|
+
</div>
|
|
960
|
+
<div class="info-item full-width">
|
|
961
|
+
<div class="info-label">个人特征</div>
|
|
962
|
+
<div class="info-value">生肖: ${getShengXiao(userInfo.shengXiao) || '<span class="unknown">未知</span>'} | 星座: ${getConstellation(userInfo.constellation) || '<span class="unknown">未知</span>'} | 血型: ${getBloodType(userInfo.kBloodType) ? `${getBloodType(userInfo.kBloodType)}型` : '<span class="unknown">未知</span>'}</div>
|
|
963
|
+
</div>
|
|
964
|
+
<div class="info-item full-width">
|
|
965
|
+
<div class="info-label">生日</div>
|
|
966
|
+
<div class="info-value">${userInfo.birthday_year && userInfo.birthday_month && userInfo.birthday_day ? `${userInfo.birthday_year}年${userInfo.birthday_month}月${userInfo.birthday_day}日` : '<span class="unknown">未知</span>'}</div>
|
|
967
|
+
</div>
|
|
968
|
+
<div class="info-item full-width">
|
|
969
|
+
<div class="info-label">VIP信息</div>
|
|
970
|
+
<div class="info-value">VIP: ${userInfo.is_vip ? "是" : "否"} | 年费VIP: ${userInfo.is_years_vip ? "是" : "否"} | VIP等级: ${userInfo.vip_level || 0}</div>
|
|
971
|
+
</div>
|
|
972
|
+
<div class="info-item full-width">
|
|
973
|
+
<div class="info-label">状态</div>
|
|
974
|
+
<div class="info-value">${userInfo.status && userInfo.status.message || '<span class="unknown">未知</span>'}</div>
|
|
975
|
+
</div>
|
|
976
|
+
</div>
|
|
977
|
+
</div>
|
|
978
|
+
</div>
|
|
979
|
+
</div>
|
|
980
|
+
</div>
|
|
981
|
+
<div class="timestamp">${timestamp}</div>
|
|
982
|
+
</body></html>`;
|
|
983
|
+
}, "getFlatMinimalUserInfoHtmlStr");
|
|
984
|
+
var getLXGWWenKaiUserInfoHtmlStr = /* @__PURE__ */ __name(async (userInfo, contextInfo, avatarBase64, groupAvatarBase64, fontBase64, enableDarkMode, hidePhoneNumber = true) => {
|
|
532
985
|
const isGroup = contextInfo.isGroup;
|
|
533
986
|
const isDarkMode = enableDarkMode;
|
|
534
987
|
const timestamp = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", {
|
|
@@ -650,11 +1103,11 @@ ${contextInfo.memberCount ? `<div class="group-member-count">群人数: ${contex
|
|
|
650
1103
|
<div class="info-card"><div class="info-label">性别</div><div class="info-value">${userInfo.sex === "male" ? "男" : userInfo.sex === "female" ? "女" : "未知"}</div></div>
|
|
651
1104
|
<div class="info-card"><div class="info-label">年龄</div><div class="info-value">${userInfo.age || '<span class="unknown">未知</span>'}</div></div>
|
|
652
1105
|
<div class="info-card"><div class="info-label">QQ等级</div><div class="info-value">${userInfo.qq_level || userInfo.level || '<span class="unknown">未知</span>'}</div></div>
|
|
653
|
-
<div class="info-card"><div class="info-label">QID</div><div class="info-value">${userInfo.q_id || '<span class="unknown">未知</span>'}</div></div>
|
|
654
|
-
${userInfo.sign || userInfo.longNick ? `<div class="info-card full-width"><div class="info-label">个性签名</div><div class="info-value">${userInfo.sign || userInfo.longNick}</div></div>` : ""}
|
|
1106
|
+
<div class="info-card"><div class="info-label">QID</div><div class="info-value">${userInfo.q_id || userInfo.qid || '<span class="unknown">未知</span>'}</div></div>
|
|
1107
|
+
${userInfo.sign || userInfo.longNick || userInfo.long_nick ? `<div class="info-card full-width"><div class="info-label">个性签名</div><div class="info-value">${userInfo.sign || userInfo.longNick || userInfo.long_nick}</div></div>` : ""}
|
|
655
1108
|
${userInfo.RegisterTime ? `<div class="info-card full-width"><div class="info-label">注册时间</div><div class="info-value">${new Date(userInfo.RegisterTime).toLocaleString("zh-CN")}</div></div>` : ""}
|
|
656
1109
|
<div class="info-card"><div class="info-label">邮箱</div><div class="info-value">${(userInfo.eMail || userInfo.email) && userInfo.eMail !== "-" ? userInfo.eMail || userInfo.email : '<span class="unknown">未知</span>'}</div></div>
|
|
657
|
-
<div class="info-card"><div class="info-label">电话</div><div class="info-value">${userInfo.phoneNum && userInfo.phoneNum !== "-" ? userInfo.phoneNum : '<span class="unknown">未知</span>'}</div></div>
|
|
1110
|
+
<div class="info-card"><div class="info-label">电话</div><div class="info-value">${hidePhoneNumber ? '<span class="unknown">已隐藏</span>' : userInfo.phoneNum && userInfo.phoneNum !== "-" ? userInfo.phoneNum : '<span class="unknown">未知</span>'}</div></div>
|
|
658
1111
|
<div class="info-card full-width"><div class="info-label">地址信息</div><div class="info-value">${formatAddress(userInfo)}</div></div>
|
|
659
1112
|
<div class="info-card full-width"><div class="info-label">个人特征</div><div class="info-value multi-info-row">
|
|
660
1113
|
<div class="multi-info-item"><div class="info-label">生肖</div><div class="info-value">${getShengXiao(userInfo.shengXiao) || '<span class="unknown">未知</span>'}</div></div>
|
|
@@ -675,7 +1128,7 @@ ${userInfo.RegisterTime ? `<div class="info-card full-width"><div class="info-la
|
|
|
675
1128
|
<div class="timestamp-watermark">${timestamp}</div>
|
|
676
1129
|
</body></html>`;
|
|
677
1130
|
}, "getLXGWWenKaiUserInfoHtmlStr");
|
|
678
|
-
async function renderUserInfo(ctx, userInfo, contextInfo, imageStyle, enableDarkMode, imageType, screenshotQuality) {
|
|
1131
|
+
async function renderUserInfo(ctx, userInfo, contextInfo, imageStyle, enableDarkMode, imageType, screenshotQuality, hidePhoneNumber = true) {
|
|
679
1132
|
const browserPage = await ctx.puppeteer.page();
|
|
680
1133
|
let avatarBase64;
|
|
681
1134
|
let groupAvatarBase64;
|
|
@@ -699,9 +1152,11 @@ async function renderUserInfo(ctx, userInfo, contextInfo, imageStyle, enableDark
|
|
|
699
1152
|
}
|
|
700
1153
|
let htmlContent;
|
|
701
1154
|
if (imageStyle === IMAGE_STYLES.SOURCE_HAN_SERIF_SC) {
|
|
702
|
-
htmlContent = await getSourceHanSerifSCStyleUserInfoHtmlStr(userInfo, contextInfo, avatarBase64 || "", groupAvatarBase64 || "", fontBase64 || "", enableDarkMode);
|
|
1155
|
+
htmlContent = await getSourceHanSerifSCStyleUserInfoHtmlStr(userInfo, contextInfo, avatarBase64 || "", groupAvatarBase64 || "", fontBase64 || "", enableDarkMode, hidePhoneNumber);
|
|
703
1156
|
} else if (imageStyle === IMAGE_STYLES.LXGW_WENKAI) {
|
|
704
|
-
htmlContent = await getLXGWWenKaiUserInfoHtmlStr(userInfo, contextInfo, avatarBase64 || "", groupAvatarBase64 || "", fontBase64 || "", enableDarkMode);
|
|
1157
|
+
htmlContent = await getLXGWWenKaiUserInfoHtmlStr(userInfo, contextInfo, avatarBase64 || "", groupAvatarBase64 || "", fontBase64 || "", enableDarkMode, hidePhoneNumber);
|
|
1158
|
+
} else if (imageStyle === IMAGE_STYLES.FLAT_MINIMAL) {
|
|
1159
|
+
htmlContent = await getFlatMinimalUserInfoHtmlStr(userInfo, contextInfo, avatarBase64 || "", groupAvatarBase64 || "", fontBase64 || "", enableDarkMode, hidePhoneNumber);
|
|
705
1160
|
}
|
|
706
1161
|
await browserPage.setViewport({
|
|
707
1162
|
width: 999,
|
|
@@ -714,8 +1169,8 @@ async function renderUserInfo(ctx, userInfo, contextInfo, imageStyle, enableDark
|
|
|
714
1169
|
const images = Array.from(document.querySelectorAll("img"));
|
|
715
1170
|
await Promise.all(images.map((img) => {
|
|
716
1171
|
if (img.complete) return;
|
|
717
|
-
return new Promise((
|
|
718
|
-
img.addEventListener("load",
|
|
1172
|
+
return new Promise((resolve3, reject) => {
|
|
1173
|
+
img.addEventListener("load", resolve3);
|
|
719
1174
|
img.addEventListener("error", reject);
|
|
720
1175
|
});
|
|
721
1176
|
}));
|
|
@@ -1041,6 +1496,325 @@ var getLXGWWenKaiAdminListHtmlStr = /* @__PURE__ */ __name(async (admins, contex
|
|
|
1041
1496
|
</body>
|
|
1042
1497
|
</html>`;
|
|
1043
1498
|
}, "getLXGWWenKaiAdminListHtmlStr");
|
|
1499
|
+
var getFlatMinimalAdminListHtmlStr = /* @__PURE__ */ __name(async (admins, contextInfo, groupAvatarBase64, fontBase64, enableDarkMode) => {
|
|
1500
|
+
const isDarkMode = enableDarkMode;
|
|
1501
|
+
const timestamp = generateTimestamp();
|
|
1502
|
+
const colors = isDarkMode ? {
|
|
1503
|
+
// 深色模式:亮蓝、灰色系
|
|
1504
|
+
background: "#000000",
|
|
1505
|
+
cardBackground: "#1a1a1a",
|
|
1506
|
+
textPrimary: "#ffffff",
|
|
1507
|
+
textSecondary: "#b0b0b0",
|
|
1508
|
+
primary: "#00d4ff",
|
|
1509
|
+
// 亮蓝色
|
|
1510
|
+
secondary: "#6c757d",
|
|
1511
|
+
// 灰色
|
|
1512
|
+
accent: "#00ff88",
|
|
1513
|
+
// 亮绿色
|
|
1514
|
+
border: "#333333",
|
|
1515
|
+
hover: "#2a2a2a",
|
|
1516
|
+
ownerBg: "rgba(255,140,0,0.2)",
|
|
1517
|
+
ownerText: "#ffa07a",
|
|
1518
|
+
adminBg: "rgba(0,212,255,0.2)",
|
|
1519
|
+
adminText: "#4da6ff"
|
|
1520
|
+
} : {
|
|
1521
|
+
// 浅色模式:蓝色、黑白灰
|
|
1522
|
+
background: "#f5f7fa",
|
|
1523
|
+
cardBackground: "#ffffff",
|
|
1524
|
+
textPrimary: "#2c3e50",
|
|
1525
|
+
textSecondary: "#6c757d",
|
|
1526
|
+
primary: "#007bff",
|
|
1527
|
+
// 蓝色
|
|
1528
|
+
secondary: "#34495e",
|
|
1529
|
+
// 深灰蓝
|
|
1530
|
+
accent: "#28a745",
|
|
1531
|
+
// 绿色
|
|
1532
|
+
border: "#dee2e6",
|
|
1533
|
+
hover: "#f8f9fa",
|
|
1534
|
+
ownerBg: "rgba(255,140,0,0.1)",
|
|
1535
|
+
ownerText: "#ff8c00",
|
|
1536
|
+
adminBg: "rgba(0,123,255,0.1)",
|
|
1537
|
+
adminText: "#007bff"
|
|
1538
|
+
};
|
|
1539
|
+
const flatAdminListItems = admins.map((admin, index) => `
|
|
1540
|
+
<div class="admin-item">
|
|
1541
|
+
<div class="admin-number">${(index + 1).toString().padStart(2, "0")}</div>
|
|
1542
|
+
<div class="admin-avatar-wrapper">
|
|
1543
|
+
<img src="${admin.avatar || `https://q1.qlogo.cn/g?b=qq&nk=${admin.user_id}&s=640`}" alt="头像" class="admin-avatar" />
|
|
1544
|
+
</div>
|
|
1545
|
+
<div class="admin-info">
|
|
1546
|
+
<div class="admin-name">${admin.nickname || "未知"}</div>
|
|
1547
|
+
<div class="admin-id">
|
|
1548
|
+
<span class="admin-id-label">QQ:</span>
|
|
1549
|
+
<span class="admin-id-value">${admin.user_id}</span>
|
|
1550
|
+
</div>
|
|
1551
|
+
${admin.card ? `<div class="admin-card"><span class="admin-card-label">群昵称:</span>${admin.card}</div>` : '<div class="admin-card-empty">无群昵称</div>'}
|
|
1552
|
+
</div>
|
|
1553
|
+
<div class="admin-role ${admin.role}">${admin.role === "owner" ? "群 主" : "管理员"}</div>
|
|
1554
|
+
</div>
|
|
1555
|
+
`).join("");
|
|
1556
|
+
return `<!DOCTYPE html>
|
|
1557
|
+
<html>
|
|
1558
|
+
<head>
|
|
1559
|
+
<style>
|
|
1560
|
+
${fontBase64 ? `@font-face { font-family: 'CustomFont'; src: url('data:font/opentype;charset=utf-8;base64,${fontBase64}') format('opentype'); font-weight: normal; font-style: normal; font-display: swap; }` : ""}
|
|
1561
|
+
|
|
1562
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1563
|
+
|
|
1564
|
+
html, body { margin: 0; padding: 0; width: 100%; height: auto; }
|
|
1565
|
+
|
|
1566
|
+
body {
|
|
1567
|
+
font-family: ${fontBase64 ? "'CustomFont'," : ""} -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", sans-serif;
|
|
1568
|
+
width: 800px;
|
|
1569
|
+
min-height: 100vh;
|
|
1570
|
+
background: ${colors.background};
|
|
1571
|
+
color: ${colors.textPrimary};
|
|
1572
|
+
padding: 40px;
|
|
1573
|
+
display: flex;
|
|
1574
|
+
align-items: center;
|
|
1575
|
+
justify-content: center;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
.container {
|
|
1579
|
+
width: 100%;
|
|
1580
|
+
max-width: 720px;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
.header {
|
|
1584
|
+
background: ${colors.cardBackground};
|
|
1585
|
+
border: 2px solid ${colors.border};
|
|
1586
|
+
border-radius: 20px;
|
|
1587
|
+
padding: 32px;
|
|
1588
|
+
margin-bottom: 24px;
|
|
1589
|
+
box-shadow: 0 4px 16px rgba(0,0,0,${isDarkMode ? "0.3" : "0.08"});
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
.group-info-wrapper {
|
|
1593
|
+
display: flex;
|
|
1594
|
+
align-items: center;
|
|
1595
|
+
gap: 24px;
|
|
1596
|
+
margin-bottom: 24px;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
.group-avatar {
|
|
1600
|
+
width: 90px;
|
|
1601
|
+
height: 90px;
|
|
1602
|
+
border-radius: 16px;
|
|
1603
|
+
object-fit: cover;
|
|
1604
|
+
border: 3px solid ${colors.primary};
|
|
1605
|
+
box-shadow: 0 4px 12px rgba(0,0,0,${isDarkMode ? "0.3" : "0.1"});
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
.group-details {
|
|
1609
|
+
flex: 1;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
.group-name {
|
|
1613
|
+
font-size: 26px;
|
|
1614
|
+
font-weight: 700;
|
|
1615
|
+
color: ${colors.textPrimary};
|
|
1616
|
+
margin-bottom: 8px;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
.group-meta {
|
|
1620
|
+
font-size: 16px;
|
|
1621
|
+
color: ${colors.textSecondary};
|
|
1622
|
+
line-height: 1.6;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
.group-meta-item {
|
|
1626
|
+
display: inline-block;
|
|
1627
|
+
margin-right: 16px;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
.group-meta-label {
|
|
1631
|
+
color: ${colors.textSecondary};
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
.group-meta-value {
|
|
1635
|
+
color: ${colors.primary};
|
|
1636
|
+
font-weight: 600;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
.title {
|
|
1640
|
+
font-size: 32px;
|
|
1641
|
+
font-weight: 700;
|
|
1642
|
+
color: ${colors.primary};
|
|
1643
|
+
text-align: center;
|
|
1644
|
+
padding-bottom: 16px;
|
|
1645
|
+
border-bottom: 2px solid ${colors.border};
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
.title-count {
|
|
1649
|
+
color: ${colors.accent};
|
|
1650
|
+
font-size: 24px;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
.admin-list {
|
|
1654
|
+
display: flex;
|
|
1655
|
+
flex-direction: column;
|
|
1656
|
+
gap: 16px;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
.admin-item {
|
|
1660
|
+
background: ${colors.cardBackground};
|
|
1661
|
+
border: 2px solid ${colors.border};
|
|
1662
|
+
border-radius: 16px;
|
|
1663
|
+
padding: 20px;
|
|
1664
|
+
display: flex;
|
|
1665
|
+
align-items: center;
|
|
1666
|
+
gap: 20px;
|
|
1667
|
+
transition: all 0.3s ease;
|
|
1668
|
+
box-shadow: 0 2px 8px rgba(0,0,0,${isDarkMode ? "0.2" : "0.05"});
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
.admin-item:hover {
|
|
1672
|
+
transform: translateY(-2px);
|
|
1673
|
+
box-shadow: 0 6px 20px rgba(0,0,0,${isDarkMode ? "0.4" : "0.12"});
|
|
1674
|
+
border-color: ${colors.primary};
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
.admin-number {
|
|
1678
|
+
font-size: 32px;
|
|
1679
|
+
font-weight: 700;
|
|
1680
|
+
color: ${colors.textSecondary};
|
|
1681
|
+
font-family: 'Courier New', monospace;
|
|
1682
|
+
min-width: 50px;
|
|
1683
|
+
text-align: center;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
.admin-avatar-wrapper {
|
|
1687
|
+
position: relative;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.admin-avatar {
|
|
1691
|
+
width: 80px;
|
|
1692
|
+
height: 80px;
|
|
1693
|
+
border-radius: 50%;
|
|
1694
|
+
object-fit: cover;
|
|
1695
|
+
border: 3px solid ${colors.border};
|
|
1696
|
+
transition: border-color 0.3s ease;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
.admin-item:hover .admin-avatar {
|
|
1700
|
+
border-color: ${colors.primary};
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
.admin-info {
|
|
1704
|
+
flex: 1;
|
|
1705
|
+
display: flex;
|
|
1706
|
+
flex-direction: column;
|
|
1707
|
+
gap: 8px;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
.admin-name {
|
|
1711
|
+
font-size: 20px;
|
|
1712
|
+
font-weight: 600;
|
|
1713
|
+
color: ${colors.textPrimary};
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
.admin-id {
|
|
1717
|
+
font-size: 14px;
|
|
1718
|
+
color: ${colors.textSecondary};
|
|
1719
|
+
font-family: 'Courier New', monospace;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
.admin-id-label {
|
|
1723
|
+
color: ${colors.textSecondary};
|
|
1724
|
+
font-weight: 500;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
.admin-id-value {
|
|
1728
|
+
color: ${colors.primary};
|
|
1729
|
+
font-weight: 600;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
.admin-card {
|
|
1733
|
+
font-size: 15px;
|
|
1734
|
+
color: ${colors.textPrimary};
|
|
1735
|
+
padding: 6px 12px;
|
|
1736
|
+
background: ${colors.hover};
|
|
1737
|
+
border-radius: 8px;
|
|
1738
|
+
display: inline-block;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
.admin-card-label {
|
|
1742
|
+
color: ${colors.textSecondary};
|
|
1743
|
+
font-weight: 500;
|
|
1744
|
+
margin-right: 8px;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
.admin-card-empty {
|
|
1748
|
+
font-size: 14px;
|
|
1749
|
+
color: ${colors.textSecondary};
|
|
1750
|
+
font-style: italic;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
.admin-role {
|
|
1754
|
+
font-size: 16px;
|
|
1755
|
+
font-weight: 700;
|
|
1756
|
+
padding: 10px 20px;
|
|
1757
|
+
border-radius: 12px;
|
|
1758
|
+
text-align: center;
|
|
1759
|
+
min-width: 90px;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
.admin-role.owner {
|
|
1763
|
+
background: ${colors.ownerBg};
|
|
1764
|
+
color: ${colors.ownerText};
|
|
1765
|
+
border: 2px solid ${colors.ownerText};
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
.admin-role.admin {
|
|
1769
|
+
background: ${colors.adminBg};
|
|
1770
|
+
color: ${colors.adminText};
|
|
1771
|
+
border: 2px solid ${colors.adminText};
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
.timestamp {
|
|
1775
|
+
position: fixed;
|
|
1776
|
+
top: 8px;
|
|
1777
|
+
left: 8px;
|
|
1778
|
+
font-size: 12px;
|
|
1779
|
+
color: ${colors.textSecondary};
|
|
1780
|
+
opacity: 0.6;
|
|
1781
|
+
font-family: 'Courier New', monospace;
|
|
1782
|
+
z-index: 1000;
|
|
1783
|
+
}
|
|
1784
|
+
</style>
|
|
1785
|
+
</head>
|
|
1786
|
+
<body>
|
|
1787
|
+
<div class="container">
|
|
1788
|
+
<div class="header">
|
|
1789
|
+
<div class="group-info-wrapper">
|
|
1790
|
+
<img src="data:image/jpeg;base64,${groupAvatarBase64}" alt="群头像" class="group-avatar" />
|
|
1791
|
+
<div class="group-details">
|
|
1792
|
+
<div class="group-name">${contextInfo.groupName || "未知群聊"}</div>
|
|
1793
|
+
<div class="group-meta">
|
|
1794
|
+
<span class="group-meta-item">
|
|
1795
|
+
<span class="group-meta-label">群号:</span>
|
|
1796
|
+
<span class="group-meta-value">${contextInfo.groupId}</span>
|
|
1797
|
+
</span>
|
|
1798
|
+
<span class="group-meta-item">
|
|
1799
|
+
<span class="group-meta-label">成员:</span>
|
|
1800
|
+
<span class="group-meta-value">${contextInfo.memberCount}/${contextInfo.maxMemberCount}</span>
|
|
1801
|
+
</span>
|
|
1802
|
+
</div>
|
|
1803
|
+
</div>
|
|
1804
|
+
</div>
|
|
1805
|
+
<div class="title">
|
|
1806
|
+
群管理员列表 <span class="title-count">(${admins.length}人)</span>
|
|
1807
|
+
</div>
|
|
1808
|
+
</div>
|
|
1809
|
+
|
|
1810
|
+
<div class="admin-list">
|
|
1811
|
+
${flatAdminListItems}
|
|
1812
|
+
</div>
|
|
1813
|
+
</div>
|
|
1814
|
+
<div class="timestamp">${timestamp}</div>
|
|
1815
|
+
</body>
|
|
1816
|
+
</html>`;
|
|
1817
|
+
}, "getFlatMinimalAdminListHtmlStr");
|
|
1044
1818
|
async function renderAdminList(ctx, admins, contextInfo, imageStyle, enableDarkMode, imageType, screenshotQuality) {
|
|
1045
1819
|
const browserPage = await ctx.puppeteer.page();
|
|
1046
1820
|
admins.sort((a, b) => {
|
|
@@ -1070,6 +1844,14 @@ async function renderAdminList(ctx, admins, contextInfo, imageStyle, enableDarkM
|
|
|
1070
1844
|
fontBase64,
|
|
1071
1845
|
enableDarkMode
|
|
1072
1846
|
);
|
|
1847
|
+
} else if (imageStyle === IMAGE_STYLES.FLAT_MINIMAL) {
|
|
1848
|
+
htmlContent = await getFlatMinimalAdminListHtmlStr(
|
|
1849
|
+
admins,
|
|
1850
|
+
contextInfo,
|
|
1851
|
+
groupAvatarBase64,
|
|
1852
|
+
fontBase64,
|
|
1853
|
+
enableDarkMode
|
|
1854
|
+
);
|
|
1073
1855
|
} else {
|
|
1074
1856
|
throw new Error(`不支持的图片样式: ${imageStyle}`);
|
|
1075
1857
|
}
|
|
@@ -1077,8 +1859,8 @@ async function renderAdminList(ctx, admins, contextInfo, imageStyle, enableDarkM
|
|
|
1077
1859
|
await browserPage.waitForSelector("body", { timeout: 15e3 });
|
|
1078
1860
|
await browserPage.evaluate(() => {
|
|
1079
1861
|
const images = Array.from(document.querySelectorAll("img"));
|
|
1080
|
-
return Promise.all(images.filter((img) => !img.complete).map((img) => new Promise((
|
|
1081
|
-
img.onload = img.onerror =
|
|
1862
|
+
return Promise.all(images.filter((img) => !img.complete).map((img) => new Promise((resolve3) => {
|
|
1863
|
+
img.onload = img.onerror = resolve3;
|
|
1082
1864
|
})));
|
|
1083
1865
|
});
|
|
1084
1866
|
const bodyElement = await browserPage.$("body");
|
|
@@ -1103,6 +1885,144 @@ async function renderAdminList(ctx, admins, contextInfo, imageStyle, enableDarkM
|
|
|
1103
1885
|
}
|
|
1104
1886
|
__name(renderAdminList, "renderAdminList");
|
|
1105
1887
|
|
|
1888
|
+
// src/data_server.ts
|
|
1889
|
+
var import_plugin_console = require("@koishijs/plugin-console");
|
|
1890
|
+
var path = __toESM(require("path"));
|
|
1891
|
+
var OnebotInfoImageDataServer = class extends import_plugin_console.DataService {
|
|
1892
|
+
static {
|
|
1893
|
+
__name(this, "OnebotInfoImageDataServer");
|
|
1894
|
+
}
|
|
1895
|
+
fontsBase64 = {
|
|
1896
|
+
sourceHanSerif: "",
|
|
1897
|
+
lxgwWenKai: ""
|
|
1898
|
+
};
|
|
1899
|
+
fontLoaded = false;
|
|
1900
|
+
currentTemplate = "sourceHanSerif";
|
|
1901
|
+
currentFont = "sourceHanSerif";
|
|
1902
|
+
currentDarkMode = true;
|
|
1903
|
+
static inject = ["console"];
|
|
1904
|
+
constructor(ctx) {
|
|
1905
|
+
super(ctx, "onebot-info-image", { immediate: true });
|
|
1906
|
+
this.loadFonts();
|
|
1907
|
+
ctx.console.addEntry({
|
|
1908
|
+
dev: path.resolve(__dirname, "../client/index.ts"),
|
|
1909
|
+
prod: path.resolve(__dirname, "../dist")
|
|
1910
|
+
});
|
|
1911
|
+
ctx.console.addListener("onebot-info-image/refresh", async () => {
|
|
1912
|
+
await this.refresh();
|
|
1913
|
+
}, { authority: 0 });
|
|
1914
|
+
ctx.console.addListener("onebot-info-image/setTemplate", async (template) => {
|
|
1915
|
+
this.currentTemplate = template;
|
|
1916
|
+
await this.refresh();
|
|
1917
|
+
}, { authority: 0 });
|
|
1918
|
+
ctx.console.addListener("onebot-info-image/setFont", async (font) => {
|
|
1919
|
+
this.currentFont = font;
|
|
1920
|
+
await this.refresh();
|
|
1921
|
+
}, { authority: 0 });
|
|
1922
|
+
ctx.console.addListener("onebot-info-image/setDarkMode", async (darkMode) => {
|
|
1923
|
+
this.currentDarkMode = darkMode;
|
|
1924
|
+
await this.refresh();
|
|
1925
|
+
}, { authority: 0 });
|
|
1926
|
+
ctx.on("bot-status-updated", async () => {
|
|
1927
|
+
await this.refresh();
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
async loadFonts() {
|
|
1931
|
+
try {
|
|
1932
|
+
await validateFonts(this.ctx);
|
|
1933
|
+
this.fontsBase64.sourceHanSerif = await getFontBase64(this.ctx, IMAGE_STYLES.SOURCE_HAN_SERIF_SC);
|
|
1934
|
+
this.fontsBase64.lxgwWenKai = await getFontBase64(this.ctx, IMAGE_STYLES.LXGW_WENKAI);
|
|
1935
|
+
this.fontLoaded = true;
|
|
1936
|
+
this.ctx.logger("onebot-info-image").info("字体加载完成");
|
|
1937
|
+
await this.refresh();
|
|
1938
|
+
} catch (e) {
|
|
1939
|
+
this.ctx.logger("onebot-info-image").warn("加载字体失败:", e);
|
|
1940
|
+
this.fontLoaded = true;
|
|
1941
|
+
await this.refresh();
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
getHtmlGenerator(template) {
|
|
1945
|
+
switch (template) {
|
|
1946
|
+
case "sourceHanSerif":
|
|
1947
|
+
return getSourceHanSerifSCStyleUserInfoHtmlStr;
|
|
1948
|
+
case "flatMinimal":
|
|
1949
|
+
return getFlatMinimalUserInfoHtmlStr;
|
|
1950
|
+
case "lxgwWenKai":
|
|
1951
|
+
return getLXGWWenKaiUserInfoHtmlStr;
|
|
1952
|
+
default:
|
|
1953
|
+
return getSourceHanSerifSCStyleUserInfoHtmlStr;
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
async get() {
|
|
1957
|
+
try {
|
|
1958
|
+
if (!this.fontLoaded) {
|
|
1959
|
+
return {
|
|
1960
|
+
status: "loading",
|
|
1961
|
+
msg: "正在加载字体..."
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
const onebotBot = this.ctx.bots.find((b) => b.platform === "onebot");
|
|
1965
|
+
if (!onebotBot) {
|
|
1966
|
+
return {
|
|
1967
|
+
status: "no_bot",
|
|
1968
|
+
msg: "未找到 OneBot 平台的机器人"
|
|
1969
|
+
};
|
|
1970
|
+
}
|
|
1971
|
+
const selfId = onebotBot.selfId;
|
|
1972
|
+
const loginInfo = await onebotBot.internal.getLoginInfo();
|
|
1973
|
+
const strangerInfo = await onebotBot.internal.getStrangerInfo(Number(selfId));
|
|
1974
|
+
const avatarUrl = `https://q.qlogo.cn/headimg_dl?dst_uin=${selfId}&spec=640&img_type=jpg`;
|
|
1975
|
+
let avatarBase64 = "";
|
|
1976
|
+
try {
|
|
1977
|
+
const response = await this.ctx.http.get(avatarUrl, { responseType: "arraybuffer" });
|
|
1978
|
+
avatarBase64 = Buffer.from(response).toString("base64");
|
|
1979
|
+
} catch (e) {
|
|
1980
|
+
this.ctx.logger("onebot-info-image").warn("获取头像失败:", e);
|
|
1981
|
+
}
|
|
1982
|
+
const userInfo = {
|
|
1983
|
+
user_id: selfId,
|
|
1984
|
+
nickname: loginInfo.nickname || strangerInfo.nickname,
|
|
1985
|
+
sex: strangerInfo.sex || "",
|
|
1986
|
+
age: strangerInfo.age || 0,
|
|
1987
|
+
sign: strangerInfo.sign,
|
|
1988
|
+
level: strangerInfo.level,
|
|
1989
|
+
login_days: strangerInfo.login_days,
|
|
1990
|
+
qid: strangerInfo.qid
|
|
1991
|
+
};
|
|
1992
|
+
const contextInfo = {
|
|
1993
|
+
isGroup: false
|
|
1994
|
+
};
|
|
1995
|
+
const fontBase64 = this.fontsBase64[this.currentFont] || "";
|
|
1996
|
+
const htmlGenerator = this.getHtmlGenerator(this.currentTemplate);
|
|
1997
|
+
const htmlContent = await htmlGenerator(
|
|
1998
|
+
userInfo,
|
|
1999
|
+
contextInfo,
|
|
2000
|
+
avatarBase64,
|
|
2001
|
+
"",
|
|
2002
|
+
fontBase64,
|
|
2003
|
+
this.currentDarkMode,
|
|
2004
|
+
// 使用当前选择的主题模式
|
|
2005
|
+
true
|
|
2006
|
+
// hidePhoneNumber: 预览中默认隐藏手机号
|
|
2007
|
+
);
|
|
2008
|
+
return {
|
|
2009
|
+
status: "loaded",
|
|
2010
|
+
msg: "加载成功",
|
|
2011
|
+
htmlContent,
|
|
2012
|
+
currentTemplate: this.currentTemplate,
|
|
2013
|
+
currentFont: this.currentFont,
|
|
2014
|
+
currentDarkMode: this.currentDarkMode
|
|
2015
|
+
};
|
|
2016
|
+
} catch (e) {
|
|
2017
|
+
this.ctx.logger("onebot-info-image").error("获取 Bot 信息失败:", e);
|
|
2018
|
+
return {
|
|
2019
|
+
status: "error",
|
|
2020
|
+
msg: `获取失败: ${e.message || e}`
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
|
|
1106
2026
|
// src/index.ts
|
|
1107
2027
|
var name = "onebot-info-image";
|
|
1108
2028
|
var inject = {
|
|
@@ -1113,12 +2033,11 @@ var pkg = JSON.parse(
|
|
|
1113
2033
|
);
|
|
1114
2034
|
var usage = `
|
|
1115
2035
|
<h1>Koishi 插件:onebot-info-image 获取群员信息 渲染成图像</h1>
|
|
1116
|
-
<h2>🎯
|
|
1117
|
-
<p>插件使用问题 / Bug反馈 / 插件开发交流,欢迎加入QQ群:<b>259248174</b></p>
|
|
2036
|
+
<h2>🎯 插件版本:<span style="color: #ff6b6b; font-weight: bold;">v${pkg.version}</span></h2>
|
|
2037
|
+
<p>插件使用问题 / Bug反馈 / 插件开发交流,欢迎加入QQ群:<b style="color: #50c878;">259248174</b></p>
|
|
1118
2038
|
|
|
1119
|
-
|
|
1120
|
-
<
|
|
1121
|
-
Napcat能拿到的东西更多, 为了更好的使用体验,推荐使用Napcat
|
|
2039
|
+
<p>目前仅仅适配了 <b>Lagrange</b> 和 <b>Napcat</b> 协议</p>
|
|
2040
|
+
<p style="color: #f39c12;">Napcat能拿到的东西更多, 为了更好的使用体验,推荐使用 Napcat</p>
|
|
1122
2041
|
|
|
1123
2042
|
<hr>
|
|
1124
2043
|
|
|
@@ -1130,20 +2049,20 @@ Napcat能拿到的东西更多, 为了更好的使用体验,推荐使用Napc
|
|
|
1130
2049
|
|
|
1131
2050
|
<hr>
|
|
1132
2051
|
|
|
1133
|
-
<h3>字体使用声明</h3>
|
|
2052
|
+
<h3 style="color: #27ae60;">字体使用声明</h3>
|
|
1134
2053
|
<p>本插件使用以下开源字体进行图像渲染:</p>
|
|
1135
2054
|
<ul>
|
|
1136
|
-
<li><b>思源宋体(Source Han Serif SC)</b> - 由 Adobe 与 Google 联合开发,遵循 <a href="https://openfontlicense.org">SIL Open Font License 1.1</a> 协议。</li>
|
|
1137
|
-
<li><b>霞鹜文楷(LXGW WenKai)</b> - 由 LXGW 开发并维护,遵循 <a href="https://openfontlicense.org">SIL Open Font License 1.1</a> 协议。</li>
|
|
2055
|
+
<li><b style="color: #3498db;">思源宋体(Source Han Serif SC)</b> - 由 Adobe 与 Google 联合开发,遵循 <a href="https://openfontlicense.org">SIL Open Font License 1.1</a> 协议。</li>
|
|
2056
|
+
<li><b style="color: #3498db;">霞鹜文楷(LXGW WenKai)</b> - 由 LXGW 开发并维护,遵循 <a href="https://openfontlicense.org">SIL Open Font License 1.1</a> 协议。</li>
|
|
1138
2057
|
</ul>
|
|
1139
2058
|
<p>两者均为自由字体,可在本项目中自由使用、修改与发布。若你也在开发相关插件或项目,欢迎一同使用这些优秀的字体。</p>
|
|
1140
2059
|
|
|
1141
2060
|
<hr>
|
|
1142
2061
|
|
|
1143
|
-
<h3>插件许可声明</h3>
|
|
2062
|
+
<h3 style="color: #e67e22;">插件许可声明</h3>
|
|
1144
2063
|
<p>本插件为开源免费项目,基于 MIT 协议开放。欢迎修改、分发、二创。</p>
|
|
1145
|
-
<p>如果你觉得插件好用,欢迎在 GitHub 上 Star 或通过其他方式给予支持(例如提供服务器、API Key 或直接赞助)!</p>
|
|
1146
|
-
<p>感谢所有开源字体与项目的贡献者 ❤️</p>
|
|
2064
|
+
<p>如果你觉得插件好用,欢迎在 GitHub 上 ⭐ Star 或通过其他方式给予支持(例如提供服务器、API Key 或直接赞助)!</p>
|
|
2065
|
+
<p style="color: #e91e63;">感谢所有开源字体与项目的贡献者 ❤️</p>
|
|
1147
2066
|
`;
|
|
1148
2067
|
var Config = import_koishi.Schema.intersect([
|
|
1149
2068
|
import_koishi.Schema.object({
|
|
@@ -1156,8 +2075,10 @@ var Config = import_koishi.Schema.intersect([
|
|
|
1156
2075
|
import_koishi.Schema.object({
|
|
1157
2076
|
enableUserInfoCommand: import_koishi.Schema.boolean().default(true).description("ℹ️ 是否启用用户信息命令。"),
|
|
1158
2077
|
userinfoCommandName: import_koishi.Schema.string().default("用户信息").description("🔍 用户信息命令名称。"),
|
|
2078
|
+
hidePhoneNumber: import_koishi.Schema.boolean().default(true).experimental().description("📱 是否隐藏手机号。开启后手机号将显示为【已隐藏】。</br> <i> 保护隐私捏 </i>"),
|
|
1159
2079
|
enableGroupAdminListCommand: import_koishi.Schema.boolean().default(false).description("👥 是否启用群管理员列表命令。"),
|
|
1160
|
-
groupAdminListCommandName: import_koishi.Schema.string().default("群管理列表").description("👥 群管理员列表命令名称。")
|
|
2080
|
+
groupAdminListCommandName: import_koishi.Schema.string().default("群管理列表").description("👥 群管理员列表命令名称。"),
|
|
2081
|
+
inspectStyleCommandName: import_koishi.Schema.string().default("查看图片样式").description("🎨 查看图片样式列表命令名称。")
|
|
1161
2082
|
}).description("基础配置 ⚙️"),
|
|
1162
2083
|
import_koishi.Schema.object({
|
|
1163
2084
|
sendText: import_koishi.Schema.boolean().default(false).description("💬 是否启用文本回复。"),
|
|
@@ -1166,11 +2087,37 @@ var Config = import_koishi.Schema.intersect([
|
|
|
1166
2087
|
import_koishi.Schema.object({
|
|
1167
2088
|
sendImage: import_koishi.Schema.boolean().default(true).description("🖼️ 是否启用 Puppeteer 渲染图片。"),
|
|
1168
2089
|
enableQuoteWithImage: import_koishi.Schema.boolean().default(false).description("📸 回复图片的时候,是否带引用触发指令的消息。"),
|
|
1169
|
-
|
|
1170
|
-
import_koishi.Schema.
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
2090
|
+
imageStyleDetails: import_koishi.Schema.array(
|
|
2091
|
+
import_koishi.Schema.object({
|
|
2092
|
+
styleKey: import_koishi.Schema.union(IMAGE_STYLE_KEY_ARR.map((key) => import_koishi.Schema.const(key).description(IMAGE_STYLES[key]))).role("radio").description("🎨 图片样式"),
|
|
2093
|
+
darkMode: import_koishi.Schema.boolean().description("🌙 启用深色模式")
|
|
2094
|
+
})
|
|
2095
|
+
).role("table").default([
|
|
2096
|
+
{
|
|
2097
|
+
styleKey: IMAGE_STYLE_KEY_ARR[0],
|
|
2098
|
+
darkMode: false
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
styleKey: IMAGE_STYLE_KEY_ARR[0],
|
|
2102
|
+
darkMode: true
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
styleKey: IMAGE_STYLE_KEY_ARR[1],
|
|
2106
|
+
darkMode: false
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
2109
|
+
styleKey: IMAGE_STYLE_KEY_ARR[1],
|
|
2110
|
+
darkMode: true
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
styleKey: IMAGE_STYLE_KEY_ARR[2],
|
|
2114
|
+
darkMode: false
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
styleKey: IMAGE_STYLE_KEY_ARR[2],
|
|
2118
|
+
darkMode: true
|
|
2119
|
+
}
|
|
2120
|
+
]).description("� 图片样式配置。第一行是默认使用的样式,指定样式请使用 -i 参数"),
|
|
1174
2121
|
imageType: import_koishi.Schema.union([
|
|
1175
2122
|
import_koishi.Schema.const(IMAGE_TYPES.PNG).description(`🖼️ ${IMAGE_TYPES.PNG}, ❌ 不支持调整quality`),
|
|
1176
2123
|
import_koishi.Schema.const(IMAGE_TYPES.JPEG).description(`🌄 ${IMAGE_TYPES.JPEG}, ✅ 支持调整quality`),
|
|
@@ -1183,27 +2130,70 @@ var Config = import_koishi.Schema.intersect([
|
|
|
1183
2130
|
}).description("发送 onebot转发消息 配置 ✉️"),
|
|
1184
2131
|
import_koishi.Schema.object({
|
|
1185
2132
|
verboseSessionOutput: import_koishi.Schema.boolean().default(false).description("🗣️ 是否在会话中输出详细信息。(生产环境别开,东西很多)"),
|
|
1186
|
-
verboseConsoleOutput: import_koishi.Schema.boolean().default(false).description("💻 是否在控制台输出详细信息。")
|
|
2133
|
+
verboseConsoleOutput: import_koishi.Schema.boolean().default(false).description("💻 是否在控制台输出详细信息。"),
|
|
2134
|
+
verboseFileOutput: import_koishi.Schema.boolean().default(false).description("📄 是否在文件中输出详细信息。(生产环境不要开)")
|
|
1187
2135
|
}).description("调试 (Debug) 配置 🐞")
|
|
1188
2136
|
]);
|
|
1189
2137
|
function apply(ctx, config) {
|
|
1190
2138
|
validateFonts(ctx).catch((error) => {
|
|
1191
2139
|
ctx.logger.error(`字体文件验证失败: ${error.message}`);
|
|
1192
2140
|
});
|
|
2141
|
+
ctx.plugin(OnebotInfoImageDataServer);
|
|
1193
2142
|
const responseHint = [
|
|
1194
2143
|
config.sendText && "文本消息",
|
|
1195
2144
|
config.sendImage && "图片消息",
|
|
1196
2145
|
config.sendForward && "合并转发消息"
|
|
1197
2146
|
].filter(Boolean).join("、");
|
|
2147
|
+
ctx.command(config.inspectStyleCommandName, "查看图片样式列表").alias("ais").alias("awa_inspect_style").action(async ({ session }) => {
|
|
2148
|
+
let msg = "用户信息图片样式列表:\n";
|
|
2149
|
+
for (let i = 0; i < config.imageStyleDetails.length; i++) {
|
|
2150
|
+
const o = config.imageStyleDetails[i];
|
|
2151
|
+
msg += ` 【${i}】: ${IMAGE_STYLES[o.styleKey]} ${o.darkMode ? "深色模式" : "浅色模式"} (${o.styleKey})
|
|
2152
|
+
`;
|
|
2153
|
+
}
|
|
2154
|
+
await session.send(msg);
|
|
2155
|
+
});
|
|
1198
2156
|
if (config.enableUserInfoCommand)
|
|
1199
|
-
ctx.command(config.userinfoCommandName
|
|
2157
|
+
ctx.command(`${config.userinfoCommandName} [qqId:string]`, `获取用户信息, 发送${responseHint}`).alias("aui").alias("awa_user_info").option("imageStyleIdx", "-i, --idx, --index <idx:number> 图片样式索引").action(async ({ session, options }, qqId) => {
|
|
1200
2158
|
if (!session.onebot)
|
|
1201
2159
|
return session.send("[error]当前会话不支持onebot协议。");
|
|
2160
|
+
const IMAGE_STYLE_VALUES = Object.values(IMAGE_STYLES);
|
|
2161
|
+
const defaultStyleDetailObj = config.imageStyleDetails.length > 0 ? config.imageStyleDetails[0] : { styleKey: IMAGE_STYLE_KEY_ARR[0], darkMode: false };
|
|
2162
|
+
let selectedStyleDetailObj = defaultStyleDetailObj;
|
|
2163
|
+
if (options.imageStyleIdx !== void 0) {
|
|
2164
|
+
const isIdxValid = options.imageStyleIdx >= 0 && options.imageStyleIdx < config.imageStyleDetails.length;
|
|
2165
|
+
if (!isIdxValid) {
|
|
2166
|
+
let idxInvalidMsgArr = [
|
|
2167
|
+
`图片样式索引不合法。`,
|
|
2168
|
+
` 合法范围:[0, ${config.imageStyleDetails.length - 1}]双闭区间。`,
|
|
2169
|
+
` 当前输入:${options.imageStyleIdx}`,
|
|
2170
|
+
`
|
|
2171
|
+
`,
|
|
2172
|
+
`输入指令 ${config.inspectStyleCommandName} 查看图片样式列表。`
|
|
2173
|
+
];
|
|
2174
|
+
return await session.send(idxInvalidMsgArr.join("\n"));
|
|
2175
|
+
}
|
|
2176
|
+
selectedStyleDetailObj = config.imageStyleDetails[options.imageStyleIdx];
|
|
2177
|
+
}
|
|
1202
2178
|
let targetUserId = session.userId;
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
2179
|
+
let isDirectQuery = false;
|
|
2180
|
+
if (qqId) {
|
|
2181
|
+
const userIdRegex = /<at id="([^"]+)"(?: name="[^"]*")?\/>/;
|
|
2182
|
+
const match = qqId.match(userIdRegex);
|
|
2183
|
+
if (match) {
|
|
2184
|
+
targetUserId = match[1];
|
|
2185
|
+
isDirectQuery = true;
|
|
2186
|
+
} else {
|
|
2187
|
+
targetUserId = qqId;
|
|
2188
|
+
isDirectQuery = true;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
if (!isDirectQuery) {
|
|
2192
|
+
for (const e of session.event.message.elements) {
|
|
2193
|
+
if (e.type === "at") {
|
|
2194
|
+
targetUserId = e.attrs.id;
|
|
2195
|
+
break;
|
|
2196
|
+
}
|
|
1207
2197
|
}
|
|
1208
2198
|
}
|
|
1209
2199
|
const userObj = await session.bot.getUser(targetUserId);
|
|
@@ -1227,7 +2217,7 @@ function apply(ctx, config) {
|
|
|
1227
2217
|
${JSON.stringify(strangerInfoObj)}`;
|
|
1228
2218
|
if (config.verboseSessionOutput) await session.send(strangerInfoObjMsg);
|
|
1229
2219
|
if (config.verboseConsoleOutput) ctx.logger.info(strangerInfoObjMsg);
|
|
1230
|
-
if (session.guildId) {
|
|
2220
|
+
if (session.guildId && !isDirectQuery) {
|
|
1231
2221
|
const groupMemberInfoObj = await session.onebot.getGroupMemberInfo(session.guildId, targetUserId);
|
|
1232
2222
|
let groupMemberInfoObjMsg = `groupMemberInfoObj =
|
|
1233
2223
|
${JSON.stringify(groupMemberInfoObj)}`;
|
|
@@ -1282,9 +2272,10 @@ function apply(ctx, config) {
|
|
|
1282
2272
|
if (config.onebotImplName === ONEBOT_IMPL_NAME.LAGRNAGE) {
|
|
1283
2273
|
} else if (config.onebotImplName === ONEBOT_IMPL_NAME.NAPCAT) {
|
|
1284
2274
|
const ncUserStatusObj = await session.onebot._request("nc_get_user_status", { user_id: targetUserId });
|
|
2275
|
+
const napcatStatusData = ncUserStatusObj?.data ?? null;
|
|
1285
2276
|
userInfoArg.status = {
|
|
1286
2277
|
napcat_origin: ncUserStatusObj,
|
|
1287
|
-
message: getNapcatQQStatusText(
|
|
2278
|
+
message: getNapcatQQStatusText(napcatStatusData?.status, napcatStatusData?.ext_status)
|
|
1288
2279
|
};
|
|
1289
2280
|
}
|
|
1290
2281
|
let userInfoArgMsg = `userInfoArg =
|
|
@@ -1320,7 +2311,20 @@ function apply(ctx, config) {
|
|
|
1320
2311
|
}
|
|
1321
2312
|
if (config.sendImage) {
|
|
1322
2313
|
const waitTipMsgId = await session.send(`${import_koishi.h.quote(session.messageId)}🔄正在渲染用户信息图片,请稍候⏳...`);
|
|
1323
|
-
const
|
|
2314
|
+
const selectedImageStyle = IMAGE_STYLES[selectedStyleDetailObj.styleKey];
|
|
2315
|
+
const selectedDarkMode = selectedStyleDetailObj.darkMode;
|
|
2316
|
+
const userInfoimageBase64 = await renderUserInfo(ctx, unifiedUserInfo, unifiedContextInfo, selectedImageStyle, selectedDarkMode, config.imageType, config.screenshotQuality, config.hidePhoneNumber);
|
|
2317
|
+
if (config.verboseFileOutput) {
|
|
2318
|
+
try {
|
|
2319
|
+
const tmpDir = (0, import_path2.resolve)(__dirname, "../tmp");
|
|
2320
|
+
(0, import_fs2.mkdirSync)(tmpDir, { recursive: true });
|
|
2321
|
+
const outputPath = (0, import_path2.resolve)(tmpDir, "image_base64.txt");
|
|
2322
|
+
(0, import_fs2.writeFileSync)(outputPath, userInfoimageBase64, "utf-8");
|
|
2323
|
+
ctx.logger.info(`图片 base64 已输出到: ${outputPath}`);
|
|
2324
|
+
} catch (error) {
|
|
2325
|
+
ctx.logger.error(`写入 base64 文件失败: ${error.message}`);
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
1324
2328
|
await session.send(`${config.enableQuoteWithImage ? import_koishi.h.quote(session.messageId) : ""}${import_koishi.h.image(`data:image/png;base64,${userInfoimageBase64}`)}`);
|
|
1325
2329
|
await session.bot.deleteMessage(session.guildId, String(waitTipMsgId));
|
|
1326
2330
|
}
|
|
@@ -1337,11 +2341,29 @@ function apply(ctx, config) {
|
|
|
1337
2341
|
}
|
|
1338
2342
|
});
|
|
1339
2343
|
if (config.enableGroupAdminListCommand)
|
|
1340
|
-
ctx.command(config.groupAdminListCommandName, `获取群管理员列表, 发送${responseHint}`).alias("al").alias("awa_group_admin_list").action(async ({ session, options }) => {
|
|
2344
|
+
ctx.command(config.groupAdminListCommandName, `获取群管理员列表, 发送${responseHint}`).alias("al").alias("awa_group_admin_list").option("imageStyleIdx", "-i, --idx, --index <idx:number> 图片样式索引").action(async ({ session, options }) => {
|
|
1341
2345
|
if (!session.onebot)
|
|
1342
2346
|
return session.send("[error]当前会话不支持onebot协议。");
|
|
1343
2347
|
if (!session.guildId)
|
|
1344
2348
|
return session.send("[error]当前会话不在群聊中。");
|
|
2349
|
+
const IMAGE_STYLE_VALUES = Object.values(IMAGE_STYLES);
|
|
2350
|
+
const defaultStyleDetailObj = config.imageStyleDetails.length > 0 ? config.imageStyleDetails[0] : { styleKey: IMAGE_STYLE_KEY_ARR[0], darkMode: false };
|
|
2351
|
+
let selectedStyleDetailObj = defaultStyleDetailObj;
|
|
2352
|
+
if (options.imageStyleIdx !== void 0) {
|
|
2353
|
+
const isIdxValid = options.imageStyleIdx >= 0 && options.imageStyleIdx < config.imageStyleDetails.length;
|
|
2354
|
+
if (!isIdxValid) {
|
|
2355
|
+
let idxInvalidMsgArr = [
|
|
2356
|
+
`图片样式索引不合法。`,
|
|
2357
|
+
` 合法范围:[0, ${config.imageStyleDetails.length - 1}]双闭区间。`,
|
|
2358
|
+
` 当前输入:${options.imageStyleIdx}`,
|
|
2359
|
+
`
|
|
2360
|
+
`,
|
|
2361
|
+
`输入指令 ${config.inspectStyleCommandName} 查看图片样式列表。`
|
|
2362
|
+
];
|
|
2363
|
+
return await session.send(idxInvalidMsgArr.join("\n"));
|
|
2364
|
+
}
|
|
2365
|
+
selectedStyleDetailObj = config.imageStyleDetails[options.imageStyleIdx];
|
|
2366
|
+
}
|
|
1345
2367
|
try {
|
|
1346
2368
|
const groupMemberListObj = await session.onebot.getGroupMemberList(session.guildId);
|
|
1347
2369
|
const groupInfoObj = await session.onebot.getGroupInfo(session.guildId);
|
|
@@ -1397,7 +2419,9 @@ function apply(ctx, config) {
|
|
|
1397
2419
|
ctx.logger.info(`context info = ${JSON.stringify(contextInfo)}`);
|
|
1398
2420
|
const waitTipMsgId = await session.send(`${import_koishi.h.quote(session.messageId)}🔄正在渲染群管理员列表图片,请稍候⏳...`);
|
|
1399
2421
|
const unifiedContextInfo = convertToUnifiedContextInfo(contextInfo, config.onebotImplName);
|
|
1400
|
-
const
|
|
2422
|
+
const selectedImageStyle = IMAGE_STYLES[selectedStyleDetailObj.styleKey];
|
|
2423
|
+
const selectedDarkMode = selectedStyleDetailObj.darkMode;
|
|
2424
|
+
const adminListImageBase64 = await renderAdminList(ctx, adminListArg, unifiedContextInfo, selectedImageStyle, selectedDarkMode, config.imageType, config.screenshotQuality);
|
|
1401
2425
|
await session.send(`${config.enableQuoteWithImage ? import_koishi.h.quote(session.messageId) : ""}${import_koishi.h.image(`data:image/png;base64,${adminListImageBase64}`)}`);
|
|
1402
2426
|
await session.bot.deleteMessage(session.guildId, String(waitTipMsgId));
|
|
1403
2427
|
}
|