rdio 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rdio/base.rb ADDED
@@ -0,0 +1,314 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+
4
+ class Object
5
+ def to_k
6
+ return self
7
+ end
8
+ end
9
+
10
+ module Rdio
11
+
12
+ # string -> string
13
+ #
14
+ # Converts camel-case string to underscore-delimited one.
15
+ #
16
+ def camel2underscores(s)
17
+ return s if not s
18
+ return s if s == ''
19
+ def decapitilize(s)
20
+ s[0,1].downcase + s[1,s.length-1].to_s
21
+ end
22
+ s = decapitilize s
23
+ while s.match /([A-Z]+)/
24
+ s = s.gsub /#{$1}/,'_'+ decapitilize($1)
25
+ end
26
+ s
27
+ end
28
+
29
+ def convert_args(args)
30
+ res = {}
31
+ args.each do |k,v|
32
+ if v.is_a? Array
33
+ v = keys v
34
+ else
35
+ v = v.to_k
36
+ end
37
+ res[k] = v
38
+ end
39
+ return res
40
+ end
41
+
42
+ def keys(objs)
43
+ objs.map {|x| x.to_k}
44
+ end
45
+
46
+ # object -> value
47
+ #
48
+ # Converts v which is probably a string, to a primitive value, so we
49
+ # can have primitives other than strings as attributes of BaseObjs.
50
+ #
51
+ def to_o(v)
52
+ if not v
53
+ return nil
54
+ end
55
+ s = v.to_s
56
+ if not s
57
+ return nil
58
+ end
59
+ if s == 'nil'
60
+ return nil
61
+ end
62
+ if s =~ /^\d+/
63
+ return s.to_i
64
+ end
65
+ if s =~ /^\d+\.?\d*$/
66
+ return s.to_f
67
+ end
68
+ if s == 'true'
69
+ return true
70
+ end
71
+ if s == 'false'
72
+ return false
73
+ end
74
+ if s =~ /^\[.*\]$/
75
+ s = s.gsub /^\[/,''
76
+ s = s.gsub /\]$/,''
77
+ return s.split(',').map {|x| to_o x}
78
+ end
79
+ return s
80
+ end
81
+
82
+ # Override this to declare how certain attributes are constructed.
83
+ # This is done at the end of types.rb.
84
+ class << self
85
+ attr_accessor :symbols_to_types
86
+ end
87
+ self.symbols_to_types = {}
88
+
89
+ # ----------------------------------------------------------------------
90
+ # Base class for remote objects. They contain an api instance, and
91
+ # also have a fill method that will set the values to the
92
+ # appropriate values
93
+ # ----------------------------------------------------------------------
94
+ class ApiObj
95
+ attr_reader :api
96
+
97
+ def initialize(api)
98
+ @api = api
99
+ end
100
+
101
+ def fill(x)
102
+ syms_to_types = Rdio::symbols_to_types || {}
103
+ x.each do |k,v|
104
+ sym = camel2underscores(k).to_sym
105
+ #
106
+ # If we have an actual type for this symbol, then use that
107
+ # type to construct this value. Otherwise, it's just a
108
+ # primitive type
109
+ #
110
+ type = syms_to_types[sym]
111
+ if Rdio::log_symbols
112
+ Rdio::log "#{self.class}.#{sym} => #{type}"
113
+ end
114
+ if type
115
+ #
116
+ # Allow simple types that are used for arrays
117
+ #
118
+ if v.is_a? Array
119
+ o = v.map do |x|
120
+ obj = type.new api
121
+ obj.fill x
122
+ obj
123
+ end
124
+ else
125
+ o = type.new api
126
+ o.fill v
127
+ end
128
+ else
129
+ o = to_o v
130
+ end
131
+ begin
132
+ sym_eq = (camel2underscores(k)+'=').to_sym
133
+ self.send sym_eq,o
134
+ rescue Exception => e
135
+ STDERR.puts "Couldn't find symbol: " +
136
+ "#{sym} => #{o} for type: #{self.class}"
137
+ end
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ # ----------------------------------------------------------------------
144
+ # An Object that is based on json with simple types
145
+ # ----------------------------------------------------------------------
146
+ class JSONObj
147
+
148
+ attr_reader :json
149
+
150
+ def initialize(json)
151
+ @json = json
152
+ end
153
+
154
+ def method_missing(method,args={})
155
+ meth = method.to_s
156
+ res = @json[meth]
157
+ #
158
+ # Maybe this should be a number
159
+ #
160
+ if meth =~ /_count$/ or meth =~ /^num_/
161
+ begin
162
+ return res.to_i
163
+ rescue Exception => e
164
+ STDERR.puts "#{meth} (err) #{e}"
165
+ end
166
+ end
167
+ return res
168
+ end
169
+ end
170
+
171
+ # ----------------------------------------------------------------------
172
+ # An ApiObj with a 'key'
173
+ # ----------------------------------------------------------------------
174
+ class BaseObj < ApiObj
175
+
176
+ attr_accessor :key
177
+
178
+ def initialize(api)
179
+ super api
180
+ end
181
+
182
+ # Compares only by key
183
+ def eql?(that)
184
+ self.class.equal?(that.class) and
185
+ self.key.equal?(that.key)
186
+ end
187
+
188
+ def to_k
189
+ key
190
+ end
191
+
192
+ end
193
+
194
+ # ----------------------------------------------------------------------
195
+ # Basis for making web-service calls and constructing the values.
196
+ # Subclasses should declare the api by calling 'call',
197
+ # 'return_object', and 'create_object'
198
+ # ----------------------------------------------------------------------
199
+ class BaseApi
200
+
201
+ def initialize(key,secret)
202
+ @oauth = RdioOAuth.new key,secret
203
+ @access_token_auth = nil
204
+ @access_token_no_auth = nil
205
+ end
206
+
207
+ def call(method,args,requires_auth=false)
208
+ #
209
+ # Convert object with keys just to use their keys
210
+ #
211
+ args = convert_args args
212
+ if Rdio::log_methods
213
+ Rdio::log "Called method: #{method}(#{args}) : auth=#{requires_auth}"
214
+ end
215
+ new_args = {}
216
+ new_args['method'] = method
217
+ args.each do |k,v|
218
+ new_args[k] = v.to_k.to_s
219
+ end
220
+ url = '/1/'
221
+ if Rdio::log_posts
222
+ Rdio::log "Post to url=#{url} method=#{method} args=#{args}"
223
+ end
224
+ resp,data = access_token(requires_auth).post url,new_args
225
+ return data
226
+ end
227
+
228
+ def return_object(type,method,args,requires_auth=false)
229
+ json = call method,args,requires_auth
230
+ if Rdio::log_json
231
+ Rdio::log json
232
+ end
233
+ create_object type,json
234
+ end
235
+
236
+ private
237
+
238
+ def fill_obj(type,x)
239
+ res = type.new self
240
+ res.fill x
241
+ return res
242
+ end
243
+
244
+ def create_object(type,json_str,keys_to_objects=false)
245
+ begin
246
+ _create_object(type,json_str,keys_to_objects)
247
+ rescue Exception => e
248
+ STDERR.puts "create_json (err): #{e}"
249
+ STDERR.puts "create_json (str): #{json_str}"
250
+ raise e
251
+ end
252
+ end
253
+
254
+ def unwrap_json(json_str)
255
+ obj = JSON.parse json_str
256
+ status = obj['status']
257
+ if status == 'error'
258
+ raise Exception.new obj['message']
259
+ end
260
+ if status == 'ok'
261
+ return obj['result']
262
+ end
263
+ raise Exception.new status
264
+ end
265
+
266
+ def _create_object(type,json_str,keys_to_objects=false)
267
+ if type == true
268
+ return true
269
+ end
270
+ if type == false
271
+ return false
272
+ end
273
+ result = unwrap_json(json_str)
274
+ if type == Boolean or type == String or
275
+ type == Fixnum or type == Float
276
+ return false if not result
277
+ return to_o result
278
+ end
279
+ #
280
+ # A mild hack, but for get the result is a hash of keys to
281
+ # objects, in this case return an array of those objects
282
+ #
283
+ if keys_to_objects
284
+ result = result.values
285
+ end
286
+ #
287
+ # This could be an array (TODO: could not be general enough)
288
+ #
289
+ if result.is_a? Array
290
+ res = result.map {|x| fill_obj type,x}
291
+ else
292
+ res = fill_obj type,result
293
+ end
294
+ return res
295
+ end
296
+
297
+ def access_token(requires_auth)
298
+ if requires_auth
299
+ if not @access_token_auth
300
+ @access_token_auth = @oauth.access_token requires_auth
301
+ end
302
+ res = @access_token_auth
303
+ else
304
+ if not @access_token_no_auth
305
+ @access_token_no_auth = @oauth.access_token requires_auth
306
+ end
307
+ res = @access_token_no_auth
308
+ end
309
+ res
310
+ end
311
+
312
+ end
313
+
314
+ end
@@ -0,0 +1,287 @@
1
+ module Rdio
2
+
3
+ class ArtistData < BaseObj
4
+ def initialize(api)
5
+ super api
6
+ end
7
+
8
+ # the name of the artist
9
+ attr_accessor :name
10
+
11
+ # the object type, always "r"
12
+ attr_accessor :type
13
+
14
+ # the URL of the artist on the Rdio web site
15
+ attr_accessor :url
16
+
17
+ # the number of tracks that the artist has on Rdio
18
+ attr_accessor :length
19
+
20
+ # an image for the artist
21
+ attr_accessor :icon
22
+
23
+ # an image for the artist, partial URL
24
+ attr_accessor :base_icon
25
+
26
+ # is an Rdio Station available for the artist?
27
+ attr_accessor :has_radio
28
+
29
+ # a short URL for the artist page
30
+ attr_accessor :short_url
31
+
32
+ # the number of albums that the artist has on Rdio
33
+ attr_accessor :album_count
34
+
35
+ end
36
+
37
+ class AlbumData < BaseObj
38
+ def initialize(api)
39
+ super api
40
+ end
41
+
42
+ # the name of the album
43
+ attr_accessor :name
44
+
45
+ # the type of the object, always "a"
46
+ attr_accessor :type
47
+
48
+ # the URL to the cover art for the album
49
+ attr_accessor :icon
50
+
51
+ # the URL to the cover art for the album
52
+ attr_accessor :base_icon
53
+
54
+ # the URL of the album on the Rdio site
55
+ attr_accessor :url
56
+
57
+ # the name of the artist that released the album
58
+ attr_accessor :artist
59
+
60
+ # the URL of the artist that released the album on the Rdio site
61
+ attr_accessor :artist_url
62
+
63
+ # is the album explicit?
64
+ attr_accessor :is_explicit
65
+
66
+ # is the album clean?
67
+ attr_accessor :is_clean
68
+
69
+ # number of tracks on the album
70
+ attr_accessor :length
71
+
72
+ # the key of the artist that released the album
73
+ attr_accessor :artist_key
74
+
75
+ # the keys of the tracks on the album
76
+ attr_accessor :track_keys
77
+
78
+ # the price of the album in US cents
79
+ attr_accessor :price
80
+
81
+ # the album can be streamed
82
+ attr_accessor :can_stream
83
+
84
+ # the album can be previewed
85
+ attr_accessor :can_sample
86
+
87
+ # the album can be sync to mobile devices
88
+ attr_accessor :can_tether
89
+
90
+ # a short URL for the album
91
+ attr_accessor :short_url
92
+
93
+ # the URL of a SWF to embed the album
94
+ attr_accessor :embed_url
95
+
96
+ # the release date of the album, human readable
97
+ attr_accessor :display_date
98
+
99
+ # the release date of the album
100
+ attr_accessor :release_date
101
+
102
+ # the duration of the album in seconds
103
+ attr_accessor :duration
104
+
105
+ # the release date of the album in ISO format
106
+ attr_accessor :release_date_iso
107
+
108
+ end
109
+
110
+ class TrackData < BaseObj
111
+ def initialize(api)
112
+ super api
113
+ end
114
+
115
+ # the name of the track
116
+ attr_accessor :name
117
+
118
+ # the name of the artist who performed the track
119
+ attr_accessor :artist
120
+
121
+ # the name of the album that the track appears on
122
+ attr_accessor :album
123
+
124
+ # the key of the album that the track appears on
125
+ attr_accessor :album_key
126
+
127
+ # the URL of the album that the track appears on, on the Rdio web site
128
+ attr_accessor :album_url
129
+
130
+ # the key of the track's artist
131
+ attr_accessor :artist_key
132
+
133
+ # the URL of the track's artist on the Rdio web site
134
+ attr_accessor :artist_url
135
+
136
+ # the object type, always "t"
137
+ attr_accessor :type
138
+
139
+ # the number of tracks in the track, ie: 1
140
+ attr_accessor :length
141
+
142
+ # the duration of the track in seconds
143
+ attr_accessor :duration
144
+
145
+ # is the track explicit?
146
+ attr_accessor :is_explicit
147
+
148
+ # is the track clean?
149
+ attr_accessor :is_clean
150
+
151
+ # the URL of the track on the Rdio web site
152
+ attr_accessor :url
153
+
154
+ # the URL of the album-art for the track
155
+ attr_accessor :base_icon
156
+
157
+ # the name of the artist whose album the track appears on
158
+ attr_accessor :album_artist
159
+
160
+ # the key of the artist whose album the track appears on
161
+ attr_accessor :album_artist_key
162
+
163
+ # the track can be downloaded
164
+ attr_accessor :can_download
165
+
166
+ # the track can only be downloaded as part of an album download
167
+ attr_accessor :can_download_album_only
168
+
169
+ # the track can be streamed
170
+ attr_accessor :can_stream
171
+
172
+ # the track can be synced to mobile devices
173
+ attr_accessor :can_tether
174
+
175
+ # the track can be previewed
176
+ attr_accessor :can_sample
177
+
178
+ # the price of the track in US cents
179
+ attr_accessor :price
180
+
181
+ # a short URL for the track
182
+ attr_accessor :short_url
183
+
184
+ # the URL of a SWF to embed the track
185
+ attr_accessor :embed_url
186
+
187
+ # the partial URL of the album-art for the track
188
+ attr_accessor :icon
189
+
190
+ # the number of times this track has been played
191
+ attr_accessor :play_count
192
+
193
+ end
194
+
195
+ class PlaylistData < BaseObj
196
+ def initialize(api)
197
+ super api
198
+ end
199
+
200
+ # the name of the playlist
201
+ attr_accessor :name
202
+
203
+ # the number of tracks in the playlist
204
+ attr_accessor :length
205
+
206
+ # the object type, always "p"
207
+ attr_accessor :type
208
+
209
+ # the URL of the playlist on the Rdio site
210
+ attr_accessor :url
211
+
212
+ # the URL of an icon for the playlist
213
+ attr_accessor :icon
214
+
215
+ # the URL of an icon for the playlist
216
+ attr_accessor :base_icon
217
+
218
+ # the name of the user who created the playlist
219
+ attr_accessor :owner
220
+
221
+ # the URL on the Rdio site of the user who created the playlist
222
+ attr_accessor :owner_url
223
+
224
+ # the key of the user who created the playlist
225
+ attr_accessor :owner_key
226
+
227
+ # the icon of the user who created the playlist
228
+ attr_accessor :owner_icon
229
+
230
+ # when the playlist was last modified
231
+ attr_accessor :last_updated
232
+
233
+ # a short URL for the playlist
234
+ attr_accessor :short_url
235
+
236
+ # the URL of a SWF to embed the playlist
237
+ attr_accessor :embed_url
238
+
239
+ end
240
+
241
+ class UserData < BaseObj
242
+ def initialize(api)
243
+ super api
244
+ end
245
+
246
+ # the first name of the user
247
+ attr_accessor :first_name
248
+
249
+ # the last name of the user
250
+ attr_accessor :last_name
251
+
252
+ # the URL of an image of the user
253
+ attr_accessor :icon
254
+
255
+ # the URL of an image of the user
256
+ attr_accessor :base_icon
257
+
258
+ # the library version of the user, used to determine if a user's collection has changed
259
+ attr_accessor :library_version
260
+
261
+ # the URL of the user on the Rdio site
262
+ attr_accessor :url
263
+
264
+ # "m" or "f"
265
+ attr_accessor :gender
266
+
267
+ # the object type, always "s"
268
+ attr_accessor :type
269
+
270
+ # the user's vanity name
271
+ attr_accessor :username
272
+
273
+ # the last song the user has played
274
+ attr_accessor :last_song_played
275
+
276
+ # how to display the user's name
277
+ attr_accessor :display_name
278
+
279
+ # the number of tracks in the user's collection
280
+ attr_accessor :track_count
281
+
282
+ # when the last played song was played
283
+ attr_accessor :last_song_play_time
284
+
285
+ end
286
+
287
+ end