From fccb0852aa0d9ee813034dc631f7b86e13f3d2f3 Mon Sep 17 00:00:00 2001
From: linyuchen <lin.yu.chen@foxmail.com>
Date: Fri, 15 Mar 2024 18:54:56 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=B8=BB=E5=8A=A8?=
 =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=A2=AB=E8=BF=87=E6=BB=A4=E7=9A=84=E5=8A=A0?=
 =?UTF-8?q?=E7=BE=A4=E9=80=9A=E7=9F=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 manifest.json                                 |  4 +-
 src/common/data.ts                            | 18 +++----
 src/common/utils.ts                           |  8 ++-
 src/main/main.ts                              |  6 +--
 src/ntqqapi/ntcall.ts                         | 49 +++++++++++++++----
 src/ntqqapi/types.ts                          |  8 ++-
 src/onebot11/action/index.ts                  |  2 +
 .../action/llonebot/GetGroupAddRequest.ts     | 32 ++++++++++++
 src/onebot11/action/types.ts                  |  1 +
 src/version.ts                                |  2 +-
 10 files changed, 102 insertions(+), 28 deletions(-)
 create mode 100644 src/onebot11/action/llonebot/GetGroupAddRequest.ts

diff --git a/manifest.json b/manifest.json
index 69d0f1b..a0b3932 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,10 +1,10 @@
 {
   "manifest_version": 4,
   "type": "extension",
-  "name": "LLOneBot v3.14.1",
+  "name": "LLOneBot v3.15.0",
   "slug": "LLOneBot",
   "description": "LiteLoaderQQNT的OneBotApi,不支持商店在线更新",
-  "version": "3.14.1",
+  "version": "3.15.0",
   "icon": "./icon.jpg",
   "authors": [
     {
diff --git a/src/common/data.ts b/src/common/data.ts
index 30f1b53..b47d7c9 100644
--- a/src/common/data.ts
+++ b/src/common/data.ts
@@ -11,7 +11,7 @@ import {
 import {type FileCache, type LLOneBotError} from './types'
 import {dbUtil} from "./db";
 import {raw} from "express";
-import {log} from "./utils";
+import {isNumeric, log} from "./utils";
 
 export const selfInfo: SelfInfo = {
     uid: '',
@@ -28,9 +28,9 @@ export const llonebotError: LLOneBotError = {
 }
 
 
-export async function getFriend(qq: string, uid: string = ""): Promise<Friend | undefined> {
-    let filterKey = uid ? "uid" : "uin"
-    let filterValue = uid ? uid : qq
+export async function getFriend(uinOrUid: string): Promise<Friend | undefined> {
+    let filterKey = isNumeric(uinOrUid) ? "uin" : "uid"
+    let filterValue = uinOrUid
     let friend = friends.find(friend => friend[filterKey] === filterValue.toString())
     // if (!friend) {
     //     try {
@@ -59,15 +59,13 @@ export async function getGroup(qq: string): Promise<Group | undefined> {
     return group
 }
 
-export async function getGroupMember(groupQQ: string | number, memberQQ: string | number, memberUid: string = null) {
+export async function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number) {
     groupQQ = groupQQ.toString()
-    if (memberQQ) {
-        memberQQ = memberQQ.toString()
-    }
+    memberUinOrUid = memberUinOrUid.toString()
     const group = await getGroup(groupQQ)
     if (group) {
-        const filterKey = memberQQ ? "uin" : "uid"
-        const filterValue = memberQQ ? memberQQ : memberUid
+        const filterKey = isNumeric(memberUinOrUid) ? "uin" : "uid"
+        const filterValue = memberUinOrUid
         let filterFunc: (member: GroupMember) => boolean = member => member[filterKey] === filterValue
         let member = group.members?.find(filterFunc)
         if (!member) {
diff --git a/src/common/utils.ts b/src/common/utils.ts
index 81a126d..c6904ab 100644
--- a/src/common/utils.ts
+++ b/src/common/utils.ts
@@ -32,6 +32,11 @@ function truncateString(obj: any, maxLength = 500) {
     return obj;
 }
 
+export function isNumeric(str: string) {
+    return /^\d+$/.test(str);
+}
+
+
 export function log(...msg: any[]) {
     if (!getConfigUtil().getConfig().log) {
         return //console.log(...msg);
@@ -225,8 +230,7 @@ export async function encodeSilk(filePath: string) {
             const pcm = fs.readFileSync(filePath);
             const silk = await encode(pcm, 0);
             fs.writeFileSync(pttPath, silk.data);
-            // fs.unlink(wavPath, (err) => {
-            // });
+            fs.unlink(wavPath, (err) => { });
             log(`语音文件${filePath}转换成功!`, pttPath)
             return {
                 converted: true,
diff --git a/src/main/main.ts b/src/main/main.ts
index c6a1a89..fc769da 100644
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -148,7 +148,7 @@ function onLoad() {
                         let operatorId = message.senderUin
                         for (const element of message.elements) {
                             const operatorUid = element.grayTipElement?.revokeElement.operatorUid
-                            const operator = await getGroupMember(message.peerUin, null, operatorUid)
+                            const operator = await getGroupMember(message.peerUin, operatorUid)
                             operatorId = operator.uin
                         }
                         const groupRecallEvent = new OB11GroupRecallNoticeEvent(
@@ -215,7 +215,7 @@ function onLoad() {
                         //     member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid);
                         // }
                         if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET].includes(notify.type)) {
-                            const member1 = await getGroupMember(notify.group.groupCode, null, notify.user1.uid);
+                            const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid);
                             log("有管理员变动通知");
                             refreshGroupMembers(notify.group.groupCode).then()
                             let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent()
@@ -253,7 +253,7 @@ function onLoad() {
                             log("收到邀请我加群通知")
                             let groupInviteEvent = new OB11GroupRequestEvent();
                             groupInviteEvent.group_id = parseInt(notify.group.groupCode);
-                            let user_id = (await getFriend("", notify.user2.uid))?.uin
+                            let user_id = (await getFriend(notify.user2.uid))?.uin
                             if (!user_id) {
                                 user_id = (await NTQQApi.getUserDetailInfo(notify.user2.uid))?.uin
                             }
diff --git a/src/ntqqapi/ntcall.ts b/src/ntqqapi/ntcall.ts
index 872de10..89e99d7 100644
--- a/src/ntqqapi/ntcall.ts
+++ b/src/ntqqapi/ntcall.ts
@@ -1,4 +1,4 @@
-import {ipcMain} from "electron";
+import {BrowserWindow, ipcMain} from "electron";
 import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
 import {log, sleep} from "../common/utils";
 import {
@@ -42,6 +42,7 @@ export enum NTQQApiClass {
     NT_API = "ns-ntApi",
     FS_API = "ns-FsApi",
     OS_API = "ns-OsApi",
+    WINDOW_API = "ns-WindowApi",
     HOTUPDATE_API = "ns-HotUpdateApi",
     BUSINESS_API = "ns-BusinessApi",
     GLOBAL_DATA = "ns-GlobalDataApi"
@@ -93,6 +94,8 @@ export enum NTQQApiMethod {
     CACHE_CHAT_GET = 'nodeIKernelStorageCleanService/getChatCacheInfo',
     CACHE_FILE_GET = 'nodeIKernelStorageCleanService/getFileCacheInfo',
     CACHE_CHAT_CLEAR = 'nodeIKernelStorageCleanService/clearChatCacheInfo',
+
+    OPEN_EXTRA_WINDOW = 'openExternalWindow',
 }
 
 enum NTQQApiChannel {
@@ -203,12 +206,13 @@ interface GeneralCallResult {
 
 
 export class NTQQApi {
-    static async setHeader(path: string){
+    static async setHeader(path: string) {
         return await callNTQQApi<GeneralCallResult>({
             methodName: NTQQApiMethod.SET_HEADER,
             args: [path]
         })
     }
+
     static async likeFriend(uid: string, count = 1) {
         return await callNTQQApi<GeneralCallResult>({
             methodName: NTQQApiMethod.LIKE_FRIEND,
@@ -256,7 +260,11 @@ export class NTQQApi {
                 null
             ]
         })
-        return result.info
+        const info = result.info
+        if (info?.uin) {
+            uidMaps[info.uid] = info.uin
+        }
+        return info
     }
 
     static async getFriends(forced = false) {
@@ -482,8 +490,7 @@ export class NTQQApi {
                     if ((await dbUtil.getMsgByLongId(sentMessage.msgId)).sendStatus == 2) {
                         return sentMessage
                     }
-                }
-                else{
+                } else {
                     return sentMessage
                 }
                 // log(`给${peerUid}发送消息成功`)
@@ -510,7 +517,7 @@ export class NTQQApi {
     static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
         return await callNTQQApi<GeneralCallResult>({
             methodName: NTQQApiMethod.FORWARD_MSG,
-            args:[
+            args: [
                 {
                     msgIds: msgIds,
                     srcContact: srcPeer,
@@ -525,6 +532,7 @@ export class NTQQApi {
         })
 
     }
+
     static async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
         const msgInfos = msgIds.map(id => {
             return {msgId: id, senderShowName: selfInfo.nick}
@@ -596,6 +604,29 @@ export class NTQQApi {
         });
     }
 
+    static async getGroupIgnoreNotifies() {
+        await NTQQApi.getGroupNotifies();
+        const result = callNTQQApi<GroupNotifies>({
+            className: NTQQApiClass.WINDOW_API,
+            methodName: NTQQApiMethod.OPEN_EXTRA_WINDOW,
+            cbCmd: ReceiveCmd.GROUP_NOTIFY,
+            afterFirstCmd: false,
+            args: [
+                "GroupNotifyFilterWindow"
+            ]
+        })
+        // 关闭窗口
+        setTimeout(() => {
+            for (const w of BrowserWindow.getAllWindows()) {
+                // log("close window", w.webContents.getURL())
+                if (w.webContents.getURL().indexOf("#/notify-filter/") != -1) {
+                    w.close();
+                }
+            }
+        }, 2000);
+        return result;
+    }
+
     static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
         const notify: GroupNotify = await dbUtil.getGroupNotify(seq)
         if (!notify) {
@@ -815,7 +846,7 @@ export class NTQQApi {
         });
     }
 
-    static clearCache(cacheKeys: Array<string> = [ 'tmp', 'hotUpdate' ]) {
+    static clearCache(cacheKeys: Array<string> = ['tmp', 'hotUpdate']) {
         return callNTQQApi<any>({ // TODO: 目前还不知道真正的返回值是什么
             methodName: NTQQApiMethod.CACHE_CLEAR,
             args: [{
@@ -835,12 +866,12 @@ export class NTQQApi {
                     pageIndex
                 }, null]
             }).then(list => res(list))
-            .catch(e => rej(e));
+                .catch(e => rej(e));
         });
     }
 
     static getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
-        const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
+        const _lastRecord = lastRecord ? lastRecord : {fileType: fileType};
 
         return callNTQQApi<CacheFileList>({
             methodName: NTQQApiMethod.CACHE_FILE_GET,
diff --git a/src/ntqqapi/types.ts b/src/ntqqapi/types.ts
index 6b5e46f..743b6df 100644
--- a/src/ntqqapi/types.ts
+++ b/src/ntqqapi/types.ts
@@ -392,11 +392,17 @@ export interface GroupNotifies {
     notifies: GroupNotify[],
 }
 
+export enum GroupNotifyStatus {
+    IGNORE = 0,
+    WAIT_HANDLE = 1,
+    APPROVE = 2,
+    REJECT = 3
+}
 export interface GroupNotify {
     time: number;  // 自己添加的字段,时间戳,毫秒, 用于判断收到短时间内收到重复的notify
     seq: string, // 唯一标识符,转成数字再除以1000应该就是时间戳?
     type: GroupNotifyTypes,
-    status: 0,  // 未知
+    status: GroupNotifyStatus,  // 0是已忽略?,1是未处理,2是已同意
     group: { groupCode: string, groupName: string },
     user1: { uid: string, nickName: string }, // 被设置管理员的人
     user2: { uid: string, nickName: string },  // 操作者
diff --git a/src/onebot11/action/index.ts b/src/onebot11/action/index.ts
index 6740960..b01359b 100644
--- a/src/onebot11/action/index.ts
+++ b/src/onebot11/action/index.ts
@@ -34,11 +34,13 @@ import GoCQHTTPMarkMsgAsRead from "./MarkMsgAsRead";
 import CleanCache from "./CleanCache";
 import GoCQHTTPUploadGroupFile from "./go-cqhttp/UploadGroupFile";
 import {GetConfigAction, SetConfigAction} from "./llonebot/Config";
+import GetGroupAddRequest from "./llonebot/GetGroupAddRequest";
 
 export const actionHandlers = [
     new Debug(),
     new GetConfigAction(),
     new SetConfigAction(),
+    new GetGroupAddRequest(),
     // onebot11
     new SendLike(),
     new GetMsg(),
diff --git a/src/onebot11/action/llonebot/GetGroupAddRequest.ts b/src/onebot11/action/llonebot/GetGroupAddRequest.ts
new file mode 100644
index 0000000..059c289
--- /dev/null
+++ b/src/onebot11/action/llonebot/GetGroupAddRequest.ts
@@ -0,0 +1,32 @@
+import {GroupNotify, GroupNotifyStatus} from "../../../ntqqapi/types";
+import BaseAction from "../BaseAction";
+import {ActionName} from "../types";
+import {NTQQApi} from "../../../ntqqapi/ntcall";
+import {uidMaps} from "../../../common/data";
+import {log} from "../../../common/utils";
+
+interface OB11GroupRequestNotify {
+    group_id: number,
+    user_id: number,
+    flag: string
+}
+
+export default class GetGroupAddRequest extends BaseAction<null, OB11GroupRequestNotify[]> {
+    actionName = ActionName.GetGroupIgnoreAddRequest
+
+    protected async _handle(payload: null): Promise<OB11GroupRequestNotify[]> {
+        const data = await NTQQApi.getGroupIgnoreNotifies()
+        log(data);
+        let notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE);
+        let returnData: OB11GroupRequestNotify[] = []
+        for (const notify of notifies) {
+            const uin = uidMaps[notify.user1.uid] || (await NTQQApi.getUserDetailInfo(notify.user1.uid))?.uin
+            returnData.push({
+                group_id: parseInt(notify.group.groupCode),
+                user_id: parseInt(uin),
+                flag: notify.seq
+            })
+        }
+        return returnData;
+    }
+}
\ No newline at end of file
diff --git a/src/onebot11/action/types.ts b/src/onebot11/action/types.ts
index e170890..112b0c2 100644
--- a/src/onebot11/action/types.ts
+++ b/src/onebot11/action/types.ts
@@ -14,6 +14,7 @@ export interface InvalidCheckResult {
 }
 
 export enum ActionName {
+    GetGroupIgnoreAddRequest = "get_group_ignore_add_request",
     GetConfig = "get_config",
     SetConfig = "set_config",
     Debug = "llonebot_debug",
diff --git a/src/version.ts b/src/version.ts
index 943ebf4..b9f51bb 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const version = "3.14.1"
\ No newline at end of file
+export const version = "3.15.0"
\ No newline at end of file