@zhin.js/adapter-icqq 1.0.16 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +151 -0
- package/dist/index.js +1 -0
- package/package.json +12 -9
- package/src/index.ts +247 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# @zhin.js/adapter-icqq
|
|
2
|
+
|
|
3
|
+
## 1.0.17
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f4a7dd7: fix: force build
|
|
8
|
+
|
|
9
|
+
## 1.0.16
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 547028f: fix: 优化包结构,优化客户端支持
|
|
14
|
+
- Updated dependencies [547028f]
|
|
15
|
+
- @zhin.js/console@1.0.10
|
|
16
|
+
- @zhin.js/types@1.0.5
|
|
17
|
+
- @zhin.js/http@1.0.7
|
|
18
|
+
- zhin.js@1.0.14
|
|
19
|
+
|
|
20
|
+
## 1.0.15
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [4034b94]
|
|
25
|
+
- @zhin.js/console@1.0.9
|
|
26
|
+
- zhin.js@1.0.13
|
|
27
|
+
|
|
28
|
+
## 1.0.14
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- zhin.js@1.0.12
|
|
33
|
+
|
|
34
|
+
## 1.0.13
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- zhin.js@1.0.11
|
|
39
|
+
|
|
40
|
+
## 1.0.12
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- Updated dependencies [c1a539e]
|
|
45
|
+
- Updated dependencies [c8c3996]
|
|
46
|
+
- @zhin.js/console@1.0.8
|
|
47
|
+
- @zhin.js/types@1.0.4
|
|
48
|
+
- zhin.js@1.0.10
|
|
49
|
+
|
|
50
|
+
## 1.0.11
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- c490260: fix: 更新脚手架结构,优化包依赖
|
|
55
|
+
- Updated dependencies [c490260]
|
|
56
|
+
- @zhin.js/console@1.0.7
|
|
57
|
+
- @zhin.js/client@1.0.5
|
|
58
|
+
- @zhin.js/http@1.0.6
|
|
59
|
+
- zhin.js@1.0.9
|
|
60
|
+
|
|
61
|
+
## 1.0.10
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- 551c4d2: fix: 插件支持配置文件读取,优化 test 用例
|
|
66
|
+
- Updated dependencies [551c4d2]
|
|
67
|
+
- @zhin.js/console@1.0.6
|
|
68
|
+
- @zhin.js/types@1.0.3
|
|
69
|
+
- @zhin.js/client@1.0.4
|
|
70
|
+
- zhin.js@1.0.8
|
|
71
|
+
- @zhin.js/http@1.0.5
|
|
72
|
+
|
|
73
|
+
## 1.0.9
|
|
74
|
+
|
|
75
|
+
### Patch Changes
|
|
76
|
+
|
|
77
|
+
- Updated dependencies [47845fb]
|
|
78
|
+
- @zhin.js/console@1.0.5
|
|
79
|
+
- zhin.js@1.0.7
|
|
80
|
+
|
|
81
|
+
## 1.0.8
|
|
82
|
+
|
|
83
|
+
### Patch Changes
|
|
84
|
+
|
|
85
|
+
- Updated dependencies [c2d9047]
|
|
86
|
+
- Updated dependencies [c2d9047]
|
|
87
|
+
- Updated dependencies [b213bbc]
|
|
88
|
+
- @zhin.js/console@1.0.4
|
|
89
|
+
- @zhin.js/client@1.0.3
|
|
90
|
+
- @zhin.js/http@1.0.4
|
|
91
|
+
- zhin.js@1.0.6
|
|
92
|
+
|
|
93
|
+
## 1.0.7
|
|
94
|
+
|
|
95
|
+
### Patch Changes
|
|
96
|
+
|
|
97
|
+
- Updated dependencies [5e2bddc]
|
|
98
|
+
- @zhin.js/console@1.0.3
|
|
99
|
+
|
|
100
|
+
## 1.0.6
|
|
101
|
+
|
|
102
|
+
### Patch Changes
|
|
103
|
+
|
|
104
|
+
- Updated dependencies [f347667]
|
|
105
|
+
- @zhin.js/http@1.0.3
|
|
106
|
+
- zhin.js@1.0.5
|
|
107
|
+
|
|
108
|
+
## 1.0.5
|
|
109
|
+
|
|
110
|
+
### Patch Changes
|
|
111
|
+
|
|
112
|
+
- Updated dependencies [d291005]
|
|
113
|
+
- @zhin.js/console@1.0.2
|
|
114
|
+
- @zhin.js/client@1.0.2
|
|
115
|
+
- @zhin.js/http@1.0.2
|
|
116
|
+
|
|
117
|
+
## 1.0.4
|
|
118
|
+
|
|
119
|
+
### Patch Changes
|
|
120
|
+
|
|
121
|
+
- zhin.js@1.0.4
|
|
122
|
+
|
|
123
|
+
## 1.0.3
|
|
124
|
+
|
|
125
|
+
### Patch Changes
|
|
126
|
+
|
|
127
|
+
- 89bc676: fix: 类型反射优化
|
|
128
|
+
- Updated dependencies [727963c]
|
|
129
|
+
- Updated dependencies [89bc676]
|
|
130
|
+
- @zhin.js/console@1.0.1
|
|
131
|
+
- @zhin.js/client@1.0.1
|
|
132
|
+
- @zhin.js/types@1.0.2
|
|
133
|
+
- zhin.js@1.0.3
|
|
134
|
+
|
|
135
|
+
## 1.0.2
|
|
136
|
+
|
|
137
|
+
### Patch Changes
|
|
138
|
+
|
|
139
|
+
- 3ecd487: fix: 函数式组件,更新文档
|
|
140
|
+
- Updated dependencies [15fc934]
|
|
141
|
+
- zhin.js@1.0.2
|
|
142
|
+
|
|
143
|
+
## 1.0.1
|
|
144
|
+
|
|
145
|
+
### Patch Changes
|
|
146
|
+
|
|
147
|
+
- efdd58a: fix: init
|
|
148
|
+
- Updated dependencies [efdd58a]
|
|
149
|
+
- @zhin.js/types@1.0.1
|
|
150
|
+
- zhin.js@1.0.1
|
|
151
|
+
- @zhin.js/http@1.0.1
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import{addPage as t}from"@zhin.js/client";import{Bot as m}from"lucide-react";function n(){return e("div",{children:"ICQQManagement"})}t({key:"icqq-management",path:"/icqq",title:"ICQQ管理",icon:e(m,{className:"w-5 h-5"}),element:e(n,{})});
|
package/package.json
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-icqq",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.17",
|
|
4
4
|
"description": "zhin adapter for icqq",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
8
|
-
"files": [
|
|
9
|
-
"lib",
|
|
10
|
-
"client",
|
|
11
|
-
"README.md"
|
|
12
|
-
],
|
|
13
8
|
"exports": {
|
|
14
9
|
".": {
|
|
15
10
|
"types": "./lib/index.d.ts",
|
|
@@ -28,6 +23,14 @@
|
|
|
28
23
|
"type": "git",
|
|
29
24
|
"directory": "plugins/adapters/icqq"
|
|
30
25
|
},
|
|
26
|
+
"files": [
|
|
27
|
+
"lib",
|
|
28
|
+
"README.md",
|
|
29
|
+
"CHANGELOG.md",
|
|
30
|
+
"client",
|
|
31
|
+
"src",
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
31
34
|
"dependencies": {
|
|
32
35
|
"@icqqjs/icqq": "latest"
|
|
33
36
|
},
|
|
@@ -41,10 +44,10 @@
|
|
|
41
44
|
},
|
|
42
45
|
"peerDependencies": {
|
|
43
46
|
"zhin.js": "1.0.14",
|
|
44
|
-
"@zhin.js/client": "1.0.5",
|
|
45
47
|
"@zhin.js/http": "1.0.7",
|
|
48
|
+
"@zhin.js/types": "1.0.5",
|
|
46
49
|
"@zhin.js/console": "1.0.10",
|
|
47
|
-
"@zhin.js/
|
|
50
|
+
"@zhin.js/client": "1.0.5"
|
|
48
51
|
},
|
|
49
52
|
"peerDependenciesMeta": {
|
|
50
53
|
"@zhin.js/client": {
|
|
@@ -61,7 +64,7 @@
|
|
|
61
64
|
}
|
|
62
65
|
},
|
|
63
66
|
"scripts": {
|
|
64
|
-
"build": "tsc && (
|
|
67
|
+
"build": "tsc && (test -f ../../services/console/lib/bin.js && node ../../services/console/lib/bin.js build || echo 'Skipping client build: console not built yet')",
|
|
65
68
|
"clean": "rm -rf lib"
|
|
66
69
|
}
|
|
67
70
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { Config, Client, PrivateMessageEvent, GroupMessageEvent, Sendable, MessageElem} from "@icqqjs/icqq";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import {
|
|
4
|
+
Bot,
|
|
5
|
+
usePlugin,
|
|
6
|
+
useContext,
|
|
7
|
+
Adapter,
|
|
8
|
+
Plugin,
|
|
9
|
+
registerAdapter,
|
|
10
|
+
Message,
|
|
11
|
+
SendOptions,
|
|
12
|
+
MessageSegment,
|
|
13
|
+
SendContent,
|
|
14
|
+
segment
|
|
15
|
+
} from "zhin.js";
|
|
16
|
+
declare module '@zhin.js/types'{
|
|
17
|
+
interface RegisteredAdapters{
|
|
18
|
+
icqq:Adapter<IcqqBot>
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const plugin =usePlugin()
|
|
22
|
+
export interface IcqqBotConfig extends Bot.Config,Config{
|
|
23
|
+
context:'icqq'
|
|
24
|
+
name:`${number}`
|
|
25
|
+
password?:string
|
|
26
|
+
scope?:string
|
|
27
|
+
}
|
|
28
|
+
export interface IcqqBot{
|
|
29
|
+
$config:IcqqBotConfig
|
|
30
|
+
}
|
|
31
|
+
export class IcqqBot extends Client implements Bot<PrivateMessageEvent|GroupMessageEvent,IcqqBotConfig>{
|
|
32
|
+
$connected?:boolean
|
|
33
|
+
constructor(config:IcqqBotConfig) {
|
|
34
|
+
if(!config.scope) config.scope='icqqjs'
|
|
35
|
+
if(!config.data_dir) config.data_dir=path.join(process.cwd(),'data')
|
|
36
|
+
if(config.scope.startsWith('@')) config.scope=config.scope.slice(1)
|
|
37
|
+
super(config);
|
|
38
|
+
this.$config=config
|
|
39
|
+
}
|
|
40
|
+
private handleIcqqMessage(msg: PrivateMessageEvent|GroupMessageEvent): void {
|
|
41
|
+
const message =this.$formatMessage(msg) ;
|
|
42
|
+
plugin.dispatch('message.receive',message)
|
|
43
|
+
plugin.logger.info(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`)
|
|
44
|
+
plugin.dispatch(`message.${message.$channel.type}.receive`,message)
|
|
45
|
+
}
|
|
46
|
+
async $connect(): Promise<void> {
|
|
47
|
+
this.on('message',this.handleIcqqMessage.bind(this))
|
|
48
|
+
this.on('system.login.device',async (e:unknown)=>{
|
|
49
|
+
await this.sendSmsCode()
|
|
50
|
+
plugin.logger.info('请输入短信验证码:')
|
|
51
|
+
process.stdin.once('data',(data)=>{
|
|
52
|
+
this.submitSmsCode(data.toString().trim())
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
this.on('system.login.qrcode',(e)=>{
|
|
56
|
+
plugin.logger.info(`取码地址:${e.image}\n请扫码完成后回车继续:`)
|
|
57
|
+
process.stdin.once('data',()=>{
|
|
58
|
+
this.login()
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
this.on('system.login.slider',(e)=>{
|
|
62
|
+
plugin.logger.info(`取码地址:${e.url}\n请输入滑块验证ticket:`)
|
|
63
|
+
process.stdin.once('data',(e)=>{
|
|
64
|
+
this.submitSlider(e.toString().trim())
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
return new Promise((resolve)=>{
|
|
68
|
+
this.once('system.online',()=>{
|
|
69
|
+
this.$connected=true;
|
|
70
|
+
resolve()
|
|
71
|
+
})
|
|
72
|
+
this.login(Number(this.$config.name),this.$config.password)
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async $disconnect(): Promise<void> {
|
|
77
|
+
await this.logout()
|
|
78
|
+
this.$connected=false;
|
|
79
|
+
}
|
|
80
|
+
$formatMessage(msg:PrivateMessageEvent|GroupMessageEvent){
|
|
81
|
+
const result= Message.from(msg,{
|
|
82
|
+
$id: msg.message_id.toString(),
|
|
83
|
+
$adapter:'icqq',
|
|
84
|
+
$bot:`${this.$config.name}`,
|
|
85
|
+
$sender:{
|
|
86
|
+
id:msg.sender.user_id.toString(),
|
|
87
|
+
name:msg.sender.nickname.toString(),
|
|
88
|
+
},
|
|
89
|
+
$channel:{
|
|
90
|
+
id:msg.message_type==='group'?msg.group_id.toString():msg.from_id.toString(),
|
|
91
|
+
type:msg.message_type
|
|
92
|
+
},
|
|
93
|
+
$content: IcqqBot.toSegments(msg.message),
|
|
94
|
+
$raw: msg.raw_message,
|
|
95
|
+
$timestamp: msg.time,
|
|
96
|
+
$reply:async (content: SendContent, quote?: boolean|string):Promise<string>=> {
|
|
97
|
+
if(!Array.isArray(content)) content=[content];
|
|
98
|
+
if(quote) content.unshift({type:'reply',data:{id:typeof quote==="boolean"?result.$id:quote}})
|
|
99
|
+
return await this.$sendMessage({
|
|
100
|
+
...result.$channel,
|
|
101
|
+
context:'icqq',
|
|
102
|
+
bot:`${this.uin}`,
|
|
103
|
+
content
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
return result
|
|
108
|
+
}
|
|
109
|
+
async $recallMessage(id:string):Promise<void> {
|
|
110
|
+
await this.deleteMsg(id)
|
|
111
|
+
}
|
|
112
|
+
async $sendMessage(options: SendOptions): Promise<string> {
|
|
113
|
+
options=await plugin.app.handleBeforeSend(options)
|
|
114
|
+
switch (options.type){
|
|
115
|
+
case 'private':{
|
|
116
|
+
const result= await this.sendPrivateMsg(Number(options.id),IcqqBot.toSendable(options.content))
|
|
117
|
+
plugin.logger.info(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`)
|
|
118
|
+
return result.message_id.toString()
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case "group":{
|
|
122
|
+
const result=await this.sendGroupMsg(Number(options.id),IcqqBot.toSendable(options.content))
|
|
123
|
+
plugin.logger.info(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`)
|
|
124
|
+
return result.message_id.toString()
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
default:
|
|
128
|
+
throw new Error(`unsupported channel type ${options.type}`)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
export namespace IcqqBot{
|
|
134
|
+
const allowTypes=[
|
|
135
|
+
'text',
|
|
136
|
+
'face',
|
|
137
|
+
'image',
|
|
138
|
+
'record',
|
|
139
|
+
'audio',
|
|
140
|
+
'dice',
|
|
141
|
+
'rps',
|
|
142
|
+
'video',
|
|
143
|
+
'file',
|
|
144
|
+
'location',
|
|
145
|
+
'share',
|
|
146
|
+
'json',
|
|
147
|
+
'at',
|
|
148
|
+
'reply',
|
|
149
|
+
'long_msg',
|
|
150
|
+
'button',
|
|
151
|
+
'markdown',
|
|
152
|
+
'xml',
|
|
153
|
+
]
|
|
154
|
+
export function toSegments(message:Sendable):MessageSegment[]{
|
|
155
|
+
if(!Array.isArray(message)) message=[message]
|
|
156
|
+
return message.filter((item,index)=>{
|
|
157
|
+
return typeof item==="string"||(item.type!=='long_msg'||index!==0)
|
|
158
|
+
}).map((item):MessageSegment=>{
|
|
159
|
+
if(typeof item==="string") return {type:'text',data:{text:item}}
|
|
160
|
+
const {type,...data}=item
|
|
161
|
+
return {type,data}
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
export function toSendable(content:SendContent):Sendable{
|
|
165
|
+
if(!Array.isArray(content)) content=[content]
|
|
166
|
+
return content.map((seg):MessageElem=>{
|
|
167
|
+
if(typeof seg==="string") return {type:'text',text:seg}
|
|
168
|
+
let {type,data}=seg
|
|
169
|
+
if(typeof type==='function') type=type.name
|
|
170
|
+
if(!allowTypes.includes(type)) return {type:'text',text:segment.toString(seg)}
|
|
171
|
+
return {type,...data} as MessageElem
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
registerAdapter(new Adapter('icqq',IcqqBot))
|
|
176
|
+
|
|
177
|
+
useContext('web', (web) => {
|
|
178
|
+
// 注册ICQQ适配器的客户端入口文件
|
|
179
|
+
const dispose = web.addEntry({
|
|
180
|
+
production: path.resolve(import.meta.dirname, '../dist/index.js'),
|
|
181
|
+
development: path.resolve(import.meta.dirname, '../client/index.tsx')
|
|
182
|
+
})
|
|
183
|
+
return dispose
|
|
184
|
+
});
|
|
185
|
+
useContext('router','icqq', (router,icqq) => {
|
|
186
|
+
router.get('/api/icqq/bots', async (ctx) => {
|
|
187
|
+
try {
|
|
188
|
+
const bots = Array.from(icqq.bots.values())
|
|
189
|
+
|
|
190
|
+
if (bots.length === 0) {
|
|
191
|
+
ctx.body = {
|
|
192
|
+
success: true,
|
|
193
|
+
data: [],
|
|
194
|
+
message: '暂无ICQQ机器人实例'
|
|
195
|
+
}
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const result = bots.map(bot => {
|
|
200
|
+
try {
|
|
201
|
+
return {
|
|
202
|
+
name: bot.$config.name,
|
|
203
|
+
connected: bot.$connected || false,
|
|
204
|
+
groupCount: bot.gl?.size || 0,
|
|
205
|
+
friendCount: bot.fl?.size || 0,
|
|
206
|
+
receiveCount: bot.stat?.recv_msg_cnt || 0,
|
|
207
|
+
sendCount: bot.stat?.sent_msg_cnt || 0,
|
|
208
|
+
loginMode: bot.$config.password ? 'password' : 'qrcode',
|
|
209
|
+
status: bot.$connected ? 'online' : 'offline',
|
|
210
|
+
lastActivity: new Date().toISOString()
|
|
211
|
+
}
|
|
212
|
+
} catch (botError) {
|
|
213
|
+
// 单个机器人数据获取失败时的处理
|
|
214
|
+
// 获取机器人数据失败,返回错误状态
|
|
215
|
+
return {
|
|
216
|
+
name: bot.$config.name,
|
|
217
|
+
connected: false,
|
|
218
|
+
groupCount: 0,
|
|
219
|
+
friendCount: 0,
|
|
220
|
+
receiveCount: 0,
|
|
221
|
+
sendCount: 0,
|
|
222
|
+
loginMode: 'unknown',
|
|
223
|
+
status: 'error',
|
|
224
|
+
error: '数据获取失败'
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
ctx.body = {
|
|
230
|
+
success: true,
|
|
231
|
+
data: result,
|
|
232
|
+
timestamp: new Date().toISOString()
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
// ICQQ API调用失败
|
|
236
|
+
|
|
237
|
+
ctx.status = 500
|
|
238
|
+
ctx.body = {
|
|
239
|
+
success: false,
|
|
240
|
+
error: 'ICQQ_API_ERROR',
|
|
241
|
+
message: '获取机器人数据失败',
|
|
242
|
+
details: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,
|
|
243
|
+
timestamp: new Date().toISOString()
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
})
|