mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3de5438139 | ||
![]() |
c4b5f34271 | ||
![]() |
22d3ac33a2 | ||
![]() |
2e5dd6535a | ||
![]() |
eac58a2a50 | ||
![]() |
e939ec0e52 | ||
![]() |
5b17a14a2a | ||
![]() |
8fb8c888f5 | ||
![]() |
4a2884509e | ||
![]() |
e295235a89 | ||
![]() |
ef515a38d0 | ||
![]() |
02cff040e3 | ||
![]() |
bb0f65a52d | ||
![]() |
d51d6a5cc1 | ||
![]() |
eb99379a79 | ||
![]() |
388eb57d0d | ||
![]() |
0b8131392a | ||
![]() |
229efbd006 | ||
![]() |
a482fa3a8d | ||
![]() |
6cf047af39 |
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "4.2.16",
|
"version": "4.2.22",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "4.2.16",
|
"version": "4.2.22",
|
||||||
"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",
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { stat } from 'fs/promises';
|
import { stat } from 'fs/promises';
|
||||||
import crypto, { randomUUID } from 'crypto';
|
import crypto, { randomUUID } from 'crypto';
|
||||||
import util from 'util';
|
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import * as fileType from 'file-type';
|
|
||||||
import { solveProblem } from '@/common/helper';
|
import { solveProblem } from '@/common/helper';
|
||||||
|
|
||||||
export interface HttpDownloadOptions {
|
export interface HttpDownloadOptions {
|
||||||
@@ -15,7 +13,6 @@ type Uri2LocalRes = {
|
|||||||
success: boolean,
|
success: boolean,
|
||||||
errMsg: string,
|
errMsg: string,
|
||||||
fileName: string,
|
fileName: string,
|
||||||
ext: string,
|
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,27 +70,6 @@ async function checkFile(path: string): Promise<void> {
|
|||||||
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
// 如果文件存在,则无需做任何事情,Promise 解决(resolve)自身
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function file2base64(path: string) {
|
|
||||||
const readFile = util.promisify(fs.readFile);
|
|
||||||
const result = {
|
|
||||||
err: '',
|
|
||||||
data: '',
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
await checkFileExist(path, 5000);
|
|
||||||
} catch (e: any) {
|
|
||||||
result.err = e.toString();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const data = await readFile(path);
|
|
||||||
result.data = data.toString('base64');
|
|
||||||
} catch (err: any) {
|
|
||||||
result.err = err.toString();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateFileMD5(filePath: string): Promise<string> {
|
export function calculateFileMD5(filePath: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 创建一个流式读取器
|
// 创建一个流式读取器
|
||||||
@@ -160,20 +136,6 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
|
|||||||
return Buffer.from(buffer);
|
return Buffer.from(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkFileV2(filePath: string) {
|
|
||||||
try {
|
|
||||||
const ext: string | undefined = (await fileType.fileTypeFromFile(filePath))?.ext;
|
|
||||||
if (ext) {
|
|
||||||
fs.renameSync(filePath, filePath + `.${ext}`);
|
|
||||||
filePath += `.${ext}`;
|
|
||||||
return { success: true, ext: ext, path: filePath };
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// log("获取文件类型失败", filePath,e.stack)
|
|
||||||
}
|
|
||||||
return { success: false, ext: '', path: filePath };
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum FileUriType {
|
export enum FileUriType {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Local = 1,
|
Local = 1,
|
||||||
@@ -213,63 +175,32 @@ export async function checkUriType(Uri: string) {
|
|||||||
return { Uri: Uri, Type: FileUriType.Unknown };
|
return { Uri: Uri, Type: FileUriType.Unknown };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function uri2local(dir: string, uri: string, filename: string | undefined = undefined): Promise<Uri2LocalRes> {
|
export async function uriToLocalFile(dir: string, uri: string): Promise<Uri2LocalRes> {
|
||||||
const { Uri: HandledUri, Type: UriType } = await checkUriType(uri);
|
const { Uri: HandledUri, Type: UriType } = await checkUriType(uri);
|
||||||
|
|
||||||
//解析失败
|
const filename = randomUUID();
|
||||||
const tempName = randomUUID();
|
const filePath = path.join(dir, filename);
|
||||||
if (!filename) filename = randomUUID();
|
|
||||||
|
|
||||||
//解析Http和Https协议
|
switch (UriType) {
|
||||||
if (UriType == FileUriType.Unknown) {
|
case FileUriType.Local:
|
||||||
return { success: false, errMsg: `未知文件类型, uri= ${uri}`, fileName: '', ext: '', path: '' };
|
const fileExt = path.extname(HandledUri);
|
||||||
}
|
const localFileName = path.basename(HandledUri, fileExt) + fileExt;
|
||||||
|
const tempFilePath = path.join(dir, filename + fileExt);
|
||||||
|
fs.copyFileSync(HandledUri, tempFilePath);
|
||||||
|
return { success: true, errMsg: '', fileName: localFileName, path: tempFilePath };
|
||||||
|
|
||||||
//解析File协议和本地文件
|
case FileUriType.Remote:
|
||||||
if (UriType == FileUriType.Local) {
|
const buffer = await httpDownload(HandledUri);
|
||||||
const fileExt = path.extname(HandledUri);
|
fs.writeFileSync(filePath, buffer, { flag: 'wx' });
|
||||||
let filename = path.basename(HandledUri, fileExt);
|
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
||||||
filename += fileExt;
|
|
||||||
//复制文件到临时文件并保持后缀
|
|
||||||
const filenameTemp = tempName + fileExt;
|
|
||||||
const filePath = path.join(dir, filenameTemp);
|
|
||||||
fs.copyFileSync(HandledUri, filePath);
|
|
||||||
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
|
|
||||||
}
|
|
||||||
|
|
||||||
//接下来都要有文件名
|
case FileUriType.Base64:
|
||||||
if (UriType == FileUriType.Remote) {
|
const base64 = HandledUri.replace(/^base64:\/\//, '');
|
||||||
const pathInfo = path.parse(decodeURIComponent(new URL(HandledUri).pathname));
|
const base64Buffer = Buffer.from(base64, 'base64');
|
||||||
if (pathInfo.name) {
|
fs.writeFileSync(filePath, base64Buffer, { flag: 'wx' });
|
||||||
const pathlen = 200 - dir.length - pathInfo.name.length;
|
return { success: true, errMsg: '', fileName: filename, path: filePath };
|
||||||
filename = pathlen > 0 ? pathInfo.name.substring(0, pathlen) : pathInfo.name.substring(pathInfo.name.length, pathInfo.name.length - 10);//过长截断
|
|
||||||
if (pathInfo.ext) {
|
|
||||||
filename += pathInfo.ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filename = filename.replace(/[/\\:*?"<>|]/g, '_');
|
|
||||||
const fileExt = path.extname(HandledUri).replace(/[/\\:*?"<>|]/g, '_').substring(0, 10);
|
|
||||||
const filePath = path.join(dir, tempName + fileExt);
|
|
||||||
const buffer = await httpDownload(HandledUri);
|
|
||||||
//没有文件就创建
|
|
||||||
fs.writeFileSync(filePath, buffer, { flag: 'wx' });
|
|
||||||
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
|
|
||||||
}
|
|
||||||
|
|
||||||
//解析Base64
|
default:
|
||||||
if (UriType == FileUriType.Base64) {
|
return { success: false, errMsg: `识别URL失败, uri= ${uri}`, fileName: '', path: '' };
|
||||||
const base64 = HandledUri.replace(/^base64:\/\//, '');
|
|
||||||
const buffer = Buffer.from(base64, 'base64');
|
|
||||||
let filePath = path.join(dir, filename);
|
|
||||||
let fileExt = '';
|
|
||||||
fs.writeFileSync(filePath, buffer);
|
|
||||||
const { success, ext, path: fileTypePath } = await checkFileV2(filePath);
|
|
||||||
if (success) {
|
|
||||||
filePath = fileTypePath;
|
|
||||||
fileExt = ext;
|
|
||||||
filename = filename + '.' + ext;
|
|
||||||
}
|
|
||||||
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
|
|
||||||
}
|
}
|
||||||
return { success: false, errMsg: `未知文件类型, uri= ${uri}`, fileName: '', ext: '', path: '' };
|
}
|
||||||
}
|
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '4.2.16';
|
export const napCatVersion = '4.2.22';
|
||||||
|
@@ -6,7 +6,6 @@ import {
|
|||||||
Peer,
|
Peer,
|
||||||
PicElement,
|
PicElement,
|
||||||
PicSubType,
|
PicSubType,
|
||||||
PicType,
|
|
||||||
RawMessage,
|
RawMessage,
|
||||||
SendFileElement,
|
SendFileElement,
|
||||||
SendPicElement,
|
SendPicElement,
|
||||||
@@ -17,7 +16,7 @@ import path from 'path';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import fsPromises from 'fs/promises';
|
import fsPromises from 'fs/promises';
|
||||||
import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
|
import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
|
||||||
import * as fileType from 'file-type';
|
import { fileTypeFromFile } from 'file-type';
|
||||||
import imageSize from 'image-size';
|
import imageSize from 'image-size';
|
||||||
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
||||||
import { RkeyManager } from '@/core/helper/rkey';
|
import { RkeyManager } from '@/core/helper/rkey';
|
||||||
@@ -41,7 +40,7 @@ export class NTQQFileApi {
|
|||||||
this.rkeyManager = new RkeyManager([
|
this.rkeyManager = new RkeyManager([
|
||||||
'https://rkey.napneko.icu/rkeys'
|
'https://rkey.napneko.icu/rkeys'
|
||||||
],
|
],
|
||||||
this.context.logger
|
this.context.logger
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ export class NTQQFileApi {
|
|||||||
|
|
||||||
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
||||||
const fileMd5 = await calculateFileMD5(filePath);
|
const fileMd5 = await calculateFileMD5(filePath);
|
||||||
const extOrEmpty = (await fileType.fileTypeFromFile(filePath))?.ext;
|
let extOrEmpty = await fileTypeFromFile(filePath).then(e => e?.ext ?? '').catch(e => '');
|
||||||
const ext = extOrEmpty ? `.${extOrEmpty}` : '';
|
const ext = extOrEmpty ? `.${extOrEmpty}` : '';
|
||||||
let fileName = `${path.basename(filePath)}`;
|
let fileName = `${path.basename(filePath)}`;
|
||||||
if (fileName.indexOf('.') === -1) {
|
if (fileName.indexOf('.') === -1) {
|
||||||
@@ -158,7 +157,7 @@ export class NTQQFileApi {
|
|||||||
|
|
||||||
let fileExt = 'mp4';
|
let fileExt = 'mp4';
|
||||||
try {
|
try {
|
||||||
const tempExt = (await fileType.fileTypeFromFile(filePath))?.ext;
|
const tempExt = (await fileTypeFromFile(filePath))?.ext;
|
||||||
if (tempExt) fileExt = tempExt;
|
if (tempExt) fileExt = tempExt;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.logError('获取文件类型失败', e);
|
this.context.logger.logError('获取文件类型失败', e);
|
||||||
@@ -306,18 +305,18 @@ export class NTQQFileApi {
|
|||||||
element.elementType === ElementType.FILE
|
element.elementType === ElementType.FILE
|
||||||
) {
|
) {
|
||||||
switch (element.elementType) {
|
switch (element.elementType) {
|
||||||
case ElementType.PIC:
|
case ElementType.PIC:
|
||||||
element.picElement!.sourcePath = elementResults[elementIndex];
|
element.picElement!.sourcePath = elementResults[elementIndex];
|
||||||
break;
|
break;
|
||||||
case ElementType.VIDEO:
|
case ElementType.VIDEO:
|
||||||
element.videoElement!.filePath = elementResults[elementIndex];
|
element.videoElement!.filePath = elementResults[elementIndex];
|
||||||
break;
|
break;
|
||||||
case ElementType.PTT:
|
case ElementType.PTT:
|
||||||
element.pttElement!.filePath = elementResults[elementIndex];
|
element.pttElement!.filePath = elementResults[elementIndex];
|
||||||
break;
|
break;
|
||||||
case ElementType.FILE:
|
case ElementType.FILE:
|
||||||
element.fileElement!.filePath = elementResults[elementIndex];
|
element.fileElement!.filePath = elementResults[elementIndex];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
elementIndex++;
|
elementIndex++;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@ import { ModifyProfileParams, User, UserDetailSource } from '@/core/types';
|
|||||||
import { RequestUtil } from '@/common/request';
|
import { RequestUtil } from '@/common/request';
|
||||||
import { InstanceContext, NapCatCore, ProfileBizType } from '..';
|
import { InstanceContext, NapCatCore, ProfileBizType } from '..';
|
||||||
import { solveAsyncProblem } from '@/common/helper';
|
import { solveAsyncProblem } from '@/common/helper';
|
||||||
|
import { promisify } from 'node:util';
|
||||||
|
import { LRUCache } from '@/common/lru-cache';
|
||||||
|
|
||||||
export class NTQQUserApi {
|
export class NTQQUserApi {
|
||||||
context: InstanceContext;
|
context: InstanceContext;
|
||||||
@@ -11,13 +13,6 @@ export class NTQQUserApi {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
//self_tind格式
|
|
||||||
async createUidFromTinyId(tinyId: string) {
|
|
||||||
return this.context.session.getMsgService().createUidFromTinyId(this.core.selfInfo.uin, tinyId);
|
|
||||||
}
|
|
||||||
async getStatusByUid(uid: string) {
|
|
||||||
return this.context.session.getProfileService().getStatus(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCoreAndBaseInfo(uids: string[]) {
|
async getCoreAndBaseInfo(uids: string[]) {
|
||||||
return await this.core.eventWrapper.callNoListenerEvent(
|
return await this.core.eventWrapper.callNoListenerEvent(
|
||||||
@@ -26,7 +21,7 @@ export class NTQQUserApi {
|
|||||||
uids,
|
uids,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认获取自己的 type = 2 获取别人 type = 1
|
// 默认获取自己的 type = 2 获取别人 type = 1
|
||||||
async getProfileLike(uid: string, start: number, count: number, type: number = 2) {
|
async getProfileLike(uid: string, start: number, count: number, type: number = 2) {
|
||||||
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
||||||
@@ -99,7 +94,7 @@ export class NTQQUserApi {
|
|||||||
};
|
};
|
||||||
return RetUser;
|
return RetUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserDetailInfo(uid: string): Promise<User> {
|
async getUserDetailInfo(uid: string): Promise<User> {
|
||||||
let retUser = await solveAsyncProblem(async (uid) => this.fetchUserDetailInfo(uid, UserDetailSource.KDB), uid);
|
let retUser = await solveAsyncProblem(async (uid) => this.fetchUserDetailInfo(uid, UserDetailSource.KDB), uid);
|
||||||
if (retUser && retUser.uin !== '0') {
|
if (retUser && retUser.uin !== '0') {
|
||||||
@@ -170,35 +165,51 @@ export class NTQQUserApi {
|
|||||||
if (!skey) {
|
if (!skey) {
|
||||||
throw new Error('SKey is Empty');
|
throw new Error('SKey is Empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
return skey;
|
return skey;
|
||||||
}
|
}
|
||||||
|
|
||||||
//后期改成流水线处理
|
|
||||||
async getUidByUinV2(Uin: string) {
|
async getUidByUinV2(Uin: string) {
|
||||||
let uid = (await this.context.session.getGroupService().getUidByUins([Uin])).uids.get(Uin);
|
if (!Uin) {
|
||||||
if (uid) return uid;
|
return '';
|
||||||
uid = (await this.context.session.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])).get(Uin);
|
}
|
||||||
if (uid) return uid;
|
const services = [
|
||||||
uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
|
() => this.context.session.getUixConvertService().getUid([Uin]).then((data) => data.uidInfo.get(Uin)).catch(() => undefined),
|
||||||
if (uid) return uid;
|
() => promisify<string, string[], Map<string, string>>
|
||||||
const unverifiedUid = (await this.getUserDetailInfoByUin(Uin)).detail.uid;//从QQ Native 特殊转换
|
(this.context.session.getProfileService().getUidByUin)('FriendsServiceImpl', [Uin]).then((data) => data.get(Uin)).catch(() => undefined),
|
||||||
if (unverifiedUid.indexOf('*') == -1) uid = unverifiedUid;
|
() => this.context.session.getGroupService().getUidByUins([Uin]).then((data) => data.uids.get(Uin)).catch(() => undefined),
|
||||||
//if (uid) return uid;
|
() => this.getUserDetailInfoByUin(Uin).then((data) => data.detail.uid).catch(() => undefined),
|
||||||
return uid;
|
];
|
||||||
|
let uid: string | undefined = undefined;
|
||||||
|
for (const service of services) {
|
||||||
|
uid = await service();
|
||||||
|
if (uid && uid.indexOf('*') == -1 && uid !== '') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uid ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
//后期改成流水线处理
|
|
||||||
async getUinByUidV2(Uid: string) {
|
async getUinByUidV2(Uid: string) {
|
||||||
let uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
|
if (!Uid) {
|
||||||
if (uin && uin !== '0') return uin;
|
return '0';
|
||||||
uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
|
}
|
||||||
if (uin && uin !== '0') return uin;
|
const services = [
|
||||||
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
|
() => this.context.session.getUixConvertService().getUin([Uid]).then((data) => data.uinInfo.get(Uid)).catch(() => undefined),
|
||||||
if (uin && uin !== '0') return uin;
|
() => this.context.session.getGroupService().getUinByUids([Uid]).then((data) => data.uins.get(Uid)).catch(() => undefined),
|
||||||
uin = (await this.core.apis.FriendApi.getBuddyIdMap(true)).getKey(Uid);
|
() => promisify<string, string[], Map<string, string>>
|
||||||
if (uin && uin !== '0') return uin;
|
(this.context.session.getProfileService().getUinByUid)('FriendsServiceImpl', [Uid]).then((data) => data.get(Uid)).catch(() => undefined),
|
||||||
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
|
() => this.core.apis.FriendApi.getBuddyIdMap(true).then((data) => data.getKey(Uid)).catch(() => undefined),
|
||||||
return uin;
|
() => this.getUserDetailInfo(Uid).then((data) => data.uin).catch(() => undefined),
|
||||||
|
];
|
||||||
|
let uin: string | undefined = undefined;
|
||||||
|
for (const service of services) {
|
||||||
|
uin = await service();
|
||||||
|
if (uin && uin !== '0' && uin !== '') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uin ?? '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecentContactListSnapShot(count: number) {
|
async getRecentContactListSnapShot(count: number) {
|
||||||
|
6
src/core/external/appid.json
vendored
6
src/core/external/appid.json
vendored
@@ -98,5 +98,9 @@
|
|||||||
"6.9.61-29927": {
|
"6.9.61-29927": {
|
||||||
"appid": 537255836,
|
"appid": 537255836,
|
||||||
"qua": "V1_MAC_NQ_6.9.61_29927_GW_B"
|
"qua": "V1_MAC_NQ_6.9.61_29927_GW_B"
|
||||||
|
},
|
||||||
|
"9.9.17-30366": {
|
||||||
|
"appid": 537258389,
|
||||||
|
"qua": "V1_WIN_NQ_9.9.17_30366_GW_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/core/external/offset.json
vendored
6
src/core/external/offset.json
vendored
@@ -102,5 +102,9 @@
|
|||||||
"6.9.61-29927-arm64": {
|
"6.9.61-29927-arm64": {
|
||||||
"send": "4038740",
|
"send": "4038740",
|
||||||
"recv": "403AF58"
|
"recv": "403AF58"
|
||||||
|
},
|
||||||
|
"9.9.17-30366-x64": {
|
||||||
|
"send": "39AB0B0",
|
||||||
|
"recv": "39AF4E4"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
import * as fileType from 'file-type';
|
import { fileTypeFromFile } from 'file-type';
|
||||||
import { PicType } from '../types';
|
import { PicType } from '../types';
|
||||||
export async function getFileTypeForSendType(picPath: string): Promise<PicType> {
|
export async function getFileTypeForSendType(picPath: string): Promise<PicType> {
|
||||||
const fileTypeResult = (await fileType.fileTypeFromFile(picPath))?.ext ?? 'jpg';
|
const fileTypeResult = (await fileTypeFromFile(picPath))?.ext ?? 'jpg';
|
||||||
const picTypeMap: { [key: string]: PicType } = {
|
const picTypeMap: { [key: string]: PicType } = {
|
||||||
//'webp': PicType.NEWPIC_WEBP,
|
//'webp': PicType.NEWPIC_WEBP,
|
||||||
'gif': PicType.NEWPIC_GIF,
|
'gif': PicType.NEWPIC_GIF,
|
||||||
|
@@ -187,11 +187,11 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
destroyGroup(groupCode: string): void;
|
destroyGroup(groupCode: string): void;
|
||||||
|
|
||||||
getSingleScreenNotifies(doubted: boolean, start_seq: string, num: number): Promise<GeneralCallResult>;
|
getSingleScreenNotifies(doubt: boolean, startSeq: string, count: number): Promise<GeneralCallResult>;
|
||||||
|
|
||||||
clearGroupNotifies(groupCode: string): void;
|
clearGroupNotifies(groupCode: string): void;
|
||||||
|
|
||||||
getGroupNotifiesUnreadCount(unknown: boolean): Promise<GeneralCallResult>;
|
getGroupNotifiesUnreadCount(doubt: boolean): Promise<GeneralCallResult>;
|
||||||
|
|
||||||
clearGroupNotifiesUnreadCount(doubt: boolean): void;
|
clearGroupNotifiesUnreadCount(doubt: boolean): void;
|
||||||
|
|
||||||
|
@@ -4,14 +4,14 @@ import { GeneralCallResult } from '@/core/services/common';
|
|||||||
|
|
||||||
export interface NodeIKernelProfileService {
|
export interface NodeIKernelProfileService {
|
||||||
getOtherFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
getOtherFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
||||||
|
|
||||||
getVasInfo(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
getVasInfo(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
||||||
|
|
||||||
getRelationFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
getRelationFlag(callfrom: string, uids: string[]): Promise<Map<string, any>>;
|
||||||
|
|
||||||
getUidByUin(callfrom: string, uin: Array<string>): Promise<Map<string, string>>;
|
getUidByUin(callfrom: string, uin: Array<string>): Map<string, string>;
|
||||||
|
|
||||||
getUinByUid(callfrom: string, uid: Array<string>): Promise<Map<string, string>>;
|
getUinByUid(callfrom: string, uid: Array<string>): Map<string, string>;
|
||||||
|
|
||||||
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>;
|
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>;
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@ export interface TextElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FaceElement {
|
export interface FaceElement {
|
||||||
|
pokeType?: number;
|
||||||
faceIndex: number;
|
faceIndex: number;
|
||||||
faceType: FaceType;
|
faceType: FaceType;
|
||||||
faceText?: string;
|
faceText?: string;
|
||||||
|
@@ -2,32 +2,44 @@ import { GroupNotifyMsgStatus } from '@/core';
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
|
|
||||||
interface OB11GroupRequestNotify {
|
interface Notify {
|
||||||
group_id: number,
|
request_id: string;
|
||||||
user_id: number,
|
invitor_uin: number;
|
||||||
flag: string
|
invitor_nick?: string;
|
||||||
|
group_id?: number;
|
||||||
|
group_name?: string;
|
||||||
|
checked: boolean;
|
||||||
|
requester_nick?: string;
|
||||||
|
actor: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class GetGroupAddRequest extends OneBotAction<null, OB11GroupRequestNotify[] | null> {
|
export default class GetGroupAddRequest extends OneBotAction<null, Notify[] | null> {
|
||||||
actionName = ActionName.GetGroupIgnoreAddRequest;
|
actionName = ActionName.GetGroupIgnoreAddRequest;
|
||||||
|
|
||||||
async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
|
async _handle(payload: null): Promise<Notify[] | null> {
|
||||||
const ignoredNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(true, 10);
|
const NTQQUserApi = this.core.apis.UserApi;
|
||||||
const retData: any = {
|
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||||
join_requests: await Promise.all(
|
const ignoredNotifies = await NTQQGroupApi.getSingleScreenNotifies(true, 10);
|
||||||
ignoredNotifies
|
const retData: Notify[] = [];
|
||||||
.filter(notify => notify.type === 7)
|
|
||||||
.map(async SSNotify => ({
|
const notifyPromises = ignoredNotifies
|
||||||
request_id: SSNotify.group.groupCode + '|' + SSNotify.seq + '|' + SSNotify.type,
|
.filter(notify => notify.type === 7)
|
||||||
requester_uin: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1?.uid),
|
.map(async SSNotify => {
|
||||||
requester_nick: SSNotify.user1?.nickName,
|
const invitorUin = SSNotify.user1?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user1.uid) : 0;
|
||||||
group_id: SSNotify.group?.groupCode,
|
const actorUin = SSNotify.user2?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user2.uid) : 0;
|
||||||
group_name: SSNotify.group?.groupName,
|
retData.push({
|
||||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
request_id: `${SSNotify.group.groupCode}|${SSNotify.seq}|${SSNotify.type}`,
|
||||||
actor: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
invitor_uin: invitorUin,
|
||||||
}))),
|
requester_nick: SSNotify.user1?.nickName,
|
||||||
};
|
group_id: +SSNotify.group?.groupCode,
|
||||||
|
group_name: SSNotify.group?.groupName,
|
||||||
|
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||||
|
actor: actorUin,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(notifyPromises);
|
||||||
|
|
||||||
return retData;
|
return retData;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { checkFileExist, uri2local } from '@/common/file';
|
import { checkFileExist, uriToLocalFile } from '@/common/file';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ export class OCRImage extends OneBotAction<Payload, any> {
|
|||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
|
const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.image));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`OCR ${payload.image}失败,image字段可能格式不正确`);
|
throw new Error(`OCR ${payload.image}失败,image字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { checkFileExist, uri2local } from '@/common/file';
|
import { checkFileExist, uriToLocalFile } from '@/common/file';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
const SchemaData = Type.Object({
|
const SchemaData = Type.Object({
|
||||||
@@ -14,7 +14,7 @@ export default class SetAvatar extends OneBotAction<Payload, null> {
|
|||||||
actionName = ActionName.SetQQAvatar;
|
actionName = ActionName.SetQQAvatar;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { checkFileExist, uri2local } from '@/common/file';
|
import { checkFileExist, uriToLocalFile } from '@/common/file';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { unlink } from 'node:fs/promises';
|
import { unlink } from 'node:fs/promises';
|
||||||
@@ -28,7 +28,7 @@ export class SendGroupNotice extends OneBotAction<Payload, null> {
|
|||||||
const {
|
const {
|
||||||
path,
|
path,
|
||||||
success,
|
success,
|
||||||
} = (await uri2local(this.core.NapCatTempPath, payload.image));
|
} = (await uriToLocalFile(this.core.NapCatTempPath, payload.image));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`群公告${payload.image}设置失败,image字段可能格式不正确`);
|
throw new Error(`群公告${payload.image}设置失败,image字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { checkFileExistV2, uri2local } from '@/common/file';
|
import { checkFileExistV2, uriToLocalFile } from '@/common/file';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
const SchemaData = Type.Object({
|
const SchemaData = Type.Object({
|
||||||
@@ -15,7 +15,7 @@ export default class SetGroupPortrait extends OneBotAction<Payload, any> {
|
|||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<any> {
|
async _handle(payload: Payload): Promise<any> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType, Peer } from '@/core/types';
|
import { ChatType, Peer } from '@/core/types';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { uri2local } from '@/common/file';
|
import { uriToLocalFile } from '@/common/file';
|
||||||
import { SendMessageContext } from '@/onebot/api';
|
import { SendMessageContext } from '@/onebot/api';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null>
|
|||||||
if (fs.existsSync(file)) {
|
if (fs.existsSync(file)) {
|
||||||
file = `file://${file}`;
|
file = `file://${file}`;
|
||||||
}
|
}
|
||||||
const downloadResult = await uri2local(this.core.NapCatTempPath, file);
|
const downloadResult = await uriToLocalFile(this.core.NapCatTempPath, file);
|
||||||
const peer: Peer = {
|
const peer: Peer = {
|
||||||
chatType: ChatType.KCHATTYPEGROUP,
|
chatType: ChatType.KCHATTYPEGROUP,
|
||||||
peerUid: payload.group_id.toString(),
|
peerUid: payload.group_id.toString(),
|
||||||
|
@@ -2,7 +2,7 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { ChatType, Peer, SendFileElement } from '@/core/types';
|
import { ChatType, Peer, SendFileElement } from '@/core/types';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { uri2local } from '@/common/file';
|
import { uriToLocalFile } from '@/common/file';
|
||||||
import { SendMessageContext } from '@/onebot/api';
|
import { SendMessageContext } from '@/onebot/api';
|
||||||
import { ContextMode, createContext } from '@/onebot/action/msg/SendMsg';
|
import { ContextMode, createContext } from '@/onebot/action/msg/SendMsg';
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
@@ -36,7 +36,7 @@ export default class GoCQHTTPUploadPrivateFile extends OneBotAction<Payload, nul
|
|||||||
if (fs.existsSync(file)) {
|
if (fs.existsSync(file)) {
|
||||||
file = `file://${file}`;
|
file = `file://${file}`;
|
||||||
}
|
}
|
||||||
const downloadResult = await uri2local(this.core.NapCatTempPath, file);
|
const downloadResult = await uriToLocalFile(this.core.NapCatTempPath, file);
|
||||||
if (!downloadResult.success) {
|
if (!downloadResult.success) {
|
||||||
throw new Error(downloadResult.errMsg);
|
throw new Error(downloadResult.errMsg);
|
||||||
}
|
}
|
||||||
|
@@ -1,26 +1,55 @@
|
|||||||
import { GroupNotifyMsgStatus } from '@/core';
|
import { GroupNotifyMsgStatus } from '@/core';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
export class GetGroupIgnoredNotifies extends OneBotAction<void, any> {
|
|
||||||
actionName = ActionName.GetGroupIgnoredNotifies;
|
|
||||||
|
|
||||||
async _handle(payload: void) {
|
interface Notify {
|
||||||
const ignoredNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(true, 10);
|
request_id: string;
|
||||||
const retData: any = {
|
invitor_uin: number;
|
||||||
join_requests: await Promise.all(
|
invitor_nick?: string;
|
||||||
ignoredNotifies
|
group_id?: number;
|
||||||
.filter(notify => notify.type === 7)
|
group_name?: string;
|
||||||
.map(async SSNotify => ({
|
checked: boolean;
|
||||||
request_id: SSNotify.group.groupCode + '|' + SSNotify.seq + '|' + SSNotify.type,
|
requester_nick?: string;
|
||||||
requester_uin: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1?.uid),
|
actor: number;
|
||||||
requester_nick: SSNotify.user1?.nickName,
|
}
|
||||||
group_id: SSNotify.group?.groupCode,
|
interface RetData {
|
||||||
group_name: SSNotify.group?.groupName,
|
InvitedRequest: Notify[];
|
||||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
join_requests: Notify[];
|
||||||
actor: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
}
|
||||||
}))),
|
|
||||||
};
|
export class GetGroupIgnoredNotifies extends OneBotAction<void, RetData> {
|
||||||
|
actionName = ActionName.GetGroupSystemMsg;
|
||||||
|
|
||||||
|
async _handle(): Promise<RetData> {
|
||||||
|
const NTQQUserApi = this.core.apis.UserApi;
|
||||||
|
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||||
|
const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(false, 50);
|
||||||
|
const retData: RetData = { InvitedRequest: [], join_requests: [] };
|
||||||
|
|
||||||
|
const notifyPromises = SingleScreenNotifies.map(async (SSNotify) => {
|
||||||
|
const invitorUin = SSNotify.user1?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user1.uid) : 0;
|
||||||
|
const actorUin = SSNotify.user2?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user2.uid) : 0;
|
||||||
|
|
||||||
|
const commonData = {
|
||||||
|
request_id: `${SSNotify.group.groupCode}|${SSNotify.seq}|${SSNotify.type}`,
|
||||||
|
invitor_uin: invitorUin,
|
||||||
|
invitor_nick: SSNotify.user1?.nickName,
|
||||||
|
group_id: +SSNotify.group?.groupCode,
|
||||||
|
group_name: SSNotify.group?.groupName,
|
||||||
|
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||||
|
actor: actorUin,
|
||||||
|
requester_nick: SSNotify.user1?.nickName,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (SSNotify.type === 1) {
|
||||||
|
retData.InvitedRequest.push(commonData);
|
||||||
|
} else if (SSNotify.type === 7) {
|
||||||
|
retData.join_requests.push(commonData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(notifyPromises);
|
||||||
|
|
||||||
return retData;
|
return retData;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -21,7 +21,8 @@ export class GetGroupMemberList extends OneBotAction<Payload, OB11GroupMember[]>
|
|||||||
const memberCache = this.core.apis.GroupApi.groupMemberCache;
|
const memberCache = this.core.apis.GroupApi.groupMemberCache;
|
||||||
let groupMembers = memberCache.get(groupIdStr);
|
let groupMembers = memberCache.get(groupIdStr);
|
||||||
if (noCache || !groupMembers) {
|
if (noCache || !groupMembers) {
|
||||||
await this.core.apis.GroupApi.refreshGroupMemberCache(groupIdStr);
|
this.core.apis.GroupApi.refreshGroupMemberCache(groupIdStr).then().catch();
|
||||||
|
//下次刷新
|
||||||
groupMembers = memberCache.get(groupIdStr);
|
groupMembers = memberCache.get(groupIdStr);
|
||||||
if (!groupMembers) {
|
if (!groupMembers) {
|
||||||
throw new Error(`Failed to get group member list for group ${groupIdStr}`);
|
throw new Error(`Failed to get group member list for group ${groupIdStr}`);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
|
||||||
import { uri2local } from "@/common/file";
|
import { uriToLocalFile } from "@/common/file";
|
||||||
import { ChatType, Peer } from "@/core";
|
import { ChatType, Peer } from "@/core";
|
||||||
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
|
||||||
import { Static, Type } from '@sinclair/typebox';
|
import { Static, Type } from '@sinclair/typebox';
|
||||||
@@ -23,7 +23,7 @@ export class SendGroupAiRecord extends GetPacketStatusDepends<Payload, {
|
|||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
||||||
const url = await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
const url = await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
||||||
const { path, errMsg, success } = (await uri2local(this.core.NapCatTempPath, url));
|
const { path, errMsg, success } = (await uriToLocalFile(this.core.NapCatTempPath, url));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
|
@@ -1,38 +1,63 @@
|
|||||||
import { GroupNotifyMsgStatus } from '@/core';
|
import { GroupNotifyMsgStatus } from '@/core';
|
||||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||||
import { ActionName } from '@/onebot/action/router';
|
import { ActionName } from '@/onebot/action/router';
|
||||||
export class GetGroupSystemMsg extends OneBotAction<void, any> {
|
|
||||||
|
interface Notify {
|
||||||
|
request_id: string;
|
||||||
|
invitor_uin: number;
|
||||||
|
invitor_nick?: string;
|
||||||
|
group_id?: number;
|
||||||
|
group_name?: string;
|
||||||
|
checked: boolean;
|
||||||
|
actor: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JoinRequest extends Notify {
|
||||||
|
requester_nick?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RetData {
|
||||||
|
InvitedRequest: Notify[];
|
||||||
|
join_requests: JoinRequest[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GetGroupSystemMsg extends OneBotAction<void, RetData> {
|
||||||
actionName = ActionName.GetGroupSystemMsg;
|
actionName = ActionName.GetGroupSystemMsg;
|
||||||
|
|
||||||
async _handle() {
|
async _handle(): Promise<RetData> {
|
||||||
const NTQQUserApi = this.core.apis.UserApi;
|
const NTQQUserApi = this.core.apis.UserApi;
|
||||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||||
// 默认10条 该api未完整实现 包括响应数据规范化 类型规范化
|
const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(false, 50);
|
||||||
const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(false, 10);
|
const retData: RetData = { InvitedRequest: [], join_requests: [] };
|
||||||
const retData: any = { InvitedRequest: [], join_requests: [] };
|
|
||||||
for (const SSNotify of SingleScreenNotifies) {
|
const notifyPromises = SingleScreenNotifies.map(async (SSNotify) => {
|
||||||
if (SSNotify.type == 1) {
|
const invitorUin = SSNotify.user1?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user1.uid) : 0;
|
||||||
|
const actorUin = SSNotify.user2?.uid ? +await NTQQUserApi.getUinByUidV2(SSNotify.user2.uid) : 0;
|
||||||
|
|
||||||
|
if (SSNotify.type === 1) {
|
||||||
retData.InvitedRequest.push({
|
retData.InvitedRequest.push({
|
||||||
request_id: SSNotify.group.groupCode + '|' + SSNotify.seq + '|' + SSNotify.type,
|
request_id: `${SSNotify.group.groupCode}|${SSNotify.seq}|${SSNotify.type}`,
|
||||||
invitor_uin: await NTQQUserApi.getUinByUidV2(SSNotify.user1?.uid),
|
invitor_uin: invitorUin,
|
||||||
invitor_nick: SSNotify.user1?.nickName,
|
invitor_nick: SSNotify.user1?.nickName,
|
||||||
group_id: SSNotify.group?.groupCode,
|
group_id: +SSNotify.group?.groupCode,
|
||||||
group_name: SSNotify.group?.groupName,
|
group_name: SSNotify.group?.groupName,
|
||||||
checked: SSNotify.status === GroupNotifyMsgStatus.KUNHANDLE ? false : true,
|
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||||
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
actor: actorUin,
|
||||||
});
|
});
|
||||||
} else if (SSNotify.type == 7) {
|
} else if (SSNotify.type === 7) {
|
||||||
retData.join_requests.push({
|
retData.join_requests.push({
|
||||||
request_id: SSNotify.group.groupCode + '|' + SSNotify.seq + '|' + SSNotify.type,
|
request_id: `${SSNotify.group.groupCode}|${SSNotify.seq}|${SSNotify.type}`,
|
||||||
requester_uin: await NTQQUserApi.getUinByUidV2(SSNotify.user1?.uid),
|
invitor_uin: invitorUin,
|
||||||
requester_nick: SSNotify.user1?.nickName,
|
requester_nick: SSNotify.user1?.nickName,
|
||||||
group_id: SSNotify.group?.groupCode,
|
group_id: +SSNotify.group?.groupCode,
|
||||||
group_name: SSNotify.group?.groupName,
|
group_name: SSNotify.group?.groupName,
|
||||||
checked: SSNotify.status === GroupNotifyMsgStatus.KUNHANDLE ? false : true,
|
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||||
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
actor: actorUin,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
await Promise.all(notifyPromises);
|
||||||
|
|
||||||
return retData;
|
return retData;
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataTyp
|
|||||||
import { OB11Construct } from '@/onebot/helper/data';
|
import { OB11Construct } from '@/onebot/helper/data';
|
||||||
import { EventType } from '@/onebot/event/OneBotEvent';
|
import { EventType } from '@/onebot/event/OneBotEvent';
|
||||||
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
||||||
import { uri2local } from '@/common/file';
|
import { uriToLocalFile } from '@/common/file';
|
||||||
import { RequestUtil } from '@/common/request';
|
import { RequestUtil } from '@/common/request';
|
||||||
import fsPromise, { constants } from 'node:fs/promises';
|
import fsPromise, { constants } from 'node:fs/promises';
|
||||||
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
|
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
|
||||||
@@ -153,6 +153,17 @@ export class OneBotMsgApi {
|
|||||||
|
|
||||||
faceElement: async element => {
|
faceElement: async element => {
|
||||||
const faceIndex = element.faceIndex;
|
const faceIndex = element.faceIndex;
|
||||||
|
if (element.faceType == FaceType.Poke) {
|
||||||
|
return {
|
||||||
|
type: OB11MessageDataType.poke,
|
||||||
|
data: {
|
||||||
|
type: element?.pokeType?.toString() ?? '0',
|
||||||
|
id: faceIndex.toString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (faceIndex === FaceIndex.DICE) {
|
if (faceIndex === FaceIndex.DICE) {
|
||||||
return {
|
return {
|
||||||
type: OB11MessageDataType.dice,
|
type: OB11MessageDataType.dice,
|
||||||
@@ -514,7 +525,7 @@ export class OneBotMsgApi {
|
|||||||
|
|
||||||
let thumb = sendMsg.data.thumb;
|
let thumb = sendMsg.data.thumb;
|
||||||
if (thumb) {
|
if (thumb) {
|
||||||
const uri2LocalRes = await uri2local(this.core.NapCatTempPath, thumb);
|
const uri2LocalRes = await uriToLocalFile(this.core.NapCatTempPath, thumb);
|
||||||
if (uri2LocalRes.success) thumb = uri2LocalRes.path;
|
if (uri2LocalRes.success) thumb = uri2LocalRes.path;
|
||||||
}
|
}
|
||||||
return await this.core.apis.FileApi.createValidSendVideoElement(context, path, fileName, thumb);
|
return await this.core.apis.FileApi.createValidSendVideoElement(context, path, fileName, thumb);
|
||||||
@@ -932,7 +943,7 @@ export class OneBotMsgApi {
|
|||||||
{ data: inputdata }: OB11MessageFileBase,
|
{ data: inputdata }: OB11MessageFileBase,
|
||||||
{ deleteAfterSentFiles }: SendMessageContext,
|
{ deleteAfterSentFiles }: SendMessageContext,
|
||||||
) {
|
) {
|
||||||
const realUri = inputdata.url || inputdata.file || inputdata.path || '';
|
const realUri = inputdata.url ?? inputdata.file ?? inputdata.path ?? '';
|
||||||
if (realUri.length === 0) {
|
if (realUri.length === 0) {
|
||||||
this.core.context.logger.logError('文件消息缺少参数', inputdata);
|
this.core.context.logger.logError('文件消息缺少参数', inputdata);
|
||||||
throw Error('文件消息缺少参数');
|
throw Error('文件消息缺少参数');
|
||||||
@@ -942,7 +953,7 @@ export class OneBotMsgApi {
|
|||||||
fileName,
|
fileName,
|
||||||
errMsg,
|
errMsg,
|
||||||
success,
|
success,
|
||||||
} = (await uri2local(this.core.NapCatTempPath, realUri));
|
} = (await uriToLocalFile(this.core.NapCatTempPath, realUri));
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.core.context.logger.logError('文件下载失败', errMsg);
|
this.core.context.logger.logError('文件下载失败', errMsg);
|
||||||
|
@@ -405,8 +405,8 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.context.logger.logDebug(`收到邀请我加群通知:${notify}`);
|
this.context.logger.logDebug(`收到邀请我加群通知:${notify}`);
|
||||||
const groupInviteEvent = new OB11GroupRequestEvent(
|
const groupInviteEvent = new OB11GroupRequestEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(notify.group.groupCode),
|
+notify.group.groupCode,
|
||||||
parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user2.uid)),
|
+await this.core.apis.UserApi.getUinByUidV2(notify.user2.uid),
|
||||||
'invite',
|
'invite',
|
||||||
notify.postscript,
|
notify.postscript,
|
||||||
flag
|
flag
|
||||||
@@ -423,8 +423,8 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.context.logger.logDebug(`收到群员邀请加群通知:${notify}`);
|
this.context.logger.logDebug(`收到群员邀请加群通知:${notify}`);
|
||||||
const groupInviteEvent = new OB11GroupRequestEvent(
|
const groupInviteEvent = new OB11GroupRequestEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(notify.group.groupCode),
|
+notify.group.groupCode,
|
||||||
parseInt(await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid)),
|
+await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid),
|
||||||
'add',
|
'add',
|
||||||
notify.postscript,
|
notify.postscript,
|
||||||
flag
|
flag
|
||||||
@@ -571,6 +571,8 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async emitFriendRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
private async emitFriendRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||||
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
|
if (!operatorUid) return undefined;
|
||||||
return new OB11FriendRecallNoticeEvent(
|
return new OB11FriendRecallNoticeEvent(
|
||||||
this.core,
|
this.core,
|
||||||
+message.senderUin,
|
+message.senderUin,
|
||||||
@@ -581,7 +583,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
if (!operatorUid) return undefined;
|
if (!operatorUid) return undefined;
|
||||||
const operatorId = message.senderUin ?? await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
const operatorId = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
||||||
return new OB11GroupRecallNoticeEvent(
|
return new OB11GroupRecallNoticeEvent(
|
||||||
this.core,
|
this.core,
|
||||||
+message.peerUin,
|
+message.peerUin,
|
||||||
|
@@ -71,6 +71,14 @@ export enum OB11MessageDataType {
|
|||||||
location = 'location'
|
location = 'location'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OB11MessagePoke {
|
||||||
|
type: OB11MessageDataType.poke;
|
||||||
|
data: {
|
||||||
|
type: string;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 商城表情消息接口定义
|
// 商城表情消息接口定义
|
||||||
export interface OB11MessageMFace {
|
export interface OB11MessageMFace {
|
||||||
type: OB11MessageDataType.mface;
|
type: OB11MessageDataType.mface;
|
||||||
@@ -247,7 +255,7 @@ export type OB11MessageData =
|
|||||||
OB11MessageAt | OB11MessageReply |
|
OB11MessageAt | OB11MessageReply |
|
||||||
OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo |
|
OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo |
|
||||||
OB11MessageNode | OB11MessageIdMusic | OB11MessageCustomMusic | OB11MessageJson |
|
OB11MessageNode | OB11MessageIdMusic | OB11MessageCustomMusic | OB11MessageJson |
|
||||||
OB11MessageDice | OB11MessageRPS | OB11MessageMarkdown | OB11MessageForward | OB11MessageContext;
|
OB11MessageDice | OB11MessageRPS | OB11MessageMarkdown | OB11MessageForward | OB11MessageContext | OB11MessagePoke;
|
||||||
|
|
||||||
// 发送消息接口定义
|
// 发送消息接口定义
|
||||||
export interface OB11PostSendMsg {
|
export interface OB11PostSendMsg {
|
||||||
|
Reference in New Issue
Block a user