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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4747aff11d6401325e92d7f6c971d5840161d84
4
- data.tar.gz: 4887f1da58515e0482d1ada0dba7d384371f58c1
3
+ metadata.gz: 2323213c6970fbad5d18f7eb6d16c265a332ffb3
4
+ data.tar.gz: 85fb56e409dc95b7623522bee66b931c25258dae
5
5
  SHA512:
6
- metadata.gz: 685e6cbfb49018deb77299a4bd93dce9eeaceb69bd194fe111b2b485cda0a4b78621f8190611a87736951c4a38833a028e709d2fee2585c03787dd66cb663efa
7
- data.tar.gz: b4464f68b8aeca510a989034257cbe8f59f16903340ed593c5771796331b557880d4a4c8b111e388d366dd8d67a20204d2d02a5bfc135056ad0861ebe8dca73d
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
- qqbot.login
20
+ # 在这里需要扫描二维码登录
21
21
 
22
22
  qqbot.get_group_list.each { |group| puts group.name }
23
23
 
24
- qqbot.get_friend_list.each do |category|
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
- - [ ] 查询用户 QQ 号
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(client, options = {})
9
- @client = 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 self.hash(uin, ptwebqq)
14
- n = Array.new(4, 0)
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
- for i in (0...ptwebqq.size)
17
- n[i % 4] ^= ptwebqq[i].ord
18
- end
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
- u = ['EC', 'OK']
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
- for i in (0...8)
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: 53999199,
111
+ clientid: QQBot::CLIENT_ID,
51
112
  psessionid: @options[:psessionid],
52
113
  key: ''
53
114
  )
54
-
55
115
  begin
56
- code, body = @client.post(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2', r: r)
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: 53999199,
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
- code, body = @client.get(uri, 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2')
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
- if code == '200'
134
- json = JSON.parse body
135
- if json['retcode'] == 0
136
- return json['result']
137
- else
138
- QQBot::LOGGER.info "获取群列表失败 返回码 #{json['retcode']}"
139
- end
140
- else
141
- QQBot::LOGGER.info "请求失败,返回码#{code}"
142
- end
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
- @client = QQBot::Client.new
5
- @auth = QQBot::Auth.new @client
6
+ @api = QQBot::Api.new
7
+ @api.auth_options = login
6
8
  end
7
9
 
8
- def login
9
- @auth.get_qrcode
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
- url = @auth.verify_qrcode
16
- @auth.get_qrcode if url == '-1'
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
- @auth.get_ptwebqq url
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
- @auth.get_vfwebqq
93
+ def get_ptwebqq(url)
94
+ code, ptwebqq = @api.get_ptwebqq url
22
95
 
23
- @auth.get_psessionid_and_uin
96
+ if code == '302'
97
+ ptwebqq
98
+ else
99
+ QQBot::LOGGER.info "请求失败,返回码#{code}"
100
+ end
101
+ end
24
102
 
25
- auth_options = @auth.options
103
+ def get_vfwebqq(ptwebqq)
104
+ code, body = @api.get_vfwebqq(ptwebqq)
26
105
 
27
- @api = QQBot::Api.new(@client, auth_options)
106
+ result = self.class.check_response_json(code, body)
107
+ result['vfwebqq'] if result
28
108
  end
29
109
 
30
- def poll &block
31
- return if @api.nil?
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
- json = @api.poll
35
- unless json.nil?
36
- json.each do |item|
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
- message.type = 0
42
- message.from_id = value['from_uin']
43
- message.send_id = value['from_uin']
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
- block.call message
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
- json = @api.nil? ? nil : @api.get_group_list
184
+ code, body = @api.get_group_list
185
+ result = self.class.check_response_json(code, body)
75
186
 
76
- unless json.nil?
187
+ if result
77
188
  group_map = {}
78
189
 
79
- gnamelist = json['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 = json['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
- return group_map.values
204
+ group_map.values
94
205
  end
95
206
  end
96
207
 
97
- def get_friend_list
98
- json = @api.nil? ? nil : @api.get_friend_list
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
- info = json['info']
125
- info.each do |item|
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 = json['categories']
215
+ categories = result['categories']
130
216
  has_default_category = false
131
- categories.each do |item|
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 = friend_map.values.select { |friend| friend.category_id == category.id }
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 = friend_map.values.select { |friend| friend.category_id == category.id }
232
+ category.friends = friend_list.select { |friend| friend.category_id == category.id }
147
233
  category_list << category
148
234
  end
149
235
 
150
- return category_list
236
+ category_list
151
237
  end
152
238
  end
153
239
 
154
- def get_discuss_list
155
- json = @api.nil? ? nil : @api.get_discuss_list
240
+ def get_friend_list
241
+ code, body = @api.get_friend_list
242
+ result = self.class.check_response_json(code, body)
156
243
 
157
- unless json.nil?
158
- discuss_list = []
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
- dnamelist = json['dnamelist']
161
- dnamelist.each do |item|
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
- discuss_list << discuss
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
- return discuss_list
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 uri
10
- uri.scheme + '://' + uri.host
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 = http.request req
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 = http.request req
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 key
56
+ def get_cookie(key)
64
57
  @cookie[key]
65
58
  end
66
59
  end
@@ -0,0 +1,4 @@
1
+ module QQBot
2
+ class Error < StandardError; end
3
+ class Error::LoginFailed < Error; end
4
+ end
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
@@ -1,3 +1,3 @@
1
1
  module QQBot
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.1"
3
3
  end
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
- LOGGER = Logger.new(STDOUT)
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.0.2
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-29 00:00:00.000000000 Z
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