hallon 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.travis.yml +2 -0
- data/CHANGELOG.md +22 -1
- data/Gemfile +2 -2
- data/README.markdown +2 -2
- data/Rakefile +69 -42
- data/hallon.gemspec +1 -1
- data/lib/hallon.rb +3 -2
- data/lib/hallon/album.rb +6 -4
- data/lib/hallon/artist.rb +6 -4
- data/lib/hallon/audio_queue.rb +1 -1
- data/lib/hallon/base.rb +4 -0
- data/lib/hallon/blob.rb +6 -0
- data/lib/hallon/error.rb +10 -41
- data/lib/hallon/ext/spotify.rb +1 -146
- data/lib/hallon/image.rb +8 -0
- data/lib/hallon/linkable.rb +6 -0
- data/lib/hallon/loadable.rb +6 -0
- data/lib/hallon/observable.rb +1 -1
- data/lib/hallon/observable/playlist_container.rb +2 -2
- data/lib/hallon/observable/session.rb +34 -0
- data/lib/hallon/player.rb +7 -3
- data/lib/hallon/playlist.rb +5 -1
- data/lib/hallon/playlist_container.rb +9 -8
- data/lib/hallon/scrobbler.rb +103 -0
- data/lib/hallon/search.rb +1 -0
- data/lib/hallon/session.rb +69 -13
- data/lib/hallon/toplist.rb +1 -1
- data/lib/hallon/track.rb +2 -2
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_spec.rb +16 -0
- data/spec/hallon/artist_spec.rb +16 -0
- data/spec/hallon/base_spec.rb +1 -1
- data/spec/hallon/error_spec.rb +3 -3
- data/spec/hallon/hallon_spec.rb +1 -1
- data/spec/hallon/image_spec.rb +6 -0
- data/spec/hallon/observable/session_spec.rb +20 -0
- data/spec/hallon/scrobbler_spec.rb +119 -0
- data/spec/hallon/session_spec.rb +38 -4
- data/spec/hallon/spotify_spec.rb +0 -45
- data/spec/mockspotify.rb +6 -1
- data/spec/spec_helper.rb +4 -5
- metadata +59 -20
- data/spec/support/cover_me.rb +0 -7
data/lib/hallon/search.rb
CHANGED
data/lib/hallon/session.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'singleton'
|
3
3
|
require 'timeout'
|
4
4
|
require 'thread'
|
5
|
+
require 'uri'
|
5
6
|
|
6
7
|
module Hallon
|
7
8
|
# The Session is fundamental for all communication with Spotify.
|
@@ -82,6 +83,7 @@ module Hallon
|
|
82
83
|
# @option options [String] :cache_path ("") where to save cache files (`""` to disable)
|
83
84
|
# @option options [String] :tracefile (nil) path to libspotify API tracefile (`nil` to disable)
|
84
85
|
# @option options [String] :device_id (nil) device ID for offline synchronization (`nil` to disable)
|
86
|
+
# @option options [String] :proxy (nil) proxy URI (supports http, https, socks4, socks5)
|
85
87
|
# @option options [Bool] :load_playlists (true) load playlists into RAM on startup
|
86
88
|
# @option options [Bool] :compress_playlists (true) compress local copies of playlists
|
87
89
|
# @option options [Bool] :cache_playlist_metadata (true) cache metadata for playlists locally
|
@@ -90,6 +92,14 @@ module Hallon
|
|
90
92
|
# @raise [Hallon::Error] if `sp_session_create` fails
|
91
93
|
# @see http://developer.spotify.com/en/libspotify/docs/structsp__session__config.html
|
92
94
|
def initialize(appkey, options = {}, &block)
|
95
|
+
if options[:proxy]
|
96
|
+
proxy_uri = URI(options[:proxy])
|
97
|
+
options[:proxy_username] ||= proxy_uri.user
|
98
|
+
options[:proxy_password] ||= proxy_uri.password
|
99
|
+
proxy_uri.user = proxy_uri.password = nil
|
100
|
+
options[:proxy] = proxy_uri.to_s
|
101
|
+
end
|
102
|
+
|
93
103
|
@options = {
|
94
104
|
:user_agent => "Hallon",
|
95
105
|
:settings_path => "tmp/hallon/",
|
@@ -98,6 +108,9 @@ module Hallon
|
|
98
108
|
:compress_playlists => true,
|
99
109
|
:cache_playlist_metadata => true,
|
100
110
|
:device_id => nil,
|
111
|
+
:proxy => nil,
|
112
|
+
:proxy_username => nil,
|
113
|
+
:proxy_password => nil,
|
101
114
|
:tracefile => nil,
|
102
115
|
}.merge(options)
|
103
116
|
|
@@ -164,7 +177,7 @@ module Hallon
|
|
164
177
|
# @note it also supports logging in via a credentials blob, if you pass
|
165
178
|
# a Hallon::Blob(blob_string) as the password instead of the real password
|
166
179
|
# @param [String] username
|
167
|
-
# @param [String]
|
180
|
+
# @param [String] password your password, or user credentials blob
|
168
181
|
# @param [Boolean] remember_me have libspotify remember credentials for {#relogin}
|
169
182
|
# @return [Session]
|
170
183
|
# @see login!
|
@@ -179,10 +192,10 @@ module Hallon
|
|
179
192
|
|
180
193
|
# Login the remembered user (see {#login}).
|
181
194
|
#
|
182
|
-
# @raise [
|
195
|
+
# @raise [Spotify::Error] if no credentials are stored in libspotify
|
183
196
|
# @see #relogin!
|
184
197
|
def relogin
|
185
|
-
|
198
|
+
Spotify.session_relogin!(pointer)
|
186
199
|
end
|
187
200
|
|
188
201
|
# Log in to Spotify using the given credentials.
|
@@ -219,7 +232,13 @@ module Hallon
|
|
219
232
|
tap { wait_for(:logged_out) { logged_out? } }
|
220
233
|
end
|
221
234
|
|
222
|
-
# @return [String] username of the
|
235
|
+
# @return [String, nil] username of the currently logged in user.
|
236
|
+
def username
|
237
|
+
username = Spotify.session_user_name(pointer)
|
238
|
+
username unless username.nil? or username.empty?
|
239
|
+
end
|
240
|
+
|
241
|
+
# @return [String, nil] username of the user stored in libspotify-remembered credentials.
|
223
242
|
def remembered_user
|
224
243
|
bufflen = Spotify.session_remembered_user(pointer, nil, 0)
|
225
244
|
FFI::Buffer.alloc_out(bufflen + 1) do |b|
|
@@ -254,15 +273,30 @@ module Hallon
|
|
254
273
|
Spotify.session_connectionstate(pointer)
|
255
274
|
end
|
256
275
|
|
257
|
-
#
|
276
|
+
# @return [Boolean] true if the session is currently set to private.
|
277
|
+
def private?
|
278
|
+
Spotify.session_is_private_session(pointer)
|
279
|
+
end
|
280
|
+
alias_method :britney_spears_mode?, :private?
|
281
|
+
|
282
|
+
# Set private session.
|
258
283
|
#
|
259
|
-
# @
|
260
|
-
#
|
284
|
+
# @note mode is reverted to normal after some time without user activity,
|
285
|
+
# see official libspotify documentation for details.
|
286
|
+
# @param [Boolean] is_private
|
287
|
+
def private=(is_private)
|
288
|
+
Spotify.session_set_private_session(pointer, !! is_private)
|
289
|
+
end
|
290
|
+
alias_method :britney_spears_mode=, :private=
|
291
|
+
|
292
|
+
# Set session cache size.
|
293
|
+
#
|
294
|
+
# @param [Integer] size new session cache size, in megabytes.
|
261
295
|
def cache_size=(size)
|
262
296
|
Spotify.session_set_cache_size(pointer, @cache_size = size)
|
263
297
|
end
|
264
298
|
|
265
|
-
# @return [String] currently logged in
|
299
|
+
# @return [String] currently logged in user’s country.
|
266
300
|
def country
|
267
301
|
coded = Spotify.session_user_country(pointer)
|
268
302
|
country = ((coded >> 8) & 0xFF).chr
|
@@ -275,7 +309,10 @@ module Hallon
|
|
275
309
|
# track = Hallon::Track.new("spotify:track:2LFQV2u6wXZmmySCWBkYGu")
|
276
310
|
# session.star(track)
|
277
311
|
#
|
278
|
-
# @
|
312
|
+
# @note (see #unstar)
|
313
|
+
# @raise (see #unstar)
|
314
|
+
#
|
315
|
+
# @param [Track…] tracks
|
279
316
|
# @return [Session]
|
280
317
|
def star(*tracks)
|
281
318
|
tap { tracks_starred(tracks, true) }
|
@@ -287,7 +324,13 @@ module Hallon
|
|
287
324
|
# track = Hallon::Track.new("spotify:track:2LFQV2u6wXZmmySCWBkYGu")
|
288
325
|
# session.unstar(track)
|
289
326
|
#
|
290
|
-
# @
|
327
|
+
# @note this method might raise a Spotify::Error, however when this might
|
328
|
+
# occur is not documented in libspotify (and I have yet to find any
|
329
|
+
# way to trigger it myself). it’s entirely possible that this method
|
330
|
+
# never returns an error, but we can’t know for sure.
|
331
|
+
#
|
332
|
+
# @raise [Spotify:Error] if libspotify reports an error (when this happens is unknown and undocumented)
|
333
|
+
# @param [Track…] tracks
|
291
334
|
# @return [Session]
|
292
335
|
def unstar(*tracks)
|
293
336
|
tap { tracks_starred(tracks, false) }
|
@@ -295,6 +338,7 @@ module Hallon
|
|
295
338
|
|
296
339
|
# Set the connection rules for this session.
|
297
340
|
#
|
341
|
+
# @raise [ArgumentError] if given invalid connection rules
|
298
342
|
# @param [Symbol, …] connection_rules
|
299
343
|
# @see Session.connection_rules
|
300
344
|
def connection_rules=(connection_rules)
|
@@ -307,6 +351,7 @@ module Hallon
|
|
307
351
|
|
308
352
|
# Set the connection type for this session.
|
309
353
|
#
|
354
|
+
# @raise [ArgumentError] if given invalid connection type
|
310
355
|
# @param [Symbol] connection_type
|
311
356
|
# @see Session.connection_types
|
312
357
|
def connection_type=(connection_type)
|
@@ -345,15 +390,25 @@ module Hallon
|
|
345
390
|
|
346
391
|
# Set preferred offline bitrate.
|
347
392
|
#
|
348
|
-
# @example
|
393
|
+
# @example setting offline bitrate without resync
|
394
|
+
# session.offline_bitrate = :'96k'
|
395
|
+
#
|
396
|
+
# @example setting offline bitrate and resync already-synced tracks
|
349
397
|
# session.offline_bitrate = :'96k', true
|
350
398
|
#
|
399
|
+
# @note under normal circumstances, ArgumentError is the error that will
|
400
|
+
# be raised on an invalid bitrate. However, if Hallon fails the type
|
401
|
+
# checking (for whatever reason), libspotify will itself return an
|
402
|
+
# error as well.
|
403
|
+
#
|
404
|
+
# @raise [ArgumentError] if given invalid bitrate
|
405
|
+
# @raise [Spotify::Error] if libspotify does not accept the given bitrate (see note)
|
351
406
|
# @param [Symbol] bitrate
|
352
407
|
# @param [Boolean] resync (default: false)
|
353
408
|
# @see Player.bitrates
|
354
409
|
def offline_bitrate=(bitrate)
|
355
410
|
bitrate, resync = Array(bitrate)
|
356
|
-
Spotify.session_preferred_offline_bitrate(pointer, bitrate, !! resync)
|
411
|
+
Spotify.session_preferred_offline_bitrate!(pointer, bitrate, !! resync)
|
357
412
|
end
|
358
413
|
|
359
414
|
# @note Returns nil when no user is logged in.
|
@@ -397,12 +452,13 @@ module Hallon
|
|
397
452
|
private
|
398
453
|
# Set starred status of given tracks.
|
399
454
|
#
|
455
|
+
# @raise [Spotify::Error] … maybe, it’s undocumented in libspotify, who knows?
|
400
456
|
# @param [Array<Track>] tracks
|
401
457
|
# @param [Boolean] starred
|
402
458
|
def tracks_starred(tracks, starred)
|
403
459
|
FFI::MemoryPointer.new(:pointer, tracks.size) do |ptr|
|
404
460
|
ptr.write_array_of_pointer tracks.map(&:pointer)
|
405
|
-
Spotify.track_set_starred(pointer, ptr, tracks.size, starred)
|
461
|
+
Spotify.track_set_starred!(pointer, ptr, tracks.size, starred)
|
406
462
|
end
|
407
463
|
end
|
408
464
|
|
data/lib/hallon/toplist.rb
CHANGED
@@ -114,7 +114,7 @@ module Hallon
|
|
114
114
|
# Convert a given two-character region to a Spotify
|
115
115
|
# compliant region (encoded in a 16bit integer).
|
116
116
|
#
|
117
|
-
# @param [#to_s]
|
117
|
+
# @param [#to_s] region
|
118
118
|
# @return [Integer]
|
119
119
|
def to_country(region)
|
120
120
|
code = region.to_s.upcase
|
data/lib/hallon/track.rb
CHANGED
@@ -210,9 +210,9 @@ module Hallon
|
|
210
210
|
|
211
211
|
# Set {#starred?} status of current track.
|
212
212
|
#
|
213
|
-
# @note
|
213
|
+
# @note (see Session#star)
|
214
|
+
# @raise (see Session#star)
|
214
215
|
# @param [Boolean] starred
|
215
|
-
# @return [Boolean]
|
216
216
|
def starred=(starred)
|
217
217
|
starred ? session.star(self) : session.unstar(self)
|
218
218
|
end
|
data/lib/hallon/version.rb
CHANGED
data/spec/hallon/album_spec.rb
CHANGED
@@ -80,6 +80,14 @@ describe Hallon::Album do
|
|
80
80
|
it "should be nil if there is no image" do
|
81
81
|
empty_album.cover.should be_nil
|
82
82
|
end
|
83
|
+
|
84
|
+
it "should support specifying size" do
|
85
|
+
album.cover(:large).should eq Hallon::Image.new(mock_image_id)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should raise an error when given an invalid size" do
|
89
|
+
expect { album.cover(:lawl) }.to raise_error(ArgumentError)
|
90
|
+
end
|
83
91
|
end
|
84
92
|
|
85
93
|
describe "#cover_link" do
|
@@ -90,5 +98,13 @@ describe Hallon::Album do
|
|
90
98
|
it "should be nil if there is no image" do
|
91
99
|
empty_album.cover_link.should be_nil
|
92
100
|
end
|
101
|
+
|
102
|
+
it "should support specifying size" do
|
103
|
+
album.cover_link(:large).should eq Hallon::Link.new("spotify:image:3ad93423add99766e02d563605c6e76ed2b0e400")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should raise an error when given an invalid size" do
|
107
|
+
expect { album.cover_link(:lawl) }.to raise_error(ArgumentError)
|
108
|
+
end
|
93
109
|
end
|
94
110
|
end
|
data/spec/hallon/artist_spec.rb
CHANGED
@@ -54,6 +54,14 @@ describe Hallon::Artist do
|
|
54
54
|
it "should be nil if an image is not available" do
|
55
55
|
empty_artist.portrait.should be_nil
|
56
56
|
end
|
57
|
+
|
58
|
+
it "should support specifying size" do
|
59
|
+
artist.portrait(:large).should eq Hallon::Image.new(mock_image_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should raise an error when given an invalid size" do
|
63
|
+
expect { artist.portrait(:lawl) }.to raise_error(ArgumentError)
|
64
|
+
end
|
57
65
|
end
|
58
66
|
|
59
67
|
describe "#portrait_link" do
|
@@ -64,5 +72,13 @@ describe Hallon::Artist do
|
|
64
72
|
it "should be nil if an image is not available" do
|
65
73
|
empty_artist.portrait_link.should be_nil
|
66
74
|
end
|
75
|
+
|
76
|
+
it "should support specifying size" do
|
77
|
+
artist.portrait_link(:large).should eq Hallon::Link.new(mock_image_uri)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should raise an error when given an invalid size" do
|
81
|
+
expect { artist.portrait_link(:lawl) }.to raise_error(ArgumentError)
|
82
|
+
end
|
67
83
|
end
|
68
84
|
end
|
data/spec/hallon/base_spec.rb
CHANGED
data/spec/hallon/error_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
describe Hallon::Error do
|
2
2
|
subject { described_class }
|
3
3
|
|
4
|
-
it { should <=
|
4
|
+
it { should <= StandardError }
|
5
5
|
|
6
6
|
describe ".disambiguate" do
|
7
7
|
it "should not fail on invalid numbers" do
|
@@ -15,11 +15,11 @@ describe Hallon::Error do
|
|
15
15
|
|
16
16
|
describe ".explain" do
|
17
17
|
it "should work properly given an integer" do
|
18
|
-
subject.explain(0).should
|
18
|
+
subject.explain(0).should match 'sp_error: 0'
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should work properly given a symbol" do
|
22
|
-
subject.explain(:bad_api_version).should
|
22
|
+
subject.explain(:bad_api_version).should match 'sp_error: 1'
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/spec/hallon/hallon_spec.rb
CHANGED
data/spec/hallon/image_spec.rb
CHANGED
@@ -18,6 +18,12 @@ describe Hallon::Image do
|
|
18
18
|
|
19
19
|
specify { image.should be_a Hallon::Loadable }
|
20
20
|
|
21
|
+
describe ".sizes" do
|
22
|
+
it "should list all sizes" do
|
23
|
+
Hallon::Image.sizes.should eq [:normal, :small, :large]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
21
27
|
describe "#loaded?" do
|
22
28
|
it "returns true when the image is loaded" do
|
23
29
|
image.should be_loaded
|
@@ -144,4 +144,24 @@ describe Hallon::Observable::Session do
|
|
144
144
|
let(:input) { [a_pointer, :ok] }
|
145
145
|
let(:output) { [:ok] }
|
146
146
|
end
|
147
|
+
|
148
|
+
specification_for_callback "credentials_blob_updated" do
|
149
|
+
let(:input) { [a_pointer, "credentials"] }
|
150
|
+
let(:output) { ["credentials"] }
|
151
|
+
end
|
152
|
+
|
153
|
+
specification_for_callback "connectionstate_updated" do
|
154
|
+
let(:input) { [a_pointer] }
|
155
|
+
let(:output) { [] }
|
156
|
+
end
|
157
|
+
|
158
|
+
specification_for_callback "scrobble_error" do
|
159
|
+
let(:input) { [a_pointer, :ok] }
|
160
|
+
let(:output) { [:ok] }
|
161
|
+
end
|
162
|
+
|
163
|
+
specification_for_callback "private_session_mode_changed" do
|
164
|
+
let(:input) { [a_pointer, true] }
|
165
|
+
let(:output) { [true] }
|
166
|
+
end
|
147
167
|
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
describe Hallon::Scrobbler do
|
2
|
+
let(:scrobbling) { Hallon::Scrobbler.new(:facebook) }
|
3
|
+
|
4
|
+
describe ".providers" do
|
5
|
+
it "returns a list of social providers" do
|
6
|
+
Hallon::Scrobbler.providers.should include :facebook
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
it "raises an error if given an invalid social provider" do
|
12
|
+
expect { Hallon::Scrobbler.new(:invalid_provider) }.to raise_error(ArgumentError, /social provider/)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#provider" do
|
17
|
+
it "returns the social provider the scrobbler was instantiated with" do
|
18
|
+
scrobbling.provider.should eq :facebook
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#credentials=" do
|
23
|
+
it "sets the credentials for the scrobbler provider" do
|
24
|
+
Spotify.should_receive(:session_set_social_credentials).with(anything, :facebook, "Kim", "password").and_return(:ok)
|
25
|
+
scrobbling.credentials = "Kim", "password"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#possible?" do
|
30
|
+
it "returns true if scrobbling is possible" do
|
31
|
+
Spotify.mocksp_session_set_is_scrobbling_possible(session.pointer, scrobbling.provider, true)
|
32
|
+
scrobbling.should be_possible
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns false if scrobbling is not possible" do
|
36
|
+
Spotify.mocksp_session_set_is_scrobbling_possible(session.pointer, scrobbling.provider, false)
|
37
|
+
scrobbling.should_not be_possible
|
38
|
+
end
|
39
|
+
|
40
|
+
it "raises an error if libspotify does not like us" do
|
41
|
+
Spotify.should_receive(:session_is_scrobbling_possible).and_return(:invalid_indata)
|
42
|
+
expect { scrobbling.possible? }.to raise_error(Spotify::Error)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#enabled=" do
|
47
|
+
it "sets the local scrobbling" do
|
48
|
+
scrobbling.should_not be_enabled
|
49
|
+
scrobbling.enabled = true
|
50
|
+
scrobbling.should be_enabled
|
51
|
+
scrobbling.enabled = false
|
52
|
+
scrobbling.should_not be_enabled
|
53
|
+
end
|
54
|
+
|
55
|
+
it "raises an error if setting scrobbling state fails" do
|
56
|
+
Spotify.should_receive(:session_set_scrobbling).and_return(:invalid_indata)
|
57
|
+
expect { scrobbling.enabled = true }.to raise_error(Spotify::Error, /INVALID_INDATA/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#enabled?" do
|
62
|
+
before do
|
63
|
+
Spotify.should_receive(:session_is_scrobbling).and_return do |session, provider, buffer|
|
64
|
+
buffer.write_int(Spotify.enum_value(state_symbol))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "if the state is locally enabled" do
|
69
|
+
let(:state_symbol) { :local_enabled }
|
70
|
+
|
71
|
+
it "returns true" do
|
72
|
+
scrobbling.should be_enabled
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "if the state is locally disabled" do
|
77
|
+
let(:state_symbol) { :local_disabled }
|
78
|
+
|
79
|
+
it "returns false" do
|
80
|
+
scrobbling.should_not be_enabled
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "if the state is globally enabled" do
|
85
|
+
let(:state_symbol) { :global_enabled }
|
86
|
+
|
87
|
+
it "returns true" do
|
88
|
+
scrobbling.should be_enabled
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "if the state is globally disabled" do
|
93
|
+
let(:state_symbol) { :global_disabled }
|
94
|
+
|
95
|
+
it "returns false" do
|
96
|
+
scrobbling.should_not be_enabled
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#reset" do
|
102
|
+
def state(scrobbler)
|
103
|
+
session = scrobbling.send(:session)
|
104
|
+
state = nil
|
105
|
+
FFI::Buffer.alloc_out(:int) do |buffer|
|
106
|
+
Spotify.session_is_scrobbling!(session.pointer, scrobbling.provider, buffer)
|
107
|
+
state = buffer.read_int
|
108
|
+
end
|
109
|
+
Spotify.enum_type(:scrobbling_state)[state]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "sets the local scrobbling state to use the global state" do
|
113
|
+
scrobbling.enabled = true
|
114
|
+
state(scrobbling).should eq :local_enabled
|
115
|
+
scrobbling.reset
|
116
|
+
state(scrobbling).should eq :global_enabled
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|