hallon 0.15.0 → 0.16.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 +40 -0
- data/README.markdown +1 -1
- data/dev/application_key_converter.rb +11 -0
- data/examples/example_support.rb +4 -0
- data/examples/playing_audio.rb +1 -1
- data/lib/hallon.rb +11 -0
- data/lib/hallon/album_browse.rb +3 -3
- data/lib/hallon/artist_browse.rb +20 -4
- data/lib/hallon/blob.rb +11 -0
- data/lib/hallon/enumerator.rb +5 -0
- data/lib/hallon/ext/spotify.rb +2 -0
- data/lib/hallon/image.rb +7 -1
- data/lib/hallon/link.rb +5 -2
- data/lib/hallon/observable.rb +48 -1
- data/lib/hallon/player.rb +15 -26
- data/lib/hallon/playlist.rb +16 -25
- data/lib/hallon/playlist_container.rb +38 -0
- data/lib/hallon/search.rb +75 -4
- data/lib/hallon/session.rb +31 -42
- data/lib/hallon/toplist.rb +3 -3
- data/lib/hallon/track.rb +28 -10
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +68 -18
- data/spec/hallon/album_spec.rb +62 -27
- data/spec/hallon/artist_browse_spec.rb +106 -31
- data/spec/hallon/artist_spec.rb +32 -18
- data/spec/hallon/blob_spec.rb +6 -0
- data/spec/hallon/enumerator_spec.rb +10 -0
- data/spec/hallon/error_spec.rb +4 -4
- data/spec/hallon/hallon_spec.rb +1 -1
- data/spec/hallon/image_spec.rb +58 -47
- data/spec/hallon/link_spec.rb +51 -43
- data/spec/hallon/observable/album_browse_spec.rb +1 -1
- data/spec/hallon/observable/artist_browse_spec.rb +1 -1
- data/spec/hallon/observable/image_spec.rb +1 -1
- data/spec/hallon/observable/playlist_container_spec.rb +4 -4
- data/spec/hallon/observable/playlist_spec.rb +14 -14
- data/spec/hallon/observable/post_spec.rb +1 -1
- data/spec/hallon/observable/search_spec.rb +1 -1
- data/spec/hallon/observable/session_spec.rb +17 -17
- data/spec/hallon/observable/toplist_spec.rb +1 -1
- data/spec/hallon/observable_spec.rb +40 -6
- data/spec/hallon/player_spec.rb +1 -1
- data/spec/hallon/playlist_container_spec.rb +96 -13
- data/spec/hallon/playlist_spec.rb +180 -45
- data/spec/hallon/search_spec.rb +211 -28
- data/spec/hallon/session_spec.rb +44 -38
- data/spec/hallon/toplist_spec.rb +31 -14
- data/spec/hallon/track_spec.rb +159 -50
- data/spec/hallon/user_post_spec.rb +10 -5
- data/spec/hallon/user_spec.rb +60 -50
- data/spec/spec_helper.rb +40 -15
- data/spec/support/album_mocks.rb +30 -0
- data/spec/support/artist_mocks.rb +36 -0
- data/spec/support/common_objects.rb +0 -201
- data/spec/support/image_mocks.rb +34 -0
- data/spec/support/playlist_container_mocks.rb +36 -0
- data/spec/support/playlist_mocks.rb +70 -0
- data/spec/support/search_mocks.rb +23 -0
- data/spec/support/session_mocks.rb +33 -0
- data/spec/support/toplist_mocks.rb +19 -0
- data/spec/support/track_mocks.rb +28 -0
- data/spec/support/user_mocks.rb +20 -0
- metadata +40 -18
- data/spec/support/context_stub_session.rb +0 -5
@@ -289,6 +289,44 @@ module Hallon
|
|
289
289
|
symbol == :ok
|
290
290
|
end
|
291
291
|
|
292
|
+
# Retrieve the number of unseen tracks for the given playlist.
|
293
|
+
#
|
294
|
+
# @param [Playlist] playlist
|
295
|
+
# @return [Integer] number of unseen tracks
|
296
|
+
def unseen_tracks_count_for(playlist)
|
297
|
+
Spotify.playlistcontainer_get_unseen_tracks(pointer, playlist.pointer, nil, 0).tap do |count|
|
298
|
+
raise OperationFailedError if count < 0
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# Retrieve the unseen tracks for the given playlist.
|
303
|
+
#
|
304
|
+
# @note The playlist must be in this container, or this method will fail.
|
305
|
+
# @see clear_unseen_tracks_for
|
306
|
+
# @param [Playlist] playlist
|
307
|
+
# @return [Array<Track>] array of unseen tracks.
|
308
|
+
def unseen_tracks_for(playlist, count = unseen_tracks_count_for(playlist))
|
309
|
+
tracks_ary = FFI::MemoryPointer.new(:pointer, count)
|
310
|
+
real_count = Spotify.playlistcontainer_get_unseen_tracks(pointer, playlist.pointer, tracks_ary, count)
|
311
|
+
raise OperationFailedError if real_count < 0
|
312
|
+
tracks_ary.read_array_of_pointer([real_count, count].min).map do |track|
|
313
|
+
track_pointer = Spotify::Pointer.new(track, :track, true)
|
314
|
+
Hallon::Track.new(track_pointer)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# Clears the unseen tracks for the given playlist.
|
319
|
+
#
|
320
|
+
# @note in libspotify v11.1.60, this method appears to do nothing
|
321
|
+
# @param [Playlist] playlist
|
322
|
+
# @return [PlaylistContainer] self
|
323
|
+
def clear_unseen_tracks_for(playlist)
|
324
|
+
tap do
|
325
|
+
result = Spotify.playlistcontainer_clear_unseen_tracks(pointer, playlist.pointer)
|
326
|
+
raise OperationFailedError if result < 0
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
292
330
|
protected
|
293
331
|
# Wrapper for original API; adjusts indices accordingly.
|
294
332
|
#
|
data/lib/hallon/search.rb
CHANGED
@@ -52,6 +52,49 @@ module Hallon
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
class PlaylistEnumerator < Enumerator
|
56
|
+
size :search_num_playlists
|
57
|
+
|
58
|
+
# @return [Integer] total playlists available from connected search result.
|
59
|
+
def total
|
60
|
+
Spotify.search_total_playlists(pointer)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Enumerates through all playlist names of a search object.
|
65
|
+
class PlaylistNames < PlaylistEnumerator
|
66
|
+
# @return [String, nil]
|
67
|
+
item :search_playlist_name
|
68
|
+
end
|
69
|
+
|
70
|
+
# Enumerates through all playlist uris of a search object.
|
71
|
+
class PlaylistUris < PlaylistEnumerator
|
72
|
+
# @return [String, nil]
|
73
|
+
item :search_playlist_uri
|
74
|
+
end
|
75
|
+
|
76
|
+
# Enumerates through all playlist image uris of a search object.
|
77
|
+
class PlaylistImageUris < PlaylistEnumerator
|
78
|
+
# @return [String, nil]
|
79
|
+
item :search_playlist_image_uri
|
80
|
+
end
|
81
|
+
|
82
|
+
# Enumerates through all playlists of a search object.
|
83
|
+
class Playlists < PlaylistEnumerator
|
84
|
+
# @return [Playlist]
|
85
|
+
item :search_playlist_uri do |uri|
|
86
|
+
Playlist.from(uri)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Enumerates through all playlist images of a search object.
|
91
|
+
class Images < PlaylistEnumerator
|
92
|
+
# @return [Playlist]
|
93
|
+
item :search_playlist_image_uri do |uri|
|
94
|
+
Image.from(uri)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
55
98
|
include Linkable
|
56
99
|
|
57
100
|
to_link :from_search
|
@@ -74,7 +117,8 @@ module Hallon
|
|
74
117
|
:tracks_offset => 0,
|
75
118
|
:albums_offset => 0,
|
76
119
|
:artists_offset => 0,
|
77
|
-
:playlists_offset => 0
|
120
|
+
:playlists_offset => 0,
|
121
|
+
:type => :standard
|
78
122
|
}
|
79
123
|
end
|
80
124
|
|
@@ -82,6 +126,7 @@ module Hallon
|
|
82
126
|
#
|
83
127
|
# @param [String, Link] search search query or spotify URI
|
84
128
|
# @param [Hash] options additional search options
|
129
|
+
# @option options [Symbol] :type (:standard) search type, either standard or suggest
|
85
130
|
# @option options [#to_i] :tracks (25) max number of tracks you want in result
|
86
131
|
# @option options [#to_i] :albums (25) max number of albums you want in result
|
87
132
|
# @option options [#to_i] :artists (25) max number of artists you want in result
|
@@ -93,6 +138,7 @@ module Hallon
|
|
93
138
|
# @see http://developer.spotify.com/en/libspotify/docs/group__search.html#gacf0b5e902e27d46ef8b1f40e332766df
|
94
139
|
def initialize(search, options = {})
|
95
140
|
opts = Search.defaults.merge(options)
|
141
|
+
type = opts.delete(:type)
|
96
142
|
opts = opts.values_at(:tracks_offset, :tracks, :albums_offset, :albums, :artists_offset, :artists, :playlists_offset, :playlists).map(&:to_i)
|
97
143
|
search = from_link(search) if Link.valid?(search)
|
98
144
|
|
@@ -100,7 +146,7 @@ module Hallon
|
|
100
146
|
@pointer = if Spotify::Pointer.typechecks?(search, :search)
|
101
147
|
search
|
102
148
|
else
|
103
|
-
Spotify.search_create!(session.pointer, search, *opts,
|
149
|
+
Spotify.search_create!(session.pointer, search, *opts, type, callback, nil)
|
104
150
|
end
|
105
151
|
|
106
152
|
raise ArgumentError, "search with #{search} failed" if @pointer.null?
|
@@ -120,12 +166,12 @@ module Hallon
|
|
120
166
|
|
121
167
|
# @return [String] search query this search was created with.
|
122
168
|
def query
|
123
|
-
Spotify.search_query(pointer)
|
169
|
+
Spotify.search_query(pointer).to_s
|
124
170
|
end
|
125
171
|
|
126
172
|
# @return [String] “did you mean?” suggestion for current search.
|
127
173
|
def did_you_mean
|
128
|
-
Spotify.search_did_you_mean(pointer)
|
174
|
+
Spotify.search_did_you_mean(pointer).to_s
|
129
175
|
end
|
130
176
|
|
131
177
|
# @return [Tracks] list of all tracks in the search result.
|
@@ -142,5 +188,30 @@ module Hallon
|
|
142
188
|
def artists
|
143
189
|
Artists.new(self)
|
144
190
|
end
|
191
|
+
|
192
|
+
# @return [PlaylistNames] list of all playlist names in the search result.
|
193
|
+
def playlist_names
|
194
|
+
PlaylistNames.new(self)
|
195
|
+
end
|
196
|
+
|
197
|
+
# @return [PlaylistUris] list of all playlist uris in the search result.
|
198
|
+
def playlist_uris
|
199
|
+
PlaylistUris.new(self)
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [PlaylistImageUris] list of all playlist image uris in the search result.
|
203
|
+
def playlist_image_uris
|
204
|
+
PlaylistImageUris.new(self)
|
205
|
+
end
|
206
|
+
|
207
|
+
# @return [Playlists] list of all playlists in the search result.
|
208
|
+
def playlists
|
209
|
+
Playlists.new(self)
|
210
|
+
end
|
211
|
+
|
212
|
+
# @return [Images] list of all images in the search result.
|
213
|
+
def playlist_images
|
214
|
+
Images.new(self)
|
215
|
+
end
|
145
216
|
end
|
146
217
|
end
|
data/lib/hallon/session.rb
CHANGED
@@ -55,7 +55,7 @@ module Hallon
|
|
55
55
|
#
|
56
56
|
# @return [Session]
|
57
57
|
def Session.instance
|
58
|
-
@__instance__ or raise "Session has not been initialized"
|
58
|
+
@__instance__ or raise NoSessionError, "Session has not been initialized"
|
59
59
|
end
|
60
60
|
|
61
61
|
# @return [Boolean] true if a Session instance exists.
|
@@ -120,11 +120,20 @@ module Hallon
|
|
120
120
|
# You pass a pointer to the session pointer to libspotify >:)
|
121
121
|
FFI::MemoryPointer.new(:pointer) do |p|
|
122
122
|
Error::maybe_raise Spotify.session_create(config, p)
|
123
|
-
@pointer =
|
123
|
+
@pointer = p.read_pointer
|
124
124
|
end
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
|
+
# Flushes the Session cache to disk.
|
129
|
+
#
|
130
|
+
# @note libspotify does this automatically periodically, under normal
|
131
|
+
# circumstances this method should not need to be used.
|
132
|
+
# @return [Session]
|
133
|
+
def flush_caches
|
134
|
+
Spotify.session_flush_caches(pointer)
|
135
|
+
end
|
136
|
+
|
128
137
|
# PlaylistContainer for the currently logged in session.
|
129
138
|
#
|
130
139
|
# @note returns nil if the session is not logged in.
|
@@ -144,43 +153,18 @@ module Hallon
|
|
144
153
|
end
|
145
154
|
end
|
146
155
|
|
147
|
-
# Wait for the given callbacks to fire until the block returns true
|
148
|
-
#
|
149
|
-
# @note Given block will be called once instantly without parameters.
|
150
|
-
# @note If no events happen for 0.25 seconds, the given block will be called
|
151
|
-
# with `:timeout` as parameter.
|
152
|
-
# @param [Symbol, ...] *events list of events to wait for
|
153
|
-
# @yield [Symbol, *args] name of the callback that fired, and its’ arguments
|
154
|
-
# @return [Hash<Event, Arguments>]
|
155
|
-
def process_events_on(*events)
|
156
|
-
yield or protecting_handlers do
|
157
|
-
channel = SizedQueue.new(1)
|
158
|
-
block = proc { |*args| channel << args }
|
159
|
-
events.each { |event| on(event, &block) }
|
160
|
-
on(:notify_main_thread) { channel << :notify }
|
161
|
-
|
162
|
-
loop do
|
163
|
-
begin
|
164
|
-
timeout = [process_events.fdiv(1000), 5].min # scope to five seconds
|
165
|
-
timeout = timeout + 0.010 # minimum of ten miliseconds timeout
|
166
|
-
params = Timeout::timeout(timeout) { channel.pop }
|
167
|
-
redo if params == :notify
|
168
|
-
rescue Timeout::Error
|
169
|
-
params = :timeout
|
170
|
-
end
|
171
|
-
|
172
|
-
if result = yield(*params)
|
173
|
-
return result
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
alias :wait_for :process_events_on
|
179
|
-
|
180
156
|
# Log into Spotify using the given credentials.
|
181
157
|
#
|
158
|
+
# @example logging in with password
|
159
|
+
# session.login 'Kim', 'password'
|
160
|
+
#
|
161
|
+
# @example logging in with credentials blob
|
162
|
+
# session.login 'Kim', Hallon::Blob('blob string')
|
163
|
+
#
|
164
|
+
# @note it also supports logging in via a credentials blob, if you pass
|
165
|
+
# a Hallon::Blob(blob_string) as the password instead of the real password
|
182
166
|
# @param [String] username
|
183
|
-
# @param [String]
|
167
|
+
# @param [String] password_or_blob
|
184
168
|
# @param [Boolean] remember_me have libspotify remember credentials for {#relogin}
|
185
169
|
# @return [Session]
|
186
170
|
# @see login!
|
@@ -189,7 +173,8 @@ module Hallon
|
|
189
173
|
raise ArgumentError, "username and password may not be blank"
|
190
174
|
end
|
191
175
|
|
192
|
-
|
176
|
+
password, blob = blob, password if password.is_a?(Blob)
|
177
|
+
tap { Spotify.session_login(pointer, username, password, remember_me, blob) }
|
193
178
|
end
|
194
179
|
|
195
180
|
# Login the remembered user (see {#login}).
|
@@ -221,7 +206,8 @@ module Hallon
|
|
221
206
|
# @raise [Error] if failed to log in
|
222
207
|
# @see #relogin
|
223
208
|
def relogin!
|
224
|
-
|
209
|
+
relogin
|
210
|
+
tap { wait_until_logged_in }
|
225
211
|
end
|
226
212
|
|
227
213
|
# Log out the current user.
|
@@ -229,7 +215,8 @@ module Hallon
|
|
229
215
|
# @note This method will not return until you’ve logged out successfully.
|
230
216
|
# @return [Session]
|
231
217
|
def logout!
|
232
|
-
|
218
|
+
logout
|
219
|
+
tap { wait_for(:logged_out) { logged_out? } }
|
233
220
|
end
|
234
221
|
|
235
222
|
# @return [String] username of the user stored in libspotify-remembered credentials.
|
@@ -335,12 +322,14 @@ module Hallon
|
|
335
322
|
|
336
323
|
# Offline synchronization status.
|
337
324
|
#
|
338
|
-
# @return [Hash
|
325
|
+
# @return [Hash] sync status (empty hash if not applicable)
|
339
326
|
# @see http://developer.spotify.com/en/libspotify/docs/structsp__offline__sync__status.html
|
340
327
|
def offline_sync_status
|
341
328
|
struct = Spotify::OfflineSyncStatus.new
|
342
329
|
if Spotify.offline_sync_get_status(pointer, struct.pointer)
|
343
330
|
Hash[struct.members.zip(struct.values)]
|
331
|
+
else
|
332
|
+
{}
|
344
333
|
end
|
345
334
|
end
|
346
335
|
|
@@ -424,8 +413,8 @@ module Hallon
|
|
424
413
|
# @see login!
|
425
414
|
# @see relogin!
|
426
415
|
def wait_until_logged_in
|
427
|
-
wait_for(:connection_error) do |error|
|
428
|
-
Error.maybe_raise(error
|
416
|
+
wait_for(:logged_in, :connection_error) do |event, error|
|
417
|
+
Error.maybe_raise(error)
|
429
418
|
session.logged_in?
|
430
419
|
end
|
431
420
|
end
|
data/lib/hallon/toplist.rb
CHANGED
@@ -103,11 +103,11 @@ module Hallon
|
|
103
103
|
end
|
104
104
|
|
105
105
|
# @note If the object is not loaded, the result is undefined.
|
106
|
-
# @
|
107
|
-
# @return [Rational, nil] time it took for the toplistbrowse request to complete (in seconds).
|
106
|
+
# @return [Rational] time it took for the toplistbrowse request to complete (in seconds).
|
108
107
|
def request_duration
|
109
108
|
duration = Spotify.toplistbrowse_backend_request_duration(pointer)
|
110
|
-
|
109
|
+
duration = 0 if duration < 0
|
110
|
+
Rational(duration, 1000)
|
111
111
|
end
|
112
112
|
|
113
113
|
private
|
data/lib/hallon/track.rb
CHANGED
@@ -50,6 +50,24 @@ module Hallon
|
|
50
50
|
|
51
51
|
# Create a new local track.
|
52
52
|
#
|
53
|
+
# Local tracks in Spotify allows you to specify title, artist, and
|
54
|
+
# optionally also album and length. This will create a local track
|
55
|
+
# (meaning {Track#local?} returns true) that libspotify will try to
|
56
|
+
# match up with an *actual* track in the Spotify database.
|
57
|
+
#
|
58
|
+
# If the track is successfully matched, once loaded, {Track#available?}
|
59
|
+
# will return true and you’ll be able to inspect the track’s {#artist}
|
60
|
+
# and {#album}, as well as the information in the track itself. If the
|
61
|
+
# track is playable you’ll also be able to play it!
|
62
|
+
#
|
63
|
+
# @example creating a local track
|
64
|
+
# track = Hallon::Track.local "Californication", "Red Hot Chili Peppers"
|
65
|
+
# puts track.artist.name # => "Red Hot Chili Peppers"
|
66
|
+
# puts track.album.name # => "Californication"
|
67
|
+
# p track.local? # => true
|
68
|
+
#
|
69
|
+
# @note I’ve been unable to get local tracks to get matched up in libspotify v11,
|
70
|
+
# it’s possible this function does not work properly in libspotify v11.
|
53
71
|
# @param [String] title
|
54
72
|
# @param [String] artist
|
55
73
|
# @param [String] album
|
@@ -60,7 +78,6 @@ module Hallon
|
|
60
78
|
new(track)
|
61
79
|
end
|
62
80
|
|
63
|
-
# @note This’ll be an empty string unless the track is loaded.
|
64
81
|
# @return [String]
|
65
82
|
def name
|
66
83
|
Spotify.track_name(pointer)
|
@@ -68,23 +85,22 @@ module Hallon
|
|
68
85
|
|
69
86
|
# Duration of the track in seconds.
|
70
87
|
#
|
71
|
-
# @note This’ll be `0` unless the track is loaded.
|
72
88
|
# @return [Rational]
|
73
89
|
def duration
|
74
90
|
Rational(Spotify.track_duration(pointer), 1000)
|
75
91
|
end
|
76
92
|
|
77
|
-
# Track popularity, between 0 and
|
93
|
+
# Track popularity, between 0 and 100.
|
78
94
|
#
|
79
|
-
# @note This’ll be `0` unless the track is loaded.
|
80
95
|
# @return [Rational]
|
81
96
|
def popularity
|
82
|
-
|
97
|
+
Spotify.track_popularity(pointer)
|
83
98
|
end
|
84
99
|
|
85
100
|
# Disc number this track appears in.
|
86
101
|
#
|
87
102
|
# @note This function is a bit special. See libspotify docs for details.
|
103
|
+
# @return [Integer] disc index from album this track appears in.
|
88
104
|
def disc
|
89
105
|
Spotify.track_disc(pointer)
|
90
106
|
end
|
@@ -139,7 +155,6 @@ module Hallon
|
|
139
155
|
Spotify.track_offline_get_status(pointer)
|
140
156
|
end
|
141
157
|
|
142
|
-
# @note This’ll be `nil` unless the track is loaded.
|
143
158
|
# @return [Hallon::Album] album this track belongs to.
|
144
159
|
def album
|
145
160
|
album = Spotify.track_album!(pointer)
|
@@ -153,13 +168,11 @@ module Hallon
|
|
153
168
|
artists.first
|
154
169
|
end
|
155
170
|
|
156
|
-
# @note Track must be loaded, or you’ll get zero artists.
|
157
171
|
# @return [Artists] all {Artist}s who performed this Track.
|
158
172
|
def artists
|
159
173
|
Artists.new(self)
|
160
174
|
end
|
161
175
|
|
162
|
-
# @note This’ll always return false unless the track is loaded.
|
163
176
|
# @return [Boolean] true if {#availability} is available.
|
164
177
|
def available?
|
165
178
|
availability == :available
|
@@ -172,13 +185,18 @@ module Hallon
|
|
172
185
|
Spotify.track_get_availability(session.pointer, pointer)
|
173
186
|
end
|
174
187
|
|
175
|
-
# @
|
188
|
+
# @see autolinked?
|
189
|
+
# @return [Track] the track this track is autolinked to for audio playback.
|
190
|
+
def playable_track
|
191
|
+
track = Spotify.track_get_playable!(session.pointer, pointer)
|
192
|
+
Track.from(track)
|
193
|
+
end
|
194
|
+
|
176
195
|
# @return [Boolean] true if the track is a local track.
|
177
196
|
def local?
|
178
197
|
Spotify.track_is_local(session.pointer, pointer)
|
179
198
|
end
|
180
199
|
|
181
|
-
# @note This’ll always return false unless the track is loaded.
|
182
200
|
# @return [Boolean] true if the track is autolinked.
|
183
201
|
def autolinked?
|
184
202
|
Spotify.track_is_autolinked(session.pointer, pointer)
|
data/lib/hallon/version.rb
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::AlbumBrowse do
|
3
|
-
|
3
|
+
let(:browse) do
|
4
|
+
album = Hallon::Album.new(mock_albums[:default])
|
5
|
+
Hallon::AlbumBrowse.new(album)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:empty_browse) do
|
9
|
+
album = Hallon::Album.new(mock_albums[:empty])
|
10
|
+
Hallon::AlbumBrowse.new(album)
|
11
|
+
end
|
12
|
+
|
13
|
+
specify { browse.should be_a Hallon::Loadable }
|
4
14
|
|
5
15
|
describe ".new" do
|
6
16
|
it "should raise an error if the browse request failed" do
|
7
17
|
Spotify.should_receive(:albumbrowse_create).and_return(null_pointer)
|
8
|
-
expect {
|
18
|
+
expect { Hallon::AlbumBrowse.new(mock_album) }.to raise_error(FFI::NullPointerError)
|
9
19
|
end
|
10
20
|
|
11
21
|
it "should raise an error given a non-album spotify pointer" do
|
@@ -13,31 +23,71 @@ describe Hallon::AlbumBrowse do
|
|
13
23
|
end
|
14
24
|
end
|
15
25
|
|
16
|
-
|
17
|
-
album
|
18
|
-
|
26
|
+
describe "#loaded?" do
|
27
|
+
it "is true when the album browser is loaded" do
|
28
|
+
browse.should be_loaded
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#status" do
|
33
|
+
it "returns the album status" do
|
34
|
+
browse.status.should eq :ok
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#album" do
|
39
|
+
it "returns the album" do
|
40
|
+
browse.album.should eq Hallon::Album.new(mock_albums[:default])
|
41
|
+
end
|
19
42
|
end
|
20
43
|
|
21
|
-
|
44
|
+
describe "#artist" do
|
45
|
+
it "returns the album’s artist" do
|
46
|
+
browse.artist.should eq Hallon::Artist.new(mock_artists[:default])
|
47
|
+
end
|
22
48
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
49
|
+
it "returns nil if the album browser is not loaded" do
|
50
|
+
empty_browse.artist.should be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#review" do
|
55
|
+
it "returns the album’s review" do
|
56
|
+
browse.review.should eq "This album is AWESOME"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns an empty string if the album browser is not loaded" do
|
60
|
+
empty_browse.review.should be_empty
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#copyrights" do
|
65
|
+
it "returns an enumerator of the album’s copyright texts" do
|
66
|
+
browse.copyrights.to_a.should eq %w[Kim Elin]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns an empty enumerator when the album browser is not loaded" do
|
70
|
+
empty_browse.copyrights.size.should eq 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#tracks" do
|
75
|
+
it "returns an enumerator of the album’s tracks" do
|
76
|
+
browse.tracks.to_a.should eq instantiate(Hallon::Track, mock_track, mock_track_two)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns an empty enumerator if the album browser is not loaded" do
|
80
|
+
empty_browse.tracks.size.should eq 0
|
81
|
+
end
|
82
|
+
end
|
32
83
|
|
33
84
|
describe "#request_duration" do
|
34
85
|
it "should return the request duration in seconds" do
|
35
86
|
browse.request_duration.should eq 2.751
|
36
87
|
end
|
37
88
|
|
38
|
-
it "should be
|
39
|
-
|
40
|
-
browse.request_duration.should be_nil
|
89
|
+
it "should be zero if the request was fetched from local cache" do
|
90
|
+
empty_browse.request_duration.should eq 0
|
41
91
|
end
|
42
92
|
end
|
43
93
|
end
|