tjplurker 1.0

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.
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: []