koishi-plugin-chat-patch 5.1.0 → 5.3.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/client/web/dist/assets/Chat-Bo5JdcNg.js +28 -0
- package/client/web/dist/assets/{Chat-CTdyeaX2.css → Chat-C-rmzMIw.css} +1 -1
- package/client/web/dist/assets/{MsgBody-DLeOklIb.js → MsgBody-h4C1nnBQ.js} +1 -1
- package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-a902ps2r.js +67 -0
- package/client/web/dist/assets/{index-Cz89G4we.js → index-CdTmWcO4.js} +121 -129
- package/client/web/dist/assets/index-wjp_A4n1.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/AboutPan.vue +2 -1
- package/client/web/src/components/BulletinBody.vue +1 -1
- package/client/web/src/components/EmojiFace.vue +0 -6
- package/client/web/src/components/FacePan.vue +0 -12
- package/client/web/src/components/FriendBody.vue +1 -0
- package/client/web/src/components/MsgBody.vue +4 -4
- package/client/web/src/components/SettingsTab.vue +133 -0
- package/client/web/src/components/TinySessionBody.vue +1 -0
- package/client/web/src/components/UpdatePan.vue +2 -2
- package/client/web/src/components/tooltip/UserInfoTooltip.vue +1 -1
- package/client/web/src/function/connect.ts +81 -28
- package/client/web/src/function/model/emoji.ts +7 -67
- package/client/web/src/function/msg.ts +68 -26
- package/client/web/src/function/satori-model.ts +8 -0
- package/client/web/src/function/satori.ts +31 -1
- package/client/web/src/function/utils/appUtil.ts +1 -4
- package/client/web/src/function/utils/avatarUtil.ts +18 -3
- 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/main.ts +5 -0
- package/client/web/src/pages/Chat.vue +3 -4
- package/client/web/src/pages/Friends.vue +72 -30
- package/client/web/src/pages/Info.vue +3 -3
- package/client/web/src/pages/Messages.vue +59 -26
- package/client/web/src/pages/Options.vue +4 -4
- package/client/web/src/pages/Qzone.vue +2 -2
- 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 +1 -14
- package/lib/index.js +14 -14
- package/lib/types.d.ts +115 -0
- package/package.json +1 -1
- package/src/bootstrap.ts +1 -0
- package/src/config.ts +1 -1
- package/src/recorder.ts +7 -7
- package/src/types.ts +4 -0
- package/src/web.ts +8 -9
- 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
|
@@ -38,17 +38,17 @@
|
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
40
40
|
<div id="message-list-body" class="robot-accordion-list">
|
|
41
|
-
<div v-for="bot in satoriLogins" :key="'bot-' + bot.selfId"
|
|
42
|
-
:class="['robot-accordion', { expanded: bot.selfId === activeBotId }]">
|
|
41
|
+
<div v-for="bot in satoriLogins" :key="'bot-' + botKey(bot.platform, bot.selfId)"
|
|
42
|
+
:class="['robot-accordion', { expanded: botKey(bot.platform, bot.selfId) === activeBotId }]">
|
|
43
43
|
<div class="robot-accordion-header" @click="toggleRobot(bot)">
|
|
44
|
-
<img :src="bot.avatar || '/img/icons/icon.svg'" :alt="bot.name" @error="avatarError">
|
|
44
|
+
<img data-avatar :src="bot.avatar || '/img/icons/icon.svg'" :alt="bot.name" @error="avatarError">
|
|
45
45
|
<div>
|
|
46
46
|
<span :title="bot.name">{{ bot.name }}</span>
|
|
47
47
|
<small>{{ bot.platform }}</small>
|
|
48
48
|
</div>
|
|
49
|
-
<font-awesome-icon :icon="['fas', bot.selfId === activeBotId ? 'angle-up' : 'angle-down']" />
|
|
49
|
+
<font-awesome-icon :icon="['fas', botKey(bot.platform, bot.selfId) === activeBotId ? 'angle-up' : 'angle-down']" />
|
|
50
50
|
</div>
|
|
51
|
-
<div v-if="bot.selfId === activeBotId" class="robot-accordion-content">
|
|
51
|
+
<div v-if="botKey(bot.platform, bot.selfId) === activeBotId" class="robot-accordion-content">
|
|
52
52
|
<div v-if="!showGroupAssist &&
|
|
53
53
|
!contactStore.systemNoticesList &&
|
|
54
54
|
(!contactStore.groupAssistList || contactStore.groupAssistList.length === 0) &&
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
<!-- 其他消息 -->
|
|
99
99
|
<FriendBody
|
|
100
100
|
v-for="item in contactStore.onMsgList"
|
|
101
|
-
:key="'inMessage-' + (item.
|
|
101
|
+
:key="'inMessage-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
102
102
|
:select="chat.show.id === item.user_id || (chat.show.id === item.group_id && chat.group_name != '')"
|
|
103
103
|
:menu="menu.select && menu.select == item"
|
|
104
104
|
:data="item"
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
<!-- 其他消息 -->
|
|
151
151
|
<FriendBody
|
|
152
152
|
v-for="item in contactStore.groupAssistList"
|
|
153
|
-
:key="'inMessage-' + (item.
|
|
153
|
+
:key="'inMessage-' + (item.channel_id || item.channelId || item.user_id || item.group_id)"
|
|
154
154
|
:select="chat.show.id === item.user_id || (chat.show.id === item.group_id && chat.group_name != '')"
|
|
155
155
|
:menu="menu.select && menu.select == item"
|
|
156
156
|
:data="item"
|
|
@@ -218,7 +218,7 @@
|
|
|
218
218
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
|
219
219
|
import { login as loginInfo } from '../function/connect'
|
|
220
220
|
import { Connector, flushPendingBotEvents, loadContactsFromCache, restoreBotStateFromMessageCache } from '../function/connect'
|
|
221
|
-
import { getActiveBot, getLogins, setActiveBot } from '../function/satori'
|
|
221
|
+
import { botKey, getActiveBot, getLogins, setActiveBot } from '../function/satori'
|
|
222
222
|
import { getShowName, updateBaseOnMsgList } from '../function/utils/msgUtil'
|
|
223
223
|
|
|
224
224
|
import {
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
import { refreshFavicon } from '../function/favicon'
|
|
233
233
|
import { backend } from '../runtime/backend'
|
|
234
234
|
import History from '../components/History.vue'
|
|
235
|
-
import { normalizeSessionId } from '../function/utils/sessionUtil'
|
|
235
|
+
import { findSessionContact, normalizeSessionId } from '../function/utils/sessionUtil'
|
|
236
236
|
import { avatarError } from '../function/utils/avatarUtil'
|
|
237
237
|
import { useUIStore } from '../state/ui'
|
|
238
238
|
import { useAuthStore } from '../state/auth'
|
|
@@ -249,7 +249,12 @@
|
|
|
249
249
|
const chatStore = useChatStore()
|
|
250
250
|
const settingsStore = useSettingsStore()
|
|
251
251
|
const satoriLogins = ref<Array<{ platform: string; selfId: string; name: string; avatar?: string; status?: number; features?: string[] }>>(getLogins())
|
|
252
|
-
const
|
|
252
|
+
const active = getActiveBot()
|
|
253
|
+
const activeBotId = ref(
|
|
254
|
+
active?.platform && active.selfId
|
|
255
|
+
? botKey(active.platform, active.selfId)
|
|
256
|
+
: loginInfo.selectedSatoriBot ?? '',
|
|
257
|
+
)
|
|
253
258
|
|
|
254
259
|
watch(() => loginInfo.satoriLogins, (list) => {
|
|
255
260
|
satoriLogins.value = list ?? []
|
|
@@ -259,7 +264,7 @@
|
|
|
259
264
|
}, { immediate: true })
|
|
260
265
|
|
|
261
266
|
const currentBotName = computed(() => {
|
|
262
|
-
return satoriLogins.value.find((item) => item.selfId === activeBotId.value)?.name ?? ''
|
|
267
|
+
return satoriLogins.value.find((item) => botKey(item.platform, item.selfId) === activeBotId.value)?.name ?? ''
|
|
263
268
|
})
|
|
264
269
|
|
|
265
270
|
function backToRobots() {
|
|
@@ -280,27 +285,39 @@
|
|
|
280
285
|
}
|
|
281
286
|
|
|
282
287
|
function restoreBotStateUi(bot: { platform: string; selfId: string }) {
|
|
283
|
-
const restored = contactStore.botStates.get(bot.selfId)
|
|
288
|
+
const restored = contactStore.botStates.get(botKey(bot.platform, bot.selfId))
|
|
284
289
|
if (!restored) return
|
|
285
290
|
contactStore.baseOnMsgList.clear()
|
|
286
|
-
for (const [
|
|
287
|
-
|
|
291
|
+
for (const [, value] of restored.baseList) {
|
|
292
|
+
const id = String(value.channel_id || value.channelId || value.user_id || value.group_id || '')
|
|
293
|
+
if (id && id !== '0') {
|
|
294
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(id), value)
|
|
295
|
+
const legacyId = String(value.user_id || value.group_id || '')
|
|
296
|
+
if (legacyId && legacyId !== id) {
|
|
297
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(legacyId), value)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
288
300
|
}
|
|
289
301
|
for (const item of restored.onMsgList) {
|
|
290
|
-
const id = String(item.user_id
|
|
302
|
+
const id = String(item.channel_id || item.channelId || item.user_id || item.group_id || '')
|
|
291
303
|
if (!id || id === '0') continue
|
|
292
304
|
contactStore.baseOnMsgList.set(
|
|
293
305
|
normalizeSessionId(id),
|
|
294
306
|
item as UserFriendElem & UserGroupElem,
|
|
295
307
|
)
|
|
308
|
+
const legacyId = String(item.user_id || item.group_id || '')
|
|
309
|
+
if (legacyId && legacyId !== id) {
|
|
310
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(legacyId), item as UserFriendElem & UserGroupElem)
|
|
311
|
+
}
|
|
296
312
|
}
|
|
297
313
|
contactStore.onMsgList = restored.onMsgList
|
|
298
314
|
}
|
|
299
315
|
|
|
300
316
|
function selectRobot(bot: { platform: string; selfId: string; name: string; avatar?: string; features?: string[] }) {
|
|
301
|
-
|
|
317
|
+
const key = botKey(bot.platform, bot.selfId)
|
|
318
|
+
if (key === activeBotId.value) return
|
|
302
319
|
snapshotCurrentBot()
|
|
303
|
-
activeBotId.value =
|
|
320
|
+
activeBotId.value = key
|
|
304
321
|
setActiveBot(bot.platform, bot.selfId)
|
|
305
322
|
loginInfo.uin = bot.selfId
|
|
306
323
|
loginInfo.nickname = bot.name
|
|
@@ -313,9 +330,9 @@
|
|
|
313
330
|
platform: bot.platform,
|
|
314
331
|
avatar: bot.avatar,
|
|
315
332
|
satoriLogins: satoriLogins.value,
|
|
316
|
-
selectedSatoriBot:
|
|
333
|
+
selectedSatoriBot: key,
|
|
317
334
|
}
|
|
318
|
-
const saved = contactStore.botStates.get(
|
|
335
|
+
const saved = contactStore.botStates.get(key)
|
|
319
336
|
if (saved) {
|
|
320
337
|
contactStore.userList = saved.userList
|
|
321
338
|
contactStore.baseOnMsgList.clear()
|
|
@@ -343,7 +360,7 @@
|
|
|
343
360
|
}
|
|
344
361
|
|
|
345
362
|
function toggleRobot(bot: { platform: string; selfId: string; name: string; avatar?: string; features?: string[] }) {
|
|
346
|
-
if (activeBotId.value === bot.selfId) {
|
|
363
|
+
if (activeBotId.value === botKey(bot.platform, bot.selfId)) {
|
|
347
364
|
backToRobots()
|
|
348
365
|
} else {
|
|
349
366
|
selectRobot(bot)
|
|
@@ -376,7 +393,7 @@
|
|
|
376
393
|
* @param data 联系人对象
|
|
377
394
|
*/
|
|
378
395
|
function userClick(data: UserFriendElem & UserGroupElem) {
|
|
379
|
-
const id = data.
|
|
396
|
+
const id = data.group_id || data.user_id
|
|
380
397
|
if (id === undefined || id === null || String(id) === '' || String(id) === '0') return
|
|
381
398
|
if (!trRead.value && id != props.chat.show.id) {
|
|
382
399
|
if (uiStore.openSideBar) {
|
|
@@ -385,11 +402,11 @@
|
|
|
385
402
|
const back = {
|
|
386
403
|
// 临时会话标志
|
|
387
404
|
temp: data.group_name == '' ? data.group_id : undefined,
|
|
388
|
-
type: data.
|
|
405
|
+
type: data.group_id ? 'group' : 'user',
|
|
389
406
|
id: id,
|
|
390
407
|
name: getShowName(data.group_name || data.nickname, data.remark),
|
|
391
408
|
avatar: data.avatar || '/img/icons/icon.svg',
|
|
392
|
-
channel_id: data.channel_id
|
|
409
|
+
channel_id: data.channel_id || data.channelId,
|
|
393
410
|
guild_id: data.guild_id ?? data.guildId,
|
|
394
411
|
}
|
|
395
412
|
if (props.chat.id != back.id) {
|
|
@@ -401,9 +418,10 @@
|
|
|
401
418
|
}
|
|
402
419
|
}
|
|
403
420
|
// 清除新消息标记
|
|
404
|
-
const sessionKey = data.channel_id
|
|
421
|
+
const sessionKey = data.channel_id || data.channelId || id
|
|
405
422
|
const item = contactStore.baseOnMsgList.get(normalizeSessionId(sessionKey))
|
|
406
423
|
?? contactStore.baseOnMsgList.get(normalizeSessionId(id))
|
|
424
|
+
?? findSessionContact(Array.from(contactStore.baseOnMsgList.values()), id)
|
|
407
425
|
if(item) {
|
|
408
426
|
if(item.new_msg) {
|
|
409
427
|
item.new_msg = false
|
|
@@ -411,6 +429,7 @@
|
|
|
411
429
|
}
|
|
412
430
|
item.highlight = undefined
|
|
413
431
|
contactStore.baseOnMsgList.set(normalizeSessionId(sessionKey), item)
|
|
432
|
+
updateBaseOnMsgList()
|
|
414
433
|
// 关闭所有通知
|
|
415
434
|
new Notify().closeAll((item.group_id ?? item.user_id).toString())
|
|
416
435
|
}
|
|
@@ -474,9 +493,10 @@
|
|
|
474
493
|
*/
|
|
475
494
|
function readMsg(data: UserFriendElem & UserGroupElem) {
|
|
476
495
|
const id = data.group_id ? data.group_id : data.user_id
|
|
477
|
-
const sessionKey = data.channel_id
|
|
496
|
+
const sessionKey = data.channel_id || data.channelId || id
|
|
478
497
|
const item = contactStore.baseOnMsgList.get(normalizeSessionId(sessionKey))
|
|
479
498
|
?? contactStore.baseOnMsgList.get(normalizeSessionId(id))
|
|
499
|
+
?? findSessionContact(Array.from(contactStore.baseOnMsgList.values()), id)
|
|
480
500
|
if(item) {
|
|
481
501
|
if(item.new_msg) {
|
|
482
502
|
item.new_msg = false
|
|
@@ -484,6 +504,7 @@
|
|
|
484
504
|
}
|
|
485
505
|
item.highlight = undefined
|
|
486
506
|
contactStore.baseOnMsgList.set(normalizeSessionId(sessionKey), item)
|
|
507
|
+
updateBaseOnMsgList()
|
|
487
508
|
}
|
|
488
509
|
// pop
|
|
489
510
|
new PopInfo().add(
|
|
@@ -518,7 +539,16 @@
|
|
|
518
539
|
)
|
|
519
540
|
if (topList.indexOf(id) >= 0) {
|
|
520
541
|
item.always_top = true
|
|
521
|
-
|
|
542
|
+
const sessionId = String(
|
|
543
|
+
item.channel_id
|
|
544
|
+
?? item.channelId
|
|
545
|
+
?? item.user_id
|
|
546
|
+
?? item.group_id
|
|
547
|
+
?? '',
|
|
548
|
+
)
|
|
549
|
+
if (sessionId && sessionId !== '0') {
|
|
550
|
+
contactStore.baseOnMsgList.set(normalizeSessionId(sessionId), item)
|
|
551
|
+
}
|
|
522
552
|
}
|
|
523
553
|
})
|
|
524
554
|
}
|
|
@@ -558,7 +588,10 @@
|
|
|
558
588
|
break
|
|
559
589
|
case 'remove': {
|
|
560
590
|
const id = item.user_id ? item.user_id : item.group_id
|
|
591
|
+
const sessionId = String(item.channel_id || item.channelId || id || '')
|
|
561
592
|
contactStore.baseOnMsgList.delete(normalizeSessionId(id))
|
|
593
|
+
contactStore.baseOnMsgList.delete(normalizeSessionId(sessionId))
|
|
594
|
+
updateBaseOnMsgList()
|
|
562
595
|
refreshFavicon()
|
|
563
596
|
break
|
|
564
597
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<!-- 保留占位元素,避免设置页右侧布局被原有左侧选择器样式影响 -->
|
|
12
12
|
<div class="opt-side-placeholder" style="display: none" />
|
|
13
13
|
<div>
|
|
14
|
-
<
|
|
14
|
+
<SettingsTab v-show="show" class="opt-tab">
|
|
15
15
|
<div :name="$t('账号')">
|
|
16
16
|
<OptAccount :config="config" />
|
|
17
17
|
</div>
|
|
@@ -27,18 +27,18 @@
|
|
|
27
27
|
<div v-if="showAbout" :name="$t('关于')">
|
|
28
28
|
<AboutPan class="opt-about" show-u-i />
|
|
29
29
|
</div>
|
|
30
|
-
</
|
|
30
|
+
</SettingsTab>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<script setup lang="ts">
|
|
36
|
-
import { ref, watch, onMounted
|
|
36
|
+
import { ref, watch, onMounted } from 'vue'
|
|
37
37
|
|
|
38
38
|
import { i18n } from '../main'
|
|
39
39
|
import { useSettingsStore } from '../state/settings'
|
|
40
40
|
|
|
41
|
-
import
|
|
41
|
+
import SettingsTab from '../components/SettingsTab.vue'
|
|
42
42
|
import OptAccount from './options/OptAccount.vue'
|
|
43
43
|
import OptView from './options/OptView.vue'
|
|
44
44
|
import OptDev from './options/OptDev.vue'
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
class="qzone-feed-card ss-card">
|
|
66
66
|
<article>
|
|
67
67
|
<header class="qzone-feed-card-header">
|
|
68
|
-
<img :src="item.avatar" :alt="item.nickname">
|
|
68
|
+
<img data-avatar :src="item.avatar" :alt="item.nickname">
|
|
69
69
|
<div class="qzone-feed-meta">
|
|
70
70
|
<a>{{ item.nickname }}</a>
|
|
71
71
|
<span>{{ item.timeText }}</span>
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
</template>
|
|
150
150
|
</div>
|
|
151
151
|
<div class="qzone-feed-reply">
|
|
152
|
-
<img :src="authStore.loginInfo.avatar || '/img/icons/icon.svg'">
|
|
152
|
+
<img data-avatar :src="authStore.loginInfo.avatar || '/img/icons/icon.svg'">
|
|
153
153
|
<label :for="`qzone-reply-input-${item.id}`" class="sr-only">{{ $t('评论输入框') }}</label>
|
|
154
154
|
<input :id="`qzone-reply-input-${item.id}`"
|
|
155
155
|
v-model="getReplyDraft(item.id).content"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
:key="'sysNot-' + index">
|
|
21
21
|
<div v-if="notice.request_type == 'friend'">
|
|
22
22
|
<div>
|
|
23
|
-
<img :src="notice.avatar || '/img/icons/icon.svg'">
|
|
23
|
+
<img data-avatar :src="notice.avatar || '/img/icons/icon.svg'">
|
|
24
24
|
<div>
|
|
25
25
|
<span>{{ notice.user_id }}
|
|
26
26
|
{{ $t('请求加为好友') }}</span>
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
</div>
|
|
50
50
|
<div v-else-if="notice.request_type == 'group'">
|
|
51
51
|
<div v-if="notice.sub_type == 'add'">
|
|
52
|
-
<img :src="notice.avatar || '/img/icons/icon.svg'">
|
|
52
|
+
<img data-avatar :src="notice.avatar || '/img/icons/icon.svg'">
|
|
53
53
|
<div>
|
|
54
54
|
<span>{{ getName(notice.user_id) }}
|
|
55
55
|
{{ $t('申请加入群聊') }}
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
</div>
|
|
69
69
|
<div v-else>
|
|
70
70
|
<!-- TODO:这情况会出现在 notice 里?记不太清了,先放着吧 😭 -->
|
|
71
|
-
<img :src="notice.group_avatar || '/img/icons/icon.svg'">
|
|
71
|
+
<img data-avatar :src="notice.group_avatar || '/img/icons/icon.svg'">
|
|
72
72
|
<div>
|
|
73
73
|
<span>{{ getName(notice.user_id) }}
|
|
74
74
|
{{ $t('邀请你加入群聊') }}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<div v-for="account in accounts"
|
|
14
14
|
:key="account.platform + ':' + account.selfId"
|
|
15
15
|
:class="['ss-card', 'account-info', { active: isActive(account) }]">
|
|
16
|
-
<img :src="account.avatar || '/img/icons/icon.svg'">
|
|
16
|
+
<img data-avatar :src="account.avatar || '/img/icons/icon.svg'">
|
|
17
17
|
<div>
|
|
18
18
|
<div>
|
|
19
19
|
<span>{{ account.name || account.selfId }}</span>
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<script setup lang="ts">
|
|
39
39
|
import { computed } from 'vue'
|
|
40
40
|
import { login as loginInfo } from '../../function/connect'
|
|
41
|
-
import { getActiveBot } from '../../function/satori'
|
|
41
|
+
import { botKey, getActiveBot, getLogins } from '../../function/satori'
|
|
42
42
|
import { useAuthStore } from '../../state/auth'
|
|
43
43
|
import { i18n } from '../../main'
|
|
44
44
|
|
|
@@ -63,9 +63,11 @@ const accounts = computed<SatoriAccount[]>(() => {
|
|
|
63
63
|
const activeBot = computed(() => {
|
|
64
64
|
const current = getActiveBot()
|
|
65
65
|
if (current?.platform && current.selfId) return current
|
|
66
|
+
const selectedKey = String(authStore.loginInfo.selectedSatoriBot ?? '')
|
|
67
|
+
const selected = getLogins().find((item) => botKey(item.platform, item.selfId) === selectedKey)
|
|
66
68
|
return {
|
|
67
|
-
platform: String(authStore.loginInfo.platform ?? ''),
|
|
68
|
-
selfId: String(
|
|
69
|
+
platform: String(selected?.platform ?? authStore.loginInfo.platform ?? ''),
|
|
70
|
+
selfId: String(selected?.selfId ?? authStore.loginInfo.uin ?? ''),
|
|
69
71
|
}
|
|
70
72
|
})
|
|
71
73
|
|
|
@@ -315,20 +315,7 @@ import packageInfo from '../../../package.json'
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
info += 'Network Info:\n'
|
|
318
|
-
|
|
319
|
-
['Github ', 'https://api.github.com'],
|
|
320
|
-
['SSQQ API ', 'https://api.stapxs.cn'],
|
|
321
|
-
]
|
|
322
|
-
for (const item of testList) {
|
|
323
|
-
const start = new Date().getTime()
|
|
324
|
-
try {
|
|
325
|
-
await fetch(item[1], { method: 'GET' })
|
|
326
|
-
const end = new Date().getTime()
|
|
327
|
-
info += ` ${item[0]} -> ${end - start} ms\n`
|
|
328
|
-
} catch (e) {
|
|
329
|
-
info += ` ${item[0]} -> failed\n`
|
|
330
|
-
}
|
|
331
|
-
}
|
|
318
|
+
info += ' local only\n'
|
|
332
319
|
info += '```'
|
|
333
320
|
// 构建 popBox 内容
|
|
334
321
|
const popInfo = {
|
package/lib/index.js
CHANGED
|
@@ -844,8 +844,8 @@ var _Recorder = class _Recorder {
|
|
|
844
844
|
}
|
|
845
845
|
async handleSession(session) {
|
|
846
846
|
const platform = session.platform || "unknown";
|
|
847
|
-
if (this.isBlocked(platform)) return;
|
|
848
847
|
if (!MESSAGE_TYPES.has(session.type)) return;
|
|
848
|
+
if (this.isBlocked(platform)) return;
|
|
849
849
|
const event = session.toJSON();
|
|
850
850
|
const message = event.message;
|
|
851
851
|
const record = {
|
|
@@ -866,15 +866,15 @@ var _Recorder = class _Recorder {
|
|
|
866
866
|
};
|
|
867
867
|
try {
|
|
868
868
|
await this.database.appendMessage(record);
|
|
869
|
-
void this.cacheMessageContacts(event).catch((error) => {
|
|
870
|
-
this.logger.warn("缓存消息联系人失败:", error);
|
|
871
|
-
});
|
|
872
|
-
void this.cacheMessageMedia(event).catch((error) => {
|
|
873
|
-
this.logger.warn("异步缓存消息媒体失败:", error);
|
|
874
|
-
});
|
|
875
869
|
} catch (error) {
|
|
876
870
|
this.logger.warn("写入历史消息失败:", error);
|
|
877
871
|
}
|
|
872
|
+
void this.cacheMessageContacts(event).catch((error) => {
|
|
873
|
+
this.logger.warn("缓存消息联系人失败:", error);
|
|
874
|
+
});
|
|
875
|
+
void this.cacheMessageMedia(event).catch((error) => {
|
|
876
|
+
this.logger.warn("异步缓存消息媒体失败:", error);
|
|
877
|
+
});
|
|
878
878
|
}
|
|
879
879
|
async cacheMessageContacts(event) {
|
|
880
880
|
const platform = event.platform || "";
|
|
@@ -1622,7 +1622,8 @@ function registerBootstrap(ctx, config, database, logger) {
|
|
|
1622
1622
|
return {
|
|
1623
1623
|
endpoint: resolveEndpoint(ctx, config),
|
|
1624
1624
|
token: ctx.satori?.server?.config?.token ?? "",
|
|
1625
|
-
basePath: config.basePath
|
|
1625
|
+
basePath: config.basePath,
|
|
1626
|
+
blockedPlatforms: config.blockedPlatforms ?? []
|
|
1626
1627
|
};
|
|
1627
1628
|
}, { authority: 4 });
|
|
1628
1629
|
ctx.console.addListener("chat-patch/history", async (query) => {
|
|
@@ -1706,13 +1707,12 @@ function registerWeb(ctx, config, database, contactCache, logger) {
|
|
|
1706
1707
|
koa.status = 404;
|
|
1707
1708
|
koa.body = "";
|
|
1708
1709
|
}, "servePublicFile");
|
|
1709
|
-
const
|
|
1710
|
-
ctx.server.get(pattern, async (koa
|
|
1711
|
-
if (!getVite()) return next();
|
|
1710
|
+
const registerPublic = /* @__PURE__ */ __name((pattern, prefix) => {
|
|
1711
|
+
ctx.server.get(pattern, async (koa) => {
|
|
1712
1712
|
await servePublicFile(koa, prefix);
|
|
1713
1713
|
});
|
|
1714
|
-
}, "
|
|
1715
|
-
|
|
1714
|
+
}, "registerPublic");
|
|
1715
|
+
registerPublic("/img(.*)", "img");
|
|
1716
1716
|
const toExtension2 = /* @__PURE__ */ __name((value) => {
|
|
1717
1717
|
const ext = value.startsWith(".") ? value : `.${value}`;
|
|
1718
1718
|
return ext.toLowerCase();
|
|
@@ -2283,7 +2283,7 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
2283
2283
|
blockedPlatforms: import_koishi2.Schema.array(import_koishi2.Schema.object({
|
|
2284
2284
|
platformName: import_koishi2.Schema.string(),
|
|
2285
2285
|
exactMatch: import_koishi2.Schema.boolean().default(true)
|
|
2286
|
-
})).role("table").description("
|
|
2286
|
+
})).role("table").description("屏蔽消息接收的平台").default([
|
|
2287
2287
|
{ platformName: "qq", exactMatch: true },
|
|
2288
2288
|
{ platformName: "qqguild", exactMatch: true },
|
|
2289
2289
|
{ platformName: "sandbox", exactMatch: false }
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Awaitable } from 'koishi';
|
|
2
|
+
export interface SatoriBootstrap {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
token: string;
|
|
5
|
+
basePath: string;
|
|
6
|
+
blockedPlatforms: Array<{
|
|
7
|
+
platformName: string;
|
|
8
|
+
exactMatch: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export interface MessageRecord {
|
|
12
|
+
id?: string;
|
|
13
|
+
sequence?: number;
|
|
14
|
+
type: string;
|
|
15
|
+
platform: string;
|
|
16
|
+
selfId: string;
|
|
17
|
+
channelId?: string;
|
|
18
|
+
guildId?: string;
|
|
19
|
+
userId?: string;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
timestampMs?: number;
|
|
22
|
+
receivedAt?: number;
|
|
23
|
+
content?: string;
|
|
24
|
+
elements?: unknown[];
|
|
25
|
+
raw?: unknown;
|
|
26
|
+
}
|
|
27
|
+
export type SelfMessageChannelType = 'group' | 'user';
|
|
28
|
+
export type SelfMessageSource = 'webui' | 'bot' | 'plugin';
|
|
29
|
+
export interface SelfMessageRecord {
|
|
30
|
+
id: string;
|
|
31
|
+
platform: string;
|
|
32
|
+
selfId: string;
|
|
33
|
+
channelId: string;
|
|
34
|
+
guildId?: string;
|
|
35
|
+
channelType?: SelfMessageChannelType;
|
|
36
|
+
messageId?: string;
|
|
37
|
+
content?: string;
|
|
38
|
+
elements?: unknown[];
|
|
39
|
+
message?: unknown[];
|
|
40
|
+
forwardId?: string;
|
|
41
|
+
forwardContent?: unknown[];
|
|
42
|
+
sentAt: number;
|
|
43
|
+
sequence: number;
|
|
44
|
+
source: SelfMessageSource;
|
|
45
|
+
kind: string;
|
|
46
|
+
fingerprint?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface SelfMessagePayload {
|
|
49
|
+
id?: string;
|
|
50
|
+
platform: string;
|
|
51
|
+
selfId: string;
|
|
52
|
+
channelId: string;
|
|
53
|
+
guildId?: string;
|
|
54
|
+
channelType?: SelfMessageChannelType;
|
|
55
|
+
messageId?: string;
|
|
56
|
+
content?: string;
|
|
57
|
+
elements?: unknown[];
|
|
58
|
+
message?: unknown[];
|
|
59
|
+
forwardId?: string;
|
|
60
|
+
forwardContent?: unknown[];
|
|
61
|
+
sentAt?: number;
|
|
62
|
+
sequence?: number;
|
|
63
|
+
source?: SelfMessageSource;
|
|
64
|
+
kind?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface HistoryQuery {
|
|
67
|
+
platform: string;
|
|
68
|
+
selfId: string;
|
|
69
|
+
channelId: string;
|
|
70
|
+
limit?: number;
|
|
71
|
+
}
|
|
72
|
+
export interface HistoryResult {
|
|
73
|
+
messages: MessageRecord[];
|
|
74
|
+
}
|
|
75
|
+
export interface PinnedState {
|
|
76
|
+
bots: string[];
|
|
77
|
+
channels: string[];
|
|
78
|
+
}
|
|
79
|
+
export interface PluginConfigPayload {
|
|
80
|
+
basePath: string;
|
|
81
|
+
maxMessagesPerChannel: number;
|
|
82
|
+
historyPageSize: number;
|
|
83
|
+
maxMediaFiles: number;
|
|
84
|
+
blockedPlatforms: Array<{
|
|
85
|
+
platformName: string;
|
|
86
|
+
exactMatch: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
loggerinfo: boolean;
|
|
89
|
+
}
|
|
90
|
+
export interface ContactCacheItem {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
avatar?: string;
|
|
94
|
+
channelId?: string;
|
|
95
|
+
guildId?: string;
|
|
96
|
+
raw?: unknown;
|
|
97
|
+
}
|
|
98
|
+
export interface ContactCacheQuery {
|
|
99
|
+
platform: string;
|
|
100
|
+
selfId: string;
|
|
101
|
+
type: string;
|
|
102
|
+
contacts?: ContactCacheItem[];
|
|
103
|
+
append?: boolean;
|
|
104
|
+
}
|
|
105
|
+
export interface ContactCacheResult {
|
|
106
|
+
contacts?: ContactCacheItem[];
|
|
107
|
+
}
|
|
108
|
+
declare module '@koishijs/console' {
|
|
109
|
+
interface Events {
|
|
110
|
+
'chat-patch/bootstrap'(): SatoriBootstrap;
|
|
111
|
+
'chat-patch/history'(query: HistoryQuery): Awaitable<HistoryResult>;
|
|
112
|
+
'chat-patch/config'(): PluginConfigPayload;
|
|
113
|
+
'chat-patch/contact-cache'(query: ContactCacheQuery): Awaitable<ContactCacheResult>;
|
|
114
|
+
}
|
|
115
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-chat-patch",
|
|
3
3
|
"description": "[<ruby>chat-patch<rp>(</rp><rt>点我预览效果</rt><rp>)</rp></ruby>](https://i0.hdslb.com/bfs/openplatform/71074dfc9e5256fc3333d8bd8478bec1af874046.png) 视奸小插件((bushi( (低性能警告)。手机端适配。灵感来自 chat 插件。",
|
|
4
|
-
"version": "5.1
|
|
4
|
+
"version": "5.3.1",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build:web": "npm --prefix client/web run build",
|
|
7
7
|
"prepack": "npm run build:web",
|
package/src/bootstrap.ts
CHANGED
package/src/config.ts
CHANGED
|
@@ -25,7 +25,7 @@ export const Config: Schema<Config> = Schema.intersect([
|
|
|
25
25
|
blockedPlatforms: Schema.array(Schema.object({
|
|
26
26
|
platformName: Schema.string(),
|
|
27
27
|
exactMatch: Schema.boolean().default(true),
|
|
28
|
-
})).role('table').description('
|
|
28
|
+
})).role('table').description('屏蔽消息接收的平台').default([
|
|
29
29
|
{ platformName: 'qq', exactMatch: true },
|
|
30
30
|
{ platformName: 'qqguild', exactMatch: true },
|
|
31
31
|
{ platformName: 'sandbox', exactMatch: false },
|
package/src/recorder.ts
CHANGED
|
@@ -41,8 +41,8 @@ export class Recorder {
|
|
|
41
41
|
|
|
42
42
|
private async handleSession(session: Session) {
|
|
43
43
|
const platform = session.platform || 'unknown'
|
|
44
|
-
if (this.isBlocked(platform)) return
|
|
45
44
|
if (!MESSAGE_TYPES.has(session.type)) return
|
|
45
|
+
if (this.isBlocked(platform)) return
|
|
46
46
|
|
|
47
47
|
const event = session.toJSON()
|
|
48
48
|
const message = event.message
|
|
@@ -65,15 +65,15 @@ export class Recorder {
|
|
|
65
65
|
|
|
66
66
|
try {
|
|
67
67
|
await this.database.appendMessage(record)
|
|
68
|
-
void this.cacheMessageContacts(event).catch((error) => {
|
|
69
|
-
this.logger.warn('缓存消息联系人失败:', error)
|
|
70
|
-
})
|
|
71
|
-
void this.cacheMessageMedia(event).catch((error) => {
|
|
72
|
-
this.logger.warn('异步缓存消息媒体失败:', error)
|
|
73
|
-
})
|
|
74
68
|
} catch (error) {
|
|
75
69
|
this.logger.warn('写入历史消息失败:', error)
|
|
76
70
|
}
|
|
71
|
+
void this.cacheMessageContacts(event).catch((error) => {
|
|
72
|
+
this.logger.warn('缓存消息联系人失败:', error)
|
|
73
|
+
})
|
|
74
|
+
void this.cacheMessageMedia(event).catch((error) => {
|
|
75
|
+
this.logger.warn('异步缓存消息媒体失败:', error)
|
|
76
|
+
})
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
private async cacheMessageContacts(event: ReturnType<Session['toJSON']>) {
|
package/src/types.ts
CHANGED
package/src/web.ts
CHANGED
|
@@ -82,15 +82,14 @@ export function registerWeb(
|
|
|
82
82
|
koa.body = ''
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// web 应用里仍有 /img
|
|
86
|
-
const
|
|
87
|
-
ctx.server.get(pattern, async (koa: WebContext
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
registerDevPublic('/img(.*)', 'img')
|
|
85
|
+
// web 应用里仍有 /img 这类运行时绝对路径,生产/开发模式都要由 Koishi 服务托管
|
|
86
|
+
const registerPublic = (pattern: string, prefix: string) => {
|
|
87
|
+
ctx.server.get(pattern, async (koa: WebContext) => {
|
|
88
|
+
await servePublicFile(koa, prefix)
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
registerPublic('/img(.*)', 'img')
|
|
94
93
|
|
|
95
94
|
const toExtension = (value: string): string => {
|
|
96
95
|
const ext = value.startsWith('.') ? value : `.${value}`
|