mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
73a859be04 | ||
![]() |
63bcee01a1 | ||
![]() |
85b4966ba8 | ||
![]() |
36c2c567b7 | ||
![]() |
7b1ac224f6 | ||
![]() |
34d9f04f15 | ||
![]() |
be5da7cc6f | ||
![]() |
8d32ccb5d4 | ||
![]() |
6acceb884c | ||
![]() |
4c834fd640 | ||
![]() |
301278c7a9 | ||
![]() |
42ee83c54f | ||
![]() |
e631f69621 | ||
![]() |
ce8760a39a | ||
![]() |
ff952956de |
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "3.3.26",
|
||||
"version": "3.4.4",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "3.3.26",
|
||||
"version": "3.4.4",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
|
@@ -85,7 +85,10 @@ export class QQBasicInfoWrapper {
|
||||
// 通过Major拉取 性能差
|
||||
try {
|
||||
let majorAppid = this.getAppidV2ByMajor(fullVersion);
|
||||
if (majorAppid) { return { appid: majorAppid, qua: this.getQUAFallback() }; }
|
||||
if (majorAppid) {
|
||||
this.context.logger.log(`[QQ版本兼容性检测] 当前版本Appid未内置 通过Major获取 为了更好的性能请尝试更新NapCat`);
|
||||
return { appid: majorAppid, qua: this.getQUAFallback() };
|
||||
}
|
||||
} catch (error) {
|
||||
this.context.logger.log(`[QQ版本兼容性检测] 通过Major 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '3.3.26';
|
||||
export const napCatVersion = '3.4.4';
|
||||
|
@@ -54,7 +54,9 @@ export class NTQQGroupApi {
|
||||
}, pskey);
|
||||
}
|
||||
async getGroupShutUpMemberList(groupCode: string) {
|
||||
return this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
|
||||
let data = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onShutUpMemberListChanged', 1, 1000, (group_id) => group_id === groupCode);
|
||||
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
|
||||
return (await data)[1];
|
||||
}
|
||||
async clearGroupNotifiesUnreadCount(uk: boolean) {
|
||||
return this.context.session.getGroupService().clearGroupNotifiesUnreadCount(uk);
|
||||
|
@@ -822,6 +822,8 @@ export interface RawMessage {
|
||||
elements: MessageElement[];
|
||||
|
||||
sourceType: MsgSourceType;
|
||||
|
||||
isOnlineMsg: boolean;
|
||||
}
|
||||
export interface QueryMsgsParams {
|
||||
chatInfo: Peer;
|
||||
|
@@ -43,6 +43,50 @@ export enum GroupInviteType {
|
||||
BYGROUPMEMBER,
|
||||
BYDISCUSSMEMBER
|
||||
}
|
||||
export interface ShutUpGroupHonor {
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
export interface ShutUpGroupMember {
|
||||
uid: string;
|
||||
qid: string;
|
||||
uin: string;
|
||||
nick: string;
|
||||
remark: string;
|
||||
cardType: number;
|
||||
cardName: string;
|
||||
role: number;
|
||||
avatarPath: string;
|
||||
shutUpTime: number;
|
||||
isDelete: boolean;
|
||||
isSpecialConcerned: boolean;
|
||||
isSpecialShield: boolean;
|
||||
isRobot: boolean;
|
||||
groupHonor: ShutUpGroupHonor;
|
||||
memberRealLevel: number;
|
||||
memberLevel: number;
|
||||
globalGroupLevel: number;
|
||||
globalGroupPoint: number;
|
||||
memberTitleId: number;
|
||||
memberSpecialTitle: string;
|
||||
specialTitleExpireTime: string;
|
||||
userShowFlag: number;
|
||||
userShowFlagNew: number;
|
||||
richFlag: number;
|
||||
mssVipType: number;
|
||||
bigClubLevel: number;
|
||||
bigClubFlag: number;
|
||||
autoRemark: string;
|
||||
creditLevel: number;
|
||||
joinTime: number;
|
||||
lastSpeakTime: number;
|
||||
memberFlag: number;
|
||||
memberFlagExt: number;
|
||||
memberMobileFlag: number;
|
||||
memberFlagExt2: number;
|
||||
isSpecialShielded: boolean;
|
||||
cardNameId: number;
|
||||
}
|
||||
|
||||
export interface GroupNotify {
|
||||
seq: string; // 通知序列号
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { DataSource, Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/core/entities';
|
||||
import { DataSource, Group, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/core/entities';
|
||||
|
||||
export class NodeIKernelGroupListener {
|
||||
onGroupListInited(listEmpty: boolean): void { }
|
||||
@@ -80,6 +80,6 @@ export class NodeIKernelGroupListener {
|
||||
onSearchMemberChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]) {
|
||||
onShutUpMemberListChanged(groupCode: string, members: Array<ShutUpGroupMember>) {
|
||||
}
|
||||
}
|
@@ -5,9 +5,11 @@ import { promises as fs } from 'fs';
|
||||
import { decode } from 'silk-wasm';
|
||||
const FFMPEG_PATH = process.env.FFMPEG_PATH || 'ffmpeg';
|
||||
|
||||
interface Payload extends GetFilePayload {
|
||||
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac';
|
||||
}
|
||||
const out_format = ['mp3' , 'amr' , 'wma' , 'm4a' , 'spx' , 'ogg' , 'wav' , 'flac'];
|
||||
|
||||
type Payload = {
|
||||
out_format : string
|
||||
} & GetFilePayload
|
||||
|
||||
export default class GetRecord extends GetFileBase {
|
||||
actionName = ActionName.GetRecord;
|
||||
@@ -17,12 +19,19 @@ export default class GetRecord extends GetFileBase {
|
||||
if (payload.out_format && typeof payload.out_format === 'string') {
|
||||
const inputFile = res.file;
|
||||
if (!inputFile) throw new Error('file not found');
|
||||
if (!out_format.includes(payload.out_format)) {
|
||||
throw new Error('转换失败 out_format 字段可能格式不正确');
|
||||
}
|
||||
const pcmFile = `${inputFile}.pcm`;
|
||||
const outputFile = `${inputFile}.${payload.out_format}`;
|
||||
try {
|
||||
await fs.access(inputFile);
|
||||
await this.decodeFile(inputFile, pcmFile);
|
||||
await this.convertFile(pcmFile, outputFile, payload.out_format);
|
||||
try {
|
||||
await fs.access(outputFile);
|
||||
} catch (error) {
|
||||
await this.decodeFile(inputFile, pcmFile);
|
||||
await this.convertFile(pcmFile, outputFile, payload.out_format);
|
||||
}
|
||||
const base64Data = await fs.readFile(outputFile, { encoding: 'base64' });
|
||||
res.file = outputFile;
|
||||
res.url = outputFile;
|
||||
@@ -48,7 +57,8 @@ export default class GetRecord extends GetFileBase {
|
||||
|
||||
private convertFile(inputFile: string, outputFile: string, format: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ffmpeg = spawn(FFMPEG_PATH, ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, outputFile]);
|
||||
const params = format === 'amr' ? ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, '-ar', '8000', '-b:a', '12.2k', outputFile] : ['-f', 's16le', '-ar', '24000', '-ac', '1', '-i', inputFile, outputFile];
|
||||
const ffmpeg = spawn(FFMPEG_PATH, params);
|
||||
|
||||
ffmpeg.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
@@ -63,4 +73,4 @@ export default class GetRecord extends GetFileBase {
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,11 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
||||
if (!uid) uid = extendData.detail.uid;
|
||||
const info = (await this.core.apis.UserApi.getUserDetailInfo(uid));
|
||||
return {
|
||||
...extendData.detail.simpleInfo.coreInfo,
|
||||
...extendData.detail.commonExt ?? {},
|
||||
...extendData.detail.simpleInfo.baseInfo,
|
||||
...extendData.detail.simpleInfo.relationFlags ?? {},
|
||||
...extendData.detail.simpleInfo.status ?? {},
|
||||
user_id: parseInt(extendData.detail.uin) ?? 0,
|
||||
uid: info.uid ?? uid,
|
||||
nickname: extendData.detail.simpleInfo.coreInfo.nick,
|
||||
@@ -33,7 +38,7 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
|
||||
qqLevel: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? info.qqLevel),
|
||||
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,
|
||||
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,
|
||||
|
@@ -13,7 +13,7 @@ const SchemaData = {
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupShutList extends BaseAction<Payload, OB11Group> {
|
||||
export class GetGroupShutList extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.GetGroupShutList;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
|
@@ -311,15 +311,19 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
};
|
||||
|
||||
const msgIdSend = new LRUCache<string, boolean>(100);
|
||||
const msgIdSend = new LRUCache<string, number>(100);
|
||||
const recallMsgs = new LRUCache<string, boolean>(100);
|
||||
msgListener.onAddSendMsg = async msg => {
|
||||
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) {
|
||||
msgIdSend.put(msg.msgId, 0);
|
||||
}
|
||||
};
|
||||
msgListener.onMsgInfoListUpdate = async msgList => {
|
||||
this.emitRecallMsg(msgList, recallMsgs)
|
||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
|
||||
|
||||
for (const msg of msgList.filter(e => e.senderUin == this.core.selfInfo.uin)) {
|
||||
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && !msgIdSend.get(msg.msgId)) {
|
||||
msgIdSend.put(msg.msgId, true);
|
||||
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && msgIdSend.get(msg.msgId) == 0) {
|
||||
msgIdSend.put(msg.msgId, 1);
|
||||
// 完成后再post
|
||||
this.apis.MsgApi.parseMessage(msg)
|
||||
.then((ob11Msg) => {
|
||||
@@ -523,7 +527,7 @@ export class NapCatOneBot11Adapter {
|
||||
);
|
||||
}
|
||||
|
||||
private async emitMsg(message: RawMessage) {
|
||||
private async emitMsg(message: RawMessage, parseEvent: boolean = true) {
|
||||
const { debug, reportSelfMessage, messagePostFormat } = this.configLoader.configData;
|
||||
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
||||
this.apis.MsgApi.parseMessage(message, messagePostFormat).then((ob11Msg) => {
|
||||
|
@@ -143,7 +143,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
private registerHeartBeat() {
|
||||
this.heartbeatIntervalId = setInterval(() => {
|
||||
this.wsClientsMutex.runExclusive(async () => {
|
||||
this.wsClients.forEach((wsClient) => {
|
||||
this.wsClientWithEvent.forEach((wsClient) => {
|
||||
if (wsClient.readyState === WebSocket.OPEN) {
|
||||
wsClient.send(JSON.stringify(new OB11HeartbeatEvent(this.core, this.heartbeatInterval, this.core.selfInfo.online, true)));
|
||||
}
|
||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V3.3.26", "napcat-update-button", "secondary")
|
||||
SettingButton("V3.4.4", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
Reference in New Issue
Block a user