mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-13 00:10:27 +00:00
Compare commits
8 Commits
copilot/ad
...
v4.8.121
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbacc89907 | ||
|
|
8e6da5e2d0 | ||
|
|
02980c4d1a | ||
|
|
0129188739 | ||
|
|
98ef642cd1 | ||
|
|
32e886e53b | ||
|
|
315d847f06 | ||
|
|
381d320967 |
BIN
external/LiteLoaderWrapper.zip
vendored
BIN
external/LiteLoaderWrapper.zip
vendored
Binary file not shown.
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "qq-chat",
|
"name": "qq-chat",
|
||||||
"verHash": "cc326038",
|
"verHash": "c50d6326",
|
||||||
"version": "9.9.21-39038",
|
"version": "9.9.22-40768",
|
||||||
"linuxVersion": "3.2.19-39038",
|
"linuxVersion": "3.2.20-40768",
|
||||||
"linuxVerHash": "c773cdf7",
|
"linuxVerHash": "ab90fdfa",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "QQ",
|
"description": "QQ",
|
||||||
"productName": "QQ",
|
"productName": "QQ",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"qd": "externals/devtools/cli/index.js"
|
"qd": "externals/devtools/cli/index.js"
|
||||||
},
|
},
|
||||||
"main": "./loadNapCat.js",
|
"main": "./loadNapCat.js",
|
||||||
"buildVersion": "39038",
|
"buildVersion": "40768",
|
||||||
"isPureShell": true,
|
"isPureShell": true,
|
||||||
"isByteCodeShell": true,
|
"isByteCodeShell": true,
|
||||||
"platform": "win32",
|
"platform": "win32",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "4.8.119",
|
"version": "4.8.120",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|||||||
24
napcat.webui/package-lock.json
generated
24
napcat.webui/package-lock.json
generated
@@ -93,7 +93,6 @@
|
|||||||
"@types/node": "^22.12.0",
|
"@types/node": "^22.12.0",
|
||||||
"@types/path-browserify": "^1.0.3",
|
"@types/path-browserify": "^1.0.3",
|
||||||
"@types/react": "^19.0.8",
|
"@types/react": "^19.0.8",
|
||||||
"@types/react-color": "^3.0.13",
|
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react-dom": "^19.0.3",
|
||||||
"@types/react-window": "^1.8.8",
|
"@types/react-window": "^1.8.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
||||||
@@ -8153,19 +8152,6 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-color": {
|
|
||||||
"version": "3.0.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.13.tgz",
|
|
||||||
"integrity": "sha512-2c/9FZ4ixC5T3JzN0LP5Cke2Mf0MKOP2Eh0NPDPWmuVH3NjPyhEjqNMQpN1Phr5m74egAy+p2lYNAFrX1z9Yrg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/reactcss": "*"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@types/react": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "19.1.6",
|
"version": "19.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz",
|
||||||
@@ -8186,16 +8172,6 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/reactcss": {
|
|
||||||
"version": "1.2.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.13.tgz",
|
|
||||||
"integrity": "sha512-gi3S+aUi6kpkF5vdhUsnkwbiSEIU/BEJyD7kBy2SudWBUuKmJk8AQKE0OVcQQeEy40Azh0lV6uynxlikYIJuwg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"@types/react": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/unist": {
|
"node_modules/@types/unist": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
|
||||||
|
|||||||
@@ -95,7 +95,6 @@
|
|||||||
"@types/node": "^22.12.0",
|
"@types/node": "^22.12.0",
|
||||||
"@types/path-browserify": "^1.0.3",
|
"@types/path-browserify": "^1.0.3",
|
||||||
"@types/react": "^19.0.8",
|
"@types/react": "^19.0.8",
|
||||||
"@types/react-color": "^3.0.13",
|
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react-dom": "^19.0.3",
|
||||||
"@types/react-window": "^1.8.8",
|
"@types/react-window": "^1.8.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
"@typescript-eslint/eslint-plugin": "^8.22.0",
|
||||||
|
|||||||
@@ -197,13 +197,4 @@ export default class WebUIManager {
|
|||||||
)
|
)
|
||||||
return data.data
|
return data.data
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理缓存
|
|
||||||
public static async cleanCache() {
|
|
||||||
const { data } =
|
|
||||||
await serverRequest.post<
|
|
||||||
ServerResponse<{ result: boolean; message: string }>
|
|
||||||
>('/base/CleanCache')
|
|
||||||
return data.data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
import { Button } from '@heroui/button'
|
|
||||||
import { Input } from '@heroui/input'
|
import { Input } from '@heroui/input'
|
||||||
import { Switch } from '@heroui/switch'
|
import { Switch } from '@heroui/switch'
|
||||||
import { useRequest } from 'ahooks'
|
import { useRequest } from 'ahooks'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { Controller, useForm } from 'react-hook-form'
|
import { Controller, useForm } from 'react-hook-form'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { MdDeleteSweep } from 'react-icons/md'
|
|
||||||
|
|
||||||
import SaveButtons from '@/components/button/save_buttons'
|
import SaveButtons from '@/components/button/save_buttons'
|
||||||
import PageLoading from '@/components/page_loading'
|
import PageLoading from '@/components/page_loading'
|
||||||
|
|
||||||
import useDialog from '@/hooks/use-dialog'
|
|
||||||
|
|
||||||
import WebUIManager from '@/controllers/webui_manager'
|
import WebUIManager from '@/controllers/webui_manager'
|
||||||
|
|
||||||
const ServerConfigCard = () => {
|
const ServerConfigCard = () => {
|
||||||
const dialog = useDialog()
|
|
||||||
const [isCleaningCache, setIsCleaningCache] = useState(false)
|
|
||||||
const {
|
const {
|
||||||
data: configData,
|
data: configData,
|
||||||
loading: configLoading,
|
loading: configLoading,
|
||||||
@@ -75,42 +69,6 @@ const ServerConfigCard = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCleanCache = () => {
|
|
||||||
dialog.confirm({
|
|
||||||
title: '清理缓存',
|
|
||||||
content: (
|
|
||||||
<div className="space-y-2">
|
|
||||||
<p>确定要清理缓存吗?此操作将清理以下内容:</p>
|
|
||||||
<ul className="list-disc list-inside text-sm text-default-600">
|
|
||||||
<li>临时文件夹中的所有文件</li>
|
|
||||||
<li>图片缓存 (Pic)</li>
|
|
||||||
<li>语音缓存 (Ptt)</li>
|
|
||||||
<li>视频缓存 (Video)</li>
|
|
||||||
<li>文件缓存 (File)</li>
|
|
||||||
<li>日志文件 (log)</li>
|
|
||||||
</ul>
|
|
||||||
<p className="text-warning text-sm">此操作不可撤销,请谨慎操作。</p>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
onConfirm: async () => {
|
|
||||||
setIsCleaningCache(true)
|
|
||||||
try {
|
|
||||||
const result = await WebUIManager.cleanCache()
|
|
||||||
if (result.result) {
|
|
||||||
toast.success(result.message || '缓存清理成功')
|
|
||||||
} else {
|
|
||||||
toast.error(result.message || '缓存清理失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const msg = (error as Error).message
|
|
||||||
toast.error(`清理缓存失败: ${msg}`)
|
|
||||||
} finally {
|
|
||||||
setIsCleaningCache(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset()
|
reset()
|
||||||
}, [configData])
|
}, [configData])
|
||||||
@@ -173,30 +131,6 @@ const ServerConfigCard = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<div className="flex-shrink-0 w-full">维护操作</div>
|
|
||||||
<div className="flex flex-col gap-2 p-4 rounded-lg bg-default-50">
|
|
||||||
<div className="flex items-start justify-between gap-2">
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium">清理缓存</div>
|
|
||||||
<div className="text-sm text-default-500">
|
|
||||||
清理临时文件、图片、语音、视频、文件缓存和日志文件
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
color="danger"
|
|
||||||
variant="flat"
|
|
||||||
startContent={<MdDeleteSweep size={20} />}
|
|
||||||
onPress={handleCleanCache}
|
|
||||||
isLoading={isCleaningCache}
|
|
||||||
isDisabled={!!configError}
|
|
||||||
>
|
|
||||||
清理缓存
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex-shrink-0 w-full">安全配置</div>
|
<div className="flex-shrink-0 w-full">安全配置</div>
|
||||||
<Controller
|
<Controller
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"version": "4.8.119",
|
"version": "4.8.98",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"version": "4.8.119",
|
"version": "4.8.98",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^5.0.0",
|
"express": "^5.0.0",
|
||||||
"silk-wasm": "^3.6.1",
|
"silk-wasm": "^3.6.1",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "4.8.119",
|
"version": "4.8.120",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||||
|
|||||||
@@ -163,8 +163,10 @@ export function getQQVersionConfigPath(exePath: string = ''): string | undefined
|
|||||||
|
|
||||||
export function calcQQLevel(level?: QQLevel) {
|
export function calcQQLevel(level?: QQLevel) {
|
||||||
if (!level) return 0;
|
if (!level) return 0;
|
||||||
const { crownNum, sunNum, moonNum, starNum } = level;
|
//const { penguinNum, crownNum, sunNum, moonNum, starNum } = level;
|
||||||
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
const { crownNum, sunNum, moonNum, starNum } = level
|
||||||
|
//没补类型
|
||||||
|
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stringifyWithBigInt(obj: any) {
|
export function stringifyWithBigInt(obj: any) {
|
||||||
@@ -204,4 +206,4 @@ export function parseAppidFromMajor(nodeMajor: string): string | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '4.8.119';
|
export const napCatVersion = '4.8.120';
|
||||||
|
|||||||
24
src/core/external/appid.json
vendored
24
src/core/external/appid.json
vendored
@@ -390,5 +390,29 @@
|
|||||||
"9.9.22-40362": {
|
"9.9.22-40362": {
|
||||||
"appid": 537314212,
|
"appid": 537314212,
|
||||||
"qua": "V1_WIN_NQ_9.9.22_40362_GW_B"
|
"qua": "V1_WIN_NQ_9.9.22_40362_GW_B"
|
||||||
|
},
|
||||||
|
"3.2.20-40768": {
|
||||||
|
"appid": 537319840,
|
||||||
|
"qua": "V1_LNX_NQ_3.2.20_40768_GW_B"
|
||||||
|
},
|
||||||
|
"9.9.22-40768": {
|
||||||
|
"appid": 537319804,
|
||||||
|
"qua": "V1_WIN_NQ_9.9.22_40768_GW_B"
|
||||||
|
},
|
||||||
|
"6.9.82-40768": {
|
||||||
|
"appid": 537319829,
|
||||||
|
"qua": "V1_MAC_NQ_6.9.82_40768_GW_B"
|
||||||
|
},
|
||||||
|
"3.2.20-40824": {
|
||||||
|
"appid": 537319840,
|
||||||
|
"qua": "V1_LNX_NQ_3.2.20_40824_GW_B"
|
||||||
|
},
|
||||||
|
"9.9.22-40824": {
|
||||||
|
"appid": 537319804,
|
||||||
|
"qua": "V1_WIN_NQ_9.9.22_40824_GW_B"
|
||||||
|
},
|
||||||
|
"6.9.82-40824": {
|
||||||
|
"appid": 537319829,
|
||||||
|
"qua": "V1_MAC_NQ_6.9.82_40824_GW_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
28
src/core/external/offset.json
vendored
28
src/core/external/offset.json
vendored
@@ -514,5 +514,33 @@
|
|||||||
"9.9.22-40362-x64": {
|
"9.9.22-40362-x64": {
|
||||||
"send": "31C0EB8",
|
"send": "31C0EB8",
|
||||||
"recv": "31C465C"
|
"recv": "31C465C"
|
||||||
|
},
|
||||||
|
"3.2.20-40768-x64": {
|
||||||
|
"send": "B69CFE0",
|
||||||
|
"recv": "B6A0A60"
|
||||||
|
},
|
||||||
|
"9.9.22-40768-x64": {
|
||||||
|
"send": "31C1838",
|
||||||
|
"recv": "31C4FDC"
|
||||||
|
},
|
||||||
|
"3.2.20-40768-arm64": {
|
||||||
|
"send": "7D49B18",
|
||||||
|
"recv": "7D4D4A8"
|
||||||
|
},
|
||||||
|
"6.9.82-40768-arm64": {
|
||||||
|
"send": "202A198",
|
||||||
|
"recv": "202B718"
|
||||||
|
},
|
||||||
|
"9.9.22-40824-x64": {
|
||||||
|
"send": "31C1838",
|
||||||
|
"recv": "31C4FDC"
|
||||||
|
},
|
||||||
|
"3.2.20-40824-arm64": {
|
||||||
|
"send": "7D49B18",
|
||||||
|
"recv": "7D4D4A8"
|
||||||
|
},
|
||||||
|
"6.9.82-40824-arm64": {
|
||||||
|
"send": "202A198",
|
||||||
|
"recv": "202B718"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
src/native/packet/MoeHoo.darwin.arm64.new.node
Normal file
BIN
src/native/packet/MoeHoo.darwin.arm64.new.node
Normal file
Binary file not shown.
@@ -4,7 +4,10 @@ import { MessageUnique } from '@/common/message-unique';
|
|||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = Type.Object({
|
const SchemaData = Type.Object({
|
||||||
message_id: Type.Union([Type.Number(), Type.String()]),
|
message_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
||||||
|
msg_seq: Type.Optional(Type.String()),
|
||||||
|
msg_random: Type.Optional(Type.String()),
|
||||||
|
group_id: Type.Optional(Type.String()),
|
||||||
});
|
});
|
||||||
|
|
||||||
type Payload = Static<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
@@ -13,6 +16,20 @@ export default class DelEssenceMsg extends OneBotAction<Payload, unknown> {
|
|||||||
override payloadSchema = SchemaData;
|
override payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<unknown> {
|
async _handle(payload: Payload): Promise<unknown> {
|
||||||
|
// 如果直接提供了 msg_seq, msg_random, group_id,优先使用
|
||||||
|
if (payload.msg_seq && payload.msg_random && payload.group_id) {
|
||||||
|
return await this.core.apis.GroupApi.removeGroupEssenceBySeq(
|
||||||
|
payload.group_id,
|
||||||
|
payload.msg_random,
|
||||||
|
payload.msg_seq,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有 message_id,则必须提供 msg_seq, msg_random, group_id
|
||||||
|
if (!payload.message_id) {
|
||||||
|
throw new Error('必须提供 message_id 或者同时提供 msg_seq, msg_random, group_id');
|
||||||
|
}
|
||||||
|
|
||||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
const data = this.core.apis.GroupApi.essenceLRU.getValue(+payload.message_id);
|
const data = this.core.apis.GroupApi.essenceLRU.getValue(+payload.message_id);
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ import { SetGroupAlbumMediaLike } from './extends/SetGroupAlbumMediaLike';
|
|||||||
import { DelGroupAlbumMedia } from './extends/DelGroupAlbumMedia';
|
import { DelGroupAlbumMedia } from './extends/DelGroupAlbumMedia';
|
||||||
import { CleanStreamTempFile } from './stream/CleanStreamTempFile';
|
import { CleanStreamTempFile } from './stream/CleanStreamTempFile';
|
||||||
import { DownloadFileStream } from './stream/DownloadFileStream';
|
import { DownloadFileStream } from './stream/DownloadFileStream';
|
||||||
|
import { DownloadFileRecordStream } from './stream/DownloadFileRecordStream';
|
||||||
|
import { DownloadFileImageStream } from './stream/DownloadFileImageStream';
|
||||||
import { TestDownloadStream } from './stream/TestStreamDownload';
|
import { TestDownloadStream } from './stream/TestStreamDownload';
|
||||||
import { UploadFileStream } from './stream/UploadFileStream';
|
import { UploadFileStream } from './stream/UploadFileStream';
|
||||||
|
|
||||||
@@ -140,6 +142,8 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
|||||||
const actionHandlers = [
|
const actionHandlers = [
|
||||||
new CleanStreamTempFile(obContext, core),
|
new CleanStreamTempFile(obContext, core),
|
||||||
new DownloadFileStream(obContext, core),
|
new DownloadFileStream(obContext, core),
|
||||||
|
new DownloadFileRecordStream(obContext, core),
|
||||||
|
new DownloadFileImageStream(obContext, core),
|
||||||
new TestDownloadStream(obContext, core),
|
new TestDownloadStream(obContext, core),
|
||||||
new UploadFileStream(obContext, core),
|
new UploadFileStream(obContext, core),
|
||||||
new DelGroupAlbumMedia(obContext, core),
|
new DelGroupAlbumMedia(obContext, core),
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export const ActionName = {
|
|||||||
TestDownloadStream: 'test_download_stream',
|
TestDownloadStream: 'test_download_stream',
|
||||||
UploadFileStream: 'upload_file_stream',
|
UploadFileStream: 'upload_file_stream',
|
||||||
DownloadFileStream: 'download_file_stream',
|
DownloadFileStream: 'download_file_stream',
|
||||||
|
DownloadFileRecordStream: 'download_file_record_stream',
|
||||||
|
DownloadFileImageStream: 'download_file_image_stream',
|
||||||
|
|
||||||
DelGroupAlbumMedia: 'del_group_album_media',
|
DelGroupAlbumMedia: 'del_group_album_media',
|
||||||
SetGroupAlbumMediaLike: 'set_group_album_media_like',
|
SetGroupAlbumMediaLike: 'set_group_album_media_like',
|
||||||
|
|||||||
99
src/onebot/action/stream/BaseDownloadStream.ts
Normal file
99
src/onebot/action/stream/BaseDownloadStream.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { OneBotAction, OneBotRequestToolkit } from '@/onebot/action/OneBotAction';
|
||||||
|
import { StreamPacket, StreamStatus } from './StreamBasic';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { FileNapCatOneBotUUID } from '@/common/file-uuid';
|
||||||
|
|
||||||
|
export interface ResolvedFileInfo {
|
||||||
|
downloadPath: string;
|
||||||
|
fileName: string;
|
||||||
|
fileSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DownloadResult {
|
||||||
|
// 文件信息
|
||||||
|
file_name?: string;
|
||||||
|
file_size?: number;
|
||||||
|
chunk_size?: number;
|
||||||
|
|
||||||
|
// 分片数据
|
||||||
|
index?: number;
|
||||||
|
data?: string;
|
||||||
|
size?: number;
|
||||||
|
progress?: number;
|
||||||
|
base64_size?: number;
|
||||||
|
|
||||||
|
// 完成信息
|
||||||
|
total_chunks?: number;
|
||||||
|
total_bytes?: number;
|
||||||
|
message?: string;
|
||||||
|
data_type?: 'file_info' | 'file_chunk' | 'file_complete';
|
||||||
|
|
||||||
|
// 可选扩展字段
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
out_format?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class BaseDownloadStream<PayloadType, ResultType> extends OneBotAction<PayloadType, StreamPacket<ResultType>> {
|
||||||
|
protected async resolveDownload(file?: string): Promise<ResolvedFileInfo> {
|
||||||
|
const target = file || '';
|
||||||
|
let downloadPath = '';
|
||||||
|
let fileName = '';
|
||||||
|
let fileSize = 0;
|
||||||
|
|
||||||
|
const contextMsgFile = FileNapCatOneBotUUID.decode(target);
|
||||||
|
if (contextMsgFile && contextMsgFile.msgId && contextMsgFile.elementId) {
|
||||||
|
const { peer, msgId, elementId } = contextMsgFile;
|
||||||
|
downloadPath = await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
|
||||||
|
const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
|
||||||
|
.find(msg => msg.msgId === msgId);
|
||||||
|
const mixElement = rawMessage?.elements.find(e => e.elementId === elementId);
|
||||||
|
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
||||||
|
if (!mixElementInner) throw new Error('element not found');
|
||||||
|
fileSize = parseInt(mixElementInner.fileSize?.toString() ?? '0');
|
||||||
|
fileName = mixElementInner.fileName ?? '';
|
||||||
|
return { downloadPath, fileName, fileSize };
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextModelIdFile = FileNapCatOneBotUUID.decodeModelId(target);
|
||||||
|
if (contextModelIdFile && contextModelIdFile.modelId) {
|
||||||
|
const { peer, modelId } = contextModelIdFile;
|
||||||
|
downloadPath = await this.core.apis.FileApi.downloadFileForModelId(peer, modelId, '');
|
||||||
|
return { downloadPath, fileName, fileSize };
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchResult = (await this.core.apis.FileApi.searchForFile([target]));
|
||||||
|
if (searchResult) {
|
||||||
|
downloadPath = await this.core.apis.FileApi.downloadFileById(searchResult.id, parseInt(searchResult.fileSize));
|
||||||
|
fileSize = parseInt(searchResult.fileSize);
|
||||||
|
fileName = searchResult.fileName;
|
||||||
|
return { downloadPath, fileName, fileSize };
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('file not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async streamFileChunks(req: OneBotRequestToolkit, streamPath: string, chunkSize: number, chunkDataType: string): Promise<{ totalChunks: number; totalBytes: number }>
|
||||||
|
{
|
||||||
|
const stats = await fs.promises.stat(streamPath);
|
||||||
|
const totalSize = stats.size;
|
||||||
|
const readStream = fs.createReadStream(streamPath, { highWaterMark: chunkSize });
|
||||||
|
let chunkIndex = 0;
|
||||||
|
let bytesRead = 0;
|
||||||
|
for await (const chunk of readStream) {
|
||||||
|
const base64Chunk = (chunk as Buffer).toString('base64');
|
||||||
|
bytesRead += (chunk as Buffer).length;
|
||||||
|
await req.send({
|
||||||
|
type: StreamStatus.Stream,
|
||||||
|
data_type: chunkDataType,
|
||||||
|
index: chunkIndex,
|
||||||
|
data: base64Chunk,
|
||||||
|
size: (chunk as Buffer).length,
|
||||||
|
progress: Math.round((bytesRead / totalSize) * 100),
|
||||||
|
base64_size: base64Chunk.length
|
||||||
|
} as unknown as StreamPacket<any>);
|
||||||
|
chunkIndex++;
|
||||||
|
}
|
||||||
|
return { totalChunks: chunkIndex, totalBytes: bytesRead };
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/onebot/action/stream/DownloadFileImageStream.ts
Normal file
60
src/onebot/action/stream/DownloadFileImageStream.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
import { OneBotRequestToolkit } from '@/onebot/action/OneBotAction';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||||
|
import { StreamPacket, StreamStatus } from './StreamBasic';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { imageSizeFallBack } from '@/image-size';
|
||||||
|
import { BaseDownloadStream, DownloadResult } from './BaseDownloadStream';
|
||||||
|
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
file: Type.Optional(Type.String()),
|
||||||
|
file_id: Type.Optional(Type.String()),
|
||||||
|
chunk_size: Type.Optional(Type.Number({ default: 64 * 1024 })) // 默认64KB分块
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class DownloadFileImageStream extends BaseDownloadStream<Payload, DownloadResult> {
|
||||||
|
override actionName = ActionName.DownloadFileImageStream;
|
||||||
|
override payloadSchema = SchemaData;
|
||||||
|
override useStream = true;
|
||||||
|
|
||||||
|
async _handle(payload: Payload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise<StreamPacket<DownloadResult>> {
|
||||||
|
try {
|
||||||
|
payload.file ||= payload.file_id || '';
|
||||||
|
const chunkSize = payload.chunk_size || 64 * 1024;
|
||||||
|
|
||||||
|
const { downloadPath, fileName, fileSize } = await this.resolveDownload(payload.file);
|
||||||
|
|
||||||
|
const stats = await fs.promises.stat(downloadPath);
|
||||||
|
const totalSize = fileSize || stats.size;
|
||||||
|
const { width, height } = await imageSizeFallBack(downloadPath);
|
||||||
|
|
||||||
|
// 发送文件信息(与 DownloadFileStream 对齐,但包含宽高)
|
||||||
|
await req.send({
|
||||||
|
type: StreamStatus.Stream,
|
||||||
|
data_type: 'file_info',
|
||||||
|
file_name: fileName,
|
||||||
|
file_size: totalSize,
|
||||||
|
chunk_size: chunkSize,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
});
|
||||||
|
|
||||||
|
const { totalChunks, totalBytes } = await this.streamFileChunks(req, downloadPath, chunkSize, 'file_chunk');
|
||||||
|
|
||||||
|
// 返回完成状态(与 DownloadFileStream 对齐)
|
||||||
|
return {
|
||||||
|
type: StreamStatus.Response,
|
||||||
|
data_type: 'file_complete',
|
||||||
|
total_chunks: totalChunks,
|
||||||
|
total_bytes: totalBytes,
|
||||||
|
message: 'Download completed'
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Download failed: ${(error as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
96
src/onebot/action/stream/DownloadFileRecordStream.ts
Normal file
96
src/onebot/action/stream/DownloadFileRecordStream.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
|
||||||
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
import { OneBotRequestToolkit } from '@/onebot/action/OneBotAction';
|
||||||
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||||
|
import { StreamPacket, StreamStatus } from './StreamBasic';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { decode } from 'silk-wasm';
|
||||||
|
import { FFmpegService } from '@/common/ffmpeg';
|
||||||
|
import { BaseDownloadStream } from './BaseDownloadStream';
|
||||||
|
|
||||||
|
const out_format = ['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac'];
|
||||||
|
|
||||||
|
const SchemaData = Type.Object({
|
||||||
|
file: Type.Optional(Type.String()),
|
||||||
|
file_id: Type.Optional(Type.String()),
|
||||||
|
chunk_size: Type.Optional(Type.Number({ default: 64 * 1024 })), // 默认64KB分块
|
||||||
|
out_format: Type.Optional(Type.String())
|
||||||
|
});
|
||||||
|
|
||||||
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
|
import { DownloadResult } from './BaseDownloadStream';
|
||||||
|
|
||||||
|
export class DownloadFileRecordStream extends BaseDownloadStream<Payload, DownloadResult> {
|
||||||
|
override actionName = ActionName.DownloadFileRecordStream;
|
||||||
|
override payloadSchema = SchemaData;
|
||||||
|
override useStream = true;
|
||||||
|
|
||||||
|
async _handle(payload: Payload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise<StreamPacket<DownloadResult>> {
|
||||||
|
try {
|
||||||
|
payload.file ||= payload.file_id || '';
|
||||||
|
const chunkSize = payload.chunk_size || 64 * 1024;
|
||||||
|
|
||||||
|
const { downloadPath, fileName, fileSize } = await this.resolveDownload(payload.file);
|
||||||
|
|
||||||
|
// 处理输出格式转换
|
||||||
|
let streamPath = downloadPath;
|
||||||
|
if (payload.out_format && typeof payload.out_format === 'string') {
|
||||||
|
if (!out_format.includes(payload.out_format)) {
|
||||||
|
throw new Error('转换失败 out_format 字段可能格式不正确');
|
||||||
|
}
|
||||||
|
|
||||||
|
const pcmFile = `${downloadPath}.pcm`;
|
||||||
|
const outputFile = `${downloadPath}.${payload.out_format}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 如果已存在目标文件则跳过转换
|
||||||
|
await fs.promises.access(outputFile);
|
||||||
|
streamPath = outputFile;
|
||||||
|
} catch {
|
||||||
|
// 尝试解码 silk 到 pcm 再用 ffmpeg 转换
|
||||||
|
await this.decodeFile(downloadPath, pcmFile);
|
||||||
|
await FFmpegService.convertFile(pcmFile, outputFile, payload.out_format);
|
||||||
|
streamPath = outputFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stats = await fs.promises.stat(streamPath);
|
||||||
|
const totalSize = fileSize || stats.size;
|
||||||
|
|
||||||
|
await req.send({
|
||||||
|
type: StreamStatus.Stream,
|
||||||
|
data_type: 'file_info',
|
||||||
|
file_name: fileName,
|
||||||
|
file_size: totalSize,
|
||||||
|
chunk_size: chunkSize,
|
||||||
|
out_format: payload.out_format
|
||||||
|
});
|
||||||
|
|
||||||
|
const { totalChunks, totalBytes } = await this.streamFileChunks(req, streamPath, chunkSize, 'file_chunk');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: StreamStatus.Response,
|
||||||
|
data_type: 'file_complete',
|
||||||
|
total_chunks: totalChunks,
|
||||||
|
total_bytes: totalBytes,
|
||||||
|
message: 'Download completed'
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Download failed: ${(error as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async decodeFile(inputFile: string, outputFile: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const inputData = await fs.promises.readFile(inputFile);
|
||||||
|
const decodedData = await decode(inputData, 24000);
|
||||||
|
await fs.promises.writeFile(outputFile, Buffer.from(decodedData.data));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error decoding file:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { OneBotAction, OneBotRequestToolkit } from '@/onebot/action/OneBotAction';
|
import { OneBotRequestToolkit } from '@/onebot/action/OneBotAction';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
import { NetworkAdapterConfig } from '@/onebot/config/config';
|
||||||
import { StreamPacket, StreamStatus } from './StreamBasic';
|
import { StreamPacket, StreamStatus } from './StreamBasic';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { FileNapCatOneBotUUID } from '@/common/file-uuid';
|
import { BaseDownloadStream, DownloadResult } from './BaseDownloadStream';
|
||||||
const SchemaData = Type.Object({
|
const SchemaData = Type.Object({
|
||||||
file: Type.Optional(Type.String()),
|
file: Type.Optional(Type.String()),
|
||||||
file_id: Type.Optional(Type.String()),
|
file_id: Type.Optional(Type.String()),
|
||||||
@@ -13,28 +13,7 @@ const SchemaData = Type.Object({
|
|||||||
|
|
||||||
type Payload = Static<typeof SchemaData>;
|
type Payload = Static<typeof SchemaData>;
|
||||||
|
|
||||||
// 下载结果类型
|
export class DownloadFileStream extends BaseDownloadStream<Payload, DownloadResult> {
|
||||||
interface DownloadResult {
|
|
||||||
// 文件信息
|
|
||||||
file_name?: string;
|
|
||||||
file_size?: number;
|
|
||||||
chunk_size?: number;
|
|
||||||
|
|
||||||
// 分片数据
|
|
||||||
index?: number;
|
|
||||||
data?: string;
|
|
||||||
size?: number;
|
|
||||||
progress?: number;
|
|
||||||
base64_size?: number;
|
|
||||||
|
|
||||||
// 完成信息
|
|
||||||
total_chunks?: number;
|
|
||||||
total_bytes?: number;
|
|
||||||
message?: string;
|
|
||||||
data_type?: 'file_info' | 'file_chunk' | 'file_complete';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DownloadFileStream extends OneBotAction<Payload, StreamPacket<DownloadResult>> {
|
|
||||||
override actionName = ActionName.DownloadFileStream;
|
override actionName = ActionName.DownloadFileStream;
|
||||||
override payloadSchema = SchemaData;
|
override payloadSchema = SchemaData;
|
||||||
override useStream = true;
|
override useStream = true;
|
||||||
@@ -43,50 +22,12 @@ export class DownloadFileStream extends OneBotAction<Payload, StreamPacket<Downl
|
|||||||
try {
|
try {
|
||||||
payload.file ||= payload.file_id || '';
|
payload.file ||= payload.file_id || '';
|
||||||
const chunkSize = payload.chunk_size || 64 * 1024;
|
const chunkSize = payload.chunk_size || 64 * 1024;
|
||||||
let downloadPath = '';
|
|
||||||
let fileName = '';
|
|
||||||
let fileSize = 0;
|
|
||||||
|
|
||||||
//接收消息标记模式
|
const { downloadPath, fileName, fileSize } = await this.resolveDownload(payload.file);
|
||||||
const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file);
|
|
||||||
if (contextMsgFile && contextMsgFile.msgId && contextMsgFile.elementId) {
|
|
||||||
const { peer, msgId, elementId } = contextMsgFile;
|
|
||||||
downloadPath = await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
|
|
||||||
const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
|
|
||||||
.find(msg => msg.msgId === msgId);
|
|
||||||
const mixElement = rawMessage?.elements.find(e => e.elementId === elementId);
|
|
||||||
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
|
||||||
if (!mixElementInner) throw new Error('element not found');
|
|
||||||
fileSize = parseInt(mixElementInner.fileSize?.toString() ?? '0');
|
|
||||||
fileName = mixElementInner.fileName ?? '';
|
|
||||||
}
|
|
||||||
//群文件模式
|
|
||||||
else if (FileNapCatOneBotUUID.decodeModelId(payload.file)) {
|
|
||||||
const contextModelIdFile = FileNapCatOneBotUUID.decodeModelId(payload.file);
|
|
||||||
if (contextModelIdFile && contextModelIdFile.modelId) {
|
|
||||||
const { peer, modelId } = contextModelIdFile;
|
|
||||||
downloadPath = await this.core.apis.FileApi.downloadFileForModelId(peer, modelId, '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//搜索名字模式
|
|
||||||
else {
|
|
||||||
const searchResult = (await this.core.apis.FileApi.searchForFile([payload.file]));
|
|
||||||
if (searchResult) {
|
|
||||||
downloadPath = await this.core.apis.FileApi.downloadFileById(searchResult.id, parseInt(searchResult.fileSize));
|
|
||||||
fileSize = parseInt(searchResult.fileSize);
|
|
||||||
fileName = searchResult.fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!downloadPath) {
|
|
||||||
throw new Error('file not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取文件大小
|
|
||||||
const stats = await fs.promises.stat(downloadPath);
|
const stats = await fs.promises.stat(downloadPath);
|
||||||
const totalSize = fileSize || stats.size;
|
const totalSize = fileSize || stats.size;
|
||||||
|
|
||||||
// 发送文件信息
|
|
||||||
await req.send({
|
await req.send({
|
||||||
type: StreamStatus.Stream,
|
type: StreamStatus.Stream,
|
||||||
data_type: 'file_info',
|
data_type: 'file_info',
|
||||||
@@ -95,34 +36,13 @@ export class DownloadFileStream extends OneBotAction<Payload, StreamPacket<Downl
|
|||||||
chunk_size: chunkSize
|
chunk_size: chunkSize
|
||||||
});
|
});
|
||||||
|
|
||||||
// 创建读取流并分块发送
|
const { totalChunks, totalBytes } = await this.streamFileChunks(req, downloadPath, chunkSize, 'file_chunk');
|
||||||
const readStream = fs.createReadStream(downloadPath, { highWaterMark: chunkSize });
|
|
||||||
let chunkIndex = 0;
|
|
||||||
let bytesRead = 0;
|
|
||||||
|
|
||||||
for await (const chunk of readStream) {
|
|
||||||
const base64Chunk = chunk.toString('base64');
|
|
||||||
bytesRead += chunk.length;
|
|
||||||
|
|
||||||
await req.send({
|
|
||||||
type: StreamStatus.Stream,
|
|
||||||
data_type: 'file_chunk',
|
|
||||||
index: chunkIndex,
|
|
||||||
data: base64Chunk,
|
|
||||||
size: chunk.length,
|
|
||||||
progress: Math.round((bytesRead / totalSize) * 100),
|
|
||||||
base64_size: base64Chunk.length
|
|
||||||
});
|
|
||||||
|
|
||||||
chunkIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回完成状态
|
|
||||||
return {
|
return {
|
||||||
type: StreamStatus.Response,
|
type: StreamStatus.Response,
|
||||||
data_type: 'file_complete',
|
data_type: 'file_complete',
|
||||||
total_chunks: chunkIndex,
|
total_chunks: totalChunks,
|
||||||
total_bytes: bytesRead,
|
total_bytes: totalBytes,
|
||||||
message: 'Download completed'
|
message: 'Download completed'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -217,15 +217,6 @@ export class NapCatOneBot11Adapter {
|
|||||||
//this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`);
|
//this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`);
|
||||||
await this.reloadNetwork(prev, newConfig);
|
await this.reloadNetwork(prev, newConfig);
|
||||||
});
|
});
|
||||||
WebUiDataRuntime.setCleanCacheCall(async () => {
|
|
||||||
try {
|
|
||||||
await this.actions.get('clean_cache')?.handle({});
|
|
||||||
return { result: true, message: '缓存清理成功' };
|
|
||||||
} catch (error) {
|
|
||||||
this.context.logger.logError('清理缓存失败:', error);
|
|
||||||
return { result: false, message: `清理缓存失败: ${(error as Error).message}` };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,3 @@ export const SetThemeConfigHandler: RequestHandler = async (req, res) => {
|
|||||||
await WebUiConfig.UpdateTheme(theme);
|
await WebUiConfig.UpdateTheme(theme);
|
||||||
sendSuccess(res, { message: '更新成功' });
|
sendSuccess(res, { message: '更新成功' });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CleanCacheHandler: RequestHandler = async (_, res) => {
|
|
||||||
const result = await WebUiDataRuntime.requestCleanCache();
|
|
||||||
sendSuccess(res, result);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ const LoginRuntime: LoginRuntimeType = {
|
|||||||
onQuickLoginRequested: async () => {
|
onQuickLoginRequested: async () => {
|
||||||
return { result: false, message: '' };
|
return { result: false, message: '' };
|
||||||
},
|
},
|
||||||
onCleanCacheRequested: async () => {
|
|
||||||
return { result: false, message: '' };
|
|
||||||
},
|
|
||||||
QQLoginList: [],
|
QQLoginList: [],
|
||||||
NewQQLoginList: [],
|
NewQQLoginList: [],
|
||||||
},
|
},
|
||||||
@@ -133,14 +130,6 @@ export const WebUiDataRuntime = {
|
|||||||
return LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11);
|
return LoginRuntime.NapCatHelper.onOB11ConfigChanged(ob11);
|
||||||
} as LoginRuntimeType['NapCatHelper']['onOB11ConfigChanged'],
|
} as LoginRuntimeType['NapCatHelper']['onOB11ConfigChanged'],
|
||||||
|
|
||||||
setCleanCacheCall(func: LoginRuntimeType['NapCatHelper']['onCleanCacheRequested']): void {
|
|
||||||
LoginRuntime.NapCatHelper.onCleanCacheRequested = func;
|
|
||||||
},
|
|
||||||
|
|
||||||
requestCleanCache: function () {
|
|
||||||
return LoginRuntime.NapCatHelper.onCleanCacheRequested();
|
|
||||||
} as LoginRuntimeType['NapCatHelper']['onCleanCacheRequested'],
|
|
||||||
|
|
||||||
getPackageJson() {
|
getPackageJson() {
|
||||||
return LoginRuntime.packageJson;
|
return LoginRuntime.packageJson;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { CleanCacheHandler, GetThemeConfigHandler, PackageInfoHandler, QQVersionHandler, SetThemeConfigHandler } from '../api/BaseInfo';
|
import { GetThemeConfigHandler, PackageInfoHandler, QQVersionHandler, SetThemeConfigHandler } from '../api/BaseInfo';
|
||||||
import { StatusRealTimeHandler } from '@webapi/api/Status';
|
import { StatusRealTimeHandler } from '@webapi/api/Status';
|
||||||
import { GetProxyHandler } from '../api/Proxy';
|
import { GetProxyHandler } from '../api/Proxy';
|
||||||
|
|
||||||
@@ -11,6 +11,5 @@ router.get('/GetSysStatusRealTime', StatusRealTimeHandler);
|
|||||||
router.get('/proxy', GetProxyHandler);
|
router.get('/proxy', GetProxyHandler);
|
||||||
router.get('/Theme', GetThemeConfigHandler);
|
router.get('/Theme', GetThemeConfigHandler);
|
||||||
router.post('/SetTheme', SetThemeConfigHandler);
|
router.post('/SetTheme', SetThemeConfigHandler);
|
||||||
router.post('/CleanCache', CleanCacheHandler);
|
|
||||||
|
|
||||||
export { router as BaseRouter };
|
export { router as BaseRouter };
|
||||||
|
|||||||
1
src/webui/src/types/data.d.ts
vendored
1
src/webui/src/types/data.d.ts
vendored
@@ -15,7 +15,6 @@ interface LoginRuntimeType {
|
|||||||
NapCatHelper: {
|
NapCatHelper: {
|
||||||
onQuickLoginRequested: (uin: string) => Promise<{ result: boolean; message: string }>;
|
onQuickLoginRequested: (uin: string) => Promise<{ result: boolean; message: string }>;
|
||||||
onOB11ConfigChanged: (ob11: OneBotConfig) => Promise<void>;
|
onOB11ConfigChanged: (ob11: OneBotConfig) => Promise<void>;
|
||||||
onCleanCacheRequested: () => Promise<{ result: boolean; message: string }>;
|
|
||||||
QQLoginList: string[];
|
QQLoginList: string[];
|
||||||
NewQQLoginList: LoginListItem[];
|
NewQQLoginList: LoginListItem[];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ export const createUrl = (
|
|||||||
url.searchParams.set(key, search[key])
|
url.searchParams.set(key, search[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return url.toString()
|
|
||||||
|
/** 进行url解码 对特殊字符进行处理 */
|
||||||
|
return decodeURIComponent(url.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user