mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-09 06:20:24 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3987e0ee0b | ||
|
|
9f53bea02f | ||
|
|
737709f9e7 | ||
|
|
39477aa6a0 | ||
|
|
f097050b56 | ||
|
|
f14726ed1a | ||
|
|
e1e4d038d9 | ||
|
|
d2db4cf887 | ||
|
|
2f3ece9ca3 | ||
|
|
9f82007116 | ||
|
|
f79198a472 | ||
|
|
ce3d35d7ec | ||
|
|
f4d40f0466 | ||
|
|
a2fa085d5f | ||
|
|
a598266a6e | ||
|
|
f5fe33cee7 | ||
|
|
200c7226ef | ||
|
|
53475a6a0e | ||
|
|
b4ec1ad6c0 | ||
|
|
ef511a729d | ||
|
|
275c4ce226 | ||
|
|
45f9c029c8 | ||
|
|
db5e4ad5d9 | ||
|
|
f05d0a9727 | ||
|
|
04593e9d9a |
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "2.2.22",
|
||||
"version": "2.2.25",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.2.22",
|
||||
"version": "2.2.25",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
|
||||
@@ -51,7 +51,7 @@ export class FileNapCatOneBotUUID {
|
||||
msgId: string,
|
||||
elementId: string
|
||||
} {
|
||||
if (!uuid.startsWith('NapCatOneBot-File-')) return undefined;
|
||||
if (!uuid.startsWith('NapCatOneBot-MsgFile-')) return undefined;
|
||||
const data = uuid.split('-');
|
||||
if (data.length !== 6) return undefined;
|
||||
const [, , chatType, peerUid, msgId, elementId] = data;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const napCatVersion = '2.2.22';
|
||||
export const napCatVersion = '2.2.25';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import fsPromises from 'fs/promises';
|
||||
import { InstanceContext, NapCatCore } from '@/core';
|
||||
import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
|
||||
import * as fileType from 'file-type';
|
||||
import imageSize from 'image-size';
|
||||
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
||||
@@ -353,20 +353,15 @@ export class NTQQFileApi {
|
||||
chatType: chatType,
|
||||
peerUid: peerUid,
|
||||
}, [msgId]);
|
||||
if (msg.msgList.length === 0) {
|
||||
return fileTransNotifyInfo.filePath;
|
||||
const mixElement = msg.msgList.find((msg) => msg.msgId === msgId)?.elements.find((e) => e.elementId === elementId);
|
||||
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
||||
let realPath = mixElementInner?.filePath;
|
||||
if (!realPath) {
|
||||
const picThumbPath: Map<number, string> = (mixElementInner as any)?.picThumbPath;
|
||||
const picThumbPathList = Array.from(picThumbPath.values());
|
||||
if (picThumbPathList.length > 0) realPath = picThumbPathList[0];
|
||||
}
|
||||
//获取原始消息
|
||||
const FileElements = msg?.msgList[0]?.elements?.find(e => e.elementId === elementId);
|
||||
if (!FileElements) {
|
||||
//失败则就乱来 Todo
|
||||
return fileTransNotifyInfo.filePath;
|
||||
}
|
||||
//从原始消息获取文件路径
|
||||
return FileElements?.fileElement?.filePath ??
|
||||
FileElements?.pttElement?.filePath ??
|
||||
FileElements?.videoElement?.filePath ??
|
||||
FileElements?.picElement?.sourcePath;
|
||||
return realPath;
|
||||
}
|
||||
|
||||
async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
|
||||
@@ -440,17 +435,36 @@ export class NTQQFileApi {
|
||||
});
|
||||
}
|
||||
|
||||
async searchfile(keys: string[]) {
|
||||
const Event = this.core.eventWrapper.createEventFunction('NodeIKernelSearchService/searchFileWithKeywords');
|
||||
const id = await Event!(keys, 12);
|
||||
const Listener = this.core.eventWrapper.registerListen(
|
||||
'NodeIKernelSearchListener/onSearchFileKeywordsResult',
|
||||
1,
|
||||
20000,
|
||||
(params) => id !== '' && params.searchId == id,
|
||||
async searchForFile(keys: string[]): Promise<SearchResultItem | undefined> {
|
||||
const [, searchResult] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelFileAssistantService/searchFile',
|
||||
'NodeIKernelFileAssistantListener/onFileSearch',
|
||||
[
|
||||
keys,
|
||||
{
|
||||
resultType: 2,
|
||||
pageLimit: 1,
|
||||
}
|
||||
]
|
||||
);
|
||||
const [ret] = (await Listener);
|
||||
return ret;
|
||||
return searchResult.resultItems[0];
|
||||
}
|
||||
|
||||
async downloadFileById(
|
||||
fileId: string,
|
||||
fileSize: number = 1024576,
|
||||
estimatedTime: number = (fileSize * 1000 / 1024576) + 5000,
|
||||
) {
|
||||
const [, ret] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelFileAssistantService/downloadFile',
|
||||
'NodeIKernelFileAssistantListener/onFileStatusChanged',
|
||||
[[fileId]],
|
||||
ret => ret.result === 0,
|
||||
status => status.fileStatus === 2 && status.fileProgress === '0',
|
||||
1,
|
||||
estimatedTime, // estimate 1MB/s
|
||||
);
|
||||
return ret.filePath!;
|
||||
}
|
||||
|
||||
async getImageUrl(element: PicElement) {
|
||||
|
||||
@@ -309,12 +309,12 @@ export class NTQQGroupApi {
|
||||
return this.context.session.getGroupService().removeGroupEssence(param);
|
||||
}
|
||||
|
||||
async getSingleScreenNotifies(num: number) {
|
||||
async getSingleScreenNotifies(doubt: boolean, num: number) {
|
||||
const [, , , notifies] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelGroupService/getSingleScreenNotifies',
|
||||
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
|
||||
[
|
||||
false,
|
||||
doubt,
|
||||
'',
|
||||
num,
|
||||
],
|
||||
|
||||
@@ -34,11 +34,26 @@ export class NTQQWebApi {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
async getGroupEssenceMsgAll(GroupCode: string) {
|
||||
let ret: GroupEssenceMsgRet[] = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let data = await this.getGroupEssenceMsg(GroupCode, i, 50);
|
||||
if (!data) break;
|
||||
if (data.data.is_end) {
|
||||
ret.push(data);
|
||||
break;
|
||||
}
|
||||
ret.push(data);
|
||||
|
||||
async getGroupEssenceMsg(GroupCode: string) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
async getGroupEssenceMsg(GroupCode: string, page_start: number = 0, page_limit: number = 50) {
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?${new URLSearchParams({
|
||||
bkn: this.getBknFromCookie(cookieObject),
|
||||
page_start: page_start.toString(),
|
||||
page_limit: page_limit.toString(),
|
||||
group_code: GroupCode,
|
||||
}).toString()
|
||||
}`;
|
||||
|
||||
@@ -593,6 +593,7 @@ export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn';
|
||||
|
||||
export interface PicElement {
|
||||
md5HexStr?: string;
|
||||
filePath?: string;
|
||||
fileSize: number | string;//number
|
||||
picWidth: number;
|
||||
picHeight: number;
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
export class NodeIKernelFileAssistantListener {
|
||||
onFileStatusChanged(...args: unknown[]) {
|
||||
onFileStatusChanged(fileStatus: {
|
||||
id: string,
|
||||
fileStatus: number,
|
||||
fileProgress: `${number}`,
|
||||
fileSize: `${number}`,
|
||||
fileSpeed: number,
|
||||
thumbPath: string | null,
|
||||
filePath: string | null,
|
||||
}) {
|
||||
}
|
||||
|
||||
onSessionListChanged(...args: unknown[]) {
|
||||
@@ -11,6 +19,42 @@ export class NodeIKernelFileAssistantListener {
|
||||
onFileListChanged(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onFileSearch(...args: unknown[]) {
|
||||
onFileSearch(searchResult: SearchResultWrapper) {
|
||||
}
|
||||
}
|
||||
|
||||
export type SearchResultWrapper = {
|
||||
searchId: number,
|
||||
resultType: number,
|
||||
hasMore: boolean,
|
||||
resultItems: SearchResultItem[],
|
||||
};
|
||||
|
||||
export type SearchResultItem = {
|
||||
id: string,
|
||||
fileName: string,
|
||||
fileNameHits: string[],
|
||||
fileStatus: number,
|
||||
fileSize: string,
|
||||
isSend: boolean,
|
||||
source: number,
|
||||
fileTime: string,
|
||||
expTime: string,
|
||||
session: {
|
||||
context: null,
|
||||
uid: string,
|
||||
nick: string,
|
||||
remark: string,
|
||||
memberCard: string,
|
||||
groupCode: string,
|
||||
groupName: string,
|
||||
groupRemark: string,
|
||||
count: number,
|
||||
},
|
||||
thumbPath: string,
|
||||
filePath: string,
|
||||
msgId: string,
|
||||
chatType: number,
|
||||
peerUid: string,
|
||||
fileType: number,
|
||||
};
|
||||
|
||||
@@ -1,25 +1,6 @@
|
||||
import { ChatType, RawMessage } from '@/core/entities';
|
||||
export interface CommonFileInfo {
|
||||
bizType: null;
|
||||
chatType: number;
|
||||
elemId: string;
|
||||
favId: null;
|
||||
fileModelId: string;
|
||||
fileName: string;
|
||||
fileSize: string;
|
||||
md5: string;
|
||||
md510m: string;
|
||||
msgId: string;
|
||||
msgTime: string;
|
||||
parent: null;
|
||||
peerUid: string;
|
||||
picThumbPath: null;
|
||||
sha: string;
|
||||
sha3: string;
|
||||
subId: string;
|
||||
uuid: string;
|
||||
[property: string]: any;
|
||||
}
|
||||
import { CommonFileInfo } from '@/core';
|
||||
|
||||
export interface OnRichMediaDownloadCompleteParams {
|
||||
fileModelId: string,
|
||||
msgElementId: string,
|
||||
|
||||
@@ -19,6 +19,13 @@ message EmojiLikeToOthersMsgSpec {
|
||||
}
|
||||
|
||||
message EmojiLikeToOthersAttributes {
|
||||
enum Operation {
|
||||
FALLBACK = 0;
|
||||
LIKE = 1;
|
||||
UNLIKE = 2;
|
||||
}
|
||||
|
||||
string emojiId = 1;
|
||||
string senderUid = 4;
|
||||
Operation operation = 5;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,27 @@ export interface EmojiLikeToOthersAttributes {
|
||||
* @generated from protobuf field: string senderUid = 4;
|
||||
*/
|
||||
senderUid: string;
|
||||
/**
|
||||
* @generated from protobuf field: SysMessage.EmojiLikeToOthersAttributes.Operation operation = 5;
|
||||
*/
|
||||
operation: EmojiLikeToOthersAttributes_Operation;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf enum SysMessage.EmojiLikeToOthersAttributes.Operation
|
||||
*/
|
||||
export enum EmojiLikeToOthersAttributes_Operation {
|
||||
/**
|
||||
* @generated from protobuf enum value: FALLBACK = 0;
|
||||
*/
|
||||
FALLBACK = 0,
|
||||
/**
|
||||
* @generated from protobuf enum value: LIKE = 1;
|
||||
*/
|
||||
LIKE = 1,
|
||||
/**
|
||||
* @generated from protobuf enum value: UNLIKE = 2;
|
||||
*/
|
||||
UNLIKE = 2
|
||||
}
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class EmojiLikeToOthersWrapper1$Type extends MessageType<EmojiLikeToOthersWrapper1> {
|
||||
@@ -260,13 +281,15 @@ class EmojiLikeToOthersAttributes$Type extends MessageType<EmojiLikeToOthersAttr
|
||||
constructor() {
|
||||
super("SysMessage.EmojiLikeToOthersAttributes", [
|
||||
{ no: 1, name: "emojiId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 4, name: "senderUid", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||
{ no: 4, name: "senderUid", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 5, name: "operation", kind: "enum", T: () => ["SysMessage.EmojiLikeToOthersAttributes.Operation", EmojiLikeToOthersAttributes_Operation] }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<EmojiLikeToOthersAttributes>): EmojiLikeToOthersAttributes {
|
||||
const message = globalThis.Object.create((this.messagePrototype!));
|
||||
message.emojiId = "";
|
||||
message.senderUid = "";
|
||||
message.operation = 0;
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<EmojiLikeToOthersAttributes>(this, message, value);
|
||||
return message;
|
||||
@@ -282,6 +305,9 @@ class EmojiLikeToOthersAttributes$Type extends MessageType<EmojiLikeToOthersAttr
|
||||
case /* string senderUid */ 4:
|
||||
message.senderUid = reader.string();
|
||||
break;
|
||||
case /* SysMessage.EmojiLikeToOthersAttributes.Operation operation */ 5:
|
||||
message.operation = reader.int32();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
@@ -300,6 +326,9 @@ class EmojiLikeToOthersAttributes$Type extends MessageType<EmojiLikeToOthersAttr
|
||||
/* string senderUid = 4; */
|
||||
if (message.senderUid !== "")
|
||||
writer.tag(4, WireType.LengthDelimited).string(message.senderUid);
|
||||
/* SysMessage.EmojiLikeToOthersAttributes.Operation operation = 5; */
|
||||
if (message.operation !== 0)
|
||||
writer.tag(5, WireType.Varint).int32(message.operation);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { NodeIKernelFileAssistantListener } from '@/core';
|
||||
|
||||
export interface NodeIKernelFileAssistantService {
|
||||
addKernelFileAssistantListener(arg1: unknown[]): unknown;
|
||||
addKernelFileAssistantListener(listener: NodeIKernelFileAssistantListener): unknown;
|
||||
|
||||
removeKernelFileAssistantListener(arg1: unknown[]): unknown;
|
||||
|
||||
@@ -9,7 +11,7 @@ export interface NodeIKernelFileAssistantService {
|
||||
|
||||
getFileSessionList(): unknown;
|
||||
|
||||
searchFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
searchFile(keywords: string[], params: { resultType: number, pageLimit: number }): unknown;
|
||||
|
||||
resetSearchFileSortType(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
@@ -17,7 +19,7 @@ export interface NodeIKernelFileAssistantService {
|
||||
|
||||
cancelSearchFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
downloadFile(arg1: unknown[]): unknown;
|
||||
downloadFile(fileIds: string[]): { result: number, errMsg: string };
|
||||
|
||||
forwardFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
@@ -32,4 +34,4 @@ export interface NodeIKernelFileAssistantService {
|
||||
saveAsWithRename(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||
|
||||
isNull(): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,8 +182,7 @@ export interface NodeIKernelGroupService {
|
||||
|
||||
destroyGroup(groupCode: string): void;
|
||||
|
||||
//获取单屏群通知列表
|
||||
getSingleScreenNotifies(force: boolean, start_seq: string, num: number): Promise<GeneralCallResult>;
|
||||
getSingleScreenNotifies(doubted: boolean, start_seq: string, num: number): Promise<GeneralCallResult>;
|
||||
|
||||
clearGroupNotifies(groupCode: string): void;
|
||||
|
||||
|
||||
@@ -33,20 +33,16 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||
const NTQQFileApi = this.core.apis.FileApi;
|
||||
|
||||
const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file);
|
||||
|
||||
//接收消息标记模式
|
||||
if (contextMsgFile) {
|
||||
const { peer, msgId, elementId } = contextMsgFile;
|
||||
|
||||
const downloadPath = await NTQQFileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
|
||||
|
||||
const mixElement = (await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
|
||||
.find(msg => msg.msgId === msgId)?.elements.find(e => e.elementId === elementId);
|
||||
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
|
||||
if (!mixElementInner) throw new Error('element not found');
|
||||
|
||||
const fileSize = mixElementInner.fileSize?.toString() || '';
|
||||
const fileName = mixElementInner.fileName || '';
|
||||
const fileSize = mixElementInner.fileSize?.toString() ?? '';
|
||||
const fileName = mixElementInner.fileName ?? '';
|
||||
|
||||
const res: GetFileResponse = {
|
||||
file: downloadPath,
|
||||
@@ -64,6 +60,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//群文件模式
|
||||
const contextModelIdFile = FileNapCatOneBotUUID.decodeModelId(payload.file);
|
||||
if (contextModelIdFile) {
|
||||
@@ -87,29 +84,14 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
||||
}
|
||||
|
||||
//搜索名字模式
|
||||
const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems;
|
||||
if (NTSearchNameResult.length !== 0) {
|
||||
const MsgId = NTSearchNameResult[0].msgId;
|
||||
let peer: Peer | undefined = undefined;
|
||||
if (NTSearchNameResult[0].chatType == ChatType.KCHATTYPEGROUP) {
|
||||
peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode };
|
||||
}
|
||||
if (!peer) throw new Error('chattype not support');
|
||||
const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList;
|
||||
if (!msgList || msgList.length == 0) {
|
||||
throw new Error('msg not found');
|
||||
}
|
||||
const msg = msgList[0];
|
||||
const file = msg.elements.filter(e => e.elementType == NTSearchNameResult[0].elemType);
|
||||
if (file.length == 0) {
|
||||
throw new Error('file not found');
|
||||
}
|
||||
const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file[0].elementId, '', '');
|
||||
const searchResult = (await NTQQFileApi.searchForFile([payload.file]));
|
||||
if (searchResult) {
|
||||
const downloadPath = await NTQQFileApi.downloadFileById(searchResult.id, parseInt(searchResult.fileSize));
|
||||
const res: GetFileResponse = {
|
||||
file: downloadPath,
|
||||
url: downloadPath,
|
||||
file_size: NTSearchNameResult[0].fileSize.toString(),
|
||||
file_name: NTSearchNameResult[0].fileName,
|
||||
file_size: searchResult.fileSize.toString(),
|
||||
file_name: searchResult.fileName,
|
||||
};
|
||||
if (this.obContext.configLoader.configData.enableLocalFile2Url && downloadPath) {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
@@ -37,6 +38,13 @@ export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any>
|
||||
}).catch((e) => {
|
||||
return [];
|
||||
});
|
||||
ret.forEach((e) => {
|
||||
let fileModelId = e?.fileInfo?.fileModelId;
|
||||
if (fileModelId) {
|
||||
e.fileModelId = fileModelId;
|
||||
}
|
||||
e.fileId = FileNapCatOneBotUUID.encodeModelId({ chatType: 2, peerUid: payload.group_id.toString() }, fileModelId);
|
||||
});
|
||||
return { FileList: ret };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChatType, GroupEssenceMsgRet, Peer } from '@/core';
|
||||
import { ChatType, Peer } from '@/core';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
@@ -18,64 +18,30 @@ type Payload = FromSchema<typeof SchemaData>;
|
||||
export class GetGroupEssence extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.GoCQHTTP_GetEssenceMsg;
|
||||
payloadSchema = SchemaData;
|
||||
async parseEssenceMsgImage(ele: any) {
|
||||
return {
|
||||
type: 'image',
|
||||
data: {
|
||||
url: ele?.image_url,
|
||||
}
|
||||
};
|
||||
}
|
||||
async parseEssenceMsgText(ele: any) {
|
||||
return {
|
||||
type: 'text',
|
||||
data: {
|
||||
text: ele?.text
|
||||
}
|
||||
};
|
||||
}
|
||||
async parseEssenceMsg(msgs: any) {
|
||||
let handledMsg: any[] = [];
|
||||
for (let msg of msgs) {
|
||||
switch (msg.msg_type) {
|
||||
case 1:
|
||||
handledMsg.push(await this.parseEssenceMsgText(msg));
|
||||
break;
|
||||
case 3:
|
||||
handledMsg.push(await this.parseEssenceMsgImage(msg));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handledMsg;
|
||||
}
|
||||
async msgSeqToMsgId(peer: Peer, msgSeq: string, msgRandom: string) {
|
||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||
const replyMsgList = (await NTQQMsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom);
|
||||
|
||||
private async msgSeqToMsgId(peer: Peer, msgSeq: string, msgRandom: string) {
|
||||
const replyMsgList = (await this.core.apis.MsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom);
|
||||
if (!replyMsgList) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
id: MessageUnique.createUniqueMsgId(peer, replyMsgList.msgId),
|
||||
msg: replyMsgList
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const NTQQWebApi = this.core.apis.WebApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
//await NTQQGroupApi.fetchGroupEssenceList(payload.group_id.toString());
|
||||
let peer = {
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
peerUid: payload.group_id.toString(),
|
||||
};
|
||||
|
||||
const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString());
|
||||
if (!ret) {
|
||||
const msglist = (await NTQQWebApi.getGroupEssenceMsgAll(payload.group_id.toString())).flatMap((e) => e.data.msg_list);
|
||||
if (!msglist) {
|
||||
throw new Error('获取失败');
|
||||
}
|
||||
const Ob11Ret = await Promise.all(ret.data.msg_list.map(async (msg) => {
|
||||
let msgOriginData = await this.msgSeqToMsgId(peer, msg.msg_seq.toString(), msg.msg_random.toString());
|
||||
return await Promise.all(msglist.map(async (msg) => {
|
||||
const msgOriginData = await this.msgSeqToMsgId({
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
peerUid: payload.group_id.toString(),
|
||||
}, msg.msg_seq.toString(), msg.msg_random.toString());
|
||||
if (msgOriginData) {
|
||||
const { id: message_id, msg: rawMessage } = msgOriginData;
|
||||
return {
|
||||
@@ -109,9 +75,25 @@ export class GetGroupEssence extends BaseAction<Payload, any> {
|
||||
operator_nick: msg.add_digest_nick,
|
||||
message_id: shortId,
|
||||
operator_time: msg.add_digest_time,
|
||||
content: await this.parseEssenceMsg(msg.msg_content)
|
||||
content: msg.msg_content.map((msg) => {
|
||||
if (msg.msg_type === 1) {
|
||||
return {
|
||||
type: 'text',
|
||||
data: {
|
||||
text: msg?.text
|
||||
}
|
||||
};
|
||||
} else if (msg.msg_type === 3) {
|
||||
return {
|
||||
type: 'image',
|
||||
data: {
|
||||
url: msg?.image_url,
|
||||
}
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}).filter(e => e !== undefined),
|
||||
};
|
||||
}));
|
||||
return Ob11Ret;
|
||||
}
|
||||
}
|
||||
|
||||
39
src/onebot/action/group/GetGroupIgnoredNotifies.ts
Normal file
39
src/onebot/action/group/GetGroupIgnoredNotifies.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { GroupNotifyMsgStatus } from '@/core';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['number', 'string'] },
|
||||
},
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupIgnoredNotifies extends BaseAction<void, any> {
|
||||
actionName = ActionName.GetGroupIgnoredNotifies;
|
||||
|
||||
async _handle(payload: void) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
const ignoredNotifies = await NTQQGroupApi.getSingleScreenNotifies(true, 10);
|
||||
const retData: any = {
|
||||
join_requests: await Promise.all(
|
||||
ignoredNotifies
|
||||
.filter(notify => notify.type === 7)
|
||||
.map(async SSNotify => ({
|
||||
request_id: SSNotify.seq,
|
||||
requester_uin: await NTQQUserApi.getUinByUidV2(SSNotify.user1?.uid),
|
||||
requester_nick: SSNotify.user1?.nickName,
|
||||
group_id: SSNotify.group?.groupCode,
|
||||
group_name: SSNotify.group?.groupName,
|
||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
||||
}))),
|
||||
};
|
||||
|
||||
return retData;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { GroupNotifyMsgStatus } from '@/core';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
group_id: { type: ['number', 'string'] },
|
||||
},
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetGroupSystemMsg extends BaseAction<void, any> {
|
||||
actionName = ActionName.GetGroupSystemMsg;
|
||||
|
||||
async _handle(payload: void) {
|
||||
const NTQQUserApi = this.core.apis.UserApi;
|
||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||
// 默认10条 该api未完整实现 包括响应数据规范化 类型规范化
|
||||
const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(10);
|
||||
const retData: any = { InvitedRequest: [], join_requests: [] };
|
||||
for (const SSNotify of SingleScreenNotifies) {
|
||||
if (SSNotify.type == 1) {
|
||||
retData.InvitedRequest.push({
|
||||
request_id: SSNotify.seq,
|
||||
invitor_uin: await NTQQUserApi.getUinByUidV2(SSNotify.user1?.uid),
|
||||
invitor_nick: SSNotify.user1?.nickName,
|
||||
group_id: SSNotify.group?.groupCode,
|
||||
group_name: SSNotify.group?.groupName,
|
||||
checked: SSNotify.status === GroupNotifyMsgStatus.KUNHANDLE ? false : true,
|
||||
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
||||
});
|
||||
} else if (SSNotify.type == 7) {
|
||||
retData.join_requests.push({
|
||||
request_id: SSNotify.seq,
|
||||
requester_uin: await NTQQUserApi.getUinByUidV2(SSNotify.user1?.uid),
|
||||
requester_nick: SSNotify.user1?.nickName,
|
||||
group_id: SSNotify.group?.groupCode,
|
||||
group_name: SSNotify.group?.groupName,
|
||||
checked: SSNotify.status === GroupNotifyMsgStatus.KUNHANDLE ? false : true,
|
||||
actor: await NTQQUserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return retData;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ import { GetFriendWithCategory } from './extends/GetFriendWithCategory';
|
||||
import { SendGroupNotice } from './go-cqhttp/SendGroupNotice';
|
||||
import { GetGroupHonorInfo } from './go-cqhttp/GetGroupHonorInfo';
|
||||
import { GoCQHTTPHandleQuickAction } from './go-cqhttp/QuickAction';
|
||||
import { GetGroupSystemMsg } from './group/GetGroupSystemMsg';
|
||||
import { GetGroupIgnoredNotifies } from './group/GetGroupIgnoredNotifies';
|
||||
import { GetOnlineClient } from './go-cqhttp/GetOnlineClient';
|
||||
import { IOCRImage, OCRImage } from './extends/OCRImage';
|
||||
import { GetGroupFileCount } from './file/GetGroupFileCount';
|
||||
@@ -159,7 +159,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
||||
new GoCQHTTPGetForwardMsgAction(obContext, core),
|
||||
new GetFriendMsgHistory(obContext, core),
|
||||
new GoCQHTTPHandleQuickAction(obContext, core),
|
||||
new GetGroupSystemMsg(obContext, core),
|
||||
new GetGroupIgnoredNotifies(obContext, core),
|
||||
new DelEssenceMsg(obContext, core),
|
||||
new SetEssenceMsg(obContext, core),
|
||||
new GetRecentContact(obContext, core),
|
||||
|
||||
@@ -87,7 +87,7 @@ export enum ActionName {
|
||||
GoCQHTTP_GetGroupMsgHistory = 'get_group_msg_history',
|
||||
GoCQHTTP_GetForwardMsg = 'get_forward_msg',
|
||||
GetFriendMsgHistory = 'get_friend_msg_history',
|
||||
GetGroupSystemMsg = 'get_group_system_msg',
|
||||
GetGroupIgnoredNotifies = 'get_group_ignored_notifies',
|
||||
GetOnlineClient = 'get_online_clients',
|
||||
OCRImage = 'ocr_image',
|
||||
IOCRImage = '.ocr_image',
|
||||
|
||||
@@ -116,18 +116,22 @@ export class OneBotGroupApi {
|
||||
const searchParams = new URL(json.items[0].jp).searchParams;
|
||||
const msgSeq = searchParams.get('msgSeq')!;
|
||||
const Group = searchParams.get('groupCode');
|
||||
if (!Group) return;
|
||||
// const businessId = searchParams.get('businessid');
|
||||
const Peer = {
|
||||
guildId: '',
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
peerUid: Group!,
|
||||
peerUid: Group,
|
||||
};
|
||||
const msgData = await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true);
|
||||
let msgList = (await this.core.apis.WebApi.getGroupEssenceMsgAll(Group)).flatMap((e) => e.data.msg_list);
|
||||
let realMsg = msgList.find((e) => e.msg_seq.toString() == msgSeq);
|
||||
return new OB11GroupEssenceEvent(
|
||||
this.core,
|
||||
parseInt(msg.peerUid),
|
||||
MessageUnique.getShortIdByMsgId(msgData.msgList[0].msgId)!,
|
||||
parseInt(msgData.msgList[0].senderUin),
|
||||
parseInt(realMsg?.add_digest_uin ?? '0'),
|
||||
);
|
||||
// 获取MsgSeq+Peer可获取具体消息
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ export class OneBotQuickActionApi {
|
||||
sendElements,
|
||||
deleteAfterSentFiles,
|
||||
} = await this.obContext.apis.MsgApi.createSendElements(replyMessage, peer);
|
||||
this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles, false).then().catch(this.core.context.logger.logError);
|
||||
this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles, false).then().catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,13 +88,13 @@ export class OneBotQuickActionApi {
|
||||
request.flag,
|
||||
quickAction.approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject,
|
||||
quickAction.reason,
|
||||
).catch(this.core.context.logger.logError);
|
||||
).catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||
}
|
||||
}
|
||||
|
||||
async handleFriendRequest(request: OB11FriendRequestEvent, quickAction: QuickActionFriendRequest) {
|
||||
if (!isNull(quickAction.approve)) {
|
||||
this.core.apis.FriendApi.handleFriendRequest(request.flag, !!quickAction.approve).then().catch(this.core.context.logger.logError);
|
||||
this.core.apis.FriendApi.handleFriendRequest(request.flag, !!quickAction.approve).then().catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ export class OB11GroupEssenceEvent extends OB11GroupNoticeEvent {
|
||||
notice_type = 'essence';
|
||||
message_id: number;
|
||||
sender_id: number;
|
||||
operator_id: number;
|
||||
sub_type: 'add' | 'delete' = 'add';
|
||||
|
||||
constructor(core: NapCatCore, groupId: number, message_id: number, sender_id: number) {
|
||||
|
||||
constructor(core: NapCatCore, groupId: number, message_id: number, sender_id: number, operator_id: number) {
|
||||
super(core, groupId, sender_id);
|
||||
this.group_id = groupId;
|
||||
this.operator_id = operator_id;
|
||||
this.message_id = message_id;
|
||||
this.sender_id = sender_id;
|
||||
}
|
||||
|
||||
@@ -255,6 +255,9 @@ export class NapCatOneBot11Adapter {
|
||||
.fromBinary(greyTip.rest)
|
||||
.wrapper!
|
||||
.body!;
|
||||
if (emojiLikeToOthers.attributes?.operation !== 1) { // Un-like
|
||||
return;
|
||||
}
|
||||
const eventOrEmpty = await this.apis.GroupApi.createGroupEmojiLikeEvent(
|
||||
greyTip.groupCode.toString(),
|
||||
await this.core.apis.UserApi.getUinByUidV2(emojiLikeToOthers.attributes!.senderUid),
|
||||
|
||||
@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V2.2.22', 'napcat-update-button', 'secondary'),
|
||||
SettingButton('V2.2.25', 'napcat-update-button', 'secondary'),
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
||||
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V2.2.22", "napcat-update-button", "secondary")
|
||||
SettingButton("V2.2.25", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
||||
Reference in New Issue
Block a user