tjplurker 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/tjplurker.rb +248 -0
  2. metadata +59 -0
data/lib/tjplurker.rb ADDED
@@ -0,0 +1,248 @@
1
+ # :title:TJPlurker API Documentation
2
+ require 'logger'
3
+ require 'json'
4
+ require 'net/http'
5
+
6
+ $tjpLog = Logger.new(STDOUT)
7
+ $tjpLog.level = Logger::INFO
8
+ $tjpLog.formatter = proc{ |severity, datetime, progname, msg|
9
+ "#{severity} [#{datetime}] in #{progname} -- #{msg}\n"
10
+ }
11
+ # It's a wrapper of Plurk API.
12
+ # Note that every methods in this class returns a JSON object
13
+ # which was converted from Plurk server's response.
14
+ # All mehtods will retry again when request timeout occurs.
15
+ class TJPlurker
16
+ # Plurk user ID.
17
+ attr_reader :user
18
+
19
+ # If +auto_login+ sets +true+, it will autologin while constructing.
20
+ def initialize api_key, user, passwd, auto_login=true
21
+ @user, @passwd, @api_key = user, passwd, api_key
22
+ @cookie = nil
23
+ @user_channel = nil
24
+ @id_buffer = nil
25
+ login if auto_login
26
+ end
27
+
28
+ # If no_data sets true, the successful login message was simplified as follow:
29
+ #
30
+ # {"success_text": "ok"}
31
+ #
32
+ # Otherwise, more details of user's profile were retured.
33
+ def login no_data=true
34
+ method = "/API/Users/login"
35
+ attr = {:username=>@user, :password=>@passwd, :api_key=>@api_key}
36
+ attr[:no_data] = '1' if no_data
37
+ api(method, attr)
38
+ end
39
+
40
+ def plurk_add content, qualifier=':', limited_to=nil, no_comments=nil, lang='tr_ch'
41
+ method = "/API/Timeline/plurkAdd"
42
+ attr = {:api_key=>@api_key, :content=>content, :qualifier=>qualifier,:limited_to=>limited_to, :no_comments=>no_comments, :lang=>lang}
43
+ api(method, attr)
44
+ end
45
+
46
+ def response_add plurk_id, content, qualifier=':'
47
+ method = "/API/Responses/responseAdd"
48
+ attr = {:api_key=>@api_key, :plurk_id=>plurk_id, :content=>content, :qualifier=>qualifier}
49
+ api(method, attr)
50
+ end
51
+
52
+ def become_fan fan_id
53
+ method = "/API/FriendsFans/becomeFan"
54
+ attr = {:api_key=>@api_key, :fan_id=>fan_id}
55
+ api(method, attr)
56
+ end
57
+
58
+ def add_all_as_friends
59
+ method = "/API/Alerts/addAllAsFriends"
60
+ attr = {:api_key=>@api_key}
61
+ api(method, attr)
62
+ end
63
+
64
+ def get_friends_by_offset user_id, limit=100, offset='0'
65
+ method = "/API/FriendsFans/getFriendsByOffset"
66
+ attr = {:api_key=>@api_key, :user_id=>user_id, :offset=>offset, :limit=>limit}
67
+ api(method, attr)
68
+ end
69
+
70
+ def get_public_profile user_id
71
+ method = "/API/Profile/getPublicProfile"
72
+ attr = {:api_key=>@api_key, :user_id=>user_id}
73
+ api(method, attr)
74
+ end
75
+
76
+ # Warning:: It has bugs in offecial Plurk API.
77
+ def get_plurks limit=nil, offset=nil
78
+ method = "/API/Polling/getPlurks"
79
+ attr = {:api_key=>@api_key, :limit=>limit, :offset=>offset}
80
+ api(method, attr)
81
+ end
82
+
83
+ def get_user_channel
84
+ method = "/API/Realtime/getUserChannel"
85
+ attr = {:api_key=>@api_key}
86
+ api(method, attr)
87
+ end
88
+
89
+ def comet_channel
90
+ #Assign new channel if @user_channel is nil
91
+ @user_channel ||= get_user_channel
92
+ begin
93
+ res = Net::HTTP.get_response(URI.parse(@user_channel['comet_server']))
94
+ json = JSON.parse(res.body.sub!(/CometChannel\.scriptCallback\((.*)\);/){|match| $1})
95
+ rescue Timeout::Error => ex
96
+ $tjpLog.warn(self.class){"Request timeout, retry."}
97
+ retry
98
+ rescue => ex
99
+ $tjpLog.fatal(self.class){"Unknown error, stop."}
100
+ puts ex.backtrace
101
+ exit
102
+ end
103
+ #Update the offset
104
+ @user_channel['comet_server'].sub!(/[\d]+$/, json["new_offset"].to_s)
105
+ if json['data']
106
+ json['data'].each{|member|
107
+ notification = NotificationData.new(member)
108
+ return if notification.id == @id_buffer
109
+ $tjpLog.info(self.class){"Notification: #{notification.user_id}: \"#{notification.content}\""}
110
+ @id_buffer = notification.id
111
+ yield(notification)
112
+ }
113
+ end
114
+ json
115
+ end
116
+
117
+ private
118
+ def api method, attr
119
+ #Build POST Request
120
+ req = Net::HTTP::Post.new(method)
121
+ req.set_form_data(attr)
122
+ req["Cookie"] = @cookie
123
+ #Build GET Request
124
+ #path = method + "?" + URI.encode_www_form(attr)
125
+ #req2 = Net::HTTP::Get.new(path)
126
+ #req2["Cookie"] = @cookie
127
+
128
+ #Build HTTP connection
129
+ http = Net::HTTP.new('www.plurk.com', 80)
130
+ begin
131
+ resp = http.start{
132
+ $tjpLog.info(self.class){"Request: #{method}, #{attr}"}
133
+ http.request(req)
134
+ }
135
+ @cookie ||= resp['set-cookie']
136
+ json = JSON.parse(resp.body)
137
+ $tjpLog.debug(self.class){"Response: #{json}"}
138
+ $tjpLog.error(self.class){json["error_text"]} if json["error_text"]
139
+ rescue Timeout::Error => ex
140
+ $tjpLog.warn(self.class){"Request timeout, retrying."}
141
+ retry
142
+ rescue JSON::ParserError => ex
143
+ $tjpLog.error(self.class){"JSON parse error, request failed."}
144
+ rescue => ex
145
+ $tjpLog.fatal(self.class){"Unknown error, stop"}
146
+ puts ex.class, ex.message, ex.backtrace
147
+ exit
148
+ end
149
+ return json
150
+ end
151
+
152
+ class NotificationData
153
+
154
+ # Can be +new_plurk+ or +new_response+.
155
+ attr_reader :type
156
+ attr_reader :response_count
157
+ attr_reader :plurk_id
158
+ attr_reader :lang
159
+ attr_reader :user_id
160
+ attr_reader :qualifier
161
+ attr_reader :content
162
+ # Notification ID.
163
+ attr_reader :id
164
+ # Time of the listened post.
165
+ attr_reader :posted
166
+ attr_reader :owner_id
167
+ # The original JSON object from server response.
168
+ attr_reader :origin
169
+
170
+ def initialize member
171
+ @type = member['type']
172
+ @response_count = member['response_count']
173
+ @plurk_id = member['plurk_id']
174
+
175
+ @lang = @type=="new_plurk" ? member['lang'] : member['response']['lang']
176
+ @user_id = @type=="new_plurk" ? member['user_id'] : member['response']['user_id']
177
+ @qualifier = @type=="new_plurk" ? member['qualifier'] : member['response']['qualifier']
178
+ @content = @type=="new_plurk" ? member['content'] : member['response']['content']
179
+ @id = @type=="new_plurk" ? member['id'] : member['response']['id']
180
+ @posted = @type=="new_plurk" ? member['posted'] : member['response']['posted']
181
+
182
+ @owner_id = @type=="new_plurk" ? member['owner_id'] : member['plurk']['owner_id']
183
+
184
+ @origin = member
185
+ end
186
+ end
187
+
188
+ class Robot
189
+ def initialize *params
190
+ case params.size
191
+ when 1
192
+ @tjplurker = params[0]
193
+ when 3
194
+ api_key, user, passwd = params
195
+ @tjplurker = TJPlurker.new(api_key, user, passwd)
196
+ when 4
197
+ api_key, user, passwd, auto_login = params
198
+ @tjplurker = TJPlurker.new(api_key, user, passwd, auto_login)
199
+ end
200
+ @services = []
201
+ end
202
+
203
+ def start
204
+ $tjpLog.info(self.class){"Start robot."}
205
+ Thread.new{
206
+ loop{
207
+ @tjplurker.add_all_as_friends
208
+ sleep(60)
209
+ }
210
+ }
211
+ loop{
212
+ @tjplurker.comet_channel{|data|
213
+ @services.each{|service|
214
+ service.serve(@tjplurker, data)
215
+ }
216
+ }
217
+ }
218
+ end
219
+
220
+ def add_service service
221
+ @services << service
222
+ end
223
+ end
224
+
225
+ class Service
226
+ def initialize &proc
227
+ if block_given?
228
+ @serve = proc
229
+ else
230
+ @serve = Proc.new{|tjplurker, data| p data}
231
+ end
232
+ end
233
+
234
+ def serve tjplurker, data
235
+ @serve[tjplurker, data]
236
+ end
237
+ end
238
+ end
239
+
240
+ if __FILE__ == $0
241
+ pk = Plurker.new("you api key", "your id", "your password")
242
+ puts pk.login
243
+ loop{
244
+ pk.comet_channel{|date|
245
+ puts data
246
+ }
247
+ }
248
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tjplurker
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tony Jian
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-05-23 00:00:00.000000000 +08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ requirement: &18468612 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 1.4.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *18468612
26
+ description: description...
27
+ email: tonytonyjan.cs97@g2.nctu.edu.tw
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - lib/tjplurker.rb
33
+ has_rdoc: true
34
+ homepage: http://code.google.com/p/tjplurker
35
+ licenses: []
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.5.2
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: A safe Plurk API wrapper based on Ruby and mainly designed for easily making
58
+ plurk robot.
59
+ test_files: []