Compare commits

...

33 Commits

Author SHA1 Message Date
手瓜一十雪
7ae8fd60c4 release: 2.5.1 2024-09-15 16:20:26 +08:00
手瓜一十雪
96b5bec5ab feat: revert 2024-09-15 16:04:10 +08:00
手瓜一十雪
d9851493df fix: #361 2024-09-15 15:51:23 +08:00
Alen
5548644aeb Merge pull request #373 from cnxysoft/test
fix: bugs
2024-09-15 15:37:09 +08:00
Alen
e3fcd91b2d Merge branch 'main' into test 2024-09-15 15:29:50 +08:00
手瓜一十雪
58cd38c4a8 chore: workflow 2024-09-15 15:20:44 +08:00
手瓜一十雪
f0e376d06b fix: 移除错误action 2024-09-15 14:55:18 +08:00
手瓜一十雪
3dc529edf4 fix: #369 2024-09-15 09:39:17 +08:00
手瓜一十雪
afcdd01c0d fix: typo 9.9.15-28060 2024-09-14 19:22:36 +08:00
手瓜一十雪
1164877e9a Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-09-14 19:10:34 +08:00
手瓜一十雪
fe92a449ba feat: 准备适配9.9.15-28060版本 2024-09-14 19:10:17 +08:00
Alen
401b0e2bd0 fix: 部分语音播放速率异常 2024-09-14 17:50:09 +08:00
手瓜一十雪
cf9c71fcc1 feat: 准备适配9.9.15-28606 2024-09-14 17:24:52 +08:00
Alen
15a2400069 fix: 修复文件删除失败
此处为重复插入待删列表
2024-09-14 11:12:43 +08:00
Alen
d68a39b49e fix: 定义错误 2024-09-14 10:49:43 +08:00
Alen
066ca22e24 Merge pull request #362 from cnxysoft/upmain
fix: 点赞通知解析
2024-09-14 01:24:20 +08:00
Alen
0418b926fe fix: 点赞通知解析失败 2024-09-14 00:42:10 +08:00
手瓜一十雪
be40bbdf40 release: 2.5.0 2024-09-13 17:42:11 +08:00
手瓜一十雪
df4f42e79e fix: video name 2024-09-13 17:38:11 +08:00
Alen
5f80058f70 Merge pull request #360 from cnxysoft/upmain
fix: bugs
2024-09-13 17:30:23 +08:00
Alen
0cbe59052d Merge branch 'main' into upmain 2024-09-13 17:25:59 +08:00
Alen
af28a26e37 fix: 无法发送url视频 2024-09-13 17:22:32 +08:00
Alen
70c596df93 fix: headers分割 2024-09-13 16:11:15 +08:00
手瓜一十雪
748b51428c feat: createUidFromTinyId 2024-09-13 16:05:25 +08:00
手瓜一十雪
8ad746397c feat: JoinDragonGroupEmoji 2024-09-13 15:35:05 +08:00
手瓜一十雪
45baed2f9a tag: deprecated 2024-09-13 15:30:04 +08:00
手瓜一十雪
74185f2d33 fix 2024-09-13 14:05:04 +08:00
手瓜一十雪
90a91e4105 fix 2024-09-13 13:54:12 +08:00
手瓜一十雪
11aa3a0315 feat: fetchOtherProfileLike 2024-09-12 20:05:46 +08:00
手瓜一十雪
0c2e39214f style: lint 2024-09-12 19:55:56 +08:00
手瓜一十雪
d89620d7a6 style: folder 2024-09-12 19:55:26 +08:00
手瓜一十雪
edf80775b7 release: v2.4.9 2024-09-12 19:47:57 +08:00
手瓜一十雪
46e56ac726 remove: polyFill 2024-09-12 19:35:54 +08:00
35 changed files with 315 additions and 132 deletions

View File

@@ -8,17 +8,15 @@ jobs:
Build-LiteLoader: Build-LiteLoader:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone Main Repository - name: Clone Main Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Use Node.js 20.X - name: Use Node.js 20.X
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
- name: Build NuCat Framework - name: Build NuCat Framework
run: | run: |
npm i npm i
@@ -27,25 +25,25 @@ jobs:
npm i --omit=dev npm i --omit=dev
rm package-lock.json rm package-lock.json
cd .. cd ..
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: NapCat.Framework name: NapCat.Framework
path: dist path: dist
Build-Shell: Build-Shell:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone Main Repository - name: Clone Main Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Use Node.js 20.X - name: Use Node.js 20.X
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
- name: Build NuCat LiteLoader - name: Build NuCat LiteLoader
run: | run: |
npm i npm i
@@ -54,6 +52,7 @@ jobs:
npm i --omit=dev npm i --omit=dev
rm package-lock.json rm package-lock.json
cd .. cd ..
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:

View File

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

View File

@@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "2.4.7", "version": "2.5.1",
"scripts": { "scripts": {
"build:framework": "vite build --mode framework", "build:framework": "vite build --mode framework",
"build:shell": "vite build --mode shell", "build:shell": "vite build --mode shell",

View File

@@ -40,12 +40,14 @@ async function convert(filePath: string, pcmPath: string, logger: LogWrapper): P
}); });
} }
async function handleWavFile(file: Buffer, filePath: string, pcmPath: string, logger: LogWrapper): Promise<Buffer> { async function handleWavFile(
file: Buffer, filePath: string, pcmPath: string, logger: LogWrapper
): Promise<{input: Buffer, sampleRate: number}> {
const { fmt } = getWavFileInfo(file); const { fmt } = getWavFileInfo(file);
if (!ALLOW_SAMPLE_RATE.includes(fmt.sampleRate)) { if (!ALLOW_SAMPLE_RATE.includes(fmt.sampleRate)) {
return await convert(filePath, pcmPath, logger); return {input: await convert(filePath, pcmPath, logger), sampleRate: 24000};
} }
return file; return {input: file, sampleRate: fmt.sampleRate};
} }
export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: LogWrapper) { export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: LogWrapper) {
@@ -55,8 +57,10 @@ export async function encodeSilk(filePath: string, TEMP_DIR: string, logger: Log
if (!isSilk(file)) { if (!isSilk(file)) {
logger.log(`语音文件${filePath}需要转换成silk`); logger.log(`语音文件${filePath}需要转换成silk`);
const pcmPath = `${pttPath}.pcm`; const pcmPath = `${pttPath}.pcm`;
const input = isWav(file) ? await handleWavFile(file, filePath, pcmPath, logger) : await convert(filePath, pcmPath, logger); const { input, sampleRate } = isWav(file)
const silk = await encode(input, 24000); ? (await handleWavFile(file, filePath, pcmPath, logger))
: {input: await convert(filePath, pcmPath, logger), sampleRate: 24000};
const silk = await encode(input, sampleRate);
await fsPromise.writeFile(pttPath, silk.data); await fsPromise.writeFile(pttPath, silk.data);
logger.log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration); logger.log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration);
return { return {

View File

@@ -128,6 +128,7 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
let url: string; let url: string;
let headers: Record<string, string> = { let headers: Record<string, string> = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
'referer': typeof options === 'string' ? options : options.url,
}; };
if (typeof options === 'string') { if (typeof options === 'string') {
url = options; url = options;

View File

@@ -209,7 +209,8 @@ export function getQQVersionConfigPath(exePath: string = ''): string | undefined
return configVersionInfoPath; return configVersionInfoPath;
} }
export function calcQQLevel(level: QQLevel) { export function calcQQLevel(level?: QQLevel) {
if (!level) return 0;
const { crownNum, sunNum, moonNum, starNum } = level; const { crownNum, sunNum, moonNum, starNum } = level;
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum; return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
} }

View File

@@ -1 +1 @@
export const napCatVersion = '2.4.7'; export const napCatVersion = '2.5.1';

View File

@@ -147,7 +147,15 @@ export class NTQQFileApi {
} catch (e) { } catch (e) {
logger.logError('获取视频信息失败,将使用默认值', e); logger.logError('获取视频信息失败,将使用默认值', e);
} }
const newFilePath = filePath + '.mp4';
let fileExt = 'mp4';
try {
const tempExt = (await fileType.fileTypeFromFile(filePath))?.ext;
if (tempExt) fileExt = tempExt;
} catch (e) {
this.context.logger.logError('获取文件类型失败', e);
}
const newFilePath = filePath + '.' + fileExt;
fs.copyFileSync(filePath, newFilePath); fs.copyFileSync(filePath, newFilePath);
context.deleteAfterSentFiles.push(newFilePath); context.deleteAfterSentFiles.push(newFilePath);
filePath = newFilePath; filePath = newFilePath;
@@ -189,11 +197,12 @@ export class NTQQFileApi {
thumbPath.set(0, _thumbPath); thumbPath.set(0, _thumbPath);
const thumbMd5 = _thumbPath ? await calculateFileMD5(_thumbPath) : ''; const thumbMd5 = _thumbPath ? await calculateFileMD5(_thumbPath) : '';
context.deleteAfterSentFiles.push(path); context.deleteAfterSentFiles.push(path);
const uploadName = (fileName || _fileName).toLocaleLowerCase().endsWith('.' + fileExt.toLocaleLowerCase()) ? (fileName || _fileName) : (fileName || _fileName) + '.' + fileExt;
return { return {
elementType: ElementType.VIDEO, elementType: ElementType.VIDEO,
elementId: '', elementId: '',
videoElement: { videoElement: {
fileName: fileName || _fileName, fileName: uploadName,
filePath: path, filePath: path,
videoMd5: md5, videoMd5: md5,
thumbMd5, thumbMd5,

View File

@@ -34,7 +34,13 @@ export class NTQQGroupApi {
} }
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`); this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
} }
async getCoreAndBaseInfo(uids: string[]) {
return await this.core.eventWrapper.callNoListenerEvent(
'NodeIKernelProfileService/getCoreAndBaseInfo',
'nodeStore',
uids,
);
}
async fetchGroupEssenceList(groupCode: string) { async fetchGroupEssenceList(groupCode: string) {
const pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!; const pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
return this.context.session.getGroupService().fetchGroupEssenceList({ return this.context.session.getGroupService().fetchGroupEssenceList({
@@ -262,6 +268,23 @@ export class NTQQGroupApi {
} }
return member; return member;
} }
async searchGroup(groupCode: string) {
const [, ret] = await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelSearchService/searchGroup',
'NodeIKernelSearchListener/onSearchGroupResult',
[{
keyWords: groupCode,
groupNum: 25,
exactSearch: false,
penetrate: ''
}],
(ret) => ret.result === 0,
(params) => !!params.groupInfos.find(g => g.groupCode === groupCode),
1,
5000
);
return ret.groupInfos.find(g => g.groupCode === groupCode);
}
async getGroupMemberEx(GroupCode: string, uid: string, forced = false, retry = 2) { async getGroupMemberEx(GroupCode: string, uid: string, forced = false, retry = 2) {
const data = await solveAsyncProblem((eventWrapper: NTEventWrapper, GroupCode: string, uid: string, forced = false) => { const data = await solveAsyncProblem((eventWrapper: NTEventWrapper, GroupCode: string, uid: string, forced = false) => {
return eventWrapper.callNormalEventV2( return eventWrapper.callNormalEventV2(

View File

@@ -94,6 +94,7 @@ export class NTQQMsgApi {
pageLimit: 1, pageLimit: 1,
}); });
} }
//@deprecated
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) { async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z); return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
} }

View File

@@ -11,7 +11,13 @@ 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 getProfileLike(uid: string) { async getProfileLike(uid: string) {
return this.context.session.getProfileLikeService().getBuddyProfileLike({ return this.context.session.getProfileLikeService().getBuddyProfileLike({
friendUids: [uid], friendUids: [uid],
@@ -24,7 +30,18 @@ export class NTQQUserApi {
limit: 20, limit: 20,
}); });
} }
async fetchOtherProfileLike(uid: string) {
return this.context.session.getProfileLikeService().getBuddyProfileLike({
friendUids: [uid],
basic: 1,
vote: 1,
favorite: 0,
userProfile: 0,
type: 1,
start: 0,
limit: 20,
});
}
async setLongNick(longNick: string) { async setLongNick(longNick: string) {
return this.context.session.getProfileService().setLongNick(longNick); return this.context.session.getProfileService().setLongNick(longNick);
} }

View File

@@ -959,3 +959,18 @@ export interface TmpChatInfo {
sessionType: number; sessionType: number;
sig: string; sig: string;
} }
export interface MsgReqType {
peer: Peer,
byType: number,
msgId: string,
msgSeq: string,
msgTime: string,
clientSeq: string,
cnt: number,
queryOrder: boolean,
includeSelf: boolean,
includeDeleteMsg: boolean,
extraCnt: number
}
//getMsgsIncludeSelf Peer必须 byType 1
//getMsgsWithMsgTimeAndClientSeqForC2C Peer必须 byType 3

View File

@@ -216,7 +216,7 @@ export interface BuddyProfileLikeReq {
userProfile: number; userProfile: number;
type: number; type: number;
start: number; start: number;
limit: number; limit?: number;
} }
export interface QQLevel { export interface QQLevel {

View File

@@ -10,5 +10,9 @@
"6.9.53-27597": { "6.9.53-27597": {
"appid": 537243538, "appid": 537243538,
"qua": "V1_MAC_NQ_6.9.53_27597_GW_B" "qua": "V1_MAC_NQ_6.9.53_27597_GW_B"
},
"9.9.15-28060":{
"appid": 537246092,
"qua": "V1_WIN_NQ_9.9.15_28060_GW_B"
} }
} }

View File

@@ -0,0 +1,97 @@
import { ChatType } from '@/core';
export interface SearchGroupInfo {
groupCode: string;
ownerUid: string;
groupFlag: number;
groupFlagExt: number;
maxMemberNum: number;
memberNum: number;
groupOption: number;
classExt: number;
groupName: string;
fingerMemo: string;
groupQuestion: string;
certType: number;
shutUpAllTimestamp: number;
shutUpMeTimestamp: number;
groupTypeFlag: number;
privilegeFlag: number;
groupSecLevel: number;
groupFlagExt3: number;
isConfGroup: number;
isModifyConfGroupFace: number;
isModifyConfGroupName: number;
noFigerOpenFlag: number;
noCodeFingerOpenFlag: number;
groupFlagExt4: number;
groupMemo: string;
cmdUinMsgSeq: number;
cmdUinJoinTime: number;
cmdUinUinFlag: number;
cmdUinMsgMask: number;
groupSecLevelInfo: number;
cmdUinPrivilege: number;
cmdUinFlagEx2: number;
appealDeadline: number;
remarkName: string;
isTop: boolean;
richFingerMemo: string;
groupAnswer: string;
joinGroupAuth: string;
isAllowModifyConfGroupName: number;
}
export interface GroupInfo {
groupCode: string;
searchGroupInfo: SearchGroupInfo;
privilege: number;
}
export interface GroupSearchResult {
keyWord: string;
errorCode: number;
groupInfos: GroupInfo[];
penetrate: string;
isEnd: boolean;
nextPos: number;
}
export interface NodeIKernelSearchListener {
onSearchGroupResult(params: GroupSearchResult): void;
onSearchFileKeywordsResult(params: {
searchId: string,
hasMore: boolean,
resultItems: {
chatType: ChatType,
buddyChatInfo: any[],
discussChatInfo: any[],
groupChatInfo: {
groupCode: string,
isConf: boolean,
hasModifyConfGroupFace: boolean,
hasModifyConfGroupName: boolean,
groupName: string,
remark: string
}[],
dataLineChatInfo: any[],
tmpChatInfo: any[],
msgId: string,
msgSeq: string,
msgTime: string,
senderUid: string,
senderNick: string,
senderRemark: string,
senderCard: string,
elemId: string,
elemType: number,
fileSize: string,
filePath: string,
fileName: string,
hits: {
start: number,
end: number
}[]
}[]
}): void;
}

View File

@@ -1,39 +0,0 @@
import { ChatType } from '@/core';
export interface NodeIKernelSearchListener_Polyfill {
onSearchFileKeywordsResult(params: {
searchId: string,
hasMore: boolean,
resultItems: {
chatType: ChatType,
buddyChatInfo: any[],
discussChatInfo: any[],
groupChatInfo: {
groupCode: string,
isConf: boolean,
hasModifyConfGroupFace: boolean,
hasModifyConfGroupName: boolean,
groupName: string,
remark: string
}[],
dataLineChatInfo: any[],
tmpChatInfo: any[],
msgId: string,
msgSeq: string,
msgTime: string,
senderUid: string,
senderNick: string,
senderRemark: string,
senderCard: string,
elemId: string,
elemType: number,
fileSize: string,
filePath: string,
fileName: string,
hits: {
start: number,
end: number
}[]
}[]
}): void;
}

View File

@@ -9,7 +9,7 @@ export * from './NodeIKernelProfileListener';
export * from './NodeIKernelTicketListener'; export * from './NodeIKernelTicketListener';
export * from './NodeIKernelStorageCleanListener'; export * from './NodeIKernelStorageCleanListener';
export * from './NodeIKernelFileAssistantListener'; export * from './NodeIKernelFileAssistantListener';
export * from './NodeIKernelSearchListener_Polyfill'; export * from './NodeIKernelSearchListener';
import type { import type {
NodeIKernelBuddyListener, NodeIKernelBuddyListener,
@@ -19,11 +19,11 @@ import type {
NodeIKernelMsgListener, NodeIKernelMsgListener,
NodeIKernelProfileListener, NodeIKernelProfileListener,
NodeIKernelRobotListener, NodeIKernelRobotListener,
NodeIKernelSearchListener_Polyfill,
NodeIKernelSessionListener, NodeIKernelSessionListener,
NodeIKernelStorageCleanListener, NodeIKernelStorageCleanListener,
NodeIKernelTicketListener, NodeIKernelTicketListener,
} from '.'; } from '.';
import { NodeIKernelSearchListener } from './NodeIKernelSearchListener';
export type ListenerNamingMapping = { export type ListenerNamingMapping = {
NodeIKernelSessionListener: NodeIKernelSessionListener; NodeIKernelSessionListener: NodeIKernelSessionListener;
@@ -36,5 +36,5 @@ export type ListenerNamingMapping = {
NodeIKernelTicketListener: NodeIKernelTicketListener; NodeIKernelTicketListener: NodeIKernelTicketListener;
NodeIKernelStorageCleanListener: NodeIKernelStorageCleanListener; NodeIKernelStorageCleanListener: NodeIKernelStorageCleanListener;
NodeIKernelFileAssistantListener: NodeIKernelFileAssistantListener; NodeIKernelFileAssistantListener: NodeIKernelFileAssistantListener;
NodeIKernelSearchListener: NodeIKernelSearchListener_Polyfill; NodeIKernelSearchListener: NodeIKernelSearchListener;
}; };

View File

@@ -14,9 +14,15 @@ export interface LikeMsgType {
detail: LikeDetailType; detail: LikeDetailType;
} }
export interface ProfileLikeTipType { export interface profileLikeSubTipType {
msg: LikeMsgType; msg: LikeMsgType;
} }
export interface ProfileLikeTipType {
msgType: number;
subType: number;
content: profileLikeSubTipType;
}
export interface SysMessageHeaderType { export interface SysMessageHeaderType {
id: string; id: string;
timestamp: number; timestamp: number;
@@ -78,6 +84,12 @@ export const likeMsg = new pb.Type("likeMsg")
.add(new pb.Field("time", 2, "int32")) .add(new pb.Field("time", 2, "int32"))
.add(new pb.Field("detail", 3, "likeDetail")); .add(new pb.Field("detail", 3, "likeDetail"));
export const profileLikeTip = new pb.Type("profileLikeTip") export const profileLikeSubTip = new pb.Type("profileLikeSubTip")
.add(likeMsg) .add(likeMsg)
.add(new pb.Field("msg", 14, "likeMsg")); .add(new pb.Field("msg", 14, "likeMsg"))
export const profileLikeTip = new pb.Type("profileLikeTip")
.add(profileLikeSubTip)
.add(new pb.Field("msgType", 1, "int32"))
.add(new pb.Field("subType", 2, "int32"))
.add(new pb.Field("content", 203, "profileLikeSubTip"));

View File

@@ -1,7 +1,7 @@
import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/core/entities'; import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/core/entities';
import { NodeIKernelMsgListener } from '@/core/listeners/NodeIKernelMsgListener'; import { NodeIKernelMsgListener } from '@/core/listeners/NodeIKernelMsgListener';
import { GeneralCallResult } from '@/core/services/common'; import { GeneralCallResult } from '@/core/services/common';
import { QueryMsgsParams, TmpChatInfoApi } from '../entities/msg'; import { MsgReqType, QueryMsgsParams, TmpChatInfoApi } from '../entities/msg';
export interface NodeIKernelMsgService { export interface NodeIKernelMsgService {
@@ -147,12 +147,15 @@ export interface NodeIKernelMsgService {
msgList: RawMessage[] msgList: RawMessage[]
}>; }>;
//@deprecated
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>; getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>;
//@deprecated
getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise<GeneralCallResult & { getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise<GeneralCallResult & {
msgList: RawMessage[] msgList: RawMessage[]
}>; }>;
//@deprecated
getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>; getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
getMsgsWithStatus(params: { getMsgsWithStatus(params: {
@@ -168,7 +171,7 @@ export interface NodeIKernelMsgService {
getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<GeneralCallResult & { getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<GeneralCallResult & {
msgList: RawMessage[] msgList: RawMessage[]
}>; }>;
//@deprecated
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & { getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & {
msgList: RawMessage[] msgList: RawMessage[]
}>; }>;
@@ -179,6 +182,8 @@ export interface NodeIKernelMsgService {
getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>; getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
getMsgsExt(msgReq: MsgReqType): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>; getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
getSourceOfReplyMsg(peer: Peer, MsgId: string, SourceSeq: string): unknown; getSourceOfReplyMsg(peer: Peer, MsgId: string, SourceSeq: string): unknown;
@@ -318,7 +323,7 @@ export interface NodeIKernelMsgService {
getFileThumbSavePath(...args: unknown[]): unknown; getFileThumbSavePath(...args: unknown[]): unknown;
translatePtt2Text(msgId: string, peer: Peer, msgElement: unknown): unknown; translatePtt2Text(msgId: string, peer: Peer, msgElement: MessageElement): unknown;
setPttPlayedState(...args: unknown[]): unknown; setPttPlayedState(...args: unknown[]): unknown;
@@ -391,7 +396,12 @@ export interface NodeIKernelMsgService {
getEmojiResourcePath(...args: unknown[]): unknown; getEmojiResourcePath(...args: unknown[]): unknown;
JoinDragonGroupEmoji(JoinDragonGroupEmojiReq: any/*joinDragonGroupEmojiReq*/): unknown; JoinDragonGroupEmoji(JoinDragonGroupEmojiReq: {
latestMsgSeq: string,
manageEmojiId: number,
manageMsgSeq: string,
peerContact: Peer
}): Promise<unknown>;
getMsgAbstracts(...args: unknown[]): unknown; getMsgAbstracts(...args: unknown[]): unknown;
@@ -518,7 +528,7 @@ export interface NodeIKernelMsgService {
canImportOldDbMsg(...args: unknown[]): unknown; canImportOldDbMsg(...args: unknown[]): unknown;
setPowerStatus(z: boolean): unknown; setPowerStatus(isPowerOn: boolean): unknown;
canProcessDataMigration(...args: unknown[]): unknown; canProcessDataMigration(...args: unknown[]): unknown;
@@ -607,7 +617,7 @@ export interface NodeIKernelMsgService {
setIKernelPublicAccountAdapter(...args: unknown[]): unknown; setIKernelPublicAccountAdapter(...args: unknown[]): unknown;
//tempChatGameSession有关 //tempChatGameSession有关
createUidFromTinyId(fromTinyId: string, toTinyId: string): unknown; createUidFromTinyId(fromTinyId: string, toTinyId: string): string;
dataMigrationGetDataAvaiableContactList(...args: unknown[]): unknown; dataMigrationGetDataAvaiableContactList(...args: unknown[]): unknown;

View File

@@ -1,4 +1,5 @@
import { ChatType } from '../entities'; import { ChatType } from '../entities';
import { GeneralCallResult } from './common';
export interface NodeIKernelSearchService { export interface NodeIKernelSearchService {
@@ -8,7 +9,12 @@ export interface NodeIKernelSearchService {
searchStranger(unknown: string, searchStranger: unknown, searchParams: unknown): Promise<unknown>; searchStranger(unknown: string, searchStranger: unknown, searchParams: unknown): Promise<unknown>;
searchGroup(...args: any[]): unknown;// needs 1 arguments searchGroup(param: {
keyWords: string,
groupNum: number,
exactSearch: boolean,
penetrate: string
}): Promise<GeneralCallResult>;// needs 1 arguments
searchLocalInfo(keywords: string, unknown: number/*4*/): unknown; searchLocalInfo(keywords: string, unknown: number/*4*/): unknown;

View File

@@ -7,8 +7,9 @@ const SchemaData = {
properties: { properties: {
group_id: { type: ['string', 'number'] }, group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' }, folder_id: { type: 'string' },
folder: { type: 'string' }
}, },
required: ['group_id', 'folder_id'], required: ['group_id'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
@@ -18,6 +19,6 @@ export class DeleteGroupFileFolder extends BaseAction<Payload, any> {
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
return (await this.core.apis.GroupApi.DelGroupFileFolder( return (await this.core.apis.GroupApi.DelGroupFileFolder(
payload.group_id.toString(), payload.folder_id)).groupFileCommonResult; payload.group_id.toString(), payload.folder ?? payload.folder_id ?? '')).groupFileCommonResult;
} }
} }

View File

@@ -73,7 +73,7 @@ export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileRespon
headers[headerItem] = ''; headers[headerItem] = '';
} else { } else {
const key = headerItem.substring(0, spilt); const key = headerItem.substring(0, spilt);
headers[key] = headerItem.substring(0, spilt + 1); headers[key] = headerItem.substring(spilt + 1);
} }
} }
} }

View File

@@ -8,9 +8,10 @@ const SchemaData = {
properties: { properties: {
group_id: { type: ['string', 'number'] }, group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' }, folder_id: { type: 'string' },
folder: { type: 'string' },
file_count: { type: ['string', 'number'] }, file_count: { type: ['string', 'number'] },
}, },
required: ['group_id', 'folder_id'], required: ['group_id'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
@@ -26,7 +27,7 @@ export class GetGroupFilesByFolder extends BaseAction<any, any> {
startIndex: 0, startIndex: 0,
sortOrder: 2, sortOrder: 2,
showOnlinedocFolder: 0, showOnlinedocFolder: 0,
folderId: payload.folder_id, folderId: payload.folder ?? payload.folder_id ?? '',
}).catch(() => []); }).catch(() => []);
return { return {
files: ret.filter(item => item.fileInfo) files: ret.filter(item => item.fileInfo)

View File

@@ -21,24 +21,25 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
async _handle(payload: Payload): Promise<OB11User> { async _handle(payload: Payload): Promise<OB11User> {
const user_id = payload.user_id.toString(); const user_id = payload.user_id.toString();
const extendData = await this.core.apis.UserApi.getUserDetailInfoByUin(user_id); const extendData = await this.core.apis.UserApi.getUserDetailInfoByUin(user_id);
const uid = (await this.core.apis.UserApi.getUidByUinV2(user_id))!; let uid = (await this.core.apis.UserApi.getUidByUinV2(user_id));
if (!uid || uid.indexOf('*') != -1) { if (!uid) uid = extendData.detail.uid;
const info = (await this.core.apis.UserApi.getUserDetailInfo(uid));
return { return {
...extendData.detail.simpleInfo.coreInfo, user_id: parseInt(extendData.detail.uin) ?? 0,
...extendData.detail.commonExt, uid: info.uid ?? uid,
...extendData.detail.simpleInfo.baseInfo,
...extendData.detail.simpleInfo.relationFlags,
...extendData.detail.simpleInfo.status,
user_id: parseInt(extendData.detail.uin) || 0,
nickname: extendData.detail.simpleInfo.coreInfo.nick, nickname: extendData.detail.simpleInfo.coreInfo.nick,
sex: OB11UserSex.unknown, age: extendData.detail.simpleInfo.baseInfo.age ?? info.age,
age: extendData.detail.simpleInfo.baseInfo.age || 0,
qid: extendData.detail.simpleInfo.baseInfo.qid, qid: extendData.detail.simpleInfo.baseInfo.qid,
level: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? 0) || 0, qqLevel: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? info.qqLevel),
login_days: 0, sex: OB11Entities.sex(extendData.detail.simpleInfo.baseInfo.sex) ?? OB11UserSex.unknown,
long_nick: extendData.detail.simpleInfo.baseInfo.longNick ?? info.longNick,
reg_time: extendData.detail.commonExt.regTime ?? info.regTime,
is_vip: extendData.detail.simpleInfo.vasInfo?.svipFlag,
is_years_vip: extendData.detail.simpleInfo.vasInfo?.yearVipFlag,
vip_level: extendData.detail.simpleInfo.vasInfo?.vipLevel,
remark: extendData.detail.simpleInfo.coreInfo.remark ?? info.remark,
status: extendData.detail.simpleInfo.status?.status ?? info.status,
login_days: 0,//失效
}; };
} }
const data = { ...extendData, ...(await this.core.apis.UserApi.getUserDetailInfo(uid)) };
return OB11Entities.stranger(data);
}
} }

View File

@@ -41,7 +41,7 @@ export default class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> {
peer: peer, peer: peer,
deleteAfterSentFiles: [] deleteAfterSentFiles: []
}; };
const sendFileEle = await this.core.apis.FileApi.createValidSendFileElement(msgContext, downloadResult.path, payload.name, payload.folder_id); const sendFileEle = await this.core.apis.FileApi.createValidSendFileElement(msgContext, downloadResult.path, payload.name, payload.folder ?? payload.folder_id);
await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, [sendFileEle], [], true); await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, [sendFileEle], [], true);
return null; return null;
} }

View File

@@ -20,7 +20,17 @@ class GetGroupInfo extends BaseAction<Payload, OB11Group> {
async _handle(payload: Payload) { async _handle(payload: Payload) {
const group = (await this.core.apis.GroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString()); const group = (await this.core.apis.GroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString());
if (!group) throw `${payload.group_id}不存在`; if (!group) {
const data = await this.core.apis.GroupApi.searchGroup(payload.group_id.toString());
if (!data) throw new Error('Group not found');
return {
...data.searchGroupInfo,
group_id: +payload.group_id,
group_name: data.searchGroupInfo.groupName,
member_count: data.searchGroupInfo.memberNum,
max_member_count: data.searchGroupInfo.maxMemberNum,
};
}
return OB11Entities.group(group); return OB11Entities.group(group);
} }
} }

View File

@@ -3,6 +3,7 @@ import { OB11Entities } from '@/onebot/entities';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { calcQQLevel } from '@/common/helper';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -22,7 +23,8 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
async _handle(payload: Payload) { async _handle(payload: Payload) {
const groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(payload.group_id.toString()); const groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(payload.group_id.toString());
const groupMembersArr = Array.from(groupMembers.values()); const groupMembersArr = Array.from(groupMembers.values());
let uids = groupMembersArr.map(item => item.uid);
//let CoreAndBase = await this.core.apis.GroupApi.getCoreAndBaseInfo(uids)
let _groupMembers = groupMembersArr.map(item => { let _groupMembers = groupMembersArr.map(item => {
return OB11Entities.groupMember(payload.group_id.toString(), item); return OB11Entities.groupMember(payload.group_id.toString(), item);
}); });
@@ -32,20 +34,19 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
for (let i = 0, len = _groupMembers.length; i < len; i++) { for (let i = 0, len = _groupMembers.length; i < len; i++) {
// 保证基础数据有这个 同时避免群管插件过于依赖这个杀了 // 保证基础数据有这个 同时避免群管插件过于依赖这个杀了
_groupMembers[i].join_time = date; const Member = await this.core.apis.GroupApi.getGroupMember(payload.group_id.toString(), _groupMembers[i].user_id);
_groupMembers[i].last_sent_time = date; _groupMembers[i].join_time = +(Member?.joinTime ?? date);
_groupMembers[i].last_sent_time = +(Member?.lastSpeakTime ?? date);
MemberMap.set(_groupMembers[i].user_id, _groupMembers[i]); MemberMap.set(_groupMembers[i].user_id, _groupMembers[i]);
} }
const selfRole = groupMembers.get(this.core.selfInfo.uid)?.role; const selfRole = groupMembers.get(this.core.selfInfo.uid)?.role;
const isPrivilege = selfRole === 3 || selfRole === 4; const isPrivilege = selfRole === 3 || selfRole === 4;
_groupMembers.forEach(item => {
item.last_sent_time = date;
item.join_time = date;
});
if (isPrivilege) { if (isPrivilege) {
try {
const webGroupMembers = await this.core.apis.WebApi.getGroupMembers(payload.group_id.toString()); const webGroupMembers = await this.core.apis.WebApi.getGroupMembers(payload.group_id.toString());
for (let i = 0, len = webGroupMembers.length; i < len; i++) { for (let i = 0, len = webGroupMembers.length; i < len; i++) {
if (!webGroupMembers[i]?.uin) { if (!webGroupMembers[i]?.uin) {
@@ -60,6 +61,11 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
MemberMap.set(webGroupMembers[i]?.uin, MemberData); MemberMap.set(webGroupMembers[i]?.uin, MemberData);
} }
} }
} catch (e) {
const logger = this.core.context.logger;
logger.logError.bind(logger)('GetGroupMemberList', e);
}
} }
_groupMembers = Array.from(MemberMap.values()); _groupMembers = Array.from(MemberMap.values());

View File

@@ -16,8 +16,8 @@ export interface InvalidCheckResult {
export enum ActionName { export enum ActionName {
// 以下为扩展napcat扩展 // 以下为扩展napcat扩展
Unknown = 'unknown', Unknown = 'unknown',
SharePeer = 'ArkShareGroup', SharePeer = 'ArkSharePeer',
ShareGroupEx = 'ArkSharePeer', ShareGroupEx = 'ArkShareGroup',
RebootNormal = 'reboot_normal',//无快速登录重新启动 RebootNormal = 'reboot_normal',//无快速登录重新启动
GetRobotUinRange = 'get_robot_uin_range', GetRobotUinRange = 'get_robot_uin_range',
SetOnlineStatus = 'set_online_status', SetOnlineStatus = 'set_online_status',

View File

@@ -466,7 +466,6 @@ export class OneBotMsgApi {
sendMsg.data.summary, sendMsg.data.summary,
sendMsg.data.sub_type, sendMsg.data.sub_type,
); );
context.deleteAfterSentFiles.push(sendPicElement.picElement.sourcePath);
return sendPicElement; return sendPicElement;
}, },

View File

@@ -47,7 +47,7 @@ export class OneBotQuickActionApi {
const peerContextMode = msg.message_type == 'private' ? ContextMode.Private : ContextMode.Group; const peerContextMode = msg.message_type == 'private' ? ContextMode.Private : ContextMode.Group;
const peer: Peer = await createContext(this.core, { const peer: Peer = await createContext(this.core, {
message: "", message_type: undefined,
group_id: msg.group_id?.toString(), group_id: msg.group_id?.toString(),
user_id: msg.user_id?.toString(), user_id: msg.user_id?.toString(),
}, peerContextMode); }, peerContextMode);

View File

@@ -13,9 +13,10 @@ export class OneBotUserApi {
this.core = core; this.core = core;
} }
async parseLikeEvent(wrappedBody: Uint8Array): Promise<OB11ProfileLikeEvent | undefined> { async parseLikeEvent(wrappedBody: Uint8Array): Promise<OB11ProfileLikeEvent | undefined> {
const likeTip = profileLikeTip.decode(Uint8Array.from(wrappedBody.slice(12))) as unknown as ProfileLikeTipType; const likeTip = profileLikeTip.decode(Uint8Array.from(wrappedBody)) as unknown as ProfileLikeTipType;
if (likeTip?.msgType !== 0 || likeTip?.subType !== 203) return;
this.core.context.logger.logDebug("收到点赞通知消息"); this.core.context.logger.logDebug("收到点赞通知消息");
const likeMsg = likeTip.msg; const likeMsg = likeTip.content.msg;
if (!likeMsg) return; if (!likeMsg) return;
const detail = likeMsg.detail; const detail = likeMsg.detail;
if (!detail) return; if (!detail) return;

View File

@@ -48,7 +48,8 @@ export class OB11Entities {
}[role]; }[role];
} }
static sex(sex: Sex): OB11UserSex { static sex(sex?: Sex): OB11UserSex {
if (!sex) return OB11UserSex.unknown;
return { return {
[Sex.male]: OB11UserSex.male, [Sex.male]: OB11UserSex.male,
[Sex.female]: OB11UserSex.female, [Sex.female]: OB11UserSex.female,
@@ -126,6 +127,7 @@ export class OB11Entities {
return { return {
group_id: parseInt(peerId), group_id: parseInt(peerId),
folder_id: folder.folderId, folder_id: folder.folderId,
folder: folder.folderId,
folder_name: folder.folderName, folder_name: folder.folderName,
create_time: folder.createTime, create_time: folder.createTime,
creator: parseInt(folder.createUin), creator: parseInt(folder.createUin),

View File

@@ -1,4 +1,5 @@
export interface OB11User { export interface OB11User {
[key: string]: any;
user_id: number; user_id: number;
nickname: string; nickname: string;
remark?: string; remark?: string;
@@ -81,6 +82,7 @@ export interface OB11GroupFile {
export interface OB11GroupFileFolder { export interface OB11GroupFileFolder {
group_id: number, group_id: number,
folder_id: string, folder_id: string,
folder: string,
folder_name: string, folder_name: string,
create_time: number, create_time: number,
creator: number, creator: number,

View File

@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem( SettingItem(
'<span id="napcat-update-title">Napcat</span>', '<span id="napcat-update-title">Napcat</span>',
undefined, undefined,
SettingButton('V2.4.7', 'napcat-update-button', 'secondary'), SettingButton('V2.5.1', 'napcat-update-button', 'secondary'),
), ),
]), ]),
SettingList([ SettingList([

View File

@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
SettingItem( SettingItem(
'<span id="napcat-update-title">Napcat</span>', '<span id="napcat-update-title">Napcat</span>',
void 0, void 0,
SettingButton("V2.4.7", "napcat-update-button", "secondary") SettingButton("V2.5.1", "napcat-update-button", "secondary")
) )
]), ]),
SettingList([ SettingList([