rdio 0.0.1

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/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