mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
49234ea5c7 | ||
![]() |
c474158a09 | ||
![]() |
813a541e7f | ||
![]() |
efd489bfd4 | ||
![]() |
9c88fcb610 | ||
![]() |
c1cac8de19 | ||
![]() |
b03fa54e63 | ||
![]() |
9785731f25 | ||
![]() |
566afde18b | ||
![]() |
bae8dabc5c | ||
![]() |
0a9dfea20a | ||
![]() |
50498aa52d |
@@ -53,7 +53,7 @@ NapCat 在设计理念下遵守 OneBot 规范大多数要求并且积极改进
|
|||||||
## 感谢他们
|
## 感谢他们
|
||||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
|
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
|
||||||
|
|
||||||
感谢 Tencent Tdesign / Vue3 强力驱动 NapCat.WebUi
|
感谢 React 强力驱动 NapCat.WebUi
|
||||||
|
|
||||||
不过最最重要的 还是需要感谢屏幕前的你哦~
|
不过最最重要的 还是需要感谢屏幕前的你哦~
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "4.4.4",
|
"version": "4.4.8",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -88,6 +88,34 @@ const AddButton: React.FC<AddButtonProps> = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
key="httpSseServers"
|
||||||
|
textValue="httpSseServers"
|
||||||
|
startContent={
|
||||||
|
<div className="w-6 h-6">
|
||||||
|
<HTTPServerIcon />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex gap-1 items-center">
|
||||||
|
HTTP SSE服务器
|
||||||
|
<Tooltip
|
||||||
|
content="「由NapCat建立」一个HTTP SSE服务器,你可以「使用框架连接」此服务器或者「自己构造请求发送」至此服务器。NapCat会根据你配置的IP和端口等建立一个地址,你或者你的框架应该连接到这个地址。"
|
||||||
|
showArrow
|
||||||
|
className="max-w-64"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
radius="full"
|
||||||
|
size="sm"
|
||||||
|
variant="light"
|
||||||
|
className="w-4 h-4 min-w-0"
|
||||||
|
>
|
||||||
|
<FaRegCircleQuestion />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</DropdownItem>
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key="httpClients"
|
key="httpClients"
|
||||||
textValue="httpClients"
|
textValue="httpClients"
|
||||||
|
@@ -24,6 +24,14 @@ export default class WebUIManager {
|
|||||||
return data.data.Credential
|
return data.data.Credential
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async proxy<T>(url = '') {
|
||||||
|
const data = await serverRequest.get<ServerResponse<string>>(
|
||||||
|
'/base/proxy?url=' + encodeURIComponent(url)
|
||||||
|
)
|
||||||
|
data.data.data = JSON.parse(data.data.data)
|
||||||
|
return data.data as ServerResponse<T>
|
||||||
|
}
|
||||||
|
|
||||||
public static async getPackageInfo() {
|
public static async getPackageInfo() {
|
||||||
const { data } =
|
const { data } =
|
||||||
await serverRequest.get<ServerResponse<PackageInfo>>('/base/PackageInfo')
|
await serverRequest.get<ServerResponse<PackageInfo>>('/base/PackageInfo')
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
import { Tab, Tabs } from '@heroui/tabs'
|
import { Tab, Tabs } from '@heroui/tabs'
|
||||||
import { useLocalStorage } from '@uidotdev/usehooks'
|
import { useLocalStorage } from '@uidotdev/usehooks'
|
||||||
import { useEffect } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { useMediaQuery } from 'react-responsive'
|
import { useMediaQuery } from 'react-responsive'
|
||||||
|
|
||||||
import key from '@/const/key'
|
import key from '@/const/key'
|
||||||
|
|
||||||
|
import PageLoading from '@/components/page_loading'
|
||||||
|
|
||||||
import useConfig from '@/hooks/use-config'
|
import useConfig from '@/hooks/use-config'
|
||||||
import useMusic from '@/hooks/use-music'
|
import useMusic from '@/hooks/use-music'
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ import WebUIConfigCard from './webui'
|
|||||||
|
|
||||||
export default function ConfigPage() {
|
export default function ConfigPage() {
|
||||||
const { config, saveConfigWithoutNetwork, refreshConfig } = useConfig()
|
const { config, saveConfigWithoutNetwork, refreshConfig } = useConfig()
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
const {
|
const {
|
||||||
control: onebotControl,
|
control: onebotControl,
|
||||||
handleSubmit: handleOnebotSubmit,
|
handleSubmit: handleOnebotSubmit,
|
||||||
@@ -82,13 +85,16 @@ export default function ConfigPage() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const onRefresh = async () => {
|
const onRefresh = async (shotTip = true) => {
|
||||||
try {
|
try {
|
||||||
|
setLoading(true)
|
||||||
await refreshConfig()
|
await refreshConfig()
|
||||||
toast.success('刷新成功')
|
if (shotTip) toast.success('刷新成功')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = (error as Error).message
|
const msg = (error as Error).message
|
||||||
toast.error(`刷新失败: ${msg}`)
|
toast.error(`刷新失败: ${msg}`)
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +103,10 @@ export default function ConfigPage() {
|
|||||||
resetWebUI()
|
resetWebUI()
|
||||||
}, [config])
|
}, [config])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onRefresh(false)
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="w-[1000px] max-w-full md:mx-auto gap-4 py-8 px-2 md:py-10">
|
<section className="w-[1000px] max-w-full md:mx-auto gap-4 py-8 px-2 md:py-10">
|
||||||
<Tabs
|
<Tabs
|
||||||
@@ -106,12 +116,13 @@ export default function ConfigPage() {
|
|||||||
isVertical={isMediumUp}
|
isVertical={isMediumUp}
|
||||||
classNames={{
|
classNames={{
|
||||||
tabList: 'sticky flex top-14 bg-opacity-50 backdrop-blur-sm',
|
tabList: 'sticky flex top-14 bg-opacity-50 backdrop-blur-sm',
|
||||||
panel: 'w-full',
|
panel: 'w-full relative',
|
||||||
base: 'md:!w-auto flex-grow-0 flex-shrink-0 mr-0',
|
base: 'md:!w-auto flex-grow-0 flex-shrink-0 mr-0',
|
||||||
cursor: 'bg-opacity-60 backdrop-blur-sm'
|
cursor: 'bg-opacity-60 backdrop-blur-sm'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tab title="OneBot配置" key="onebot">
|
<Tab title="OneBot配置" key="onebot">
|
||||||
|
<PageLoading loading={loading} />
|
||||||
<OneBotConfigCard
|
<OneBotConfigCard
|
||||||
isSubmitting={isOnebotSubmitting}
|
isSubmitting={isOnebotSubmitting}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
|
@@ -294,6 +294,13 @@ export default function NetworkPage() {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (httpSseServers.find((i) => i.name === item.name)) {
|
||||||
|
return renderCard(
|
||||||
|
'httpSseServers',
|
||||||
|
item as OneBotConfig['network']['httpSseServers'][0],
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
if (httpClients.find((i) => i.name === item.name)) {
|
if (httpClients.find((i) => i.name === item.name)) {
|
||||||
return renderCard(
|
return renderCard(
|
||||||
'httpClients',
|
'httpClients',
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
/* HarmonyOS Sans SC */
|
/* HarmonyOS Sans SC */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Harmony';
|
font-family: 'Harmony';
|
||||||
src: url('/fonts/harmony/HarmonyOS_Sans_SC_Bold.ttf') format('truetype');
|
src: url('/webui/fonts/harmony/HarmonyOS_Sans_SC_Bold.ttf') format('truetype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Harmony';
|
font-family: 'Harmony';
|
||||||
src: url('/fonts/harmony/HarmonyOS_Sans_SC_Regular.ttf') format('truetype');
|
src: url('/webui/fonts/harmony/HarmonyOS_Sans_SC_Regular.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@@ -16,56 +16,56 @@
|
|||||||
/* Ubuntu */
|
/* Ubuntu */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/ubuntu/Ubuntu-Bold.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-Bold.ttf') format('truetype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/ubuntu/Ubuntu-Regular.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-Regular.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/ubuntu/Ubuntu-Light.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-Light.ttf') format('truetype');
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/ubuntu/Ubuntu-BoldItalic.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-BoldItalic.ttf') format('truetype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/ubuntu/Ubuntu-Italic.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-Italic.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/ubuntu/Ubuntu-LightItalic.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-LightItalic.ttf') format('truetype');
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/pingfang/Ubuntu-Medium.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-Medium.ttf') format('truetype');
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: 'Ubuntu';
|
||||||
src: url('/fonts/pingfang/Ubuntu-MediumItalic.ttf') format('truetype');
|
src: url('/webui/fonts/ubuntu/Ubuntu-MediumItalic.ttf') format('truetype');
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@@ -73,21 +73,21 @@
|
|||||||
/* LibreBaskerville */
|
/* LibreBaskerville */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Libre Baskerville';
|
font-family: 'Libre Baskerville';
|
||||||
src: url('/fonts/LibreBaskerville/LibreBaskerville-Bold.ttf') format('truetype');
|
src: url('/webui/fonts/LibreBaskerville/LibreBaskerville-Bold.ttf') format('truetype');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Libre Baskerville';
|
font-family: 'Libre Baskerville';
|
||||||
src: url('/fonts/LibreBaskerville/LibreBaskerville-Regular.ttf') format('truetype');
|
src: url('/webui/fonts/LibreBaskerville/LibreBaskerville-Regular.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Libre Baskerville';
|
font-family: 'Libre Baskerville';
|
||||||
src: url('/fonts/LibreBaskerville/LibreBaskerville-Italic.ttf') format('truetype');
|
src: url('/webui/fonts/LibreBaskerville/LibreBaskerville-Italic.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@@ -95,17 +95,17 @@
|
|||||||
/* NotoSerifSC */
|
/* NotoSerifSC */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Noto Serif SC';
|
font-family: 'Noto Serif SC';
|
||||||
src: url('/fonts/NotoSerifSC-VariableFont_wght.ttf') format('truetype');
|
src: url('/webui/fonts/NotoSerifSC-VariableFont_wght.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Outfit */
|
/* Outfit */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Outfit';
|
font-family: 'Outfit';
|
||||||
src: url('/fonts/Outfit-VariableFont_wght.ttf') format('truetype');
|
src: url('/webui/fonts/Outfit-VariableFont_wght.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FiraCode */
|
/* FiraCode */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Fira Code';
|
font-family: 'Fira Code';
|
||||||
src: url('/fonts/FiraCode-VariablFont_wght.ttf') format('truetype');
|
src: url('/webui/fonts/FiraCode-VariableFont_wght.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
@@ -6,17 +6,17 @@ import type {
|
|||||||
Music163URLResponse
|
Music163URLResponse
|
||||||
} from '@/types/music'
|
} from '@/types/music'
|
||||||
|
|
||||||
import { request } from './request'
|
import WebUIManager from '@/controllers/webui_manager'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取网易云音乐歌单
|
* 获取网易云音乐歌单
|
||||||
* @param id 歌单id
|
* @param id 歌单id
|
||||||
* @returns 歌单信息
|
* @returns 歌单信息
|
||||||
*/
|
*/
|
||||||
export const get163MusicList = async (id: string) => {
|
export const get163MusicList = async (id: string) => {
|
||||||
const res = await request.get<Music163ListResponse>(
|
let res = await WebUIManager.proxy<Music163ListResponse>('https://wavesgame.top/playlist/track/all?id=' + id);
|
||||||
`https://wavesgame.top/playlist/track/all?id=${id}`
|
// const res = await request.get<Music163ListResponse>(
|
||||||
)
|
// `https://wavesgame.top/playlist/track/all?id=${id}`
|
||||||
|
// )
|
||||||
if (res?.data?.code !== 200) {
|
if (res?.data?.code !== 200) {
|
||||||
throw new Error('获取歌曲列表失败')
|
throw new Error('获取歌曲列表失败')
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ export const getSongsURL = async (ids: number[]) => {
|
|||||||
}, [] as number[][])
|
}, [] as number[][])
|
||||||
const res = await Promise.all(
|
const res = await Promise.all(
|
||||||
_ids.map(async (id) => {
|
_ids.map(async (id) => {
|
||||||
const res = await request.get<Music163URLResponse>(
|
const res = await WebUIManager.proxy<Music163URLResponse>(
|
||||||
`https://wavesgame.top/song/url?id=${id.join(',')}`
|
`https://wavesgame.top/song/url?id=${id.join(',')}`
|
||||||
)
|
)
|
||||||
if (res?.data?.code !== 200) {
|
if (res?.data?.code !== 200) {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "4.4.4",
|
"version": "4.4.8",
|
||||||
"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",
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
"dev:depend": "npm i && cd napcat.webui && npm i"
|
"dev:depend": "npm i && cd napcat.webui && npm i"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"json5": "^2.2.3",
|
||||||
"esbuild": "0.24.0",
|
"esbuild": "0.24.0",
|
||||||
"@babel/preset-typescript": "^7.24.7",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@eslint/compat": "^1.2.2",
|
"@eslint/compat": "^1.2.2",
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import type { NapCatCore } from '@/core';
|
import type { NapCatCore } from '@/core';
|
||||||
|
import json5 from 'json5';
|
||||||
|
|
||||||
export abstract class ConfigBase<T> {
|
export abstract class ConfigBase<T> {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -46,7 +47,7 @@ export abstract class ConfigBase<T> {
|
|||||||
fs.writeFileSync(configPath, '{}');
|
fs.writeFileSync(configPath, '{}');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.configData = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
this.configData = json5.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||||
this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
|
this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
|
||||||
return this.configData;
|
return this.configData;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
@@ -25,7 +25,6 @@ export class Fallback<T> {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
|
||||||
errors.push(error instanceof Error ? error : new Error(String(error)));
|
errors.push(error instanceof Error ? error : new Error(String(error)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -181,28 +181,28 @@ export async function uriToLocalFile(dir: string, uri: string, filename: string
|
|||||||
const filePath = path.join(dir, filename);
|
const filePath = path.join(dir, filename);
|
||||||
|
|
||||||
switch (UriType) {
|
switch (UriType) {
|
||||||
case FileUriType.Local: {
|
case FileUriType.Local: {
|
||||||
const fileExt = path.extname(HandledUri);
|
const fileExt = path.extname(HandledUri);
|
||||||
const localFileName = path.basename(HandledUri, fileExt) + fileExt;
|
const localFileName = path.basename(HandledUri, fileExt) + fileExt;
|
||||||
const tempFilePath = path.join(dir, filename + fileExt);
|
const tempFilePath = path.join(dir, filename + fileExt);
|
||||||
fs.copyFileSync(HandledUri, tempFilePath);
|
fs.copyFileSync(HandledUri, tempFilePath);
|
||||||
return { success: true, errMsg: '', fileName: localFileName, path: tempFilePath };
|
return { success: true, errMsg: '', fileName: localFileName, path: tempFilePath };
|
||||||
}
|
}
|
||||||
|
|
||||||
case FileUriType.Remote: {
|
case FileUriType.Remote: {
|
||||||
const buffer = await httpDownload({ url: HandledUri, headers: headers });
|
const buffer = await httpDownload({ url: HandledUri, headers: headers });
|
||||||
fs.writeFileSync(filePath, buffer);
|
fs.writeFileSync(filePath, buffer);
|
||||||
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
||||||
}
|
}
|
||||||
|
|
||||||
case FileUriType.Base64: {
|
case FileUriType.Base64: {
|
||||||
const base64 = HandledUri.replace(/^base64:\/\//, '');
|
const base64 = HandledUri.replace(/^base64:\/\//, '');
|
||||||
const base64Buffer = Buffer.from(base64, 'base64');
|
const base64Buffer = Buffer.from(base64, 'base64');
|
||||||
fs.writeFileSync(filePath, base64Buffer);
|
fs.writeFileSync(filePath, base64Buffer);
|
||||||
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return { success: false, errMsg: `识别URL失败, uri= ${uri}`, fileName: '', path: '' };
|
return { success: false, errMsg: `识别URL失败, uri= ${uri}`, fileName: '', path: '' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '4.4.4';
|
export const napCatVersion = '4.4.8';
|
||||||
|
@@ -67,7 +67,7 @@ export class NTQQGroupApi {
|
|||||||
1,
|
1,
|
||||||
1000
|
1000
|
||||||
).then((data) => {
|
).then((data) => {
|
||||||
resolve(data[1])
|
resolve(data[1]);
|
||||||
}).catch(reject);
|
}).catch(reject);
|
||||||
|
|
||||||
onCancel(() => {
|
onCancel(() => {
|
||||||
@@ -78,9 +78,9 @@ export class NTQQGroupApi {
|
|||||||
const task = new CancelableTask(executor);
|
const task = new CancelableTask(executor);
|
||||||
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode).then(e => {
|
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode).then(e => {
|
||||||
if (e.result !== 0) {
|
if (e.result !== 0) {
|
||||||
task.cancel()
|
task.cancel();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return await task.catch(() => []);
|
return await task.catch(() => []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -905,16 +905,16 @@ export class OneBotMsgApi {
|
|||||||
const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => {
|
const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => {
|
||||||
const sizePromises = elements.map(async element => {
|
const sizePromises = elements.map(async element => {
|
||||||
switch (element.elementType) {
|
switch (element.elementType) {
|
||||||
case ElementType.PTT:
|
case ElementType.PTT:
|
||||||
return (await fsPromise.stat(element.pttElement.filePath)).size;
|
return (await fsPromise.stat(element.pttElement.filePath)).size;
|
||||||
case ElementType.FILE:
|
case ElementType.FILE:
|
||||||
return (await fsPromise.stat(element.fileElement.filePath)).size;
|
return (await fsPromise.stat(element.fileElement.filePath)).size;
|
||||||
case ElementType.VIDEO:
|
case ElementType.VIDEO:
|
||||||
return (await fsPromise.stat(element.videoElement.filePath)).size;
|
return (await fsPromise.stat(element.videoElement.filePath)).size;
|
||||||
case ElementType.PIC:
|
case ElementType.PIC:
|
||||||
return (await fsPromise.stat(element.picElement.sourcePath)).size;
|
return (await fsPromise.stat(element.picElement.sourcePath)).size;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const sizes = await Promise.all(sizePromises);
|
const sizes = await Promise.all(sizePromises);
|
||||||
@@ -1007,14 +1007,14 @@ export class OneBotMsgApi {
|
|||||||
}
|
}
|
||||||
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 130:
|
case 130:
|
||||||
return 'leave';
|
return 'leave';
|
||||||
case 131:
|
case 131:
|
||||||
return 'kick';
|
return 'kick';
|
||||||
case 3:
|
case 3:
|
||||||
return 'kick_me';
|
return 'kick_me';
|
||||||
default:
|
default:
|
||||||
return 'kick';
|
return 'kick';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -98,7 +98,7 @@ export type NetworkConfigKey = keyof OneBotConfig['network'];
|
|||||||
|
|
||||||
|
|
||||||
export function loadConfig(config: Partial<OneBotConfig>): OneBotConfig {
|
export function loadConfig(config: Partial<OneBotConfig>): OneBotConfig {
|
||||||
const ajv = new Ajv({ useDefaults: true });
|
const ajv = new Ajv({ useDefaults: true, coerceTypes: true });
|
||||||
const validate = ajv.compile(OneBotConfigSchema);
|
const validate = ajv.compile(OneBotConfigSchema);
|
||||||
const valid = validate(config);
|
const valid = validate(config);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
@@ -53,6 +53,6 @@ export const OB11SetConfigHandler: RequestHandler = async (req, res) => {
|
|||||||
await WebUiDataRuntime.setOB11Config(JSON.parse(req.body.config));
|
await WebUiDataRuntime.setOB11Config(JSON.parse(req.body.config));
|
||||||
return sendSuccess(res, null);
|
return sendSuccess(res, null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return sendError(res, 'Config Set Error');
|
return sendError(res, 'Error: ' + e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
14
src/webui/src/api/Proxy.ts
Normal file
14
src/webui/src/api/Proxy.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { RequestUtil } from "@/common/request";
|
||||||
|
import { sendError, sendSuccess } from "../utils/response";
|
||||||
|
|
||||||
|
export const GetProxyHandler: RequestHandler = async (req, res) => {
|
||||||
|
let { url } = req.query;
|
||||||
|
if (url && typeof url === "string") {
|
||||||
|
url = decodeURIComponent(url);
|
||||||
|
const responseText = await RequestUtil.HttpGetText(url);
|
||||||
|
res.send(sendSuccess(res, responseText));
|
||||||
|
} else {
|
||||||
|
res.send(sendError(res, 'url参数不合法'));
|
||||||
|
}
|
||||||
|
};
|
@@ -1,11 +1,12 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { PackageInfoHandler, QQVersionHandler } from '../api/BaseInfo';
|
import { PackageInfoHandler, QQVersionHandler } from '../api/BaseInfo';
|
||||||
import { StatusRealTimeHandler } from "@webapi/api/Status";
|
import { StatusRealTimeHandler } from "@webapi/api/Status";
|
||||||
|
import { GetProxyHandler } from '../api/Proxy';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
// router: 获取nc的package.json信息
|
// router: 获取nc的package.json信息
|
||||||
router.get('/QQVersion', QQVersionHandler);
|
router.get('/QQVersion', QQVersionHandler);
|
||||||
router.get('/PackageInfo', PackageInfoHandler);
|
router.get('/PackageInfo', PackageInfoHandler);
|
||||||
router.get('/GetSysStatusRealTime', StatusRealTimeHandler);
|
router.get('/GetSysStatusRealTime', StatusRealTimeHandler);
|
||||||
|
router.get('/proxy', GetProxyHandler);
|
||||||
export { router as BaseRouter };
|
export { router as BaseRouter };
|
||||||
|
Reference in New Issue
Block a user