qqbot 0.0.2 → 0.1.1

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.
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