koishi-plugin-chat-patch 3.0.2 → 5.0.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.
Files changed (194) hide show
  1. package/client/vue/index.vue +60 -634
  2. package/client/web/env.d.ts +56 -0
  3. package/client/web/index.html +21 -0
  4. package/client/web/package-lock.json +3419 -0
  5. package/client/web/package.json +62 -0
  6. package/client/web/public/bcui/css/color-dark.css +35 -0
  7. package/client/web/public/bcui/css/color-light.css +35 -0
  8. package/client/web/public/bcui/css/style.css +468 -0
  9. package/client/web/public/bcui/js/main.js +193 -0
  10. package/client/web/public/css/append-dark.css +13 -0
  11. package/client/web/public/css/append-light.css +13 -0
  12. package/client/web/public/css/append-napcat-dark.css +14 -0
  13. package/client/web/public/css/append-napcat-light.css +14 -0
  14. package/client/web/public/favicon.ico +0 -0
  15. package/client/web/public/img/icons/icon-for-fuck-apple.png +0 -0
  16. package/client/web/public/img/icons/icon-maskable.png +0 -0
  17. package/client/web/public/img/icons/icon.png +0 -0
  18. package/client/web/public/img/icons/icon.svg +10 -0
  19. package/client/web/public/robots.txt +2 -0
  20. package/client/web/public/sw.js +58 -0
  21. package/client/web/scripts/copy-bcui.mjs +17 -0
  22. package/client/web/src/App.vue +1127 -0
  23. package/client/web/src/assets/css/append/append_darwin.css +68 -0
  24. package/client/web/src/assets/css/append/append_full_vibrancy.css +290 -0
  25. package/client/web/src/assets/css/append/append_linux.css +125 -0
  26. package/client/web/src/assets/css/append/append_linux_vibrancy.css +22 -0
  27. package/client/web/src/assets/css/append/append_napcat.css +35 -0
  28. package/client/web/src/assets/css/append/append_new.css +843 -0
  29. package/client/web/src/assets/css/append/append_vibrancy.css +113 -0
  30. package/client/web/src/assets/css/append/append_win32.css +109 -0
  31. package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +349 -0
  32. package/client/web/src/assets/css/append/mobile/append_mobile_vertical.css +96 -0
  33. package/client/web/src/assets/css/chat.css +2104 -0
  34. package/client/web/src/assets/css/msg.css +941 -0
  35. package/client/web/src/assets/css/options.css +811 -0
  36. package/client/web/src/assets/css/sys_notice.css +62 -0
  37. package/client/web/src/assets/css/view.css +2105 -0
  38. package/client/web/src/assets/font//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223.ttf +0 -0
  39. package/client/web/src/assets/img/Vue.png +0 -0
  40. package/client/web/src/assets/img/cakes.svg +189 -0
  41. package/client/web/src/assets/img/icons/AppIcon.png +0 -0
  42. package/client/web/src/assets/img/icons/AppIconDark.png +0 -0
  43. package/client/web/src/assets/img/icons/CapacitorAppIcon.png +0 -0
  44. package/client/web/src/assets/img/icons/CapacitorAppIconDark.png +0 -0
  45. package/client/web/src/assets/img/icons/NapcatAppIcon.png +0 -0
  46. package/client/web/src/assets/img/icons/NapcatAppIconDark.png +0 -0
  47. package/client/web/src/assets/img/icons/exit.png +0 -0
  48. package/client/web/src/assets/img/icons/pen.png +0 -0
  49. package/client/web/src/assets/img/stars.svg +89 -0
  50. package/client/web/src/assets/img//346/234/237/345/276/205.png +0 -0
  51. package/client/web/src/assets/l10n/_About I10n.md +35 -0
  52. package/client/web/src/assets/l10n/_l10nconfig.json +7 -0
  53. package/client/web/src/assets/l10n/zh-CN.po +1941 -0
  54. package/client/web/src/assets/logo.png +0 -0
  55. package/client/web/src/assets/pathMap/LLOneBot.yaml +2 -0
  56. package/client/web/src/assets/pathMap/Lagrange.OneBot.yaml +180 -0
  57. package/client/web/src/assets/pathMap/NapCat.Onebot.yaml +224 -0
  58. package/client/web/src/assets/pathMap/SnowLuma.yaml +80 -0
  59. package/client/web/src/assets/qed.txt +1 -0
  60. package/client/web/src/components/AboutPan.vue +197 -0
  61. package/client/web/src/components/BulletinBody.vue +129 -0
  62. package/client/web/src/components/DepPan.vue +310 -0
  63. package/client/web/src/components/EmojiFace.vue +32 -0
  64. package/client/web/src/components/FacePan.vue +461 -0
  65. package/client/web/src/components/FileBody.vue +129 -0
  66. package/client/web/src/components/FileManager.vue +532 -0
  67. package/client/web/src/components/FriendBody.vue +54 -0
  68. package/client/web/src/components/GlobalSessionSearchBar.vue +301 -0
  69. package/client/web/src/components/History.vue +49 -0
  70. package/client/web/src/components/LazyLottie.vue +82 -0
  71. package/client/web/src/components/MergePan.vue +127 -0
  72. package/client/web/src/components/MsgBody.vue +1478 -0
  73. package/client/web/src/components/MusicPlayer.vue +549 -0
  74. package/client/web/src/components/NoticeBody.vue +168 -0
  75. package/client/web/src/components/QzonePermissionPan.vue +150 -0
  76. package/client/web/src/components/RawMsgRenderPreviewPan.vue +190 -0
  77. package/client/web/src/components/ThemeColorPickerPan.vue +420 -0
  78. package/client/web/src/components/TinySessionBody.vue +51 -0
  79. package/client/web/src/components/UmamiInfoPan.vue +1549 -0
  80. package/client/web/src/components/UpdatePan.vue +263 -0
  81. package/client/web/src/components/ViewerCom.vue +1360 -0
  82. package/client/web/src/components/VoiceMsg.vue +626 -0
  83. package/client/web/src/components/WelPan.vue +894 -0
  84. package/client/web/src/components/msg-body/.gitkeep +0 -0
  85. package/client/web/src/components/msg-component/JsonSegComp.vue +138 -0
  86. package/client/web/src/components/msg-component/XmlSegComp.vue +132 -0
  87. package/client/web/src/components/msg-component/jsonComp/AutoReply.vue +97 -0
  88. package/client/web/src/components/msg-component/jsonComp/Contact.lua.vue +129 -0
  89. package/client/web/src/components/msg-component/jsonComp/Feed.lua.vue +94 -0
  90. package/client/web/src/components/msg-component/jsonComp/Forum.vue +84 -0
  91. package/client/web/src/components/msg-component/jsonComp/Mannounce.vue +111 -0
  92. package/client/web/src/components/msg-component/jsonComp/Map.vue +52 -0
  93. package/client/web/src/components/msg-component/jsonComp/Miniapp.lua.vue +53 -0
  94. package/client/web/src/components/msg-component/jsonComp/Miniapp.vue +69 -0
  95. package/client/web/src/components/msg-component/jsonComp/Music.lua.vue +135 -0
  96. package/client/web/src/components/msg-component/jsonComp/Tuwen.lua.vue +56 -0
  97. package/client/web/src/components/notice-component/.gitkeep +0 -0
  98. package/client/web/src/components/notice-component/MealHungryPan.vue +119 -0
  99. package/client/web/src/components/tooltip/CustomFaceTooltip.vue +22 -0
  100. package/client/web/src/components/tooltip/Tooltip.vue +50 -0
  101. package/client/web/src/components/tooltip/Tooltips.vue +14 -0
  102. package/client/web/src/components/tooltip/UserInfoTooltip.vue +69 -0
  103. package/client/web/src/function/base.ts +238 -0
  104. package/client/web/src/function/connect.ts +2042 -0
  105. package/client/web/src/function/debug.ts +10 -0
  106. package/client/web/src/function/elements/information.ts +141 -0
  107. package/client/web/src/function/elements/system.ts +101 -0
  108. package/client/web/src/function/elements/vueComp.ts +62 -0
  109. package/client/web/src/function/favicon.ts +76 -0
  110. package/client/web/src/function/input.ts +69 -0
  111. package/client/web/src/function/model/emoji.ts +127 -0
  112. package/client/web/src/function/model/img.ts +150 -0
  113. package/client/web/src/function/model/msg-body.ts +51 -0
  114. package/client/web/src/function/msg.ts +2674 -0
  115. package/client/web/src/function/notify.ts +225 -0
  116. package/client/web/src/function/option.ts +749 -0
  117. package/client/web/src/function/satori-model.ts +818 -0
  118. package/client/web/src/function/satori.ts +325 -0
  119. package/client/web/src/function/sender.ts +178 -0
  120. package/client/web/src/function/tooltip.ts +49 -0
  121. package/client/web/src/function/utils/appUtil.ts +2288 -0
  122. package/client/web/src/function/utils/avatarUtil.ts +31 -0
  123. package/client/web/src/function/utils/backgroundUtil.ts +110 -0
  124. package/client/web/src/function/utils/linkViewUtil.ts +101 -0
  125. package/client/web/src/function/utils/localHistoryUtil.ts +517 -0
  126. package/client/web/src/function/utils/msgUtil.ts +1242 -0
  127. package/client/web/src/function/utils/pinyin.ts +141 -0
  128. package/client/web/src/function/utils/recordUtil.ts +187 -0
  129. package/client/web/src/function/utils/sessionUtil.ts +114 -0
  130. package/client/web/src/function/utils/systemUtil.ts +664 -0
  131. package/client/web/src/main.ts +91 -0
  132. package/client/web/src/pages/Chat.vue +3453 -0
  133. package/client/web/src/pages/Friends.vue +636 -0
  134. package/client/web/src/pages/Info.vue +717 -0
  135. package/client/web/src/pages/Messages.vue +875 -0
  136. package/client/web/src/pages/Options.vue +82 -0
  137. package/client/web/src/pages/Qzone.vue +1178 -0
  138. package/client/web/src/pages/chat-view/ChatDanmaku.vue +759 -0
  139. package/client/web/src/pages/chat-view/ChatGlagame.vue +642 -0
  140. package/client/web/src/pages/chat-view/ChatTerminal.vue +1044 -0
  141. package/client/web/src/pages/chat-view/SystemNotice.vue +171 -0
  142. package/client/web/src/pages/options/OptAccount.vue +107 -0
  143. package/client/web/src/pages/options/OptAddon.vue +185 -0
  144. package/client/web/src/pages/options/OptDev.vue +704 -0
  145. package/client/web/src/pages/options/OptFunction.vue +403 -0
  146. package/client/web/src/pages/options/OptInfo.vue +165 -0
  147. package/client/web/src/pages/options/OptView.vue +846 -0
  148. package/client/web/src/runtime/backend.ts +310 -0
  149. package/client/web/src/state/auth.ts +14 -0
  150. package/client/web/src/state/chat.ts +36 -0
  151. package/client/web/src/state/connection.ts +20 -0
  152. package/client/web/src/state/contact.ts +37 -0
  153. package/client/web/src/state/qzone.ts +18 -0
  154. package/client/web/src/state/sessionHistory.ts +25 -0
  155. package/client/web/src/state/settings.ts +18 -0
  156. package/client/web/src/state/sticker.ts +10 -0
  157. package/client/web/src/state/ui.ts +56 -0
  158. package/client/web/tsconfig.json +27 -0
  159. package/client/web/tsconfig.tsbuildinfo +1 -0
  160. package/client/web/vite.config.ts +33 -0
  161. package/dist/index.js +1 -12
  162. package/dist/style.css +1 -1
  163. package/lib/index.js +2070 -2077
  164. package/package.json +15 -2
  165. package/readme.md +0 -22
  166. package/src/bootstrap.ts +71 -0
  167. package/src/cache.ts +319 -0
  168. package/src/config.ts +23 -35
  169. package/src/database.ts +650 -0
  170. package/src/index.ts +27 -59
  171. package/src/media.ts +302 -0
  172. package/src/recorder.ts +175 -0
  173. package/src/self-message.ts +456 -0
  174. package/src/server.d.ts +26 -0
  175. package/src/types.ts +108 -48
  176. package/src/web.ts +712 -0
  177. package/client/vue/chat-logic.ts +0 -683
  178. package/client/vue/composables/useChatActions.ts +0 -61
  179. package/client/vue/composables/useChatData.ts +0 -185
  180. package/client/vue/composables/useImageCache.ts +0 -281
  181. package/client/vue/composables/useVideoCache.ts +0 -125
  182. package/client/vue/types.ts +0 -72
  183. package/lib/api-handlers.d.ts +0 -25
  184. package/lib/config.d.ts +0 -14
  185. package/lib/file-manager.d.ts +0 -124
  186. package/lib/index.d.ts +0 -17
  187. package/lib/logger.d.ts +0 -9
  188. package/lib/message-handler.d.ts +0 -35
  189. package/lib/types.d.ts +0 -57
  190. package/lib/utils.d.ts +0 -18
  191. package/src/api-handlers.ts +0 -646
  192. package/src/file-manager.ts +0 -1436
  193. package/src/message-handler.ts +0 -507
  194. package/src/utils.ts +0 -189
@@ -0,0 +1,31 @@
1
+ const QQ_GROUP_AVATAR_PLATFORMS = new Set([
2
+ 'onebot',
3
+ 'red',
4
+ 'napcat',
5
+ 'milky',
6
+ 'llonebot',
7
+ 'llob',
8
+ ])
9
+
10
+ // 仅用于白名单平台的 QQ 群头像,不能用于用户头像
11
+ export function buildQqGroupAvatar(
12
+ platform: string,
13
+ groupId: string | number,
14
+ size: number = 0,
15
+ ): string {
16
+ const platformName = String(platform).toLowerCase().trim()
17
+ if (!QQ_GROUP_AVATAR_PLATFORMS.has(platformName)) return ''
18
+ const rawId = String(groupId)
19
+ .replace(/^(?:group|room|chat|channel|guild):/i, '')
20
+ .replace(/^\[_?([\s\S]+?)_?\]$/, '$1')
21
+ .trim()
22
+ if (!/^\d+$/.test(rawId)) return ''
23
+ const safeSize = size === 100 || size === 640 ? size : 0
24
+ return `https://p.qlogo.cn/gh/${rawId}/${rawId}/${safeSize}`
25
+ }
26
+
27
+ export function avatarError(event: Event) {
28
+ const img = event.target as HTMLImageElement
29
+ const fallback = new URL('/img/icons/icon.svg', location.origin).href
30
+ if (img.src !== fallback) img.src = fallback
31
+ }
@@ -0,0 +1,110 @@
1
+ import { backend } from '../../runtime/backend'
2
+ import { ref } from 'vue'
3
+
4
+ const objectUrls = new Map<string, string>()
5
+ const backgroundUrlVersion = ref(0)
6
+ const dbName = 'ssqq-local-assets'
7
+ const dbVersion = 1
8
+ const imageStoreName = 'images'
9
+ const chatBackgroundKey = 'chat_background'
10
+ const chatBackgroundUrl = `ssqq-background://${chatBackgroundKey}`
11
+
12
+ export interface LocalImageInfo {
13
+ path: string
14
+ url?: string
15
+ }
16
+
17
+ export function getBackgroundImageUrl(
18
+ value: string | null | undefined,
19
+ _version = backgroundUrlVersion.value,
20
+ ) {
21
+ if (!value) return ''
22
+ if (value.startsWith('ssqq-background://')) {
23
+ return objectUrls.get(value) ?? ''
24
+ }
25
+ if (value.startsWith('data:') || value.startsWith('blob:') || value.startsWith('file:')) {
26
+ return value
27
+ }
28
+ if (backend.type === 'tauri') {
29
+ return objectUrls.get(value) ?? value
30
+ }
31
+ return value
32
+ }
33
+
34
+ export function toBackgroundImageStyle(value: string | null | undefined) {
35
+ const url = getBackgroundImageUrl(value)
36
+ return url ? `url("${url.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}")` : ''
37
+ }
38
+
39
+ export async function resolveLocalImageUrl(image: LocalImageInfo) {
40
+ if (backend.type === 'tauri') {
41
+ const { convertFileSrc } = await import('@tauri-apps/api/core')
42
+ const url = convertFileSrc(image.path)
43
+ objectUrls.set(image.path, url)
44
+ return url
45
+ }
46
+ return image.url ?? image.path
47
+ }
48
+
49
+ export function rememberLocalImageUrl(path: string, url: string) {
50
+ objectUrls.set(path, url)
51
+ backgroundUrlVersion.value += 1
52
+ }
53
+
54
+ export async function saveBrowserBackgroundImage(file: Blob) {
55
+ const db = await openAssetDb()
56
+ await putImageBlob(db, chatBackgroundKey, file)
57
+ return chatBackgroundUrl
58
+ }
59
+
60
+ export async function migrateInlineBackgroundImage(value: string | null | undefined) {
61
+ if (!value?.startsWith('data:image')) return null
62
+ const response = await fetch(value)
63
+ const blob = await response.blob()
64
+ const backgroundUrl = await saveBrowserBackgroundImage(blob)
65
+ rememberLocalImageUrl(backgroundUrl, URL.createObjectURL(blob))
66
+ return backgroundUrl
67
+ }
68
+
69
+ export async function hydrateBackgroundImage(value: string | null | undefined) {
70
+ if (!value?.startsWith('ssqq-background://') || objectUrls.has(value)) {
71
+ return
72
+ }
73
+ const db = await openAssetDb()
74
+ const blob = await getImageBlob(db, chatBackgroundKey)
75
+ if (!blob) return
76
+ const url = URL.createObjectURL(blob)
77
+ rememberLocalImageUrl(value, url)
78
+ }
79
+
80
+ function openAssetDb() {
81
+ return new Promise<IDBDatabase>((resolve, reject) => {
82
+ const request = indexedDB.open(dbName, dbVersion)
83
+ request.onupgradeneeded = () => {
84
+ const db = request.result
85
+ if (!db.objectStoreNames.contains(imageStoreName)) {
86
+ db.createObjectStore(imageStoreName)
87
+ }
88
+ }
89
+ request.onsuccess = () => resolve(request.result)
90
+ request.onerror = () => reject(request.error)
91
+ })
92
+ }
93
+
94
+ function putImageBlob(db: IDBDatabase, key: string, file: Blob) {
95
+ return new Promise<void>((resolve, reject) => {
96
+ const transaction = db.transaction(imageStoreName, 'readwrite')
97
+ transaction.objectStore(imageStoreName).put(file, key)
98
+ transaction.oncomplete = () => resolve()
99
+ transaction.onerror = () => reject(transaction.error)
100
+ })
101
+ }
102
+
103
+ function getImageBlob(db: IDBDatabase, key: string) {
104
+ return new Promise<Blob | undefined>((resolve, reject) => {
105
+ const transaction = db.transaction(imageStoreName, 'readonly')
106
+ const request = transaction.objectStore(imageStoreName).get(key)
107
+ request.onsuccess = () => resolve(request.result)
108
+ request.onerror = () => reject(request.error)
109
+ })
110
+ }
@@ -0,0 +1,101 @@
1
+ import { backend } from '../../runtime/backend'
2
+ import { Logger } from '../base'
3
+ import { getApi, getForegroundToneGridFromImageUrl } from './systemUtil'
4
+ import jp from 'jsonpath'
5
+
6
+ export const linkView = {
7
+ async bilibili(url: string) {
8
+ const logger = new Logger()
9
+
10
+ const combinedQuantity = (numObj: any) => {
11
+ try {
12
+ const num = Number(numObj)
13
+ // 如果数量大于一万,返回为 xx 万
14
+ if(num / 10000 >= 1) {
15
+ return (num / 10000).toFixed(1) + ' w'
16
+ } else if(num / 1000 >= 1) {
17
+ return (num / 1000).toFixed(1) + ' k'
18
+ } else {
19
+ return num.toString()
20
+ }
21
+ } catch (_) {
22
+ return numObj
23
+ }
24
+ }
25
+
26
+ const previewAPI = 'https://api.bilibili.com/x/web-interface/wbi/view?bvid='
27
+ const match = url.match(/bilibili.com\/video\/(BV[0-9a-zA-Z]+)/)
28
+ if (match) {
29
+ const bvid = match[1]
30
+ logger.info(`[linkView] 获取到 bilibili 链接:${bvid}`)
31
+ const data = await getApi(previewAPI + bvid)
32
+ if (data && data.code === 0) {
33
+ logger.info(`[linkView] 预览 bilibili 链接成功:${data.data.title}`)
34
+ const stat = data.data.stat
35
+ Object.keys(stat).forEach((key) => {
36
+ stat[key] = combinedQuantity(stat[key])
37
+ })
38
+ return {
39
+ type: 'bilibili',
40
+ sub_type: 'video',
41
+ url: url,
42
+ data: {
43
+ title: data.data.title,
44
+ desc: data.data.desc,
45
+ pic: data.data.pic,
46
+ public: data.data.pubdate,
47
+ owner: data.data.owner,
48
+ stat: stat
49
+ }
50
+ }
51
+ }
52
+ }
53
+ return null
54
+ },
55
+
56
+ async music163(url: string) {
57
+ const logger = new Logger()
58
+
59
+ const urlObj = new URL(url)
60
+ const params = new URLSearchParams(urlObj.search)
61
+ const id = params.get('id')
62
+ if(id != null) {
63
+ logger.info(`[linkView] 获取获取网易云音乐歌曲 ID:${id}`)
64
+ const baseUrl = import.meta.env.VITE_APP_163_MUSIC_API
65
+ try {
66
+ const responseDetail = await getApi(baseUrl + '/song/detail?ids=' + id)
67
+ const responseUrl = await getApi(baseUrl + '/song/url?id=' + id)
68
+
69
+ const getData = {
70
+ detail: responseDetail,
71
+ url: responseUrl,
72
+ }
73
+ const colorInfo = await getForegroundToneGridFromImageUrl(backend.proxyUrl(jp.query(getData['detail'], '$..al.picUrl')[0]), 0.4)
74
+ const finalData = {
75
+ type: 'music163',
76
+ sub_type: 'song',
77
+ data: {
78
+ id: id,
79
+ play_link: jp.query(getData['url'], '$..url')[0],
80
+ cover: jp.query(getData['detail'], '$..al.picUrl')[0],
81
+ cover_light: colorInfo[1][1] == 'light',
82
+ info: {
83
+ name: jp.query(getData['detail'], '$..name')[0],
84
+ author: jp.query(getData['detail'], '$..ar[*].name'),
85
+ time: jp.query(getData['detail'], '$..dt')[0] / 1000,
86
+ free: jp.query(getData['url'], '$..freeTrialInfo')[0] != null ? {
87
+ start: jp.query(getData['url'], '$..freeTrialInfo')[0].start,
88
+ end: jp.query(getData['url'], '$..freeTrialInfo')[0].end,
89
+ } : null
90
+ }
91
+ }
92
+ }
93
+ logger.info('[linkView] 预览网易云音乐成功')
94
+ return finalData
95
+ } catch (error) {
96
+ logger.error(error as Error, '[linkView] 预览网易云音乐失败')
97
+ }
98
+ }
99
+ return null
100
+ }
101
+ }