chore: fix indentation in files

This commit is contained in:
Wesley F. Young
2024-08-09 15:58:40 +08:00
parent 518ff48e97
commit be71abe580
6 changed files with 1045 additions and 955 deletions

View File

@@ -1,9 +1,9 @@
import { import {
CacheFileListItem, CacheFileListItem,
CacheFileType, CacheFileType,
ChatCacheListItemBasic, ChatCacheListItemBasic,
ChatType, ChatType,
ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, Peer, PicElement ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, Peer, PicElement
} from '@/core/entities'; } from '@/core/entities';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
@@ -18,197 +18,197 @@ import { calculateFileMD5 } from '@/common/utils/file';
export class NTQQFileApi { export class NTQQFileApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
rkeyManager: RkeyManager; rkeyManager: RkeyManager;
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
this.core = core; this.core = core;
this.rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey', this.context.logger); this.rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey', this.context.logger);
} }
async getFileType(filePath: string) { async getFileType(filePath: string) {
return fileType.fileTypeFromFile(filePath); return fileType.fileTypeFromFile(filePath);
} }
async copyFile(filePath: string, destPath: string) { async copyFile(filePath: string, destPath: string) {
await this.context.wrapper.util.copyFile(filePath, destPath); await this.context.wrapper.util.copyFile(filePath, destPath);
} }
async getFileSize(filePath: string): Promise<number> { async getFileSize(filePath: string): Promise<number> {
return await this.context.wrapper.util.getFileSize(filePath); return await this.context.wrapper.util.getFileSize(filePath);
} }
async getVideoUrl(peer: Peer, msgId: string, elementId: string) { async getVideoUrl(peer: Peer, msgId: string, elementId: string) {
return (await this.context.session.getRichMediaService().getVideoPlayUrlV2(peer, msgId, elementId, 0, { downSourceType: 1, triggerType: 1 })).urlResult.domainUrl; return (await this.context.session.getRichMediaService().getVideoPlayUrlV2(peer, msgId, elementId, 0, { downSourceType: 1, triggerType: 1 })).urlResult.domainUrl;
} }
// 上传文件到QQ的文件夹 // 上传文件到QQ的文件夹
async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) { async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
// napCatCore.wrapper.util. // napCatCore.wrapper.util.
const fileMd5 = await calculateFileMD5(filePath); const fileMd5 = await calculateFileMD5(filePath);
let ext: string = (await this.getFileType(filePath))?.ext as string || ''; let ext: string = (await this.getFileType(filePath))?.ext as string || '';
if (ext) { if (ext) {
ext = '.' + ext; ext = '.' + ext;
}
let fileName = `${path.basename(filePath)}`;
if (fileName.indexOf('.') === -1) {
fileName += ext;
}
const mediaPath = this.context.session.getMsgService().getRichMediaFilePathForGuild({
md5HexStr: fileMd5,
fileName: fileName,
elementType: elementType,
elementSubType,
thumbSize: 0,
needCreate: true,
downloadType: 1,
file_uuid: ''
});
await this.copyFile(filePath, mediaPath!);
const fileSize = await this.getFileSize(filePath);
return {
md5: fileMd5,
fileName,
path: mediaPath,
fileSize,
ext
};
} }
let fileName = `${path.basename(filePath)}`; async downloadMediaByUuid() {
if (fileName.indexOf('.') === -1) {
fileName += ext;
}
const mediaPath = this.context.session.getMsgService().getRichMediaFilePathForGuild({
md5HexStr: fileMd5,
fileName: fileName,
elementType: elementType,
elementSubType,
thumbSize: 0,
needCreate: true,
downloadType: 1,
file_uuid: ''
});
await this.copyFile(filePath, mediaPath!);
const fileSize = await this.getFileSize(filePath);
return {
md5: fileMd5,
fileName,
path: mediaPath,
fileSize,
ext
};
}
async downloadMediaByUuid() {
//napCatCore.session.getRichMediaService().downloadFileForFileUuid(); //napCatCore.session.getRichMediaService().downloadFileForFileUuid();
}
// async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
// //logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force);
// // 用于下载收到的消息中的图片等
// if (sourcePath && fs.existsSync(sourcePath)) {
// if (force) {
// try {
// await fsPromises.unlink(sourcePath);
// } catch (e) {
// //
// }
// } else {
// return sourcePath;
// }
// }
// const data = await this.core.eventWrapper.CallNormalEvent<
// (
// params: {
// fileModelId: string,
// downloadSourceType: number,
// triggerType: number,
// msgId: string,
// chatType: ChatType,
// peerUid: string,
// elementId: string,
// thumbSize: number,
// downloadType: number,
// filePath: string
// }) => Promise<unknown>,
// (fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) => void
// >(
// 'NodeIKernelMsgService/downloadRichMedia',
// 'NodeIKernelMsgListener/onRichMediaDownloadComplete',
// 1,
// timeout,
// (arg: OnRichMediaDownloadCompleteParams) => {
// if (arg.msgId === msgId) {
// return true;
// }
// return false;
// },
// {
// fileModelId: '0',
// downloadSourceType: 0,
// triggerType: 1,
// msgId: msgId,
// chatType: chatType,
// peerUid: peerUid,
// elementId: elementId,
// thumbSize: 0,
// downloadType: 1,
// filePath: thumbPath
// }
// );
// let filePath = data[1].filePath;
// if (filePath.startsWith('\\')) {
// // log('filePath start with \\');
// const downloadPath = sessionConfig.defaultFileDownloadPath;
// //logDebug('downloadPath', downloadPath);
// filePath = path.join(downloadPath, filePath);
// // 下载路径是下载文件夹的相对路径
// }
// return filePath;
// }
async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
return new Promise((resolve, reject) => {
imageSize(filePath, (err, dimensions) => {
if (err) {
reject(err);
} else {
resolve(dimensions);
}
});
});
}
async addFileCache(peer: Peer, msgId: string, msgSeq: string, senderUid: string, elemId: string, elemType: string, fileSize: string, fileName: string) {
let GroupData;
let BuddyData;
if (peer.chatType === ChatType.group) {
GroupData =
[{
groupCode: peer.peerUid,
isConf: false,
hasModifyConfGroupFace: true,
hasModifyConfGroupName: true,
groupName: "NapCat.Cached",
remark: "NapCat.Cached"
}];
} else if (peer.chatType === ChatType.friend) {
BuddyData = [{
category_name: 'NapCat.Cached',
peerUid: peer.peerUid,
peerUin: peer.peerUid,
remark: 'NapCat.Cached'
}];
} else {
return undefined;
} }
// async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
// //logDebug('receive downloadMedia task', msgId, chatType, peerUid, elementId, thumbPath, sourcePath, timeout, force);
// // 用于下载收到的消息中的图片等
// if (sourcePath && fs.existsSync(sourcePath)) {
// if (force) {
// try {
// await fsPromises.unlink(sourcePath);
// } catch (e) {
// //
// }
// } else {
// return sourcePath;
// }
// }
// const data = await this.core.eventWrapper.CallNormalEvent<
// (
// params: {
// fileModelId: string,
// downloadSourceType: number,
// triggerType: number,
// msgId: string,
// chatType: ChatType,
// peerUid: string,
// elementId: string,
// thumbSize: number,
// downloadType: number,
// filePath: string
// }) => Promise<unknown>,
// (fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) => void
// >(
// 'NodeIKernelMsgService/downloadRichMedia',
// 'NodeIKernelMsgListener/onRichMediaDownloadComplete',
// 1,
// timeout,
// (arg: OnRichMediaDownloadCompleteParams) => {
// if (arg.msgId === msgId) {
// return true;
// }
// return false;
// },
// {
// fileModelId: '0',
// downloadSourceType: 0,
// triggerType: 1,
// msgId: msgId,
// chatType: chatType,
// peerUid: peerUid,
// elementId: elementId,
// thumbSize: 0,
// downloadType: 1,
// filePath: thumbPath
// }
// );
// let filePath = data[1].filePath;
// if (filePath.startsWith('\\')) {
// // log('filePath start with \\');
// const downloadPath = sessionConfig.defaultFileDownloadPath;
// //logDebug('downloadPath', downloadPath);
// filePath = path.join(downloadPath, filePath);
// // 下载路径是下载文件夹的相对路径
// }
// return filePath;
// }
return this.context.session.getSearchService().addSearchHistory({ async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
type: 4, return new Promise((resolve, reject) => {
contactList: [], imageSize(filePath, (err, dimensions) => {
id: -1, if (err) {
groupInfos: [], reject(err);
msgs: [], } else {
fileInfos: [ resolve(dimensions);
{ }
chatType: peer.chatType, });
buddyChatInfo: BuddyData || [], });
discussChatInfo: [], }
groupChatInfo: GroupData || [], async addFileCache(peer: Peer, msgId: string, msgSeq: string, senderUid: string, elemId: string, elemType: string, fileSize: string, fileName: string) {
dataLineChatInfo: [], let GroupData;
tmpChatInfo: [], let BuddyData;
msgId: msgId, if (peer.chatType === ChatType.group) {
msgSeq: msgSeq, GroupData =
msgTime: Math.floor(Date.now() / 1000).toString(), [{
senderUid: senderUid, groupCode: peer.peerUid,
senderNick: 'NapCat.Cached', isConf: false,
senderRemark: 'NapCat.Cached', hasModifyConfGroupFace: true,
senderCard: 'NapCat.Cached', hasModifyConfGroupName: true,
elemId: elemId, groupName: "NapCat.Cached",
elemType: elemType, remark: "NapCat.Cached"
fileSize: fileSize, }];
filePath: '', } else if (peer.chatType === ChatType.friend) {
fileName: fileName, BuddyData = [{
hits: [{ category_name: 'NapCat.Cached',
start: 12, peerUid: peer.peerUid,
end: 14 peerUin: peer.peerUid,
}] remark: 'NapCat.Cached'
}];
} else {
return undefined;
} }
]
}); return this.context.session.getSearchService().addSearchHistory({
} type: 4,
async searchfile(keys: string[]) { contactList: [],
id: -1,
groupInfos: [],
msgs: [],
fileInfos: [
{
chatType: peer.chatType,
buddyChatInfo: BuddyData || [],
discussChatInfo: [],
groupChatInfo: GroupData || [],
dataLineChatInfo: [],
tmpChatInfo: [],
msgId: msgId,
msgSeq: msgSeq,
msgTime: Math.floor(Date.now() / 1000).toString(),
senderUid: senderUid,
senderNick: 'NapCat.Cached',
senderRemark: 'NapCat.Cached',
senderCard: 'NapCat.Cached',
elemId: elemId,
elemType: elemType,
fileSize: fileSize,
filePath: '',
fileName: fileName,
hits: [{
start: 12,
end: 14
}]
}
]
});
}
async searchfile(keys: string[]) {
type EventType = NodeIKernelSearchService['searchFileWithKeywords']; type EventType = NodeIKernelSearchService['searchFileWithKeywords'];
interface OnListener { interface OnListener {
searchId: string, searchId: string,
@@ -250,99 +250,100 @@ export class NTQQFileApi {
} }
const Event = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords'); const Event = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords');
let id = ''; let id = '';
const Listener = this.core.eventWrapper.RegisterListen<(params: OnListener) => void>('NodeIKernelSearchListener/onSearchFileKeywordsResult', 1, 20000, (params) => { const Listener = this.core.eventWrapper.RegisterListen<(params: OnListener) => void>
if (id !== '' && params.searchId == id) { (
return true; 'NodeIKernelSearchListener/onSearchFileKeywordsResult',
} 1,
return false; 20000,
}); (params) => id !== '' && params.searchId == id
);
id = await Event!(keys, 12); id = await Event!(keys, 12);
const [ret] = (await Listener); const [ret] = (await Listener);
return ret; return ret;
}
async getImageUrl(element: PicElement) {
if (!element) {
return '';
} }
const url: string = element.originImageUrl!; // 没有域名 async getImageUrl(element: PicElement) {
const md5HexStr = element.md5HexStr; if (!element) {
const fileMd5 = element.md5HexStr; return '';
const fileUuid = element.fileUuid;
if (url) {
const UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
const imageAppid = UrlParse.searchParams.get('appid');
const isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid);
if (isNewPic) {
let UrlRkey = UrlParse.searchParams.get('rkey');
if (UrlRkey) {
return IMAGE_HTTP_HOST_NT + url;
} }
const rkeyData = await this.rkeyManager.getRkey(); const url: string = element.originImageUrl!; // 没有域名
UrlRkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey; const md5HexStr = element.md5HexStr;
return IMAGE_HTTP_HOST_NT + url + `${UrlRkey}`; const fileMd5 = element.md5HexStr;
} else { const fileUuid = element.fileUuid;
// 老的图片url不需要rkey
return IMAGE_HTTP_HOST + url; if (url) {
} const UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
} else if (fileMd5 || md5HexStr) { const imageAppid = UrlParse.searchParams.get('appid');
// 没有url需要自己拼接 const isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid);
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0`; if (isNewPic) {
let UrlRkey = UrlParse.searchParams.get('rkey');
if (UrlRkey) {
return IMAGE_HTTP_HOST_NT + url;
}
const rkeyData = await this.rkeyManager.getRkey();
UrlRkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
return IMAGE_HTTP_HOST_NT + url + `${UrlRkey}`;
} else {
// 老的图片url不需要rkey
return IMAGE_HTTP_HOST + url;
}
} else if (fileMd5 || md5HexStr) {
// 没有url需要自己拼接
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0`;
}
this.context.logger.logDebug('图片url获取失败', element);
return '';
} }
this.context.logger.logDebug('图片url获取失败', element);
return '';
}
} }
export class NTQQFileCacheApi { export class NTQQFileCacheApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
this.core = core; this.core = core;
} }
async setCacheSilentScan(isSilent: boolean = true) { async setCacheSilentScan(isSilent: boolean = true) {
return ''; return '';
} }
getCacheSessionPathList() { getCacheSessionPathList() {
return ''; return '';
} }
clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) { clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
// 参数未验证 // 参数未验证
return this.context.session.getStorageCleanService().clearCacheDataByKeys(cacheKeys); return this.context.session.getStorageCleanService().clearCacheDataByKeys(cacheKeys);
} }
addCacheScannedPaths(pathMap: object = {}) { addCacheScannedPaths(pathMap: object = {}) {
return this.context.session.getStorageCleanService().addCacheScanedPaths(pathMap); return this.context.session.getStorageCleanService().addCacheScanedPaths(pathMap);
} }
scanCache() { scanCache() {
//return (await this.context.session.getStorageCleanService().scanCache()).size; //return (await this.context.session.getStorageCleanService().scanCache()).size;
} }
getHotUpdateCachePath() { getHotUpdateCachePath() {
// 未实现 // 未实现
return ''; return '';
} }
getDesktopTmpPath() { getDesktopTmpPath() {
// 未实现 // 未实现
return ''; return '';
} }
getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) { getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) {
return this.context.session.getStorageCleanService().getChatCacheInfo(type, pageSize, 1, pageIndex); return this.context.session.getStorageCleanService().getChatCacheInfo(type, pageSize, 1, pageIndex);
} }
getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) { getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
const _lastRecord = lastRecord ? lastRecord : { fileType: fileType }; const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
//需要五个参数 //需要五个参数
//return napCatCore.session.getStorageCleanService().getFileCacheInfo(); //return napCatCore.session.getStorageCleanService().getFileCacheInfo();
} }
async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) { async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {
return this.context.session.getStorageCleanService().clearChatCacheInfo(chats, fileKeys); return this.context.session.getStorageCleanService().clearChatCacheInfo(chats, fileKeys);
} }
} }

View File

@@ -1,26 +1,31 @@
import { FriendV2, User } from '@/core/entities'; import { FriendV2, User } from '@/core/entities';
import { BuddyListReqType, InstanceContext, NapCatCore, NodeIKernelProfileService, OnBuddyChangeParams } from '@/core'; import { BuddyListReqType, InstanceContext, NapCatCore, NodeIKernelProfileService, OnBuddyChangeParams } from '@/core';
import { LimitedHashTable } from '@/common/utils/MessageUnique'; import { LimitedHashTable } from '@/common/utils/MessageUnique';
export class NTQQFriendApi { export class NTQQFriendApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
this.core = core; this.core = core;
} }
async getBuddyV2(refresh = false): Promise<FriendV2[]> { async getBuddyV2(refresh = false): Promise<FriendV2[]> {
const uids: string[] = []; const uids: string[] = [];
const buddyService = this.context.session.getBuddyService(); const buddyService = this.context.session.getBuddyService();
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL); const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids)); uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>( const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids 'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids,
); );
return Array.from(data.values()); return Array.from(data.values());
} }
async getBuddyIdMapCache(refresh = false): Promise<LimitedHashTable<string, string>> { async getBuddyIdMapCache(refresh = false): Promise<LimitedHashTable<string, string>> {
return await this.getBuddyIdMap(refresh); return await this.getBuddyIdMap(refresh);
} }
async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> { async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> {
const uids: string[] = []; const uids: string[] = [];
const retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000); const retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000);
@@ -28,7 +33,7 @@ export class NTQQFriendApi {
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL); const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids)); uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>( const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids 'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids,
); );
data.forEach((value, key) => { data.forEach((value, key) => {
retMap.set(value.uin!, value.uid!); retMap.set(value.uin!, value.uid!);
@@ -36,6 +41,7 @@ export class NTQQFriendApi {
//console.log('getBuddyIdMap', retMap.getValue); //console.log('getBuddyIdMap', retMap.getValue);
return retMap; return retMap;
} }
async getBuddyV2ExWithCate(refresh = false) { async getBuddyV2ExWithCate(refresh = false) {
const uids: string[] = []; const uids: string[] = [];
const categoryMap: Map<string, any> = new Map(); const categoryMap: Map<string, any> = new Map();
@@ -49,32 +55,37 @@ export class NTQQFriendApi {
return item.buddyUids; return item.buddyUids;
})); }));
const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>( const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids 'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids,
); );
return Array.from(data).map(([key, value]) => { return Array.from(data).map(([key, value]) => {
const category = categoryMap.get(key); const category = categoryMap.get(key);
return category ? { ...value, categoryId: category.categoryId, categroyName: category.categroyName } : value; return category ? {
...value,
categoryId: category.categoryId,
categroyName: category.categroyName,
} : value;
}); });
} }
async isBuddy(uid: string) { async isBuddy(uid: string) {
return this.context.session.getBuddyService().isBuddy(uid); return this.context.session.getBuddyService().isBuddy(uid);
} }
/** /**
* @deprecated * @deprecated
* @param forced * @param forced
* @returns * @returns
*/ */
async getFriends(forced = false): Promise<User[]> { async getFriends(forced = false): Promise<User[]> {
const [_retData, _BuddyArg] = await this.core.eventWrapper.CallNormalEvent const [_retData, _BuddyArg] = await this.core.eventWrapper.CallNormalEvent<(force: boolean) => Promise<any>, (arg: OnBuddyChangeParams) => void>
<(force: boolean) => Promise<any>, (arg: OnBuddyChangeParams) => void> (
( 'NodeIKernelBuddyService/getBuddyList',
'NodeIKernelBuddyService/getBuddyList', 'NodeIKernelBuddyListener/onBuddyListChange',
'NodeIKernelBuddyListener/onBuddyListChange', 1,
1, 5000,
5000, () => true,
() => true, forced,
forced );
);
const friends: User[] = []; const friends: User[] = [];
for (const categoryItem of _BuddyArg) { for (const categoryItem of _BuddyArg) {
for (const friend of categoryItem.buddyList) { for (const friend of categoryItem.buddyList) {
@@ -94,7 +105,7 @@ export class NTQQFriendApi {
this.context.session.getBuddyService()?.approvalFriendRequest({ this.context.session.getBuddyService()?.approvalFriendRequest({
friendUid: friendUid, friendUid: friendUid,
reqTime: reqTime, reqTime: reqTime,
accept accept,
}); });
} }
} }

View File

@@ -1,325 +1,367 @@
import { GroupMember, GroupRequestOperateTypes, GroupMemberRole, GroupNotify, Group, MemberExtSourceType, GroupNotifyTypes, ChatType, Peer, GroupListUpdateType } from '../entities'; import {
ChatType,
GroupMember,
GroupMemberRole,
GroupNotify,
GroupRequestOperateTypes,
MemberExtSourceType,
} from '../entities';
import { GeneralCallResult, InstanceContext, NapCatCore, NodeIKernelGroupService } from '@/core'; import { GeneralCallResult, InstanceContext, NapCatCore, NodeIKernelGroupService } from '@/core';
import { runAllWithTimeout } from '@/common/utils/helper'; import { runAllWithTimeout } from '@/common/utils/helper';
import { NodeIKernelGroupListener } from '../listeners'; import { NodeIKernelGroupListener } from '../listeners';
export class NTQQGroupApi { export class NTQQGroupApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; constructor(context: InstanceContext, core: NapCatCore) {
this.core = core; this.context = context;
} this.core = core;
async setGroupAvatar(gc: string, filePath: string) {
return this.context.session.getGroupService().setHeader(gc, filePath);
}
async getGroups(forced = false) {
type ListenerType = NodeIKernelGroupListener['onGroupListUpdate'];
const [_retData, _updateType, groupList] = await this.core.eventWrapper.CallNormalEvent
<(force: boolean) => Promise<any>, ListenerType>
(
'NodeIKernelGroupService/getGroupList',
'NodeIKernelGroupListener/onGroupListUpdate',
1,
5000,
(updateType) => true,
forced
);
return groupList;
}
async getGroupMemberLatestSendTimeCache(GroupCode: string, uids: string[]) {
return this.getGroupMemberLatestSendTime(GroupCode, uids);
}
/**
* 通过QQ自带数据库获取群成员最后发言时间(仅返回有效数据 且消耗延迟大 需要进行缓存)
* @param GroupCode 群号
* @returns Map<string, string> key: uin value: sendTime
* @example
* let ret = await NTQQGroupApi.getGroupMemberLastestSendTime('123456');
* for (let [uin, sendTime] of ret) {
* console.log(uin, sendTime);
* }
*/
async getGroupMemberLatestSendTime(GroupCode: string, uids: string[]) {
const getdata = async (uid: string) => {
const NTRet = await this.getLatestMsgByUids(GroupCode, [uid]);
if (NTRet.result != 0 && NTRet.msgList.length < 1) {
return undefined;
}
return { sendUin: NTRet.msgList[0].senderUin, sendTime: NTRet.msgList[0].msgTime };
};
const PromiseData: Promise<({
sendUin: string;
sendTime: string;
} | undefined)>[] = [];
const ret: Map<string, string> = new Map();
for (const uid of uids) {
PromiseData.push(getdata(uid).catch(() => undefined));
}
const allRet = await runAllWithTimeout(PromiseData, 2500);
for (const PromiseDo of allRet) {
if (PromiseDo) {
ret.set(PromiseDo.sendUin, PromiseDo.sendTime);
}
}
return ret;
}
async getLatestMsgByUids(GroupCode: string, uids: string[]) {
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: {
peerUid: GroupCode,
chatType: ChatType.group,
},
filterMsgType: [],
filterSendersUid: uids,
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
return ret;
}
async getGroupMemberAll(GroupCode: string, forced = false) {
return this.context.session.getGroupService().getAllMemberList(GroupCode, forced);
}
async getLatestMsg(GroupCode: string, uins: string[]) {
const uids: Array<string> = [];
for (const uin of uins) {
const uid = await this.core.getApiContext().UserApi.getUidByUin(uin);
if (uid) {
uids.push(uid);
}
}
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: {
peerUid: GroupCode,
chatType: ChatType.group,
},
filterMsgType: [],
filterSendersUid: uids,
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
return ret;
}
async getGroupRecommendContactArkJson(GroupCode: string) {
return this.context.session.getGroupService().getGroupRecommendContactArkJson(GroupCode);
}
async CreatGroupFileFolder(groupCode: string, folderName: string) {
return this.context.session.getRichMediaService().createGroupFolder(groupCode, folderName);
}
async DelGroupFile(groupCode: string, files: string[]) {
return this.context.session.getRichMediaService().deleteGroupFile(groupCode, [102], files);
}
async DelGroupFileFolder(groupCode: string, folderId: string) {
return this.context.session.getRichMediaService().deleteGroupFolder(groupCode, folderId);
}
async addGroupEssence(GroupCode: string, msgId: string) {
// 代码没测过
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false);
const param = {
groupCode: GroupCode,
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
};
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
return this.context.session.getGroupService().addGroupEssence(param);
}
async removeGroupEssence(GroupCode: string, msgId: string) {
// 代码没测过
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false);
const param = {
groupCode: GroupCode,
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
};
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
return this.context.session.getGroupService().removeGroupEssence(param);
}
async getSingleScreenNotifies(num: number) {
const [_retData, _doubt, _seq, notifies] = await this.core.eventWrapper.CallNormalEvent
<(arg1: boolean, arg2: string, arg3: number) => Promise<any>, (doubt: boolean, seq: string, notifies: GroupNotify[]) => void>
(
'NodeIKernelGroupService/getSingleScreenNotifies',
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
1,
5000,
() => true,
false,
'',
num
);
return notifies;
}
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
type ListenerType = NodeIKernelGroupListener['onMemberInfoChange'];
type EventType = NodeIKernelGroupService['getMemberInfo'];
// NTEventDispatch.CreatListenerFunction('NodeIKernelGroupListener/onGroupMemberInfoUpdate',
//return napCatCore.session.getGroupService().getMemberInfo(GroupCode, [uid], forced);
const [ret, _groupCode, _changeType, _members] = await this.core.eventWrapper.CallNormalEvent
<EventType, ListenerType>
(
'NodeIKernelGroupService/getMemberInfo',
'NodeIKernelGroupListener/onMemberInfoChange',
1,
5000,
(groupCode: string, changeType: number, members: Map<string, GroupMember>) => {
return groupCode == GroupCode && members.has(uid);
},
GroupCode, [uid], forced
);
return _members.get(uid);
}
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
const groupService = this.context.session.getGroupService();
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
const result = await groupService.getNextMemberList(sceneId!, undefined, num);
if (result.errCode !== 0) {
throw ('获取群成员列表出错,' + result.errMsg);
} }
//logDebug(`获取群(${groupQQ})成员列表结果:`, `finish: ${result.result.finish}`); //, Array.from(result.result.infos.values())); async setGroupAvatar(gc: string, filePath: string) {
return result.result.infos; return this.context.session.getGroupService().setHeader(gc, filePath);
/* }
console.log(sceneId);
const result = await napCatCore.getGroupService().getNextMemberList(sceneId, num);
console.log(result);
return result; async getGroups(forced = false) {
*/ type ListenerType = NodeIKernelGroupListener['onGroupListUpdate'];
} const [_retData, _updateType, groupList] = await this.core.eventWrapper.CallNormalEvent <(force: boolean) => Promise<any>, ListenerType>
(
'NodeIKernelGroupService/getGroupList',
'NodeIKernelGroupListener/onGroupListUpdate',
1,
5000,
(updateType) => true,
forced,
);
return groupList;
}
async getGroupNotifies() { async getGroupMemberLatestSendTimeCache(GroupCode: string, uids: string[]) {
// 获取管理员变更 return this.getGroupMemberLatestSendTime(GroupCode, uids);
// 加群通知,退出通知,需要管理员权限 }
} /**
async GetGroupFileCount(Gids: Array<string>) { * 通过QQ自带数据库获取群成员最后发言时间(仅返回有效数据 且消耗延迟大 需要进行缓存)
return this.context.session.getRichMediaService().batchGetGroupFileCount(Gids); * @param GroupCode 群号
} * @returns Map<string, string> key: uin value: sendTime
async getGroupIgnoreNotifies() { * @example
} * let ret = await NTQQGroupApi.getGroupMemberLastestSendTime('123456');
async getArkJsonGroupShare(GroupCode: string) { * for (let [uin, sendTime] of ret) {
const ret = await this.core.eventWrapper.callNoListenerEvent * console.log(uin, sendTime);
<(GroupId: string) => Promise<GeneralCallResult & { arkJson: string }>>( * }
'NodeIKernelGroupService/getGroupRecommendContactArkJson', */
5000, async getGroupMemberLatestSendTime(GroupCode: string, uids: string[]) {
GroupCode const getdata = async (uid: string) => {
); const NTRet = await this.getLatestMsgByUids(GroupCode, [uid]);
return ret.arkJson; if (NTRet.result != 0 && NTRet.msgList.length < 1) {
} return undefined;
//需要异常处理 }
async uploadGroupBulletinPic(GroupCode: string, imageurl: string) { return { sendUin: NTRet.msgList[0].senderUin, sendTime: NTRet.msgList[0].msgTime };
const _Pskey = (await this.core.getApiContext().UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!; };
return this.context.session.getGroupService().uploadGroupBulletinPic(GroupCode, _Pskey, imageurl); const PromiseData: Promise<({
} sendUin: string;
async handleGroupRequest(flag: string, operateType: GroupRequestOperateTypes, reason?: string) { sendTime: string;
const flagitem = flag.split('|'); } | undefined)>[] = [];
const groupCode = flagitem[0]; const ret: Map<string, string> = new Map();
const seq = flagitem[1]; for (const uid of uids) {
const type = parseInt(flagitem[2]); PromiseData.push(getdata(uid).catch(() => undefined));
return this.context.session.getGroupService().operateSysNotify(
false,
{
'operateType': operateType, // 2 拒绝
'targetMsg': {
'seq': seq, // 通知序列号
'type': type,
'groupCode': groupCode,
'postscript': reason || ' ' // 仅传空值可能导致处理失败,故默认给个空格
} }
}); const allRet = await runAllWithTimeout(PromiseData, 2500);
} for (const PromiseDo of allRet) {
if (PromiseDo) {
async quitGroup(groupQQ: string) { ret.set(PromiseDo.sendUin, PromiseDo.sendTime);
return this.context.session.getGroupService().quitGroup(groupQQ); }
}
async kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
return this.context.session.getGroupService().kickMember(groupQQ, kickUids, refuseForever, kickReason);
}
async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
// timeStamp为秒数, 0为解除禁言
return this.context.session.getGroupService().setMemberShutUp(groupQQ, memList);
}
async banGroup(groupQQ: string, shutUp: boolean) {
return this.context.session.getGroupService().setGroupShutUp(groupQQ, shutUp);
}
async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
return this.context.session.getGroupService().modifyMemberCardName(groupQQ, memberUid, cardName);
}
async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
return this.context.session.getGroupService().modifyMemberRole(groupQQ, memberUid, role);
}
async setGroupName(groupQQ: string, groupName: string) {
return this.context.session.getGroupService().modifyGroupName(groupQQ, groupName, false);
}
// 头衔不可用
async setGroupTitle(groupQQ: string, uid: string, title: string) {
}
async publishGroupBulletin(groupQQ: string, content: string, picInfo: { id: string, width: number, height: number } | undefined = undefined, pinned: number = 0, confirmRequired: number = 0,) {
const _Pskey = (await this.core.getApiContext().UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com');
//text是content内容url编码
const data = {
text: encodeURI(content),
picInfo: picInfo,
oldFeedsId: '',
pinned: pinned,
confirmRequired: confirmRequired
};
return this.context.session.getGroupService().publishGroupBulletin(groupQQ, _Pskey!, data);
}
async getGroupRemainAtTimes(GroupCode: string) {
this.context.session.getGroupService().getGroupRemainAtTimes(GroupCode);
}
async getMemberExtInfo(groupCode: string, uin: string) {
// 仅NTQQ 9.9.11 24568测试 容易炸开谨慎使用
return this.context.session.getGroupService().getMemberExtInfo(
{
groupCode: groupCode,
sourceType: MemberExtSourceType.TITLETYPE,
beginUin: '0',
dataTime: '0',
uinList: [uin],
uinNum: '',
seq: '',
groupType: '',
richCardNameVer: '',
memberExtFilter: {
memberLevelInfoUin: 1,
memberLevelInfoPoint: 1,
memberLevelInfoActiveDay: 1,
memberLevelInfoLevel: 1,
memberLevelInfoName: 1,
levelName: 1,
dataTime: 1,
userShowFlag: 1,
sysShowFlag: 1,
timeToUpdate: 1,
nickName: 1,
specialTitle: 1,
levelNameNew: 1,
userShowFlagNew: 1,
msgNeedField: 1,
cmdUinFlagExt3Grocery: 1,
memberIcon: 1,
memberInfoSeq: 1
} }
} return ret;
); }
}
async getLatestMsgByUids(GroupCode: string, uids: string[]) {
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: {
peerUid: GroupCode,
chatType: ChatType.group,
},
filterMsgType: [],
filterSendersUid: uids,
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
return ret;
}
async getGroupMemberAll(GroupCode: string, forced = false) {
return this.context.session.getGroupService().getAllMemberList(GroupCode, forced);
}
async getLatestMsg(GroupCode: string, uins: string[]) {
const uids: Array<string> = [];
for (const uin of uins) {
const uid = await this.core.getApiContext().UserApi.getUidByUin(uin);
if (uid) {
uids.push(uid);
}
}
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: {
peerUid: GroupCode,
chatType: ChatType.group,
},
filterMsgType: [],
filterSendersUid: uids,
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
return ret;
}
async getGroupRecommendContactArkJson(GroupCode: string) {
return this.context.session.getGroupService().getGroupRecommendContactArkJson(GroupCode);
}
async CreatGroupFileFolder(groupCode: string, folderName: string) {
return this.context.session.getRichMediaService().createGroupFolder(groupCode, folderName);
}
async DelGroupFile(groupCode: string, files: string[]) {
return this.context.session.getRichMediaService().deleteGroupFile(groupCode, [102], files);
}
async DelGroupFileFolder(groupCode: string, folderId: string) {
return this.context.session.getRichMediaService().deleteGroupFolder(groupCode, folderId);
}
async addGroupEssence(GroupCode: string, msgId: string) {
// 代码没测过
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
chatType: 2,
guildId: '',
peerUid: GroupCode,
}, msgId, 1, false);
const param = {
groupCode: GroupCode,
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
};
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
return this.context.session.getGroupService().addGroupEssence(param);
}
async removeGroupEssence(GroupCode: string, msgId: string) {
// 代码没测过
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
const MsgData = await this.context.session.getMsgService().getMsgsIncludeSelf({
chatType: 2,
guildId: '',
peerUid: GroupCode,
}, msgId, 1, false);
const param = {
groupCode: GroupCode,
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
msgSeq: parseInt(MsgData.msgList[0].msgSeq),
};
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
return this.context.session.getGroupService().removeGroupEssence(param);
}
async getSingleScreenNotifies(num: number) {
const [_retData, _doubt, _seq, notifies] = await this.core.eventWrapper.CallNormalEvent <(arg1: boolean, arg2: string, arg3: number) => Promise<any>, (doubt: boolean, seq: string, notifies: GroupNotify[]) => void>
(
'NodeIKernelGroupService/getSingleScreenNotifies',
'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
1,
5000,
() => true,
false,
'',
num,
);
return notifies;
}
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
type ListenerType = NodeIKernelGroupListener['onMemberInfoChange'];
type EventType = NodeIKernelGroupService['getMemberInfo'];
// NTEventDispatch.CreatListenerFunction('NodeIKernelGroupListener/onGroupMemberInfoUpdate',
//return napCatCore.session.getGroupService().getMemberInfo(GroupCode, [uid], forced);
const [ret, _groupCode, _changeType, _members] = await this.core.eventWrapper.CallNormalEvent <EventType, ListenerType>
(
'NodeIKernelGroupService/getMemberInfo',
'NodeIKernelGroupListener/onMemberInfoChange',
1,
5000,
(groupCode: string, changeType: number, members: Map<string, GroupMember>) => {
return groupCode == GroupCode && members.has(uid);
},
GroupCode, [uid], forced,
);
return _members.get(uid);
}
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
const groupService = this.context.session.getGroupService();
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
const result = await groupService.getNextMemberList(sceneId!, undefined, num);
if (result.errCode !== 0) {
throw ('获取群成员列表出错,' + result.errMsg);
}
//logDebug(`获取群(${groupQQ})成员列表结果:`, `finish: ${result.result.finish}`); //, Array.from(result.result.infos.values()));
return result.result.infos;
/*
console.log(sceneId);
const result = await napCatCore.getGroupService().getNextMemberList(sceneId, num);
console.log(result);
return result;
*/
}
async getGroupNotifies() {
// 获取管理员变更
// 加群通知,退出通知,需要管理员权限
}
async GetGroupFileCount(Gids: Array<string>) {
return this.context.session.getRichMediaService().batchGetGroupFileCount(Gids);
}
async getGroupIgnoreNotifies() {
}
async getArkJsonGroupShare(GroupCode: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent<(GroupId: string) => Promise<GeneralCallResult & {
arkJson: string
}>>(
'NodeIKernelGroupService/getGroupRecommendContactArkJson',
5000,
GroupCode,
);
return ret.arkJson;
}
//需要异常处理
async uploadGroupBulletinPic(GroupCode: string, imageurl: string) {
const _Pskey = (await this.core.getApiContext().UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
return this.context.session.getGroupService().uploadGroupBulletinPic(GroupCode, _Pskey, imageurl);
}
async handleGroupRequest(flag: string, operateType: GroupRequestOperateTypes, reason?: string) {
const flagitem = flag.split('|');
const groupCode = flagitem[0];
const seq = flagitem[1];
const type = parseInt(flagitem[2]);
return this.context.session.getGroupService().operateSysNotify(
false,
{
'operateType': operateType, // 2 拒绝
'targetMsg': {
'seq': seq, // 通知序列号
'type': type,
'groupCode': groupCode,
'postscript': reason || ' ', // 仅传空值可能导致处理失败,故默认给个空格
},
});
}
async quitGroup(groupQQ: string) {
return this.context.session.getGroupService().quitGroup(groupQQ);
}
async kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
return this.context.session.getGroupService().kickMember(groupQQ, kickUids, refuseForever, kickReason);
}
async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
// timeStamp为秒数, 0为解除禁言
return this.context.session.getGroupService().setMemberShutUp(groupQQ, memList);
}
async banGroup(groupQQ: string, shutUp: boolean) {
return this.context.session.getGroupService().setGroupShutUp(groupQQ, shutUp);
}
async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
return this.context.session.getGroupService().modifyMemberCardName(groupQQ, memberUid, cardName);
}
async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
return this.context.session.getGroupService().modifyMemberRole(groupQQ, memberUid, role);
}
async setGroupName(groupQQ: string, groupName: string) {
return this.context.session.getGroupService().modifyGroupName(groupQQ, groupName, false);
}
// 头衔不可用
async setGroupTitle(groupQQ: string, uid: string, title: string) {
}
async publishGroupBulletin(groupQQ: string, content: string, picInfo: {
id: string,
width: number,
height: number
} | undefined = undefined, pinned: number = 0, confirmRequired: number = 0) {
const _Pskey = (await this.core.getApiContext().UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com');
//text是content内容url编码
const data = {
text: encodeURI(content),
picInfo: picInfo,
oldFeedsId: '',
pinned: pinned,
confirmRequired: confirmRequired,
};
return this.context.session.getGroupService().publishGroupBulletin(groupQQ, _Pskey!, data);
}
async getGroupRemainAtTimes(GroupCode: string) {
this.context.session.getGroupService().getGroupRemainAtTimes(GroupCode);
}
async getMemberExtInfo(groupCode: string, uin: string) {
// 仅NTQQ 9.9.11 24568测试 容易炸开谨慎使用
return this.context.session.getGroupService().getMemberExtInfo(
{
groupCode: groupCode,
sourceType: MemberExtSourceType.TITLETYPE,
beginUin: '0',
dataTime: '0',
uinList: [uin],
uinNum: '',
seq: '',
groupType: '',
richCardNameVer: '',
memberExtFilter: {
memberLevelInfoUin: 1,
memberLevelInfoPoint: 1,
memberLevelInfoActiveDay: 1,
memberLevelInfoLevel: 1,
memberLevelInfoName: 1,
levelName: 1,
dataTime: 1,
userShowFlag: 1,
sysShowFlag: 1,
timeToUpdate: 1,
nickName: 1,
specialTitle: 1,
levelNameNew: 1,
userShowFlagNew: 1,
msgNeedField: 1,
cmdUinFlagExt3Grocery: 1,
memberIcon: 1,
memberInfoSeq: 1,
},
},
);
}
} }

View File

@@ -1,6 +1,5 @@
import { RequestUtil } from '@/common/utils/request'; import { RequestUtil } from '@/common/utils/request';
import { MiniAppLuaJsonType } from '../entities/sign'; import { MiniAppLuaJsonType } from '@/core';
import { InstanceContext, NapCatCore } from '..'; import { InstanceContext, NapCatCore } from '..';
// let t = await napCatCore.session.getGroupService().shareDigest({ // let t = await napCatCore.session.getGroupService().shareDigest({
@@ -73,14 +72,17 @@ import { InstanceContext, NapCatCore } from '..';
// }); // });
// } // }
// } // }
export class NTQQMusicSignApi { export class NTQQMusicSignApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
this.core = core; this.core = core;
} }
async SignMiniApp(CardData: MiniAppLuaJsonType) {
async signMiniApp(CardData: MiniAppLuaJsonType) {
// { // {
// "app": "com.tencent.miniapp.lua", // "app": "com.tencent.miniapp.lua",
// "bizsrc": "tianxuan.imgJumpArk", // "bizsrc": "tianxuan.imgJumpArk",
@@ -128,26 +130,26 @@ export class NTQQMusicSignApi {
// return hash & 0x7fffffff; // return hash & 0x7fffffff;
// } // }
const signCard = { const signCard = {
"app": "com.tencent.miniapp.lua", 'app': 'com.tencent.miniapp.lua',
"bizsrc": "tianxuan.imgJumpArk", 'bizsrc': 'tianxuan.imgJumpArk',
"view": "miniapp", 'view': 'miniapp',
"prompt": CardData.prompt, 'prompt': CardData.prompt,
"config": { 'config': {
"type": "normal", 'type': 'normal',
"forward": 1, 'forward': 1,
"autosize": 0 'autosize': 0,
},
'meta': {
'miniapp': {
'title': CardData.title,
'preview': (CardData.preview as string).replace(/\\/g, '\\/\\/'),
'jumpUrl': (CardData.jumpUrl as string).replace(/\\/g, '\\/\\/'),
'tag': CardData.tag,
'tagIcon': (CardData.tagIcon as string).replace(/\\/g, '\\/\\/'),
'source': CardData.source,
'sourcelogo': (CardData.sourcelogo as string).replace(/\\/g, '\\/\\/'),
},
}, },
"meta": {
"miniapp": {
"title": CardData.title,
"preview": (CardData.preview as string).replace(/\\/g, "\\/\\/"),
"jumpUrl": (CardData.jumpUrl as string).replace(/\\/g, "\\/\\/"),
"tag": CardData.tag,
"tagIcon": (CardData.tagIcon as string).replace(/\\/g, "\\/\\/"),
"source": CardData.source,
"sourcelogo": (CardData.sourcelogo as string).replace(/\\/g, "\\/\\/")
}
}
}; };
// let signCard = { // let signCard = {
// "app": "com.tencent.eventshare.lua", // "app": "com.tencent.eventshare.lua",
@@ -188,10 +190,13 @@ export class NTQQMusicSignApi {
const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + this.core.selfInfo.uin + '; uin=o' + this.core.selfInfo.uin; const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + this.core.selfInfo.uin + '; uin=o' + this.core.selfInfo.uin;
const signurl = "https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=" + Bkn + "&ark=" + encodeURIComponent(JSON.stringify(signCard)); const signurl = 'https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=' + Bkn + '&ark=' + encodeURIComponent(JSON.stringify(signCard));
let signed_ark = ""; let signed_ark = '';
try { try {
const retData = await RequestUtil.HttpGetJson<{ code: number, data: { signed_ark: string } }>(signurl, 'GET', undefined, { Cookie: CookieValue }); const retData = await RequestUtil.HttpGetJson<{
code: number,
data: { signed_ark: string }
}>(signurl, 'GET', undefined, { Cookie: CookieValue });
//logDebug('MiniApp JSON 消息生成成功', retData); //logDebug('MiniApp JSON 消息生成成功', retData);
signed_ark = retData.data.signed_ark; signed_ark = retData.data.signed_ark;
} catch (error) { } catch (error) {
@@ -199,76 +204,92 @@ export class NTQQMusicSignApi {
} }
return signed_ark; return signed_ark;
} }
async SignMusicInternal(songname: string, singer: string, cover: string, songmid: string, songmusic: string) {
async signInternal(songname: string, singer: string, cover: string, songmid: string, songmusic: string) {
//curl -X POST 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003' -H 'Content-Type: application/json' -H 'Cookie: uin=o10086' -d '{"app":"com.tencent.qqreader.share","config":{"ctime":1718634110,"forward":1,"token":"9a63343c32d5a16bcde653eb97faa25d","type":"normal"},"extra":{"app_type":1,"appid":100497308,"msg_seq":14386738075403815000.0,"uin":1733139081},"meta":{"music":{"action":"","android_pkg_name":"","app_type":1,"appid":100497308,"ctime":1718634110,"desc":"周杰伦","jumpUrl":"https://i.y.qq.com/v8/playsong.html?songmid=0039MnYb0qxYhV&type=0","musicUrl":"http://ws.stream.qqmusic.qq.com/http://isure6.stream.qqmusic.qq.com/M800002202B43Cq4V4.mp3?fromtag=810033622&guid=br_xzg&trace=23fe7bcbe2336bbf&uin=553&vkey=CF0F5CE8B0FA16F3001F8A88D877A217EB5E4F00BDCEF1021EB6C48969CA33C6303987AEECE9CC840122DD2F917A59D6130D8A8CA4577C87","preview":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","cover":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","sourceMsgId":"0","source_icon":"https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0","source_url":"","tag":"QQ音乐","title":"晴天","uin":10086}},"prompt":"[分享]晴天","ver":"0.0.0.1","view":"music"}' //curl -X POST 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003' -H 'Content-Type: application/json' -H 'Cookie: uin=o10086' -d '{"app":"com.tencent.qqreader.share","config":{"ctime":1718634110,"forward":1,"token":"9a63343c32d5a16bcde653eb97faa25d","type":"normal"},"extra":{"app_type":1,"appid":100497308,"msg_seq":14386738075403815000.0,"uin":1733139081},"meta":{"music":{"action":"","android_pkg_name":"","app_type":1,"appid":100497308,"ctime":1718634110,"desc":"周杰伦","jumpUrl":"https://i.y.qq.com/v8/playsong.html?songmid=0039MnYb0qxYhV&type=0","musicUrl":"http://ws.stream.qqmusic.qq.com/http://isure6.stream.qqmusic.qq.com/M800002202B43Cq4V4.mp3?fromtag=810033622&guid=br_xzg&trace=23fe7bcbe2336bbf&uin=553&vkey=CF0F5CE8B0FA16F3001F8A88D877A217EB5E4F00BDCEF1021EB6C48969CA33C6303987AEECE9CC840122DD2F917A59D6130D8A8CA4577C87","preview":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","cover":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","sourceMsgId":"0","source_icon":"https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0","source_url":"","tag":"QQ音乐","title":"晴天","uin":10086}},"prompt":"[分享]晴天","ver":"0.0.0.1","view":"music"}'
const signurl = 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003'; const signurl = 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003';
//let = "https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg"; //let = "https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg";
const signCard = { const signCard = {
app: "com.tencent.qqreader.share", app: 'com.tencent.qqreader.share',
config: { config: {
ctime: 1718634110, ctime: 1718634110,
forward: 1, forward: 1,
token: "9a63343c32d5a16bcde653eb97faa25d", token: '9a63343c32d5a16bcde653eb97faa25d',
type: "normal" type: 'normal',
}, },
extra: { extra: {
app_type: 1, app_type: 1,
appid: 100497308, appid: 100497308,
msg_seq: 14386738075403815000.0, msg_seq: 14386738075403815000,
uin: 1733139081 uin: 1733139081,
}, },
meta: { meta: {
music: music: {
{ action: '',
action: "", android_pkg_name: '',
android_pkg_name: "",
app_type: 1, app_type: 1,
appid: 100497308, appid: 100497308,
ctime: 1718634110, ctime: 1718634110,
desc: singer, desc: singer,
jumpUrl: "https://i.y.qq.com/v8/playsong.html?songmid=" + songmid + "&type=0", jumpUrl: 'https://i.y.qq.com/v8/playsong.html?songmid=' + songmid + '&type=0',
musicUrl: songmusic, musicUrl: songmusic,
preview: cover, preview: cover,
cover: cover, cover: cover,
sourceMsgId: "0", sourceMsgId: '0',
source_icon: "https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0", source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0',
source_url: "", source_url: '',
tag: "QQ音乐", tag: 'QQ音乐',
title: songname, title: songname,
uin: 10086 uin: 10086,
} },
}, },
prompt: "[分享]" + songname, prompt: '[分享]' + songname,
ver: "0.0.0.1", ver: '0.0.0.1',
view: "music" view: 'music',
}; };
//console.log(JSON.stringify(signCard, null, 2)); //console.log(JSON.stringify(signCard, null, 2));
const data = await RequestUtil.HttpGetJson<{ code: number, data: { arkResult: string } }> const data = await RequestUtil.HttpGetJson<{ code: number, data: { arkResult: string } }>
(signurl, 'POST', signCard, { 'Cookie': 'uin=o10086', 'Content-Type': 'application/json' }); (signurl, 'POST', signCard, { 'Cookie': 'uin=o10086', 'Content-Type': 'application/json' });
return data; return data;
} }
//注意处理错误 //注意处理错误
async CreateMusicThridWay0(id: string = '', mid: string = '') { async signWay03(id: string = '', mid: string = '') {
let signedMid;
if (mid == '') { if (mid == '') {
const MusicInfo = await RequestUtil.HttpGetJson const MusicInfo = await RequestUtil.HttpGetJson<{
<{ songinfo?: { data?: { track_info: { mid: string } } } }> songinfo?: {
( data?: {
'https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"songinfo":{"method":"get_song_detail_yqq","param":{"song_type":0,"song_mid":"","song_id":' + id + '},"module":"music.pf_song_detail_svr"}}', track_info: {
'GET', mid: string
undefined }
); }
mid = MusicInfo.songinfo?.data?.track_info.mid!; }
}>(
'https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"songinfo":{"method":"get_song_detail_yqq","param":{"song_type":0,"song_mid":"","song_id":' + id + '},"module":"music.pf_song_detail_svr"}}',
'GET',
undefined,
);
signedMid = MusicInfo.songinfo?.data?.track_info.mid;
} }
//第三方接口 存在速率限制 现在勉强用 //第三方接口 存在速率限制 现在勉强用
const MusicReal = await RequestUtil.HttpGetJson const MusicReal = await RequestUtil.HttpGetJson<{
<{ code: number, data?: { name: string, singer: string, url: string, cover: string } }> code: number,
('https://api.leafone.cn/api/qqmusic?id=' + mid + '&type=8', 'GET', undefined); data?: {
name: string,
singer: string,
url: string,
cover: string
}
}>('https://api.leafone.cn/api/qqmusic?id=' + signedMid + '&type=8', 'GET');
//console.log(MusicReal); //console.log(MusicReal);
return { ...MusicReal.data, mid: mid }; return { ...MusicReal.data, mid: signedMid };
} }
async CreateMusicThridWay1(id: string = '', mid: string = '') {
async CreateMusicThirdWay1(id: string = '', mid: string = '') {
} }
//转换外域名为 https://qq.ugcimg.cn/v1/cpqcbu4b8870i61bde6k7cbmjgejq8mr3in82qir4qi7ielffv5slv8ck8g42novtmev26i233ujtuab6tvu2l2sjgtupfr389191v00s1j5oh5325j5eqi40774jv1i/khovifoh7jrqd6eahoiv7koh8o //转换外域名为 https://qq.ugcimg.cn/v1/cpqcbu4b8870i61bde6k7cbmjgejq8mr3in82qir4qi7ielffv5slv8ck8g42novtmev26i233ujtuab6tvu2l2sjgtupfr389191v00s1j5oh5325j5eqi40774jv1i/khovifoh7jrqd6eahoiv7koh8o
//https://cgi.connect.qq.com/qqconnectopen/openapi/change_image_url?url=https://th.bing.com/th?id=OSK.b8ed36f1fb1889de6dc84fd81c187773&w=46&h=46&c=11&rs=1&qlt=80&o=6&dpr=2&pid=SANGAM //https://cgi.connect.qq.com/qqconnectopen/openapi/change_image_url?url=https://th.bing.com/th?id=OSK.b8ed36f1fb1889de6dc84fd81c187773&w=46&h=46&c=11&rs=1&qlt=80&o=6&dpr=2&pid=SANGAM
@@ -283,9 +304,8 @@ export class NTQQMusicSignApi {
//还有一处公告上传可以上传高质量图片 持久为qq域名 //还有一处公告上传可以上传高质量图片 持久为qq域名
async SignMusicWrapper(id: string = '') { async SignMusicWrapper(id: string = '') {
const MusicInfo = await this.CreateMusicThridWay0(id)!; const MusicInfo = await this.signWay03(id)!;
const MusicCard = await this.SignMusicInternal(MusicInfo.name!, MusicInfo.singer!, MusicInfo.cover!, MusicInfo.mid!, "https://ws.stream.qqmusic.qq.com/" + MusicInfo.url!); return await this.signInternal(MusicInfo.name!, MusicInfo.singer!, MusicInfo.cover!, MusicInfo.mid!, 'https://ws.stream.qqmusic.qq.com/' + MusicInfo.url!);
return MusicCard;
} }
} }

View File

@@ -1,36 +1,43 @@
import { GeneralCallResult, InstanceContext, NapCatCore } from '@/core'; import { GeneralCallResult, InstanceContext, NapCatCore } from '@/core';
export class NTQQSystemApi { export class NTQQSystemApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
this.core = core; this.core = core;
} }
async hasOtherRunningQQProcess() { async hasOtherRunningQQProcess() {
return this.context.wrapper.util.hasOtherRunningQQProcess(); return this.context.wrapper.util.hasOtherRunningQQProcess();
} }
async ORCImage(filePath: string) { async ORCImage(filePath: string) {
return this.context.session.getNodeMiscService().wantWinScreenOCR(filePath); return this.context.session.getNodeMiscService().wantWinScreenOCR(filePath);
} }
async translateEnWordToZn(words: string[]) { async translateEnWordToZn(words: string[]) {
return this.context.session.getRichMediaService().translateEnWordToZn(words); return this.context.session.getRichMediaService().translateEnWordToZn(words);
} }
//调用会超时 没灯用 (好像是通知listener的) onLineDev //调用会超时 没灯用 (好像是通知listener的) onLineDev
async getOnlineDev() { async getOnlineDev() {
return this.context.session.getMsgService().getOnLineDev(); return this.context.session.getMsgService().getOnLineDev();
} }
//1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50 //1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50
async getArkJsonCollection(cid: string) { async getArkJsonCollection(cid: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent const ret = await this.core.eventWrapper.callNoListenerEvent<(cid: string) => Promise<GeneralCallResult & {
<(cid: string) => Promise<GeneralCallResult & { arkJson: string }>>( arkJson: string
'NodeIKernelCollectionService/collectionArkShare', }>>(
'NodeIKernelCollectionService/collectionArkShare',
5000, 5000,
'1717662698058' '1717662698058',
); );
return ret; return ret;
} }
async BootMiniApp(appfile: string, params: string) { async BootMiniApp(appfile: string, params: string) {
await this.context.session.getNodeMiscService().setMiniAppVersion('2.16.4'); await this.context.session.getNodeMiscService().setMiniAppVersion('2.16.4');
const c = await this.context.session.getNodeMiscService().getMiniAppPath(); const c = await this.context.session.getNodeMiscService().getMiniAppPath();

View File

@@ -5,310 +5,319 @@ import { NodeIKernelProfileService, ProfileBizType, UserDetailSource } from '@/c
import { InstanceContext, NapCatCore } from '..'; import { InstanceContext, NapCatCore } from '..';
export class NTQQUserApi { export class NTQQUserApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
constructor(context: InstanceContext, core: NapCatCore) {
this.context = context;
this.core = core;
}
async getProfileLike(uid: string) {
return this.context.session.getProfileLikeService().getBuddyProfileLike({
friendUids: [
uid
],
basic: 1,
vote: 1,
favorite: 0,
userProfile: 1,
type: 2,
start: 0,
limit: 20
});
}
async setLongNick(longNick: string) {
return this.context.session.getProfileService().setLongNick(longNick);
}
async setSelfOnlineStatus(status: number, extStatus: number, batteryStatus: number) {
return this.context.session.getMsgService().setStatus({ status: status, extStatus: extStatus, batteryStatus: batteryStatus });
}
async getBuddyRecommendContactArkJson(uin: string, sencenID = '') {
return this.context.session.getBuddyService().getBuddyRecommendContactArkJson(uin, sencenID);
}
async like(uid: string, count = 1): Promise<{ result: number, errMsg: string, succCounts: number }> {
return this.context.session.getProfileLikeService().setBuddyProfileLike({
friendUid: uid,
sourceId: 71,
doLikeCount: count,
doLikeTollCount: 0
});
}
async setQQAvatar(filePath: string) { constructor(context: InstanceContext, core: NapCatCore) {
type setQQAvatarRet = { result: number, errMsg: string }; this.context = context;
const ret = await this.context.session.getProfileService().setHeader(filePath) as setQQAvatarRet; this.core = core;
return { result: ret?.result, errMsg: ret?.errMsg }; }
}
async setGroupAvatar(gc: string, filePath: string) {
return this.context.session.getGroupService().setHeader(gc, filePath);
}
async fetchUserDetailInfos(uids: string[]) { async getProfileLike(uid: string) {
//26702 以上使用新接口 .Dev Mlikiowa return this.context.session.getProfileLikeService().getBuddyProfileLike({
type EventService = NodeIKernelProfileService['fetchUserDetailInfo']; friendUids: [
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged']; uid,
let retData: User[] = []; ],
let [_retData, _retListener] = await this.core.eventWrapper.CallNormalEvent basic: 1,
<EventService, EventListener> vote: 1,
( favorite: 0,
'NodeIKernelProfileService/fetchUserDetailInfo', userProfile: 1,
'NodeIKernelProfileListener/onUserDetailInfoChanged', type: 2,
uids.length, start: 0,
5000, limit: 20,
(profile) => { });
if (uids.includes(profile.uid)) { }
let RetUser: User = {
...profile.simpleInfo.coreInfo,
...profile.simpleInfo.status,
...profile.simpleInfo.vasInfo,
...profile.commonExt,
...profile.simpleInfo.baseInfo,
qqLevel: profile.commonExt.qqLevel,
pendantId: ""
};
retData.push(RetUser);
return true;
}
return false;
},
"BuddyProfileStore",
uids,
UserDetailSource.KSERVER,
[
ProfileBizType.KALL
]
);
return retData; async setLongNick(longNick: string) {
} return this.context.session.getProfileService().setLongNick(longNick);
async fetchUserDetailInfo(uid: string) {
type EventService = NodeIKernelProfileService['fetchUserDetailInfo'];
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
let [_retData, profile] = await this.core.eventWrapper.CallNormalEvent
<EventService, EventListener>
(
'NodeIKernelProfileService/fetchUserDetailInfo',
'NodeIKernelProfileListener/onUserDetailInfoChanged',
1,
5000,
(profile) => {
if (profile.uid === uid) {
return true;
}
return false;
},
"BuddyProfileStore",
[
uid
],
UserDetailSource.KSERVER,
[
ProfileBizType.KALL
]
);
let RetUser: User = {
...profile.simpleInfo.coreInfo,
...profile.simpleInfo.status,
...profile.simpleInfo.vasInfo,
...profile.commonExt,
...profile.simpleInfo.baseInfo,
qqLevel: profile.commonExt.qqLevel,
pendantId: ""
};
return RetUser;
}
async getUserDetailInfo(uid: string) {
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return this.fetchUserDetailInfo(uid);
} }
return this.getUserDetailInfoOld(uid);
}
async getUserDetailInfoOld(uid: string) {
type EventService = NodeIKernelProfileService['getUserDetailInfoWithBizInfo'];
type EventListener = NodeIKernelProfileListener['onProfileDetailInfoChanged'];
let [_retData, profile] = await this.core.eventWrapper.CallNormalEvent
<EventService, EventListener>
(
'NodeIKernelProfileService/getUserDetailInfoWithBizInfo',
'NodeIKernelProfileListener/onProfileDetailInfoChanged',
2,
5000,
(profile: User) => {
if (profile.uid === uid) {
return true;
}
return false;
},
uid,
[0]
);
return profile;
}
async modifySelfProfile(param: ModifyProfileParams) {
return this.context.session.getProfileService().modifyDesktopMiniProfile(param);
}
//需要异常处理
async getCookies(domain: string) {
const ClientKeyData = await this.forceFetchClientKey();
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2F' + domain + '%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27'
let cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
return cookies;
}
async getPSkey(domainList: string[]) {
return await this.context.session.getTipOffService().getPskey(domainList, true);
}
async getRobotUinRange(): Promise<Array<any>> {
const robotUinRanges = await this.context.session.getRobotService().getRobotUinRange({
justFetchMsgConfig: '1',
type: 1,
version: 0,
aioKeywordVersion: 0
});
// console.log(robotUinRanges?.response?.robotUinRanges);
return robotUinRanges?.response?.robotUinRanges;
}
//需要异常处理
async getQzoneCookies() { async setSelfOnlineStatus(status: number, extStatus: number, batteryStatus: number) {
const ClientKeyData = await this.forceFetchClientKey(); return this.context.session.getMsgService().setStatus({
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27' status: status,
let cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl); extStatus: extStatus,
return cookies; batteryStatus: batteryStatus,
} });
//需要异常处理 }
async getSkey(): Promise<string | undefined> { async getBuddyRecommendContactArkJson(uin: string, sencenID = '') {
const ClientKeyData = await this.forceFetchClientKey(); return this.context.session.getBuddyService().getBuddyRecommendContactArkJson(uin, sencenID);
if (ClientKeyData.result !== 0) {
throw new Error('getClientKey Error');
} }
const clientKey = ClientKeyData.clientKey;
const keyIndex = ClientKeyData.keyIndex;
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + clientKey + '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=19%27';
let cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
const skey = cookies['skey'];
if (!skey) {
throw new Error('getSkey Skey is Empty');
}
return skey;
}
async getUidByUin(Uin: string) {
//此代码仅临时使用,后期会被废弃
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return await this.getUidByUinV2(Uin);
}
return await this.getUidByUinV1(Uin);
}
async getUinByUid(Uid: string) {
//此代码仅临时使用,后期会被废弃
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return await this.getUinByUidV2(Uid);
}
return await this.getUinByUidV1(Uid);
}
//后期改成流水线处理 async like(uid: string, count = 1): Promise<{ result: number, errMsg: string, succCounts: number }> {
async getUidByUinV2(Uin: string) { return this.context.session.getProfileLikeService().setBuddyProfileLike({
let uid = (await this.context.session.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])).get(Uin); friendUid: uid,
if (uid) return uid; sourceId: 71,
uid = (await this.context.session.getGroupService().getUidByUins([Uin])).uids.get(Uin); doLikeCount: count,
if (uid) return uid; doLikeTollCount: 0,
uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin); });
if (uid) return uid; }
console.log((await this.core.getApiContext().FriendApi.getBuddyIdMapCache(true)));
uid = (await this.core.getApiContext().FriendApi.getBuddyIdMapCache(true)).getValue(Uin);//从Buddy缓存获取Uid
if (uid) return uid;
uid = (await this.core.getApiContext().FriendApi.getBuddyIdMap(true)).getValue(Uin);
if (uid) return uid;
let unveifyUid = (await this.getUserDetailInfoByUinV2(Uin)).detail.uid;//从QQ Native 特殊转换
if (unveifyUid.indexOf("*") == -1) uid = unveifyUid;
//if (uid) return uid;
return uid;
}
//后期改成流水线处理
async getUinByUidV2(Uid: string) {
let uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
if (uin) return uin;
uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
if (uin) return uin;
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
if (uin) return uin;
uin = (await this.core.getApiContext().FriendApi.getBuddyIdMapCache(true)).getKey(Uid);//从Buddy缓存获取Uin
if (uin) return uin;
uin = (await this.core.getApiContext().FriendApi.getBuddyIdMap(true)).getKey(Uid);
if (uin) return uin;
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
return uin;
}
async getUidByUinV1(Uin: string) { async setQQAvatar(filePath: string) {
// 通用转换开始尝试 type setQQAvatarRet = { result: number, errMsg: string };
let uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin); const ret = await this.context.session.getProfileService().setHeader(filePath) as setQQAvatarRet;
if (!uid) { return { result: ret?.result, errMsg: ret?.errMsg };
let unveifyUid = (await this.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
if (unveifyUid.indexOf("*") == -1) {
uid = unveifyUid;
}
} }
return uid;
} async setGroupAvatar(gc: string, filePath: string) {
async getUinByUidV1(Uid: string) { return this.context.session.getGroupService().setHeader(gc, filePath);
let ret = await this.core.eventWrapper.callNoListenerEvent }
<(Uin: string[]) => Promise<{ uinInfo: Map<string, string> }>>(
'NodeIKernelUixConvertService/getUin', async fetchUserDetailInfos(uids: string[]) {
5000, //26702 以上使用新接口 .Dev Mlikiowa
[Uid] type EventService = NodeIKernelProfileService['fetchUserDetailInfo'];
); type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
let uin = ret.uinInfo.get(Uid); const retData: User[] = [];
if (!uin) { const [_retData, _retListener] = await this.core.eventWrapper.CallNormalEvent<
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换 EventService, EventListener
>(
'NodeIKernelProfileService/fetchUserDetailInfo',
'NodeIKernelProfileListener/onUserDetailInfoChanged',
uids.length,
5000,
(profile) => {
if (uids.includes(profile.uid)) {
const RetUser: User = {
...profile.simpleInfo.coreInfo,
...profile.simpleInfo.status,
...profile.simpleInfo.vasInfo,
...profile.commonExt,
...profile.simpleInfo.baseInfo,
qqLevel: profile.commonExt.qqLevel,
pendantId: '',
};
retData.push(RetUser);
return true;
}
return false;
},
'BuddyProfileStore',
uids,
UserDetailSource.KSERVER,
[ProfileBizType.KALL],
);
return retData;
}
async fetchUserDetailInfo(uid: string) {
type EventService = NodeIKernelProfileService['fetchUserDetailInfo'];
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
const [_retData, profile] = await this.core.eventWrapper.CallNormalEvent<EventService, EventListener>(
'NodeIKernelProfileService/fetchUserDetailInfo',
'NodeIKernelProfileListener/onUserDetailInfoChanged',
1,
5000,
(profile) => profile.uid === uid,
'BuddyProfileStore',
[uid],
UserDetailSource.KSERVER,
[ProfileBizType.KALL],
);
const RetUser: User = {
...profile.simpleInfo.coreInfo,
...profile.simpleInfo.status,
...profile.simpleInfo.vasInfo,
...profile.commonExt,
...profile.simpleInfo.baseInfo,
qqLevel: profile.commonExt.qqLevel,
pendantId: '',
};
return RetUser;
}
async getUserDetailInfo(uid: string) {
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return this.fetchUserDetailInfo(uid);
}
return this.getUserDetailInfoOld(uid);
}
async getUserDetailInfoOld(uid: string) {
type EventService = NodeIKernelProfileService['getUserDetailInfoWithBizInfo'];
type EventListener = NodeIKernelProfileListener['onProfileDetailInfoChanged'];
const [_retData, profile] = await this.core.eventWrapper.CallNormalEvent<EventService, EventListener>(
'NodeIKernelProfileService/getUserDetailInfoWithBizInfo',
'NodeIKernelProfileListener/onProfileDetailInfoChanged',
2,
5000,
(profile) => profile.uid === uid,
uid,
[0],
);
return profile;
}
async modifySelfProfile(param: ModifyProfileParams) {
return this.context.session.getProfileService().modifyDesktopMiniProfile(param);
}
//需要异常处理
async getCookies(domain: string) {
const ClientKeyData = await this.forceFetchClientKey();
const requestUrl = `https://ssl.ptlogin2.qq.com/jump?${
new URLSearchParams({
ptlang: '1033',
clientuin: this.core.selfInfo.uin,
clientkey: ClientKeyData.clientKey,
u1: `https://user.qzone.qq.com/${this.core.selfInfo.uin}/infocenter`,
keyindex: '19',
})
}`;
return await RequestUtil.HttpsGetCookies(requestUrl);
}
async getPSkey(domainList: string[]) {
return await this.context.session.getTipOffService().getPskey(domainList, true);
}
async getRobotUinRange(): Promise<Array<any>> {
const robotUinRanges = await this.context.session.getRobotService().getRobotUinRange({
justFetchMsgConfig: '1',
type: 1,
version: 0,
aioKeywordVersion: 0,
});
// console.log(robotUinRanges?.response?.robotUinRanges);
return robotUinRanges?.response?.robotUinRanges;
}
//需要异常处理
async getQzoneCookies() {
const ClientKeyData = await this.forceFetchClientKey();
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27';
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
return cookies;
}
//需要异常处理
async getSkey(): Promise<string | undefined> {
const ClientKeyData = await this.forceFetchClientKey();
if (ClientKeyData.result !== 0) {
throw new Error('getClientKey Error');
}
const clientKey = ClientKeyData.clientKey;
const keyIndex = ClientKeyData.keyIndex;
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + clientKey + '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=19%27';
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
const skey = cookies['skey'];
if (!skey) {
throw new Error('getSkey Skey is Empty');
}
return skey;
}
/**
* @deprecated
*/
async getUidByUin(Uin: string) {
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return await this.getUidByUinV2(Uin);
}
return await this.getUidByUinV1(Uin);
}
/**
* @deprecated
*/
async getUinByUid(Uid: string) {
if (this.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
return await this.getUinByUidV2(Uid);
}
return await this.getUinByUidV1(Uid);
}
//后期改成流水线处理
async getUidByUinV2(Uin: string) {
let uid = (await this.context.session.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])).get(Uin);
if (uid) return uid;
uid = (await this.context.session.getGroupService().getUidByUins([Uin])).uids.get(Uin);
if (uid) return uid;
uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
if (uid) return uid;
console.log((await this.core.getApiContext().FriendApi.getBuddyIdMapCache(true)));
uid = (await this.core.getApiContext().FriendApi.getBuddyIdMapCache(true)).getValue(Uin);//从Buddy缓存获取Uid
if (uid) return uid;
uid = (await this.core.getApiContext().FriendApi.getBuddyIdMap(true)).getValue(Uin);
if (uid) return uid;
const unveifyUid = (await this.getUserDetailInfoByUinV2(Uin)).detail.uid;//从QQ Native 特殊转换
if (unveifyUid.indexOf('*') == -1) uid = unveifyUid;
//if (uid) return uid;
return uid;
}
//后期改成流水线处理
async getUinByUidV2(Uid: string) {
let uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
if (uin) return uin;
uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
if (uin) return uin;
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
if (uin) return uin;
uin = (await this.core.getApiContext().FriendApi.getBuddyIdMapCache(true)).getKey(Uid);//从Buddy缓存获取Uin
if (uin) return uin;
uin = (await this.core.getApiContext().FriendApi.getBuddyIdMap(true)).getKey(Uid);
if (uin) return uin;
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
return uin;
}
async getUidByUinV1(Uin: string) {
// 通用转换开始尝试
let uid = (await this.context.session.getUixConvertService().getUid([Uin])).uidInfo.get(Uin);
if (!uid) {
const unveifyUid = (await this.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
if (unveifyUid.indexOf('*') == -1) {
uid = unveifyUid;
}
}
return uid;
}
async getUinByUidV1(Uid: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent<(Uin: string[]) => Promise<{ uinInfo: Map<string, string> }>>
('NodeIKernelUixConvertService/getUin', 5000, [Uid]);
let uin = ret.uinInfo.get(Uid);
if (!uin) {
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
}
// if (!uin) {
// uin = (await NTQQFriendApi.getFriends(false)).find((t) => { t.uid == Uid })?.uin; //从QQ Native 缓存转换
// }
// if (!uin) {
// uin = (await NTQQFriendApi.getFriends(true)).find((t) => { t.uid == Uid })?.uin; //从QQ Native 非缓存转换
// }
return uin;
}
async getRecentContactListSnapShot(count: number) {
return await this.context.session.getRecentContactService().getRecentContactListSnapShot(count);
}
async getRecentContactListSyncLimit(count: number) {
return await this.context.session.getRecentContactService().getRecentContactListSyncLimit(count);
}
async getRecentContactListSync() {
return await this.context.session.getRecentContactService().getRecentContactListSync();
}
async getRecentContactList() {
return await this.context.session.getRecentContactService().getRecentContactList();
}
async getUserDetailInfoByUinV2(Uin: string) {
return await this.core.eventWrapper.callNoListenerEvent<(Uin: string) => Promise<UserDetailInfoByUinV2>>
('NodeIKernelProfileService/getUserDetailInfoByUin', 5000, Uin);
}
async getUserDetailInfoByUin(Uin: string) {
return this.core.eventWrapper.callNoListenerEvent<(Uin: string) => Promise<UserDetailInfoByUin>>
('NodeIKernelProfileService/getUserDetailInfoByUin', 5000, Uin);
}
async forceFetchClientKey() {
return await this.context.session.getTicketService().forceFetchClientKey('');
} }
// if (!uin) {
// uin = (await NTQQFriendApi.getFriends(false)).find((t) => { t.uid == Uid })?.uin; //从QQ Native 缓存转换
// }
// if (!uin) {
// uin = (await NTQQFriendApi.getFriends(true)).find((t) => { t.uid == Uid })?.uin; //从QQ Native 非缓存转换
// }
return uin;
}
async getRecentContactListSnapShot(count: number) {
return await this.context.session.getRecentContactService().getRecentContactListSnapShot(count);
}
async getRecentContactListSyncLimit(count: number) {
return await this.context.session.getRecentContactService().getRecentContactListSyncLimit(count);
}
async getRecentContactListSync() {
return await this.context.session.getRecentContactService().getRecentContactListSync();
}
async getRecentContactList() {
return await this.context.session.getRecentContactService().getRecentContactList();
}
async getUserDetailInfoByUinV2(Uin: string) {
return await this.core.eventWrapper.callNoListenerEvent
<(Uin: string) => Promise<UserDetailInfoByUinV2>>(
'NodeIKernelProfileService/getUserDetailInfoByUin',
5000,
Uin
);
}
async getUserDetailInfoByUin(Uin: string) {
return this.core.eventWrapper.callNoListenerEvent
<(Uin: string) => Promise<UserDetailInfoByUin>>(
'NodeIKernelProfileService/getUserDetailInfoByUin',
5000,
Uin
);
}
async forceFetchClientKey() {
return await this.context.session.getTicketService().forceFetchClientKey('');
}
} }