douban-ruby 0.0.5
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.tar.gz.sig +0 -0
- data/History.txt +40 -0
- data/Manifest.txt +34 -0
- data/README.txt +25 -0
- data/Rakefile +34 -0
- data/examples/example.rb +21 -0
- data/lib/douban.rb +57 -0
- data/lib/douban/author.rb +41 -0
- data/lib/douban/authorize.rb +1150 -0
- data/lib/douban/collection.rb +69 -0
- data/lib/douban/equal.rb +11 -0
- data/lib/douban/event.rb +80 -0
- data/lib/douban/mail.rb +56 -0
- data/lib/douban/miniblog.rb +59 -0
- data/lib/douban/note.rb +60 -0
- data/lib/douban/people.rb +48 -0
- data/lib/douban/recommendation.rb +47 -0
- data/lib/douban/recommendation_comment.rb +36 -0
- data/lib/douban/review.rb +66 -0
- data/lib/douban/subject.rb +87 -0
- data/lib/douban/tag.rb +39 -0
- data/spec/douban/author_spec.rb +32 -0
- data/spec/douban/authorize_spec.rb +508 -0
- data/spec/douban/collection_spec.rb +77 -0
- data/spec/douban/event_spec.rb +60 -0
- data/spec/douban/mail_spec.rb +98 -0
- data/spec/douban/miniblog_spec.rb +48 -0
- data/spec/douban/note_spec.rb +60 -0
- data/spec/douban/people_spec.rb +49 -0
- data/spec/douban/recommendation_comment_spec.rb +38 -0
- data/spec/douban/recommendation_spec.rb +48 -0
- data/spec/douban/review_spec.rb +76 -0
- data/spec/douban/tag_spec.rb +29 -0
- data/spec/douban_spec.rb +9 -0
- data/spec/spec_helper.rb +3 -0
- metadata +152 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
Binary file
|
data/History.txt
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
=== 0.0.5 / 2010-07-04
|
2
|
+
* Douban::Authorize
|
3
|
+
* all modify_* functions will return an Object if success, otherwise nil. In
|
4
|
+
old version, it will return true or false.
|
5
|
+
* all create_* and delete_* will correctly escape the param for xml.
|
6
|
+
* all the functions return list will work correctly
|
7
|
+
* all the .rb files can be loaded. (you don't have to load from douban.rb)
|
8
|
+
* some bug fix.
|
9
|
+
|
10
|
+
=== 0.0.4 / 2010-07-03
|
11
|
+
* Douban::Authorize
|
12
|
+
* all create_* functions (except create_mail) will return an Object if
|
13
|
+
success, otherwise nil, in old version, it will return true or false.
|
14
|
+
create_mail does not work like other functions, it's should be named
|
15
|
+
as send_mail.
|
16
|
+
* some refactors on the model classes.
|
17
|
+
|
18
|
+
=== 0.0.3 / 2010-07-02
|
19
|
+
* Douban::Authorize
|
20
|
+
* recommendation apis added
|
21
|
+
* get_recommendation
|
22
|
+
* get_user_recommendations
|
23
|
+
* get_recommendation_comments
|
24
|
+
* create_recommendation
|
25
|
+
* delete_recommendation
|
26
|
+
* create_recommendation_comment
|
27
|
+
* delete_recommendation_comment
|
28
|
+
|
29
|
+
=== 0.0.2 / 2010-07-01
|
30
|
+
* Douban.authorize no longer works, you need use Douban::Authorize.new
|
31
|
+
* Douban::Authorize
|
32
|
+
* you can restore request token with request_token=
|
33
|
+
* you can restore access token with access_token=
|
34
|
+
* create_miniblog will quote +content+ parameter
|
35
|
+
* create_miniblog will return a Douban::Miniblog if success, otherwise return nil
|
36
|
+
* add some test with rspec
|
37
|
+
|
38
|
+
=== 0.0.1 / 2010-06-30
|
39
|
+
|
40
|
+
* import from http://code.google.com/p/doubanclient-ruby/
|
data/Manifest.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
examples/example.rb
|
6
|
+
lib/douban.rb
|
7
|
+
lib/douban/author.rb
|
8
|
+
lib/douban/authorize.rb
|
9
|
+
lib/douban/collection.rb
|
10
|
+
lib/douban/equal.rb
|
11
|
+
lib/douban/event.rb
|
12
|
+
lib/douban/mail.rb
|
13
|
+
lib/douban/miniblog.rb
|
14
|
+
lib/douban/note.rb
|
15
|
+
lib/douban/people.rb
|
16
|
+
lib/douban/recommendation.rb
|
17
|
+
lib/douban/recommendation_comment.rb
|
18
|
+
lib/douban/review.rb
|
19
|
+
lib/douban/subject.rb
|
20
|
+
lib/douban/tag.rb
|
21
|
+
spec/douban/author_spec.rb
|
22
|
+
spec/douban/authorize_spec.rb
|
23
|
+
spec/douban/collection_spec.rb
|
24
|
+
spec/douban/event_spec.rb
|
25
|
+
spec/douban/mail_spec.rb
|
26
|
+
spec/douban/miniblog_spec.rb
|
27
|
+
spec/douban/note_spec.rb
|
28
|
+
spec/douban/people_spec.rb
|
29
|
+
spec/douban/recommendation_comment_spec.rb
|
30
|
+
spec/douban/recommendation_spec.rb
|
31
|
+
spec/douban/review_spec.rb
|
32
|
+
spec/douban/tag_spec.rb
|
33
|
+
spec/douban_spec.rb
|
34
|
+
spec/spec_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= Douban Ruby Client
|
2
|
+
|
3
|
+
http://github.com/lidaobing/douban-ruby
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
douban ruby client. including OAuth support.
|
8
|
+
|
9
|
+
Douban API reference: http://www.douban.com/service/apidoc/reference/
|
10
|
+
|
11
|
+
== Requirments
|
12
|
+
|
13
|
+
* oauth: sudo gem install oauth
|
14
|
+
|
15
|
+
== INSTALL:
|
16
|
+
|
17
|
+
sudo rake install_gem
|
18
|
+
|
19
|
+
== Usage:
|
20
|
+
|
21
|
+
http://github.com/lidaobing/douban-ruby/blob/master/examples/example.rb
|
22
|
+
|
23
|
+
== LICENSE:
|
24
|
+
|
25
|
+
licensed under Artistic License or GPL license.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
$:.unshift(File.dirname(__FILE__) + "/lib")
|
4
|
+
require 'douban'
|
5
|
+
|
6
|
+
ENV["SPEC_OPTS"] ||= "-f nested --color -b"
|
7
|
+
|
8
|
+
Hoe.spec 'douban-ruby' do
|
9
|
+
developer "Hoooopo", "hoooopo@gmail.com"
|
10
|
+
developer "LI Daobing", "lidaobing@gmail.com"
|
11
|
+
end
|
12
|
+
|
13
|
+
Hoe.plugin :minitest
|
14
|
+
Hoe.plugin :git
|
15
|
+
Hoe.plugin :gemcutter
|
16
|
+
|
17
|
+
desc "Simple require on packaged files to make sure they are all there"
|
18
|
+
task :verify => :package do
|
19
|
+
# An error message will be displayed if files are missing
|
20
|
+
if system %(ruby -e "require 'pkg/douban-#{Douban::VERSION}/lib/douban'")
|
21
|
+
puts "\nThe library files are present"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
task :release => :verify
|
26
|
+
|
27
|
+
namespace :spec do
|
28
|
+
desc "Run specs with RCov"
|
29
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
30
|
+
t.spec_files = FileList['spec/**/*_spec.rb' ]
|
31
|
+
t.rcov = true
|
32
|
+
t.rcov_opts = ['--exclude' , 'gems,spec' ]
|
33
|
+
end
|
34
|
+
end
|
data/examples/example.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'douban'
|
3
|
+
|
4
|
+
class MyDouban < Douban::Authorize
|
5
|
+
def initialize
|
6
|
+
@apikey = '042bc009d7d4a04d0c83401d877de0e7'
|
7
|
+
@secret = 'a9bb2d7f8cc00110'
|
8
|
+
super(@apikey, @secret)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
douban = MyDouban.new
|
14
|
+
|
15
|
+
print "please open #{douban.get_authorize_url}\n"
|
16
|
+
print "after login, press Enter to continue\n"
|
17
|
+
|
18
|
+
gets
|
19
|
+
|
20
|
+
douban.auth
|
21
|
+
print douban.get_people
|
data/lib/douban.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#=douban.rb
|
2
|
+
#
|
3
|
+
# Copyright (c) 2008 Hooopo
|
4
|
+
# Written and maintained by Hooopo<hoooopo@gmail.com>
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This program is free software. You can re-distribute and/or
|
8
|
+
# modify this program under the same terms of ruby itself ---
|
9
|
+
# Ruby Distribution License or GNU General Public License.
|
10
|
+
#
|
11
|
+
# See Douban::Authorize for an overview and examples.
|
12
|
+
#
|
13
|
+
#== Douban API Client Based Ruby
|
14
|
+
# This is the Douban Ruby library, which communicates to the Douban
|
15
|
+
# API REST servers and converts Atom into proper Ruby objects.
|
16
|
+
# In order to use the library, you need to sign up for a Douban account and
|
17
|
+
# ensure you have the oauth and modules installed.
|
18
|
+
# Douban account and ApiKey,SecrectKey
|
19
|
+
# To get a Douban account,you need to sign up at:
|
20
|
+
# http://www.douban.com/register
|
21
|
+
# Once approved, you will need to create an application to get your api key and
|
22
|
+
# secret key at :
|
23
|
+
# http://www.douban.com/service/apikey/
|
24
|
+
# You can get apikey and secrectkey ,if you create an application.
|
25
|
+
# The keys can be placed into douban.yaml or specified at runtime
|
26
|
+
# when you new a Douban::Authorize.
|
27
|
+
# Depencencies
|
28
|
+
# This library has some external dependencies:
|
29
|
+
# oauth ( http://oauth.googlecode.com/svn/code/ruby )
|
30
|
+
# You can install oauth via rubygem:
|
31
|
+
# Gem install oauth -y
|
32
|
+
#==Usage
|
33
|
+
# require "douban"
|
34
|
+
# client=Douban.authorize(apikey, secret)
|
35
|
+
# authorize_url=client.get_authorize_url
|
36
|
+
# NOTE:
|
37
|
+
# Permission to access a user's data is restricted -- you can't just access
|
38
|
+
# any user's data. In order to access a user's data, they need to have
|
39
|
+
# visit the authorize_url and press the 'agree' button .
|
40
|
+
# when user has press the 'agree' button ,we use client.auth to authorize.
|
41
|
+
# client=client.auth
|
42
|
+
# puts client.authoried? #return true or false
|
43
|
+
# Get users' info via his uid
|
44
|
+
# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
45
|
+
# people = client.get_people('hooopo')
|
46
|
+
# people.class === People
|
47
|
+
# people.title === hooopo
|
48
|
+
# people.location === "长沙"
|
49
|
+
#==Install and Wiki
|
50
|
+
# http://code.google.com/p/doubanclient-ruby/
|
51
|
+
|
52
|
+
require 'douban/authorize'
|
53
|
+
|
54
|
+
module Douban
|
55
|
+
VERSION = "0.0.5"
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'douban/equal'
|
3
|
+
|
4
|
+
module Douban
|
5
|
+
class Author
|
6
|
+
include Douban::Equal
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def attr_names
|
10
|
+
[
|
11
|
+
:uri,
|
12
|
+
:link,
|
13
|
+
:name
|
14
|
+
]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
attr_names.each do |attr|
|
18
|
+
attr_accessor attr
|
19
|
+
end
|
20
|
+
def initialize(atom=nil)
|
21
|
+
doc = case atom
|
22
|
+
when REXML::Document then atom.root
|
23
|
+
when REXML::Element then atom
|
24
|
+
when nil then nil
|
25
|
+
else REXML::Document.new(atom).root
|
26
|
+
end
|
27
|
+
|
28
|
+
unless doc.nil?
|
29
|
+
REXML::XPath.each(doc,"./link") do|link|
|
30
|
+
@link||={}
|
31
|
+
@link[link.attributes['rel']]=link.attributes['href']
|
32
|
+
end
|
33
|
+
name=REXML::XPath.first(doc,"./name")
|
34
|
+
@name=name.text if name
|
35
|
+
uri=REXML::XPath.first(doc,"./uri")
|
36
|
+
@uri=uri.text if uri
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,1150 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'oauth'
|
3
|
+
require 'oauth'
|
4
|
+
require 'oauth/consumer'
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
require 'douban/author'
|
9
|
+
require 'douban/collection'
|
10
|
+
require 'douban/event'
|
11
|
+
require 'douban/mail'
|
12
|
+
require 'douban/miniblog'
|
13
|
+
require 'douban/note'
|
14
|
+
require 'douban/people'
|
15
|
+
require 'douban/recommendation'
|
16
|
+
require 'douban/recommendation_comment'
|
17
|
+
require 'douban/review'
|
18
|
+
require 'douban/subject'
|
19
|
+
require 'douban/tag'
|
20
|
+
|
21
|
+
module Douban
|
22
|
+
class Authorize
|
23
|
+
attr_reader :api_key
|
24
|
+
attr_reader :api_secret
|
25
|
+
attr_reader :authorize_url
|
26
|
+
attr_reader :consumer
|
27
|
+
attr_reader :request_token
|
28
|
+
attr_reader :access_token
|
29
|
+
|
30
|
+
@@debug = false
|
31
|
+
|
32
|
+
@@default_oauth_request_options = {
|
33
|
+
:signature_method=>"HMAC-SHA1",
|
34
|
+
:site=>"http://www.douban.com",
|
35
|
+
:request_token_path=>"/service/auth/request_token",
|
36
|
+
:access_token_path=>"/service/auth/access_token",
|
37
|
+
:authorize_path=>"/service/auth/authorize",
|
38
|
+
:scheme=>:header,
|
39
|
+
:realm=>"http://www.example.com/"
|
40
|
+
}
|
41
|
+
|
42
|
+
@@default_oauth_access_options = {
|
43
|
+
:site=>"http://api.douban.com",
|
44
|
+
:scheme=>:header,
|
45
|
+
:signature_method=>"HMAC-SHA1",
|
46
|
+
:realm=>"http://www.example.com/"
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
def self.debug=(val)
|
51
|
+
@@debug = val
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(api_key, secret_key, options={})
|
55
|
+
@api_key=api_key
|
56
|
+
@secret_key=secret_key
|
57
|
+
@oauth_request_option = @@default_oauth_request_options.merge(options)
|
58
|
+
@oauth_access_option = @@default_oauth_access_options.merge(options)
|
59
|
+
yield self if block_given?
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def authorized?
|
64
|
+
! @access_token.nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_authorize_url(oauth_callback=nil)
|
68
|
+
oauth_callback ||= @oauth_request_option[:realm]
|
69
|
+
|
70
|
+
@consumer=new_request_consumer
|
71
|
+
@request_token=@consumer.get_request_token
|
72
|
+
@authorize_url="#{@request_token.authorize_url}&oauth_callback=#{CGI.escape(oauth_callback)}"
|
73
|
+
yield @request_token if block_given?
|
74
|
+
@authorize_url
|
75
|
+
end
|
76
|
+
|
77
|
+
def auth
|
78
|
+
begin
|
79
|
+
@access_token=@request_token.get_access_token
|
80
|
+
@access_token=OAuth::AccessToken.new(new_access_consumer,
|
81
|
+
@access_token.token,
|
82
|
+
@access_token.secret
|
83
|
+
)
|
84
|
+
rescue
|
85
|
+
#raise $!
|
86
|
+
ensure
|
87
|
+
yield self if block_given?
|
88
|
+
return self
|
89
|
+
end
|
90
|
+
end
|
91
|
+
def get_people(uid="@me")
|
92
|
+
resp=get("/people/#{u uid}")
|
93
|
+
if resp.code=="200"
|
94
|
+
atom=resp.body
|
95
|
+
People.new(atom)
|
96
|
+
else
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_friends(uid="@me",option={:start_index=>1,:max_results=>10})
|
102
|
+
resp=get("/people/#{u uid.to_s}/friends?start-index=#{u option[:start_index]}&max-results=#{u option[:max_results]}")
|
103
|
+
if resp.code=="200"
|
104
|
+
friends=[]
|
105
|
+
atom=resp.body
|
106
|
+
doc=REXML::Document.new(atom)
|
107
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
108
|
+
friends << People.new(entry)
|
109
|
+
end
|
110
|
+
friends
|
111
|
+
else
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_contacts(uid="@me",option={:start_index=>1,:max_results=>10})
|
117
|
+
resp=get("/people/#{u uid.to_s}/contacts?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
118
|
+
if resp.code=="200"
|
119
|
+
contacts=[]
|
120
|
+
atom=resp.body
|
121
|
+
doc=REXML::Document.new(atom)
|
122
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
123
|
+
contacts << People.new(entry)
|
124
|
+
end
|
125
|
+
contacts
|
126
|
+
else
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def search_people(q="",option={:start_index=>1,:max_results=>10})
|
133
|
+
resp=get("/people?q=#{u(q.to_s)}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
134
|
+
if resp.code=="200"
|
135
|
+
results=[]
|
136
|
+
atom=resp.body
|
137
|
+
doc=REXML::Document.new(atom)
|
138
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
139
|
+
results << People.new(entry)
|
140
|
+
end
|
141
|
+
results
|
142
|
+
else
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
def get_book(id="")
|
147
|
+
if id.to_s.size >=10
|
148
|
+
resp=get("/book/subject/isbn/#{u(id.to_s)}")
|
149
|
+
else
|
150
|
+
resp=get("/book/subject/#{u(id.to_s)}")
|
151
|
+
end
|
152
|
+
if resp.code=="200"
|
153
|
+
atom=resp.body
|
154
|
+
Book.new(atom)
|
155
|
+
else
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
def get_movie(id="")
|
160
|
+
if id.to_s=~/^tt\d+/
|
161
|
+
resp=get("/movie/subject/imdb/#{u(id.to_s)}")
|
162
|
+
else
|
163
|
+
resp=get("/movie/subject/#{u(id.to_s)}")
|
164
|
+
end
|
165
|
+
if resp.code=="200"
|
166
|
+
atom=resp.body
|
167
|
+
Movie.new(atom)
|
168
|
+
else
|
169
|
+
nil
|
170
|
+
end
|
171
|
+
end
|
172
|
+
def get_music(id=nil)
|
173
|
+
resp=get("/music/subject/#{u(id.to_s)}")
|
174
|
+
if resp.code=="200"
|
175
|
+
atom=resp.body
|
176
|
+
Music.new(atom)
|
177
|
+
else
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
end
|
181
|
+
def search_book(tag="",option={:start_index=>1,:max_results=>10})
|
182
|
+
resp=get("/book/subjects?tag=#{u(tag.to_s)}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
183
|
+
if resp.code=="200"
|
184
|
+
atom=resp.body
|
185
|
+
doc=REXML::Document.new(atom)
|
186
|
+
books=[]
|
187
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
188
|
+
books << Book.new(entry)
|
189
|
+
end
|
190
|
+
books
|
191
|
+
else
|
192
|
+
nil
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
def search_movie(tag="",option={:start_index=>1,:max_results=>10})
|
197
|
+
resp=get("/movie/subjects?tag=#{u(tag.to_s)}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
198
|
+
if resp.code=="200"
|
199
|
+
atom=resp.body
|
200
|
+
doc=REXML::Document.new(atom)
|
201
|
+
movies=[]
|
202
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
203
|
+
movies << Movie.new(entry)
|
204
|
+
end
|
205
|
+
movies
|
206
|
+
else
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
end
|
210
|
+
def search_music(tag="",option={:start_index=>1,:max_results=>10})
|
211
|
+
resp=get("/music/subjects?tag=#{u(tag)}&start-index=#{option['start-index']}&max-results=#{option['max-results']}")
|
212
|
+
if resp.code=="200"
|
213
|
+
atom=resp.body
|
214
|
+
doc=REXML::Document.new(atom)
|
215
|
+
music=[]
|
216
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
217
|
+
music << Music.new(entry)
|
218
|
+
end
|
219
|
+
music
|
220
|
+
else
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
end
|
224
|
+
def get_review(id="")
|
225
|
+
resp=get("/review/#{u(id.to_s)}")
|
226
|
+
if resp.code=="200"
|
227
|
+
atom=resp.body
|
228
|
+
Review.new(atom)
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
def get_user_reviews(user_id="@me",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
234
|
+
resp=get("/people/#{u(user_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
235
|
+
if resp.code=="200"
|
236
|
+
atom=resp.body
|
237
|
+
reviews=[]
|
238
|
+
doc=REXML::Document.new(atom)
|
239
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
240
|
+
reviews<< Review.new(entry)
|
241
|
+
end
|
242
|
+
reviews
|
243
|
+
else
|
244
|
+
debug(resp)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
def get_movie_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
248
|
+
resp=get("/movie/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
249
|
+
if resp.code=="200"
|
250
|
+
atom=resp.body
|
251
|
+
reviews=[]
|
252
|
+
doc=REXML::Document.new(atom)
|
253
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
254
|
+
|
255
|
+
reviews<< Review.new(entry)
|
256
|
+
end
|
257
|
+
reviews
|
258
|
+
else
|
259
|
+
nil
|
260
|
+
end
|
261
|
+
end
|
262
|
+
def get_music_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
263
|
+
resp=get("/music/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
264
|
+
if resp.code=="200"
|
265
|
+
atom=resp.body
|
266
|
+
reviews=[]
|
267
|
+
doc=REXML::Document.new(atom)
|
268
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
269
|
+
reviews<< Review.new(entry)
|
270
|
+
end
|
271
|
+
reviews
|
272
|
+
else
|
273
|
+
nil
|
274
|
+
end
|
275
|
+
end
|
276
|
+
def get_book_reviews(subject_id="",option={:start_index=>1,:max_results=>10,:orderby=>'score'})
|
277
|
+
resp=get("/book/subject/#{u(subject_id.to_s)}/reviews?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}&orderby=#{option[:orderby]}")
|
278
|
+
if resp.code=="200"
|
279
|
+
atom=resp.body
|
280
|
+
reviews=[]
|
281
|
+
doc=REXML::Document.new(atom)
|
282
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
283
|
+
reviews<< Review.new(entry)
|
284
|
+
end
|
285
|
+
reviews
|
286
|
+
else
|
287
|
+
nil
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def delete_review(review)
|
292
|
+
review_id = case review
|
293
|
+
when Review then review.review_id
|
294
|
+
else review
|
295
|
+
end
|
296
|
+
|
297
|
+
resp=delete("/review/#{u(review_id.to_s)}")
|
298
|
+
if resp.code=="200"
|
299
|
+
true
|
300
|
+
else
|
301
|
+
false
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def create_review(subject_link="",title="",content="",rating=5)
|
306
|
+
subject_link = subject_link.id if subject_link.kind_of?(Subject)
|
307
|
+
|
308
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
309
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom">
|
310
|
+
<db:subject xmlns:db="http://www.douban.com/xmlns/">
|
311
|
+
<id>#{h subject_link}</id>
|
312
|
+
</db:subject>
|
313
|
+
<content>#{h content}</content>
|
314
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" ></gd:rating>
|
315
|
+
<title>#{h title}</title>
|
316
|
+
</entry>
|
317
|
+
}
|
318
|
+
resp=post("/reviews",entry,{"Content-Type" => "application/atom+xml"})
|
319
|
+
if resp.code=="201"
|
320
|
+
Review.new(resp.body)
|
321
|
+
else
|
322
|
+
debug(resp)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def modify_review(review, subject_link=nil,title="",content="",rating=5)
|
327
|
+
review_id = case review
|
328
|
+
when Review then review.review_id
|
329
|
+
else review
|
330
|
+
end
|
331
|
+
|
332
|
+
subject_link = review.subject.id if subject_link.nil? and review.kind_of?(Review)
|
333
|
+
|
334
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
335
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom">
|
336
|
+
<id>http://api.douban.com/review/#{h review_id}</id>
|
337
|
+
<db:subject xmlns:db="http://www.douban.com/xmlns/">
|
338
|
+
<id>#{h subject_link}</id>
|
339
|
+
</db:subject>
|
340
|
+
<content>#{h content}</content>
|
341
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" ></gd:rating>
|
342
|
+
<title>#{h title}</title>
|
343
|
+
</entry>
|
344
|
+
}
|
345
|
+
resp=put("/review/#{u(review_id)}",entry,{"Content-Type" => "application/atom+xml"})
|
346
|
+
if resp.code=="202"
|
347
|
+
Review.new(resp.body)
|
348
|
+
else
|
349
|
+
debug(resp)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
def get_collection(collection_id="")
|
353
|
+
resp=get("/collection/#{u(collection_id.to_s)}")
|
354
|
+
if resp.code=="200"
|
355
|
+
atom=resp.body
|
356
|
+
Collection.new(atom)
|
357
|
+
else
|
358
|
+
nil
|
359
|
+
end
|
360
|
+
end
|
361
|
+
def get_user_collection(
|
362
|
+
user_id="@me",
|
363
|
+
option={
|
364
|
+
:cat=>'',
|
365
|
+
:tag=>'',
|
366
|
+
:status=>'',
|
367
|
+
:start_index=>1,
|
368
|
+
:max_results=>10,
|
369
|
+
:updated_max=>'',
|
370
|
+
:updated_min=>''
|
371
|
+
}
|
372
|
+
)
|
373
|
+
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]}")
|
374
|
+
if resp.code=="200"
|
375
|
+
atom=resp.body
|
376
|
+
doc=REXML::Document.new(atom)
|
377
|
+
author=REXML::XPath.first(doc,"//feed/author")
|
378
|
+
author=Author.new(author.to_s) if author
|
379
|
+
title=REXML::XPath.first(doc,"//feed/title")
|
380
|
+
title=title.text if title
|
381
|
+
collections=[]
|
382
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
383
|
+
collection=Collection.new(entry)
|
384
|
+
collection.author=author
|
385
|
+
collection.title=title
|
386
|
+
collections<< collection
|
387
|
+
end
|
388
|
+
collections
|
389
|
+
else
|
390
|
+
nil
|
391
|
+
end
|
392
|
+
end
|
393
|
+
def create_collection( subject_id="",content="",rating=5,status="",tag=[],option={ :privacy=>"public"})
|
394
|
+
db_tag=""
|
395
|
+
if tag.size==0
|
396
|
+
db_tag='<db:tag name="" />'
|
397
|
+
else
|
398
|
+
tag.each do |t|
|
399
|
+
db_tag+=%Q{<db:tag name="#{h t}" />}
|
400
|
+
end
|
401
|
+
end
|
402
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
403
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
404
|
+
<db:status>#{h status}</db:status>
|
405
|
+
#{db_tag}
|
406
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" />
|
407
|
+
<content>#{h content}</content>
|
408
|
+
<db:subject>
|
409
|
+
<id>#{h subject_id}</id>
|
410
|
+
</db:subject>
|
411
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
412
|
+
</entry>
|
413
|
+
}
|
414
|
+
resp=post("/collection",entry,{"Content-Type"=>"application/atom+xml"})
|
415
|
+
if resp.code=="201"
|
416
|
+
Collection.new(resp.body)
|
417
|
+
else
|
418
|
+
debug(resp)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def modify_collection(collection, subject_id="",content="",rating=5,status="",tag=[],option={:privacy=>"public"})
|
423
|
+
collection_id = case collection
|
424
|
+
when Collection then collection.collection_id
|
425
|
+
else collection
|
426
|
+
end
|
427
|
+
|
428
|
+
subject_id = collection.subject.id if subject_id.nil? and collection.kind_of?(Collection)
|
429
|
+
|
430
|
+
db_tag=""
|
431
|
+
if tag.size==0
|
432
|
+
db_tag='<db:tag name="" />'
|
433
|
+
else
|
434
|
+
tag.each do |t|
|
435
|
+
db_tag+=%Q{<db:tag name="#{h t}" />}
|
436
|
+
end
|
437
|
+
end
|
438
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
439
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
440
|
+
<id>http://api.douban.com/collection/#{h collection_id}</id>
|
441
|
+
<db:status>#{h status}</db:status>
|
442
|
+
|
443
|
+
#{db_tag}
|
444
|
+
<gd:rating xmlns:gd="http://schemas.google.com/g/2005" value="#{h rating}" />
|
445
|
+
<content>#{h content}</content>
|
446
|
+
<db:subject>
|
447
|
+
<id>#{h subject_id}</id>
|
448
|
+
</db:subject>
|
449
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
450
|
+
</entry>
|
451
|
+
}
|
452
|
+
resp=put("/collection/#{u collection_id}",entry,{"Content-Type"=>"application/atom+xml"})
|
453
|
+
# resp.code should be 202, but currently it's 200
|
454
|
+
# http://www.douban.com/group/topic/12451628/
|
455
|
+
if resp.code=="200" or resp.code == "202"
|
456
|
+
Collection.new(resp.body)
|
457
|
+
else
|
458
|
+
debug(resp)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
def delete_collection(collection)
|
462
|
+
collection_id = case collection
|
463
|
+
when Collection then collection.collection_id
|
464
|
+
else collection
|
465
|
+
end
|
466
|
+
|
467
|
+
resp=delete("/collection/#{u(collection_id.to_s)}")
|
468
|
+
if resp.code=="200"
|
469
|
+
true
|
470
|
+
else
|
471
|
+
false
|
472
|
+
end
|
473
|
+
end
|
474
|
+
def get_user_miniblog(user_id="@me",option={:start_index=>1,:max_results=>10})
|
475
|
+
resp=get("/people/#{u(user_id.to_s)}/miniblog?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
476
|
+
if resp.code=="200"
|
477
|
+
atom=resp.body
|
478
|
+
doc=REXML::Document.new(atom)
|
479
|
+
author=REXML::XPath.first(doc,"//feed/author")
|
480
|
+
author=Author.new(author.to_s) if author
|
481
|
+
miniblogs=[]
|
482
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
483
|
+
miniblog=Miniblog.new(entry)
|
484
|
+
miniblog.author=author
|
485
|
+
miniblogs<< miniblog
|
486
|
+
end
|
487
|
+
miniblogs
|
488
|
+
else
|
489
|
+
nil
|
490
|
+
end
|
491
|
+
end
|
492
|
+
def get_user_contact_miniblog(user_id="@me",option={:start_index=>1,:max_results=>10})
|
493
|
+
resp=get("/people/#{u(user_id.to_s)}/miniblog/contacts?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
494
|
+
if resp.code=="200"
|
495
|
+
atom=resp.body
|
496
|
+
doc=REXML::Document.new(atom)
|
497
|
+
miniblogs=[]
|
498
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
499
|
+
miniblog=Miniblog.new(entry)
|
500
|
+
miniblogs<< miniblog
|
501
|
+
end
|
502
|
+
miniblogs
|
503
|
+
else
|
504
|
+
nil
|
505
|
+
end
|
506
|
+
end
|
507
|
+
def create_miniblog(content="")
|
508
|
+
entry=%Q{<?xml version='1.0' encoding='UTF-8'?>
|
509
|
+
<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
510
|
+
<content>#{h content}</content>
|
511
|
+
</entry>}
|
512
|
+
resp=post("/miniblog/saying",entry,{"Content-Type"=>"application/atom+xml"})
|
513
|
+
if resp.code=="201"
|
514
|
+
Miniblog.new(resp.body)
|
515
|
+
else
|
516
|
+
nil
|
517
|
+
end
|
518
|
+
end
|
519
|
+
def delete_miniblog(miniblog_id="")
|
520
|
+
resp=delete("/miniblog/#{u(miniblog_id.to_s)}")
|
521
|
+
if resp.code=="200"
|
522
|
+
true
|
523
|
+
else
|
524
|
+
false
|
525
|
+
end
|
526
|
+
end
|
527
|
+
def get_note(note_id="")
|
528
|
+
resp=get("/note/#{u(note_id.to_s)}")
|
529
|
+
if resp.code=="200"
|
530
|
+
atom=resp.body
|
531
|
+
Note.new(atom)
|
532
|
+
else
|
533
|
+
nil
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def get_user_notes(user_id="@me",option={:start_index=>1,:max_results=>10})
|
538
|
+
resp=get("/people/#{u(user_id.to_s)}/notes?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
539
|
+
if resp.code=="200"
|
540
|
+
atom=resp.body
|
541
|
+
doc=REXML::Document.new(atom)
|
542
|
+
author=REXML::XPath.first(doc,"//feed/author")
|
543
|
+
author=Author.new(author.to_s) if author
|
544
|
+
notes=[]
|
545
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
546
|
+
note=Note.new(entry)
|
547
|
+
note.author=author
|
548
|
+
notes << note
|
549
|
+
end
|
550
|
+
notes
|
551
|
+
else
|
552
|
+
nil
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
def create_note(title="",content="",option={:privacy=>"public",:can_reply=>"yes"})
|
557
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
558
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
559
|
+
<title>#{h title}</title>
|
560
|
+
<content>#{h content}</content>
|
561
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
562
|
+
<db:attribute name="can_reply">#{h option[:can_reply]}</db:attribute>
|
563
|
+
</entry>
|
564
|
+
}
|
565
|
+
resp=post("/notes",entry,{"Content-Type"=>"application/atom+xml"})
|
566
|
+
if resp.code=="201"
|
567
|
+
Note.new(resp.body)
|
568
|
+
else
|
569
|
+
debug(resp)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
def delete_note(note_id="")
|
574
|
+
note_id = note_id.note_id if note_id.kind_of?(Note)
|
575
|
+
|
576
|
+
resp=delete("/note/#{u(note_id.to_s)}")
|
577
|
+
if resp.code=="200"
|
578
|
+
true
|
579
|
+
else
|
580
|
+
false
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
def modify_note(note,title="",content="",option={:privacy=>"public",:can_reply=>"yes"})
|
585
|
+
note_id = case note
|
586
|
+
when Note then note.note_id
|
587
|
+
else note
|
588
|
+
end
|
589
|
+
|
590
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
591
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
|
592
|
+
<title>#{h title}</title>
|
593
|
+
<content>#{h content}</content>
|
594
|
+
<db:attribute name="privacy">#{h option[:privacy]}</db:attribute>
|
595
|
+
<db:attribute name="can_reply">#{h option[:can_reply]}</db:attribute>
|
596
|
+
</entry>
|
597
|
+
}
|
598
|
+
resp=put("/note/#{u(note_id.to_s)}",entry,{"Content-Type"=>"application/atom+xml"})
|
599
|
+
if resp.code=="202"
|
600
|
+
Note.new(resp.body)
|
601
|
+
else
|
602
|
+
debug(resp)
|
603
|
+
end
|
604
|
+
end
|
605
|
+
def get_event(event_id="")
|
606
|
+
resp=get("/event/#{u(event_id.to_s)}")
|
607
|
+
if resp.code=="200"
|
608
|
+
atom=resp.body
|
609
|
+
Event.new(atom)
|
610
|
+
else
|
611
|
+
nil
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
# <b>DEPRECATED:</b> Please use <tt>get_event_participant_people</tt> instead.
|
616
|
+
def get_participant_people(*args)
|
617
|
+
warn "[DEPRECATION] `get_participant_people` is deprecated. Please use `get_event_participant_people` instead."
|
618
|
+
get_event_participant_people(*args)
|
619
|
+
end
|
620
|
+
|
621
|
+
def get_event_participant_people(event_id=nil,option={:start_index=>1,:max_results=>10})
|
622
|
+
resp=get("/event/#{u(event_id.to_s)}/participants?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
623
|
+
if resp.code=="200"
|
624
|
+
people=[]
|
625
|
+
atom=resp.body
|
626
|
+
doc=REXML::Document.new(atom)
|
627
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
628
|
+
people<< People.new(entry)
|
629
|
+
end
|
630
|
+
people
|
631
|
+
else
|
632
|
+
nil
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
# <b>DEPRECATED:</b> Please use <tt>get_event_wisher_people</tt> instead.
|
637
|
+
def get_wisher_people(*args)
|
638
|
+
warn "[DEPRECATION] `get_wisher_people` is deprecated. Please use `get_event_wisher_people` instead."
|
639
|
+
get_event_wisher_people(*args)
|
640
|
+
end
|
641
|
+
|
642
|
+
def get_event_wisher_people(event_id=nil,option={:start_index=>1,:max_results=>10})
|
643
|
+
resp=get("/event/#{u(event_id.to_s)}/wishers?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
644
|
+
if resp.code=="200"
|
645
|
+
people=[]
|
646
|
+
atom=resp.body
|
647
|
+
doc=REXML::Document.new(atom)
|
648
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
649
|
+
people<< People.new(entry)
|
650
|
+
end
|
651
|
+
people
|
652
|
+
else
|
653
|
+
nil
|
654
|
+
end
|
655
|
+
end
|
656
|
+
def get_user_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
657
|
+
resp=get("/people/#{u(user_id.to_s)}/events?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
658
|
+
if resp.code=="200"
|
659
|
+
events=[]
|
660
|
+
atom=resp.body
|
661
|
+
doc=REXML::Document.new(atom)
|
662
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
663
|
+
events<< Event.new(entry)
|
664
|
+
end
|
665
|
+
events
|
666
|
+
else
|
667
|
+
nil
|
668
|
+
end
|
669
|
+
end
|
670
|
+
def get_user_initiate_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
671
|
+
resp=get("/people/#{u(user_id.to_s)}/events/initiate?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
672
|
+
if resp.code=="200"
|
673
|
+
events=[]
|
674
|
+
atom=resp.body
|
675
|
+
doc=REXML::Document.new(atom)
|
676
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
677
|
+
events<< Event.new(entry)
|
678
|
+
end
|
679
|
+
events
|
680
|
+
else
|
681
|
+
nil
|
682
|
+
end
|
683
|
+
end
|
684
|
+
def get_user_participate_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
685
|
+
resp=get("/people/#{u(user_id.to_s)}/events/participate?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
686
|
+
if resp.code=="200"
|
687
|
+
events=[]
|
688
|
+
atom=resp.body
|
689
|
+
doc=REXML::Document.new(atom)
|
690
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
691
|
+
events<< Event.new(entry)
|
692
|
+
end
|
693
|
+
events
|
694
|
+
else
|
695
|
+
nil
|
696
|
+
end
|
697
|
+
end
|
698
|
+
def get_user_wish_events(user_id="@me",option={:start_index=>1,:max_results=>10})
|
699
|
+
resp=get("/people/#{u(user_id.to_s)}/events/wish?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
700
|
+
if resp.code=="200"
|
701
|
+
events=[]
|
702
|
+
atom=resp.body
|
703
|
+
doc=REXML::Document.new(atom)
|
704
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
705
|
+
events<< Event.new(entry)
|
706
|
+
end
|
707
|
+
events
|
708
|
+
else
|
709
|
+
nil
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
def get_city_events(location_id=nil,option={:type=>"all",:start_index=>1,:max_results=>10})
|
714
|
+
resp=get("/event/location/#{u(location_id.to_s)}?type=#{option[:type]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
715
|
+
if resp.code=="200"
|
716
|
+
events=[]
|
717
|
+
atom=resp.body
|
718
|
+
doc=REXML::Document.new(atom)
|
719
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
720
|
+
events<< Event.new(entry)
|
721
|
+
end
|
722
|
+
events
|
723
|
+
else
|
724
|
+
nil
|
725
|
+
end
|
726
|
+
end
|
727
|
+
def search_events(q="",option={:location=>"all",:start_index=>1,:max_results=>10})
|
728
|
+
resp=get("/events?q=#{u(q.to_s)}&location=#{option[:location]}&start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
729
|
+
if resp.code=="200"
|
730
|
+
events=[]
|
731
|
+
atom=resp.body
|
732
|
+
doc=REXML::Document.new(atom)
|
733
|
+
REXML::XPath.each(doc,"//feed/entry") do |entry|
|
734
|
+
events<< Event.new(entry)
|
735
|
+
end
|
736
|
+
events
|
737
|
+
else
|
738
|
+
nil
|
739
|
+
end
|
740
|
+
end
|
741
|
+
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")}})
|
742
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
743
|
+
<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/">
|
744
|
+
<title>#{h title}</title>
|
745
|
+
<category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#event.#{option[:kind]}"/>
|
746
|
+
<content>#{h content}</content>
|
747
|
+
<db:attribute name="invite_only">#{h option[:invite_only]}</db:attribute>
|
748
|
+
<db:attribute name="can_invite">#{h option[:can_invite]}</db:attribute>
|
749
|
+
<gd:when endTime="#{h option[:when]["endTime"]}" startTime="#{h option[:when]["startTime"]}"/>
|
750
|
+
<gd:where valueString="#{h where}" />
|
751
|
+
</entry>
|
752
|
+
}
|
753
|
+
resp=post("/events",entry,{"Content-Type"=>"application/atom+xml"})
|
754
|
+
if resp.code=="201"
|
755
|
+
Event.new(resp.body)
|
756
|
+
else
|
757
|
+
debug(resp)
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
def modify_event(event,title=nil,content=nil,where=nil,option=nil)
|
762
|
+
|
763
|
+
event_id = case event
|
764
|
+
when Event then event.event_id
|
765
|
+
else event
|
766
|
+
end
|
767
|
+
|
768
|
+
option = {} if option.nil?
|
769
|
+
option = {:kind=>"exhibit",
|
770
|
+
:invite_only=>"no",
|
771
|
+
:can_invite=>"yes",
|
772
|
+
:when=>{"endTime"=>(Time.now+60*60*24*5).strftime("%Y-%m-%dT%H:%M:%S+08:00"),
|
773
|
+
"startTime"=>Time.now.strftime("%Y-%m-%dT%H:%M:%S+08:00")}}.merge(option)
|
774
|
+
|
775
|
+
entry=%Q{<?xml version="1.0" encoding="UTF-8"?>
|
776
|
+
<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/">
|
777
|
+
<title>#{h title}</title>
|
778
|
+
<category scheme="http://www.douban.com/2007#kind" term="http://www.douban.com/2007#event.#{option[:kind]}"/>
|
779
|
+
<content>#{h content}</content>
|
780
|
+
<db:attribute name="invite_only">#{h option[:invite_only]}</db:attribute>
|
781
|
+
<db:attribute name="can_invite">#{h option[:can_invite]}</db:attribute>
|
782
|
+
<gd:when endTime="#{h option[:when]["endTime"]}" startTime="#{h option[:when]["startTime"]}"/>
|
783
|
+
<gd:where valueString="#{h where}" />
|
784
|
+
</entry>
|
785
|
+
}
|
786
|
+
resp=put("/event/#{u(event_id)}",entry,{"Content-Type"=>"application/atom+xml"})
|
787
|
+
if resp.code=="200"
|
788
|
+
Event.new(resp.body)
|
789
|
+
else
|
790
|
+
debug(resp)
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
794
|
+
def get_mail_inbox(option={:start_index=>1,:max_results=>10})
|
795
|
+
resp=get("/doumail/inbox?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
796
|
+
if resp.code=="200"
|
797
|
+
mails=[]
|
798
|
+
atom=resp.body
|
799
|
+
doc=REXML::Document.new(atom)
|
800
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
801
|
+
mails << Mail.new(entry)
|
802
|
+
end
|
803
|
+
mails
|
804
|
+
else
|
805
|
+
nil
|
806
|
+
end
|
807
|
+
end
|
808
|
+
def get_unread_mail(option={:start_index=>1,:max_results=>10})
|
809
|
+
resp=get("/doumail/inbox/unread?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
810
|
+
if resp.code=="200"
|
811
|
+
mails=[]
|
812
|
+
atom=resp.body
|
813
|
+
doc=REXML::Document.new(atom)
|
814
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
815
|
+
mails << Mail.new(entry)
|
816
|
+
end
|
817
|
+
mails
|
818
|
+
else
|
819
|
+
nil
|
820
|
+
end
|
821
|
+
end
|
822
|
+
def get_mail_outbox(option={:start_index=>1,:max_results=>10})
|
823
|
+
resp=get("/doumail/outbox?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
824
|
+
if resp.code=="200"
|
825
|
+
mails=[]
|
826
|
+
atom=resp.body
|
827
|
+
doc=REXML::Document.new(atom)
|
828
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
829
|
+
mails << Mail.new(entry)
|
830
|
+
end
|
831
|
+
mails
|
832
|
+
else
|
833
|
+
nil
|
834
|
+
end
|
835
|
+
end
|
836
|
+
def get_mail(mail_id="",keep_unread="false")
|
837
|
+
resp=get("/doumail/#{u(mail_id.to_s)}?keep-unread=#{keep_unread}")
|
838
|
+
if resp.code=="200"
|
839
|
+
atom=resp.body
|
840
|
+
Mail.new(atom)
|
841
|
+
else
|
842
|
+
nil
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
# <b>DEPRECATED:</b> Please use <tt>send_mail</tt> instead.
|
847
|
+
def create_mail(*args)
|
848
|
+
warn "[DEPRECATION] `create_mail` is deprecated. Please use `send_mail` instead."
|
849
|
+
send_mail(*args)
|
850
|
+
end
|
851
|
+
|
852
|
+
def send_mail(id="",title="",content="",captcha_token="",captcha_string="")
|
853
|
+
if !(captcha_token.empty?&&captcha_string.empty?)
|
854
|
+
entry=%Q(<?xml version="1.0" encoding="UTF-8"?>
|
855
|
+
<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/">
|
856
|
+
<db:entity name="receiver"><uri>http://api.douban.com/people/#{h id}</uri></db:entity>
|
857
|
+
<content>#{h content}</content>
|
858
|
+
<title>#{h title}</title>
|
859
|
+
<db:attribute name="captcha_token">#{h captcha_token}</db:attribute>
|
860
|
+
<db:attribute name="captcha_string">#{h captcha_string}</db:attribute>
|
861
|
+
</entry>)
|
862
|
+
else
|
863
|
+
entry=%Q(<?xml version="1.0" encoding="UTF-8"?>
|
864
|
+
<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/">
|
865
|
+
<db:entity name="receiver">
|
866
|
+
<uri>http://api.douban.com/people/#{h id}</uri></db:entity>
|
867
|
+
<content>#{h content}</content>
|
868
|
+
<title>#{h title}</title>
|
869
|
+
</entry>)
|
870
|
+
end
|
871
|
+
resp=post("/doumails",entry,{"Content-Type"=>"application/atom+xml"})
|
872
|
+
if resp.code=="201"
|
873
|
+
true
|
874
|
+
elsif resp.code=="403"
|
875
|
+
hash={}
|
876
|
+
str=CGI.unescapeHTML(resp.body)
|
877
|
+
hash[:token]=str.scan(/^captcha_token=(.*?)&/).flatten.to_s
|
878
|
+
hash[:url]=str.scan(/captcha_url=(.*?)$/).flatten.to_s
|
879
|
+
hash
|
880
|
+
else
|
881
|
+
debug(resp)
|
882
|
+
end
|
883
|
+
end
|
884
|
+
def read_mail(mail_id="")
|
885
|
+
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>}
|
886
|
+
resp=put("/doumail/#{mail_id.to_s}",entry,{"Content-Type" => "application/atom+xml"})
|
887
|
+
if resp.code=="202"
|
888
|
+
true
|
889
|
+
else
|
890
|
+
false
|
891
|
+
end
|
892
|
+
end
|
893
|
+
def delete_mail(mail_id="")
|
894
|
+
resp=delete("/doumail/#{mail_id.to_s}")
|
895
|
+
if resp.code=="200"
|
896
|
+
true
|
897
|
+
else
|
898
|
+
false
|
899
|
+
end
|
900
|
+
end
|
901
|
+
def read_mails(mail_ids=[])
|
902
|
+
entrys=""
|
903
|
+
mail_ids.each do |mail_id|
|
904
|
+
entrys +=%Q{<entry><id>http://api.douban.com/doumail/#{mail_id}</id><db:attribute name="unread">false</db:attribute></entry>}
|
905
|
+
end
|
906
|
+
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>}
|
907
|
+
resp=put("/doumail/",feed,{"Content-Type" => "application/atom+xml"})
|
908
|
+
if resp.code=="202"
|
909
|
+
true
|
910
|
+
else
|
911
|
+
false
|
912
|
+
end
|
913
|
+
end
|
914
|
+
def delete_mails(mail_ids=[])
|
915
|
+
entrys=""
|
916
|
+
mail_ids.each do |mail_id|
|
917
|
+
entrys += %Q{<entry><id>http://api.douban.com/doumail/#{mail_id}</id></entry>}
|
918
|
+
end
|
919
|
+
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>}
|
920
|
+
resp=post("/doumail/delete",feed,{"Content-Type" => "application/atom+xml"})
|
921
|
+
if resp.code=="202"
|
922
|
+
true
|
923
|
+
else
|
924
|
+
false
|
925
|
+
end
|
926
|
+
end
|
927
|
+
|
928
|
+
def get_book_tags(subject_id="",flag=:book)
|
929
|
+
case flag
|
930
|
+
when :book
|
931
|
+
resp=get("/book/subject/#{subject_id}/tags")
|
932
|
+
when :music
|
933
|
+
resp=get("/music/subject/#{subject_id}/tags")
|
934
|
+
when :movie
|
935
|
+
resp=get("/movie/subject/#{subject_id}/tags")
|
936
|
+
end
|
937
|
+
if resp.code=="200"
|
938
|
+
tags=[]
|
939
|
+
atom=resp.body
|
940
|
+
doc=REXML::Document.new(atom)
|
941
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
942
|
+
tags << Tag.new(entry)
|
943
|
+
end
|
944
|
+
tags
|
945
|
+
else
|
946
|
+
nil
|
947
|
+
end
|
948
|
+
end
|
949
|
+
def get_user_tags(user_id="@me",flag=:book,option={:max_results=>10})
|
950
|
+
case flag
|
951
|
+
when :book
|
952
|
+
resp=get("/people/#{u user_id}/tags?cat=book&max-results=#{option[:max_results]}")
|
953
|
+
when :music
|
954
|
+
resp=get("/people/#{u user_id}/tags?cat=music&max-results=#{option[:max_results]}")
|
955
|
+
when :movie
|
956
|
+
resp=get("/people/#{u user_id}/tags?cat=movie&max-results=#{option[:max_results]}")
|
957
|
+
end
|
958
|
+
if resp.code=="200"
|
959
|
+
tags=[]
|
960
|
+
atom=resp.body
|
961
|
+
doc=REXML::Document.new(atom)
|
962
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
963
|
+
tags << Tag.new(entry)
|
964
|
+
end
|
965
|
+
tags
|
966
|
+
else
|
967
|
+
debug(resp)
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
def delete_event(event_id="")
|
972
|
+
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>}
|
973
|
+
resp=post("/event/#{u(event_id)}/delete",entry,{"Content-Type"=>"application/atom+xml"})
|
974
|
+
if resp.code=="200"
|
975
|
+
true
|
976
|
+
else
|
977
|
+
debug(resp, false)
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
981
|
+
def request_token=(token)
|
982
|
+
unless token.kind_of? OAuth::RequestToken
|
983
|
+
token = OAuth::RequestToken.new(
|
984
|
+
new_request_consumer,
|
985
|
+
token.token,
|
986
|
+
token.secret)
|
987
|
+
end
|
988
|
+
@request_token = token
|
989
|
+
end
|
990
|
+
|
991
|
+
def access_token=(token)
|
992
|
+
unless token.kind_of? OAuth::AccessToken
|
993
|
+
token = OAuth::AccessToken.new(
|
994
|
+
new_access_consumer,
|
995
|
+
token.token,
|
996
|
+
token.secret)
|
997
|
+
end
|
998
|
+
@access_token = token
|
999
|
+
end
|
1000
|
+
|
1001
|
+
def get_recommendation(id)
|
1002
|
+
resp=get("/recommendation/#{u(id.to_s)}")
|
1003
|
+
if resp.code=="200"
|
1004
|
+
Recommendation.new(resp.body)
|
1005
|
+
elsif resp.code == "404"
|
1006
|
+
nil
|
1007
|
+
else
|
1008
|
+
debug(resp)
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def get_user_recommendations(user_id="@me",option={:start_index=>1,:max_results=>10})
|
1013
|
+
resp=get("/people/#{u(user_id.to_s)}/recommendations?start-index=#{option[:start_index]}&max-results=#{option[:max_results]}")
|
1014
|
+
if resp.code == "200"
|
1015
|
+
recommendations = []
|
1016
|
+
doc=REXML::Document.new(resp.body)
|
1017
|
+
REXML::XPath.each(doc,"//entry") do |entry|
|
1018
|
+
recommendations << Recommendation.new(entry)
|
1019
|
+
end
|
1020
|
+
recommendations
|
1021
|
+
else
|
1022
|
+
debug(resp)
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def get_recommendation_comments(recommendation_id)
|
1027
|
+
resp = get("/recommendation/#{u(recommendation_id)}/comments")
|
1028
|
+
if resp.code == "200"
|
1029
|
+
comments = []
|
1030
|
+
doc=REXML::Document.new(resp.body)
|
1031
|
+
REXML::XPath.each(doc, "//entry") do |entry|
|
1032
|
+
comments << RecommendationComment.new(entry)
|
1033
|
+
end
|
1034
|
+
comments
|
1035
|
+
else
|
1036
|
+
debug(resp)
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
def create_recommendation(subject, title, comment)
|
1041
|
+
subject = subject.kind_of?(Douban::Subject) ? subject.id : subject
|
1042
|
+
entry = %Q{<?xml version="1.0" encoding="UTF-8"?>
|
1043
|
+
<entry xmlns="http://www.w3.org/2005/Atom"
|
1044
|
+
xmlns:gd="http://schemas.google.com/g/2005"
|
1045
|
+
xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"
|
1046
|
+
xmlns:db="http://www.douban.com/xmlns/">
|
1047
|
+
<title>#{h title}</title>
|
1048
|
+
<db:attribute name="comment">#{h comment}</db:attribute>
|
1049
|
+
<link href="#{h subject}" rel="related" />
|
1050
|
+
</entry>}
|
1051
|
+
resp = post("/recommendations", entry, {"Content-Type"=>"application/atom+xml"})
|
1052
|
+
if resp.code == '201'
|
1053
|
+
Recommendation.new(resp.body)
|
1054
|
+
else
|
1055
|
+
debug(resp)
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
def delete_recommendation(recommendation_id)
|
1060
|
+
if recommendation_id.kind_of?(Douban::Recommendation)
|
1061
|
+
recommendation_id = %r{/(\d+)$}.match(recommendation_id.id)[1]
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
resp = delete("/recommendation/#{u recommendation_id}")
|
1065
|
+
if resp.code == '200'
|
1066
|
+
true
|
1067
|
+
else
|
1068
|
+
debug(resp, false)
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
def create_recommendation_comment(recommendation, content)
|
1073
|
+
recommendation_id = recommendation.kind_of?(Douban::Recommendation) \
|
1074
|
+
? recommendation.recommendation_id : recommendation
|
1075
|
+
entry = %Q{<?xml version='1.0' encoding='UTF-8'?>
|
1076
|
+
<entry>
|
1077
|
+
<content>#{h content}</content>
|
1078
|
+
</entry>}
|
1079
|
+
resp = post("/recommendation/#{u recommendation_id}/comments", entry, {"Content-Type"=>"application/atom+xml"})
|
1080
|
+
if resp.code == '201'
|
1081
|
+
RecommendationComment.new(resp.body)
|
1082
|
+
else
|
1083
|
+
debug(resp)
|
1084
|
+
end
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
# delete_recommendation_comment(comment:RecommendationComment)
|
1088
|
+
# delete_recommendation_comment(recommendation:Recommendation, comment_id:Integer)
|
1089
|
+
# delete_recommendation_comment(recommendation_id:Integer, comment_id:Integer)
|
1090
|
+
def delete_recommendation_comment(recommendation, comment_id=nil)
|
1091
|
+
if comment_id.nil?
|
1092
|
+
recommendation_id = recommendation.recommendation_id
|
1093
|
+
comment_id = recommendation.comment_id
|
1094
|
+
else
|
1095
|
+
recommendation_id = recommendation.kind_of?(Douban::Recommendation) \
|
1096
|
+
? recommendation.recommendation_id : recommendation
|
1097
|
+
end
|
1098
|
+
resp = delete("/recommendation/#{u recommendation_id}/comment/#{u comment_id}")
|
1099
|
+
if resp.code == '200'
|
1100
|
+
true
|
1101
|
+
else
|
1102
|
+
debug(resp, false)
|
1103
|
+
end
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
protected
|
1107
|
+
def new_request_consumer
|
1108
|
+
OAuth::Consumer.new(@api_key, @secret_key, @oauth_request_option)
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
def new_access_consumer
|
1112
|
+
OAuth::Consumer.new(@api_key, @secret_key, @oauth_access_option)
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
def debug(resp, retval=nil)
|
1116
|
+
if @@debug
|
1117
|
+
p resp.code
|
1118
|
+
p resp.body
|
1119
|
+
end
|
1120
|
+
retval
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
def html_encode(o)
|
1124
|
+
CGI.escapeHTML(o.to_s)
|
1125
|
+
end
|
1126
|
+
alias_method :h, :html_encode
|
1127
|
+
|
1128
|
+
def url_encode(o)
|
1129
|
+
CGI.escape(o.to_s)
|
1130
|
+
end
|
1131
|
+
alias_method :u, :url_encode
|
1132
|
+
|
1133
|
+
def get(path,headers={})
|
1134
|
+
@access_token.get(path,headers)
|
1135
|
+
end
|
1136
|
+
def post(path,data="",headers={})
|
1137
|
+
@access_token.post(path,data,headers)
|
1138
|
+
end
|
1139
|
+
def put(path,body="",headers={})
|
1140
|
+
@access_token.put(path,body,headers)
|
1141
|
+
end
|
1142
|
+
def delete(path,headers={})
|
1143
|
+
@access_token.delete(path,headers)
|
1144
|
+
end
|
1145
|
+
def head(path,headers={})
|
1146
|
+
@access_token.head(path,headers)
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
end
|
1150
|
+
|