koishi-plugin-chat-patch 5.1.0 → 5.3.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-B448YOeN.js +28 -0
- package/client/web/dist/assets/{MsgBody-DLeOklIb.js → MsgBody-DDacjWJ9.js} +1 -1
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-B1dWyCB0.js +67 -0
- package/client/web/dist/assets/{index-Cz89G4we.js → index-BlLut5xn.js} +121 -129
- package/client/web/dist/assets/index-fW_zcub3.css +1 -0
- package/client/web/dist/assets/pinyin-Dsq98249.js +157657 -0
- package/client/web/dist/index.html +2 -2
- package/client/web/dist/notice_local.json +1 -0
- package/client/web/package-lock.json +49 -0
- package/client/web/package.json +1 -0
- package/client/web/public/notice_local.json +1 -0
- package/client/web/src/components/EmojiFace.vue +0 -6
- package/client/web/src/components/FacePan.vue +0 -12
- package/client/web/src/components/MsgBody.vue +3 -4
- package/client/web/src/components/SettingsTab.vue +133 -0
- package/client/web/src/function/connect.ts +34 -14
- package/client/web/src/function/model/emoji.ts +7 -67
- package/client/web/src/function/msg.ts +68 -26
- package/client/web/src/function/utils/appUtil.ts +1 -4
- package/client/web/src/function/utils/msgUtil.ts +86 -52
- package/client/web/src/function/utils/pinyin.ts +25 -65
- package/client/web/src/function/utils/sessionUtil.ts +90 -14
- package/client/web/src/pages/Friends.vue +49 -13
- package/client/web/src/pages/Messages.vue +39 -12
- package/client/web/src/pages/Options.vue +4 -4
- package/client/web/src/pages/options/OptDev.vue +1 -14
- package/package.json +1 -1
- package/client/web/dist/assets/Chat-BoNiWGxb.js +0 -28
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-CGjy4Jzz.js +0 -67
- package/client/web/dist/assets/index-BgOX_tNa.css +0 -1
|
@@ -87,6 +87,7 @@ import { useUIStore } from '../state/ui'
|
|
|
87
87
|
import { useSettingsStore } from '../state/settings'
|
|
88
88
|
import { useQzoneStore } from '../state/qzone'
|
|
89
89
|
import {
|
|
90
|
+
findSessionContact,
|
|
90
91
|
getSessionId,
|
|
91
92
|
getMissingGroupPreviewSessions,
|
|
92
93
|
mergeEarlySessionContacts,
|
|
@@ -119,6 +120,11 @@ function getString(value: unknown): string {
|
|
|
119
120
|
return typeof value === 'string' ? value : String(value)
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
function normalizeChannelForMatch(value: string): string {
|
|
124
|
+
if (/^(?:private|direct):/i.test(value)) return value.replace(/^(?:private|direct):/i, '')
|
|
125
|
+
return normalizeGroupId(value)
|
|
126
|
+
}
|
|
127
|
+
|
|
122
128
|
// 其他 tag
|
|
123
129
|
let listLoadTimes = 0
|
|
124
130
|
const logger = new Logger()
|
|
@@ -963,9 +969,11 @@ const msgFunctions = {
|
|
|
963
969
|
)
|
|
964
970
|
// 更新消息列表
|
|
965
971
|
const onmsg = contactStore.baseOnMsgList.get(normalizeSessionId(id))
|
|
972
|
+
?? findSessionContact(Array.from(contactStore.baseOnMsgList.values()), id)
|
|
966
973
|
if (onmsg && list[0]) {
|
|
974
|
+
const canonicalId = normalizeSessionId(getSessionId(onmsg))
|
|
967
975
|
Object.assign(onmsg, formatMessageData(list[0], Boolean(onmsg.group_id)))
|
|
968
|
-
contactStore.baseOnMsgList.set(
|
|
976
|
+
contactStore.baseOnMsgList.set(canonicalId, onmsg)
|
|
969
977
|
updateBaseOnMsgList()
|
|
970
978
|
}
|
|
971
979
|
}
|
|
@@ -1606,12 +1614,18 @@ function saveUser(msg: { [key: string]: any }, type: string) {
|
|
|
1606
1614
|
list = list.filter((item, index, arr) => {
|
|
1607
1615
|
return (
|
|
1608
1616
|
arr.findIndex((item2) => {
|
|
1609
|
-
const
|
|
1610
|
-
const
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1617
|
+
const channelA = String(item2.channel_id ?? item2.channelId ?? '')
|
|
1618
|
+
const channelB = String(item.channel_id ?? item.channelId ?? '')
|
|
1619
|
+
const groupA = String(item2.group_id ?? item2.id ?? item2.guild_id ?? '')
|
|
1620
|
+
const groupB = String(item.group_id ?? item.id ?? item.guild_id ?? '')
|
|
1621
|
+
if (channelA && channelB) {
|
|
1622
|
+
return normalizeGroupId(channelA) === normalizeGroupId(channelB)
|
|
1623
|
+
}
|
|
1624
|
+
if (channelA || channelB) {
|
|
1625
|
+
return normalizeGroupId(channelA || channelB)
|
|
1626
|
+
=== normalizeGroupId(groupA || groupB)
|
|
1627
|
+
}
|
|
1628
|
+
return normalizeGroupId(groupA) === normalizeGroupId(groupB)
|
|
1615
1629
|
}) == index
|
|
1616
1630
|
)
|
|
1617
1631
|
})
|
|
@@ -1681,15 +1695,34 @@ function saveUser(msg: { [key: string]: any }, type: string) {
|
|
|
1681
1695
|
list,
|
|
1682
1696
|
contactStore.baseOnMsgList,
|
|
1683
1697
|
)
|
|
1684
|
-
const
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1698
|
+
const sessionDedupKey = (item: any): string => {
|
|
1699
|
+
const channel = String(item.channel_id ?? item.channelId ?? '')
|
|
1700
|
+
const group = String(item.group_id ?? '')
|
|
1701
|
+
const user = String(item.user_id ?? '')
|
|
1702
|
+
if (group) return `group:${normalizeGroupId(channel || group)}`
|
|
1703
|
+
return `user:${String(user).replace(/^(?:private|direct):/i, '')}`
|
|
1704
|
+
}
|
|
1705
|
+
const existingIds = new Set(contactStore.userList.map(sessionDedupKey))
|
|
1689
1706
|
const freshList = list.filter((item) => {
|
|
1690
|
-
return !existingIds.has(
|
|
1707
|
+
return !existingIds.has(sessionDedupKey(item))
|
|
1691
1708
|
})
|
|
1692
|
-
|
|
1709
|
+
const mergedContacts = [...contactStore.userList, ...freshList] as (UserFriendElem & UserGroupElem)[]
|
|
1710
|
+
const userMap = new Map<string, UserFriendElem & UserGroupElem>()
|
|
1711
|
+
for (const item of mergedContacts) {
|
|
1712
|
+
const key = sessionDedupKey(item)
|
|
1713
|
+
const existing = userMap.get(key)
|
|
1714
|
+
if (existing) {
|
|
1715
|
+
const pyName = existing.py_name
|
|
1716
|
+
const pyStart = existing.py_start
|
|
1717
|
+
Object.assign(existing, item)
|
|
1718
|
+
if (pyName) existing.py_name = pyName
|
|
1719
|
+
if (pyStart) existing.py_start = pyStart
|
|
1720
|
+
userMap.set(key, existing)
|
|
1721
|
+
} else {
|
|
1722
|
+
userMap.set(key, item)
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
contactStore.userList = [...userMap.values()]
|
|
1693
1726
|
if (
|
|
1694
1727
|
settingsStore.sysConfig.session_display_mode === 'all' ||
|
|
1695
1728
|
didMergeEarlySessions
|
|
@@ -1858,13 +1891,11 @@ async function saveMsg(msg: any, append = undefined as undefined | string) {
|
|
|
1858
1891
|
const lastMsg =
|
|
1859
1892
|
chatStore.messageList[chatStore.messageList.length - 1]
|
|
1860
1893
|
if (lastMsg) {
|
|
1861
|
-
const user = contactStore.userList.
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
})
|
|
1867
|
-
const sessionId = normalizeSessionId(chatStore.chatInfo.show.id)
|
|
1894
|
+
const user = findSessionContact(contactStore.userList, chatStore.chatInfo.show.id)
|
|
1895
|
+
const sessionId = normalizeSessionId(
|
|
1896
|
+
chatStore.chatInfo.show.channel_id
|
|
1897
|
+
?? chatStore.chatInfo.show.id,
|
|
1898
|
+
)
|
|
1868
1899
|
const session = contactStore.baseOnMsgList.get(sessionId) ?? user
|
|
1869
1900
|
if (session) {
|
|
1870
1901
|
const preview = formatMessageData(
|
|
@@ -2302,6 +2333,7 @@ function newMsg(_: string, data: any) {
|
|
|
2302
2333
|
getString(getDataObject(data.channel).id)
|
|
2303
2334
|
const loginId = String(authStore.loginInfo.uin ?? '')
|
|
2304
2335
|
const showId = String(chatStore.chatInfo.show.id ?? '')
|
|
2336
|
+
const showChannelId = getString(chatStore.chatInfo.show.channel_id)
|
|
2305
2337
|
const sender = getString(rawInfo.sender) ||
|
|
2306
2338
|
getString(getDataObject(data.sender).user_id) ||
|
|
2307
2339
|
getString(data.user_id)
|
|
@@ -2323,6 +2355,16 @@ function newMsg(_: string, data: any) {
|
|
|
2323
2355
|
const sessionChannelId = getString(rawInfo.channel_id) || getString(data.channel_id)
|
|
2324
2356
|
const sessionGuildId = getString(rawInfo.guild_id) || getString(data.guild_id)
|
|
2325
2357
|
if (!id || id === '0') return
|
|
2358
|
+
const isCurrentSession = Boolean(
|
|
2359
|
+
(
|
|
2360
|
+
sessionChannelId &&
|
|
2361
|
+
showChannelId &&
|
|
2362
|
+
normalizeChannelForMatch(sessionChannelId) === normalizeChannelForMatch(showChannelId)
|
|
2363
|
+
) || (
|
|
2364
|
+
(!sessionChannelId || !showChannelId) &&
|
|
2365
|
+
(id === showId || targetId === showId || String(sessionChannelId || sessionGuildId || '') === showId)
|
|
2366
|
+
),
|
|
2367
|
+
)
|
|
2326
2368
|
// 在好友列表里找一下他
|
|
2327
2369
|
const senderInfo = contactStore.userList.find((item) => {
|
|
2328
2370
|
return String(item.user_id ?? '') === sender
|
|
@@ -2377,7 +2419,7 @@ function newMsg(_: string, data: any) {
|
|
|
2377
2419
|
}
|
|
2378
2420
|
|
|
2379
2421
|
// 显示消息 ============================================
|
|
2380
|
-
if (id &&
|
|
2422
|
+
if (id && isCurrentSession) {
|
|
2381
2423
|
// 如果有正在输入的提示,清除它
|
|
2382
2424
|
chatStore.chatInfo.show.appendInfo = undefined
|
|
2383
2425
|
const cachedAvatar = getCachedUserAvatar(
|
|
@@ -2517,7 +2559,7 @@ function newMsg(_: string, data: any) {
|
|
|
2517
2559
|
sender != loginId &&
|
|
2518
2560
|
sender !== '' &&
|
|
2519
2561
|
sender !== '0' &&
|
|
2520
|
-
|
|
2562
|
+
!isCurrentSession &&
|
|
2521
2563
|
allowGroupInnerNotice
|
|
2522
2564
|
) {
|
|
2523
2565
|
if (!session.new_msg) {
|
|
@@ -2525,7 +2567,7 @@ function newMsg(_: string, data: any) {
|
|
|
2525
2567
|
contactStore.newMsgCount++
|
|
2526
2568
|
}
|
|
2527
2569
|
}
|
|
2528
|
-
if (
|
|
2570
|
+
if (!isCurrentSession && allowGroupInnerNotice) {
|
|
2529
2571
|
if (data.atme) { session.highlight = $t('[有人@你]') }
|
|
2530
2572
|
if (data.atall) { session.highlight = $t('[@全体]') }
|
|
2531
2573
|
if (isImportant) { session.highlight = $t('[特別关心]') }
|
|
@@ -2542,7 +2584,7 @@ function newMsg(_: string, data: any) {
|
|
|
2542
2584
|
allowGroupSystemNotice
|
|
2543
2585
|
) {
|
|
2544
2586
|
logger.add(LogType.DEBUG, '通知判定:', {
|
|
2545
|
-
notShow:
|
|
2587
|
+
notShow: !isCurrentSession,
|
|
2546
2588
|
notFocus: !document.hasFocus(),
|
|
2547
2589
|
hidden: document.hidden,
|
|
2548
2590
|
isImportant: isImportant
|
|
@@ -2554,7 +2596,7 @@ function newMsg(_: string, data: any) {
|
|
|
2554
2596
|
if (
|
|
2555
2597
|
forceGroupSystemNotice ||
|
|
2556
2598
|
forceImportantNotice ||
|
|
2557
|
-
|
|
2599
|
+
!isCurrentSession ||
|
|
2558
2600
|
!document.hasFocus() ||
|
|
2559
2601
|
document.hidden
|
|
2560
2602
|
) {
|
|
@@ -1026,10 +1026,7 @@ export function checkOpenTimes() {
|
|
|
1026
1026
|
*/
|
|
1027
1027
|
export function checkNotice() {
|
|
1028
1028
|
const uiStore = useUIStore()
|
|
1029
|
-
|
|
1030
|
-
if (import.meta.env.DEV) {
|
|
1031
|
-
url = 'notice_local.json'
|
|
1032
|
-
}
|
|
1029
|
+
const url = 'notice_local.json'
|
|
1033
1030
|
const version = 3
|
|
1034
1031
|
const fetchData = {
|
|
1035
1032
|
time: new Date().getTime().toString(),
|
|
@@ -20,11 +20,14 @@ import { useContactStore } from '../../state/contact'
|
|
|
20
20
|
import { useUIStore } from '../../state/ui'
|
|
21
21
|
import { useAuthStore } from '../../state/auth'
|
|
22
22
|
import { useChatStore } from '../../state/chat'
|
|
23
|
-
import {
|
|
24
|
-
findSessionContact,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
import {
|
|
24
|
+
findSessionContact,
|
|
25
|
+
getSessionAliases,
|
|
26
|
+
getSessionDedupKey,
|
|
27
|
+
getSessionId,
|
|
28
|
+
mergeSessionState,
|
|
29
|
+
normalizeSessionId,
|
|
30
|
+
} from './sessionUtil'
|
|
28
31
|
|
|
29
32
|
const logger = new Logger()
|
|
30
33
|
|
|
@@ -787,8 +790,9 @@ export function updateLastestHistory(item: UserFriendElem & UserGroupElem) {
|
|
|
787
790
|
const authStore = useAuthStore()
|
|
788
791
|
// 发起获取历史消息请求
|
|
789
792
|
const type = item.user_id ? 'user' : 'group'
|
|
790
|
-
const id = item.user_id ? item.user_id : item.group_id
|
|
791
|
-
|
|
793
|
+
const id = item.user_id ? item.user_id : item.group_id
|
|
794
|
+
const sessionId = normalizeSessionId(getSessionId(item))
|
|
795
|
+
let name
|
|
792
796
|
if (authStore.jsonMap.message_list && type != 'group') {
|
|
793
797
|
name = authStore.jsonMap.message_list.private_name
|
|
794
798
|
} else {
|
|
@@ -804,7 +808,7 @@ export function updateLastestHistory(item: UserFriendElem & UserGroupElem) {
|
|
|
804
808
|
message_id: 0,
|
|
805
809
|
count: 1,
|
|
806
810
|
},
|
|
807
|
-
'getChatHistoryOnMsg_' +
|
|
811
|
+
'getChatHistoryOnMsg_' + sessionId,
|
|
808
812
|
)
|
|
809
813
|
}
|
|
810
814
|
|
|
@@ -817,47 +821,75 @@ function getSessionSortName(item: UserFriendElem & UserGroupElem) {
|
|
|
817
821
|
return item.py_start ?? getShowName(item.group_name ?? item.nickname ?? '', item.remark ?? '')
|
|
818
822
|
}
|
|
819
823
|
|
|
820
|
-
function normalizeBaseSessionMap() {
|
|
821
|
-
const contactStore = useContactStore()
|
|
822
|
-
let needNormalize = false
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
824
|
+
function normalizeBaseSessionMap() {
|
|
825
|
+
const contactStore = useContactStore()
|
|
826
|
+
let needNormalize = false
|
|
827
|
+
const seen = new Map<string, UserFriendElem & UserGroupElem>()
|
|
828
|
+
for (const [rawKey, item] of contactStore.baseOnMsgList) {
|
|
829
|
+
const id = getSessionDedupKey(item)
|
|
830
|
+
if (id.endsWith(':0') || id.endsWith(':')) continue
|
|
831
|
+
const existing = seen.get(id)
|
|
832
|
+
if (existing && existing !== item) {
|
|
833
|
+
needNormalize = true
|
|
834
|
+
continue
|
|
835
|
+
}
|
|
836
|
+
seen.set(id, item)
|
|
837
|
+
if (
|
|
838
|
+
typeof rawKey !== 'string' ||
|
|
839
|
+
!getSessionAliases(item).includes(normalizeSessionId(rawKey))
|
|
840
|
+
) {
|
|
841
|
+
needNormalize = true
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (!needNormalize) return
|
|
845
|
+
|
|
846
|
+
const canonical = new Map<string, UserFriendElem & UserGroupElem>()
|
|
847
|
+
contactStore.baseOnMsgList.forEach((item) => {
|
|
848
|
+
const id = getSessionDedupKey(item)
|
|
849
|
+
if (id === 'group:0' || id === 'group:' || id === 'user:0' || id === 'user:') return
|
|
850
|
+
const existing = canonical.get(id)
|
|
851
|
+
if (existing && existing !== item) {
|
|
852
|
+
canonical.set(id, mergeSessionState(existing, item))
|
|
853
|
+
} else if (!existing) {
|
|
854
|
+
canonical.set(id, item)
|
|
855
|
+
}
|
|
856
|
+
})
|
|
857
|
+
contactStore.baseOnMsgList.clear()
|
|
858
|
+
for (const [id, item] of canonical) {
|
|
859
|
+
for (const alias of getSessionAliases(item)) {
|
|
860
|
+
contactStore.baseOnMsgList.set(alias, item)
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function getSessionList() {
|
|
866
|
+
const contactStore = useContactStore()
|
|
867
|
+
const settingsStore = useSettingsStore()
|
|
868
|
+
const sessionMap = new Map<string, UserFriendElem & UserGroupElem>()
|
|
869
|
+
|
|
870
|
+
const addSession = (item: UserFriendElem & UserGroupElem) => {
|
|
871
|
+
const id = getSessionDedupKey(item)
|
|
872
|
+
if (id === 'group:0' || id === 'group:' || id === 'user:0' || id === 'user:') return
|
|
873
|
+
const existing = sessionMap.get(id)
|
|
874
|
+
if (existing && existing !== item) {
|
|
875
|
+
sessionMap.set(id, mergeSessionState(existing, item))
|
|
876
|
+
} else if (!existing) {
|
|
877
|
+
sessionMap.set(id, item)
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (settingsStore.sysConfig.session_display_mode === 'all') {
|
|
882
|
+
contactStore.userList.forEach((item) => {
|
|
883
|
+
addSession(item)
|
|
884
|
+
})
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
contactStore.baseOnMsgList.forEach((item) => {
|
|
888
|
+
addSession(item)
|
|
889
|
+
})
|
|
890
|
+
|
|
891
|
+
return [...sessionMap.values()]
|
|
892
|
+
}
|
|
861
893
|
|
|
862
894
|
/**
|
|
863
895
|
* 刷新消息列表排序
|
|
@@ -890,9 +922,11 @@ export function updateBaseOnMsgList() {
|
|
|
890
922
|
let groupAssistList = [] as any[]
|
|
891
923
|
if (settingsStore.sysConfig.bubble_sort_user) {
|
|
892
924
|
// 将 normalList 进行拆分
|
|
893
|
-
const shouldShowInMainList = (item: UserFriendElem & UserGroupElem) => {
|
|
894
|
-
return item.
|
|
895
|
-
|
|
925
|
+
const shouldShowInMainList = (item: UserFriendElem & UserGroupElem) => {
|
|
926
|
+
return item.group_id
|
|
927
|
+
? item.always_top
|
|
928
|
+
: Boolean(item.user_id) || item.always_top
|
|
929
|
+
}
|
|
896
930
|
onMsgList = topList.concat(normalList.filter((item) => {
|
|
897
931
|
return shouldShowInMainList(item)
|
|
898
932
|
}))
|
|
@@ -5,30 +5,25 @@ export type PinYinData = {
|
|
|
5
5
|
short: string[]
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const PINYIN_SCRIPT_SRC = 'https://lib.stapxs.cn/modules/pinyin.min.js'
|
|
8
|
+
type PinyinModule = typeof import('pinyin')
|
|
11
9
|
|
|
10
|
+
let pinyinModule: PinyinModule | null = null
|
|
12
11
|
let pinyinLoadPromise: Promise<boolean> | null = null
|
|
13
12
|
|
|
14
13
|
function createEmptyPinyinData(): PinYinData {
|
|
15
14
|
return {
|
|
16
15
|
main: [],
|
|
17
|
-
short: []
|
|
16
|
+
short: [],
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
function hasPinyinLib() {
|
|
22
|
-
return typeof window !== 'undefined' && typeof window.pinyin !== 'undefined'
|
|
23
|
-
}
|
|
24
|
-
|
|
25
20
|
function scheduleIdleTask(task: () => void) {
|
|
26
21
|
if (typeof window === 'undefined') return
|
|
27
22
|
|
|
28
23
|
const idleWindow = window as Window & {
|
|
29
24
|
requestIdleCallback?: (
|
|
30
25
|
callback: IdleRequestCallback,
|
|
31
|
-
options?: IdleRequestOptions
|
|
26
|
+
options?: IdleRequestOptions,
|
|
32
27
|
) => number
|
|
33
28
|
}
|
|
34
29
|
|
|
@@ -41,57 +36,23 @@ function scheduleIdleTask(task: () => void) {
|
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
export function isPinyinReady() {
|
|
44
|
-
return
|
|
39
|
+
return pinyinModule !== null
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
export function ensurePinyinLoaded(): Promise<boolean> {
|
|
48
|
-
if (
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
pinyinLoadPromise = null
|
|
62
|
-
}
|
|
63
|
-
resolve(success)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const handleLoad = () => {
|
|
67
|
-
if (script) {
|
|
68
|
-
script.dataset.loaded = 'true'
|
|
69
|
-
}
|
|
70
|
-
finish(hasPinyinLib())
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const handleError = () => {
|
|
74
|
-
if (isDebugMode()) console.warn('拼音库加载失败')
|
|
75
|
-
script?.remove()
|
|
76
|
-
finish(false)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (script?.dataset.loaded === 'true') {
|
|
80
|
-
finish(hasPinyinLib())
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!script) {
|
|
85
|
-
script = document.createElement('script')
|
|
86
|
-
script.src = PINYIN_SCRIPT_SRC
|
|
87
|
-
script.async = true
|
|
88
|
-
script.dataset.ssqqPinyinLib = 'true'
|
|
89
|
-
document.body.appendChild(script)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
script.addEventListener('load', handleLoad, { once: true })
|
|
93
|
-
script.addEventListener('error', handleError, { once: true })
|
|
94
|
-
})
|
|
43
|
+
if (pinyinModule) return Promise.resolve(true)
|
|
44
|
+
if (pinyinLoadPromise) return pinyinLoadPromise
|
|
45
|
+
|
|
46
|
+
pinyinLoadPromise = import('pinyin')
|
|
47
|
+
.then((mod) => {
|
|
48
|
+
pinyinModule = mod
|
|
49
|
+
return true
|
|
50
|
+
})
|
|
51
|
+
.catch((error: unknown) => {
|
|
52
|
+
if (isDebugMode()) console.warn('本地拼音库加载失败:', error)
|
|
53
|
+
pinyinLoadPromise = null
|
|
54
|
+
return false
|
|
55
|
+
})
|
|
95
56
|
|
|
96
57
|
return pinyinLoadPromise
|
|
97
58
|
}
|
|
@@ -103,22 +64,21 @@ export function preloadPinyin() {
|
|
|
103
64
|
}
|
|
104
65
|
|
|
105
66
|
export function getPinyin(name: string): PinYinData {
|
|
106
|
-
if (!
|
|
67
|
+
if (!pinyinModule) return createEmptyPinyinData()
|
|
107
68
|
|
|
108
69
|
try {
|
|
109
|
-
const pinyinLib =
|
|
110
|
-
if (!pinyinLib) return createEmptyPinyinData()
|
|
70
|
+
const pinyinLib = pinyinModule.pinyin
|
|
111
71
|
return {
|
|
112
|
-
main: pinyinLib
|
|
72
|
+
main: pinyinLib(name, {
|
|
113
73
|
heteronym: true,
|
|
114
74
|
compact: true,
|
|
115
75
|
style: 'normal',
|
|
116
|
-
}).map((item
|
|
117
|
-
short: pinyinLib
|
|
76
|
+
}).map((item) => item.join('').toLowerCase()),
|
|
77
|
+
short: pinyinLib(name, {
|
|
118
78
|
heteronym: true,
|
|
119
79
|
compact: true,
|
|
120
80
|
style: 'first_letter',
|
|
121
|
-
}).map((item
|
|
81
|
+
}).map((item) => item.join('').toLowerCase()),
|
|
122
82
|
}
|
|
123
83
|
} catch (error) {
|
|
124
84
|
if (isDebugMode()) console.warn('拼音转换失败:', error)
|
|
@@ -128,7 +88,7 @@ export function getPinyin(name: string): PinYinData {
|
|
|
128
88
|
|
|
129
89
|
export function matchPinyin(
|
|
130
90
|
pinyinData: PinYinData,
|
|
131
|
-
matchStr: string
|
|
91
|
+
matchStr: string,
|
|
132
92
|
): boolean {
|
|
133
93
|
const str = matchStr.toLowerCase()
|
|
134
94
|
for (const py of pinyinData.main) {
|
|
@@ -18,15 +18,45 @@ export function getSessionId(item: Session): number | string {
|
|
|
18
18
|
return item.user_id ?? item.group_id ?? 0
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function getLegacySessionId(item: Session): number | string | undefined {
|
|
22
|
+
return item.user_id ?? item.group_id
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getSessionAliases(item: Session): string[] {
|
|
26
|
+
const rawAliases: Array<number | string | undefined> = [
|
|
27
|
+
getSessionId(item),
|
|
28
|
+
getLegacySessionId(item),
|
|
29
|
+
]
|
|
30
|
+
if (item.group_id !== undefined && item.group_id !== null) {
|
|
31
|
+
rawAliases.push(normalizeGroupId(String(item.group_id)))
|
|
32
|
+
}
|
|
33
|
+
if (item.user_id !== undefined && item.user_id !== null) {
|
|
34
|
+
rawAliases.push(String(item.user_id).replace(/^(?:private|direct):/i, ''))
|
|
35
|
+
}
|
|
36
|
+
const aliases = rawAliases.filter((value): value is number | string => {
|
|
37
|
+
const text = String(value ?? '')
|
|
38
|
+
return text !== '' && text !== '0'
|
|
39
|
+
})
|
|
40
|
+
return [...new Set(aliases.map((value) => normalizeSessionId(value)))]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getSessionDedupKey(item: Session): string {
|
|
44
|
+
const channelId = String(item.channel_id ?? item.channelId ?? '')
|
|
45
|
+
const groupId = String(item.group_id ?? '')
|
|
46
|
+
const userId = String(item.user_id ?? '')
|
|
47
|
+
if (groupId) return `group:${normalizeGroupId(channelId || groupId)}`
|
|
48
|
+
if (userId) return `user:${userId.replace(/^(?:private|direct):/i, '')}`
|
|
49
|
+
return /^(?:private|direct):/i.test(channelId)
|
|
50
|
+
? `user:${channelId.replace(/^(?:private|direct):/i, '')}`
|
|
51
|
+
: `group:${normalizeGroupId(channelId)}`
|
|
52
|
+
}
|
|
53
|
+
|
|
21
54
|
export function setSessionContact(
|
|
22
55
|
map: Map<number | string, Session>,
|
|
23
56
|
item: Session,
|
|
24
57
|
) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const legacyId = item.user_id ?? item.group_id
|
|
28
|
-
if (legacyId !== undefined && legacyId !== null && String(legacyId) !== key) {
|
|
29
|
-
map.set(normalizeSessionId(String(legacyId)), item)
|
|
58
|
+
for (const alias of getSessionAliases(item)) {
|
|
59
|
+
map.set(alias, item)
|
|
30
60
|
}
|
|
31
61
|
}
|
|
32
62
|
|
|
@@ -34,8 +64,13 @@ export function findSessionContact(
|
|
|
34
64
|
contacts: Session[],
|
|
35
65
|
sessionId: number | string,
|
|
36
66
|
) {
|
|
67
|
+
const target = normalizeSessionId(sessionId)
|
|
37
68
|
return contacts.find((item) => {
|
|
38
|
-
return
|
|
69
|
+
return getSessionAliases(item).some((alias) => alias === target)
|
|
70
|
+
|| (
|
|
71
|
+
Boolean(item.group_id) &&
|
|
72
|
+
normalizeGroupId(String(item.group_id)) === normalizeGroupId(target)
|
|
73
|
+
)
|
|
39
74
|
})
|
|
40
75
|
}
|
|
41
76
|
|
|
@@ -98,6 +133,28 @@ function copyDefinedSessionState<K extends SessionStateKey>(
|
|
|
98
133
|
) {
|
|
99
134
|
const value = currentSession[key]
|
|
100
135
|
if (value !== undefined) {
|
|
136
|
+
const current = contact[key]
|
|
137
|
+
if (
|
|
138
|
+
key === 'time' &&
|
|
139
|
+
typeof current === 'number' &&
|
|
140
|
+
typeof value === 'number' &&
|
|
141
|
+
current > value
|
|
142
|
+
) {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
contact[key] = value
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function copyMissingIdentity<K extends keyof Session>(
|
|
150
|
+
contact: Session,
|
|
151
|
+
currentSession: Session,
|
|
152
|
+
key: K,
|
|
153
|
+
) {
|
|
154
|
+
const value = currentSession[key]
|
|
155
|
+
if (value === undefined || value === null || String(value) === '') return
|
|
156
|
+
const current = contact[key]
|
|
157
|
+
if (current === undefined || current === null || String(current) === '') {
|
|
101
158
|
contact[key] = value
|
|
102
159
|
}
|
|
103
160
|
}
|
|
@@ -106,6 +163,21 @@ export function mergeSessionState(
|
|
|
106
163
|
contact: Session,
|
|
107
164
|
currentSession: Session,
|
|
108
165
|
) {
|
|
166
|
+
const identityKeys = [
|
|
167
|
+
'channel_id',
|
|
168
|
+
'channelId',
|
|
169
|
+
'guild_id',
|
|
170
|
+
'guildId',
|
|
171
|
+
'group_id',
|
|
172
|
+
'user_id',
|
|
173
|
+
'group_name',
|
|
174
|
+
'nickname',
|
|
175
|
+
'remark',
|
|
176
|
+
'avatar',
|
|
177
|
+
] as const
|
|
178
|
+
identityKeys.forEach((key) =>
|
|
179
|
+
copyMissingIdentity(contact, currentSession, key),
|
|
180
|
+
)
|
|
109
181
|
SESSION_STATE_KEYS.forEach((key) =>
|
|
110
182
|
copyDefinedSessionState(contact, currentSession, key),
|
|
111
183
|
)
|
|
@@ -122,14 +194,18 @@ export function mergeEarlySessionContacts(
|
|
|
122
194
|
) {
|
|
123
195
|
let didMerge = false
|
|
124
196
|
contacts.forEach((contact) => {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
197
|
+
for (const [key, currentSession] of sessions.entries()) {
|
|
198
|
+
if (currentSession === contact) continue
|
|
199
|
+
if (
|
|
200
|
+
findSessionContact([currentSession], getSessionId(contact))
|
|
201
|
+
|| getSessionDedupKey(contact) === getSessionDedupKey(currentSession)
|
|
202
|
+
) {
|
|
203
|
+
sessions.set(
|
|
204
|
+
key,
|
|
205
|
+
mergeSessionState(contact, currentSession),
|
|
206
|
+
)
|
|
207
|
+
didMerge = true
|
|
208
|
+
}
|
|
133
209
|
}
|
|
134
210
|
})
|
|
135
211
|
return didMerge
|