mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9b32140f87 | ||
![]() |
dc5982c6b2 | ||
![]() |
ce46c99330 | ||
![]() |
d3abaf806f | ||
![]() |
e10a67ce05 | ||
![]() |
c8e897abdb | ||
![]() |
e07c06f3e9 | ||
![]() |
9c694a11b5 | ||
![]() |
6e3bb7c9cf | ||
![]() |
0d8d3ac24f | ||
![]() |
c96d032820 | ||
![]() |
837f48b63a | ||
![]() |
9d0f9e7096 | ||
![]() |
801d79d79d | ||
![]() |
0d5640046c |
7
.gitattributes
vendored
7
.gitattributes
vendored
@@ -1,7 +0,0 @@
|
||||
* text eol=lf
|
||||
|
||||
*.png -text
|
||||
*.jpg -text
|
||||
*.ico -text
|
||||
*.gif -text
|
||||
*.webp -text
|
@@ -4,7 +4,7 @@
|
||||
"name": "LLOneBot",
|
||||
"slug": "LLOneBot",
|
||||
"description": "实现 OneBot 11 和 Satori 协议,用于 QQ 机器人开发",
|
||||
"version": "4.0.4",
|
||||
"version": "4.0.8",
|
||||
"icon": "./icon.webp",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -45,8 +45,11 @@ export class NTQQGroupApi extends Service {
|
||||
return result.groupList
|
||||
}
|
||||
|
||||
async getGroupMembers(groupCode: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||
const sceneId = await invoke(NTMethod.GROUP_MEMBER_SCENE, [{ groupCode, scene: 'groupMemberList_MainWindow' }])
|
||||
async getGroupMembers(groupCode: string, num = 3000) {
|
||||
const sceneId = await invoke(NTMethod.GROUP_MEMBER_SCENE, [{
|
||||
groupCode,
|
||||
scene: 'groupMemberList_MainWindow'
|
||||
}])
|
||||
const data = await invoke(NTMethod.GROUP_MEMBERS, [{ sceneId, num }])
|
||||
if (data.errCode !== 0) {
|
||||
throw new Error('获取群成员列表出错,' + data.errMsg)
|
||||
|
@@ -263,4 +263,8 @@ export class NTQQMsgApi extends Service {
|
||||
async getServerTime() {
|
||||
return await invoke('nodeIKernelMSFService/getServerTime', [])
|
||||
}
|
||||
|
||||
async fetchUnitedCommendConfig(groups: string[]) {
|
||||
return await invoke('nodeIKernelUnitedConfigService/fetchUnitedCommendConfig', [{ groups }])
|
||||
}
|
||||
}
|
||||
|
@@ -118,7 +118,7 @@ export class NTQQUserApi extends Service {
|
||||
await this.ctx.sleep(30)
|
||||
member = await this.ctx.ntGroupApi.searchMember(groupCode, uin)
|
||||
}
|
||||
uid = member.values().find(e => e.uin === uin)?.uid
|
||||
uid = Array.from(member.values()).find(e => e.uin === uin)?.uid
|
||||
}
|
||||
if (!uid) {
|
||||
const unveifyUid = (await this.getUserDetailInfoByUin(uin)).info.uid
|
||||
|
@@ -19,6 +19,7 @@ import {
|
||||
import { selfInfo, llonebotError } from '../common/globalVars'
|
||||
import { version } from '../version'
|
||||
import { invoke } from './ntcall'
|
||||
import { Native } from './native/index'
|
||||
|
||||
declare module 'cordis' {
|
||||
interface Context {
|
||||
@@ -38,9 +39,11 @@ declare module 'cordis' {
|
||||
class Core extends Service {
|
||||
static inject = ['ntMsgApi', 'ntFriendApi', 'ntGroupApi', 'store']
|
||||
public startTime = 0
|
||||
public native
|
||||
|
||||
constructor(protected ctx: Context, public config: Core.Config) {
|
||||
super(ctx, 'app', true)
|
||||
this.native = new Native(ctx)
|
||||
}
|
||||
|
||||
public start() {
|
||||
|
BIN
src/ntqqapi/native/external/crychic-win32-x64.node
vendored
Normal file
BIN
src/ntqqapi/native/external/crychic-win32-x64.node
vendored
Normal file
Binary file not shown.
54
src/ntqqapi/native/index.ts
Normal file
54
src/ntqqapi/native/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Context } from 'cordis'
|
||||
import { Dict } from 'cosmokit'
|
||||
import { getBuildVersion } from '@/common/utils/misc'
|
||||
import addon from './external/crychic-win32-x64.node?asset'
|
||||
|
||||
export class Native {
|
||||
private crychic?: Dict
|
||||
|
||||
constructor(private ctx: Context) {
|
||||
ctx.on('ready', () => {
|
||||
this.start()
|
||||
})
|
||||
}
|
||||
|
||||
checkPlatform() {
|
||||
return process.platform === 'win32' && process.arch === 'x64'
|
||||
}
|
||||
|
||||
checkVersion() {
|
||||
const version = getBuildVersion()
|
||||
// 27187—27597
|
||||
return version >= 27187 && version < 28060
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.crychic) {
|
||||
return
|
||||
}
|
||||
if (!this.checkPlatform()) {
|
||||
return
|
||||
}
|
||||
if (!this.checkVersion()) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
this.crychic = require(addon)
|
||||
this.crychic!.init()
|
||||
} catch (e) {
|
||||
this.ctx.logger.warn('crychic 加载失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
async sendFriendPoke(uin: number) {
|
||||
if (!this.crychic) return
|
||||
this.crychic.sendFriendPoke(uin)
|
||||
await this.ctx.ntMsgApi.fetchUnitedCommendConfig(['100243'])
|
||||
}
|
||||
|
||||
async sendGroupPoke(groupCode: number, memberUin: number) {
|
||||
if (!this.crychic) return
|
||||
this.crychic.sendGroupPoke(memberUin, groupCode)
|
||||
await this.ctx.ntMsgApi.fetchUnitedCommendConfig(['100243'])
|
||||
}
|
||||
}
|
@@ -124,7 +124,12 @@ export function invoke<
|
||||
return new Promise<R>((resolve, reject) => {
|
||||
const apiArgs = [method, ...args]
|
||||
const callbackId = randomUUID()
|
||||
let eventId: string
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (eventId) {
|
||||
removeReceiveHook(eventId)
|
||||
}
|
||||
log(`ntqq api timeout ${channel}, ${eventName}, ${method}`, args)
|
||||
reject(`ntqq api timeout ${channel}, ${eventName}, ${method}, ${JSON.stringify(args)}`)
|
||||
}, timeout)
|
||||
@@ -140,16 +145,16 @@ export function invoke<
|
||||
let result: unknown
|
||||
// 这里的callback比较特殊,QQ后端先返回是否调用成功,再返回一条结果数据
|
||||
const secondCallback = () => {
|
||||
const hookId = registerReceiveHook<R>(options.cbCmd!, (payload) => {
|
||||
eventId = registerReceiveHook<R>(options.cbCmd!, (payload) => {
|
||||
if (options.cmdCB) {
|
||||
if (options.cmdCB(payload, result)) {
|
||||
removeReceiveHook(hookId)
|
||||
removeReceiveHook(eventId)
|
||||
clearTimeout(timeoutId)
|
||||
resolve(payload)
|
||||
}
|
||||
}
|
||||
else {
|
||||
removeReceiveHook(hookId)
|
||||
removeReceiveHook(eventId)
|
||||
clearTimeout(timeoutId)
|
||||
resolve(payload)
|
||||
}
|
||||
|
@@ -294,6 +294,9 @@ export interface GrayTipElement {
|
||||
jsonGrayTipElement?: {
|
||||
busiId: string
|
||||
jsonStr: string
|
||||
xmlToJsonParam?: {
|
||||
templParam: Map<string, string>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,10 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
||||
protected async _handle(payload: Payload) {
|
||||
const groupCode = payload.group_id.toString()
|
||||
let groupMembers = await this.ctx.ntGroupApi.getGroupMembers(groupCode)
|
||||
if (groupMembers.size === 0) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (groupMembers.size > 0) {
|
||||
break
|
||||
}
|
||||
await this.ctx.sleep(100)
|
||||
groupMembers = await this.ctx.ntGroupApi.getGroupMembers(groupCode)
|
||||
}
|
||||
|
@@ -74,6 +74,8 @@ import { GetGroupNotice } from './go-cqhttp/GetGroupNotice'
|
||||
import { GetRobotUinRange } from './llonebot/GetRobotUinRange'
|
||||
import { DeleteFriend } from './go-cqhttp/DeleteFriend'
|
||||
import { OCRImage } from './go-cqhttp/OCRImage'
|
||||
import { GroupPoke } from './llonebot/GroupPoke'
|
||||
import { FriendPoke } from './llonebot/FriendPoke'
|
||||
|
||||
export function initActionMap(adapter: Adapter) {
|
||||
const actionHandlers = [
|
||||
@@ -92,6 +94,8 @@ export function initActionMap(adapter: Adapter) {
|
||||
new FetchCustomFace(adapter),
|
||||
new SetMsgEmojiLike(adapter),
|
||||
new GetRobotUinRange(adapter),
|
||||
new GroupPoke(adapter),
|
||||
new FriendPoke(adapter),
|
||||
// onebot11
|
||||
new SendLike(adapter),
|
||||
new GetMsg(adapter),
|
||||
|
25
src/onebot11/action/llonebot/FriendPoke.ts
Normal file
25
src/onebot11/action/llonebot/FriendPoke.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { BaseAction, Schema } from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { getBuildVersion } from '@/common/utils/misc'
|
||||
|
||||
interface Payload {
|
||||
user_id: number | string
|
||||
}
|
||||
|
||||
export class FriendPoke extends BaseAction<Payload, null> {
|
||||
actionName = ActionName.FriendPoke
|
||||
payloadSchema = Schema.object({
|
||||
user_id: Schema.union([Number, String]).required()
|
||||
})
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
if (!this.ctx.app.native.checkPlatform()) {
|
||||
throw new Error('当前系统平台或架构不支持')
|
||||
}
|
||||
if (!this.ctx.app.native.checkVersion()) {
|
||||
throw new Error(`当前 QQ 版本 ${getBuildVersion()} 不支持,可尝试其他版本 27187—27597`)
|
||||
}
|
||||
await this.ctx.app.native.sendFriendPoke(+payload.user_id)
|
||||
return null
|
||||
}
|
||||
}
|
27
src/onebot11/action/llonebot/GroupPoke.ts
Normal file
27
src/onebot11/action/llonebot/GroupPoke.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { BaseAction, Schema } from '../BaseAction'
|
||||
import { ActionName } from '../types'
|
||||
import { getBuildVersion } from '@/common/utils/misc'
|
||||
|
||||
interface Payload {
|
||||
group_id: number | string
|
||||
user_id: number | string
|
||||
}
|
||||
|
||||
export class GroupPoke extends BaseAction<Payload, null> {
|
||||
actionName = ActionName.GroupPoke
|
||||
payloadSchema = Schema.object({
|
||||
group_id: Schema.union([Number, String]).required(),
|
||||
user_id: Schema.union([Number, String]).required()
|
||||
})
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
if (!this.ctx.app.native.checkPlatform()) {
|
||||
throw new Error('当前系统平台或架构不支持')
|
||||
}
|
||||
if (!this.ctx.app.native.checkVersion()) {
|
||||
throw new Error(`当前 QQ 版本 ${getBuildVersion()} 不支持,可尝试其他版本 27187—27597`)
|
||||
}
|
||||
await this.ctx.app.native.sendGroupPoke(+payload.group_id, +payload.user_id)
|
||||
return null
|
||||
}
|
||||
}
|
@@ -27,6 +27,8 @@ export enum ActionName {
|
||||
SendForwardMsg = 'send_forward_msg',
|
||||
SetMsgEmojiLike = 'set_msg_emoji_like',
|
||||
GetRobotUinRange = 'get_robot_uin_range',
|
||||
GroupPoke = 'group_poke',
|
||||
FriendPoke = 'friend_poke',
|
||||
// onebot 11
|
||||
SendLike = 'send_like',
|
||||
GetLoginInfo = 'get_login_info',
|
||||
|
@@ -33,12 +33,13 @@ declare module 'cordis' {
|
||||
class OneBot11Adapter extends Service {
|
||||
static inject = [
|
||||
'ntMsgApi', 'ntFileApi', 'ntFileCacheApi', 'ntFriendApi',
|
||||
'ntGroupApi', 'ntUserApi', 'ntWindowApi', 'ntWebApi', 'store'
|
||||
'ntGroupApi', 'ntUserApi', 'ntWindowApi', 'ntWebApi',
|
||||
'store', 'app'
|
||||
]
|
||||
private ob11WebSocket: OB11WebSocket
|
||||
private ob11WebSocketReverseManager: OB11WebSocketReverseManager
|
||||
private ob11Http: OB11Http
|
||||
private ob11HttpPost: OB11HttpPost
|
||||
private ob11WebSocket
|
||||
private ob11WebSocketReverseManager
|
||||
private ob11Http
|
||||
private ob11HttpPost
|
||||
|
||||
constructor(public ctx: Context, public config: OneBot11Adapter.Config) {
|
||||
super(ctx, 'onebot', true)
|
||||
|
@@ -548,14 +548,23 @@ export namespace OB11Entities {
|
||||
else if (grayTipElement.subElementType == GrayTipElementSubType.JSON) {
|
||||
const json = JSON.parse(grayTipElement.jsonGrayTipElement!.jsonStr)
|
||||
if (grayTipElement.jsonGrayTipElement?.busiId === '1061') {
|
||||
const param = grayTipElement.jsonGrayTipElement.xmlToJsonParam
|
||||
if (param) {
|
||||
return new OB11GroupPokeEvent(
|
||||
Number(msg.peerUid),
|
||||
Number(param.templParam.get('uin_str1')),
|
||||
Number(param.templParam.get('uin_str2')),
|
||||
json.items
|
||||
)
|
||||
}
|
||||
const pokedetail: Dict[] = json.items
|
||||
//筛选item带有uid的元素
|
||||
const poke_uid = pokedetail.filter(item => item.uid)
|
||||
if (poke_uid.length == 2) {
|
||||
return new OB11GroupPokeEvent(
|
||||
parseInt(msg.peerUid),
|
||||
parseInt(await ctx.ntUserApi.getUinByUid(poke_uid[0].uid) ?? 0),
|
||||
parseInt(await ctx.ntUserApi.getUinByUid(poke_uid[1].uid) ?? 0),
|
||||
Number(msg.peerUid),
|
||||
Number(await ctx.ntUserApi.getUinByUid(poke_uid[0].uid) ?? 0),
|
||||
Number(await ctx.ntUserApi.getUinByUid(poke_uid[1].uid) ?? 0),
|
||||
pokedetail
|
||||
)
|
||||
}
|
||||
@@ -665,11 +674,13 @@ export namespace OB11Entities {
|
||||
}
|
||||
|
||||
export function groupMember(group_id: string, member: GroupMember): OB11GroupMember {
|
||||
const titleExpireTime = +member.specialTitleExpireTime
|
||||
const int32Max = Math.pow(2, 31) - 1
|
||||
return {
|
||||
group_id: parseInt(group_id),
|
||||
user_id: parseInt(member.uin),
|
||||
nickname: member.nick,
|
||||
card: member.cardName,
|
||||
card: member.cardName || member.nick,
|
||||
sex: OB11UserSex.Unknown,
|
||||
age: 0,
|
||||
area: '',
|
||||
@@ -677,7 +688,7 @@ export namespace OB11Entities {
|
||||
qq_level: 0,
|
||||
join_time: member.joinTime,
|
||||
last_sent_time: member.lastSpeakTime,
|
||||
title_expire_time: +member.specialTitleExpireTime,
|
||||
title_expire_time: titleExpireTime > int32Max ? 0 : titleExpireTime,
|
||||
unfriendly: false,
|
||||
card_changeable: true,
|
||||
is_robot: member.isRobot,
|
||||
|
@@ -1 +1 @@
|
||||
export const version = '4.0.4'
|
||||
export const version = '4.0.8'
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"target": "ES2023",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
@@ -20,7 +20,10 @@
|
||||
"./src/ntqqapi/*"
|
||||
]
|
||||
},
|
||||
"noEmit": true
|
||||
"noEmit": true,
|
||||
"types": [
|
||||
"electron-vite/node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
|
Reference in New Issue
Block a user