koishi-plugin-chat-patch 5.3.0 → 5.5.0
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/client/web/dist/assets/Chat-Clqxn7CB.js +28 -0
- package/client/web/dist/assets/{Chat-CTdyeaX2.css → Chat-DTEsebnY.css} +1 -1
- package/client/web/dist/assets/{MsgBody-DDacjWJ9.js → MsgBody-C0TKsXhC.js} +1 -1
- package/client/web/dist/assets/{MsgBody.vue_vue_type_script_setup_true_lang-B1dWyCB0.js → MsgBody.vue_vue_type_script_setup_true_lang-CCdBwlN_.js} +2 -2
- package/client/web/dist/assets/{append_darwin-CqBNU62J.css → append_darwin-Cql-dV6d.css} +1 -1
- package/client/web/dist/assets/{append_full_vibrancy-j0D2LM9m.css → append_full_vibrancy-ih3loy1O.css} +1 -1
- package/client/web/dist/assets/{append_linux-uhxeBqeC.css → append_linux-B3LvR8KB.css} +1 -1
- package/client/web/dist/assets/{append_new-407Lo5_V.css → append_new-DfhN_NX9.css} +1 -1
- package/client/web/dist/assets/{append_vibrancy-6FHctkOY.css → append_vibrancy-D3pVsmAa.css} +1 -1
- package/client/web/dist/assets/{append_win32-srmD-78y.css → append_win32-Dh9JlmlE.css} +1 -1
- package/client/web/dist/assets/index-B71pPwae.css +1 -0
- package/client/web/dist/assets/{index-BlLut5xn.js → index-BA37EQGa.js} +97 -76
- package/client/web/dist/index.html +2 -2
- package/client/web/src/App.vue +2 -2
- package/client/web/src/assets/css/append/append_darwin.css +2 -2
- package/client/web/src/assets/css/append/append_full_vibrancy.css +2 -2
- package/client/web/src/assets/css/append/append_linux.css +2 -2
- package/client/web/src/assets/css/append/append_new.css +2 -2
- package/client/web/src/assets/css/append/append_vibrancy.css +1 -1
- package/client/web/src/assets/css/append/append_win32.css +2 -2
- package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +1 -1
- package/client/web/src/assets/css/chat.css +4 -3
- package/client/web/src/assets/css/msg.css +7 -3
- package/client/web/src/assets/css/options.css +2 -2
- package/client/web/src/assets/css/view.css +14 -3
- package/client/web/src/assets/l10n/zh-CN.po +21 -0
- package/client/web/src/components/AboutPan.vue +7 -4
- package/client/web/src/components/BulletinBody.vue +1 -1
- package/client/web/src/components/DepPan.vue +1 -1
- package/client/web/src/components/FriendBody.vue +1 -0
- package/client/web/src/components/MsgBody.vue +1 -3
- package/client/web/src/components/ThemeColorPickerPan.vue +1 -1
- package/client/web/src/components/TinySessionBody.vue +1 -0
- package/client/web/src/components/UmamiInfoPan.vue +1 -1
- package/client/web/src/components/UpdatePan.vue +2 -2
- package/client/web/src/components/WelPan.vue +1 -1
- package/client/web/src/components/tooltip/UserInfoTooltip.vue +1 -1
- package/client/web/src/function/connect.ts +279 -86
- package/client/web/src/function/elements/information.ts +1 -0
- package/client/web/src/function/msg.ts +42 -23
- package/client/web/src/function/satori-model.ts +35 -13
- package/client/web/src/function/satori.ts +33 -2
- package/client/web/src/function/utils/appUtil.ts +3 -11
- package/client/web/src/function/utils/avatarUtil.ts +18 -3
- package/client/web/src/function/utils/localHistoryUtil.ts +36 -12
- package/client/web/src/function/utils/msgUtil.ts +32 -21
- package/client/web/src/function/utils/sessionUtil.ts +20 -18
- package/client/web/src/main.ts +5 -0
- package/client/web/src/pages/Chat.vue +50 -47
- package/client/web/src/pages/Friends.vue +28 -24
- package/client/web/src/pages/Info.vue +5 -5
- package/client/web/src/pages/Messages.vue +57 -36
- package/client/web/src/pages/Qzone.vue +2 -2
- package/client/web/src/pages/chat-view/ChatTerminal.vue +4 -1
- package/client/web/src/pages/chat-view/SystemNotice.vue +3 -3
- package/client/web/src/pages/options/OptAccount.vue +6 -4
- package/client/web/src/pages/options/OptDev.vue +45 -2
- package/lib/database.d.ts +58 -0
- package/lib/index.js +234 -82
- package/lib/media.d.ts +24 -0
- package/lib/recorder.d.ts +21 -0
- package/lib/self-message.d.ts +27 -0
- package/lib/types.d.ts +121 -0
- package/lib/web.d.ts +7 -0
- package/package.json +1 -1
- package/src/bootstrap.ts +1 -0
- package/src/cache.ts +1 -5
- package/src/config.ts +1 -1
- package/src/database.ts +52 -8
- package/src/index.ts +4 -4
- package/src/media.ts +97 -0
- package/src/recorder.ts +35 -26
- package/src/self-message.ts +68 -19
- package/src/types.ts +10 -0
- package/src/web.ts +57 -48
- package/client/web/dist/assets/Chat-B448YOeN.js +0 -28
- package/client/web/dist/assets/index-fW_zcub3.css +0 -1
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
import { reactive } from 'vue'
|
|
4
4
|
import { dispatch, msgPreprocess } from './msg'
|
|
5
5
|
import {
|
|
6
|
+
botKey,
|
|
6
7
|
connect as connectSatori,
|
|
7
8
|
getActiveBot,
|
|
9
|
+
getBlockedPlatforms,
|
|
8
10
|
getBootstrap,
|
|
9
11
|
getLogins,
|
|
10
12
|
request,
|
|
@@ -29,6 +31,7 @@ import {
|
|
|
29
31
|
getSessionDedupKey,
|
|
30
32
|
normalizeSessionId,
|
|
31
33
|
setSessionContact,
|
|
34
|
+
upsertSessionContact,
|
|
32
35
|
} from './utils/sessionUtil'
|
|
33
36
|
import { buildQqGroupAvatar } from './utils/avatarUtil'
|
|
34
37
|
import type { ConnectionHistoryItem, LoginCacheElem } from './elements/system'
|
|
@@ -42,6 +45,14 @@ function encodeKeyPart(value: string): string {
|
|
|
42
45
|
return encodeURIComponent(value)
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
function isBlockedPlatform(platform: string): boolean {
|
|
49
|
+
return getBlockedPlatforms().some((item) => {
|
|
50
|
+
return item.exactMatch
|
|
51
|
+
? platform === item.platformName
|
|
52
|
+
: platform.includes(item.platformName)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
function getChannelKind(value: unknown): 'group' | 'direct' | 'unknown' {
|
|
46
57
|
if (typeof value === 'number') {
|
|
47
58
|
if (value === 0) return 'group'
|
|
@@ -350,7 +361,7 @@ function updateBotStateGroup(
|
|
|
350
361
|
apply: (target: Record<string, unknown>) => void,
|
|
351
362
|
) {
|
|
352
363
|
const contactStore = useContactStore()
|
|
353
|
-
const state = contactStore.botStates.get(selfId)
|
|
364
|
+
const state = contactStore.botStates.get(botKey(platform, selfId))
|
|
354
365
|
const session = state?.onMsgList.find((item) => String(item.group_id) === sessionId)
|
|
355
366
|
if (!state || !session) return
|
|
356
367
|
apply(session as unknown as Record<string, unknown>)
|
|
@@ -363,7 +374,7 @@ function updateBotStateGroup(
|
|
|
363
374
|
} else {
|
|
364
375
|
baseList.push([key, typedSession])
|
|
365
376
|
}
|
|
366
|
-
contactStore.botStates.set(selfId, {
|
|
377
|
+
contactStore.botStates.set(botKey(platform, selfId), {
|
|
367
378
|
userList: [...state.userList],
|
|
368
379
|
baseList,
|
|
369
380
|
onMsgList: [...state.onMsgList],
|
|
@@ -494,7 +505,7 @@ async function fetchUserIdentity(
|
|
|
494
505
|
const guildId = getString(msg.guild_id) || getString(msg.group_id)
|
|
495
506
|
const isPrivate = isPrivateMessage(msg)
|
|
496
507
|
const channelId = isPrivate
|
|
497
|
-
? (getString(msg.channel_id) ||
|
|
508
|
+
? (getString(msg.channel_id) || userId)
|
|
498
509
|
: ''
|
|
499
510
|
const sender = getObject(msg.sender)
|
|
500
511
|
const senderName = getString(sender.nickname) || getString(sender.card) || getString(sender.name)
|
|
@@ -545,10 +556,11 @@ function recordBotMessage(platform: string, selfId: string, msg: Record<string,
|
|
|
545
556
|
})
|
|
546
557
|
const isGroup = isGroupMessage(msg)
|
|
547
558
|
const channelId = typeof msg.channel_id === 'string' ? msg.channel_id : ''
|
|
559
|
+
const guildId = typeof msg.guild_id === 'string' ? msg.guild_id : ''
|
|
548
560
|
const sessionId = String(
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
561
|
+
isGroup
|
|
562
|
+
? (msg.group_id || channelId || guildId || '')
|
|
563
|
+
: (msg.user_id || channelId || ''),
|
|
552
564
|
)
|
|
553
565
|
if (!sessionId || sessionId === '0') {
|
|
554
566
|
identityDebug('recordBotMessage: skipped invalid session', { sessionId, msg })
|
|
@@ -561,7 +573,8 @@ function recordBotMessage(platform: string, selfId: string, msg: Record<string,
|
|
|
561
573
|
const senderId = String(
|
|
562
574
|
sender.user_id
|
|
563
575
|
|| msg.user_id
|
|
564
|
-
||
|
|
576
|
+
|| channelId
|
|
577
|
+
|| '',
|
|
565
578
|
)
|
|
566
579
|
const raw = getMsgRawTxt(msg) || (typeof msg.raw_message === 'string' ? msg.raw_message : '')
|
|
567
580
|
const senderName = String(sender.card || sender.nickname || (isGroup ? senderId : ''))
|
|
@@ -578,7 +591,7 @@ function recordBotMessage(platform: string, selfId: string, msg: Record<string,
|
|
|
578
591
|
? (eventGroupAvatar || cachedGroupInfo?.avatar || buildQqGroupAvatar(platform, sessionId) || undefined)
|
|
579
592
|
: undefined
|
|
580
593
|
const contactStore = useContactStore()
|
|
581
|
-
const state = contactStore.botStates.get(selfId) ?? {
|
|
594
|
+
const state = contactStore.botStates.get(botKey(platform, selfId)) ?? {
|
|
582
595
|
userList: [],
|
|
583
596
|
baseList: [],
|
|
584
597
|
onMsgList: [],
|
|
@@ -601,60 +614,108 @@ function recordBotMessage(platform: string, selfId: string, msg: Record<string,
|
|
|
601
614
|
channel_id: typeof msg.channel_id === 'string' ? msg.channel_id : undefined,
|
|
602
615
|
guild_id: typeof msg.guild_id === 'string' ? msg.guild_id : undefined,
|
|
603
616
|
}
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
617
|
+
const typedSession = session as unknown as UserFriendElem & UserGroupElem
|
|
618
|
+
const memberContact = isGroup && senderId && senderId !== '0'
|
|
619
|
+
? {
|
|
620
|
+
user_id: senderId,
|
|
621
|
+
nickname: String(sender.nickname || sender.card || senderName || senderId),
|
|
622
|
+
remark: String(sender.nickname || sender.card || senderName || senderId),
|
|
623
|
+
avatar: hasUsableAvatar(sender.avatar) ? getString(sender.avatar) : undefined,
|
|
624
|
+
class_id: 0,
|
|
625
|
+
class_name: '我的好友',
|
|
626
|
+
_groupMember: true,
|
|
627
|
+
raw_msg: senderName ? `${senderName}: ${raw}` : raw,
|
|
628
|
+
raw_msg_base: raw,
|
|
629
|
+
time: sessionTime,
|
|
630
|
+
message_id: String(msg.message_id ?? ''),
|
|
631
|
+
guild_id: typeof msg.guild_id === 'string' ? msg.guild_id : undefined,
|
|
632
|
+
} as UserFriendElem & UserGroupElem
|
|
633
|
+
: undefined
|
|
634
|
+
let baseList = [...state.baseList]
|
|
635
|
+
if (isGroup) {
|
|
636
|
+
// 群消息进入群会话列表,群成员只进联系人列表
|
|
637
|
+
state.userList = upsertSessionContact(state.userList, typedSession)
|
|
638
|
+
if (memberContact) {
|
|
639
|
+
state.userList = upsertSessionContact(state.userList, memberContact)
|
|
640
|
+
}
|
|
641
|
+
const existing = state.onMsgList.find((item) => {
|
|
642
|
+
const itemChannelId = String(item.channel_id || item.channelId || '')
|
|
643
|
+
if (itemChannelId) {
|
|
608
644
|
return normalizeGroupId(itemChannelId) === normalizeGroupId(channelId || sessionId)
|
|
609
645
|
}
|
|
610
|
-
return
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
646
|
+
return String(item.group_id) === sessionId
|
|
647
|
+
})
|
|
648
|
+
if (existing) {
|
|
649
|
+
const previousAvatar = existing.avatar
|
|
650
|
+
const previousGroupName = existing.group_name
|
|
651
|
+
Object.assign(existing, session)
|
|
652
|
+
if (!hasUsableAvatar(session.avatar) && hasUsableAvatar(previousAvatar)) {
|
|
653
|
+
existing.avatar = previousAvatar
|
|
654
|
+
}
|
|
655
|
+
if (
|
|
656
|
+
!msg.group_name &&
|
|
657
|
+
previousGroupName &&
|
|
658
|
+
String(previousGroupName) !== String(sessionId)
|
|
659
|
+
) {
|
|
660
|
+
existing.group_name = previousGroupName
|
|
661
|
+
}
|
|
662
|
+
session = existing
|
|
663
|
+
} else {
|
|
664
|
+
state.onMsgList.unshift(session)
|
|
625
665
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
existing.group_name = previousGroupName
|
|
666
|
+
const baseKey = normalizeSessionId(sessionKey)
|
|
667
|
+
const baseIndex = baseList.findIndex(([, value]) => value === session)
|
|
668
|
+
if (baseIndex >= 0) {
|
|
669
|
+
baseList[baseIndex] = [baseKey, typedSession]
|
|
670
|
+
} else {
|
|
671
|
+
baseList.push([baseKey, typedSession])
|
|
633
672
|
}
|
|
634
|
-
|
|
635
|
-
|
|
673
|
+
} else {
|
|
674
|
+
const existing = state.onMsgList.find((item) => {
|
|
675
|
+
const itemChannelId = String(item.channel_id || item.channelId || '')
|
|
676
|
+
if (itemChannelId) {
|
|
677
|
+
return itemChannelId === String(sessionId)
|
|
678
|
+
}
|
|
679
|
+
return String(item.user_id) === sessionId
|
|
680
|
+
})
|
|
681
|
+
if (existing) {
|
|
682
|
+
const previousAvatar = existing.avatar
|
|
683
|
+
const previousNickname = existing.nickname
|
|
684
|
+
const previousRemark = existing.remark
|
|
685
|
+
Object.assign(existing, session)
|
|
686
|
+
if (existing._groupMember) existing._groupMember = false
|
|
687
|
+
if (!hasUsableAvatar(session.avatar) && hasUsableAvatar(previousAvatar)) {
|
|
688
|
+
existing.avatar = previousAvatar
|
|
689
|
+
}
|
|
690
|
+
if (!isGroup && !sender.nickname && previousNickname) {
|
|
691
|
+
existing.nickname = previousNickname
|
|
692
|
+
}
|
|
693
|
+
if (!isGroup && !existing.remark && previousRemark) {
|
|
694
|
+
existing.remark = previousRemark
|
|
695
|
+
}
|
|
696
|
+
session = existing
|
|
697
|
+
} else {
|
|
698
|
+
state.onMsgList.unshift(session)
|
|
636
699
|
}
|
|
637
|
-
|
|
638
|
-
|
|
700
|
+
const baseKey = normalizeSessionId(sessionKey)
|
|
701
|
+
const baseIndex = baseList.findIndex(([, value]) => value === session)
|
|
702
|
+
if (baseIndex >= 0) {
|
|
703
|
+
baseList[baseIndex] = [baseKey, typedSession]
|
|
704
|
+
} else {
|
|
705
|
+
baseList.push([baseKey, typedSession])
|
|
639
706
|
}
|
|
640
|
-
session = existing
|
|
641
|
-
} else {
|
|
642
|
-
state.onMsgList.unshift(session)
|
|
643
|
-
}
|
|
644
|
-
const baseKey = normalizeSessionId(sessionKey)
|
|
645
|
-
const baseList = [...state.baseList]
|
|
646
|
-
const baseIndex = baseList.findIndex(([, value]) => value === session)
|
|
647
|
-
const typedSession = session as unknown as UserFriendElem & UserGroupElem
|
|
648
|
-
if (baseIndex >= 0) {
|
|
649
|
-
baseList[baseIndex] = [baseKey, typedSession]
|
|
650
|
-
} else {
|
|
651
|
-
baseList.push([baseKey, typedSession])
|
|
652
707
|
}
|
|
653
|
-
contactStore.botStates.set(selfId, {
|
|
708
|
+
contactStore.botStates.set(botKey(platform, selfId), {
|
|
654
709
|
userList: [...state.userList],
|
|
655
710
|
baseList,
|
|
656
711
|
onMsgList: [...state.onMsgList],
|
|
657
712
|
})
|
|
713
|
+
if (isGroup && isActiveBot({ platform, selfId })) {
|
|
714
|
+
contactStore.userList = upsertSessionContact(contactStore.userList, typedSession)
|
|
715
|
+
if (memberContact) {
|
|
716
|
+
contactStore.userList = upsertSessionContact(contactStore.userList, memberContact)
|
|
717
|
+
}
|
|
718
|
+
}
|
|
658
719
|
if (
|
|
659
720
|
isActiveBot({ platform, selfId }) &&
|
|
660
721
|
!contactStore.baseOnMsgList.has(normalizeSessionId(sessionKey))
|
|
@@ -664,7 +725,7 @@ function recordBotMessage(platform: string, selfId: string, msg: Record<string,
|
|
|
664
725
|
}
|
|
665
726
|
|
|
666
727
|
const chatStore = useChatStore()
|
|
667
|
-
const cacheKey = [platform, selfId,
|
|
728
|
+
const cacheKey = [platform, selfId, sessionKey].map(encodeKeyPart).join(':')
|
|
668
729
|
const messages = chatStore.sessionMessageCache.get(cacheKey) ?? []
|
|
669
730
|
const messageId = String(msg.message_id ?? '')
|
|
670
731
|
if (messageId && !messages.some((item) => String(item.message_id) === messageId)) {
|
|
@@ -726,6 +787,26 @@ function recordBotMessage(platform: string, selfId: string, msg: Record<string,
|
|
|
726
787
|
)
|
|
727
788
|
if (senderId && senderId !== '0') {
|
|
728
789
|
void fetchUserIdentity(platform, selfId, senderId, null, msg)
|
|
790
|
+
if (isCurrentChat) {
|
|
791
|
+
const members = chatStore.chatInfo.info.group_members
|
|
792
|
+
const member = {
|
|
793
|
+
user_id: senderId,
|
|
794
|
+
nickname: String(sender.nickname || sender.card || senderName || senderId),
|
|
795
|
+
card: String(sender.card || ''),
|
|
796
|
+
role: String(sender.role || ''),
|
|
797
|
+
avatar: hasUsableAvatar(sender.avatar) ? getString(sender.avatar) : undefined,
|
|
798
|
+
title: '',
|
|
799
|
+
join_time: 0,
|
|
800
|
+
last_sent_time: Math.floor(sessionTime),
|
|
801
|
+
level: 0,
|
|
802
|
+
rank: '',
|
|
803
|
+
sex: '',
|
|
804
|
+
shutup_time: 0,
|
|
805
|
+
}
|
|
806
|
+
const index = members.findIndex((item) => String(item.user_id) === senderId)
|
|
807
|
+
if (index >= 0) Object.assign(members[index], member)
|
|
808
|
+
else members.push(member)
|
|
809
|
+
}
|
|
729
810
|
}
|
|
730
811
|
} else if (senderId && senderId !== '0') {
|
|
731
812
|
identityDebug('recordBotMessage: private identity branch', {
|
|
@@ -748,7 +829,9 @@ export function restoreBotStateFromMessageCache(platform: string, selfId: string
|
|
|
748
829
|
const msg = messages[messages.length - 1]
|
|
749
830
|
if (!msg) continue
|
|
750
831
|
const isGroup = isGroupMessage(msg)
|
|
751
|
-
const id = String(isGroup
|
|
832
|
+
const id = String(isGroup
|
|
833
|
+
? (msg.group_id || msg.channel_id || msg.guild_id)
|
|
834
|
+
: (msg.user_id || msg.channel_id))
|
|
752
835
|
if (!id || id === '0') continue
|
|
753
836
|
const sender = getObject(msg.sender)
|
|
754
837
|
const senderId = getString(sender.user_id) || getString(msg.user_id) || ''
|
|
@@ -780,7 +863,7 @@ export function restoreBotStateFromMessageCache(platform: string, selfId: string
|
|
|
780
863
|
}
|
|
781
864
|
if (!sessions.length) return
|
|
782
865
|
|
|
783
|
-
const state = contactStore.botStates.get(selfId) ?? {
|
|
866
|
+
const state = contactStore.botStates.get(botKey(platform, selfId)) ?? {
|
|
784
867
|
userList: [],
|
|
785
868
|
baseList: [],
|
|
786
869
|
onMsgList: [],
|
|
@@ -788,28 +871,28 @@ export function restoreBotStateFromMessageCache(platform: string, selfId: string
|
|
|
788
871
|
const baseMap = new Map<string, UserFriendElem & UserGroupElem>()
|
|
789
872
|
for (const [, value] of state.baseList) {
|
|
790
873
|
const id = getSessionDedupKey(value)
|
|
791
|
-
if (
|
|
874
|
+
if (id !== '0' && id !== '') baseMap.set(id, value)
|
|
792
875
|
}
|
|
793
876
|
const baseList = [...baseMap.entries()]
|
|
794
877
|
const baseKeys = new Set(baseList.map(([key]) => key))
|
|
795
878
|
const existing = new Set(
|
|
796
879
|
state.onMsgList.map((item) => {
|
|
797
880
|
const id = getSessionDedupKey(item)
|
|
798
|
-
return
|
|
881
|
+
return id !== '0' && id !== '' ? id : ''
|
|
799
882
|
}).filter(Boolean),
|
|
800
883
|
)
|
|
801
884
|
for (const session of sessions) {
|
|
802
885
|
const id = getSessionDedupKey(session)
|
|
803
|
-
if (
|
|
886
|
+
if (id !== '0' && id !== '' && !existing.has(id)) {
|
|
804
887
|
state.onMsgList.unshift(session)
|
|
805
888
|
existing.add(id)
|
|
806
889
|
}
|
|
807
|
-
if (
|
|
890
|
+
if (id !== '0' && id !== '' && !baseKeys.has(id)) {
|
|
808
891
|
baseList.push([normalizeSessionId(String(session.channel_id || session.channelId || session.user_id || session.group_id || '')), session])
|
|
809
892
|
baseKeys.add(id)
|
|
810
893
|
}
|
|
811
894
|
}
|
|
812
|
-
contactStore.botStates.set(selfId, {
|
|
895
|
+
contactStore.botStates.set(botKey(platform, selfId), {
|
|
813
896
|
userList: [...state.userList],
|
|
814
897
|
baseList,
|
|
815
898
|
onMsgList: [...state.onMsgList],
|
|
@@ -817,6 +900,7 @@ export function restoreBotStateFromMessageCache(platform: string, selfId: string
|
|
|
817
900
|
}
|
|
818
901
|
|
|
819
902
|
function onSatoriEvent(event: SatoriEvent) {
|
|
903
|
+
if (isBlockedPlatform(event.platform)) return
|
|
820
904
|
const oneBot = satoriEventToOneBot(event.body, String(event.platform || ''))
|
|
821
905
|
if (oneBot) {
|
|
822
906
|
oneBot._rawSatori = {
|
|
@@ -865,6 +949,7 @@ export function flushPendingBotEvents(platform: string, selfId: string) {
|
|
|
865
949
|
if (!events?.length) return
|
|
866
950
|
pendingBotEvents.delete(key)
|
|
867
951
|
for (const event of events) {
|
|
952
|
+
if (isBlockedPlatform(event.platform)) continue
|
|
868
953
|
const oneBot = satoriEventToOneBot(event.body, String(event.platform || ''))
|
|
869
954
|
if (oneBot) {
|
|
870
955
|
oneBot._rawSatori = {
|
|
@@ -893,7 +978,8 @@ function onSatoriReady(logins: Array<{ platform: string; selfId: string; name: s
|
|
|
893
978
|
login.creating = false
|
|
894
979
|
login.status = true
|
|
895
980
|
const authStore = useAuthStore()
|
|
896
|
-
|
|
981
|
+
const visibleLogins = logins.filter((item) => !isBlockedPlatform(item.platform))
|
|
982
|
+
for (const item of visibleLogins) {
|
|
897
983
|
if (!item.platform || !item.selfId) continue
|
|
898
984
|
identityInfoCache.set(identityCacheKey('user', item.platform, item.selfId, item.selfId), {
|
|
899
985
|
name: item.name || item.selfId,
|
|
@@ -907,7 +993,7 @@ function onSatoriReady(logins: Array<{ platform: string; selfId: string; name: s
|
|
|
907
993
|
},
|
|
908
994
|
})
|
|
909
995
|
}
|
|
910
|
-
const first =
|
|
996
|
+
const first = visibleLogins[0]
|
|
911
997
|
if (!first) return
|
|
912
998
|
|
|
913
999
|
setActiveBot(first.platform, first.selfId)
|
|
@@ -915,16 +1001,16 @@ function onSatoriReady(logins: Array<{ platform: string; selfId: string; name: s
|
|
|
915
1001
|
login.uin = first.selfId
|
|
916
1002
|
login.nickname = first.name
|
|
917
1003
|
login.platform = first.platform
|
|
918
|
-
login.satoriLogins =
|
|
919
|
-
login.selectedSatoriBot = first.selfId
|
|
1004
|
+
login.satoriLogins = visibleLogins
|
|
1005
|
+
login.selectedSatoriBot = botKey(first.platform, first.selfId)
|
|
920
1006
|
authStore.loginInfo = {
|
|
921
1007
|
uin: first.selfId,
|
|
922
1008
|
user_id: first.selfId,
|
|
923
1009
|
nickname: first.name,
|
|
924
1010
|
platform: first.platform,
|
|
925
1011
|
avatar: first.avatar,
|
|
926
|
-
satoriLogins:
|
|
927
|
-
selectedSatoriBot: first.selfId,
|
|
1012
|
+
satoriLogins: visibleLogins,
|
|
1013
|
+
selectedSatoriBot: botKey(first.platform, first.selfId),
|
|
928
1014
|
}
|
|
929
1015
|
authStore.botInfo = {
|
|
930
1016
|
app_name: 'Satori',
|
|
@@ -944,9 +1030,7 @@ function contactId(item: unknown): string {
|
|
|
944
1030
|
}
|
|
945
1031
|
|
|
946
1032
|
function normalizeGroupId(value: string): string {
|
|
947
|
-
|
|
948
|
-
const wrapped = raw.match(/^\[_?([\s\S]+?)_?\]$/)
|
|
949
|
-
return wrapped ? wrapped[1] : raw || value
|
|
1033
|
+
return String(value)
|
|
950
1034
|
}
|
|
951
1035
|
|
|
952
1036
|
function contactName(item: unknown): string {
|
|
@@ -1092,6 +1176,7 @@ export interface SendForwardResult {
|
|
|
1092
1176
|
ok: boolean
|
|
1093
1177
|
native: boolean
|
|
1094
1178
|
messageId?: string
|
|
1179
|
+
channelId?: string
|
|
1095
1180
|
}
|
|
1096
1181
|
|
|
1097
1182
|
function extractFirstMessageId(data: unknown): string | undefined {
|
|
@@ -1102,7 +1187,56 @@ function extractFirstMessageId(data: unknown): string | undefined {
|
|
|
1102
1187
|
? root.data as unknown[]
|
|
1103
1188
|
: []
|
|
1104
1189
|
const first = list.length > 0 ? getObject(list[0]) : root
|
|
1105
|
-
|
|
1190
|
+
const id = first.id ?? first.message_id
|
|
1191
|
+
return id == null ? undefined : String(id)
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
function extractDirectChannelId(data: unknown): string {
|
|
1195
|
+
const root = getObject(data)
|
|
1196
|
+
const nested = getObject(root.data)
|
|
1197
|
+
const channel = getObject(root.channel)
|
|
1198
|
+
const id = getString(channel.id)
|
|
1199
|
+
|| getString(nested.id)
|
|
1200
|
+
|| getString(root.id)
|
|
1201
|
+
if (!id) throw new Error('user.channel.create 未返回频道 ID')
|
|
1202
|
+
return id
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
function getPrivateSendUserId(action: string, params: Record<string, unknown>): string {
|
|
1206
|
+
const normalized = action.replace(/^_/, '')
|
|
1207
|
+
const userId = params.user_id == null ? '' : String(params.user_id)
|
|
1208
|
+
const groupId = params.group_id == null ? '' : String(params.group_id)
|
|
1209
|
+
const guildId = params.guild_id == null ? '' : String(params.guild_id)
|
|
1210
|
+
if (normalized === 'send_private_msg') return userId
|
|
1211
|
+
if (normalized === 'send_msg'
|
|
1212
|
+
&& userId
|
|
1213
|
+
&& !groupId
|
|
1214
|
+
&& !guildId) {
|
|
1215
|
+
return userId
|
|
1216
|
+
}
|
|
1217
|
+
return ''
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
async function sendPrivateSatoriMessage(
|
|
1221
|
+
userId: string,
|
|
1222
|
+
content: string,
|
|
1223
|
+
guildId: string | undefined,
|
|
1224
|
+
active: ReturnType<typeof getActiveBot>,
|
|
1225
|
+
channelIdHint?: string,
|
|
1226
|
+
): Promise<{ data: unknown; channelId: string }> {
|
|
1227
|
+
// 不构造前缀,优先透传前端已有的完整频道 ID
|
|
1228
|
+
let channelId = channelIdHint || userId
|
|
1229
|
+
try {
|
|
1230
|
+
const direct = await request('user.channel.create', { user_id: userId, guild_id: guildId }, active)
|
|
1231
|
+
channelId = extractDirectChannelId(direct)
|
|
1232
|
+
} catch {
|
|
1233
|
+
// 兼容未实现 createDirectChannel 的适配器,无完整频道 ID 时退回 private: 前缀私聊
|
|
1234
|
+
channelId = channelIdHint || (/^(?:private|direct):/i.test(userId) ? userId : `private:${userId}`)
|
|
1235
|
+
}
|
|
1236
|
+
return {
|
|
1237
|
+
data: await request('message.create', { channel_id: channelId, content }, active),
|
|
1238
|
+
channelId,
|
|
1239
|
+
}
|
|
1106
1240
|
}
|
|
1107
1241
|
|
|
1108
1242
|
export async function sendForwardMessage(
|
|
@@ -1111,29 +1245,33 @@ export async function sendForwardMessage(
|
|
|
1111
1245
|
type: 'group' | 'user',
|
|
1112
1246
|
id: string,
|
|
1113
1247
|
messages: unknown[],
|
|
1248
|
+
channelIdHint?: string,
|
|
1114
1249
|
): Promise<SendForwardResult> {
|
|
1115
1250
|
if (!platform || !selfId || !id || messages.length === 0) {
|
|
1116
1251
|
return { ok: false, native: false }
|
|
1117
1252
|
}
|
|
1118
1253
|
// 优先走 Satori 原生合并转发,避免依赖 onebot 专属的 send-forward API
|
|
1119
1254
|
if (platform) {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
? id
|
|
1123
|
-
: platform === 'yunhu'
|
|
1124
|
-
? `group:${id}`
|
|
1125
|
-
: id
|
|
1126
|
-
: /^(?:private|direct):/i.test(id)
|
|
1127
|
-
? id
|
|
1128
|
-
: `private:${id}`
|
|
1255
|
+
// Satori 的 ID 是完整 string,调用方传什么就原样发什么
|
|
1256
|
+
const channelId = channelIdHint || id
|
|
1129
1257
|
const content = buildForwardMessage(messages)
|
|
1130
1258
|
if (content) {
|
|
1131
1259
|
try {
|
|
1132
|
-
|
|
1260
|
+
let finalChannelId = channelId
|
|
1261
|
+
if (type === 'user') {
|
|
1262
|
+
try {
|
|
1263
|
+
const direct = await request('user.channel.create', { user_id: id }, { platform, selfId })
|
|
1264
|
+
finalChannelId = extractDirectChannelId(direct)
|
|
1265
|
+
} catch {
|
|
1266
|
+
finalChannelId = channelIdHint || (/^(?:private|direct):/i.test(id) ? id : `private:${id}`)
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
const data = await request('message.create', { channel_id: finalChannelId, content }, { platform, selfId })
|
|
1133
1270
|
return {
|
|
1134
1271
|
ok: true,
|
|
1135
1272
|
native: true,
|
|
1136
1273
|
messageId: extractFirstMessageId(data),
|
|
1274
|
+
channelId: finalChannelId,
|
|
1137
1275
|
}
|
|
1138
1276
|
} catch {
|
|
1139
1277
|
// 原生路径失败时回退到旧 API,方便兼容尚未热重载的 Koishi 后端
|
|
@@ -1197,10 +1335,8 @@ function selfMessageToOneBot(record: unknown): Record<string, unknown> | null {
|
|
|
1197
1335
|
const sentAt = Number(obj.sentAt ?? Date.now())
|
|
1198
1336
|
const messageId = getString(obj.messageId)
|
|
1199
1337
|
const localId = getString(obj.id) || `self-${sentAt}`
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
? 'user'
|
|
1203
|
-
: 'group'
|
|
1338
|
+
// 只按记录里的显式 channelType 判断,不根据频道 ID 前缀推断
|
|
1339
|
+
const channelType = getString(obj.channelType) === 'user' ? 'user' : 'group'
|
|
1204
1340
|
if (!platform || !selfId || !channelId) return null
|
|
1205
1341
|
|
|
1206
1342
|
const login = getLogins().find((item) => {
|
|
@@ -1251,7 +1387,7 @@ function selfMessageToOneBot(record: unknown): Record<string, unknown> | null {
|
|
|
1251
1387
|
if (message.length === 0) return null
|
|
1252
1388
|
|
|
1253
1389
|
const groupId = channelType === 'group' ? normalizeGroupId(channelId) : ''
|
|
1254
|
-
const userId = channelType === 'user' ? channelId
|
|
1390
|
+
const userId = channelType === 'user' ? channelId : ''
|
|
1255
1391
|
const guildId = getString(obj.guildId)
|
|
1256
1392
|
const fallbackId = messageId || `self-${localId}`
|
|
1257
1393
|
const rawMessage = getString(obj.content) || getMsgRawTxt({ message })
|
|
@@ -1288,9 +1424,26 @@ function selfMessageToOneBot(record: unknown): Record<string, unknown> | null {
|
|
|
1288
1424
|
},
|
|
1289
1425
|
_from_self_cache: true,
|
|
1290
1426
|
}
|
|
1427
|
+
if (obj.revoked === true) {
|
|
1428
|
+
msg.revoke = true
|
|
1429
|
+
msg.revoked = true
|
|
1430
|
+
msg.revokeTime = Number(obj.revokedAt) || Date.now() / 1000
|
|
1431
|
+
}
|
|
1291
1432
|
return msg
|
|
1292
1433
|
}
|
|
1293
1434
|
|
|
1435
|
+
export async function clearAllCache(): Promise<boolean> {
|
|
1436
|
+
try {
|
|
1437
|
+
const info = await getBootstrap()
|
|
1438
|
+
const response = await fetch(`${location.origin}${info.basePath}/api/clear-all`, {
|
|
1439
|
+
method: 'POST',
|
|
1440
|
+
})
|
|
1441
|
+
return response.ok
|
|
1442
|
+
} catch {
|
|
1443
|
+
return false
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1294
1447
|
export async function loadChatHistoryFromCache(params: {
|
|
1295
1448
|
platform: string
|
|
1296
1449
|
selfId: string
|
|
@@ -1336,6 +1489,11 @@ export async function loadChatHistoryFromCache(params: {
|
|
|
1336
1489
|
target_id: getString(msg.target_id),
|
|
1337
1490
|
sender: userId,
|
|
1338
1491
|
}
|
|
1492
|
+
if (recordObj.revoked === true) {
|
|
1493
|
+
msg.revoke = true
|
|
1494
|
+
msg.revoked = true
|
|
1495
|
+
msg.revokeTime = Number(recordObj.revokedAt) || Date.now() / 1000
|
|
1496
|
+
}
|
|
1339
1497
|
messages.push(msg)
|
|
1340
1498
|
}
|
|
1341
1499
|
const existingIds = new Set(messages.map((item) => getString(item.message_id)))
|
|
@@ -1406,9 +1564,9 @@ async function loadAllBotsCache() {
|
|
|
1406
1564
|
}
|
|
1407
1565
|
const userList = [...groupRaws, ...friendRaws] as unknown as (UserFriendElem & UserGroupElem)[]
|
|
1408
1566
|
|
|
1409
|
-
const state = contactStore.botStates.get(selfId)
|
|
1567
|
+
const state = contactStore.botStates.get(botKey(platform, selfId))
|
|
1410
1568
|
if (!state || state.userList.length === 0) {
|
|
1411
|
-
contactStore.botStates.set(selfId, {
|
|
1569
|
+
contactStore.botStates.set(botKey(platform, selfId), {
|
|
1412
1570
|
userList,
|
|
1413
1571
|
baseList: state?.baseList ?? [],
|
|
1414
1572
|
onMsgList: state?.onMsgList ?? [],
|
|
@@ -1469,6 +1627,7 @@ function buildFriendItem(raw: unknown, data: unknown): Record<string, unknown> {
|
|
|
1469
1627
|
const item: Record<string, unknown> = { ...getObject(raw) }
|
|
1470
1628
|
if (!item.channel_id && item.channelId) item.channel_id = item.channelId
|
|
1471
1629
|
if (!item.guild_id && item.guildId) item.guild_id = item.guildId
|
|
1630
|
+
if (getString(item.guild_id) || getString(item.guildId)) item._groupMember = true
|
|
1472
1631
|
if (name) {
|
|
1473
1632
|
item.nickname = name
|
|
1474
1633
|
item.remark = name
|
|
@@ -1978,6 +2137,20 @@ export class Connector {
|
|
|
1978
2137
|
const mapped = mapAction(api, args)
|
|
1979
2138
|
if (!mapped) return undefined
|
|
1980
2139
|
const active = getActiveBot()
|
|
2140
|
+
const privateUserId = getPrivateSendUserId(api, args)
|
|
2141
|
+
if (privateUserId) {
|
|
2142
|
+
const result = await sendPrivateSatoriMessage(
|
|
2143
|
+
privateUserId,
|
|
2144
|
+
getString(mapped.params.content),
|
|
2145
|
+
getString(args.group_id) || getString(args.guild_id) || undefined,
|
|
2146
|
+
active,
|
|
2147
|
+
getString(mapped.params.channel_id) || getString(args.channel_id),
|
|
2148
|
+
)
|
|
2149
|
+
const response = satoriResponseToOneBot(api, result.data, active.platform)
|
|
2150
|
+
response.channel_id = result.channelId
|
|
2151
|
+
response.channelId = result.channelId
|
|
2152
|
+
return response.data
|
|
2153
|
+
}
|
|
1981
2154
|
const data = await request(mapped.method, mapped.params, active)
|
|
1982
2155
|
return satoriResponseToOneBot(api, data, active.platform).data
|
|
1983
2156
|
}
|
|
@@ -1989,6 +2162,26 @@ export class Connector {
|
|
|
1989
2162
|
return
|
|
1990
2163
|
}
|
|
1991
2164
|
const active = getActiveBot()
|
|
2165
|
+
const privateUserId = getPrivateSendUserId(action, value)
|
|
2166
|
+
if (privateUserId) {
|
|
2167
|
+
void sendPrivateSatoriMessage(
|
|
2168
|
+
privateUserId,
|
|
2169
|
+
getString(mapped.params.content),
|
|
2170
|
+
getString(value.group_id) || getString(value.guild_id) || undefined,
|
|
2171
|
+
active,
|
|
2172
|
+
getString(mapped.params.channel_id) || getString(value.channel_id),
|
|
2173
|
+
)
|
|
2174
|
+
.then((result) => {
|
|
2175
|
+
const response = satoriResponseToOneBot(action, result.data, active.platform)
|
|
2176
|
+
response.channel_id = result.channelId
|
|
2177
|
+
response.channelId = result.channelId
|
|
2178
|
+
dispatch(response, echo)
|
|
2179
|
+
})
|
|
2180
|
+
.catch((error: unknown) => {
|
|
2181
|
+
dispatch({ retcode: -1, data: null, error: String(error) }, echo)
|
|
2182
|
+
})
|
|
2183
|
+
return
|
|
2184
|
+
}
|
|
1992
2185
|
if (active && (action === 'get_friend_list' || action === 'get_group_list')) {
|
|
1993
2186
|
const type = action === 'get_friend_list' ? 'friend' : 'group'
|
|
1994
2187
|
void loadContactType(active, { type, action, echo })
|