officialfm 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/changelog.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0 Aug 03, 2011
4
+ * Advanced API is now fully supported, see docs here: http://official.fm/developers/advanced
5
+ * OAuth sign-in demo can be found here: https://github.com/officialfm/sign-in-with-officialfm-ruby
6
+
3
7
  ## 0.0.4 May 20, 2011
4
8
  * Removed 'tracks' workaround, as the official API now includes it by default
5
9
 
@@ -0,0 +1,23 @@
1
+ require 'faraday'
2
+
3
+ module Faraday
4
+ class Request::OfficialFMOAuth < Faraday::Middleware
5
+ dependency 'simple_oauth'
6
+
7
+ def call(env)
8
+ params = env[:body] || {}
9
+ signature_params = params
10
+
11
+ params.map{ |k,v| signature_params = {} if v.respond_to?(:content_type) }
12
+
13
+ header = SimpleOAuth::Header.new(env[:method], env[:url], signature_params, @options)
14
+ env[:request_headers]['Authorization'] = header.to_s
15
+
16
+ @app.call(env)
17
+ end
18
+
19
+ def initialize(app, options)
20
+ @app, @options = app, options
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ module OfficialFM
2
+ # @private
3
+ module Authentication
4
+ private
5
+
6
+ # Authentication hash
7
+ #
8
+ # @return [Hash]
9
+ def authentication
10
+ {
11
+ :consumer_key => @api_key,
12
+ :consumer_secret => @api_secret,
13
+ :token => @access_token,
14
+ :token_secret => @access_secret,
15
+ }
16
+ end
17
+
18
+ # Check whether user is authenticated
19
+ #
20
+ # @return [Boolean]
21
+ def authenticated?
22
+ authentication[:token] != nil
23
+ end
24
+
25
+ private
26
+
27
+ def check_auth(name)
28
+ raise "#{name} is an advanced API method - lacking OAuth credentials." unless authenticated?
29
+ end
30
+ end
31
+ end
@@ -1,7 +1,7 @@
1
1
  require 'forwardable'
2
-
3
- # Note: this gem only supports the Simple API, since the Advanced API
4
- # is still in development
2
+ require 'faraday/request/officialfm_oauth'
3
+ require 'officialfm/authentication'
4
+ require 'officialfm/version'
5
5
 
6
6
  module OfficialFM
7
7
  class Client
@@ -10,31 +10,64 @@ module OfficialFM
10
10
  include Users
11
11
  include Tracks
12
12
  include Playlists
13
+ include Authentication
13
14
 
14
- attr_reader :api_key
15
+ attr_reader :api_key, :api_secret
15
16
 
16
- def_delegators :web_server
17
+ def_delegators :web_server, :authorize_url, :access_token_url
17
18
 
18
19
  def initialize(options={})
19
20
  @api_key = options[:api_key] || OfficialFM.api_key
21
+ @api_secret = options[:api_secret] || OfficialFM.api_secret
22
+ @access_token = options[:access_token]
23
+ @access_secret = options[:access_secret]
20
24
  # Note: Although the default of the API is to return XML, I think
21
25
  # json is more appropriate in the Ruby world
22
26
 
23
- # Note: I really don't understand how js_callback_function works,
24
- # so I'm not exposing it here. (Is it for AJAX client-side requests?)
25
27
  @format = options[:format] || :json
26
- connection
28
+ connection unless @access_token
29
+ end
30
+
31
+ # GET request arguments for simple API calls
32
+ def simple_params (options = nil)
33
+ params = {
34
+ :key => @api_key,
35
+ :format => @format,
36
+ }
37
+ if options
38
+ options.each { |key, value|
39
+ case key
40
+ when 'limit'
41
+ params['api_max_responses'] = value
42
+ when 'embed'
43
+ params['api_embed_codes'] = value
44
+ else
45
+ params[key] = value
46
+ end
47
+ }
48
+ end
49
+ params
27
50
  end
28
51
 
29
52
  # Raw HTTP connection, either Faraday::Connection
30
53
  #
31
54
  # @return [Faraday::Connection]
32
55
  def connection
33
- params = {:key => @api_key, :format => @format}
34
- @connection ||= Faraday::Connection.new(:url => api_url, :params => params, :headers => default_headers) do |builder|
35
- builder.adapter Faraday.default_adapter
36
- builder.use Faraday::Response::ParseJson
56
+ params =
57
+
58
+ options = {
59
+ :url => api_url,
60
+ :headers => default_headers
61
+ }
62
+
63
+ @connection ||= Faraday.new(options) do |builder|
64
+ builder.use Faraday::Request::OfficialFMOAuth, authentication if authenticated?
65
+ builder.use Faraday::Request::Multipart
66
+ builder.use Faraday::Request::UrlEncoded
67
+
37
68
  builder.use Faraday::Response::Mashify
69
+ builder.use Faraday::Response::ParseJson
70
+ builder.adapter Faraday.default_adapter
38
71
  end
39
72
 
40
73
  end
@@ -43,7 +76,7 @@ module OfficialFM
43
76
  def default_headers
44
77
  headers = {
45
78
  :accept => 'application/json',
46
- :user_agent => 'officialfm Ruby gem'
79
+ :user_agent => "officialfm ruby gem version #{OfficialFM::VERSION}"
47
80
  }
48
81
  end
49
82
 
@@ -10,8 +10,7 @@ module OfficialFM
10
10
  # @return [Hashie::Mash] Playlist list
11
11
  def playlists(search_param, options={})
12
12
  response = connection.get do |req|
13
- req.url "/search/playlists/#{CGI::escape(search_param)}",
14
- :api_max_responses => options[:limit]
13
+ req.url "/search/playlists/#{CGI::escape(search_param)}", simple_params(options)
15
14
  end
16
15
 
17
16
  response.body.map do |pl| improve(pl) end
@@ -24,8 +23,7 @@ module OfficialFM
24
23
  # @return [Hashie::Mash] Playlist
25
24
  def playlist(playlist_id, options={})
26
25
  response = connection.get do |req|
27
- req.url "/playlist/#{playlist_id}",
28
- :api_embed_codes => options[:embed]
26
+ req.url "/playlist/#{playlist_id}", simple_params(options)
29
27
  end
30
28
  improve(response.body[0])
31
29
  end
@@ -37,8 +35,7 @@ module OfficialFM
37
35
  # @return [Hashie::Mash] User list
38
36
  def playlist_votes(playlist_id, options={})
39
37
  response = connection.get do |req|
40
- req.url "/playlist/#{playlist_id}/votes",
41
- :api_max_responses => options[:limit]
38
+ req.url "/playlist/#{playlist_id}/votes", simple_params(options)
42
39
  end
43
40
  response.body
44
41
  end
@@ -48,6 +45,101 @@ module OfficialFM
48
45
  playlist.running_time = playlist["length"]
49
46
  playlist
50
47
  end
48
+
49
+ ####################################################################
50
+ ######################### Advanced API methods #####################
51
+ ####################################################################
52
+
53
+ # Update information of a given playlist
54
+ #
55
+ # @param [String] playlist_id: id
56
+ # @param [String] description (optional)
57
+ # @param [String] name (optional)
58
+ # @param [String] password (optional)
59
+ # @param [String] private (optional)
60
+ # @return [Hashie::Mash] Playlist
61
+ def update_playlist! (playlist_id, data = {})
62
+ check_auth :update_playlist
63
+
64
+ response = connection.put do |req|
65
+ req.url "/playlist/update/#{playlist_id}", data
66
+ req.body = { :format => @format }
67
+ end
68
+ response
69
+ end
70
+
71
+ # Upload a picture for a given playlist
72
+ #
73
+ # @param [String] playlist_id: id
74
+ # @param [String] path: path to a picture
75
+ # @param [String] mime: the mime-type of the picture (e.g. image/jpeg, image/png, etc.)
76
+ # @return [Hashie::Mash] Success or error message
77
+ def playlist_picture! (playlist_id, path, mime)
78
+ check_auth :playlist_picture
79
+
80
+ response = connection.post do |req|
81
+ req.url "/playlist/picture/#{playlist_id}"
82
+ req.body = { :file => Faraday::UploadIO.new(path, mime), :format => @format }
83
+ end
84
+ response
85
+ end
86
+
87
+ # Remove a playlist
88
+ #
89
+ # @param [String] playlist_id: id
90
+ # @return [Hashie::Mash] Success or error message
91
+ def playlist_remove! (playlist_id)
92
+ check_auth :playlist_remove
93
+
94
+ response = connection.delete do |req|
95
+ req.url "/playlist/remove/#{playlist_id}"
96
+ req.body = { :format => @format }
97
+ end
98
+ response
99
+ end
100
+
101
+ # Create a playlist
102
+ #
103
+ # @param [String] name: playlist name
104
+ # @param [String] track_id: first track id of the new playlist
105
+ # @return [Hashie::Mash] Playlist object
106
+ def playlist_create! (name, track_id)
107
+ check_auth :playlist_create
108
+
109
+ response = connection.post do |req|
110
+ req.url "/playlist/create"
111
+ req.body = { :format => @format, :name => name, :track_id => track_id }
112
+ end
113
+ response
114
+ end
115
+
116
+ # Vote for a playlist
117
+ #
118
+ # @param [String] playlist_id: id
119
+ # @return [Hashie::Mash] Success or error message
120
+ def playlist_vote! (playlist_id)
121
+ check_auth :playlist_vote
122
+
123
+ response = connection.post do |req|
124
+ req.url "/playlist/vote/#{playlist_id}"
125
+ req.body = { :format => @format }
126
+ end
127
+ response
128
+ end
129
+
130
+ # Remote vote for a playlist
131
+ #
132
+ # @param [String] playlist_id: id
133
+ # @return [Hashie::Mash] Success or error message
134
+ def playlist_unvote! (playlist_id)
135
+ check_auth :playlist_unvote
136
+
137
+ response = connection.post do |req|
138
+ req.url "/playlist/unvote/#{playlist_id}"
139
+ req.body = { :format => @format }
140
+ end
141
+ response
142
+ end
51
143
 
52
144
  end
53
145
  end
@@ -10,8 +10,7 @@ module OfficialFM
10
10
  # @return [Hashie::Mash] Track list
11
11
  def tracks(search_param, options={})
12
12
  response = connection.get do |req|
13
- req.url "/search/tracks/#{CGI::escape(search_param)}",
14
- :api_max_responses => options[:limit]
13
+ req.url "/search/tracks/#{CGI::escape(search_param)}", simple_params(options)
15
14
  end
16
15
  response.body
17
16
  end
@@ -26,8 +25,7 @@ module OfficialFM
26
25
  # @return [Hashie::Mash] Track
27
26
  def track(track_id, options={})
28
27
  response = connection.get do |req|
29
- req.url "/track/#{track_id}",
30
- :api_embed_codes => options[:embed]
28
+ req.url "/track/#{track_id}", simple_params(options)
31
29
  end
32
30
  response.body[0]
33
31
  end
@@ -39,8 +37,7 @@ module OfficialFM
39
37
  # @return [Hashie::Mash] User list
40
38
  def track_votes(track_id, options={})
41
39
  response = connection.get do |req|
42
- req.url "/track/#{track_id}/votes",
43
- :api_max_responses => options[:limit]
40
+ req.url "/track/#{track_id}/votes", simple_params(options)
44
41
  end
45
42
  response.body
46
43
  end
@@ -55,9 +52,7 @@ module OfficialFM
55
52
  # @return [Hashie::Mash] Track list
56
53
  def charts(charting, options={})
57
54
  response = connection.get do |req|
58
- req.url "/tracks/charts",
59
- :charting => charting, :genre => options[:genre], :country => options[:country],
60
- :api_embed_codes => options[:embed], :api_max_responses => options[:limit]
55
+ req.url "/tracks/charts", simple_params(options)
61
56
  end
62
57
  response.body
63
58
  end
@@ -71,12 +66,142 @@ module OfficialFM
71
66
  # @return [Hashie::Mash] Track list
72
67
  def latest(options={})
73
68
  response = connection.get do |req|
74
- req.url "/tracks/latest", :genre => options[:genre],
75
- :country => options[:country], :api_embed_codes => options[:embed],
76
- :api_max_responses => options[:limit]
69
+ req.url "/tracks/latest", simple_params(options)
77
70
  end
78
71
  response.body
79
72
  end
80
-
73
+
74
+ ####################################################################
75
+ ######################### Advanced API methods #####################
76
+ ####################################################################
77
+
78
+ # Update information of a given track
79
+ #
80
+ # @param [String] track_id: id
81
+ # @param [String] artist_name (optional)
82
+ # @param [String] buy_url (optional)
83
+ # @param [String] country_id (optional)
84
+ # @param [String] downloadable (optional)
85
+ # @param [String] derived_by (optional)
86
+ # @param [String] derived_type (optional)
87
+ # @param [String] description (optional)
88
+ # @param [String] isrc (optional)
89
+ # @param [String] label_name (optional)
90
+ # @param [String] label_none (optional)
91
+ # @param [String] license_type (optional)
92
+ # @param [String] lyrics (optional)
93
+ # @param [String] genre_string (optional)
94
+ # @param [String] original_track_id (optional)
95
+ # @param [String] password (optional)
96
+ # @param [String] pr_url (optional)
97
+ # @param [String] private (optional)
98
+ # @param [String] require_valid_email (optional)
99
+ # @param [String] tag_string (optional)
100
+ # @param [String] title (optional)
101
+ # @param [String] url_1_name (optional)
102
+ # @param [String] url_1 (optional)
103
+ # @param [String] url_2_name (optional)
104
+ # @param [String] url_2 (optional)
105
+ # @param [String] web_url (optional)
106
+ # @return [Hashie::Mash] Track
107
+ def update_track! (track_id, data = {})
108
+ check_auth :update_track
109
+
110
+ response = connection.put do |req|
111
+ req.url "/track/update/#{track_id}", data
112
+ req.body = { :format => @format }
113
+ end
114
+ response
115
+ end
116
+
117
+ # Upload a picture for a given track
118
+ #
119
+ # @param [String] track_id: id
120
+ # @param [String] path: path to a picture
121
+ # @param [String] mime: the mime-type of the picture (e.g. image/jpeg, image/png, etc.)
122
+ # @return [Hashie::Mash] Success or error message
123
+ def track_picture! (track_id, path, mime)
124
+ check_auth :track_picture
125
+
126
+ response = connection.post do |req|
127
+ req.url "/track/picture/#{track_id}"
128
+ req.body = { :file => Faraday::UploadIO.new(path, mime), :format => @format }
129
+ end
130
+ response
131
+ end
132
+
133
+ # Vote for a track
134
+ #
135
+ # @param [String] track_id: id
136
+ # @return [Hashie::Mash] Success or error message
137
+ def track_vote! (track_id)
138
+ check_auth :track_vote
139
+
140
+ response = connection.post do |req|
141
+ req.url "/track/vote/#{track_id}"
142
+ req.body = { :format => @format }
143
+ end
144
+ response
145
+ end
146
+
147
+ # Remove vote for a track
148
+ #
149
+ # @param [String] track_id: id
150
+ # @return [Hashie::Mash] Success or error message
151
+ def track_unvote! (track_id)
152
+ check_auth :track_unvote
153
+
154
+ response = connection.post do |req|
155
+ req.url "/track/unvote/#{track_id}"
156
+ req.body = { :format => @format }
157
+ end
158
+ response
159
+ end
160
+
161
+ # Add a track to a playlist
162
+ #
163
+ # @param [String] track_id: id
164
+ # @param [String] playlist_id: id
165
+ # @return [Hashie::Mash] Success or error message
166
+ def add_track_to_playlist! (track_id)
167
+ check_auth :add_track_to_playlist!
168
+
169
+ response = connection.post do |req|
170
+ req.url "/track/#{track_id}/addto/#{playlist_id}"
171
+ req.body = { :format => @format }
172
+ end
173
+ response
174
+ end
175
+
176
+ # Remove a track from a playlist
177
+ #
178
+ # @param [String] track_id: id
179
+ # @param [String] playlist_id: id
180
+ # @return [Hashie::Mash] Success or error message
181
+ def remove_track_from_playlist! (track_id)
182
+ check_auth :remove_track_from_playlist!
183
+
184
+ response = connection.delete do |req|
185
+ req.url "/track/#{track_id}/removefrom/#{playlist_id}"
186
+ req.body = { :format => @format }
187
+ end
188
+ response
189
+ end
190
+
191
+ # Upload a new track to Official.fm
192
+ #
193
+ # @param [String] path: path to an mp3, 44.1Khz file
194
+ # @param [String] mime: the mime-type of the file (e.g. audio/mpeg, etc.)
195
+ # @return [Hashie::Mash] Track
196
+ def upload! (path, mime)
197
+ check_auth :upload
198
+
199
+ response = connection.post do |req|
200
+ req.url "/track/upload"
201
+ req.body = { :file => Faraday::UploadIO.new(path, mime), :format => @format }
202
+ end
203
+ response
204
+ end
205
+
81
206
  end
82
207
  end
@@ -10,7 +10,7 @@ module OfficialFM
10
10
  # @return [Hashie::Mash] User list
11
11
  def users(search_param, options={})
12
12
  response = connection.get do |req|
13
- req.url "/search/users/#{CGI::escape(search_param)}", :api_max_responses => options[:limit]
13
+ req.url "/search/users/#{CGI::escape(search_param)}", simple_params(options)
14
14
  end
15
15
  response.body
16
16
  end
@@ -21,12 +21,12 @@ module OfficialFM
21
21
  # @return [Hashie::Mash] User
22
22
  def user(user_id)
23
23
  response = connection.get do |req|
24
- req.url "/user/#{user_id}"
24
+ req.url "/user/#{user_id}", simple_params
25
25
  end
26
26
  response.body[0]
27
27
  end
28
28
 
29
- # Retrieve a list of the tracks of this user
29
+ # Retrieve a list of the tracks of a given user
30
30
  #
31
31
  # @param [String] user_id: id or login
32
32
  # @param [Integer] limit (50) limit per page
@@ -34,13 +34,12 @@ module OfficialFM
34
34
  # @return [Hashie::Mash] Track list
35
35
  def user_tracks(user_id, options={})
36
36
  response = connection.get do |req|
37
- req.url "/user/#{user_id}/tracks",
38
- :api_embed_codes => options[:embed], :api_max_responses => options[:limit]
37
+ req.url "/user/#{user_id}/tracks", simple_params(options)
39
38
  end
40
39
  response.body
41
40
  end
42
41
 
43
- # Retrieve a list of the tracks this user has voted for
42
+ # Retrieve a list of the tracks a given user has voted for
44
43
  #
45
44
  # @param [String] user_id: id or login
46
45
  # @param [Integer] limit (50) limit per page
@@ -48,13 +47,12 @@ module OfficialFM
48
47
  # @return [Hashie::Mash] Track list
49
48
  def voted_tracks(user_id, options={})
50
49
  response = connection.get do |req|
51
- req.url "/user/#{user_id}/voted_tracks",
52
- :api_embed_codes => options[:embed], :api_max_responses => options[:limit]
50
+ req.url "/user/#{user_id}/voted_tracks", simple_params(options)
53
51
  end
54
52
  response.body
55
53
  end
56
54
 
57
- # Retrieve a list of the playlists of this user
55
+ # Retrieve a list of the playlists of a given user
58
56
  #
59
57
  # @param [String] user_id: id or login
60
58
  # @param [Integer] limit (50) limit per page
@@ -62,13 +60,12 @@ module OfficialFM
62
60
  # @return [Hashie::Mash] Playlist list
63
61
  def user_playlists(user_id, options={})
64
62
  response = connection.get do |req|
65
- req.url "/user/#{user_id}/playlists",
66
- :api_embed_codes => options[:embed], :api_max_responses => options[:limit]
63
+ req.url "/user/#{user_id}/playlists", simple_params(options)
67
64
  end
68
65
  response.body
69
66
  end
70
67
 
71
- # Retrieve a list of the playlists this user has voted for
68
+ # Retrieve a list of the playlists a given user has voted for
72
69
  #
73
70
  # @param [String] user_id: id or login
74
71
  # @param [Integer] limit (50) limit per page
@@ -76,50 +73,178 @@ module OfficialFM
76
73
  # @return [Hashie::Mash] Playlist list
77
74
  def voted_playlists(user_id, options={})
78
75
  response = connection.get do |req|
79
- req.url "/user/#{user_id}/voted_playlists",
80
- :api_embed_codes => options[:embed], :api_max_responses => options[:limit]
76
+ req.url "/user/#{user_id}/voted_playlists", simple_params(options)
81
77
  end
82
78
  response.body
83
79
  end
84
80
 
85
- # Retrieve a list of the contacts of this user
81
+ # Retrieve a list of the contacts of a given user
86
82
  #
87
83
  # @param [String] user_id: id or login
88
84
  # @param [Integer] limit (50) limit per page
89
85
  # @return [Hashie::Mash] User list
90
86
  def user_contacts(user_id, options={})
91
87
  response = connection.get do |req|
92
- req.url "/user/#{user_id}/contacts",
93
- :api_max_responses => options[:limit]
88
+ req.url "/user/#{user_id}/contacts", simple_params(options)
94
89
  end
95
90
  response.body
96
91
  end
97
92
 
98
- # Retrieve a list of the subscribers of this user
93
+ # Retrieve a list of the subscribers of a given user
99
94
  #
100
95
  # @param [String] user_id: id or login
101
96
  # @param [Integer] limit (50) limit per page
102
97
  # @return [Hashie::Mash] User list
103
98
  def user_subscribers(user_id, options={})
104
99
  response = connection.get do |req|
105
- req.url "/user/#{user_id}/subscribers",
106
- :api_max_responses => options[:limit]
100
+ req.url "/user/#{user_id}/subscribers", simple_params(options)
107
101
  end
108
102
  response.body
109
103
  end
110
104
 
111
- # Retrieve a list of the subscriptions of this user
105
+ # Retrieve a list of the subscriptions of a given user
112
106
  #
113
107
  # @param [String] user_id: id or login
114
108
  # @param [Integer] limit (50) limit per page
115
109
  # @return [Hashie::Mash] User list
116
110
  def user_subscriptions(user_id, options={})
117
111
  response = connection.get do |req|
118
- req.url "/user/#{user_id}/subscriptions",
119
- :api_max_responses => options[:limit]
112
+ req.url "/user/#{user_id}/subscriptions", simple_params(options)
120
113
  end
121
114
  response.body
122
115
  end
116
+
117
+ ####################################################################
118
+ ######################### Advanced API methods #####################
119
+ ####################################################################
120
+
121
+ # Retrieve information about the logged in user
122
+ #
123
+ # @return [Hashie::Mash] User
124
+ def profile
125
+ check_auth :profile
126
+
127
+ response = connection.post do |req|
128
+ req.url '/user/profile'
129
+ req.body = { :format => @format }
130
+ end
131
+ response.body[0]
132
+ end
133
+
134
+ # Retrieve tracks of the logged in user
135
+ #
136
+ # @return [Hashie::Mash] Track list
137
+ def own_tracks
138
+ check_auth :own_tracks
139
+
140
+ response = connection.post do |req|
141
+ req.url '/user/tracks'
142
+ req.body = { :format => @format }
143
+ end
144
+ response
145
+ end
146
+
147
+ # Retrieve dropbox tracks of the logged in user
148
+ #
149
+ # @return [Hashie::Mash] Track list
150
+ def dropbox
151
+ check_auth :dropbox
152
+
153
+ response = connection.post do |req|
154
+ req.url '/user/dropbox'
155
+ req.body = { :format => @format }
156
+ end
157
+ response
158
+ end
159
+
160
+ # Retrieve playlists of the logged in user
161
+ #
162
+ # @return [Hashie::Mash] Playlist list
163
+ def own_playlists
164
+ check_auth :own_playlists
165
+
166
+ response = connection.post do |req|
167
+ req.url '/user/playlists'
168
+ req.body = { :format => @format }
169
+ end
170
+ response
171
+ end
172
+
173
+ # Retrieve events of the logged in user's newsfeed
174
+ #
175
+ # @return [Hashie::Mash] Event list
176
+ def newsfeed
177
+ check_auth :newsfeed
178
+
179
+ response = connection.post do |req|
180
+ req.url '/user/newsfeed'
181
+ req.body = { :format => @format }
182
+ end
183
+ response
184
+ end
185
+
186
+ # Update information of the logged in user
187
+ #
188
+ # @param [String] email (optional)
189
+ # @param [String] city (optional)
190
+ # @param [String] country_id (optional)
191
+ # @param [String] url (optional)
192
+ # @param [String] profile (optional)
193
+ # @param [String] birthdate (optional)
194
+ # @param [String] gender (optional)
195
+ # @return [Hashie::Mash] User
196
+ def update_profile! (data = {})
197
+ check_auth :update
198
+
199
+ response = connection.put do |req|
200
+ req.url '/user/update'
201
+ req.body = { :format => @format }.merge(data)
202
+ end
203
+ response
204
+ end
205
+
206
+ # Subscribe the logged in user to a given user
207
+ #
208
+ # @param [String] user_id: the user to subscribe to
209
+ # @return [Hashie::Mash] Success or error message
210
+ def subscribe! (user_id)
211
+ check_auth :subscribe
212
+
213
+ response = connection.post do |req|
214
+ req.url "/user/subscribe/#{user_id}"
215
+ req.body = { :format => @format }
216
+ end
217
+ response
218
+ end
219
+
220
+ # Unsubscribe the logged in user from a given user
221
+ #
222
+ # @param [String] user_id: the user to unsubscribe from
223
+ # @return [Hashie::Mash] Success or error message
224
+ def unsubscribe! (user_id)
225
+ check_auth :unsubscribe
226
+
227
+ response = connection.post do |req|
228
+ req.url "/user/unsubscribe/#{user_id}"
229
+ req.body = { :format => @format }
230
+ end
231
+ response
232
+ end
233
+
234
+ # Upload a picture for authenticated user
235
+ #
236
+ # @param [String] path: path to a picture
237
+ # @param [String] mime: the mime-type of the picture (e.g. image/jpeg, image/png, etc.)
238
+ # @return [Hashie::Mash] Success or error message
239
+ def picture! (path, mime)
240
+ check_auth :picture
241
+
242
+ response = connection.post do |req|
243
+ req.url "/user/picture"
244
+ req.body = { :file => Faraday::UploadIO.new(path, mime), :format => @format }
245
+ end
246
+ response
247
+ end
123
248
 
124
249
  end
125
250
  end
@@ -1,3 +1,3 @@
1
1
  module OfficialFM
2
- VERSION = '0.0.4'
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/officialfm.rb CHANGED
@@ -7,10 +7,11 @@ module OfficialFM
7
7
 
8
8
  class << self
9
9
  attr_accessor :api_key
10
+ attr_accessor :api_secret
10
11
  attr_accessor :test_mode
11
12
 
12
13
  # Configures default credentials easily
13
- # @yield [api_key]
14
+ # @yield [api_key, username, password]
14
15
  def configure
15
16
  yield self
16
17
  true
data/officialfm.gemspec CHANGED
@@ -1,31 +1,43 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require File.expand_path('../lib/officialfm/version', __FILE__)
3
3
 
4
- Gem::Specification.new do |s|
5
- s.name = 'officialfm'
6
- s.version = OfficialFM::VERSION
7
- s.authors = ["Amos Wenger"]
8
- s.email = ['amos@official.fm']
9
- s.summary = %q{Official Ruby bindings for the official.fm API}
10
- s.description = %q{Official Ruby bindings for the official.fm API}
11
- s.homepage = 'http://github.com/officialfm/officialfm-ruby'
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'officialfm'
6
+ gem.version = OfficialFM::VERSION
7
+ gem.authors = ["Amos Wenger"]
8
+ gem.email = ['amos@official.fm']
9
+ gem.summary = %q{Official Ruby bindings for the official.fm API}
10
+ gem.description = %q{Official Ruby bindings for the official.fm API}
11
+ gem.post_install_message =<<eos
12
+ ********************************************************************************
12
13
 
13
- s.add_runtime_dependency 'faraday', '~> 0.5.3'
14
- s.add_runtime_dependency 'faraday_middleware', '~> 0.3.0'
15
- s.add_runtime_dependency 'hashie', '~> 1.0.0'
14
+ Follow @ofmdev on Twitter for announcements, updates, and news.
15
+ https://twitter.com/ofmdev
16
16
 
17
- s.add_development_dependency 'bundler', '~> 1.0'
18
- s.add_development_dependency 'fakeweb', '~> 1.3'
19
- s.add_development_dependency 'jnunemaker-matchy', '~> 0.4'
20
- s.add_development_dependency 'json_pure', '~> 1.4'
21
- s.add_development_dependency 'rake', '~> 0.8'
22
- s.add_development_dependency 'shoulda', '~> 2.11'
23
- s.add_development_dependency 'test-unit', '~> 2.1'
17
+ Don't forget to get your API key here:
18
+ http://official.fm/developers/manager
24
19
 
25
- s.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if s.respond_to? :required_rubygems_version=
26
- s.platform = Gem::Platform::RUBY
27
- s.require_paths = ['lib']
28
- s.files = `git ls-files`.split("\n")
29
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
- s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
20
+ ********************************************************************************
21
+ eos
22
+ gem.homepage = 'http://github.com/officialfm/officialfm-ruby'
23
+
24
+ gem.add_runtime_dependency 'faraday', '~> 0.6'
25
+ gem.add_runtime_dependency 'faraday_middleware', '~> 0.6'
26
+ gem.add_runtime_dependency 'hashie', '~> 1.0.0'
27
+ gem.add_runtime_dependency 'simple_oauth', '~> 0.1.5'
28
+
29
+ gem.add_development_dependency 'bundler', '~> 1.0'
30
+ gem.add_development_dependency 'fakeweb', '~> 1.3'
31
+ gem.add_development_dependency 'jnunemaker-matchy', '~> 0.4'
32
+ gem.add_development_dependency 'json_pure', '~> 1.5'
33
+ gem.add_development_dependency 'rake', '~> 0.8'
34
+ gem.add_development_dependency 'shoulda', '~> 2.11'
35
+ gem.add_development_dependency 'test-unit', '~> 2.1'
36
+
37
+ gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if gem.respond_to? :required_rubygems_version=
38
+ gem.platform = Gem::Platform::RUBY
39
+ gem.require_paths = ['lib']
40
+ gem.files = `git ls-files`.split("\n")
41
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
42
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
31
43
  end
@@ -1,92 +1,122 @@
1
1
  [
2
- {
3
- "comments_count":0,
4
- "created_at":"2011-03-01 00:33:20 UTC",
5
- "description":"",
6
- "id":55569,
7
-
8
- "length":4167,
9
-
10
- "name":"HLSTRS – Timeless (Mixtape for HARTZINE)",
11
- "picture_absolute_url":"http://cdn.official.fm/playlist_pictures/55/55569_small.jpg",
12
- "plays_count":50,
13
- "shuffle":false,
14
-
15
-
16
- "tracks_count":16,
17
- "tracks_list":"216372,216374,216378,216381,216384,216385,216388,216389,216392,216390,216395,216394,216396,216398,216400,216399",
18
- "user_id":46269,
19
- "votes_count":1 },
20
- {
21
- "comments_count":0,
22
- "created_at":"2011-02-02 12:12:39 UTC",
23
- "description":null,
24
- "id":53202,
25
-
26
- "length":1575,
27
-
28
- "name":"MIXTAPE BOOTIE RIO NATAL",
29
- "picture_absolute_url":"http://cdn.official.fm/playlist_pictures/53/53202_small.jpg",
30
- "plays_count":4,
31
- "shuffle":false,
32
-
33
-
34
- "tracks_count":1,
35
- "tracks_list":"183448",
36
- "user_id":98816,
37
- "votes_count":0 },
38
- {
39
- "comments_count":0,
40
- "created_at":"2011-02-02 12:12:59 UTC",
41
- "description":null,
42
- "id":53203,
43
-
44
- "length":3768,
45
-
46
- "name":"MIXTAPE TEM GRINGO NO MASHUP",
47
- "picture_absolute_url":"http://cdn.official.fm/playlist_pictures/53/53203_small.jpg",
48
- "plays_count":1,
49
- "shuffle":false,
50
-
51
-
52
- "tracks_count":1,
53
- "tracks_list":"178977",
54
- "user_id":98816,
55
- "votes_count":0 },
56
- {
57
- "comments_count":0,
58
- "created_at":"2008-09-20 17:36:33 UTC",
59
- "description":"",
60
- "id":5801,
61
-
62
- "length":940,
63
-
64
- "name":"Rap",
65
- "picture_absolute_url":"http://cdn.official.fm/playlist_pictures/5/5801_small.jpg",
66
- "plays_count":3,
67
- "shuffle":false,
68
-
69
-
70
- "tracks_count":4,
71
- "tracks_list":"57854,40057,11290,12818",
72
- "user_id":6603,
73
- "votes_count":0 },
74
- {
75
- "comments_count":0,
76
- "created_at":"2011-01-24 14:25:27 UTC",
77
- "description":"",
78
- "id":52439,
79
-
80
- "length":1055,
81
-
82
- "name":"pop4",
83
- "picture_absolute_url":"http://cdn.official.fm/playlist_pictures/52/52439_small.jpg",
84
- "plays_count":1,
85
- "shuffle":false,
86
-
87
-
88
- "tracks_count":4,
89
- "tracks_list":"24970,26036,26032,25520",
90
- "user_id":51638,
91
- "votes_count":0 }
2
+ {
3
+
4
+ "comments_count":0,
5
+ "created_at":"2011-03-01 00:33:20 UTC",
6
+ "description":"",
7
+ "id":55569,
8
+
9
+ "length":4167,
10
+
11
+ "name":"HLSTRS – Timeless (Mixtape for HARTZINE)",
12
+ "password":null,
13
+ "picture_absolute_url":"http://cdn.official.fm/playlist_pictures/55/55569_small.jpg",
14
+ "plays_count":74,
15
+ "private":false,
16
+ "shuffle":false,
17
+
18
+
19
+ "tracks":[216372,216374,216378,216381,216384,216385,216388,216389,216392,216390,216395,216394,216396,216398,216400,216399],
20
+ "tracks_count":16,
21
+ "tracks_list":"216372,216374,216378,216381,216384,216385,216388,216389,216392,216390,216395,216394,216396,216398,216400,216399",
22
+ "user_id":46269,
23
+ "votes_count":1
24
+ }
25
+ ,
26
+ {
27
+
28
+ "comments_count":0,
29
+ "created_at":"2011-06-11 06:12:57 UTC",
30
+ "description":null,
31
+ "id":64801,
32
+
33
+ "length":1946,
34
+
35
+ "name":"Guruguru",
36
+ "password":null,
37
+ "picture_absolute_url":"http://cdn.official.fm/track_pictures/252/252818_small.jpg",
38
+ "plays_count":0,
39
+ "private":false,
40
+ "shuffle":false,
41
+
42
+
43
+ "tracks":[252818],
44
+ "tracks_count":1,
45
+ "tracks_list":"252818",
46
+ "user_id":119997,
47
+ "votes_count":0
48
+ }
49
+ ,
50
+ {
51
+
52
+ "comments_count":0,
53
+ "created_at":"2011-02-02 12:12:39 UTC",
54
+ "description":null,
55
+ "id":53202,
56
+
57
+ "length":1575,
58
+
59
+ "name":"MIXTAPE BOOTIE RIO NATAL",
60
+ "password":null,
61
+ "picture_absolute_url":"http://cdn.official.fm/track_pictures/183/183448_small.jpg",
62
+ "plays_count":4,
63
+ "private":false,
64
+ "shuffle":false,
65
+
66
+
67
+ "tracks":[183448],
68
+ "tracks_count":1,
69
+ "tracks_list":"183448",
70
+ "user_id":98816,
71
+ "votes_count":0
72
+ }
73
+ ,
74
+ {
75
+
76
+ "comments_count":0,
77
+ "created_at":"2011-02-02 12:12:59 UTC",
78
+ "description":null,
79
+ "id":53203,
80
+
81
+ "length":3768,
82
+
83
+ "name":"MIXTAPE TEM GRINGO NO MASHUP",
84
+ "password":null,
85
+ "picture_absolute_url":"http://cdn.official.fm/track_pictures/178/178977_small.jpg",
86
+ "plays_count":2,
87
+ "private":false,
88
+ "shuffle":false,
89
+
90
+
91
+ "tracks":[178977],
92
+ "tracks_count":1,
93
+ "tracks_list":"178977",
94
+ "user_id":98816,
95
+ "votes_count":0
96
+ }
97
+ ,
98
+ {
99
+
100
+ "comments_count":0,
101
+ "created_at":"2008-09-20 17:36:33 UTC",
102
+ "description":"",
103
+ "id":5801,
104
+
105
+ "length":940,
106
+
107
+ "name":"Rap",
108
+ "password":null,
109
+ "picture_absolute_url":"http://cdn.official.fm/track_pictures/57/57854_small.jpg",
110
+ "plays_count":3,
111
+ "private":false,
112
+ "shuffle":false,
113
+
114
+
115
+ "tracks":[57854,40057,11290,12818],
116
+ "tracks_count":4,
117
+ "tracks_list":"57854,40057,11290,12818",
118
+ "user_id":6603,
119
+ "votes_count":0
120
+ }
121
+
92
122
  ]
@@ -12,7 +12,7 @@ class PlaylistsTests < Test::Unit::TestCase
12
12
  tracks = @client.playlists('R&B Mixtape', :limit => 5)
13
13
  tracks.length.should == 5
14
14
  tracks[0].running_time.should == 4167
15
- tracks[3].tracks[1].should == 40057
15
+ tracks[4].tracks[3].should == 12818
16
16
  end
17
17
 
18
18
  should "get info on HLSTRS Timeless mixtape" do
metadata CHANGED
@@ -1,138 +1,144 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: officialfm
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
4
5
  prerelease:
5
- version: 0.0.4
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Amos Wenger
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-05-20 00:00:00 +02:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
12
+ date: 2011-08-03 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
17
15
  name: faraday
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &73388740 !ruby/object:Gem::Requirement
20
17
  none: false
21
- requirements:
18
+ requirements:
22
19
  - - ~>
23
- - !ruby/object:Gem::Version
24
- version: 0.5.3
20
+ - !ruby/object:Gem::Version
21
+ version: '0.6'
25
22
  type: :runtime
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
28
- name: faraday_middleware
29
23
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *73388740
25
+ - !ruby/object:Gem::Dependency
26
+ name: faraday_middleware
27
+ requirement: &73388490 !ruby/object:Gem::Requirement
31
28
  none: false
32
- requirements:
29
+ requirements:
33
30
  - - ~>
34
- - !ruby/object:Gem::Version
35
- version: 0.3.0
31
+ - !ruby/object:Gem::Version
32
+ version: '0.6'
36
33
  type: :runtime
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
39
- name: hashie
40
34
  prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *73388490
36
+ - !ruby/object:Gem::Dependency
37
+ name: hashie
38
+ requirement: &73388260 !ruby/object:Gem::Requirement
42
39
  none: false
43
- requirements:
40
+ requirements:
44
41
  - - ~>
45
- - !ruby/object:Gem::Version
42
+ - !ruby/object:Gem::Version
46
43
  version: 1.0.0
47
44
  type: :runtime
48
- version_requirements: *id003
49
- - !ruby/object:Gem::Dependency
50
- name: bundler
51
45
  prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
46
+ version_requirements: *73388260
47
+ - !ruby/object:Gem::Dependency
48
+ name: simple_oauth
49
+ requirement: &73388030 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.5
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *73388030
58
+ - !ruby/object:Gem::Dependency
59
+ name: bundler
60
+ requirement: &73387800 !ruby/object:Gem::Requirement
53
61
  none: false
54
- requirements:
62
+ requirements:
55
63
  - - ~>
56
- - !ruby/object:Gem::Version
57
- version: "1.0"
64
+ - !ruby/object:Gem::Version
65
+ version: '1.0'
58
66
  type: :development
59
- version_requirements: *id004
60
- - !ruby/object:Gem::Dependency
61
- name: fakeweb
62
67
  prerelease: false
63
- requirement: &id005 !ruby/object:Gem::Requirement
68
+ version_requirements: *73387800
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakeweb
71
+ requirement: &73387570 !ruby/object:Gem::Requirement
64
72
  none: false
65
- requirements:
73
+ requirements:
66
74
  - - ~>
67
- - !ruby/object:Gem::Version
68
- version: "1.3"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.3'
69
77
  type: :development
70
- version_requirements: *id005
71
- - !ruby/object:Gem::Dependency
72
- name: jnunemaker-matchy
73
78
  prerelease: false
74
- requirement: &id006 !ruby/object:Gem::Requirement
79
+ version_requirements: *73387570
80
+ - !ruby/object:Gem::Dependency
81
+ name: jnunemaker-matchy
82
+ requirement: &73387340 !ruby/object:Gem::Requirement
75
83
  none: false
76
- requirements:
84
+ requirements:
77
85
  - - ~>
78
- - !ruby/object:Gem::Version
79
- version: "0.4"
86
+ - !ruby/object:Gem::Version
87
+ version: '0.4'
80
88
  type: :development
81
- version_requirements: *id006
82
- - !ruby/object:Gem::Dependency
83
- name: json_pure
84
89
  prerelease: false
85
- requirement: &id007 !ruby/object:Gem::Requirement
90
+ version_requirements: *73387340
91
+ - !ruby/object:Gem::Dependency
92
+ name: json_pure
93
+ requirement: &73387110 !ruby/object:Gem::Requirement
86
94
  none: false
87
- requirements:
95
+ requirements:
88
96
  - - ~>
89
- - !ruby/object:Gem::Version
90
- version: "1.4"
97
+ - !ruby/object:Gem::Version
98
+ version: '1.5'
91
99
  type: :development
92
- version_requirements: *id007
93
- - !ruby/object:Gem::Dependency
94
- name: rake
95
100
  prerelease: false
96
- requirement: &id008 !ruby/object:Gem::Requirement
101
+ version_requirements: *73387110
102
+ - !ruby/object:Gem::Dependency
103
+ name: rake
104
+ requirement: &73386880 !ruby/object:Gem::Requirement
97
105
  none: false
98
- requirements:
106
+ requirements:
99
107
  - - ~>
100
- - !ruby/object:Gem::Version
101
- version: "0.8"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.8'
102
110
  type: :development
103
- version_requirements: *id008
104
- - !ruby/object:Gem::Dependency
105
- name: shoulda
106
111
  prerelease: false
107
- requirement: &id009 !ruby/object:Gem::Requirement
112
+ version_requirements: *73386880
113
+ - !ruby/object:Gem::Dependency
114
+ name: shoulda
115
+ requirement: &73386650 !ruby/object:Gem::Requirement
108
116
  none: false
109
- requirements:
117
+ requirements:
110
118
  - - ~>
111
- - !ruby/object:Gem::Version
112
- version: "2.11"
119
+ - !ruby/object:Gem::Version
120
+ version: '2.11'
113
121
  type: :development
114
- version_requirements: *id009
115
- - !ruby/object:Gem::Dependency
116
- name: test-unit
117
122
  prerelease: false
118
- requirement: &id010 !ruby/object:Gem::Requirement
123
+ version_requirements: *73386650
124
+ - !ruby/object:Gem::Dependency
125
+ name: test-unit
126
+ requirement: &73386420 !ruby/object:Gem::Requirement
119
127
  none: false
120
- requirements:
128
+ requirements:
121
129
  - - ~>
122
- - !ruby/object:Gem::Version
123
- version: "2.1"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.1'
124
132
  type: :development
125
- version_requirements: *id010
133
+ prerelease: false
134
+ version_requirements: *73386420
126
135
  description: Official Ruby bindings for the official.fm API
127
- email:
136
+ email:
128
137
  - amos@official.fm
129
138
  executables: []
130
-
131
139
  extensions: []
132
-
133
140
  extra_rdoc_files: []
134
-
135
- files:
141
+ files:
136
142
  - .document
137
143
  - .gitignore
138
144
  - Gemfile
@@ -140,7 +146,9 @@ files:
140
146
  - README.md
141
147
  - Rakefile
142
148
  - changelog.md
149
+ - lib/faraday/request/officialfm_oauth.rb
143
150
  - lib/officialfm.rb
151
+ - lib/officialfm/authentication.rb
144
152
  - lib/officialfm/client.rb
145
153
  - lib/officialfm/playlists.rb
146
154
  - lib/officialfm/tracks.rb
@@ -167,52 +175,30 @@ files:
167
175
  - test/playlists_test.rb
168
176
  - test/tracks_test.rb
169
177
  - test/users_test.rb
170
- has_rdoc: true
171
178
  homepage: http://github.com/officialfm/officialfm-ruby
172
179
  licenses: []
173
-
174
- post_install_message:
180
+ post_install_message: ! "********************************************************************************\n\n
181
+ \ Follow @ofmdev on Twitter for announcements, updates, and news.\n https://twitter.com/ofmdev\n\n
182
+ \ Don't forget to get your API key here:\n http://official.fm/developers/manager\n\n********************************************************************************\n"
175
183
  rdoc_options: []
176
-
177
- require_paths:
184
+ require_paths:
178
185
  - lib
179
- required_ruby_version: !ruby/object:Gem::Requirement
186
+ required_ruby_version: !ruby/object:Gem::Requirement
180
187
  none: false
181
- requirements:
182
- - - ">="
183
- - !ruby/object:Gem::Version
184
- version: "0"
185
- required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ! '>='
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
193
  none: false
187
- requirements:
188
- - - ">="
189
- - !ruby/object:Gem::Version
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
190
197
  version: 1.3.6
191
198
  requirements: []
192
-
193
199
  rubyforge_project:
194
- rubygems_version: 1.6.2
200
+ rubygems_version: 1.8.6
195
201
  signing_key:
196
202
  specification_version: 3
197
203
  summary: Official Ruby bindings for the official.fm API
198
- test_files:
199
- - test/fixtures/charts.json
200
- - test/fixtures/latest.json
201
- - test/fixtures/playlist.json
202
- - test/fixtures/playlist_votes.json
203
- - test/fixtures/playlists.json
204
- - test/fixtures/track.json
205
- - test/fixtures/track_votes.json
206
- - test/fixtures/tracks.json
207
- - test/fixtures/user.json
208
- - test/fixtures/user_contacts.json
209
- - test/fixtures/user_playlists.json
210
- - test/fixtures/user_subscribers.json
211
- - test/fixtures/user_subscriptions.json
212
- - test/fixtures/user_tracks.json
213
- - test/fixtures/voted_playlists.json
214
- - test/fixtures/voted_tracks.json
215
- - test/helper.rb
216
- - test/playlists_test.rb
217
- - test/tracks_test.rb
218
- - test/users_test.rb
204
+ test_files: []