douban-ruby 0.0.8 → 0.0.9
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.
- data/.rspec +1 -0
- data/Gemfile.lock +12 -11
- data/History.rdoc +4 -0
- data/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/douban-ruby.gemspec +1 -0
- data/lib/douban.rb +58 -58
- data/lib/douban/authorize.rb +1400 -1369
- data/lib/douban/collection.rb +69 -69
- data/lib/douban/event.rb +80 -80
- data/lib/douban/miniblog.rb +63 -63
- data/lib/douban/note.rb +60 -60
- data/lib/douban/people.rb +48 -48
- data/lib/douban/review.rb +66 -66
- data/lib/douban/subject.rb +119 -119
- data/lib/douban/version.rb +1 -1
- data/spec/douban/authorize_spec.rb +36 -5
- metadata +19 -4
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour -f nested
|
data/Gemfile.lock
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
douban-ruby (0.0.
|
4
|
+
douban-ruby (0.0.9)
|
5
5
|
oauth
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
10
|
diff-lcs (1.1.2)
|
11
|
-
oauth (0.4.
|
12
|
-
rake (0.
|
11
|
+
oauth (0.4.5)
|
12
|
+
rake (0.9.2)
|
13
13
|
rcov (0.9.9)
|
14
|
-
|
15
|
-
|
16
|
-
rspec-
|
17
|
-
rspec-
|
18
|
-
|
19
|
-
rspec-
|
14
|
+
rdoc (3.8)
|
15
|
+
rspec (2.6.0)
|
16
|
+
rspec-core (~> 2.6.0)
|
17
|
+
rspec-expectations (~> 2.6.0)
|
18
|
+
rspec-mocks (~> 2.6.0)
|
19
|
+
rspec-core (2.6.4)
|
20
|
+
rspec-expectations (2.6.0)
|
20
21
|
diff-lcs (~> 1.1.2)
|
21
|
-
rspec-mocks (2.
|
22
|
+
rspec-mocks (2.6.0)
|
22
23
|
|
23
24
|
PLATFORMS
|
24
25
|
ruby
|
@@ -26,7 +27,7 @@ PLATFORMS
|
|
26
27
|
DEPENDENCIES
|
27
28
|
bundler (>= 1.0.0)
|
28
29
|
douban-ruby!
|
29
|
-
oauth
|
30
30
|
rake
|
31
31
|
rcov
|
32
|
+
rdoc
|
32
33
|
rspec (~> 2.0)
|
data/History.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -38,7 +38,7 @@ douban ruby client. including OAuth support.
|
|
38
38
|
# step 1, initial state, store request_token to session
|
39
39
|
callback_url = url_for :action => :index
|
40
40
|
redirect_url = douban.get_authorize_url(callback_url)
|
41
|
-
session[:request_token] = douban.request_token :
|
41
|
+
session[:request_token] = douban.request_token :as_hash
|
42
42
|
redirect_to redirect_url
|
43
43
|
else
|
44
44
|
# step 3, have access_token, now you can use douban API
|
@@ -51,7 +51,7 @@ douban ruby client. including OAuth support.
|
|
51
51
|
douban.request_token = session[:request_token]
|
52
52
|
douban.auth
|
53
53
|
reset_session
|
54
|
-
session[:access_token] = douban.access_token :
|
54
|
+
session[:access_token] = douban.access_token :as_hash
|
55
55
|
redirect_to :action => :index
|
56
56
|
else
|
57
57
|
# error branch, you return from douban, but no request_token in session
|
data/Rakefile
CHANGED
data/douban-ruby.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency 'rspec', '~> 2.0'
|
23
23
|
s.add_development_dependency 'rake'
|
24
24
|
s.add_development_dependency 'rcov'
|
25
|
+
s.add_development_dependency 'rdoc'
|
25
26
|
|
26
27
|
s.files = `git ls-files`.split("\n")
|
27
28
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
data/lib/douban.rb
CHANGED
@@ -1,58 +1,58 @@
|
|
1
|
-
#=douban.rb
|
2
|
-
#
|
3
|
-
# Copyright (c) 2008 Hooopo
|
4
|
-
# Written and maintained by Hooopo<hoooopo@gmail.com>
|
5
|
-
#
|
6
|
-
# Copyright (C) 2010-2011 LI Daobing <lidaobing@gmail.com>
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# This program is free software. You can re-distribute and/or
|
10
|
-
# modify this program under the same terms of ruby itself ---
|
11
|
-
# Ruby Distribution License or GNU General Public License.
|
12
|
-
#
|
13
|
-
# See Douban::Authorize for an overview and examples.
|
14
|
-
#
|
15
|
-
#== Douban API Client Based Ruby
|
16
|
-
# This is the Douban Ruby library, which communicates to the Douban
|
17
|
-
# API REST servers and converts Atom into proper Ruby objects.
|
18
|
-
# In order to use the library, you need to sign up for a Douban account and
|
19
|
-
# ensure you have the oauth and modules installed.
|
20
|
-
# Douban account and ApiKey,SecrectKey
|
21
|
-
# To get a Douban account,you need to sign up at:
|
22
|
-
# http://www.douban.com/register
|
23
|
-
# Once approved, you will need to create an application to get your api key and
|
24
|
-
# secret key at :
|
25
|
-
# http://www.douban.com/service/apikey/
|
26
|
-
# You can get apikey and secrectkey ,if you create an application.
|
27
|
-
# The keys can be placed into douban.yaml or specified at runtime
|
28
|
-
# when you new a Douban::Authorize.
|
29
|
-
# Depencencies
|
30
|
-
# This library has some external dependencies:
|
31
|
-
# oauth ( http://oauth.googlecode.com/svn/code/ruby )
|
32
|
-
# You can install oauth via rubygem:
|
33
|
-
# Gem install oauth -y
|
34
|
-
#==Usage
|
35
|
-
# require "douban"
|
36
|
-
# client=Douban.authorize(apikey, secret)
|
37
|
-
# authorize_url=client.get_authorize_url
|
38
|
-
# NOTE:
|
39
|
-
# Permission to access a user's data is restricted -- you can't just access
|
40
|
-
# any user's data. In order to access a user's data, they need to have
|
41
|
-
# visit the authorize_url and press the 'agree' button .
|
42
|
-
# when user has press the 'agree' button ,we use client.auth to authorize.
|
43
|
-
# client=client.auth
|
44
|
-
# puts client.authoried? #return true or false
|
45
|
-
# Get users' info via his uid
|
46
|
-
# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
47
|
-
# people = client.get_people('hooopo')
|
48
|
-
# people.class === People
|
49
|
-
# people.title === hooopo
|
50
|
-
# people.location === "长沙"
|
51
|
-
#==Install and Wiki
|
52
|
-
# http://code.google.com/p/doubanclient-ruby/
|
53
|
-
|
54
|
-
|
55
|
-
module Douban
|
56
|
-
autoload :Authorize, 'douban/authorize'
|
57
|
-
end
|
58
|
-
require 'douban/version'
|
1
|
+
#=douban.rb
|
2
|
+
#
|
3
|
+
# Copyright (c) 2008 Hooopo
|
4
|
+
# Written and maintained by Hooopo<hoooopo@gmail.com>
|
5
|
+
#
|
6
|
+
# Copyright (C) 2010-2011 LI Daobing <lidaobing@gmail.com>
|
7
|
+
#
|
8
|
+
#
|
9
|
+
# This program is free software. You can re-distribute and/or
|
10
|
+
# modify this program under the same terms of ruby itself ---
|
11
|
+
# Ruby Distribution License or GNU General Public License.
|
12
|
+
#
|
13
|
+
# See Douban::Authorize for an overview and examples.
|
14
|
+
#
|
15
|
+
#== Douban API Client Based Ruby
|
16
|
+
# This is the Douban Ruby library, which communicates to the Douban
|
17
|
+
# API REST servers and converts Atom into proper Ruby objects.
|
18
|
+
# In order to use the library, you need to sign up for a Douban account and
|
19
|
+
# ensure you have the oauth and modules installed.
|
20
|
+
# Douban account and ApiKey,SecrectKey
|
21
|
+
# To get a Douban account,you need to sign up at:
|
22
|
+
# http://www.douban.com/register
|
23
|
+
# Once approved, you will need to create an application to get your api key and
|
24
|
+
# secret key at :
|
25
|
+
# http://www.douban.com/service/apikey/
|
26
|
+
# You can get apikey and secrectkey ,if you create an application.
|
27
|
+
# The keys can be placed into douban.yaml or specified at runtime
|
28
|
+
# when you new a Douban::Authorize.
|
29
|
+
# Depencencies
|
30
|
+
# This library has some external dependencies:
|
31
|
+
# oauth ( http://oauth.googlecode.com/svn/code/ruby )
|
32
|
+
# You can install oauth via rubygem:
|
33
|
+
# Gem install oauth -y
|
34
|
+
#==Usage
|
35
|
+
# require "douban"
|
36
|
+
# client=Douban.authorize(apikey, secret)
|
37
|
+
# authorize_url=client.get_authorize_url
|
38
|
+
# NOTE:
|
39
|
+
# Permission to access a user's data is restricted -- you can't just access
|
40
|
+
# any user's data. In order to access a user's data, they need to have
|
41
|
+
# visit the authorize_url and press the 'agree' button .
|
42
|
+
# when user has press the 'agree' button ,we use client.auth to authorize.
|
43
|
+
# client=client.auth
|
44
|
+
# puts client.authoried? #return true or false
|
45
|
+
# Get users' info via his uid
|
46
|
+
# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
47
|
+
# people = client.get_people('hooopo')
|
48
|
+
# people.class === People
|
49
|
+
# people.title === hooopo
|
50
|
+
# people.location === "长沙"
|
51
|
+
#==Install and Wiki
|
52
|
+
# http://code.google.com/p/doubanclient-ruby/
|
53
|
+
|
54
|
+
|
55
|
+
module Douban
|
56
|
+
autoload :Authorize, 'douban/authorize'
|
57
|
+
end
|
58
|
+
require 'douban/version'
|
data/lib/douban/authorize.rb
CHANGED
@@ -1,1369 +1,1400 @@
|
|
1
|
-
require 'oauth'
|
2
|
-
require 'oauth/consumer'
|
3
|
-
require 'rexml/document'
|
4
|
-
require 'net/http'
|
5
|
-
|
6
|
-
require 'douban/author'
|
7
|
-
require 'douban/collection'
|
8
|
-
require 'douban/event'
|
9
|
-
require 'douban/mail'
|
10
|
-
require 'douban/miniblog'
|
11
|
-
require 'douban/miniblog_comments'
|
12
|
-
require 'douban/note'
|
13
|
-
require 'douban/people'
|
14
|
-
require 'douban/recommendation'
|
15
|
-
require 'douban/recommendation_comment'
|
16
|
-
require 'douban/review'
|
17
|
-
require 'douban/subject'
|
18
|
-
require 'douban/tag'
|
19
|
-
|
20
|
-
module Douban
|
21
|
-
class Authorize
|
22
|
-
attr_reader :api_key
|
23
|
-
attr_reader :api_secret
|
24
|
-
attr_reader :authorize_url
|
25
|
-
attr_reader :consumer
|
26
|
-
|
27
|
-
@@debug = false
|
28
|
-
|
29
|
-
@@default_oauth_request_options = {
|
30
|
-
:signature_method=>"HMAC-SHA1",
|
31
|
-
:site=>"http://www.douban.com",
|
32
|
-
:request_token_path=>"/service/auth/request_token",
|
33
|
-
:access_token_path=>"/service/auth/access_token",
|
34
|
-
:authorize_path=>"/service/auth/authorize",
|
35
|
-
:scheme=>:header,
|
36
|
-
:realm=>"http://www.example.com/"
|
37
|
-
}
|
38
|
-
|
39
|
-
@@default_oauth_access_options = {
|
40
|
-
:site=>"http://api.douban.com",
|
41
|
-
:scheme=>:header,
|
42
|
-
:signature_method=>"HMAC-SHA1",
|
43
|
-
:realm=>"http://www.example.com/"
|
44
|
-
}
|
45
|
-
|
46
|
-
|
47
|
-
def self.debug=(val)
|
48
|
-
@@debug = val
|
49
|
-
end
|
50
|
-
|
51
|
-
def initialize(api_key, secret_key, options={})
|
52
|
-
@api_key=api_key
|
53
|
-
@secret_key=secret_key
|
54
|
-
@oauth_request_option = @@default_oauth_request_options.merge(options)
|
55
|
-
@oauth_access_option = @@default_oauth_access_options.merge(options)
|
56
|
-
yield self if block_given?
|
57
|
-
self
|
58
|
-
end
|
59
|
-
|
60
|
-
def authorized?
|
61
|
-
! @access_token.nil?
|
62
|
-
end
|
63
|
-
|
64
|
-
def get_authorize_url(oauth_callback=nil)
|
65
|
-
oauth_callback ||= @oauth_request_option[:realm]
|
66
|
-
|
67
|
-
@consumer=new_request_consumer
|
68
|
-
@request_token=@consumer.get_request_token
|
69
|
-
@authorize_url="#{@request_token.authorize_url}&oauth_callback=#{CGI.escape(oauth_callback)}"
|
70
|
-
yield @request_token if block_given?
|
71
|
-
@authorize_url
|
72
|
-
end
|
73
|
-
|
74
|
-
def auth
|
75
|
-
begin
|
76
|
-
@access_token=@request_token.get_access_token
|
77
|
-
@access_token=OAuth::AccessToken.new(new_access_consumer,
|
78
|
-
@access_token.token,
|
79
|
-
@access_token.secret
|
80
|
-
)
|
81
|
-
rescue
|
82
|
-
#raise $!
|
83
|
-
ensure
|
84
|
-
yield self if block_given?
|
85
|
-
return self
|
86
|
-
end
|
87
|
-
end
|
88
|
-
def get_people(uid="@me")
|
89
|
-
resp=get("/people/#{u uid}")
|
90
|
-
if resp.code=="200"
|
91
|
-
atom=resp.body
|
92
|
-
People.new(atom)
|
93
|
-
else
|
94
|
-
debug(resp)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def get_friends(uid="@me",option={:start_index=>1,:max_results=>10})
|
99
|
-
resp=get("/people/#{u uid.to_s}/friends?start-index=#{u option[:start_index]}&max-results=#{u option[:max_results]}")
|
100
|
-
if resp.code=="200"
|
101
|
-
friends=[]
|
102
|
-
atom=resp.body
|
103
|
-
doc=REXML::Document.new(atom)
|
104
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
105
|
-
friends << People.new(entry)
|
106
|
-
end
|
107
|
-
friends
|
108
|
-
else
|
109
|
-
debug(resp)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def get_contacts(uid="@me",option={:start_index=>1,:max_results=>10})
|
114
|
-
resp=get("/people/#{u uid.to_s}/contacts?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
115
|
-
if resp.code=="200"
|
116
|
-
contacts=[]
|
117
|
-
atom=resp.body
|
118
|
-
doc=REXML::Document.new(atom)
|
119
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
120
|
-
contacts << People.new(entry)
|
121
|
-
end
|
122
|
-
contacts
|
123
|
-
else
|
124
|
-
nil
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
def search_people(q="",option={:start_index=>1,:max_results=>10})
|
130
|
-
resp=get("/people?q=#{u(q.to_s)}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
131
|
-
if resp.code=="200"
|
132
|
-
results=[]
|
133
|
-
atom=resp.body
|
134
|
-
doc=REXML::Document.new(atom)
|
135
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
136
|
-
results << People.new(entry)
|
137
|
-
end
|
138
|
-
results
|
139
|
-
else
|
140
|
-
nil
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
# 获取书籍信息
|
145
|
-
# http://goo.gl/HaG5
|
146
|
-
#
|
147
|
-
# get_book(:isbn => isbn) => Book
|
148
|
-
# get_book(:id => id) => Book
|
149
|
-
# get_book(id) => Book
|
150
|
-
# get_book(Book) => Book (refresh Book)
|
151
|
-
def get_book(id)
|
152
|
-
resp = case id
|
153
|
-
when Book
|
154
|
-
get("/book/subject/#{u id.subject_id}")
|
155
|
-
when Hash
|
156
|
-
if id[:isbn]
|
157
|
-
get("/book/subject/isbn/#{u id[:isbn]}")
|
158
|
-
elsif id[:id]
|
159
|
-
get("/book/subject/#{u id[:id]}")
|
160
|
-
else
|
161
|
-
raise "Hash only support :isbn or :id"
|
162
|
-
end
|
163
|
-
else
|
164
|
-
get("/book/subject/#{u id}")
|
165
|
-
end
|
166
|
-
|
167
|
-
if resp.code=="200"
|
168
|
-
atom=resp.body
|
169
|
-
Book.new(atom)
|
170
|
-
else
|
171
|
-
nil
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
# 获取电影信息
|
176
|
-
# http://goo.gl/2fZ4
|
177
|
-
#
|
178
|
-
# get_movie(:imdb => imdb) => Movie
|
179
|
-
# get_movie(:id => id) => Movie
|
180
|
-
# get_movie(id) => Movie
|
181
|
-
# get_movie(Movie) => Movie (refresh Movie)
|
182
|
-
def get_movie(id)
|
183
|
-
resp = case id
|
184
|
-
when Movie
|
185
|
-
get("/movie/subject/#{u id.subject_id}")
|
186
|
-
when Hash
|
187
|
-
if id[:imdb]
|
188
|
-
get("/movie/subject/imdb/#{u id[:imdb]}")
|
189
|
-
elsif id[:id]
|
190
|
-
get("/movie/subject/#{u id[:id]}")
|
191
|
-
else
|
192
|
-
raise "Hash only support :imdb or :id"
|
193
|
-
end
|
194
|
-
else
|
195
|
-
get("/movie/subject/#{u id}")
|
196
|
-
end
|
197
|
-
|
198
|
-
if resp.code=="200"
|
199
|
-
atom=resp.body
|
200
|
-
Movie.new(atom)
|
201
|
-
else
|
202
|
-
nil
|
203
|
-
end
|
204
|
-
end
|
205
|
-
def get_music(id=nil)
|
206
|
-
resp=get("/music/subject/#{u(id.to_s)}")
|
207
|
-
if resp.code=="200"
|
208
|
-
atom=resp.body
|
209
|
-
Music.new(atom)
|
210
|
-
else
|
211
|
-
nil
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# :call-seq:
|
216
|
-
# search_book(:q => "search word") => [Book] or nil
|
217
|
-
# search_book(:tag => "tag name") => [Book] or nil
|
218
|
-
# search_book("search word") => [Book] or nil
|
219
|
-
#
|
220
|
-
# 搜索书籍
|
221
|
-
#
|
222
|
-
# http://goo.gl/rYDf
|
223
|
-
#
|
224
|
-
# * option
|
225
|
-
# * q: query string
|
226
|
-
# * tag:
|
227
|
-
# * start_index:
|
228
|
-
# * max_results:
|
229
|
-
def search_book(*args)
|
230
|
-
url = _subject_search_args_to_url(:book, *args)
|
231
|
-
|
232
|
-
resp=get(url)
|
233
|
-
if resp.code=="200"
|
234
|
-
atom=resp.body
|
235
|
-
doc=REXML::Document.new(atom)
|
236
|
-
books=[]
|
237
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
238
|
-
books << Book.new(entry)
|
239
|
-
end
|
240
|
-
books
|
241
|
-
else
|
242
|
-
nil
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def search_movie(*args)
|
247
|
-
url = _subject_search_args_to_url(:movie, *args)
|
248
|
-
|
249
|
-
resp=get(url)
|
250
|
-
if resp.code=="200"
|
251
|
-
atom=resp.body
|
252
|
-
doc=REXML::Document.new(atom)
|
253
|
-
movies=[]
|
254
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
255
|
-
movies << Movie.new(entry)
|
256
|
-
end
|
257
|
-
movies
|
258
|
-
else
|
259
|
-
nil
|
260
|
-
end
|
261
|
-
end
|
262
|
-
def search_music(tag="",option={:start_index=>1,:max_results=>10})
|
263
|
-
url = _subject_search_args_to_url(:music, *args)
|
264
|
-
|
265
|
-
resp=get(url)
|
266
|
-
if resp.code=="200"
|
267
|
-
atom=resp.body
|
268
|
-
doc=REXML::Document.new(atom)
|
269
|
-
music=[]
|
270
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
271
|
-
music << Music.new(entry)
|
272
|
-
end
|
273
|
-
music
|
274
|
-
else
|
275
|
-
nil
|
276
|
-
end
|
277
|
-
end
|
278
|
-
def get_review(id="")
|
279
|
-
resp=get("/review/#{u(id.to_s)}")
|
280
|
-
if resp.code=="200"
|
281
|
-
atom=resp.body
|
282
|
-
Review.new(atom)
|
283
|
-
else
|
284
|
-
nil
|
285
|
-
end
|
286
|
-
end
|
287
|
-
def get_user_reviews(user_id="@me",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
288
|
-
resp=get("/people/#{u(user_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
289
|
-
if resp.code=="200"
|
290
|
-
atom=resp.body
|
291
|
-
reviews=[]
|
292
|
-
doc=REXML::Document.new(atom)
|
293
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
294
|
-
reviews<< Review.new(entry)
|
295
|
-
end
|
296
|
-
reviews
|
297
|
-
else
|
298
|
-
debug(resp)
|
299
|
-
end
|
300
|
-
end
|
301
|
-
def get_movie_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
302
|
-
resp=get("/movie/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
303
|
-
if resp.code=="200"
|
304
|
-
atom=resp.body
|
305
|
-
reviews=[]
|
306
|
-
doc=REXML::Document.new(atom)
|
307
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
308
|
-
|
309
|
-
reviews<< Review.new(entry)
|
310
|
-
end
|
311
|
-
reviews
|
312
|
-
else
|
313
|
-
nil
|
314
|
-
end
|
315
|
-
end
|
316
|
-
def get_music_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
317
|
-
resp=get("/music/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
318
|
-
if resp.code=="200"
|
319
|
-
atom=resp.body
|
320
|
-
reviews=[]
|
321
|
-
doc=REXML::Document.new(atom)
|
322
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
323
|
-
reviews<< Review.new(entry)
|
324
|
-
end
|
325
|
-
reviews
|
326
|
-
else
|
327
|
-
nil
|
328
|
-
end
|
329
|
-
end
|
330
|
-
def get_book_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
331
|
-
resp=get("/book/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
332
|
-
if resp.code=="200"
|
333
|
-
atom=resp.body
|
334
|
-
reviews=[]
|
335
|
-
doc=REXML::Document.new(atom)
|
336
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
337
|
-
reviews<< Review.new(entry)
|
338
|
-
end
|
339
|
-
reviews
|
340
|
-
else
|
341
|
-
nil
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
def delete_review(review)
|
346
|
-
review_id = case review
|
347
|
-
when Review then review.review_id
|
348
|
-
else review
|
349
|
-
end
|
350
|
-
|
351
|
-
resp=delete("/review/#{u(review_id.to_s)}")
|
352
|
-
if resp.code=="200"
|
353
|
-
true
|
354
|
-
else
|
355
|
-
false
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
def create_review(subject_link="",title="",content="",rating=5)
|
360
|
-
subject_link = subject_link.id if subject_link.kind_of?(Subject)
|
361
|
-
|
362
|
-
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
363
|
-
<entry xmlns:ns0="http://www.w3.org/2005/Atom">
|
364
|
-
<db:subject xmlns:db="http://www.douban.com/xmlns/">
|
365
|
-
<id>#{h subject_link}</id>
|
366
|
-
</db:subject>
|
367
|
-
<content>#{h content}</content>
|
368
|
-
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" ></gd:rating>
|
369
|
-
<title>#{h title}</title>
|
370
|
-
</entry>
|
371
|
-
}
|
372
|
-
resp=post("/reviews",entry,{"Content-Type" => "application/atom+xml"})
|
373
|
-
if resp.code=="201"
|
374
|
-
Review.new(resp.body)
|
375
|
-
else
|
376
|
-
debug(resp)
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
def modify_review(review, subject_link=nil,title="",content="",rating=5)
|
381
|
-
review_id = case review
|
382
|
-
when Review then review.review_id
|
383
|
-
else review
|
384
|
-
end
|
385
|
-
|
386
|
-
subject_link = review.subject.id if subject_link.nil? and review.kind_of?(Review)
|
387
|
-
|
388
|
-
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
389
|
-
<entry xmlns:ns0="http://www.w3.org/2005/Atom">
|
390
|
-
<id>http://api.douban.com/review/#{h review_id}</id>
|
391
|
-
<db:subject xmlns:db="http://www.douban.com/xmlns/">
|
392
|
-
<id>#{h subject_link}</id>
|
393
|
-
</db:subject>
|
394
|
-
<content>#{h content}</content>
|
395
|
-
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" ></gd:rating>
|
396
|
-
<title>#{h title}</title>
|
397
|
-
</entry>
|
398
|
-
}
|
399
|
-
resp=put("/review/#{u(review_id)}",entry,{"Content-Type" => "application/atom+xml"})
|
400
|
-
if resp.code=="202"
|
401
|
-
Review.new(resp.body)
|
402
|
-
else
|
403
|
-
debug(resp)
|
404
|
-
end
|
405
|
-
end
|
406
|
-
def get_collection(collection_id="")
|
407
|
-
resp=get("/collection/#{u(collection_id.to_s)}")
|
408
|
-
if resp.code=="200"
|
409
|
-
atom=resp.body
|
410
|
-
Collection.new(atom)
|
411
|
-
else
|
412
|
-
nil
|
413
|
-
end
|
414
|
-
end
|
415
|
-
def get_user_collection(
|
416
|
-
user_id="@me",
|
417
|
-
option={
|
418
|
-
:cat=>'',
|
419
|
-
:tag=>'',
|
420
|
-
:status=>'',
|
421
|
-
:start_index=>1,
|
422
|
-
:max_results=>10,
|
423
|
-
:updated_max=>'',
|
424
|
-
:updated_min=>''
|
425
|
-
}
|
426
|
-
)
|
427
|
-
resp=get("/people/#{u(user_id.to_s)}/collection?cat=#{option[:cat]}&tag=#{option[:tag]}&status=#{option[:status]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&updated-max=#{option[:updated_max]}&updated-min=#{option[:updated_min]}")
|
428
|
-
if resp.code=="200"
|
429
|
-
atom=resp.body
|
430
|
-
doc=REXML::Document.new(atom)
|
431
|
-
author=REXML::XPath.first(doc,"//feed/author")
|
432
|
-
author=Author.new(author.to_s) if author
|
433
|
-
title=REXML::XPath.first(doc,"//feed/title")
|
434
|
-
title=title.text if title
|
435
|
-
collections=[]
|
436
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
437
|
-
collection=Collection.new(entry)
|
438
|
-
collection.author=author
|
439
|
-
collection.title=title
|
440
|
-
collections<< collection
|
441
|
-
end
|
442
|
-
collections
|
443
|
-
else
|
444
|
-
nil
|
445
|
-
end
|
446
|
-
end
|
447
|
-
def create_collection( subject_id="",content="",rating=5,status="",tag=[],option={ :privacy=>"public"})
|
448
|
-
db_tag=""
|
449
|
-
if tag.size==0
|
450
|
-
db_tag='<db:tag name="" />'
|
451
|
-
else
|
452
|
-
tag.each do |t|
|
453
|
-
db_tag+=%Q{<db:tag name="#{h t}" />}
|
454
|
-
end
|
455
|
-
end
|
456
|
-
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
457
|
-
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
458
|
-
<db:status>#{h status}</db:status>
|
459
|
-
#{db_tag}
|
460
|
-
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" />
|
461
|
-
<content>#{h content}</content>
|
462
|
-
<db:subject>
|
463
|
-
<id>#{h subject_id}</id>
|
464
|
-
</db:subject>
|
465
|
-
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
466
|
-
</entry>
|
467
|
-
}
|
468
|
-
resp=post("/collection",entry,{"Content-Type"=>"application/atom+xml"})
|
469
|
-
if resp.code=="201"
|
470
|
-
Collection.new(resp.body)
|
471
|
-
else
|
472
|
-
debug(resp)
|
473
|
-
end
|
474
|
-
end
|
475
|
-
|
476
|
-
def modify_collection(collection, subject_id="",content="",rating=5,status="",tag=[],option={:privacy=>"public"})
|
477
|
-
collection_id = case collection
|
478
|
-
when Collection then collection.collection_id
|
479
|
-
else collection
|
480
|
-
end
|
481
|
-
|
482
|
-
subject_id = collection.subject.id if subject_id.nil? and collection.kind_of?(Collection)
|
483
|
-
|
484
|
-
db_tag=""
|
485
|
-
if tag.size==0
|
486
|
-
db_tag='<db:tag name="" />'
|
487
|
-
else
|
488
|
-
tag.each do |t|
|
489
|
-
db_tag+=%Q{<db:tag name="#{h t}" />}
|
490
|
-
end
|
491
|
-
end
|
492
|
-
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
493
|
-
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
494
|
-
<id>http://api.douban.com/collection/#{h collection_id}</id>
|
495
|
-
<db:status>#{h status}</db:status>
|
496
|
-
|
497
|
-
#{db_tag}
|
498
|
-
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" />
|
499
|
-
<content>#{h content}</content>
|
500
|
-
<db:subject>
|
501
|
-
<id>#{h subject_id}</id>
|
502
|
-
</db:subject>
|
503
|
-
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
504
|
-
</entry>
|
505
|
-
}
|
506
|
-
resp=put("/collection/#{u collection_id}",entry,{"Content-Type"=>"application/atom+xml"})
|
507
|
-
# resp.code should be 202, but currently it's 200
|
508
|
-
# http://www.douban.com/group/topic/12451628/
|
509
|
-
if resp.code=="200" or resp.code == "202"
|
510
|
-
Collection.new(resp.body)
|
511
|
-
else
|
512
|
-
debug(resp)
|
513
|
-
end
|
514
|
-
end
|
515
|
-
def delete_collection(collection)
|
516
|
-
collection_id = case collection
|
517
|
-
when Collection then collection.collection_id
|
518
|
-
else collection
|
519
|
-
end
|
520
|
-
|
521
|
-
resp=delete("/collection/#{u(collection_id.to_s)}")
|
522
|
-
if resp.code=="200"
|
523
|
-
true
|
524
|
-
else
|
525
|
-
false
|
526
|
-
end
|
527
|
-
end
|
528
|
-
def get_user_miniblog(user_id="@me",option={:start_index=>1,:max_results=>10})
|
529
|
-
resp=get("/people/#{u(user_id.to_s)}/miniblog?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
530
|
-
if resp.code=="200"
|
531
|
-
atom=resp.body
|
532
|
-
doc=REXML::Document.new(atom)
|
533
|
-
author=REXML::XPath.first(doc,"//feed/author")
|
534
|
-
author=Author.new(author.to_s) if author
|
535
|
-
miniblogs=[]
|
536
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
537
|
-
miniblog=Miniblog.new(entry)
|
538
|
-
miniblog.author=author
|
539
|
-
miniblogs<< miniblog
|
540
|
-
end
|
541
|
-
miniblogs
|
542
|
-
else
|
543
|
-
nil
|
544
|
-
end
|
545
|
-
end
|
546
|
-
def get_user_contact_miniblog(user_id="@me",option={:start_index=>1,:max_results=>10})
|
547
|
-
resp=get("/people/#{u(user_id.to_s)}/miniblog/contacts?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
548
|
-
if resp.code=="200"
|
549
|
-
atom=resp.body
|
550
|
-
doc=REXML::Document.new(atom)
|
551
|
-
miniblogs=[]
|
552
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
553
|
-
miniblog=Miniblog.new(entry)
|
554
|
-
miniblogs<< miniblog
|
555
|
-
end
|
556
|
-
miniblogs
|
557
|
-
else
|
558
|
-
nil
|
559
|
-
end
|
560
|
-
end
|
561
|
-
def create_miniblog(content="")
|
562
|
-
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
563
|
-
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
564
|
-
<content>#{h content}</content>
|
565
|
-
</entry>}
|
566
|
-
resp=post("/miniblog/saying",entry,{"Content-Type"=>"application/atom+xml"})
|
567
|
-
if resp.code=="201"
|
568
|
-
Miniblog.new(resp.body)
|
569
|
-
else
|
570
|
-
nil
|
571
|
-
end
|
572
|
-
end
|
573
|
-
def delete_miniblog(miniblog_id="")
|
574
|
-
resp=delete("/miniblog/#{u(miniblog_id.to_s)}")
|
575
|
-
if resp.code=="200"
|
576
|
-
true
|
577
|
-
else
|
578
|
-
false
|
579
|
-
end
|
580
|
-
end
|
581
|
-
|
582
|
-
# :call-seq:
|
583
|
-
# get_miniblog_comments(aMiniblog, options) => MiniblogComments or nil
|
584
|
-
# get_miniblog_comments(miniblog_id, options) => MiniblogComments or nil
|
585
|
-
#
|
586
|
-
# 获取我说回复 (http://goo.gl/nTZK)
|
587
|
-
def get_miniblog_comments(miniblog, options={})
|
588
|
-
miniblog_id = case miniblog
|
589
|
-
when Miniblog then miniblog.miniblog_id
|
590
|
-
else miniblog
|
591
|
-
end
|
592
|
-
|
593
|
-
url = "/miniblog/#{u miniblog_id}/comments?"
|
594
|
-
if options[:start_index]
|
595
|
-
url << "start-index=#{u options[:start_index]}&"
|
596
|
-
end
|
597
|
-
if options[:max_results]
|
598
|
-
url << "max-results=#{u options[:max_results]}&"
|
599
|
-
end
|
600
|
-
|
601
|
-
url = url[0..-2]
|
602
|
-
|
603
|
-
resp = get(url)
|
604
|
-
if resp.code == "200"
|
605
|
-
MiniblogComments.new(resp.body)
|
606
|
-
else
|
607
|
-
debug(resp)
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
|
-
# :call-seq:
|
612
|
-
# create_miniblog_comment(aMiniblog, aString) => MiniblogComment or nil
|
613
|
-
# create_miniblog_comment(obj, aString) => MiniblogComment or nil
|
614
|
-
#
|
615
|
-
# 回应我说 (http://goo.gl/j43Z)
|
616
|
-
def create_miniblog_comment(miniblog, content)
|
617
|
-
miniblog_id = case miniblog
|
618
|
-
when Miniblog then miniblog.miniblog_id
|
619
|
-
else miniblog
|
620
|
-
end
|
621
|
-
entry = %Q{<?xml version='1.0' encoding='UTF-8'?>
|
622
|
-
<entry>
|
623
|
-
<content>#{h content}</content>
|
624
|
-
</entry>}
|
625
|
-
|
626
|
-
resp = post("/miniblog/#{u miniblog_id}/comments", entry)
|
627
|
-
if resp.code == "201"
|
628
|
-
MiniblogComment.new(resp.body)
|
629
|
-
else
|
630
|
-
debug(resp)
|
631
|
-
end
|
632
|
-
end
|
633
|
-
|
634
|
-
# :call-seq:
|
635
|
-
# delete_miniblog_comment(aMiniblogComment) => true or false
|
636
|
-
# delete_miniblog_comment(miniblog_id, comment_id) => true or false
|
637
|
-
# 删除我说
|
638
|
-
def delete_miniblog_comment(*args)
|
639
|
-
if args.size == 1 and args[0].kind_of?(MiniblogComment)
|
640
|
-
miniblog_id = args[0].miniblog_id
|
641
|
-
comment_id = args[0].comment_id
|
642
|
-
elsif args.size == 2
|
643
|
-
miniblog_id = args[0].to_s
|
644
|
-
comment_id = args[1].to_s
|
645
|
-
else
|
646
|
-
raise "unsupported argument error"
|
647
|
-
end
|
648
|
-
|
649
|
-
resp = delete("/miniblog/#{u miniblog_id}/comment/#{u comment_id}")
|
650
|
-
if resp.code == "200"
|
651
|
-
true
|
652
|
-
else
|
653
|
-
debug(resp, false)
|
654
|
-
end
|
655
|
-
end
|
656
|
-
|
657
|
-
def get_note(note_id="")
|
658
|
-
resp=get("/note/#{u(note_id.to_s)}")
|
659
|
-
if resp.code=="200"
|
660
|
-
atom=resp.body
|
661
|
-
Note.new(atom)
|
662
|
-
else
|
663
|
-
nil
|
664
|
-
end
|
665
|
-
end
|
666
|
-
|
667
|
-
def get_user_notes(user_id="@me",option={:start_index=>1,:max_results=>10})
|
668
|
-
resp=get("/people/#{u(user_id.to_s)}/notes?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
669
|
-
if resp.code=="200"
|
670
|
-
atom=resp.body
|
671
|
-
doc=REXML::Document.new(atom)
|
672
|
-
author=REXML::XPath.first(doc,"//feed/author")
|
673
|
-
author=Author.new(author.to_s) if author
|
674
|
-
notes=[]
|
675
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
676
|
-
note=Note.new(entry)
|
677
|
-
note.author=author
|
678
|
-
notes << note
|
679
|
-
end
|
680
|
-
notes
|
681
|
-
else
|
682
|
-
nil
|
683
|
-
end
|
684
|
-
end
|
685
|
-
|
686
|
-
def create_note(title="",content="",option={:privacy=>"public",:can_reply=>"yes"})
|
687
|
-
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
688
|
-
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
689
|
-
<title>#{h title}</title>
|
690
|
-
<content>#{h content}</content>
|
691
|
-
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
692
|
-
<db:attribute name="can_reply">#{h option[:can_reply]}</db:attribute>
|
693
|
-
</entry>
|
694
|
-
}
|
695
|
-
resp=post("/notes",entry,{"Content-Type"=>"application/atom+xml"})
|
696
|
-
if resp.code=="201"
|
697
|
-
Note.new(resp.body)
|
698
|
-
else
|
699
|
-
debug(resp)
|
700
|
-
end
|
701
|
-
end
|
702
|
-
|
703
|
-
def delete_note(note_id="")
|
704
|
-
note_id = note_id.note_id if note_id.kind_of?(Note)
|
705
|
-
|
706
|
-
resp=delete("/note/#{u(note_id.to_s)}")
|
707
|
-
if resp.code=="200"
|
708
|
-
true
|
709
|
-
else
|
710
|
-
false
|
711
|
-
end
|
712
|
-
end
|
713
|
-
|
714
|
-
def modify_note(note,title="",content="",option={:privacy=>"public",:can_reply=>"yes"})
|
715
|
-
note_id = case note
|
716
|
-
when Note then note.note_id
|
717
|
-
else note
|
718
|
-
end
|
719
|
-
|
720
|
-
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
721
|
-
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
722
|
-
<title>#{h title}</title>
|
723
|
-
<content>#{h content}</content>
|
724
|
-
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
725
|
-
<db:attribute name="can_reply">#{h option[:can_reply]}</db:attribute>
|
726
|
-
</entry>
|
727
|
-
}
|
728
|
-
resp=put("/note/#{u(note_id.to_s)}",entry,{"Content-Type"=>"application/atom+xml"})
|
729
|
-
if resp.code=="202"
|
730
|
-
Note.new(resp.body)
|
731
|
-
else
|
732
|
-
debug(resp)
|
733
|
-
end
|
734
|
-
end
|
735
|
-
def get_event(event_id="")
|
736
|
-
resp=get("/event/#{u(event_id.to_s)}")
|
737
|
-
if resp.code=="200"
|
738
|
-
atom=resp.body
|
739
|
-
Event.new(atom)
|
740
|
-
else
|
741
|
-
nil
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
|
-
# <b>DEPRECATED:</b> Please use <tt>get_event_participant_people</tt> instead.
|
746
|
-
def get_participant_people(*args)
|
747
|
-
warn "[DEPRECATION] `get_participant_people` is deprecated. Please use `get_event_participant_people` instead."
|
748
|
-
get_event_participant_people(*args)
|
749
|
-
end
|
750
|
-
|
751
|
-
def get_event_participant_people(event_id=nil,option={:start_index=>1,:max_results=>10})
|
752
|
-
resp=get("/event/#{u(event_id.to_s)}/participants?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
753
|
-
if resp.code=="200"
|
754
|
-
people=[]
|
755
|
-
atom=resp.body
|
756
|
-
doc=REXML::Document.new(atom)
|
757
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
758
|
-
people<< People.new(entry)
|
759
|
-
end
|
760
|
-
people
|
761
|
-
else
|
762
|
-
nil
|
763
|
-
end
|
764
|
-
end
|
765
|
-
|
766
|
-
# <b>DEPRECATED:</b> Please use <tt>get_event_wisher_people</tt> instead.
|
767
|
-
def get_wisher_people(*args)
|
768
|
-
warn "[DEPRECATION] `get_wisher_people` is deprecated. Please use `get_event_wisher_people` instead."
|
769
|
-
get_event_wisher_people(*args)
|
770
|
-
end
|
771
|
-
|
772
|
-
def get_event_wisher_people(event_id=nil,option={:start_index=>1,:max_results=>10})
|
773
|
-
resp=get("/event/#{u(event_id.to_s)}/wishers?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
774
|
-
if resp.code=="200"
|
775
|
-
people=[]
|
776
|
-
atom=resp.body
|
777
|
-
doc=REXML::Document.new(atom)
|
778
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
779
|
-
people<< People.new(entry)
|
780
|
-
end
|
781
|
-
people
|
782
|
-
else
|
783
|
-
nil
|
784
|
-
end
|
785
|
-
end
|
786
|
-
def get_user_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
787
|
-
resp=get("/people/#{u(user_id.to_s)}/events?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
788
|
-
if resp.code=="200"
|
789
|
-
events=[]
|
790
|
-
atom=resp.body
|
791
|
-
doc=REXML::Document.new(atom)
|
792
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
793
|
-
events<< Event.new(entry)
|
794
|
-
end
|
795
|
-
events
|
796
|
-
else
|
797
|
-
nil
|
798
|
-
end
|
799
|
-
end
|
800
|
-
def get_user_initiate_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
801
|
-
resp=get("/people/#{u(user_id.to_s)}/events/initiate?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
802
|
-
if resp.code=="200"
|
803
|
-
events=[]
|
804
|
-
atom=resp.body
|
805
|
-
doc=REXML::Document.new(atom)
|
806
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
807
|
-
events<< Event.new(entry)
|
808
|
-
end
|
809
|
-
events
|
810
|
-
else
|
811
|
-
nil
|
812
|
-
end
|
813
|
-
end
|
814
|
-
def get_user_participate_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
815
|
-
resp=get("/people/#{u(user_id.to_s)}/events/participate?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
816
|
-
if resp.code=="200"
|
817
|
-
events=[]
|
818
|
-
atom=resp.body
|
819
|
-
doc=REXML::Document.new(atom)
|
820
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
821
|
-
events<< Event.new(entry)
|
822
|
-
end
|
823
|
-
events
|
824
|
-
else
|
825
|
-
nil
|
826
|
-
end
|
827
|
-
end
|
828
|
-
def get_user_wish_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
829
|
-
resp=get("/people/#{u(user_id.to_s)}/events/wish?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
830
|
-
if resp.code=="200"
|
831
|
-
events=[]
|
832
|
-
atom=resp.body
|
833
|
-
doc=REXML::Document.new(atom)
|
834
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
835
|
-
events<< Event.new(entry)
|
836
|
-
end
|
837
|
-
events
|
838
|
-
else
|
839
|
-
nil
|
840
|
-
end
|
841
|
-
end
|
842
|
-
|
843
|
-
def get_city_events(location_id=nil,option={:type=>"all",:start_index=>1,:max_results=>10})
|
844
|
-
resp=get("/event/location/#{u(location_id.to_s)}?type=#{option[:type]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
845
|
-
if resp.code=="200"
|
846
|
-
events=[]
|
847
|
-
atom=resp.body
|
848
|
-
doc=REXML::Document.new(atom)
|
849
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
850
|
-
events<< Event.new(entry)
|
851
|
-
end
|
852
|
-
events
|
853
|
-
else
|
854
|
-
nil
|
855
|
-
end
|
856
|
-
end
|
857
|
-
def search_events(q="",option={:location=>"all",:start_index=>1,:max_results=>10})
|
858
|
-
resp=get("/events?q=#{u(q.to_s)}&location=#{option[:location]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
859
|
-
if resp.code=="200"
|
860
|
-
events=[]
|
861
|
-
atom=resp.body
|
862
|
-
doc=REXML::Document.new(atom)
|
863
|
-
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
864
|
-
events<< Event.new(entry)
|
865
|
-
end
|
866
|
-
events
|
867
|
-
else
|
868
|
-
nil
|
869
|
-
end
|
870
|
-
end
|
871
|
-
def create_event(title="",content="",where="",option={:kind=>"party",:invite_only=>"no",:can_invite=>"yes",:when=>{"endTime"=>(Time.now+60*60*24*5).strftime("%Y-%m-%dT%H:%M:%S+08:00"),"startTime"=>Time.now.strftime("%Y-%m-%dT%H:%M:%S+08:00")}})
|
872
|
-
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
873
|
-
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
874
|
-
<title>#{h title}</title>
|
875
|
-
<category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#event.#{option[:kind]}"/>
|
876
|
-
<content>#{h content}</content>
|
877
|
-
<db:attribute name="invite_only">#{h option[:invite_only]}</db:attribute>
|
878
|
-
<db:attribute name="can_invite">#{h option[:can_invite]}</db:attribute>
|
879
|
-
<gd:when endTime="#{h option[:when]["endTime"]}" startTime="#{h option[:when]["startTime"]}"/>
|
880
|
-
<gd:where valueString="#{h where}" />
|
881
|
-
</entry>
|
882
|
-
}
|
883
|
-
resp=post("/events",entry,{"Content-Type"=>"application/atom+xml"})
|
884
|
-
if resp.code=="201"
|
885
|
-
Event.new(resp.body)
|
886
|
-
else
|
887
|
-
debug(resp)
|
888
|
-
end
|
889
|
-
end
|
890
|
-
|
891
|
-
def modify_event(event,title=nil,content=nil,where=nil,option=nil)
|
892
|
-
|
893
|
-
event_id = case event
|
894
|
-
when Event then event.event_id
|
895
|
-
else event
|
896
|
-
end
|
897
|
-
|
898
|
-
option = {} if option.nil?
|
899
|
-
option = {:kind=>"exhibit",
|
900
|
-
:invite_only=>"no",
|
901
|
-
:can_invite=>"yes",
|
902
|
-
:when=>{"endTime"=>(Time.now+60*60*24*5).strftime("%Y-%m-%dT%H:%M:%S+08:00"),
|
903
|
-
"startTime"=>Time.now.strftime("%Y-%m-%dT%H:%M:%S+08:00")}}.merge(option)
|
904
|
-
|
905
|
-
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
906
|
-
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
907
|
-
<title>#{h title}</title>
|
908
|
-
<category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#event.#{option[:kind]}"/>
|
909
|
-
<content>#{h content}</content>
|
910
|
-
<db:attribute name="invite_only">#{h option[:invite_only]}</db:attribute>
|
911
|
-
<db:attribute name="can_invite">#{h option[:can_invite]}</db:attribute>
|
912
|
-
<gd:when endTime="#{h option[:when]["endTime"]}" startTime="#{h option[:when]["startTime"]}"/>
|
913
|
-
<gd:where valueString="#{h where}" />
|
914
|
-
</entry>
|
915
|
-
}
|
916
|
-
resp=put("/event/#{u(event_id)}",entry,{"Content-Type"=>"application/atom+xml"})
|
917
|
-
if resp.code=="200"
|
918
|
-
Event.new(resp.body)
|
919
|
-
else
|
920
|
-
debug(resp)
|
921
|
-
end
|
922
|
-
end
|
923
|
-
|
924
|
-
def get_mail_inbox(option={:start_index=>1,:max_results=>10})
|
925
|
-
resp=get("/doumail/inbox?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
926
|
-
if resp.code=="200"
|
927
|
-
mails=[]
|
928
|
-
atom=resp.body
|
929
|
-
doc=REXML::Document.new(atom)
|
930
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
931
|
-
mails << Mail.new(entry)
|
932
|
-
end
|
933
|
-
mails
|
934
|
-
else
|
935
|
-
nil
|
936
|
-
end
|
937
|
-
end
|
938
|
-
def get_unread_mail(option={:start_index=>1,:max_results=>10})
|
939
|
-
resp=get("/doumail/inbox/unread?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
940
|
-
if resp.code=="200"
|
941
|
-
mails=[]
|
942
|
-
atom=resp.body
|
943
|
-
doc=REXML::Document.new(atom)
|
944
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
945
|
-
mails << Mail.new(entry)
|
946
|
-
end
|
947
|
-
mails
|
948
|
-
else
|
949
|
-
nil
|
950
|
-
end
|
951
|
-
end
|
952
|
-
def get_mail_outbox(option={:start_index=>1,:max_results=>10})
|
953
|
-
resp=get("/doumail/outbox?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
954
|
-
if resp.code=="200"
|
955
|
-
mails=[]
|
956
|
-
atom=resp.body
|
957
|
-
doc=REXML::Document.new(atom)
|
958
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
959
|
-
mails << Mail.new(entry)
|
960
|
-
end
|
961
|
-
mails
|
962
|
-
else
|
963
|
-
nil
|
964
|
-
end
|
965
|
-
end
|
966
|
-
def get_mail(mail_id="",keep_unread="false")
|
967
|
-
resp=get("/doumail/#{u(mail_id.to_s)}?keep-unread=#{keep_unread}")
|
968
|
-
if resp.code=="200"
|
969
|
-
atom=resp.body
|
970
|
-
Mail.new(atom)
|
971
|
-
else
|
972
|
-
nil
|
973
|
-
end
|
974
|
-
end
|
975
|
-
|
976
|
-
# <b>DEPRECATED:</b> Please use <tt>send_mail</tt> instead.
|
977
|
-
def create_mail(*args)
|
978
|
-
warn "[DEPRECATION] `create_mail` is deprecated. Please use `send_mail` instead."
|
979
|
-
send_mail(*args)
|
980
|
-
end
|
981
|
-
|
982
|
-
def send_mail(id="",title="",content="",captcha_token="",captcha_string="")
|
983
|
-
if !(captcha_token.empty?&&captcha_string.empty?)
|
984
|
-
entry=%Q(<?xml version="1.0" encoding="UTF-8"?>
|
985
|
-
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
986
|
-
<db:entity name="receiver"><uri>http://api.douban.com/people/#{h id}</uri></db:entity>
|
987
|
-
<content>#{h content}</content>
|
988
|
-
<title>#{h title}</title>
|
989
|
-
<db:attribute name="captcha_token">#{h captcha_token}</db:attribute>
|
990
|
-
<db:attribute name="captcha_string">#{h captcha_string}</db:attribute>
|
991
|
-
</entry>)
|
992
|
-
else
|
993
|
-
entry=%Q(<?xml version="1.0" encoding="UTF-8"?>
|
994
|
-
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
995
|
-
<db:entity name="receiver">
|
996
|
-
<uri>http://api.douban.com/people/#{h id}</uri></db:entity>
|
997
|
-
<content>#{h content}</content>
|
998
|
-
<title>#{h title}</title>
|
999
|
-
</entry>)
|
1000
|
-
end
|
1001
|
-
resp=post("/doumails",entry,{"Content-Type"=>"application/atom+xml"})
|
1002
|
-
if resp.code=="201"
|
1003
|
-
true
|
1004
|
-
elsif resp.code=="403"
|
1005
|
-
hash={}
|
1006
|
-
str=CGI.unescapeHTML(resp.body)
|
1007
|
-
hash[:token]=str.scan(/^captcha_token=(.*?)&/).flatten.to_s
|
1008
|
-
hash[:url]=str.scan(/captcha_url=(.*?)$/).flatten.to_s
|
1009
|
-
hash
|
1010
|
-
else
|
1011
|
-
debug(resp)
|
1012
|
-
end
|
1013
|
-
end
|
1014
|
-
def read_mail(mail_id="")
|
1015
|
-
entry=%Q{<?xml version="1.0" encoding="UTF-8"?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"><db:attribute name="unread">false</db:attribute></entry>}
|
1016
|
-
resp=put("/doumail/#{mail_id.to_s}",entry,{"Content-Type" => "application/atom+xml"})
|
1017
|
-
if resp.code=="202"
|
1018
|
-
true
|
1019
|
-
else
|
1020
|
-
false
|
1021
|
-
end
|
1022
|
-
end
|
1023
|
-
def delete_mail(mail_id="")
|
1024
|
-
resp=delete("/doumail/#{mail_id.to_s}")
|
1025
|
-
if resp.code=="200"
|
1026
|
-
true
|
1027
|
-
else
|
1028
|
-
false
|
1029
|
-
end
|
1030
|
-
end
|
1031
|
-
def read_mails(mail_ids=[])
|
1032
|
-
entrys=""
|
1033
|
-
mail_ids.each do |mail_id|
|
1034
|
-
entrys +=%Q{<entry><id>http://api.douban.com/doumail/#{mail_id}</id><db:attribute name="unread">false</db:attribute></entry>}
|
1035
|
-
end
|
1036
|
-
feed=%Q{<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">#{entrys}</feed>}
|
1037
|
-
resp=put("/doumail/",feed,{"Content-Type" => "application/atom+xml"})
|
1038
|
-
if resp.code=="202"
|
1039
|
-
true
|
1040
|
-
else
|
1041
|
-
false
|
1042
|
-
end
|
1043
|
-
end
|
1044
|
-
def delete_mails(mail_ids=[])
|
1045
|
-
entrys=""
|
1046
|
-
mail_ids.each do |mail_id|
|
1047
|
-
entrys += %Q{<entry><id>http://api.douban.com/doumail/#{mail_id}</id></entry>}
|
1048
|
-
end
|
1049
|
-
feed=%Q{<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">#{entrys}</feed>}
|
1050
|
-
resp=post("/doumail/delete",feed,{"Content-Type" => "application/atom+xml"})
|
1051
|
-
if resp.code=="202"
|
1052
|
-
true
|
1053
|
-
else
|
1054
|
-
false
|
1055
|
-
end
|
1056
|
-
end
|
1057
|
-
|
1058
|
-
def get_book_tags(subject_id="",flag=:book)
|
1059
|
-
case flag
|
1060
|
-
when :book
|
1061
|
-
resp=get("/book/subject/#{subject_id}/tags")
|
1062
|
-
when :music
|
1063
|
-
resp=get("/music/subject/#{subject_id}/tags")
|
1064
|
-
when :movie
|
1065
|
-
resp=get("/movie/subject/#{subject_id}/tags")
|
1066
|
-
end
|
1067
|
-
if resp.code=="200"
|
1068
|
-
tags=[]
|
1069
|
-
atom=resp.body
|
1070
|
-
doc=REXML::Document.new(atom)
|
1071
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
1072
|
-
tags << Tag.new(entry)
|
1073
|
-
end
|
1074
|
-
tags
|
1075
|
-
else
|
1076
|
-
nil
|
1077
|
-
end
|
1078
|
-
end
|
1079
|
-
def get_user_tags(user_id="@me",flag=:book,option={:max_results=>10})
|
1080
|
-
case flag
|
1081
|
-
when :book
|
1082
|
-
resp=get("/people/#{u user_id}/tags?cat=book&max-results=#{option[:max_results]}")
|
1083
|
-
when :music
|
1084
|
-
resp=get("/people/#{u user_id}/tags?cat=music&max-results=#{option[:max_results]}")
|
1085
|
-
when :movie
|
1086
|
-
resp=get("/people/#{u user_id}/tags?cat=movie&max-results=#{option[:max_results]}")
|
1087
|
-
end
|
1088
|
-
if resp.code=="200"
|
1089
|
-
tags=[]
|
1090
|
-
atom=resp.body
|
1091
|
-
doc=REXML::Document.new(atom)
|
1092
|
-
REXML::XPath.each(doc,"//entry") do |entry|
|
1093
|
-
tags << Tag.new(entry)
|
1094
|
-
end
|
1095
|
-
tags
|
1096
|
-
else
|
1097
|
-
debug(resp)
|
1098
|
-
end
|
1099
|
-
end
|
1100
|
-
|
1101
|
-
def delete_event(event_id="")
|
1102
|
-
entry=%Q{<?xml version='1.0' encoding='UTF-8'?><entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/"><content>sorry!!!</content></entry>}
|
1103
|
-
resp=post("/event/#{u(event_id)}/delete",entry,{"Content-Type"=>"application/atom+xml"})
|
1104
|
-
if resp.code=="200"
|
1105
|
-
true
|
1106
|
-
else
|
1107
|
-
debug(resp, false)
|
1108
|
-
end
|
1109
|
-
end
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
def
|
1254
|
-
if
|
1255
|
-
recommendation_id =
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
#
|
1283
|
-
#
|
1284
|
-
def
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
else
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
if
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
end
|
1369
|
-
|
1
|
+
require 'oauth'
|
2
|
+
require 'oauth/consumer'
|
3
|
+
require 'rexml/document'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
require 'douban/author'
|
7
|
+
require 'douban/collection'
|
8
|
+
require 'douban/event'
|
9
|
+
require 'douban/mail'
|
10
|
+
require 'douban/miniblog'
|
11
|
+
require 'douban/miniblog_comments'
|
12
|
+
require 'douban/note'
|
13
|
+
require 'douban/people'
|
14
|
+
require 'douban/recommendation'
|
15
|
+
require 'douban/recommendation_comment'
|
16
|
+
require 'douban/review'
|
17
|
+
require 'douban/subject'
|
18
|
+
require 'douban/tag'
|
19
|
+
|
20
|
+
module Douban
|
21
|
+
class Authorize
|
22
|
+
attr_reader :api_key
|
23
|
+
attr_reader :api_secret
|
24
|
+
attr_reader :authorize_url
|
25
|
+
attr_reader :consumer
|
26
|
+
|
27
|
+
@@debug = false
|
28
|
+
|
29
|
+
@@default_oauth_request_options = {
|
30
|
+
:signature_method=>"HMAC-SHA1",
|
31
|
+
:site=>"http://www.douban.com",
|
32
|
+
:request_token_path=>"/service/auth/request_token",
|
33
|
+
:access_token_path=>"/service/auth/access_token",
|
34
|
+
:authorize_path=>"/service/auth/authorize",
|
35
|
+
:scheme=>:header,
|
36
|
+
:realm=>"http://www.example.com/"
|
37
|
+
}
|
38
|
+
|
39
|
+
@@default_oauth_access_options = {
|
40
|
+
:site=>"http://api.douban.com",
|
41
|
+
:scheme=>:header,
|
42
|
+
:signature_method=>"HMAC-SHA1",
|
43
|
+
:realm=>"http://www.example.com/"
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
def self.debug=(val)
|
48
|
+
@@debug = val
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(api_key, secret_key, options={})
|
52
|
+
@api_key=api_key
|
53
|
+
@secret_key=secret_key
|
54
|
+
@oauth_request_option = @@default_oauth_request_options.merge(options)
|
55
|
+
@oauth_access_option = @@default_oauth_access_options.merge(options)
|
56
|
+
yield self if block_given?
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def authorized?
|
61
|
+
! @access_token.nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_authorize_url(oauth_callback=nil)
|
65
|
+
oauth_callback ||= @oauth_request_option[:realm]
|
66
|
+
|
67
|
+
@consumer=new_request_consumer
|
68
|
+
@request_token=@consumer.get_request_token
|
69
|
+
@authorize_url="#{@request_token.authorize_url}&oauth_callback=#{CGI.escape(oauth_callback)}"
|
70
|
+
yield @request_token if block_given?
|
71
|
+
@authorize_url
|
72
|
+
end
|
73
|
+
|
74
|
+
def auth
|
75
|
+
begin
|
76
|
+
@access_token=@request_token.get_access_token
|
77
|
+
@access_token=OAuth::AccessToken.new(new_access_consumer,
|
78
|
+
@access_token.token,
|
79
|
+
@access_token.secret
|
80
|
+
)
|
81
|
+
rescue
|
82
|
+
#raise $!
|
83
|
+
ensure
|
84
|
+
yield self if block_given?
|
85
|
+
return self
|
86
|
+
end
|
87
|
+
end
|
88
|
+
def get_people(uid="@me")
|
89
|
+
resp=get("/people/#{u uid}")
|
90
|
+
if resp.code=="200"
|
91
|
+
atom=resp.body
|
92
|
+
People.new(atom)
|
93
|
+
else
|
94
|
+
debug(resp)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_friends(uid="@me",option={:start_index=>1,:max_results=>10})
|
99
|
+
resp=get("/people/#{u uid.to_s}/friends?start-index=#{u option[:start_index]}&max-results=#{u option[:max_results]}")
|
100
|
+
if resp.code=="200"
|
101
|
+
friends=[]
|
102
|
+
atom=resp.body
|
103
|
+
doc=REXML::Document.new(atom)
|
104
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
105
|
+
friends << People.new(entry)
|
106
|
+
end
|
107
|
+
friends
|
108
|
+
else
|
109
|
+
debug(resp)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_contacts(uid="@me",option={:start_index=>1,:max_results=>10})
|
114
|
+
resp=get("/people/#{u uid.to_s}/contacts?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
115
|
+
if resp.code=="200"
|
116
|
+
contacts=[]
|
117
|
+
atom=resp.body
|
118
|
+
doc=REXML::Document.new(atom)
|
119
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
120
|
+
contacts << People.new(entry)
|
121
|
+
end
|
122
|
+
contacts
|
123
|
+
else
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def search_people(q="",option={:start_index=>1,:max_results=>10})
|
130
|
+
resp=get("/people?q=#{u(q.to_s)}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
131
|
+
if resp.code=="200"
|
132
|
+
results=[]
|
133
|
+
atom=resp.body
|
134
|
+
doc=REXML::Document.new(atom)
|
135
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
136
|
+
results << People.new(entry)
|
137
|
+
end
|
138
|
+
results
|
139
|
+
else
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# 获取书籍信息
|
145
|
+
# http://goo.gl/HaG5
|
146
|
+
#
|
147
|
+
# get_book(:isbn => isbn) => Book
|
148
|
+
# get_book(:id => id) => Book
|
149
|
+
# get_book(id) => Book
|
150
|
+
# get_book(Book) => Book (refresh Book)
|
151
|
+
def get_book(id)
|
152
|
+
resp = case id
|
153
|
+
when Book
|
154
|
+
get("/book/subject/#{u id.subject_id}")
|
155
|
+
when Hash
|
156
|
+
if id[:isbn]
|
157
|
+
get("/book/subject/isbn/#{u id[:isbn]}")
|
158
|
+
elsif id[:id]
|
159
|
+
get("/book/subject/#{u id[:id]}")
|
160
|
+
else
|
161
|
+
raise "Hash only support :isbn or :id"
|
162
|
+
end
|
163
|
+
else
|
164
|
+
get("/book/subject/#{u id}")
|
165
|
+
end
|
166
|
+
|
167
|
+
if resp.code=="200"
|
168
|
+
atom=resp.body
|
169
|
+
Book.new(atom)
|
170
|
+
else
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# 获取电影信息
|
176
|
+
# http://goo.gl/2fZ4
|
177
|
+
#
|
178
|
+
# get_movie(:imdb => imdb) => Movie
|
179
|
+
# get_movie(:id => id) => Movie
|
180
|
+
# get_movie(id) => Movie
|
181
|
+
# get_movie(Movie) => Movie (refresh Movie)
|
182
|
+
def get_movie(id)
|
183
|
+
resp = case id
|
184
|
+
when Movie
|
185
|
+
get("/movie/subject/#{u id.subject_id}")
|
186
|
+
when Hash
|
187
|
+
if id[:imdb]
|
188
|
+
get("/movie/subject/imdb/#{u id[:imdb]}")
|
189
|
+
elsif id[:id]
|
190
|
+
get("/movie/subject/#{u id[:id]}")
|
191
|
+
else
|
192
|
+
raise "Hash only support :imdb or :id"
|
193
|
+
end
|
194
|
+
else
|
195
|
+
get("/movie/subject/#{u id}")
|
196
|
+
end
|
197
|
+
|
198
|
+
if resp.code=="200"
|
199
|
+
atom=resp.body
|
200
|
+
Movie.new(atom)
|
201
|
+
else
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
def get_music(id=nil)
|
206
|
+
resp=get("/music/subject/#{u(id.to_s)}")
|
207
|
+
if resp.code=="200"
|
208
|
+
atom=resp.body
|
209
|
+
Music.new(atom)
|
210
|
+
else
|
211
|
+
nil
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# :call-seq:
|
216
|
+
# search_book(:q => "search word") => [Book] or nil
|
217
|
+
# search_book(:tag => "tag name") => [Book] or nil
|
218
|
+
# search_book("search word") => [Book] or nil
|
219
|
+
#
|
220
|
+
# 搜索书籍
|
221
|
+
#
|
222
|
+
# http://goo.gl/rYDf
|
223
|
+
#
|
224
|
+
# * option
|
225
|
+
# * q: query string
|
226
|
+
# * tag:
|
227
|
+
# * start_index:
|
228
|
+
# * max_results:
|
229
|
+
def search_book(*args)
|
230
|
+
url = _subject_search_args_to_url(:book, *args)
|
231
|
+
|
232
|
+
resp=get(url)
|
233
|
+
if resp.code=="200"
|
234
|
+
atom=resp.body
|
235
|
+
doc=REXML::Document.new(atom)
|
236
|
+
books=[]
|
237
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
238
|
+
books << Book.new(entry)
|
239
|
+
end
|
240
|
+
books
|
241
|
+
else
|
242
|
+
nil
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def search_movie(*args)
|
247
|
+
url = _subject_search_args_to_url(:movie, *args)
|
248
|
+
|
249
|
+
resp=get(url)
|
250
|
+
if resp.code=="200"
|
251
|
+
atom=resp.body
|
252
|
+
doc=REXML::Document.new(atom)
|
253
|
+
movies=[]
|
254
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
255
|
+
movies << Movie.new(entry)
|
256
|
+
end
|
257
|
+
movies
|
258
|
+
else
|
259
|
+
nil
|
260
|
+
end
|
261
|
+
end
|
262
|
+
def search_music(tag="",option={:start_index=>1,:max_results=>10})
|
263
|
+
url = _subject_search_args_to_url(:music, *args)
|
264
|
+
|
265
|
+
resp=get(url)
|
266
|
+
if resp.code=="200"
|
267
|
+
atom=resp.body
|
268
|
+
doc=REXML::Document.new(atom)
|
269
|
+
music=[]
|
270
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
271
|
+
music << Music.new(entry)
|
272
|
+
end
|
273
|
+
music
|
274
|
+
else
|
275
|
+
nil
|
276
|
+
end
|
277
|
+
end
|
278
|
+
def get_review(id="")
|
279
|
+
resp=get("/review/#{u(id.to_s)}")
|
280
|
+
if resp.code=="200"
|
281
|
+
atom=resp.body
|
282
|
+
Review.new(atom)
|
283
|
+
else
|
284
|
+
nil
|
285
|
+
end
|
286
|
+
end
|
287
|
+
def get_user_reviews(user_id="@me",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
288
|
+
resp=get("/people/#{u(user_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
289
|
+
if resp.code=="200"
|
290
|
+
atom=resp.body
|
291
|
+
reviews=[]
|
292
|
+
doc=REXML::Document.new(atom)
|
293
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
294
|
+
reviews<< Review.new(entry)
|
295
|
+
end
|
296
|
+
reviews
|
297
|
+
else
|
298
|
+
debug(resp)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
def get_movie_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
302
|
+
resp=get("/movie/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
303
|
+
if resp.code=="200"
|
304
|
+
atom=resp.body
|
305
|
+
reviews=[]
|
306
|
+
doc=REXML::Document.new(atom)
|
307
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
308
|
+
|
309
|
+
reviews<< Review.new(entry)
|
310
|
+
end
|
311
|
+
reviews
|
312
|
+
else
|
313
|
+
nil
|
314
|
+
end
|
315
|
+
end
|
316
|
+
def get_music_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
317
|
+
resp=get("/music/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
318
|
+
if resp.code=="200"
|
319
|
+
atom=resp.body
|
320
|
+
reviews=[]
|
321
|
+
doc=REXML::Document.new(atom)
|
322
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
323
|
+
reviews<< Review.new(entry)
|
324
|
+
end
|
325
|
+
reviews
|
326
|
+
else
|
327
|
+
nil
|
328
|
+
end
|
329
|
+
end
|
330
|
+
def get_book_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
331
|
+
resp=get("/book/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
332
|
+
if resp.code=="200"
|
333
|
+
atom=resp.body
|
334
|
+
reviews=[]
|
335
|
+
doc=REXML::Document.new(atom)
|
336
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
337
|
+
reviews<< Review.new(entry)
|
338
|
+
end
|
339
|
+
reviews
|
340
|
+
else
|
341
|
+
nil
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def delete_review(review)
|
346
|
+
review_id = case review
|
347
|
+
when Review then review.review_id
|
348
|
+
else review
|
349
|
+
end
|
350
|
+
|
351
|
+
resp=delete("/review/#{u(review_id.to_s)}")
|
352
|
+
if resp.code=="200"
|
353
|
+
true
|
354
|
+
else
|
355
|
+
false
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def create_review(subject_link="",title="",content="",rating=5)
|
360
|
+
subject_link = subject_link.id if subject_link.kind_of?(Subject)
|
361
|
+
|
362
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
363
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom">
|
364
|
+
<db:subject xmlns:db="http://www.douban.com/xmlns/">
|
365
|
+
<id>#{h subject_link}</id>
|
366
|
+
</db:subject>
|
367
|
+
<content>#{h content}</content>
|
368
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" ></gd:rating>
|
369
|
+
<title>#{h title}</title>
|
370
|
+
</entry>
|
371
|
+
}
|
372
|
+
resp=post("/reviews",entry,{"Content-Type" => "application/atom+xml"})
|
373
|
+
if resp.code=="201"
|
374
|
+
Review.new(resp.body)
|
375
|
+
else
|
376
|
+
debug(resp)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def modify_review(review, subject_link=nil,title="",content="",rating=5)
|
381
|
+
review_id = case review
|
382
|
+
when Review then review.review_id
|
383
|
+
else review
|
384
|
+
end
|
385
|
+
|
386
|
+
subject_link = review.subject.id if subject_link.nil? and review.kind_of?(Review)
|
387
|
+
|
388
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
389
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom">
|
390
|
+
<id>http://api.douban.com/review/#{h review_id}</id>
|
391
|
+
<db:subject xmlns:db="http://www.douban.com/xmlns/">
|
392
|
+
<id>#{h subject_link}</id>
|
393
|
+
</db:subject>
|
394
|
+
<content>#{h content}</content>
|
395
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" ></gd:rating>
|
396
|
+
<title>#{h title}</title>
|
397
|
+
</entry>
|
398
|
+
}
|
399
|
+
resp=put("/review/#{u(review_id)}",entry,{"Content-Type" => "application/atom+xml"})
|
400
|
+
if resp.code=="202"
|
401
|
+
Review.new(resp.body)
|
402
|
+
else
|
403
|
+
debug(resp)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
def get_collection(collection_id="")
|
407
|
+
resp=get("/collection/#{u(collection_id.to_s)}")
|
408
|
+
if resp.code=="200"
|
409
|
+
atom=resp.body
|
410
|
+
Collection.new(atom)
|
411
|
+
else
|
412
|
+
nil
|
413
|
+
end
|
414
|
+
end
|
415
|
+
def get_user_collection(
|
416
|
+
user_id="@me",
|
417
|
+
option={
|
418
|
+
:cat=>'',
|
419
|
+
:tag=>'',
|
420
|
+
:status=>'',
|
421
|
+
:start_index=>1,
|
422
|
+
:max_results=>10,
|
423
|
+
:updated_max=>'',
|
424
|
+
:updated_min=>''
|
425
|
+
}
|
426
|
+
)
|
427
|
+
resp=get("/people/#{u(user_id.to_s)}/collection?cat=#{option[:cat]}&tag=#{option[:tag]}&status=#{option[:status]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&updated-max=#{option[:updated_max]}&updated-min=#{option[:updated_min]}")
|
428
|
+
if resp.code=="200"
|
429
|
+
atom=resp.body
|
430
|
+
doc=REXML::Document.new(atom)
|
431
|
+
author=REXML::XPath.first(doc,"//feed/author")
|
432
|
+
author=Author.new(author.to_s) if author
|
433
|
+
title=REXML::XPath.first(doc,"//feed/title")
|
434
|
+
title=title.text if title
|
435
|
+
collections=[]
|
436
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
437
|
+
collection=Collection.new(entry)
|
438
|
+
collection.author=author
|
439
|
+
collection.title=title
|
440
|
+
collections<< collection
|
441
|
+
end
|
442
|
+
collections
|
443
|
+
else
|
444
|
+
nil
|
445
|
+
end
|
446
|
+
end
|
447
|
+
def create_collection( subject_id="",content="",rating=5,status="",tag=[],option={ :privacy=>"public"})
|
448
|
+
db_tag=""
|
449
|
+
if tag.size==0
|
450
|
+
db_tag='<db:tag name="" />'
|
451
|
+
else
|
452
|
+
tag.each do |t|
|
453
|
+
db_tag+=%Q{<db:tag name="#{h t}" />}
|
454
|
+
end
|
455
|
+
end
|
456
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
457
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
458
|
+
<db:status>#{h status}</db:status>
|
459
|
+
#{db_tag}
|
460
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" />
|
461
|
+
<content>#{h content}</content>
|
462
|
+
<db:subject>
|
463
|
+
<id>#{h subject_id}</id>
|
464
|
+
</db:subject>
|
465
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
466
|
+
</entry>
|
467
|
+
}
|
468
|
+
resp=post("/collection",entry,{"Content-Type"=>"application/atom+xml"})
|
469
|
+
if resp.code=="201"
|
470
|
+
Collection.new(resp.body)
|
471
|
+
else
|
472
|
+
debug(resp)
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def modify_collection(collection, subject_id="",content="",rating=5,status="",tag=[],option={:privacy=>"public"})
|
477
|
+
collection_id = case collection
|
478
|
+
when Collection then collection.collection_id
|
479
|
+
else collection
|
480
|
+
end
|
481
|
+
|
482
|
+
subject_id = collection.subject.id if subject_id.nil? and collection.kind_of?(Collection)
|
483
|
+
|
484
|
+
db_tag=""
|
485
|
+
if tag.size==0
|
486
|
+
db_tag='<db:tag name="" />'
|
487
|
+
else
|
488
|
+
tag.each do |t|
|
489
|
+
db_tag+=%Q{<db:tag name="#{h t}" />}
|
490
|
+
end
|
491
|
+
end
|
492
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
493
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
494
|
+
<id>http://api.douban.com/collection/#{h collection_id}</id>
|
495
|
+
<db:status>#{h status}</db:status>
|
496
|
+
|
497
|
+
#{db_tag}
|
498
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" />
|
499
|
+
<content>#{h content}</content>
|
500
|
+
<db:subject>
|
501
|
+
<id>#{h subject_id}</id>
|
502
|
+
</db:subject>
|
503
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
504
|
+
</entry>
|
505
|
+
}
|
506
|
+
resp=put("/collection/#{u collection_id}",entry,{"Content-Type"=>"application/atom+xml"})
|
507
|
+
# resp.code should be 202, but currently it's 200
|
508
|
+
# http://www.douban.com/group/topic/12451628/
|
509
|
+
if resp.code=="200" or resp.code == "202"
|
510
|
+
Collection.new(resp.body)
|
511
|
+
else
|
512
|
+
debug(resp)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
def delete_collection(collection)
|
516
|
+
collection_id = case collection
|
517
|
+
when Collection then collection.collection_id
|
518
|
+
else collection
|
519
|
+
end
|
520
|
+
|
521
|
+
resp=delete("/collection/#{u(collection_id.to_s)}")
|
522
|
+
if resp.code=="200"
|
523
|
+
true
|
524
|
+
else
|
525
|
+
false
|
526
|
+
end
|
527
|
+
end
|
528
|
+
def get_user_miniblog(user_id="@me",option={:start_index=>1,:max_results=>10})
|
529
|
+
resp=get("/people/#{u(user_id.to_s)}/miniblog?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
530
|
+
if resp.code=="200"
|
531
|
+
atom=resp.body
|
532
|
+
doc=REXML::Document.new(atom)
|
533
|
+
author=REXML::XPath.first(doc,"//feed/author")
|
534
|
+
author=Author.new(author.to_s) if author
|
535
|
+
miniblogs=[]
|
536
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
537
|
+
miniblog=Miniblog.new(entry)
|
538
|
+
miniblog.author=author
|
539
|
+
miniblogs<< miniblog
|
540
|
+
end
|
541
|
+
miniblogs
|
542
|
+
else
|
543
|
+
nil
|
544
|
+
end
|
545
|
+
end
|
546
|
+
def get_user_contact_miniblog(user_id="@me",option={:start_index=>1,:max_results=>10})
|
547
|
+
resp=get("/people/#{u(user_id.to_s)}/miniblog/contacts?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
548
|
+
if resp.code=="200"
|
549
|
+
atom=resp.body
|
550
|
+
doc=REXML::Document.new(atom)
|
551
|
+
miniblogs=[]
|
552
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
553
|
+
miniblog=Miniblog.new(entry)
|
554
|
+
miniblogs<< miniblog
|
555
|
+
end
|
556
|
+
miniblogs
|
557
|
+
else
|
558
|
+
nil
|
559
|
+
end
|
560
|
+
end
|
561
|
+
def create_miniblog(content="")
|
562
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
563
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
564
|
+
<content>#{h content}</content>
|
565
|
+
</entry>}
|
566
|
+
resp=post("/miniblog/saying",entry,{"Content-Type"=>"application/atom+xml"})
|
567
|
+
if resp.code=="201"
|
568
|
+
Miniblog.new(resp.body)
|
569
|
+
else
|
570
|
+
nil
|
571
|
+
end
|
572
|
+
end
|
573
|
+
def delete_miniblog(miniblog_id="")
|
574
|
+
resp=delete("/miniblog/#{u(miniblog_id.to_s)}")
|
575
|
+
if resp.code=="200"
|
576
|
+
true
|
577
|
+
else
|
578
|
+
false
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
# :call-seq:
|
583
|
+
# get_miniblog_comments(aMiniblog, options) => MiniblogComments or nil
|
584
|
+
# get_miniblog_comments(miniblog_id, options) => MiniblogComments or nil
|
585
|
+
#
|
586
|
+
# 获取我说回复 (http://goo.gl/nTZK)
|
587
|
+
def get_miniblog_comments(miniblog, options={})
|
588
|
+
miniblog_id = case miniblog
|
589
|
+
when Miniblog then miniblog.miniblog_id
|
590
|
+
else miniblog
|
591
|
+
end
|
592
|
+
|
593
|
+
url = "/miniblog/#{u miniblog_id}/comments?"
|
594
|
+
if options[:start_index]
|
595
|
+
url << "start-index=#{u options[:start_index]}&"
|
596
|
+
end
|
597
|
+
if options[:max_results]
|
598
|
+
url << "max-results=#{u options[:max_results]}&"
|
599
|
+
end
|
600
|
+
|
601
|
+
url = url[0..-2]
|
602
|
+
|
603
|
+
resp = get(url)
|
604
|
+
if resp.code == "200"
|
605
|
+
MiniblogComments.new(resp.body)
|
606
|
+
else
|
607
|
+
debug(resp)
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
# :call-seq:
|
612
|
+
# create_miniblog_comment(aMiniblog, aString) => MiniblogComment or nil
|
613
|
+
# create_miniblog_comment(obj, aString) => MiniblogComment or nil
|
614
|
+
#
|
615
|
+
# 回应我说 (http://goo.gl/j43Z)
|
616
|
+
def create_miniblog_comment(miniblog, content)
|
617
|
+
miniblog_id = case miniblog
|
618
|
+
when Miniblog then miniblog.miniblog_id
|
619
|
+
else miniblog
|
620
|
+
end
|
621
|
+
entry = %Q{<?xml version='1.0' encoding='UTF-8'?>
|
622
|
+
<entry>
|
623
|
+
<content>#{h content}</content>
|
624
|
+
</entry>}
|
625
|
+
|
626
|
+
resp = post("/miniblog/#{u miniblog_id}/comments", entry)
|
627
|
+
if resp.code == "201"
|
628
|
+
MiniblogComment.new(resp.body)
|
629
|
+
else
|
630
|
+
debug(resp)
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
# :call-seq:
|
635
|
+
# delete_miniblog_comment(aMiniblogComment) => true or false
|
636
|
+
# delete_miniblog_comment(miniblog_id, comment_id) => true or false
|
637
|
+
# 删除我说
|
638
|
+
def delete_miniblog_comment(*args)
|
639
|
+
if args.size == 1 and args[0].kind_of?(MiniblogComment)
|
640
|
+
miniblog_id = args[0].miniblog_id
|
641
|
+
comment_id = args[0].comment_id
|
642
|
+
elsif args.size == 2
|
643
|
+
miniblog_id = args[0].to_s
|
644
|
+
comment_id = args[1].to_s
|
645
|
+
else
|
646
|
+
raise "unsupported argument error"
|
647
|
+
end
|
648
|
+
|
649
|
+
resp = delete("/miniblog/#{u miniblog_id}/comment/#{u comment_id}")
|
650
|
+
if resp.code == "200"
|
651
|
+
true
|
652
|
+
else
|
653
|
+
debug(resp, false)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
def get_note(note_id="")
|
658
|
+
resp=get("/note/#{u(note_id.to_s)}")
|
659
|
+
if resp.code=="200"
|
660
|
+
atom=resp.body
|
661
|
+
Note.new(atom)
|
662
|
+
else
|
663
|
+
nil
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
def get_user_notes(user_id="@me",option={:start_index=>1,:max_results=>10})
|
668
|
+
resp=get("/people/#{u(user_id.to_s)}/notes?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
669
|
+
if resp.code=="200"
|
670
|
+
atom=resp.body
|
671
|
+
doc=REXML::Document.new(atom)
|
672
|
+
author=REXML::XPath.first(doc,"//feed/author")
|
673
|
+
author=Author.new(author.to_s) if author
|
674
|
+
notes=[]
|
675
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
676
|
+
note=Note.new(entry)
|
677
|
+
note.author=author
|
678
|
+
notes << note
|
679
|
+
end
|
680
|
+
notes
|
681
|
+
else
|
682
|
+
nil
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
def create_note(title="",content="",option={:privacy=>"public",:can_reply=>"yes"})
|
687
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
688
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
689
|
+
<title>#{h title}</title>
|
690
|
+
<content>#{h content}</content>
|
691
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
692
|
+
<db:attribute name="can_reply">#{h option[:can_reply]}</db:attribute>
|
693
|
+
</entry>
|
694
|
+
}
|
695
|
+
resp=post("/notes",entry,{"Content-Type"=>"application/atom+xml"})
|
696
|
+
if resp.code=="201"
|
697
|
+
Note.new(resp.body)
|
698
|
+
else
|
699
|
+
debug(resp)
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
def delete_note(note_id="")
|
704
|
+
note_id = note_id.note_id if note_id.kind_of?(Note)
|
705
|
+
|
706
|
+
resp=delete("/note/#{u(note_id.to_s)}")
|
707
|
+
if resp.code=="200"
|
708
|
+
true
|
709
|
+
else
|
710
|
+
false
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
def modify_note(note,title="",content="",option={:privacy=>"public",:can_reply=>"yes"})
|
715
|
+
note_id = case note
|
716
|
+
when Note then note.note_id
|
717
|
+
else note
|
718
|
+
end
|
719
|
+
|
720
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
721
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
722
|
+
<title>#{h title}</title>
|
723
|
+
<content>#{h content}</content>
|
724
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
725
|
+
<db:attribute name="can_reply">#{h option[:can_reply]}</db:attribute>
|
726
|
+
</entry>
|
727
|
+
}
|
728
|
+
resp=put("/note/#{u(note_id.to_s)}",entry,{"Content-Type"=>"application/atom+xml"})
|
729
|
+
if resp.code=="202"
|
730
|
+
Note.new(resp.body)
|
731
|
+
else
|
732
|
+
debug(resp)
|
733
|
+
end
|
734
|
+
end
|
735
|
+
def get_event(event_id="")
|
736
|
+
resp=get("/event/#{u(event_id.to_s)}")
|
737
|
+
if resp.code=="200"
|
738
|
+
atom=resp.body
|
739
|
+
Event.new(atom)
|
740
|
+
else
|
741
|
+
nil
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
# <b>DEPRECATED:</b> Please use <tt>get_event_participant_people</tt> instead.
|
746
|
+
def get_participant_people(*args)
|
747
|
+
warn "[DEPRECATION] `get_participant_people` is deprecated. Please use `get_event_participant_people` instead."
|
748
|
+
get_event_participant_people(*args)
|
749
|
+
end
|
750
|
+
|
751
|
+
def get_event_participant_people(event_id=nil,option={:start_index=>1,:max_results=>10})
|
752
|
+
resp=get("/event/#{u(event_id.to_s)}/participants?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
753
|
+
if resp.code=="200"
|
754
|
+
people=[]
|
755
|
+
atom=resp.body
|
756
|
+
doc=REXML::Document.new(atom)
|
757
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
758
|
+
people<< People.new(entry)
|
759
|
+
end
|
760
|
+
people
|
761
|
+
else
|
762
|
+
nil
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
# <b>DEPRECATED:</b> Please use <tt>get_event_wisher_people</tt> instead.
|
767
|
+
def get_wisher_people(*args)
|
768
|
+
warn "[DEPRECATION] `get_wisher_people` is deprecated. Please use `get_event_wisher_people` instead."
|
769
|
+
get_event_wisher_people(*args)
|
770
|
+
end
|
771
|
+
|
772
|
+
def get_event_wisher_people(event_id=nil,option={:start_index=>1,:max_results=>10})
|
773
|
+
resp=get("/event/#{u(event_id.to_s)}/wishers?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
774
|
+
if resp.code=="200"
|
775
|
+
people=[]
|
776
|
+
atom=resp.body
|
777
|
+
doc=REXML::Document.new(atom)
|
778
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
779
|
+
people<< People.new(entry)
|
780
|
+
end
|
781
|
+
people
|
782
|
+
else
|
783
|
+
nil
|
784
|
+
end
|
785
|
+
end
|
786
|
+
def get_user_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
787
|
+
resp=get("/people/#{u(user_id.to_s)}/events?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
788
|
+
if resp.code=="200"
|
789
|
+
events=[]
|
790
|
+
atom=resp.body
|
791
|
+
doc=REXML::Document.new(atom)
|
792
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
793
|
+
events<< Event.new(entry)
|
794
|
+
end
|
795
|
+
events
|
796
|
+
else
|
797
|
+
nil
|
798
|
+
end
|
799
|
+
end
|
800
|
+
def get_user_initiate_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
801
|
+
resp=get("/people/#{u(user_id.to_s)}/events/initiate?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
802
|
+
if resp.code=="200"
|
803
|
+
events=[]
|
804
|
+
atom=resp.body
|
805
|
+
doc=REXML::Document.new(atom)
|
806
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
807
|
+
events<< Event.new(entry)
|
808
|
+
end
|
809
|
+
events
|
810
|
+
else
|
811
|
+
nil
|
812
|
+
end
|
813
|
+
end
|
814
|
+
def get_user_participate_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
815
|
+
resp=get("/people/#{u(user_id.to_s)}/events/participate?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
816
|
+
if resp.code=="200"
|
817
|
+
events=[]
|
818
|
+
atom=resp.body
|
819
|
+
doc=REXML::Document.new(atom)
|
820
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
821
|
+
events<< Event.new(entry)
|
822
|
+
end
|
823
|
+
events
|
824
|
+
else
|
825
|
+
nil
|
826
|
+
end
|
827
|
+
end
|
828
|
+
def get_user_wish_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
829
|
+
resp=get("/people/#{u(user_id.to_s)}/events/wish?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
830
|
+
if resp.code=="200"
|
831
|
+
events=[]
|
832
|
+
atom=resp.body
|
833
|
+
doc=REXML::Document.new(atom)
|
834
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
835
|
+
events<< Event.new(entry)
|
836
|
+
end
|
837
|
+
events
|
838
|
+
else
|
839
|
+
nil
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
def get_city_events(location_id=nil,option={:type=>"all",:start_index=>1,:max_results=>10})
|
844
|
+
resp=get("/event/location/#{u(location_id.to_s)}?type=#{option[:type]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
845
|
+
if resp.code=="200"
|
846
|
+
events=[]
|
847
|
+
atom=resp.body
|
848
|
+
doc=REXML::Document.new(atom)
|
849
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
850
|
+
events<< Event.new(entry)
|
851
|
+
end
|
852
|
+
events
|
853
|
+
else
|
854
|
+
nil
|
855
|
+
end
|
856
|
+
end
|
857
|
+
def search_events(q="",option={:location=>"all",:start_index=>1,:max_results=>10})
|
858
|
+
resp=get("/events?q=#{u(q.to_s)}&location=#{option[:location]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
859
|
+
if resp.code=="200"
|
860
|
+
events=[]
|
861
|
+
atom=resp.body
|
862
|
+
doc=REXML::Document.new(atom)
|
863
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
864
|
+
events<< Event.new(entry)
|
865
|
+
end
|
866
|
+
events
|
867
|
+
else
|
868
|
+
nil
|
869
|
+
end
|
870
|
+
end
|
871
|
+
def create_event(title="",content="",where="",option={:kind=>"party",:invite_only=>"no",:can_invite=>"yes",:when=>{"endTime"=>(Time.now+60*60*24*5).strftime("%Y-%m-%dT%H:%M:%S+08:00"),"startTime"=>Time.now.strftime("%Y-%m-%dT%H:%M:%S+08:00")}})
|
872
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
873
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
874
|
+
<title>#{h title}</title>
|
875
|
+
<category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#event.#{option[:kind]}"/>
|
876
|
+
<content>#{h content}</content>
|
877
|
+
<db:attribute name="invite_only">#{h option[:invite_only]}</db:attribute>
|
878
|
+
<db:attribute name="can_invite">#{h option[:can_invite]}</db:attribute>
|
879
|
+
<gd:when endTime="#{h option[:when]["endTime"]}" startTime="#{h option[:when]["startTime"]}"/>
|
880
|
+
<gd:where valueString="#{h where}" />
|
881
|
+
</entry>
|
882
|
+
}
|
883
|
+
resp=post("/events",entry,{"Content-Type"=>"application/atom+xml"})
|
884
|
+
if resp.code=="201"
|
885
|
+
Event.new(resp.body)
|
886
|
+
else
|
887
|
+
debug(resp)
|
888
|
+
end
|
889
|
+
end
|
890
|
+
|
891
|
+
def modify_event(event,title=nil,content=nil,where=nil,option=nil)
|
892
|
+
|
893
|
+
event_id = case event
|
894
|
+
when Event then event.event_id
|
895
|
+
else event
|
896
|
+
end
|
897
|
+
|
898
|
+
option = {} if option.nil?
|
899
|
+
option = {:kind=>"exhibit",
|
900
|
+
:invite_only=>"no",
|
901
|
+
:can_invite=>"yes",
|
902
|
+
:when=>{"endTime"=>(Time.now+60*60*24*5).strftime("%Y-%m-%dT%H:%M:%S+08:00"),
|
903
|
+
"startTime"=>Time.now.strftime("%Y-%m-%dT%H:%M:%S+08:00")}}.merge(option)
|
904
|
+
|
905
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
906
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
907
|
+
<title>#{h title}</title>
|
908
|
+
<category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#event.#{option[:kind]}"/>
|
909
|
+
<content>#{h content}</content>
|
910
|
+
<db:attribute name="invite_only">#{h option[:invite_only]}</db:attribute>
|
911
|
+
<db:attribute name="can_invite">#{h option[:can_invite]}</db:attribute>
|
912
|
+
<gd:when endTime="#{h option[:when]["endTime"]}" startTime="#{h option[:when]["startTime"]}"/>
|
913
|
+
<gd:where valueString="#{h where}" />
|
914
|
+
</entry>
|
915
|
+
}
|
916
|
+
resp=put("/event/#{u(event_id)}",entry,{"Content-Type"=>"application/atom+xml"})
|
917
|
+
if resp.code=="200"
|
918
|
+
Event.new(resp.body)
|
919
|
+
else
|
920
|
+
debug(resp)
|
921
|
+
end
|
922
|
+
end
|
923
|
+
|
924
|
+
def get_mail_inbox(option={:start_index=>1,:max_results=>10})
|
925
|
+
resp=get("/doumail/inbox?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
926
|
+
if resp.code=="200"
|
927
|
+
mails=[]
|
928
|
+
atom=resp.body
|
929
|
+
doc=REXML::Document.new(atom)
|
930
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
931
|
+
mails << Mail.new(entry)
|
932
|
+
end
|
933
|
+
mails
|
934
|
+
else
|
935
|
+
nil
|
936
|
+
end
|
937
|
+
end
|
938
|
+
def get_unread_mail(option={:start_index=>1,:max_results=>10})
|
939
|
+
resp=get("/doumail/inbox/unread?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
940
|
+
if resp.code=="200"
|
941
|
+
mails=[]
|
942
|
+
atom=resp.body
|
943
|
+
doc=REXML::Document.new(atom)
|
944
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
945
|
+
mails << Mail.new(entry)
|
946
|
+
end
|
947
|
+
mails
|
948
|
+
else
|
949
|
+
nil
|
950
|
+
end
|
951
|
+
end
|
952
|
+
def get_mail_outbox(option={:start_index=>1,:max_results=>10})
|
953
|
+
resp=get("/doumail/outbox?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
954
|
+
if resp.code=="200"
|
955
|
+
mails=[]
|
956
|
+
atom=resp.body
|
957
|
+
doc=REXML::Document.new(atom)
|
958
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
959
|
+
mails << Mail.new(entry)
|
960
|
+
end
|
961
|
+
mails
|
962
|
+
else
|
963
|
+
nil
|
964
|
+
end
|
965
|
+
end
|
966
|
+
def get_mail(mail_id="",keep_unread="false")
|
967
|
+
resp=get("/doumail/#{u(mail_id.to_s)}?keep-unread=#{keep_unread}")
|
968
|
+
if resp.code=="200"
|
969
|
+
atom=resp.body
|
970
|
+
Mail.new(atom)
|
971
|
+
else
|
972
|
+
nil
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
# <b>DEPRECATED:</b> Please use <tt>send_mail</tt> instead.
|
977
|
+
def create_mail(*args)
|
978
|
+
warn "[DEPRECATION] `create_mail` is deprecated. Please use `send_mail` instead."
|
979
|
+
send_mail(*args)
|
980
|
+
end
|
981
|
+
|
982
|
+
def send_mail(id="",title="",content="",captcha_token="",captcha_string="")
|
983
|
+
if !(captcha_token.empty?&&captcha_string.empty?)
|
984
|
+
entry=%Q(<?xml version="1.0" encoding="UTF-8"?>
|
985
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
986
|
+
<db:entity name="receiver"><uri>http://api.douban.com/people/#{h id}</uri></db:entity>
|
987
|
+
<content>#{h content}</content>
|
988
|
+
<title>#{h title}</title>
|
989
|
+
<db:attribute name="captcha_token">#{h captcha_token}</db:attribute>
|
990
|
+
<db:attribute name="captcha_string">#{h captcha_string}</db:attribute>
|
991
|
+
</entry>)
|
992
|
+
else
|
993
|
+
entry=%Q(<?xml version="1.0" encoding="UTF-8"?>
|
994
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
|
995
|
+
<db:entity name="receiver">
|
996
|
+
<uri>http://api.douban.com/people/#{h id}</uri></db:entity>
|
997
|
+
<content>#{h content}</content>
|
998
|
+
<title>#{h title}</title>
|
999
|
+
</entry>)
|
1000
|
+
end
|
1001
|
+
resp=post("/doumails",entry,{"Content-Type"=>"application/atom+xml"})
|
1002
|
+
if resp.code=="201"
|
1003
|
+
true
|
1004
|
+
elsif resp.code=="403"
|
1005
|
+
hash={}
|
1006
|
+
str=CGI.unescapeHTML(resp.body)
|
1007
|
+
hash[:token]=str.scan(/^captcha_token=(.*?)&/).flatten.to_s
|
1008
|
+
hash[:url]=str.scan(/captcha_url=(.*?)$/).flatten.to_s
|
1009
|
+
hash
|
1010
|
+
else
|
1011
|
+
debug(resp)
|
1012
|
+
end
|
1013
|
+
end
|
1014
|
+
def read_mail(mail_id="")
|
1015
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"><db:attribute name="unread">false</db:attribute></entry>}
|
1016
|
+
resp=put("/doumail/#{mail_id.to_s}",entry,{"Content-Type" => "application/atom+xml"})
|
1017
|
+
if resp.code=="202"
|
1018
|
+
true
|
1019
|
+
else
|
1020
|
+
false
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
def delete_mail(mail_id="")
|
1024
|
+
resp=delete("/doumail/#{mail_id.to_s}")
|
1025
|
+
if resp.code=="200"
|
1026
|
+
true
|
1027
|
+
else
|
1028
|
+
false
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
def read_mails(mail_ids=[])
|
1032
|
+
entrys=""
|
1033
|
+
mail_ids.each do |mail_id|
|
1034
|
+
entrys +=%Q{<entry><id>http://api.douban.com/doumail/#{mail_id}</id><db:attribute name="unread">false</db:attribute></entry>}
|
1035
|
+
end
|
1036
|
+
feed=%Q{<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">#{entrys}</feed>}
|
1037
|
+
resp=put("/doumail/",feed,{"Content-Type" => "application/atom+xml"})
|
1038
|
+
if resp.code=="202"
|
1039
|
+
true
|
1040
|
+
else
|
1041
|
+
false
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
def delete_mails(mail_ids=[])
|
1045
|
+
entrys=""
|
1046
|
+
mail_ids.each do |mail_id|
|
1047
|
+
entrys += %Q{<entry><id>http://api.douban.com/doumail/#{mail_id}</id></entry>}
|
1048
|
+
end
|
1049
|
+
feed=%Q{<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">#{entrys}</feed>}
|
1050
|
+
resp=post("/doumail/delete",feed,{"Content-Type" => "application/atom+xml"})
|
1051
|
+
if resp.code=="202"
|
1052
|
+
true
|
1053
|
+
else
|
1054
|
+
false
|
1055
|
+
end
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
def get_book_tags(subject_id="",flag=:book)
|
1059
|
+
case flag
|
1060
|
+
when :book
|
1061
|
+
resp=get("/book/subject/#{subject_id}/tags")
|
1062
|
+
when :music
|
1063
|
+
resp=get("/music/subject/#{subject_id}/tags")
|
1064
|
+
when :movie
|
1065
|
+
resp=get("/movie/subject/#{subject_id}/tags")
|
1066
|
+
end
|
1067
|
+
if resp.code=="200"
|
1068
|
+
tags=[]
|
1069
|
+
atom=resp.body
|
1070
|
+
doc=REXML::Document.new(atom)
|
1071
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
1072
|
+
tags << Tag.new(entry)
|
1073
|
+
end
|
1074
|
+
tags
|
1075
|
+
else
|
1076
|
+
nil
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
def get_user_tags(user_id="@me",flag=:book,option={:max_results=>10})
|
1080
|
+
case flag
|
1081
|
+
when :book
|
1082
|
+
resp=get("/people/#{u user_id}/tags?cat=book&max-results=#{option[:max_results]}")
|
1083
|
+
when :music
|
1084
|
+
resp=get("/people/#{u user_id}/tags?cat=music&max-results=#{option[:max_results]}")
|
1085
|
+
when :movie
|
1086
|
+
resp=get("/people/#{u user_id}/tags?cat=movie&max-results=#{option[:max_results]}")
|
1087
|
+
end
|
1088
|
+
if resp.code=="200"
|
1089
|
+
tags=[]
|
1090
|
+
atom=resp.body
|
1091
|
+
doc=REXML::Document.new(atom)
|
1092
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
1093
|
+
tags << Tag.new(entry)
|
1094
|
+
end
|
1095
|
+
tags
|
1096
|
+
else
|
1097
|
+
debug(resp)
|
1098
|
+
end
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
def delete_event(event_id="")
|
1102
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?><entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/"><content>sorry!!!</content></entry>}
|
1103
|
+
resp=post("/event/#{u(event_id)}/delete",entry,{"Content-Type"=>"application/atom+xml"})
|
1104
|
+
if resp.code=="200"
|
1105
|
+
true
|
1106
|
+
else
|
1107
|
+
debug(resp, false)
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
# @param token can be OAuth::RequestToken or OAuth::Token or Hash
|
1112
|
+
#
|
1113
|
+
# @see #request_token
|
1114
|
+
def request_token=(token)
|
1115
|
+
case token
|
1116
|
+
when OAuth::RequestToken
|
1117
|
+
@request_token = token
|
1118
|
+
when OAuth::Token
|
1119
|
+
@request_token = OAuth::RequestToken.new(
|
1120
|
+
new_request_consumer,
|
1121
|
+
token.token,
|
1122
|
+
token.secret)
|
1123
|
+
when Hash
|
1124
|
+
@request_token = OAuth::RequestToken.new(
|
1125
|
+
new_request_consumer,
|
1126
|
+
token[:token],
|
1127
|
+
token[:secret])
|
1128
|
+
else
|
1129
|
+
raise ArgumentError
|
1130
|
+
end
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
|
1134
|
+
# :call-seq:
|
1135
|
+
# request_token => OAuth::RequestToken
|
1136
|
+
# request_token :as_token => OAuth::Token
|
1137
|
+
# request_token :as_hash => Hash
|
1138
|
+
#
|
1139
|
+
# if you want to serialize request_token, use :as_token or :as_hash
|
1140
|
+
def request_token(arg=nil)
|
1141
|
+
if arg.nil?
|
1142
|
+
@request_token
|
1143
|
+
elsif arg == :as_token
|
1144
|
+
@request_token.nil? ? nil :
|
1145
|
+
OAuth::Token.new(@request_token.token, @request_token.secret)
|
1146
|
+
elsif arg == :as_hash
|
1147
|
+
@request_token.nil? ? nil :
|
1148
|
+
{:token => @request_token.token,
|
1149
|
+
:secret => @request_token.secret}
|
1150
|
+
else
|
1151
|
+
raise ArgumentError
|
1152
|
+
end
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
def access_token=(token)
|
1156
|
+
case token
|
1157
|
+
when OAuth::AccessToken
|
1158
|
+
@access_token = token
|
1159
|
+
when OAuth::Token
|
1160
|
+
@access_token = OAuth::AccessToken.new(
|
1161
|
+
new_access_consumer,
|
1162
|
+
token.token,
|
1163
|
+
token.secret)
|
1164
|
+
when Hash
|
1165
|
+
@access_token = OAuth::AccessToken.new(
|
1166
|
+
new_access_consumer,
|
1167
|
+
token[:token],
|
1168
|
+
token[:secret])
|
1169
|
+
else
|
1170
|
+
raise ArgumentError
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
# :call-seq:
|
1175
|
+
# access_token => OAuth::AccessToken
|
1176
|
+
# access_token :as_token => OAuth::Token
|
1177
|
+
# access_token :as_hash => Hash
|
1178
|
+
#
|
1179
|
+
# if you want to serialize access_token, use :as_token or :as_hash
|
1180
|
+
def access_token(arg=nil)
|
1181
|
+
if arg.nil?
|
1182
|
+
@access_token
|
1183
|
+
elsif arg == :as_token
|
1184
|
+
@access_token.nil? ? nil :
|
1185
|
+
OAuth::Token.new(@access_token.token, @access_token.secret)
|
1186
|
+
elsif arg == :as_hash
|
1187
|
+
@access_token.nil? ? nil :
|
1188
|
+
{:token => @access_token.token,
|
1189
|
+
:secret => @access_token.secret}
|
1190
|
+
else
|
1191
|
+
raise ArgumentError
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def get_recommendation(id)
|
1196
|
+
resp=get("/recommendation/#{u(id.to_s)}")
|
1197
|
+
if resp.code=="200"
|
1198
|
+
Recommendation.new(resp.body)
|
1199
|
+
elsif resp.code == "404"
|
1200
|
+
nil
|
1201
|
+
else
|
1202
|
+
debug(resp)
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def get_user_recommendations(user_id="@me",option={:start_index=>1,:max_results=>10})
|
1207
|
+
resp=get("/people/#{u(user_id.to_s)}/recommendations?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
1208
|
+
if resp.code == "200"
|
1209
|
+
recommendations = []
|
1210
|
+
doc=REXML::Document.new(resp.body)
|
1211
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
1212
|
+
recommendations << Recommendation.new(entry)
|
1213
|
+
end
|
1214
|
+
recommendations
|
1215
|
+
else
|
1216
|
+
debug(resp)
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def get_recommendation_comments(recommendation_id)
|
1221
|
+
resp = get("/recommendation/#{u(recommendation_id)}/comments")
|
1222
|
+
if resp.code == "200"
|
1223
|
+
comments = []
|
1224
|
+
doc=REXML::Document.new(resp.body)
|
1225
|
+
REXML::XPath.each(doc, "//entry") do |entry|
|
1226
|
+
comments << RecommendationComment.new(entry)
|
1227
|
+
end
|
1228
|
+
comments
|
1229
|
+
else
|
1230
|
+
debug(resp)
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
def create_recommendation(subject, title, comment)
|
1235
|
+
subject = subject.kind_of?(Douban::Subject) ? subject.id : subject
|
1236
|
+
entry = %Q{<?xml version="1.0" encoding="UTF-8"?>
|
1237
|
+
<entry xmlns="http://www.w3.org/2005/Atom"
|
1238
|
+
xmlns:gd="http://schemas.google.com/g/2005"
|
1239
|
+
xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"
|
1240
|
+
xmlns:db="http://www.douban.com/xmlns/">
|
1241
|
+
<title>#{h title}</title>
|
1242
|
+
<db:attribute name="comment">#{h comment}</db:attribute>
|
1243
|
+
<link href="#{h subject}" rel="related" />
|
1244
|
+
</entry>}
|
1245
|
+
resp = post("/recommendations", entry, {"Content-Type"=>"application/atom+xml"})
|
1246
|
+
if resp.code == '201'
|
1247
|
+
Recommendation.new(resp.body)
|
1248
|
+
else
|
1249
|
+
debug(resp)
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
def delete_recommendation(recommendation_id)
|
1254
|
+
if recommendation_id.kind_of?(Douban::Recommendation)
|
1255
|
+
recommendation_id = %r{/(\d+)$}.match(recommendation_id.id)[1]
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
resp = delete("/recommendation/#{u recommendation_id}")
|
1259
|
+
if resp.code == '200'
|
1260
|
+
true
|
1261
|
+
else
|
1262
|
+
debug(resp, false)
|
1263
|
+
end
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
def create_recommendation_comment(recommendation, content)
|
1267
|
+
recommendation_id = recommendation.kind_of?(Douban::Recommendation) \
|
1268
|
+
? recommendation.recommendation_id : recommendation
|
1269
|
+
entry = %Q{<?xml version='1.0' encoding='UTF-8'?>
|
1270
|
+
<entry>
|
1271
|
+
<content>#{h content}</content>
|
1272
|
+
</entry>}
|
1273
|
+
resp = post("/recommendation/#{u recommendation_id}/comments", entry, {"Content-Type"=>"application/atom+xml"})
|
1274
|
+
if resp.code == '201'
|
1275
|
+
RecommendationComment.new(resp.body)
|
1276
|
+
else
|
1277
|
+
debug(resp)
|
1278
|
+
end
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
# delete_recommendation_comment(comment:RecommendationComment)
|
1282
|
+
# delete_recommendation_comment(recommendation:Recommendation, comment_id:Integer)
|
1283
|
+
# delete_recommendation_comment(recommendation_id:Integer, comment_id:Integer)
|
1284
|
+
def delete_recommendation_comment(recommendation, comment_id=nil)
|
1285
|
+
if comment_id.nil?
|
1286
|
+
recommendation_id = recommendation.recommendation_id
|
1287
|
+
comment_id = recommendation.comment_id
|
1288
|
+
else
|
1289
|
+
recommendation_id = recommendation.kind_of?(Douban::Recommendation) \
|
1290
|
+
? recommendation.recommendation_id : recommendation
|
1291
|
+
end
|
1292
|
+
resp = delete("/recommendation/#{u recommendation_id}/comment/#{u comment_id}")
|
1293
|
+
if resp.code == '200'
|
1294
|
+
true
|
1295
|
+
else
|
1296
|
+
debug(resp, false)
|
1297
|
+
end
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
# 验证Access Token是否可用
|
1301
|
+
# http://goo.gl/8v8d
|
1302
|
+
def verify_token
|
1303
|
+
resp = get("/access_token/#{@access_token.token}")
|
1304
|
+
if resp.code == "200"
|
1305
|
+
true
|
1306
|
+
elsif resp.code == "401"
|
1307
|
+
false
|
1308
|
+
else
|
1309
|
+
debug(resp, false)
|
1310
|
+
end
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
# 注销一个Access Token
|
1314
|
+
# http://goo.gl/0JAB
|
1315
|
+
def delete_token
|
1316
|
+
resp = delete("/access_token/#{@access_token.token}")
|
1317
|
+
if resp.code == "200"
|
1318
|
+
true
|
1319
|
+
else
|
1320
|
+
debug(resp, false)
|
1321
|
+
end
|
1322
|
+
end
|
1323
|
+
alias_method :logout, :delete_token
|
1324
|
+
|
1325
|
+
protected
|
1326
|
+
def new_request_consumer
|
1327
|
+
OAuth::Consumer.new(@api_key, @secret_key, @oauth_request_option)
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
def new_access_consumer
|
1331
|
+
OAuth::Consumer.new(@api_key, @secret_key, @oauth_access_option)
|
1332
|
+
end
|
1333
|
+
|
1334
|
+
def debug(resp, retval=nil)
|
1335
|
+
if @@debug
|
1336
|
+
p resp.code
|
1337
|
+
p resp.body
|
1338
|
+
end
|
1339
|
+
retval
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
def html_encode(o)
|
1343
|
+
CGI.escapeHTML(o.to_s)
|
1344
|
+
end
|
1345
|
+
alias_method :h, :html_encode
|
1346
|
+
|
1347
|
+
def url_encode(o)
|
1348
|
+
CGI.escape(o.to_s)
|
1349
|
+
end
|
1350
|
+
alias_method :u, :url_encode
|
1351
|
+
|
1352
|
+
def get(path,headers={})
|
1353
|
+
@access_token.get(path,headers)
|
1354
|
+
end
|
1355
|
+
def post(path,data="",headers=nil)
|
1356
|
+
headers ||= {"Content-Type" => "application/atom+xml"}
|
1357
|
+
@access_token.post(path,data,headers)
|
1358
|
+
end
|
1359
|
+
def put(path,body="",headers=nil)
|
1360
|
+
headers ||= {"Content-Type" => "application/atom+xml"}
|
1361
|
+
@access_token.put(path,body,headers)
|
1362
|
+
end
|
1363
|
+
def delete(path,headers={})
|
1364
|
+
@access_token.delete(path,headers)
|
1365
|
+
end
|
1366
|
+
def head(path,headers={})
|
1367
|
+
@access_token.head(path,headers)
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
def _subject_search_args_to_url(type, *args)
|
1371
|
+
arg = args.shift
|
1372
|
+
|
1373
|
+
option = case arg
|
1374
|
+
when String
|
1375
|
+
arg2 = args.shift
|
1376
|
+
arg2 ||= {}
|
1377
|
+
arg2.merge(:q => arg)
|
1378
|
+
when Hash
|
1379
|
+
arg
|
1380
|
+
else
|
1381
|
+
raise "unknown type for first arg: #{arg.class}"
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
raise "extra argument" unless args.empty?
|
1385
|
+
|
1386
|
+
if option[:q].nil? and option[:tag].nil?
|
1387
|
+
raise "you must specify :q or :tag"
|
1388
|
+
end
|
1389
|
+
|
1390
|
+
url = "/#{type}/subjects?"
|
1391
|
+
url << "q=#{u option[:q]}&" if option[:q]
|
1392
|
+
url << "tag=#{u option[:tag]}&" if option[:tag]
|
1393
|
+
url << "start_index=#{u option[:start_index]}&" if option[:start_index]
|
1394
|
+
url << "max_results=#{u option[:max_results]}&" if option[:max_results]
|
1395
|
+
url.slice!(-1)
|
1396
|
+
url
|
1397
|
+
end
|
1398
|
+
end
|
1399
|
+
end
|
1400
|
+
|