diff --git a/package.json b/package.json index 9251451..c9e7f6f 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build-mac": "tsc && npm run deploy-mac", + "build": "tsc & tsc -p src/tsconfig.json", + "build-mac": "npm run build && npm run deploy-mac", "deploy-mac": "cp dist/* ~/Library/Containers/com.tencent.qq/Data/Documents/LiteLoaderQQNT/plugins/LLOnebot/", - "build-win": "tsc && npm run deploy-win", + "build-win": "npm run build && npm run deploy-win", "deploy-win": "cmd /c \"copy dist\\* %USERPROFILE%\\documents\\LiteLoaderQQNT\\plugins\\LLOnebot\\\"" }, "author": "", diff --git a/src/global.d.ts b/src/global.d.ts index 76301a4..96ebbbe 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -31,7 +31,7 @@ declare var llonebot: { updateFriends: (friends: User[]) => void updateGroupMembers: (data: { groupMembers: User[], group_id: string }) => void startExpress: () => void - log(data: any): void + log(data: any): void, }; declare global { diff --git a/src/llapi/renderer.js b/src/llapi/renderer.js index a79443a..665a904 100644 --- a/src/llapi/renderer.js +++ b/src/llapi/renderer.js @@ -605,10 +605,10 @@ class Destructor { elementId: "", textElement: { content: element.content, - atType: 0, - atUid: "", + atType: element.atType || 0, + atUid: element.atUid || "", atTinyId: "", - atNtUid: "", + atNtUid: element.atNtUid, }, }; } diff --git a/src/main.ts b/src/main.ts index f6d628d..b464947 100644 --- a/src/main.ts +++ b/src/main.ts @@ -66,7 +66,14 @@ function startExpress(event: any) { resData["data"] = groups.map(group => { return { group_id: group.uid, - group_name: group.name + group_name: group.name, + group_members: group.members.map(member => { + return { + user_id: member.uin, + user_name: member.cardName || member.nick, + user_display_name: member.cardName || member.nick + } + }) } }) } @@ -74,10 +81,29 @@ function startExpress(event: any) { let group = groups.find(group => group.uid == jsonData.params.group_id) if (group){ resData["data"] = group?.members?.map(member => { + let role = "member" + switch (member.role) { + case 4: { + role = "owner" + break; + } + case 3:{ + role = "admin" + break + } + case 2:{ + role = "member" + break + } + + } return { user_id: member.uin, - user_name: member.cardName || member.nick, - user_display_name: member.cardName || member.nick + user_name: member.nick, + user_display_name: member.cardName || member.nick, + nickname: member.nick, + card: member.cardName, + role } }) || [] @@ -96,7 +122,7 @@ function startExpress(event: any) { } res.send(resData) }); - app.listen(port, () => { + app.listen(port,"0.0.0.0", () => { console.log(`服务器已启动,监听端口 ${port}`); }); } @@ -109,6 +135,28 @@ function onLoad(plugin: any) { }) ipcMain.on("updateGroups", (event: any, arg: Group[]) => { + for(const group of arg){ + let existGroup = groups.find(g => g.uid == group.uid) + if (existGroup){ + if (!existGroup.members){ + existGroup.members = [] + } + existGroup.name = group.name + for (const member of group.members || []){ + let existMember = existGroup.members?.find(m => m.uin == member.uin) + if (existMember){ + existMember.nick = member.nick + existMember.cardName = member.cardName + } + else{ + existGroup.members?.push(member) + } + } + } + else{ + groups.push(group) + } + } groups = arg }) diff --git a/src/renderer.ts b/src/renderer.ts index c1d97b9..bfaa4a9 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -2,7 +2,8 @@ // import express from "express"; // const { ipcRenderer } = require('electron'); -import {Group, MessageElement, Peer, PostDataSendMsg, User} from "./types"; +import {AtType, Group, MessageElement, Peer, PostDataSendMsg, User} from "./types"; + const host = "http://localhost:5000" @@ -50,12 +51,13 @@ async function getGroups() { async function getGroupMembers(group_qq: string, forced: boolean = false) { let group = await getGroup(group_qq) if (!group?.members || group!.members!.length == 0 || forced) { - let res = (await window.LLAPI.getGroupMemberList(group_qq + "_groupMemberList_MainWindow", 5000)) + let res = (await window.LLAPI.getGroupMemberList(group_qq, 5000)) // console.log(`更新群${group}成员列表 await`, _res) // window.LLAPI.getGroupMemberList(group_qq + "_groupMemberList_MainWindow", 5000).then(res =>{ let members = res.result.infos.values(); + console.log("getGroupMemberList api response:", res) if (members && forced) { - group!.members = [] + group.members = [] } for (const member of members) { if (!group!.members!.find(m => m.uid == member.uid)) { @@ -63,7 +65,7 @@ async function getGroupMembers(group_qq: string, forced: boolean = false) { } } window.llonebot.updateGroups(groups) - console.log(`更新群${group}成员列表`, group) + console.log(`更新群${group.name}成员列表`, group) // }) } return group?.members @@ -89,8 +91,11 @@ async function forwardMessage(message: MessageElement) { platform: "qq", user_id: self_qq }, + self_id: self_qq, time: 0, type: "message", + post_type: "message", + message_type: message.peer.chatType, detail_type: message.peer.chatType, sub_type: "", message: [] @@ -111,28 +116,27 @@ async function forwardMessage(message: MessageElement) { data: {}, type: "unknown" } - - if (element.textElement?.atType == 2) { - message_data["type"] = "at" - if (element.textElement.atUid != "0") { - message_data["data"]["mention"] = element.textElement.atUid - } else { - let uid = element.textElement.atNtUid - let atMember = await getGroupMember(message.peer.uid, uid) - message_data["data"]["mention"] = atMember!.uin + if (element.textElement?.atType == 2) { + message_data["type"] = "at" + if (element.textElement.atUid != "0") { + message_data["data"]["mention"] = element.textElement.atUid + } else { + let uid = element.textElement.atNtUid + let atMember = await getGroupMember(message.peer.uid, uid) + message_data["data"]["mention"] = atMember!.uin + } + } else if (element.textElement) { + message_data["type"] = "text" + message_data["data"]["text"] = element.textElement.content + } else if (element.picElement) { + message_data["type"] = "image" + message_data["data"]["file_id"] = element.picElement.fileUuid + message_data["data"]["path"] = element.picElement.sourcePath + } else if (element.replyElement) { + message_data["type"] = "reply" + message_data["data"]["reply"] = element.replyElement.sourceMsgIdInRecords } - } else if (element.textElement) { - message_data["type"] = "text" - message_data["data"]["text"] = element.textElement.content - } else if (element.picElement) { - message_data["type"] = "image" - message_data["data"]["file_id"] = element.picElement.fileUuid - message_data["data"]["path"] = element.picElement.sourcePath - } else if (element.replyElement) { - message_data["type"] = "reply" - message_data["data"]["reply"] = element.replyElement.sourceMsgIdInRecords - } - onebot_message_data.message.push(message_data) + onebot_message_data.message.push(message_data) } console.log("发送上传消息给ipc main", onebot_message_data) @@ -169,11 +173,20 @@ async function listenSendMessage(postData: PostDataSendMsg) { name: group.name, uid: group.uid } + for (let message of postData.params.message){ + if (message.type == "text" && message.atType == 2){ + let atUid = message.atUid + let group = await getGroup(postData.params.group_id) + let atMember = group.members.find(member => member.uin == atUid) + message.atNtUid = atMember.uid + } + } } else { console.log("未找到群, 发送群消息失败", postData) } } if (peer) { + console.log("发送消息", postData) window.LLAPI.sendMessage(peer, postData.params.message).then(res => console.log("消息发送成功:", res), err => console.log("消息发送失败", postData, err)) } @@ -187,7 +200,28 @@ function onLoad() { window.llonebot.listenSendMessage((postData: PostDataSendMsg) => { listenSendMessage(postData).then() }); - getGroups().then() + + async function getGroupsMembers(groupsArg: Group[]) { + // 批量获取群成员列表 + let failedGroups: Group[] = [] + for (const group of groupsArg) { + let handledGroup = await getGroupMembers(group.uid, true) + if (handledGroup.length == 0) { + failedGroups.push(group) + } + } + if (failedGroups.length > 0) { + console.log("获取群成员列表失败,重试", failedGroups.map(group => group.name)) + setTimeout(() => { + getGroupsMembers(failedGroups).then() + }, 1000) + } + else{ + console.log("全部群成员获取完毕", groups) + } + } + + function onNewMessages(messages: MessageElement[]) { async function func(messages: MessageElement[]) { @@ -203,41 +237,51 @@ function onLoad() { console.log("chatListEle", chatListEle) } - window.LLAPI.on("new-messages", onNewMessages); - - try { - window.LLAPI.add_qmenu((qContextMenu: Node) => { - let btn = document.createElement("a") - btn.className = "q-context-menu-item q-context-menu-item--normal vue-component" - btn.setAttribute("aria-disabled", "false") - btn.setAttribute("role", "menuitem") - btn.setAttribute("tabindex", "-1") - btn.onclick = ()=>{ - // window.LLAPI.getPeer().then(peer => { - // // console.log("current peer", peer) - // if (peer && peer.chatType == "group") { - // getGroupMembers(peer.uid, true).then(()=> { - // console.log("获取群成员列表成功", groups); - // alert("获取群成员列表成功") - // }) - // } - // }) - window.LLAPI.getGroupMemberList("164461995", 5000).then(res =>{ - console.log("获取群成员列表结果", res) - }) - } - btn.innerText = "获取群成员列表" - console.log(qContextMenu) - // qContextMenu.appendChild(btn) - // qContextMenu.insertAdjacentHTML("beforeend", btn) + getGroups().then(()=>{ + getGroupsMembers(groups).then(()=>{ + window.LLAPI.on("new-messages", onNewMessages); }) - }catch (e){ - console.log(e) - } + }) + + window.LLAPI.add_qmenu((qContextMenu: Node) => { + let btn = document.createElement("a") + btn.className = "q-context-menu-item q-context-menu-item--normal vue-component" + btn.setAttribute("aria-disabled", "false") + btn.setAttribute("role", "menuitem") + btn.setAttribute("tabindex", "-1") + btn.onclick = ()=>{ + // window.LLAPI.getPeer().then(peer => { + // // console.log("current peer", peer) + // if (peer && peer.chatType == "group") { + // getGroupMembers(peer.uid, true).then(()=> { + // console.log("获取群成员列表成功", groups); + // alert("获取群成员列表成功") + // }) + // } + // }) + async function func() { + for (const group of groups) { + await getGroupMembers(group.uid, true) + } + } + func().then(()=> { + console.log("获取群成员列表结果", groups); + // 找到members数量为空的群 + groups.map(group => { + if (group.members.length == 0) { + console.log(`${group.name}群成员为空`) + } + }) + window.llonebot.updateGroups(groups) + }) + } + btn.innerText = "获取群成员列表" + console.log(qContextMenu) + qContextMenu.appendChild(btn) + }) window.LLAPI.on("context-msg-menu", (event, target, msgIds) => { - // console.log("msg menu", event, target, msgIds); - // 消息右键菜单添加一个获取群成员列表的按钮 + console.log("msg menu", event, target, msgIds); }) // console.log("getAccountInfo", LLAPI.getAccountInfo()); @@ -247,33 +291,33 @@ function onLoad() { if (chatListEle.length == 0) { setTimeout(getChatListEle, 500) } else { - // try { - // // 选择要观察的目标节点 - // const targetNode = chatListEle[0]; - // - // // 创建一个观察器实例并传入回调函数 - // const observer = new MutationObserver(function (mutations) { - // mutations.forEach(function (mutation) { - // // console.log("chat list changed", mutation.type); // 输出 mutation 的类型 - // // 获得当前聊天窗口 - // window.LLAPI.getPeer().then(peer => { - // // console.log("current peer", peer) - // if (peer && peer.chatType == "group"){ - // getGroupMembers(peer.uid, false).then() - // } - // }) - // }); - // }); - // - // // 配置观察选项 - // const config = {attributes: true, childList: true, subtree: true}; - // - // // 传入目标节点和观察选项 - // observer.observe(targetNode, config); - // - // }catch (e) { - // window.llonebot.log(e) - // } + try { + // 选择要观察的目标节点 + const targetNode = chatListEle[0]; + + // 创建一个观察器实例并传入回调函数 + const observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + // console.log("chat list changed", mutation.type); // 输出 mutation 的类型 + // 获得当前聊天窗口 + window.LLAPI.getPeer().then(peer => { + // console.log("current peer", peer) + if (peer && peer.chatType == "group"){ + getGroupMembers(peer.uid, false).then() + } + }) + }); + }); + + // 配置观察选项 + const config = {attributes: true, childList: true, subtree: true}; + + // 传入目标节点和观察选项 + observer.observe(targetNode, config); + + }catch (e) { + window.llonebot.log(e) + } } } diff --git a/src/tsconfig.json b/src/tsconfig.json index 490f276..626a4a9 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -1,10 +1,13 @@ { - "extends": "../tsconfig.json", "compilerOptions": { - "module": "es6", "target": "es6", - "outDir": "dist2/" + "module": "es6", + "outDir": "../dist", + "strict": false, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "moduleResolution": "node" }, "files": ["renderer.ts"], - "exclude": ["main.ts", "preload.ts"] +// "exclude": ["main.ts", "preload.ts"] } \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 6a6c11e..2f3e904 100644 --- a/src/types.ts +++ b/src/types.ts @@ -74,6 +74,9 @@ export type MessageElement = { export type SendMessage = { type: "text", content: string, + atType?: AtType, + atUid?: string, + atNtUid?: string } | { type: "image", file: string, // 本地路径 diff --git a/tsconfig.json b/tsconfig.json index fdcb841..8c73008 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es6", + "target": "ESNext", "module": "commonjs", "outDir": "./dist", "strict": false, @@ -9,9 +9,7 @@ "moduleResolution": "node", // "declaration": false }, - "include": [ - "src" - ], + "files": ["src/main.ts", "src/preload.ts"], "exclude": [ "node_modules" ]