Compare commits

..

8 Commits

Author SHA1 Message Date
手瓜一十雪
0b8bf739e9 fix: event 2024-11-18 19:51:08 +08:00
手瓜一十雪
0222664db8 fix: type
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 14m48s
Build Action / Build-Shell (push) Failing after 14m43s
2024-11-17 16:02:25 +08:00
手瓜一十雪
a88792e452 docs: 没有参考故移除 2024-11-17 16:01:44 +08:00
手瓜一十雪
ad45400742 docs: 调整更新速度与Packet重构 2024-11-17 15:57:21 +08:00
手瓜一十雪
53e5ba03be fix 2024-11-17 15:56:48 +08:00
手瓜一十雪
b587d6b91d fix: (SetGroupSign) BaseAction-->GetPacketStatusDepends 2024-11-17 15:37:10 +08:00
手瓜一十雪
5e750d4ee9 feat: uploadQunAlbum未测试
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 2m40s
Build Action / Build-Shell (push) Failing after 2m38s
2024-11-17 13:39:57 +08:00
Mlikiowa
50fb32f81c release: v4.1.5 2024-11-17 03:39:17 +00:00
9 changed files with 154 additions and 29 deletions

View File

@@ -8,7 +8,7 @@
## 欢迎回家
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
## 碎碎叨叨
## 特性介绍
- [x] **安装简单**:就算是笨蛋也能使用
- [x] **性能友好**:就算是低内存也能使用
- [x] **接口丰富**:就算是没有也能使用
@@ -26,19 +26,19 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
[Cloudflare.HKServer](https://napcat.napneko.icu/)
[Github.IO](https://napneko.github.io/)
[Cloudflare.Pages](https://napneko.pages.dev/)
[Server.China](https://napneko.com/)
[Server.Other](https://napcat.cyou/)
[Github.IO](https://napneko.github.io/)
## 回家旅途
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
## 感谢他们
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot)
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
感谢 Tencent Tdesign / Vue3 强力驱动 NapCat.WebUi
@@ -46,6 +46,14 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
不过最最重要的 还是需要感谢屏幕前的你哦~
---
## 延缓Native模块与NapCat对新版QQ适配
为未来持续与高效的使用Native模块 模块代码转为完全非Git仓库的本地保存源码 并进行相关重构
同时为了保证稳定 NapCat 本体通常会在3 Week+的周期进行新版本适配
因此此时推荐使用release指定版本
## 开源附加
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经仓库主作者授权二次分发或基于 NapCat 代码开发。**

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ",
"slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现",
"version": "4.1.3",
"version": "4.1.5",
"icon": "./logo.png",
"authors": [
{

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.1.3",
"version": "4.1.5",
"scripts": {
"build:framework": "npm run build:webui && vite build --mode framework",
"build:shell": "npm run build:webui && vite build --mode shell",

View File

@@ -234,25 +234,33 @@ export class NTEventWrapper {
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
this.createListenerFunction(ListenerMainName);
this.createEventFunction(serviceAndMethod)!(...(args))
.then((eventResult: any) => {
retEvent = eventResult;
if (!checkerEvent(retEvent) && timeoutRef.hasRef()) {
clearTimeout(timeoutRef);
reject(
new Error(
'EventChecker Failed: NTEvent serviceAndMethod:' +
serviceAndMethod +
' ListenerName:' +
listenerAndMethod +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n',
),
);
}
let eventResult = this.createEventFunction(serviceAndMethod)!(...(args));
const eventRetHandle = (eventData: any) => {
retEvent = eventData;
if (!checkerEvent(retEvent) && timeoutRef.hasRef()) {
clearTimeout(timeoutRef);
reject(
new Error(
'EventChecker Failed: NTEvent serviceAndMethod:' +
serviceAndMethod +
' ListenerName:' +
listenerAndMethod +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n',
),
);
}
}
if (eventResult instanceof Promise) {
eventResult.then((eventResult: any) => {
eventRetHandle(eventResult);
})
.catch(reject);
.catch(reject);
} else {
eventRetHandle(eventResult);
}
},
);
}

View File

@@ -1 +1 @@
export const napCatVersion = '4.1.3';
export const napCatVersion = '4.1.5';

View File

@@ -8,6 +8,9 @@ import {
WebHonorType,
} from '@/core';
import { NapCatCore } from '..';
import { createReadStream, readFileSync, statSync } from 'node:fs';
import { createHash } from 'node:crypto';
import { basename } from 'node:path';
export class NTQQWebApi {
context: InstanceContext;
@@ -303,4 +306,110 @@ export class NTQQWebApi {
}
return (hash & 0x7FFFFFFF).toString();
}
async createQunAlbumSession(gc: string, sAlbumID: string, sAlbumName: string, path: string, skey: string, pskey: string, uin: string) {
const img = readFileSync(path);
const img_md5 = createHash('md5').update(img).digest('hex');
const img_size = img.length;
const img_name = basename(path);
const time = Math.floor(Date.now() / 1000);
const GTK = this.getBknFromSKey(pskey);
const cookie = `p_uin=${uin}; p_skey=${pskey}; skey=${skey}; uin=${uin}`;
const body = {
control_req: [{
uin: uin,
token: {
type: 4,
data: pskey,
appid: 5
},
appid: "qun",
checksum: img_md5,
check_type: 0,
file_len: img_size,
env: {
refer: "qzone",
deviceInfo: "h5"
},
model: 0,
biz_req: {
sPicTitle: img_name,
sPicDesc: "",
sAlbumName: sAlbumName,
sAlbumID: sAlbumID,
iAlbumTypeID: 0,
iBitmap: 0,
iUploadType: 0,
iUpPicType: 0,
iBatchID: time,
sPicPath: "",
iPicWidth: 0,
iPicHight: 0,
iWaterType: 0,
iDistinctUse: 0,
iNeedFeeds: 1,
iUploadTime: time,
mapExt: {
appid: "qun",
userid: gc
}
},
session: "",
asy_upload: 0,
cmd: "FileUpload"
}]
};
const api = `https://h5.qzone.qq.com/webapp/json/sliceUpload/FileBatchControl/${img_md5}?g_tk=${GTK}`;
const post = await RequestUtil.HttpGetJson(api, 'POST', body, {
"Cookie": cookie,
"Content-Type": "application/json"
});
return post;
}
async uploadQunAlbumSlice(path: string, session: string, skey: string, pskey: string, uin: string, slice_size: number) {
const img_size = statSync(path).size;
const img_name = basename(path);
let seq = 0;
let offset = 0;
const GTK = this.getBknFromSKey(pskey);
const cookie = `p_uin=${uin}; p_skey=${pskey}; skey=${skey}; uin=${uin}`;
const stream = createReadStream(path, { highWaterMark: slice_size });
for await (const chunk of stream) {
const end = Math.min(offset + chunk.length, img_size);
const boundary = `----WebKitFormBoundary${Math.random().toString(36).substring(2)}`;
const formData = await RequestUtil.createFormData(boundary, path);
const api = `https://h5.qzone.qq.com/webapp/json/sliceUpload/FileUpload?seq=${seq}&retry=0&offset=${offset}&end=${end}&total=${img_size}&type=form&g_tk=${GTK}`;
const body = {
uin: uin,
appid: "qun",
session: session,
offset: offset,
data: formData,
checksum: "",
check_type: 0,
retry: 0,
seq: seq,
end: end,
cmd: "FileUpload",
slice_size: slice_size,
"biz_req.iUploadType": 0
};
const post = await RequestUtil.HttpGetJson(api, 'POST', body, {
"Cookie": cookie,
"Content-Type": `multipart/form-data; boundary=${boundary}`
});
offset += chunk.length;
seq++;
}
}
async uploadQunAlbum(path: string, albumId: string, group: string, skey: string, pskey: string, uin: string) {
const session = (await this.createQunAlbumSession(group, albumId, group, path, skey, pskey, uin) as { data: { session: string } }).data.session;
return await this.uploadQunAlbumSlice(path, session, skey, pskey, uin, 1024 * 1024);
}
}

View File

@@ -150,7 +150,7 @@ export interface NodeIQQNTWrapperSession {
nodeIKernelSessionListener: NodeIKernelSessionListener,
): void;
startNT(n: 0): void;
startNT(session: number): void;
startNT(): void;

View File

@@ -1,4 +1,4 @@
import BaseAction from '../BaseAction';
import { GetPacketStatusDepends } from '../packet/GetPacketStatus';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
@@ -12,7 +12,7 @@ const SchemaData = {
type Payload = FromSchema<typeof SchemaData>;
export class SetGroupSign extends BaseAction<Payload, any> {
export class SetGroupSign extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.SetGroupSign;
payloadSchema = SchemaData;

View File

@@ -28,7 +28,7 @@ export class GetGroupRootFiles extends BaseAction<Payload, {
startIndex: 0,
sortOrder: 2,
showOnlinedocFolder: 0,
}).catch(() => []);
});
return {
files: ret.filter(item => item.fileInfo)