mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
群成员获取研究
This commit is contained in:
parent
7a7d21d533
commit
e2759417f5
@ -5,7 +5,8 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "tsc"
|
"build-mac": "tsc && npm run deploy-mac",
|
||||||
|
"deploy-mac": "cp dist/* ~/Library/Containers/com.tencent.qq/Data/Documents/LiteLoaderQQNT/plugins/LLOnebot/"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
85
src/global.d.ts
vendored
85
src/global.d.ts
vendored
@ -1,68 +1,6 @@
|
|||||||
declare enum AtType {
|
import {Group, GroupMemberInfo, MessageElement, Peer, PostDataSendMsg, SendMessage, User} from "./types";
|
||||||
notAt = 0,
|
|
||||||
atUser = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
declare type Peer = {
|
|
||||||
chatType: "private" | "group"
|
|
||||||
name: string
|
|
||||||
uid: string // qq号
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MessageElement {
|
|
||||||
raw: {
|
|
||||||
elements: {
|
|
||||||
|
|
||||||
replyElement: {
|
|
||||||
senderUid: string, // 原消息发送者QQ号
|
|
||||||
sourceMsgIsIncPic: boolean; // 原消息是否有图片
|
|
||||||
sourceMsgText: string;
|
|
||||||
sourceMsgIdInRecords: string; // 原消息id
|
|
||||||
},
|
|
||||||
textElement: {
|
|
||||||
atType: AtType
|
|
||||||
atUid: string,
|
|
||||||
content: string
|
|
||||||
},
|
|
||||||
picElement: {
|
|
||||||
sourcePath: string // 图片本地路径
|
|
||||||
picWidth: number
|
|
||||||
picHeight: number
|
|
||||||
fileSize: number
|
|
||||||
fileName: string
|
|
||||||
fileUuid: string
|
|
||||||
}
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
peer: Peer,
|
|
||||||
sender: {
|
|
||||||
uid: string // 一串加密的字符串
|
|
||||||
memberName: string
|
|
||||||
nickname: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare type User = {
|
|
||||||
avatarUrl?: string;
|
|
||||||
bio?: string; // 签名
|
|
||||||
nickName: string;
|
|
||||||
uid?: string; // 加密的字符串
|
|
||||||
uin: string; // QQ号
|
|
||||||
}
|
|
||||||
|
|
||||||
declare type Group = {
|
|
||||||
uid: string; // 群号
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare type SendMessage = {
|
|
||||||
type: "text",
|
|
||||||
content: string,
|
|
||||||
} | {
|
|
||||||
type: "image",
|
|
||||||
file: string, // 这是本地路径?
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var LLAPI: {
|
declare var LLAPI: {
|
||||||
on(event: "new-messages", callback: (data: MessageElement[]) => void): void;
|
on(event: "new-messages", callback: (data: MessageElement[]) => void): void;
|
||||||
@ -76,16 +14,12 @@ declare var LLAPI: {
|
|||||||
sendMessage(peer: Peer, message: SendMessage[]): Promise<void>;
|
sendMessage(peer: Peer, message: SendMessage[]): Promise<void>;
|
||||||
getGroupsList(forced: boolean): Promise<Group[]>
|
getGroupsList(forced: boolean): Promise<Group[]>
|
||||||
getFriendsList(forced: boolean): Promise<User[]>
|
getFriendsList(forced: boolean): Promise<User[]>
|
||||||
|
getGroupMemberList(group_id: string, num: number): Promise<{result: { infos: Record<string, GroupMemberInfo> }}>
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type PostDataSendMsg = {
|
|
||||||
action: "send_private_msg" | "send_group_msg" | "get_group_list",
|
|
||||||
params: {
|
|
||||||
user_id: string,
|
|
||||||
group_id: string,
|
|
||||||
message: SendMessage[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var llonebot: {
|
declare var llonebot: {
|
||||||
postData: (data: any) => void
|
postData: (data: any) => void
|
||||||
@ -94,4 +28,11 @@ declare var llonebot: {
|
|||||||
updateFriends: (friends: User[]) => void
|
updateFriends: (friends: User[]) => void
|
||||||
updateGroupMembers: (data: { groupMembers: User[], group_id: string }) => void
|
updateGroupMembers: (data: { groupMembers: User[], group_id: string }) => void
|
||||||
startExpress: () => void
|
startExpress: () => void
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
LLAPI: typeof LLAPI;
|
||||||
|
llonebot: typeof llonebot;
|
||||||
|
}
|
||||||
|
}
|
11
src/main.ts
11
src/main.ts
@ -1,5 +1,7 @@
|
|||||||
// 运行在 Electron 主进程 下的插件入口
|
// 运行在 Electron 主进程 下的插件入口
|
||||||
|
|
||||||
|
import {Group, PostDataSendMsg, User} from "./types";
|
||||||
|
|
||||||
const express = require("express")
|
const express = require("express")
|
||||||
const {ipcMain, webContents} = require('electron');
|
const {ipcMain, webContents} = require('electron');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@ -24,8 +26,9 @@ function sendIPCCallSendQQMsg(postData: PostDataSendMsg) {
|
|||||||
sendIPCMsg(CHANNEL_SEND_MSG, postData);
|
sendIPCMsg(CHANNEL_SEND_MSG, postData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function log(msg: string){
|
function log(msg: any){
|
||||||
fs.appendFile("d:\\llonebot.log", msg + "\n", (err: any) => {
|
let currentDateTime = new Date().toLocaleString();
|
||||||
|
fs.appendFile("./llonebot.log", currentDateTime + ":" + msg + "\n", (err: any) => {
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -143,6 +146,10 @@ function onLoad(plugin: any) {
|
|||||||
log(e.toString())
|
log(e.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.on("llonebot_log", (event: any, arg: any) => {
|
||||||
|
log(arg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// Electron 主进程 与 渲染进程 交互的桥梁
|
// Electron 主进程 与 渲染进程 交互的桥梁
|
||||||
|
|
||||||
|
import {Group, PostDataSendMsg, User} from "./types";
|
||||||
|
|
||||||
const {contextBridge} = require("electron");
|
const {contextBridge} = require("electron");
|
||||||
const {ipcRenderer} = require('electron');
|
const {ipcRenderer} = require('electron');
|
||||||
|
|
||||||
@ -24,6 +26,9 @@ contextBridge.exposeInMainWorld("llonebot", {
|
|||||||
},
|
},
|
||||||
startExpress: () => {
|
startExpress: () => {
|
||||||
ipcRenderer.send("startExpress");
|
ipcRenderer.send("startExpress");
|
||||||
|
},
|
||||||
|
log: (data: any) => {
|
||||||
|
ipcRenderer.send("log", data);
|
||||||
}
|
}
|
||||||
// startExpress,
|
// startExpress,
|
||||||
});
|
});
|
169
src/renderer.ts
169
src/renderer.ts
@ -2,16 +2,23 @@
|
|||||||
|
|
||||||
// import express from "express";
|
// import express from "express";
|
||||||
// const { ipcRenderer } = require('electron');
|
// const { ipcRenderer } = require('electron');
|
||||||
enum AtType {
|
import {AtType, Group, MessageElement, Peer, PostDataSendMsg, User} from "./types";
|
||||||
notAt = 0,
|
|
||||||
atUser = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
const host = "http://localhost:5000"
|
const host = "http://localhost:5000"
|
||||||
|
|
||||||
|
let self_qq: string = ""
|
||||||
let groups: Group[] = []
|
let groups: Group[] = []
|
||||||
let friends: User[] = []
|
let friends: User[] = []
|
||||||
let groupMembers: { group_id: string, groupMembers: User[] }[] = []
|
let uid_maps: Record<string, User> = {} // 一串加密的字符串 -> qq号
|
||||||
|
async function getUserInfo(uid: string): Promise<User>{
|
||||||
|
let user = uid_maps[uid]
|
||||||
|
if (!user){
|
||||||
|
// 从服务器获取用户信息
|
||||||
|
user = await window.LLAPI.getUserInfo(uid)
|
||||||
|
uid_maps[uid] = user
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
function getFriend(qq: string) {
|
function getFriend(qq: string) {
|
||||||
return friends.find(friend => friend.uid == qq)
|
return friends.find(friend => friend.uid == qq)
|
||||||
@ -21,9 +28,7 @@ function getGroup(qq: string) {
|
|||||||
return groups.find(group => group.uid == qq)
|
return groups.find(group => group.uid == qq)
|
||||||
}
|
}
|
||||||
|
|
||||||
let self_qq: string = ""
|
|
||||||
|
|
||||||
let uid_maps: Record<string, string> = {} // 一串加密的字符串 -> qq号
|
|
||||||
|
|
||||||
function forwardMessage(message: MessageElement) {
|
function forwardMessage(message: MessageElement) {
|
||||||
try {
|
try {
|
||||||
@ -36,79 +41,92 @@ function forwardMessage(message: MessageElement) {
|
|||||||
type: "message",
|
type: "message",
|
||||||
detail_type: message.peer.chatType,
|
detail_type: message.peer.chatType,
|
||||||
sub_type: "",
|
sub_type: "",
|
||||||
message: message.raw.elements.map(element => {
|
message: []
|
||||||
let message_data: any = {
|
|
||||||
data: {}
|
|
||||||
}
|
|
||||||
if (element.textElement?.atType == AtType.atUser) {
|
|
||||||
message_data["type"] = "at"
|
|
||||||
message_data["data"]["mention"] = element.textElement.atUid
|
|
||||||
} 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
|
|
||||||
}
|
|
||||||
return message_data
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
let group: Group
|
||||||
if (message.peer.chatType == "group") {
|
if (message.peer.chatType == "group") {
|
||||||
|
let group_id = message.peer.uid
|
||||||
|
group = groups.find(group => group.uid == group_id)!
|
||||||
onebot_message_data["group_id"] = message.peer.uid
|
onebot_message_data["group_id"] = message.peer.uid
|
||||||
// todo: 将加密的uid转成qq号
|
let groupMember = group.members!.find(member => member.uid == message.sender.uid)
|
||||||
let groupMember = groupMembers.find(group => group.group_id == message.peer.uid)?.groupMembers.find(member => member.uid == message.sender.uid)
|
if (groupMember) {
|
||||||
onebot_message_data["user_id"] = groupMember!.uin
|
console.log("群成员信息存在,使用群成员信息")
|
||||||
|
onebot_message_data["user_id"] = groupMember.uin
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log("群成员信息不存在,使用原始uid")
|
||||||
|
onebot_message_data["user_id"] = message.sender.uid
|
||||||
|
}
|
||||||
console.log("收到群消息", onebot_message_data)
|
console.log("收到群消息", onebot_message_data)
|
||||||
} else if (message.peer.chatType == "private") {
|
} else if (message.peer.chatType == "private") {
|
||||||
onebot_message_data["user_id"] = message.peer.uid
|
onebot_message_data["user_id"] = message.peer.uid
|
||||||
}
|
}
|
||||||
console.log("发送上传消息给ipcmain", onebot_message_data)
|
for (let element of message.raw.elements) {
|
||||||
llonebot.postData(onebot_message_data);
|
let message_data: any = {
|
||||||
|
data: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.textElement?.atType == AtType.atUser) {
|
||||||
|
message_data["type"] = "at"
|
||||||
|
if (element.textElement.atUid != "0") {
|
||||||
|
message_data["data"]["mention"] = element.textElement.atUid
|
||||||
|
} else {
|
||||||
|
let uid = element.textElement.atNtUid
|
||||||
|
let atMember = group!.members!.find(member => member.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
|
||||||
|
}
|
||||||
|
onebot_message_data.message.push(message_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("发送上传消息给ipc main", onebot_message_data)
|
||||||
|
window.llonebot.postData(onebot_message_data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("上传消息事件失败", e)
|
console.log("上传消息事件失败", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNewMessage(messages: MessageElement[]) {
|
async function handleNewMessage(messages: MessageElement[]) {
|
||||||
messages.forEach(message => {
|
for (let message of messages) {
|
||||||
if (message.peer.chatType == "group") {
|
if (message.peer.chatType == "group") {
|
||||||
let group = groupMembers.find(group => group.group_id == message.peer.uid)
|
let group = groups.find(group => group.uid == message.peer.uid)
|
||||||
if (!group) {
|
if (!group) {
|
||||||
|
let members = (await window.LLAPI.getGroupMemberList(message.peer.uid + "_groupMemberList_MainWindow", 5000)).result.infos
|
||||||
|
let membersList = Object.values(members)
|
||||||
group = {
|
group = {
|
||||||
group_id: message.peer.uid,
|
name: message.peer.name,
|
||||||
groupMembers: []
|
uid: message.peer.uid,
|
||||||
|
members: membersList
|
||||||
}
|
}
|
||||||
groupMembers.push(group)
|
groups.push(group)
|
||||||
}
|
window.llonebot.updateGroups(groups);
|
||||||
let existMember = group!.groupMembers.find(member => member.uid == message.sender.uid)
|
|
||||||
if (!existMember) {
|
|
||||||
window.LLAPI.getUserInfo(message.sender.uid).then(user => {
|
|
||||||
let member = {memberName: message.sender.memberName, uid: user.uin, nickName: user.nickName}
|
|
||||||
// group!.groupMembers.push(member)
|
|
||||||
group!.groupMembers.push(user)
|
|
||||||
llonebot.updateGroupMembers(group!)
|
|
||||||
forwardMessage(message)
|
|
||||||
}).catch(err => {
|
|
||||||
console.log("获取群成员信息失败", err)
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
forwardMessage(message)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
forwardMessage(message);
|
||||||
forwardMessage(message);
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
async function getGroups(){
|
||||||
|
groups = await window.LLAPI.getGroupsList(false)
|
||||||
|
for (let group of groups) {
|
||||||
|
group.members = [];
|
||||||
|
}
|
||||||
|
window.llonebot.updateGroups(groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
llonebot.startExpress();
|
window.llonebot.startExpress();
|
||||||
llonebot.listenSendMessage((postData: PostDataSendMsg) => {
|
window.llonebot.listenSendMessage((postData: PostDataSendMsg) => {
|
||||||
if (postData.action == "send_private_msg" || postData.action == "send_group_msg") {
|
if (postData.action == "send_private_msg" || postData.action == "send_group_msg") {
|
||||||
let peer: Peer | null = null;
|
let peer: Peer | null = null;
|
||||||
if (postData.action == "send_private_msg") {
|
if (postData.action == "send_private_msg") {
|
||||||
@ -131,30 +149,25 @@ function onLoad() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peer) {
|
if (peer) {
|
||||||
LLAPI.sendMessage(peer, postData.params.message).then(res => console.log("消息发送成功:", res),
|
window.LLAPI.sendMessage(peer, postData.params.message).then(res => console.log("消息发送成功:", res),
|
||||||
err => console.log("消息发送失败", postData, err))
|
err => console.log("消息发送失败", postData, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
getGroups().then()
|
||||||
window.LLAPI.getGroupsList(false).then(groupsList => {
|
function onNewMessages(messages: MessageElement[]){
|
||||||
groups = groupsList
|
async function func(messages: MessageElement[]){
|
||||||
llonebot.updateGroups(groupsList)
|
console.log("收到新消息", messages)
|
||||||
})
|
if (!self_qq) {
|
||||||
|
self_qq = (await window.LLAPI.getAccountInfo()).uin
|
||||||
window.LLAPI.on("new-messages", (messages) => {
|
}
|
||||||
console.log("收到新消息", messages)
|
await handleNewMessage(messages);
|
||||||
// 往groupMembers里面添加群成员
|
|
||||||
if (!self_qq){
|
|
||||||
window.LLAPI.getAccountInfo().then(accountInfo => {
|
|
||||||
console.log("getAccountInfo", accountInfo)
|
|
||||||
self_qq = accountInfo.uin
|
|
||||||
handleNewMessage(messages)
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
handleNewMessage(messages)
|
|
||||||
}
|
}
|
||||||
});
|
func(messages).then(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
window.LLAPI.on("new-messages", onNewMessages);
|
||||||
|
|
||||||
// console.log("getAccountInfo", LLAPI.getAccountInfo());
|
// console.log("getAccountInfo", LLAPI.getAccountInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
89
src/types.ts
Normal file
89
src/types.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
export enum AtType {
|
||||||
|
notAt = 0,
|
||||||
|
atUser = 2
|
||||||
|
}
|
||||||
|
export type GroupMemberInfo = {
|
||||||
|
avatarPath: string;
|
||||||
|
cardName: string;
|
||||||
|
cardType: number;
|
||||||
|
isDelete: boolean;
|
||||||
|
nick: string;
|
||||||
|
qid: string;
|
||||||
|
remark: string;
|
||||||
|
role: number; // 群主:4, 管理员:3,群员:2
|
||||||
|
shutUpTime: number; // 禁言时间,单位是什么暂时不清楚
|
||||||
|
uid: string; // 加密的字符串
|
||||||
|
uin: string; // QQ号
|
||||||
|
}
|
||||||
|
|
||||||
|
export type User = {
|
||||||
|
avatarUrl?: string;
|
||||||
|
bio?: string; // 签名
|
||||||
|
nickName: string;
|
||||||
|
uid?: string; // 加密的字符串
|
||||||
|
uin: string; // QQ号
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Group = {
|
||||||
|
uid: string; // 群号
|
||||||
|
name: string;
|
||||||
|
members?: GroupMemberInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Peer = {
|
||||||
|
chatType: "private" | "group"
|
||||||
|
name: string
|
||||||
|
uid: string // qq号
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MessageElement = {
|
||||||
|
raw: {
|
||||||
|
elements: {
|
||||||
|
|
||||||
|
replyElement: {
|
||||||
|
senderUid: string, // 原消息发送者QQ号
|
||||||
|
sourceMsgIsIncPic: boolean; // 原消息是否有图片
|
||||||
|
sourceMsgText: string;
|
||||||
|
sourceMsgIdInRecords: string; // 原消息id
|
||||||
|
},
|
||||||
|
textElement: {
|
||||||
|
atType: AtType
|
||||||
|
atUid: string,
|
||||||
|
content: string,
|
||||||
|
atNtUid: string
|
||||||
|
},
|
||||||
|
picElement: {
|
||||||
|
sourcePath: string // 图片本地路径
|
||||||
|
picWidth: number
|
||||||
|
picHeight: number
|
||||||
|
fileSize: number
|
||||||
|
fileName: string
|
||||||
|
fileUuid: string
|
||||||
|
}
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
peer: Peer,
|
||||||
|
sender: {
|
||||||
|
uid: string // 一串加密的字符串
|
||||||
|
memberName: string
|
||||||
|
nickname: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SendMessage = {
|
||||||
|
type: "text",
|
||||||
|
content: string,
|
||||||
|
} | {
|
||||||
|
type: "image",
|
||||||
|
file: string, // 本地路径
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PostDataSendMsg = {
|
||||||
|
action: "send_private_msg" | "send_group_msg" | "get_group_list",
|
||||||
|
params: {
|
||||||
|
user_id: string,
|
||||||
|
group_id: string,
|
||||||
|
message: SendMessage[];
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user