hallon 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,46 @@ Hallon’s Changelog
|
|
4
4
|
[HEAD][]
|
5
5
|
------------------
|
6
6
|
|
7
|
+
[v0.16.0][]
|
8
|
+
------------------
|
9
|
+
This release brings a lot of changes to the Hallon test suite, mainly to make
|
10
|
+
it more readable and less of a mess.
|
11
|
+
|
12
|
+
__Added__
|
13
|
+
|
14
|
+
- ArtistBrowse#top_hits [5ef57a7]
|
15
|
+
- Session#flush_caches [693567]
|
16
|
+
- Track#playable_track [2d9cdfb]
|
17
|
+
- Support for playlists in search results [05f49e4]
|
18
|
+
- Support for suggestion search [1ae4b29]
|
19
|
+
- Support for unseen tracks for playlists in playlist containers [4bf8496]
|
20
|
+
- Support for login with credentials blob instead of password [61ffdf3]
|
21
|
+
|
22
|
+
__Changed__
|
23
|
+
|
24
|
+
- Removed the final `self` parameter of all libspotify events [d738a79]
|
25
|
+
- Renamed Playlist::Track#create_time to added_at [1adc2d7]
|
26
|
+
- Renamed Playlist::Track#creator to adder [1adc2d7]
|
27
|
+
- Session#offline_sync_status now returns a hash always [c14d42ae]
|
28
|
+
- Make AlbumBrowse#request_duration always return an integer [ee0697c2]
|
29
|
+
- Make ArtistBrowse#request_duration always return an integer [ee0697c2]
|
30
|
+
- Make Toplist#request_duration always return an integer [ebc64e1a]
|
31
|
+
- Track#popularity now returns a value between 0 and 100 [cd85ae7f]
|
32
|
+
- Move Session#wait_for onto Observable, now they all support it! [e14da3e]
|
33
|
+
- Make Playlist#update rely solely on callbacks [e703c132]
|
34
|
+
- Player.new no longer takes a session parameter [7508d18]
|
35
|
+
- Session.instance now raises NoSessionError on missing session [3b47b7]
|
36
|
+
- Observable#wait_for now calls original handler on events [be236bfd]
|
37
|
+
|
38
|
+
__Fixed__
|
39
|
+
|
40
|
+
- Have Playlist#subscribers always return an array [a8d26c9a]
|
41
|
+
- Fix Image#data for images with no data [e7d8627]
|
42
|
+
- Playlist::Track#message always return a string [72a644a]
|
43
|
+
- Session#login! now raises when given the wrong password [f650a36]
|
44
|
+
- Do not wrap the Session pointer in a Spotify pointer [9ae047d]
|
45
|
+
- Link.valid? segfaulting if having no session [84c9f69c]
|
46
|
+
|
7
47
|
[v0.15.0][]
|
8
48
|
------------------
|
9
49
|
Updated to libspotify v11.1.60 [3c810b0], and improved the examples provided within Hallon codebase significantly.
|
data/README.markdown
CHANGED
@@ -64,7 +64,7 @@ For more information about audio support in Hallon, see the section "Audio suppo
|
|
64
64
|
|
65
65
|
### Contact details
|
66
66
|
|
67
|
-
- __Got questions?__ Ask on the mailing list: <https://groups.google.com/d/forum/ruby-hallon>
|
67
|
+
- __Got questions?__ Ask on the mailing list: <mailto:ruby-hallon@googlegroups.com> (<https://groups.google.com/d/forum/ruby-hallon>)
|
68
68
|
- __Found a bug?__ Report an issue: <https://github.com/Burgestrand/Hallon/issues/new>
|
69
69
|
- __Have feedback?__ I ❤ feedback! Please send it to the mailing list.
|
70
70
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGF.file == STDIN
|
4
|
+
puts "You forgot to give me a file!"
|
5
|
+
abort "Usage: ruby application_key_converter.rb spotify_appkey.key > new_spotify_appkey.key"
|
6
|
+
end
|
7
|
+
|
8
|
+
old_format = ARGF.read.split.join
|
9
|
+
new_format = [old_format].pack("H*")
|
10
|
+
|
11
|
+
print new_format
|
data/examples/example_support.rb
CHANGED
data/examples/playing_audio.rb
CHANGED
@@ -11,7 +11,7 @@ rescue LoadError => e
|
|
11
11
|
abort "[ERROR] Could not load gem 'hallon-openal', please install with 'gem install hallon-openal'"
|
12
12
|
end
|
13
13
|
|
14
|
-
player = Hallon::Player.new(
|
14
|
+
player = Hallon::Player.new(Hallon::OpenAL)
|
15
15
|
|
16
16
|
# Program flow.
|
17
17
|
|
data/lib/hallon.rb
CHANGED
@@ -12,6 +12,7 @@ require 'hallon/error'
|
|
12
12
|
require 'hallon/base'
|
13
13
|
require 'hallon/enumerator'
|
14
14
|
require 'hallon/audio_queue'
|
15
|
+
require 'hallon/blob'
|
15
16
|
|
16
17
|
require 'hallon/observable/album_browse'
|
17
18
|
require 'hallon/observable/artist_browse'
|
@@ -70,6 +71,16 @@ module Hallon
|
|
70
71
|
# Thrown by {Loadable#load} and {Playlist#update} on failure.
|
71
72
|
TimeoutError = Class.new(Hallon::Error)
|
72
73
|
|
74
|
+
# Raised by Session.instance
|
75
|
+
NoSessionError = Class.new(StandardError)
|
76
|
+
|
77
|
+
# Raised by Session#login! and Session#relogin!
|
78
|
+
LoginError = Class.new(StandardError)
|
79
|
+
|
80
|
+
# Raised by PlaylistContainer#num_unseen_tracks_for and PlaylistContainer#unseen_tracks_for.
|
81
|
+
# @note most likely raised because of the playlist not being in the playlist container.
|
82
|
+
OperationFailedError = Class.new(StandardError)
|
83
|
+
|
73
84
|
class << self
|
74
85
|
# @return [Numeric] default load timeout in seconds, used in {Loadable#load}.
|
75
86
|
attr_reader :load_timeout
|
data/lib/hallon/album_browse.rb
CHANGED
@@ -77,11 +77,11 @@ module Hallon
|
|
77
77
|
end
|
78
78
|
|
79
79
|
# @note If the object is not loaded, the result is undefined.
|
80
|
-
# @
|
81
|
-
# @return [Rational, nil] time it took for the albumbrowse request to complete (in seconds).
|
80
|
+
# @return [Rational] time it took for the albumbrowse request to complete (in seconds).
|
82
81
|
def request_duration
|
83
82
|
duration = Spotify.albumbrowse_backend_request_duration(pointer)
|
84
|
-
|
83
|
+
duration = 0 if duration < 0
|
84
|
+
Rational(duration, 1000)
|
85
85
|
end
|
86
86
|
|
87
87
|
# @return [Copyrights] enumerator of copyright notices.
|
data/lib/hallon/artist_browse.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
module Hallon
|
3
|
-
# ArtistBrowse is
|
3
|
+
# An ArtistBrowse object is for retrieving details about a given artist, such
|
4
|
+
# as it’s tracks, albums, similar artists and more.
|
4
5
|
#
|
5
6
|
# @see Artist
|
6
7
|
# @see http://developer.spotify.com/en/libspotify/docs/group__artistbrowse.html
|
@@ -55,6 +56,16 @@ module Hallon
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
59
|
+
# Enumerates through all tophit tracks of an album browsing object.
|
60
|
+
class TopHits < Enumerator
|
61
|
+
size :artistbrowse_num_tophit_tracks
|
62
|
+
|
63
|
+
# @return [Track, nil]
|
64
|
+
item :artistbrowse_tophit_track! do |track|
|
65
|
+
Track.from(track)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
58
69
|
extend Observable::ArtistBrowse
|
59
70
|
include Loadable
|
60
71
|
|
@@ -107,11 +118,11 @@ module Hallon
|
|
107
118
|
end
|
108
119
|
|
109
120
|
# @note If the object is not loaded, the result is undefined.
|
110
|
-
# @
|
111
|
-
# @return [Rational, nil] time it took for the albumbrowse request to complete (in seconds).
|
121
|
+
# @return [Rational] time it took for the albumbrowse request to complete (in seconds).
|
112
122
|
def request_duration
|
113
123
|
duration = Spotify.artistbrowse_backend_request_duration(pointer)
|
114
|
-
|
124
|
+
duration = 0 if duration < 0
|
125
|
+
Rational(duration, 1000)
|
115
126
|
end
|
116
127
|
|
117
128
|
# @return [Portraits] artist portraits as {Image}s.
|
@@ -138,5 +149,10 @@ module Hallon
|
|
138
149
|
def similar_artists
|
139
150
|
SimilarArtists.new(self)
|
140
151
|
end
|
152
|
+
|
153
|
+
# @return [TopHits] enumerator of the artist’s most popular tracks.
|
154
|
+
def top_hits
|
155
|
+
TopHits.new(self)
|
156
|
+
end
|
141
157
|
end
|
142
158
|
end
|
data/lib/hallon/blob.rb
ADDED
data/lib/hallon/enumerator.rb
CHANGED
data/lib/hallon/ext/spotify.rb
CHANGED
@@ -46,6 +46,7 @@ module Spotify
|
|
46
46
|
wrap_function :track_artist, :artist
|
47
47
|
wrap_function :track_album, :album
|
48
48
|
wrap_function :localtrack_create, :track
|
49
|
+
wrap_function :track_get_playable, :track
|
49
50
|
|
50
51
|
wrap_function :album_artist, :artist
|
51
52
|
|
@@ -59,6 +60,7 @@ module Spotify
|
|
59
60
|
wrap_function :artistbrowse_track, :track
|
60
61
|
wrap_function :artistbrowse_album, :album
|
61
62
|
wrap_function :artistbrowse_similar_artist, :artist
|
63
|
+
wrap_function :artistbrowse_tophit_track, :track
|
62
64
|
|
63
65
|
wrap_function :image_create, :image
|
64
66
|
wrap_function :image_create_from_link, :image
|
data/lib/hallon/image.rb
CHANGED
@@ -71,7 +71,13 @@ module Hallon
|
|
71
71
|
def data
|
72
72
|
FFI::MemoryPointer.new(:size_t) do |size|
|
73
73
|
data = Spotify.image_data(pointer, size)
|
74
|
-
|
74
|
+
size = size.read_size_t
|
75
|
+
|
76
|
+
if size > 0
|
77
|
+
return data.read_bytes(size)
|
78
|
+
else
|
79
|
+
return "".force_encoding("BINARY")
|
80
|
+
end
|
75
81
|
end
|
76
82
|
end
|
77
83
|
|
data/lib/hallon/link.rb
CHANGED
@@ -9,6 +9,10 @@ module Hallon
|
|
9
9
|
# @param [#to_s] spotify_uri
|
10
10
|
# @return [Boolean]
|
11
11
|
def self.valid?(spotify_uri)
|
12
|
+
unless Session.instance?
|
13
|
+
raise NoSessionError, "You must have initialized a session to create links"
|
14
|
+
end
|
15
|
+
|
12
16
|
if spotify_uri.is_a?(Link)
|
13
17
|
return true
|
14
18
|
elsif spotify_uri.to_s["\x00"] # image ids
|
@@ -25,9 +29,8 @@ module Hallon
|
|
25
29
|
# @param [#to_str] uri
|
26
30
|
# @raise [ArgumentError] link could not be parsed
|
27
31
|
def initialize(uri)
|
28
|
-
# if no session instance exists, libspotify segfaults, so assert that we have one
|
29
32
|
unless Session.instance?
|
30
|
-
raise "
|
33
|
+
raise NoSessionError, "You must have initialized a session to create links"
|
31
34
|
end
|
32
35
|
|
33
36
|
# we support any #to_link’able object
|
data/lib/hallon/observable.rb
CHANGED
@@ -111,6 +111,53 @@ module Hallon
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
+
# Wait for the given callbacks to fire until the block returns true
|
115
|
+
#
|
116
|
+
# @note Given block will be called once instantly without parameters.
|
117
|
+
# @note If no events happen for 0.25 seconds, the block will be called without parameters.
|
118
|
+
# @param [Symbol, ...] *events list of events to wait for
|
119
|
+
# @yield [Symbol, *args] name of the event that fired, and its’ arguments
|
120
|
+
# @return whatever the block returns
|
121
|
+
def wait_for(*events)
|
122
|
+
channel = SizedQueue.new(10) # sized just to be safe
|
123
|
+
|
124
|
+
old_handlers = events.each_with_object({}) do |event, hash|
|
125
|
+
hash[event] = on(event) do |*args|
|
126
|
+
channel << [event, *args]
|
127
|
+
hash[event].call(*args)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
old_notify = session.on(:notify_main_thread) do
|
132
|
+
channel << :notify
|
133
|
+
end
|
134
|
+
|
135
|
+
if result = yield
|
136
|
+
return result
|
137
|
+
end
|
138
|
+
|
139
|
+
loop do
|
140
|
+
begin
|
141
|
+
timeout = [session.process_events.fdiv(1000), 2].min # scope to two seconds
|
142
|
+
timeout = timeout + 0.010 # minimum of ten miliseconds timeout
|
143
|
+
params = Timeout::timeout(timeout) { channel.pop }
|
144
|
+
redo if params == :notify
|
145
|
+
rescue Timeout::Error
|
146
|
+
params = nil
|
147
|
+
end
|
148
|
+
|
149
|
+
if result = yield(*params)
|
150
|
+
return result
|
151
|
+
end
|
152
|
+
end
|
153
|
+
ensure
|
154
|
+
old_handlers.each_pair do |event, handler|
|
155
|
+
on(event, &handler)
|
156
|
+
end unless old_handlers.nil?
|
157
|
+
session.on(:notify_main_thread, &old_notify) unless old_notify.nil?
|
158
|
+
end
|
159
|
+
|
160
|
+
|
114
161
|
# @param [#to_s] name
|
115
162
|
# @return [Boolean] true if a callback with `name` exists.
|
116
163
|
def has_callback?(name)
|
@@ -149,7 +196,7 @@ module Hallon
|
|
149
196
|
# @return whatever the handler returns
|
150
197
|
def trigger(name, *arguments, &block)
|
151
198
|
if handler = handlers[name.to_s]
|
152
|
-
handler.call(*arguments,
|
199
|
+
handler.call(*arguments, &block)
|
153
200
|
end
|
154
201
|
end
|
155
202
|
|
data/lib/hallon/player.rb
CHANGED
@@ -6,7 +6,7 @@ module Hallon
|
|
6
6
|
# controlling the playback features of libspotify.
|
7
7
|
#
|
8
8
|
# @see Session
|
9
|
-
class Player
|
9
|
+
class Player < Base
|
10
10
|
# meep?
|
11
11
|
extend Observable::Player
|
12
12
|
|
@@ -24,18 +24,17 @@ module Hallon
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
# Constructs a Player, given
|
27
|
+
# Constructs a Player, given an audio driver.
|
28
28
|
#
|
29
29
|
# @example
|
30
|
-
# player = Hallon::Player.new(
|
30
|
+
# player = Hallon::Player.new(Hallon::OpenAL)
|
31
31
|
# player.play(track)
|
32
32
|
#
|
33
33
|
# @note for instructions on how to write your own audio driver, see Hallons’ README
|
34
|
-
# @param [Session] session
|
35
34
|
# @param [AudioDriver] driver
|
36
35
|
# @yield instance_evals itself, allowing you to define callbacks using `on`
|
37
|
-
def initialize(
|
38
|
-
@session =
|
36
|
+
def initialize(driver, &block)
|
37
|
+
@session = Hallon::Session.instance
|
39
38
|
@pointer = @session.pointer
|
40
39
|
|
41
40
|
# sample rate is often (if not always) 44.1KHz, so
|
@@ -85,20 +84,20 @@ module Hallon
|
|
85
84
|
#
|
86
85
|
# Will be called after calling our buffers are full enough to support
|
87
86
|
# continous playback.
|
88
|
-
def start_playback
|
87
|
+
def start_playback
|
89
88
|
self.status = :playing
|
90
89
|
end
|
91
90
|
|
92
91
|
# Called by libspotify when the driver should pause audio playback.
|
93
92
|
#
|
94
93
|
# Might happen if we’re playing audio faster than we can stream it.
|
95
|
-
def stop_playback
|
94
|
+
def stop_playback
|
96
95
|
self.status = :paused
|
97
96
|
end
|
98
97
|
|
99
98
|
# Called by libspotify on music delivery; format is
|
100
99
|
# a hash of (sample) rate, channels and (sample) type.
|
101
|
-
def music_delivery(format, frames
|
100
|
+
def music_delivery(format, frames)
|
102
101
|
@queue.synchronize do
|
103
102
|
if frames.none?
|
104
103
|
@queue.clear
|
@@ -113,7 +112,7 @@ module Hallon
|
|
113
112
|
# Called by libspotify to request information about our
|
114
113
|
# audio buffer. Required if we want libspotify to tell
|
115
114
|
# us when we should start and stop playback.
|
116
|
-
def get_audio_buffer_stats
|
115
|
+
def get_audio_buffer_stats
|
117
116
|
drops = @driver.drops if @driver.respond_to?(:drops)
|
118
117
|
[@queue.size, drops.to_i]
|
119
118
|
end
|
@@ -192,22 +191,12 @@ module Hallon
|
|
192
191
|
# @param (see #play)
|
193
192
|
# @return (see #play)
|
194
193
|
def play!(track = nil)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
on(:end_of_track) do
|
202
|
-
monitor.synchronize do
|
203
|
-
end_of_track = true
|
204
|
-
condvar.signal
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
play(track)
|
209
|
-
condvar.wait_until { end_of_track }
|
210
|
-
end
|
194
|
+
end_of_track = false
|
195
|
+
old_callback = on(:end_of_track) { end_of_track = true }
|
196
|
+
play(track)
|
197
|
+
wait_for(:end_of_track) { end_of_track }
|
198
|
+
ensure
|
199
|
+
on(:end_of_track, &old_callback)
|
211
200
|
end
|
212
201
|
|
213
202
|
# Set preferred playback bitrate.
|
data/lib/hallon/playlist.rb
CHANGED
@@ -29,10 +29,10 @@ module Hallon
|
|
29
29
|
|
30
30
|
@index = index
|
31
31
|
@playlist_ptr = playlist_pointer
|
32
|
-
@
|
33
|
-
@message = Spotify.playlist_track_message(playlist_ptr, index)
|
32
|
+
@message = Spotify.playlist_track_message(playlist_ptr, index).to_s
|
34
33
|
@seen = Spotify.playlist_track_seen(playlist_ptr, index)
|
35
|
-
@
|
34
|
+
@added_at = Time.at(Spotify.playlist_track_create_time(playlist_ptr, index)).utc
|
35
|
+
@adder = begin
|
36
36
|
creator = Spotify.playlist_track_creator!(playlist_ptr, index)
|
37
37
|
User.from(creator)
|
38
38
|
end
|
@@ -46,11 +46,11 @@ module Hallon
|
|
46
46
|
# @return [Integer] index this track was created with.
|
47
47
|
attr_reader :index
|
48
48
|
|
49
|
-
# @return [Time] time when track at {#index} was added to playlist.
|
50
|
-
attr_reader :
|
49
|
+
# @return [Time, nil] time when track at {#index} was added to playlist.
|
50
|
+
attr_reader :added_at
|
51
51
|
|
52
52
|
# @return [User, nil] person who added track at {#index} to this playlist.
|
53
|
-
attr_reader :
|
53
|
+
attr_reader :adder
|
54
54
|
|
55
55
|
# @return [String] message attached to this track at {#index}.
|
56
56
|
attr_reader :message
|
@@ -150,24 +150,14 @@ module Hallon
|
|
150
150
|
Spotify.playlist_set_collaborative(pointer, !!collaborative)
|
151
151
|
end
|
152
152
|
|
153
|
-
#
|
154
|
-
# This method will block until libspotify says the playlist no longer
|
155
|
-
# has pending changes.
|
153
|
+
# Waits for the playlist to begin updating and blocks until it is done.
|
156
154
|
#
|
157
155
|
# @return [Playlist]
|
158
156
|
def upload(timeout = Hallon.load_timeout)
|
159
|
-
unless pending?
|
160
|
-
# libspotify has this bug where pending? returns false directly after
|
161
|
-
# adding tracks to a playlist; processing events once usually toggles
|
162
|
-
# the playlist into pending? mode
|
163
|
-
session.process_events
|
164
|
-
end
|
165
|
-
|
166
157
|
Timeout.timeout(timeout, Hallon::TimeoutError) do
|
167
|
-
|
158
|
+
wait_for(:playlist_update_in_progress) { |done| done }
|
159
|
+
self
|
168
160
|
end
|
169
|
-
|
170
|
-
self
|
171
161
|
end
|
172
162
|
|
173
163
|
# @return [Boolean] true if playlist has pending changes
|
@@ -215,7 +205,7 @@ module Hallon
|
|
215
205
|
Spotify.playlist_set_offline_mode(session.pointer, pointer, !! available_offline)
|
216
206
|
end
|
217
207
|
|
218
|
-
# @return [String]
|
208
|
+
# @return [String] playlist name, or an empty string if unavailable.
|
219
209
|
def name
|
220
210
|
Spotify.playlist_name(pointer)
|
221
211
|
end
|
@@ -258,17 +248,18 @@ module Hallon
|
|
258
248
|
def subscribers
|
259
249
|
ptr = Spotify.playlist_subscribers(pointer)
|
260
250
|
|
261
|
-
|
251
|
+
if ptr.null?
|
252
|
+
[]
|
253
|
+
else
|
262
254
|
struct = Spotify::Subscribers.new(ptr)
|
263
|
-
|
264
255
|
if struct[:count].zero?
|
265
256
|
[]
|
266
257
|
else
|
267
258
|
struct[:subscribers].map(&:read_string)
|
268
259
|
end
|
269
|
-
|
270
|
-
|
271
|
-
|
260
|
+
end
|
261
|
+
ensure
|
262
|
+
Spotify.playlist_subscribers_free(ptr) unless ptr.null?
|
272
263
|
end
|
273
264
|
|
274
265
|
# @return [Integer] total number of subscribers.
|