qqbot 0.0.2 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -11
- data/lib/qqbot/api.rb +225 -73
- data/lib/qqbot/bot.rb +380 -80
- data/lib/qqbot/client.rb +14 -21
- data/lib/qqbot/error.rb +4 -0
- data/lib/qqbot/model.rb +32 -0
- data/lib/qqbot/version.rb +1 -1
- data/lib/qqbot.rb +26 -3
- metadata +3 -3
- data/lib/qqbot/auth.rb +0 -180
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2323213c6970fbad5d18f7eb6d16c265a332ffb3
|
4
|
+
data.tar.gz: 85fb56e409dc95b7623522bee66b931c25258dae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 263e39aadc3568d61200cab91a59e8a942c2ab9c3e286857ae19a91b45cd3015f5cc60cdd89a01eb7b5312a7615b1a812b39cd7d6809317c402cf3bcb3d9ff88
|
7
|
+
data.tar.gz: c156c8f2523c2f63e9471db1176f5db688ae001039e6ac30d7c35e468284831962c9462c5a2842149daec0f0de18a17b138319231b51bd27953cf5a0c67e7e35
|
data/README.md
CHANGED
@@ -17,11 +17,11 @@ require 'qqbot'
|
|
17
17
|
|
18
18
|
qqbot = QQBot.new
|
19
19
|
|
20
|
-
|
20
|
+
# 在这里需要扫描二维码登录
|
21
21
|
|
22
22
|
qqbot.get_group_list.each { |group| puts group.name }
|
23
23
|
|
24
|
-
qqbot.
|
24
|
+
qqbot.get_friend_list_with_category.each do |category|
|
25
25
|
puts category.name
|
26
26
|
category.friends.each do |friend|
|
27
27
|
puts "———— #{friend.nickname}"
|
@@ -36,16 +36,17 @@ end
|
|
36
36
|
- [x] 获取群列表
|
37
37
|
- [x] 获取好友列表
|
38
38
|
- [x] 获取讨论组列表
|
39
|
-
- [
|
40
|
-
- [
|
41
|
-
- [
|
39
|
+
- [x] 发送私聊消息
|
40
|
+
- [x] 发送群消息
|
41
|
+
- [x] 发送讨论组消息
|
42
|
+
- [x] 发送临时消息
|
42
43
|
- [ ] 好友详细信息
|
43
|
-
- [
|
44
|
-
- [
|
45
|
-
- [
|
46
|
-
- [
|
47
|
-
- [
|
48
|
-
- [
|
44
|
+
- [x] 群详细信息
|
45
|
+
- [x] 讨论组详细信息
|
46
|
+
- [x] 获取在线好友
|
47
|
+
- [x] 获取最近会话
|
48
|
+
- [x] 获取登录用户信息
|
49
|
+
- [x] 查询用户 QQ 号
|
49
50
|
- [ ] 退出登录
|
50
51
|
|
51
52
|
|
data/lib/qqbot/api.rb
CHANGED
@@ -1,95 +1,131 @@
|
|
1
1
|
require 'uri'
|
2
|
-
require 'json'
|
3
|
-
require 'fileutils'
|
4
2
|
|
5
3
|
module QQBot
|
6
4
|
class Api
|
7
5
|
|
8
|
-
def initialize
|
9
|
-
@client =
|
6
|
+
def initialize
|
7
|
+
@client = QQBot::Client.new
|
8
|
+
@msg_id = 1_000_000
|
9
|
+
end
|
10
|
+
|
11
|
+
def auth_options=(options = {})
|
10
12
|
@options = options
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
14
|
-
|
15
|
+
def get_qrcode
|
16
|
+
uri = URI('https://ssl.ptlogin2.qq.com/ptqrshow');
|
17
|
+
uri.query =
|
18
|
+
URI.encode_www_form(
|
19
|
+
appid: 501004106,
|
20
|
+
e: 0,
|
21
|
+
l: :M,
|
22
|
+
s: 5,
|
23
|
+
d: 72,
|
24
|
+
v: 4,
|
25
|
+
t: 0.1,
|
26
|
+
)
|
27
|
+
@client.get(uri)
|
28
|
+
end
|
15
29
|
|
16
|
-
|
17
|
-
|
18
|
-
|
30
|
+
def verify_qrcode
|
31
|
+
uri = URI('https://ssl.ptlogin2.qq.com/ptqrlogin');
|
32
|
+
uri.query =
|
33
|
+
URI.encode_www_form(
|
34
|
+
webqq_type: 10,
|
35
|
+
remember_uin: 1,
|
36
|
+
login2qq: 1,
|
37
|
+
aid: 501004106,
|
38
|
+
u1: 'http://Fw.qq.com/proxy.html?login2qq=1&webqq_type=10',
|
39
|
+
ptredirect: 0,
|
40
|
+
ptlang: 2052,
|
41
|
+
daid: 164,
|
42
|
+
from_ui: 1,
|
43
|
+
pttype: 1,
|
44
|
+
dumy: '',
|
45
|
+
fp: 'loginerroralert',
|
46
|
+
action: '0-0-157510',
|
47
|
+
mibao_css: 'm_webqq',
|
48
|
+
t: 1,
|
49
|
+
g: 1,
|
50
|
+
js_type: 0,
|
51
|
+
js_ver: 10143,
|
52
|
+
login_sig: '',
|
53
|
+
pt_randsalt: 0,
|
54
|
+
)
|
55
|
+
@client.get(uri)
|
56
|
+
end
|
19
57
|
|
20
|
-
|
58
|
+
def get_ptwebqq(url)
|
59
|
+
uri = URI(url);
|
60
|
+
code, body = @client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
61
|
+
return code, @client.get_cookie('ptwebqq')
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_vfwebqq(ptwebqq)
|
65
|
+
uri = URI('http://s.web2.qq.com/api/getvfwebqq');
|
66
|
+
uri.query =
|
67
|
+
URI.encode_www_form(
|
68
|
+
ptwebqq: ptwebqq,
|
69
|
+
clientid: QQBot::CLIENT_ID,
|
70
|
+
psessionid: '',
|
71
|
+
t: 0.1,
|
72
|
+
)
|
73
|
+
@client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_psessionid_and_uin(ptwebqq)
|
77
|
+
uri = URI('http://d1.web2.qq.com/channel/login2');
|
78
|
+
r = JSON.generate(
|
79
|
+
ptwebqq: ptwebqq,
|
80
|
+
clientid: QQBot::CLIENT_ID,
|
81
|
+
psessionid: '',
|
82
|
+
status: 'online'
|
83
|
+
)
|
84
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
85
|
+
end
|
21
86
|
|
87
|
+
def self.hash(uin, ptwebqq)
|
88
|
+
n = Array.new(4, 0)
|
89
|
+
ptwebqq.chars.each_index { |i| n[i % 4] ^= ptwebqq[i].ord }
|
90
|
+
u = ['EC', 'OK']
|
22
91
|
v = Array.new(4)
|
23
92
|
v[0] = uin >> 24 & 255 ^ u[0][0].ord;
|
24
93
|
v[1] = uin >> 16 & 255 ^ u[0][1].ord;
|
25
94
|
v[2] = uin >> 8 & 255 ^ u[1][0].ord;
|
26
95
|
v[3] = uin & 255 ^ u[1][1].ord;
|
27
|
-
|
28
96
|
u = Array.new(8)
|
29
|
-
|
30
|
-
u[i] = i.odd? ? v[i >> 1] : n[i >> 1]
|
31
|
-
end
|
32
|
-
|
97
|
+
(0...8).each { |i| u[i] = i.odd? ? v[i >> 1] : n[i >> 1] }
|
33
98
|
n = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
|
34
|
-
|
35
99
|
v = ''
|
36
|
-
|
37
100
|
u.each do |i|
|
38
101
|
v << n[(i >> 4) & 15]
|
39
102
|
v << n[i & 15]
|
40
103
|
end
|
41
|
-
|
42
104
|
v
|
43
105
|
end
|
44
106
|
|
45
107
|
def poll
|
46
108
|
uri = URI('http://d1.web2.qq.com/channel/poll2')
|
47
|
-
|
48
109
|
r = JSON.generate(
|
49
110
|
ptwebqq: @options[:ptwebqq],
|
50
|
-
clientid:
|
111
|
+
clientid: QQBot::CLIENT_ID,
|
51
112
|
psessionid: @options[:psessionid],
|
52
113
|
key: ''
|
53
114
|
)
|
54
|
-
|
55
115
|
begin
|
56
|
-
|
116
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
57
117
|
rescue
|
58
118
|
retry
|
59
119
|
end
|
60
|
-
|
61
|
-
if code == '200'
|
62
|
-
json = JSON.parse body
|
63
|
-
if json['retcode'] == 0
|
64
|
-
return json['result']
|
65
|
-
else
|
66
|
-
QQBot::LOGGER.info "获取消息失败 返回码 #{json['retcode']}"
|
67
|
-
end
|
68
|
-
else
|
69
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
70
|
-
end
|
71
120
|
end
|
72
121
|
|
73
122
|
def get_group_list
|
74
123
|
uri = URI('http://s.web2.qq.com/api/get_group_name_list_mask2')
|
75
|
-
|
76
124
|
r = JSON.generate(
|
77
125
|
vfwebqq: @options[:vfwebqq],
|
78
126
|
hash: hash
|
79
127
|
)
|
80
|
-
|
81
|
-
code, body = @client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
82
|
-
|
83
|
-
if code == '200'
|
84
|
-
json = JSON.parse body
|
85
|
-
if json['retcode'] == 0
|
86
|
-
return json['result']
|
87
|
-
else
|
88
|
-
QQBot::LOGGER.info "获取群列表失败 返回码 #{json['retcode']}"
|
89
|
-
end
|
90
|
-
else
|
91
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
92
|
-
end
|
128
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
93
129
|
end
|
94
130
|
|
95
131
|
def hash
|
@@ -98,52 +134,168 @@ module QQBot
|
|
98
134
|
|
99
135
|
def get_friend_list
|
100
136
|
uri = URI('http://s.web2.qq.com/api/get_user_friends2')
|
101
|
-
|
102
137
|
r = JSON.generate(
|
103
138
|
vfwebqq: @options[:vfwebqq],
|
104
139
|
hash: hash
|
105
140
|
)
|
106
|
-
|
107
|
-
code, body = @client.post(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1', r: r)
|
108
|
-
|
109
|
-
if code == '200'
|
110
|
-
json = JSON.parse body
|
111
|
-
if json['retcode'] == 0
|
112
|
-
return json['result']
|
113
|
-
else
|
114
|
-
QQBot::LOGGER.info "获取好友列表失败 返回码 #{json['retcode']}"
|
115
|
-
end
|
116
|
-
else
|
117
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
118
|
-
end
|
141
|
+
@client.post(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1', r: r)
|
119
142
|
end
|
120
143
|
|
121
144
|
def get_discuss_list
|
122
145
|
uri = URI('http://s.web2.qq.com/api/get_discus_list')
|
123
146
|
uri.query =
|
124
147
|
URI.encode_www_form(
|
125
|
-
clientid:
|
148
|
+
clientid: QQBot::CLIENT_ID,
|
126
149
|
psessionid: @options[:psessionid],
|
127
150
|
vfwebqq: @options[:vfwebqq],
|
128
151
|
t: 0.1
|
129
152
|
)
|
153
|
+
@client.get(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2')
|
154
|
+
end
|
155
|
+
|
156
|
+
def send_to_friend(friend_id, content)
|
157
|
+
uri = URI('http://d1.web2.qq.com/channel/send_buddy_msg2')
|
158
|
+
r = JSON.generate(
|
159
|
+
to: friend_id,
|
160
|
+
content: self.class.build_message(content),
|
161
|
+
face: 522,
|
162
|
+
clientid: QQBot::CLIENT_ID,
|
163
|
+
msg_id: msg_id,
|
164
|
+
psessionid: @options[:psessionid]
|
165
|
+
)
|
166
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
167
|
+
end
|
168
|
+
|
169
|
+
def send_to_group(group_id, content)
|
170
|
+
uri = URI('http://d1.web2.qq.com/channel/send_qun_msg2')
|
171
|
+
r = JSON.generate(
|
172
|
+
group_uin: group_id,
|
173
|
+
content: self.class.build_message(content),
|
174
|
+
face: 522,
|
175
|
+
clientid: QQBot::CLIENT_ID,
|
176
|
+
msg_id: msg_id,
|
177
|
+
psessionid: @options[:psessionid]
|
178
|
+
)
|
179
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
180
|
+
end
|
181
|
+
|
182
|
+
def send_to_discuss(discuss_id, content)
|
183
|
+
uri = URI('http://d1.web2.qq.com/channel/send_discu_msg2')
|
184
|
+
r = JSON.generate(
|
185
|
+
did: discuss_id,
|
186
|
+
content: self.class.build_message(content),
|
187
|
+
face: 522,
|
188
|
+
clientid: QQBot::CLIENT_ID,
|
189
|
+
msg_id: msg_id,
|
190
|
+
psessionid: @options[:psessionid]
|
191
|
+
)
|
192
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
193
|
+
end
|
194
|
+
|
195
|
+
def send_to_sess(sess_id, content)
|
196
|
+
uri = URI('http://d1.web2.qq.com/channel/send_sess_msg2')
|
197
|
+
r = JSON.generate(
|
198
|
+
to: sess_id,
|
199
|
+
content: self.class.build_message(content),
|
200
|
+
face: 522,
|
201
|
+
clientid: QQBot::CLIENT_ID,
|
202
|
+
msg_id: msg_id,
|
203
|
+
psessionid: @options[:psessionid]
|
204
|
+
)
|
205
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_account_info
|
209
|
+
uri = URI('http://s.web2.qq.com/api/get_self_info2')
|
210
|
+
uri.query =
|
211
|
+
URI.encode_www_form(
|
212
|
+
t: 0.1
|
213
|
+
)
|
214
|
+
|
215
|
+
@client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
216
|
+
end
|
217
|
+
|
218
|
+
def get_recent_list
|
219
|
+
uri = URI('http://d1.web2.qq.com/channel/get_recent_list2')
|
220
|
+
r = JSON.generate(
|
221
|
+
vfwebqq: @options[:vfwebqq],
|
222
|
+
clientid: QQBot::CLIENT_ID,
|
223
|
+
psessionid: ''
|
224
|
+
)
|
225
|
+
@client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
226
|
+
end
|
227
|
+
|
228
|
+
def get_qq_by_id(id)
|
229
|
+
uri = URI('http://s.web2.qq.com/api/get_friend_uin2')
|
230
|
+
uri.query =
|
231
|
+
URI.encode_www_form(
|
232
|
+
tuin: id,
|
233
|
+
type: 1,
|
234
|
+
vfwebqq: @options[:vfwebqq],
|
235
|
+
t: 0.1
|
236
|
+
)
|
237
|
+
@client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
238
|
+
end
|
239
|
+
|
240
|
+
def get_online_friends
|
241
|
+
uri = URI('http://d1.web2.qq.com/channel/get_online_buddies2')
|
242
|
+
uri.query =
|
243
|
+
URI.encode_www_form(
|
244
|
+
vfwebqq: @options[:vfwebqq],
|
245
|
+
clientid: QQBot::CLIENT_ID,
|
246
|
+
psessionid: @options[:psessionid],
|
247
|
+
t: 0.1
|
248
|
+
)
|
249
|
+
@client.get(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2')
|
250
|
+
end
|
130
251
|
|
131
|
-
|
252
|
+
def get_group_info(group_code)
|
253
|
+
uri = URI('http://s.web2.qq.com/api/get_group_info_ext2')
|
254
|
+
uri.query =
|
255
|
+
URI.encode_www_form(
|
256
|
+
gcode: group_code,
|
257
|
+
vfwebqq: @options[:vfwebqq],
|
258
|
+
t: 0.1
|
259
|
+
)
|
260
|
+
@client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
261
|
+
end
|
132
262
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
263
|
+
def get_discuss_info(discuss_id)
|
264
|
+
uri = URI('http://d1.web2.qq.com/channel/get_discu_info')
|
265
|
+
uri.query =
|
266
|
+
URI.encode_www_form(
|
267
|
+
did: discuss_id,
|
268
|
+
vfwebqq: @options[:vfwebqq],
|
269
|
+
clientid: QQBot::CLIENT_ID,
|
270
|
+
psessionid: @options[:psessionid],
|
271
|
+
t: 0.1
|
272
|
+
)
|
273
|
+
@client.get(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2')
|
143
274
|
end
|
144
275
|
|
145
276
|
def hash
|
146
277
|
self.class.hash(@options[:uin], @options[:ptwebqq])
|
147
278
|
end
|
279
|
+
|
280
|
+
def msg_id
|
281
|
+
@msg_id += 1
|
282
|
+
end
|
283
|
+
|
284
|
+
def self.build_message(content)
|
285
|
+
JSON.generate(
|
286
|
+
[
|
287
|
+
content,
|
288
|
+
[
|
289
|
+
'font',
|
290
|
+
{
|
291
|
+
name: '宋体',
|
292
|
+
size: 10,
|
293
|
+
style: [0, 0, 0],
|
294
|
+
color: '000000'
|
295
|
+
}
|
296
|
+
]
|
297
|
+
]
|
298
|
+
)
|
299
|
+
end
|
148
300
|
end
|
149
301
|
end
|
data/lib/qqbot/bot.rb
CHANGED
@@ -1,56 +1,166 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module QQBot
|
2
4
|
class Bot
|
3
5
|
def initialize
|
4
|
-
@
|
5
|
-
@
|
6
|
+
@api = QQBot::Api.new
|
7
|
+
@api.auth_options = login
|
6
8
|
end
|
7
9
|
|
8
|
-
def
|
9
|
-
|
10
|
+
def self.check_response_json(code, body)
|
11
|
+
if code == '200'
|
12
|
+
json = JSON.parse body
|
13
|
+
if json['retcode'] == 0
|
14
|
+
return json['result']
|
15
|
+
else
|
16
|
+
QQBot::LOGGER.info "请求失败, JSON返回码 #{json['retcode']}"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
QQBot::LOGGER.info "请求失败,HTTP返回码#{code} retcode"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.check_send_msg_response(code, body)
|
24
|
+
if code == '200'
|
25
|
+
json = JSON.parse body
|
26
|
+
if json['errCode'] == 0
|
27
|
+
QQBot::LOGGER.info '发送成功'
|
28
|
+
return true
|
29
|
+
else
|
30
|
+
QQBot::LOGGER.info "发送失败 返回码 #{json['retcode']}"
|
31
|
+
end
|
32
|
+
else
|
33
|
+
QQBot::LOGGER.info "请求失败,返回码 #{code}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_qrcode
|
38
|
+
code, body = @api.get_qrcode
|
39
|
+
|
40
|
+
if code == '200'
|
41
|
+
file_name = File.expand_path('qrcode.png', File.dirname(__FILE__));
|
42
|
+
|
43
|
+
File.open(file_name, 'wb') do |file|
|
44
|
+
file.write body
|
45
|
+
file.close
|
46
|
+
end
|
47
|
+
|
48
|
+
QQBot::LOGGER.info "二维码已经保存在#{file_name}中"
|
49
|
+
|
50
|
+
unless @pid
|
51
|
+
QQBot::LOGGER.info '开启web服务进程'
|
52
|
+
@pid = spawn("ruby -run -e httpd #{file_name} -p 9090")
|
53
|
+
end
|
10
54
|
|
55
|
+
QQBot::LOGGER.info '也可以通过访问 http://localhost:9090 查看二维码'
|
56
|
+
return true
|
57
|
+
else
|
58
|
+
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def verify_qrcode
|
11
63
|
url = ''
|
12
64
|
|
13
65
|
until url.start_with? 'http' do
|
14
66
|
sleep 5
|
15
|
-
|
16
|
-
|
67
|
+
code, body = @api.verify_qrcode
|
68
|
+
|
69
|
+
if code == '200'
|
70
|
+
result = body.force_encoding("UTF-8")
|
71
|
+
if result.include? '二维码已失效'
|
72
|
+
QQBot::LOGGER.info '二维码已失效,准备重新获取'
|
73
|
+
return unless get_qrcode
|
74
|
+
elsif result.include? 'http'
|
75
|
+
QQBot::LOGGER.info '认证成功'
|
76
|
+
return URI.extract(result).first
|
77
|
+
end
|
78
|
+
else
|
79
|
+
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
80
|
+
return
|
81
|
+
end
|
17
82
|
end
|
83
|
+
end
|
18
84
|
|
19
|
-
|
85
|
+
def close_qrcode_server
|
86
|
+
if @pid
|
87
|
+
QQBot::LOGGER.info '关闭web服务进程'
|
88
|
+
Process.kill('KILL', @pid)
|
89
|
+
@pid = nil
|
90
|
+
end
|
91
|
+
end
|
20
92
|
|
21
|
-
|
93
|
+
def get_ptwebqq(url)
|
94
|
+
code, ptwebqq = @api.get_ptwebqq url
|
22
95
|
|
23
|
-
|
96
|
+
if code == '302'
|
97
|
+
ptwebqq
|
98
|
+
else
|
99
|
+
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
100
|
+
end
|
101
|
+
end
|
24
102
|
|
25
|
-
|
103
|
+
def get_vfwebqq(ptwebqq)
|
104
|
+
code, body = @api.get_vfwebqq(ptwebqq)
|
26
105
|
|
27
|
-
|
106
|
+
result = self.class.check_response_json(code, body)
|
107
|
+
result['vfwebqq'] if result
|
28
108
|
end
|
29
109
|
|
30
|
-
def
|
31
|
-
|
110
|
+
def get_psessionid_and_uin(ptwebqq)
|
111
|
+
code, body = @api.get_psessionid_and_uin ptwebqq
|
32
112
|
|
113
|
+
result = self.class.check_response_json(code, body)
|
114
|
+
if result
|
115
|
+
return result['psessionid'], result['uin']
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def login
|
120
|
+
QQBot::LOGGER.info '开始获取二维码'
|
121
|
+
raise QQBot::Error::LoginFailed unless get_qrcode
|
122
|
+
|
123
|
+
QQBot::LOGGER.info '等待扫描二维码'
|
124
|
+
url = verify_qrcode
|
125
|
+
raise QQBot::Error::LoginFailed unless url
|
126
|
+
|
127
|
+
close_qrcode_server
|
128
|
+
|
129
|
+
QQBot::LOGGER.info '开始获取ptwebqq'
|
130
|
+
ptwebqq = get_ptwebqq url
|
131
|
+
raise QQBot::Error::LoginFailed unless ptwebqq
|
132
|
+
|
133
|
+
QQBot::LOGGER.info '开始获取vfwebqq'
|
134
|
+
vfwebqq = get_vfwebqq ptwebqq
|
135
|
+
raise QQBot::Error::LoginFailed unless vfwebqq
|
136
|
+
|
137
|
+
QQBot::LOGGER.info '开始获取psessionid和uin'
|
138
|
+
psessionid, uin = get_psessionid_and_uin ptwebqq
|
139
|
+
raise QQBot::Error::LoginFailed unless uin && psessionid
|
140
|
+
|
141
|
+
{
|
142
|
+
ptwebqq: ptwebqq,
|
143
|
+
vfwebqq: vfwebqq,
|
144
|
+
psessionid: psessionid,
|
145
|
+
uin: uin
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
def poll
|
33
150
|
loop do
|
34
|
-
|
35
|
-
|
36
|
-
|
151
|
+
code, body = @api.poll
|
152
|
+
result = self.class.check_response_json(code, body)
|
153
|
+
|
154
|
+
if result
|
155
|
+
result.each do |item|
|
37
156
|
message = QQBot::Message.new
|
38
157
|
value = item['value']
|
158
|
+
message.type, message.from_id, message.send_id =
|
39
159
|
case item['poll_type']
|
40
|
-
when 'message' then
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
when 'group_message' then
|
45
|
-
message.type = 1
|
46
|
-
message.from_id = value['from_uin']
|
47
|
-
message.send_id = value['send_uin']
|
48
|
-
when 'discu_message' then
|
49
|
-
message.type = 2
|
50
|
-
message.from_id = value['from_uin']
|
51
|
-
message.send_id = value['send_uin']
|
52
|
-
else
|
53
|
-
message.type = 3
|
160
|
+
when 'message' then [0, value['from_uin'], value['from_uin']]
|
161
|
+
when 'group_message' then [1, value['from_uin'], value['send_uin']]
|
162
|
+
when 'discu_message' then [2, value['from_uin'], value['send_uin']]
|
163
|
+
else 3
|
54
164
|
end
|
55
165
|
message.time = value['time']
|
56
166
|
message.content = value['content'][1]
|
@@ -63,7 +173,7 @@ module QQBot
|
|
63
173
|
font.style = font_json['style']
|
64
174
|
message.font = font
|
65
175
|
|
66
|
-
|
176
|
+
yield if block_given?
|
67
177
|
end
|
68
178
|
end
|
69
179
|
sleep 1
|
@@ -71,12 +181,13 @@ module QQBot
|
|
71
181
|
end
|
72
182
|
|
73
183
|
def get_group_list
|
74
|
-
|
184
|
+
code, body = @api.get_group_list
|
185
|
+
result = self.class.check_response_json(code, body)
|
75
186
|
|
76
|
-
|
187
|
+
if result
|
77
188
|
group_map = {}
|
78
189
|
|
79
|
-
gnamelist =
|
190
|
+
gnamelist = result['gnamelist']
|
80
191
|
gnamelist.each do |item|
|
81
192
|
group = QQBot::Group.new
|
82
193
|
group.name = item['name']
|
@@ -85,57 +196,32 @@ module QQBot
|
|
85
196
|
group_map[group.id] = group
|
86
197
|
end
|
87
198
|
|
88
|
-
gmarklist =
|
199
|
+
gmarklist = result['gmarklist']
|
89
200
|
gmarklist.each do |item|
|
90
201
|
group_map[item['uin']].markname = item['markname']
|
91
202
|
end
|
92
203
|
|
93
|
-
|
204
|
+
group_map.values
|
94
205
|
end
|
95
206
|
end
|
96
207
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
unless json.nil?
|
101
|
-
friend_map = {}
|
102
|
-
category_list = []
|
103
|
-
|
104
|
-
friends = json['friends']
|
105
|
-
friends.each do |item|
|
106
|
-
friend = QQBot::Friend.new
|
107
|
-
friend.id = item['uin']
|
108
|
-
friend.category_id = item['categories']
|
109
|
-
friend_map[friend.id] = friend
|
110
|
-
end
|
111
|
-
|
112
|
-
marknames = json['marknames']
|
113
|
-
marknames.each do |item|
|
114
|
-
friend_map[item['uin']].markname = item['markname']
|
115
|
-
end
|
116
|
-
|
117
|
-
vipinfo = json['vipinfo']
|
118
|
-
vipinfo.each do |item|
|
119
|
-
friend = friend_map[item['u']]
|
120
|
-
friend.is_vip = item['is_vip']
|
121
|
-
friend.vip_level = item['vip_level']
|
122
|
-
end
|
208
|
+
def get_friend_list_with_category
|
209
|
+
code, body = @api.get_friend_list
|
210
|
+
result = self.class.check_response_json(code, body)
|
123
211
|
|
124
|
-
|
125
|
-
|
126
|
-
friend_map[item['uin']].nickname = item['nick']
|
127
|
-
end
|
212
|
+
if result
|
213
|
+
friend_list = self.class.build_friend_list result
|
128
214
|
|
129
|
-
categories =
|
215
|
+
categories = result['categories']
|
130
216
|
has_default_category = false
|
131
|
-
categories.
|
217
|
+
category_list = categories.collect do |item|
|
132
218
|
category = QQBot::Category.new
|
133
219
|
category.name = item['name']
|
134
220
|
category.sort = item['sort']
|
135
221
|
category.id = item['index']
|
136
|
-
category.friends =
|
137
|
-
category_list << category
|
222
|
+
category.friends = friend_list.select { |friend| friend.category_id == category.id }
|
138
223
|
has_default_category ||= (category.id == 0)
|
224
|
+
category
|
139
225
|
end
|
140
226
|
|
141
227
|
unless has_default_category
|
@@ -143,29 +229,243 @@ module QQBot
|
|
143
229
|
category.name = '我的好友(默认)'
|
144
230
|
category.sort = 1
|
145
231
|
category.id = 0
|
146
|
-
category.friends =
|
232
|
+
category.friends = friend_list.select { |friend| friend.category_id == category.id }
|
147
233
|
category_list << category
|
148
234
|
end
|
149
235
|
|
150
|
-
|
236
|
+
category_list
|
151
237
|
end
|
152
238
|
end
|
153
239
|
|
154
|
-
def
|
155
|
-
|
240
|
+
def get_friend_list
|
241
|
+
code, body = @api.get_friend_list
|
242
|
+
result = self.class.check_response_json(code, body)
|
156
243
|
|
157
|
-
|
158
|
-
|
244
|
+
if result
|
245
|
+
self.class.build_friend_list(result)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def self.build_friend_list(json)
|
250
|
+
friend_map = {}
|
251
|
+
|
252
|
+
friends = json['friends']
|
253
|
+
friends.each do |item|
|
254
|
+
friend = QQBot::Friend.new
|
255
|
+
friend.id = item['uin']
|
256
|
+
friend.category_id = item['categories']
|
257
|
+
friend_map[friend.id] = friend
|
258
|
+
end
|
159
259
|
|
160
|
-
|
161
|
-
|
260
|
+
marknames = json['marknames']
|
261
|
+
marknames.each do |item|
|
262
|
+
friend_map[item['uin']].markname = item['markname']
|
263
|
+
end
|
264
|
+
|
265
|
+
vipinfo = json['vipinfo']
|
266
|
+
vipinfo.each do |item|
|
267
|
+
friend = friend_map[item['u']]
|
268
|
+
friend.is_vip = item['is_vip']
|
269
|
+
friend.vip_level = item['vip_level']
|
270
|
+
end
|
271
|
+
|
272
|
+
info = json['info']
|
273
|
+
info.each do |item|
|
274
|
+
friend_map[item['uin']].nickname = item['nick']
|
275
|
+
end
|
276
|
+
|
277
|
+
friend_map.values
|
278
|
+
end
|
279
|
+
|
280
|
+
def get_discuss_list
|
281
|
+
code, body = @api.get_discuss_list
|
282
|
+
result = self.class.check_response_json(code, body)
|
283
|
+
|
284
|
+
if result
|
285
|
+
dnamelist = result['dnamelist']
|
286
|
+
dnamelist.collect do |item|
|
162
287
|
discuss = QQBot::Discuss.new
|
163
288
|
discuss.name = item['name']
|
164
289
|
discuss.id = item['did']
|
165
|
-
|
290
|
+
discuss
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def send_to_friend(friend_id, content)
|
296
|
+
code, body = @api.send_to_friend(friend_id, content)
|
297
|
+
self.class.check_send_msg_response(code, body)
|
298
|
+
end
|
299
|
+
|
300
|
+
def send_to_group(group_id, content)
|
301
|
+
code, body = @api.send_to_group(group_id, content)
|
302
|
+
self.class.check_send_msg_response(code, body)
|
303
|
+
end
|
304
|
+
|
305
|
+
def send_to_discuss(discuss_id, content)
|
306
|
+
code, body = @api.send_to_discuss(discuss_id, content)
|
307
|
+
self.class.check_send_msg_response(code, body)
|
308
|
+
end
|
309
|
+
|
310
|
+
def send_to_sess(sess_id, content)
|
311
|
+
code, body = @api.send_to_sess(sess_id, content)
|
312
|
+
self.class.check_send_msg_response(code, body)
|
313
|
+
end
|
314
|
+
|
315
|
+
def get_account_info
|
316
|
+
code, body = @api.get_account_info
|
317
|
+
result = self.class.check_response_json(code, body)
|
318
|
+
|
319
|
+
if result
|
320
|
+
# TODO
|
321
|
+
account_info = QQBot::AccountInfo.new
|
322
|
+
account_info.phone = result['phone']
|
323
|
+
account_info.occupation = result['occupation']
|
324
|
+
account_info.college = result['college']
|
325
|
+
account_info.id = result['uin']
|
326
|
+
account_info.blood = result['blood']
|
327
|
+
account_info.slogan = result['lnick']
|
328
|
+
account_info.homepage = result['homepage']
|
329
|
+
account_info.vip_info = result['vip_info']
|
330
|
+
account_info.city = result['city']
|
331
|
+
account_info.country = result['country']
|
332
|
+
account_info.province = result['province']
|
333
|
+
account_info.personal = result['personal']
|
334
|
+
account_info.shengxiao = result['shengxiao']
|
335
|
+
account_info.nickname = result['nick']
|
336
|
+
account_info.email = result['email']
|
337
|
+
account_info.account = result['account']
|
338
|
+
account_info.gender = result['gender']
|
339
|
+
account_info.mobile = result['mobile']
|
340
|
+
birthday = QQBot::Birthday.new
|
341
|
+
birthday.year = result['birthday']['year']
|
342
|
+
birthday.month = result['birthday']['month']
|
343
|
+
birthday.day = result['birthday']['day']
|
344
|
+
account_info.birthday = birthday
|
345
|
+
|
346
|
+
account_info
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def get_recent_list
|
351
|
+
code, body = @api.get_recent_list
|
352
|
+
result = self.class.check_response_json(code, body)
|
353
|
+
|
354
|
+
if result
|
355
|
+
result.collect do |item|
|
356
|
+
recent = QQBot::Recent.new
|
357
|
+
recent.id = item['uin']
|
358
|
+
recent.type = item['type']
|
359
|
+
recent
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def get_qq_by_id(id)
|
365
|
+
code, body = @api.get_qq_by_id(id)
|
366
|
+
result = self.class.check_response_json(code, body)
|
367
|
+
|
368
|
+
if result
|
369
|
+
result['account']
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def get_online_friends
|
374
|
+
code, body = @api.get_online_friends
|
375
|
+
result = self.class.check_response_json(code, body)
|
376
|
+
|
377
|
+
if result
|
378
|
+
result.collect do |item|
|
379
|
+
online = QQBot::Online.new
|
380
|
+
online.id = item['uin']
|
381
|
+
online.client_type = item['client_type']
|
382
|
+
online
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def get_group_info(group_code)
|
388
|
+
code, body = @api.get_group_info(group_code)
|
389
|
+
result = self.class.check_response_json(code, body)
|
390
|
+
|
391
|
+
if result
|
392
|
+
group_info = QQBot::GroupInfo.new
|
393
|
+
ginfo = result['ginfo']
|
394
|
+
group_info.id = ginfo['gid']
|
395
|
+
group_info.create_time = ginfo['createtime']
|
396
|
+
group_info.memo = ginfo['memo']
|
397
|
+
group_info.name = ginfo['name']
|
398
|
+
group_info.owner_id = ginfo['owner']
|
399
|
+
group_info.markname = ginfo['markname']
|
400
|
+
|
401
|
+
member_map = {}
|
402
|
+
|
403
|
+
minfo = result['minfo']
|
404
|
+
minfo.each do |item|
|
405
|
+
member = QQBot::GroupMember.new
|
406
|
+
member.id = item['uin']
|
407
|
+
member.nickname = item['nick']
|
408
|
+
member.gender = item['gender']
|
409
|
+
member.country = item['country']
|
410
|
+
member.city = item['city']
|
411
|
+
member_map[member.id] = member
|
412
|
+
end
|
413
|
+
|
414
|
+
cards = result['cards']
|
415
|
+
cards.each do |item|
|
416
|
+
member_map[item['muin']].markname = item['card']
|
417
|
+
end
|
418
|
+
|
419
|
+
vipinfo = result['vipinfo']
|
420
|
+
vipinfo.each do |item|
|
421
|
+
member = member_map[item['u']]
|
422
|
+
member.is_vip = item['is_vip']
|
423
|
+
member.vip_level = item['vip_level']
|
424
|
+
end
|
425
|
+
|
426
|
+
stats = result['stats']
|
427
|
+
stats.each do |item|
|
428
|
+
member = member_map[item['uin']]
|
429
|
+
member.client_type = item['client_type']
|
430
|
+
member.status = item['stat']
|
166
431
|
end
|
167
432
|
|
168
|
-
|
433
|
+
group_info.members = member_map.values
|
434
|
+
|
435
|
+
group_info
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
def get_discuss_info(discuss_id)
|
440
|
+
code, body = @api.get_discuss_info(discuss_id)
|
441
|
+
result = self.class.check_response_json(code, body)
|
442
|
+
|
443
|
+
if result
|
444
|
+
discuss_info = QQBot::DiscussInfo.new
|
445
|
+
info = result['info']
|
446
|
+
discuss_info.id = info['did']
|
447
|
+
discuss_info.name = info['discu_name']
|
448
|
+
|
449
|
+
member_map = {}
|
450
|
+
|
451
|
+
mem_info = result['mem_info']
|
452
|
+
mem_info.each do |item|
|
453
|
+
member = QQBot::DiscussMember.new
|
454
|
+
member.id = item['uin']
|
455
|
+
member.nickname = item['nick']
|
456
|
+
member_map[member.id] = member
|
457
|
+
end
|
458
|
+
|
459
|
+
mem_status = result['mem_status']
|
460
|
+
mem_status.each do |item|
|
461
|
+
member = member_map[item['uin']]
|
462
|
+
member.client_type = item['client_type']
|
463
|
+
member.status = item['status']
|
464
|
+
end
|
465
|
+
|
466
|
+
discuss_info.members = member_map.values
|
467
|
+
|
468
|
+
discuss_info
|
169
469
|
end
|
170
470
|
end
|
171
471
|
end
|
data/lib/qqbot/client.rb
CHANGED
@@ -6,8 +6,8 @@ module QQBot
|
|
6
6
|
|
7
7
|
@@user_agent = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36';
|
8
8
|
|
9
|
-
def self.origin
|
10
|
-
uri.scheme
|
9
|
+
def self.origin(uri)
|
10
|
+
"#{uri.scheme}://#{uri.host}"
|
11
11
|
end
|
12
12
|
|
13
13
|
def initialize
|
@@ -15,52 +15,45 @@ module QQBot
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def get(uri, referer = '')
|
18
|
+
QQBot::LOGGER.debug { "get #{uri.to_s}" }
|
19
|
+
|
18
20
|
Net::HTTP.start(uri.host, uri.port,
|
19
21
|
use_ssl: uri.scheme == 'https',
|
20
22
|
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
|
21
|
-
|
22
|
-
req = Net::HTTP::Get.new uri
|
23
|
-
|
23
|
+
req = Net::HTTP::Get.new(uri)
|
24
24
|
req.initialize_http_header(
|
25
25
|
'User-Agent' => @@user_agent,
|
26
26
|
'Cookie' => @cookie.to_s,
|
27
27
|
'Referer' => referer
|
28
28
|
)
|
29
|
-
|
30
|
-
res
|
31
|
-
|
32
|
-
@cookie.put res.get_fields('set-cookie')
|
33
|
-
|
29
|
+
res = http.request(req)
|
30
|
+
@cookie.put(res.get_fields('set-cookie'))
|
31
|
+
QQBot::LOGGER.debug { "code: #{res.code}, body: #{res.body}" }
|
34
32
|
return res.code, res.body
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
38
36
|
def post(uri, referer = '', form_data = {})
|
37
|
+
QQBot::LOGGER.debug { "post uri: #{uri.to_s} data: #{form_data.to_s}" }
|
39
38
|
Net::HTTP.start(uri.host, uri.port,
|
40
39
|
use_ssl: uri.scheme == 'https',
|
41
40
|
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
|
42
|
-
|
43
|
-
req = Net::HTTP::Post.new uri
|
44
|
-
|
41
|
+
req = Net::HTTP::Post.new(uri)
|
45
42
|
req.set_form_data(form_data)
|
46
|
-
|
47
43
|
req.initialize_http_header(
|
48
44
|
'User-Agent' => @@user_agent,
|
49
45
|
'Cookie' => @cookie.to_s,
|
50
46
|
'Referer' => referer,
|
51
47
|
'Origin' => self.class.origin(uri)
|
52
48
|
)
|
53
|
-
|
54
|
-
res
|
55
|
-
|
56
|
-
@cookie.put res.get_fields('set-cookie')
|
57
|
-
|
49
|
+
res = http.request(req)
|
50
|
+
@cookie.put(res.get_fields('set-cookie'))
|
51
|
+
QQBot::LOGGER.debug { "response code: #{res.code}, body: #{res.body}" }
|
58
52
|
return res.code, res.body
|
59
|
-
|
60
53
|
end
|
61
54
|
end
|
62
55
|
|
63
|
-
def get_cookie
|
56
|
+
def get_cookie(key)
|
64
57
|
@cookie[key]
|
65
58
|
end
|
66
59
|
end
|
data/lib/qqbot/error.rb
ADDED
data/lib/qqbot/model.rb
CHANGED
@@ -22,4 +22,36 @@ module QQBot
|
|
22
22
|
class Font
|
23
23
|
attr_accessor :color, :name, :size, :style
|
24
24
|
end
|
25
|
+
|
26
|
+
class AccountInfo
|
27
|
+
attr_accessor :phone, :occupation, :college, :id, :blood, :slogan, :homepage, :vip_info, :city, :country, :province, :personal, :shengxiao, :nickname, :email, :account, :gender, :mobile, :birthday
|
28
|
+
end
|
29
|
+
|
30
|
+
class Birthday
|
31
|
+
attr_accessor :year, :month, :day
|
32
|
+
end
|
33
|
+
|
34
|
+
class Recent
|
35
|
+
attr_accessor :id, :type
|
36
|
+
end
|
37
|
+
|
38
|
+
class Online
|
39
|
+
attr_accessor :id, :client_type
|
40
|
+
end
|
41
|
+
|
42
|
+
class GroupMember
|
43
|
+
attr_accessor :id, :nickname, :gender, :country, :city, :markname, :is_vip, :vip_level, :client_type, :status
|
44
|
+
end
|
45
|
+
|
46
|
+
class GroupInfo
|
47
|
+
attr_accessor :id, :create_time, :memo, :name, :owner_id, :markname, :members
|
48
|
+
end
|
49
|
+
|
50
|
+
class DiscussInfo
|
51
|
+
attr_accessor :id, :name, :members
|
52
|
+
end
|
53
|
+
|
54
|
+
class DiscussMember
|
55
|
+
attr_accessor :id, :nickname, :client_type, :status
|
56
|
+
end
|
25
57
|
end
|
data/lib/qqbot/version.rb
CHANGED
data/lib/qqbot.rb
CHANGED
@@ -1,11 +1,25 @@
|
|
1
|
-
require 'qqbot/version'
|
2
1
|
require 'logger'
|
2
|
+
require 'qqbot/version'
|
3
3
|
|
4
4
|
module QQBot
|
5
5
|
|
6
|
-
|
6
|
+
class Logger < Logger
|
7
|
+
|
8
|
+
def info(*args)
|
9
|
+
super || false if info?
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug(*args)
|
13
|
+
super || false if debug?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
LOGGER = QQBot::Logger.new(STDOUT)
|
18
|
+
LOGGER.datetime_format = '%Y-%m-%d %H:%M:%S'
|
19
|
+
LOGGER.level = Logger::INFO
|
20
|
+
|
21
|
+
CLIENT_ID = 53999199
|
7
22
|
|
8
|
-
autoload :Auth, 'qqbot/auth'
|
9
23
|
autoload :Cookie, 'qqbot/cookie'
|
10
24
|
autoload :Client, 'qqbot/client'
|
11
25
|
autoload :Api, 'qqbot/api'
|
@@ -16,6 +30,15 @@ module QQBot
|
|
16
30
|
autoload :Discuss, 'qqbot/model'
|
17
31
|
autoload :Message, 'qqbot/model'
|
18
32
|
autoload :Font, 'qqbot/model'
|
33
|
+
autoload :AccountInfo, 'qqbot/model'
|
34
|
+
autoload :Birthday, 'qqbot/model'
|
35
|
+
autoload :Recent, 'qqbot/model'
|
36
|
+
autoload :Online, 'qqbot/model'
|
37
|
+
autoload :GroupInfo, 'qqbot/model'
|
38
|
+
autoload :GroupMember, 'qqbot/model'
|
39
|
+
autoload :DiscussInfo, 'qqbot/model'
|
40
|
+
autoload :DiscussMember, 'qqbot/model'
|
41
|
+
autoload :Error, 'qqbot/error'
|
19
42
|
|
20
43
|
def self.new
|
21
44
|
QQBot::Bot.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qqbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ScienJus
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,10 +71,10 @@ files:
|
|
71
71
|
- bin/setup
|
72
72
|
- lib/qqbot.rb
|
73
73
|
- lib/qqbot/api.rb
|
74
|
-
- lib/qqbot/auth.rb
|
75
74
|
- lib/qqbot/bot.rb
|
76
75
|
- lib/qqbot/client.rb
|
77
76
|
- lib/qqbot/cookie.rb
|
77
|
+
- lib/qqbot/error.rb
|
78
78
|
- lib/qqbot/model.rb
|
79
79
|
- lib/qqbot/version.rb
|
80
80
|
- qqbot.gemspec
|
data/lib/qqbot/auth.rb
DELETED
@@ -1,180 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'json'
|
3
|
-
require 'fileutils'
|
4
|
-
|
5
|
-
module QQBot
|
6
|
-
class Auth
|
7
|
-
|
8
|
-
def initialize client
|
9
|
-
@client = client
|
10
|
-
end
|
11
|
-
|
12
|
-
def get_qrcode
|
13
|
-
QQBot::LOGGER.info '开始获取二维码'
|
14
|
-
|
15
|
-
uri = URI('https://ssl.ptlogin2.qq.com/ptqrshow');
|
16
|
-
|
17
|
-
uri.query =
|
18
|
-
URI.encode_www_form(
|
19
|
-
appid: 501004106,
|
20
|
-
e: 0,
|
21
|
-
l: :M,
|
22
|
-
s: 5,
|
23
|
-
d: 72,
|
24
|
-
v: 4,
|
25
|
-
t: 0.1,
|
26
|
-
)
|
27
|
-
|
28
|
-
code, body = @client.get uri
|
29
|
-
|
30
|
-
if code == '200'
|
31
|
-
file_name = File.expand_path('qrcode.png', File.dirname(__FILE__));
|
32
|
-
|
33
|
-
File.open(file_name, 'wb') do |file|
|
34
|
-
file.write body
|
35
|
-
file.close
|
36
|
-
end
|
37
|
-
|
38
|
-
QQBot::LOGGER.info "二维码已经保存在#{file_name}中"
|
39
|
-
|
40
|
-
if @pid.nil?
|
41
|
-
QQBot::LOGGER.info '开启web服务进程'
|
42
|
-
@pid = spawn("ruby -run -e httpd #{file_name} -p 9090")
|
43
|
-
end
|
44
|
-
|
45
|
-
QQBot::LOGGER.info '也可以通过访问 http://localhost:9090 查看二维码'
|
46
|
-
else
|
47
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def verify_qrcode
|
52
|
-
QQBot::LOGGER.info '等待扫描二维码'
|
53
|
-
|
54
|
-
uri = URI('https://ssl.ptlogin2.qq.com/ptqrlogin');
|
55
|
-
uri.query =
|
56
|
-
URI.encode_www_form(
|
57
|
-
webqq_type: 10,
|
58
|
-
remember_uin: 1,
|
59
|
-
login2qq: 1,
|
60
|
-
aid: 501004106,
|
61
|
-
u1: 'http://Fw.qq.com/proxy.html?login2qq=1&webqq_type=10',
|
62
|
-
ptredirect: 0,
|
63
|
-
ptlang: 2052,
|
64
|
-
daid: 164,
|
65
|
-
from_ui: 1,
|
66
|
-
pttype: 1,
|
67
|
-
dumy: '',
|
68
|
-
fp: 'loginerroralert',
|
69
|
-
action: '0-0-157510',
|
70
|
-
mibao_css: 'm_webqq',
|
71
|
-
t: 1,
|
72
|
-
g: 1,
|
73
|
-
js_type: 0,
|
74
|
-
js_ver: 10143,
|
75
|
-
login_sig: '',
|
76
|
-
pt_randsalt: 0,
|
77
|
-
)
|
78
|
-
|
79
|
-
code, body = @client.get uri
|
80
|
-
|
81
|
-
if code == '200'
|
82
|
-
result = body.force_encoding("UTF-8")
|
83
|
-
if result.include? '二维码已失效'
|
84
|
-
QQBot::LOGGER.info '二维码已失效,请重新获取'
|
85
|
-
return '-1'
|
86
|
-
elsif result.include? 'http'
|
87
|
-
QQBot::LOGGER.info '认证成功'
|
88
|
-
unless @pid.nil?
|
89
|
-
QQBot::LOGGER.info '关闭web服务进程'
|
90
|
-
Process.kill('KILL', @pid)
|
91
|
-
@pid = nil
|
92
|
-
end
|
93
|
-
return URI.extract(result)[0]
|
94
|
-
else
|
95
|
-
return '0'
|
96
|
-
end
|
97
|
-
else
|
98
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
99
|
-
return '0'
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def get_ptwebqq url
|
104
|
-
QQBot::LOGGER.info '开始获取ptwebqq'
|
105
|
-
|
106
|
-
uri = URI(url);
|
107
|
-
|
108
|
-
code, body = @client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
109
|
-
|
110
|
-
if code == '302'
|
111
|
-
@ptwebqq = @client.get_cookie 'ptwebqq'
|
112
|
-
else
|
113
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def get_vfwebqq
|
118
|
-
QQBot::LOGGER.info '开始获取vfwebqq'
|
119
|
-
|
120
|
-
uri = URI('http://s.web2.qq.com/api/getvfwebqq');
|
121
|
-
|
122
|
-
uri.query =
|
123
|
-
URI.encode_www_form(
|
124
|
-
ptwebqq: @ptwebqq,
|
125
|
-
clientid: 53999199,
|
126
|
-
psessionid: '',
|
127
|
-
t: 0.1,
|
128
|
-
)
|
129
|
-
|
130
|
-
code, body = @client.get(uri, 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1')
|
131
|
-
|
132
|
-
if code == '200'
|
133
|
-
json = JSON.parse body
|
134
|
-
if json['retcode'] == 0
|
135
|
-
@vfwebqq = json['result']['vfwebqq']
|
136
|
-
else
|
137
|
-
QQBot::LOGGER.info "获取vfwebqq失败 返回码 #{json['retcode']}"
|
138
|
-
end
|
139
|
-
else
|
140
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def get_psessionid_and_uin
|
145
|
-
QQBot::LOGGER.info '开始获取psessionid和uin'
|
146
|
-
|
147
|
-
uri = URI('http://d1.web2.qq.com/channel/login2');
|
148
|
-
|
149
|
-
r = JSON.generate(
|
150
|
-
ptwebqq: @ptwebqq,
|
151
|
-
clientid: 53999199,
|
152
|
-
psessionid: '',
|
153
|
-
status: 'online'
|
154
|
-
)
|
155
|
-
|
156
|
-
code, body = @client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
|
157
|
-
|
158
|
-
if code == '200'
|
159
|
-
json = JSON.parse body
|
160
|
-
if json['retcode'] == 0
|
161
|
-
@uin = json['result']['uin']
|
162
|
-
@psessionid = json['result']['psessionid']
|
163
|
-
else
|
164
|
-
QQBot::LOGGER.info "获取vfwebqq失败 返回码 #{json['retcode']}"
|
165
|
-
end
|
166
|
-
else
|
167
|
-
QQBot::LOGGER.info "请求失败,返回码#{code}"
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def options
|
172
|
-
{
|
173
|
-
ptwebqq: @ptwebqq,
|
174
|
-
vfwebqq: @vfwebqq,
|
175
|
-
psessionid: @psessionid,
|
176
|
-
uin: @uin
|
177
|
-
}
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|