hallon 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +16 -0
- data/lib/hallon/album.rb +4 -4
- data/lib/hallon/album_browse.rb +3 -1
- data/lib/hallon/artist.rb +2 -2
- data/lib/hallon/artist_browse.rb +2 -0
- data/lib/hallon/linkable.rb +6 -10
- data/lib/hallon/playlist.rb +48 -38
- data/lib/hallon/playlist_container.rb +46 -2
- data/lib/hallon/user.rb +11 -10
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +12 -1
- data/spec/hallon/album_spec.rb +3 -0
- data/spec/hallon/artist_browse_spec.rb +7 -0
- data/spec/hallon/artist_spec.rb +5 -5
- data/spec/hallon/linkable_spec.rb +13 -0
- data/spec/hallon/playlist_container_spec.rb +35 -7
- data/spec/hallon/playlist_spec.rb +20 -11
- data/spec/hallon/session_spec.rb +1 -2
- data/spec/hallon/user_spec.rb +15 -0
- data/spec/mockspotify.rb +14 -3
- data/spec/support/common_objects.rb +11 -2
- metadata +14 -14
data/CHANGELOG
CHANGED
@@ -1,6 +1,22 @@
|
|
1
1
|
Hallon’s Changelog
|
2
2
|
==================
|
3
3
|
|
4
|
+
v0.9.1
|
5
|
+
------------------
|
6
|
+
[ Added ]
|
7
|
+
- PlaylistContainer#size
|
8
|
+
- User#published
|
9
|
+
- PlaylistContainer#contents (only for playlists)
|
10
|
+
- PlaylistContainer#add (existing playlist, new playlist)
|
11
|
+
|
12
|
+
[ Changed ]
|
13
|
+
- Playlist#seen now moved to Playlist::Track#seen=
|
14
|
+
|
15
|
+
[ Fixed ]
|
16
|
+
- Album#cover null pointer issue (https://github.com/Burgestrand/Hallon/issues/53)
|
17
|
+
- Various possible null pointer bugs
|
18
|
+
|
19
|
+
|
4
20
|
v0.9.0
|
5
21
|
------------------
|
6
22
|
- Upgraded to libspotify *v10*
|
data/lib/hallon/album.rb
CHANGED
@@ -83,11 +83,11 @@ module Hallon
|
|
83
83
|
# @return [Image, Link, nil] album cover, the link to it, or nil.
|
84
84
|
def cover(as_image = true)
|
85
85
|
if as_image
|
86
|
-
|
87
|
-
Image.new
|
86
|
+
cover = Spotify.album_cover(pointer)
|
87
|
+
Image.new cover.read_string(20) unless cover.null?
|
88
88
|
else
|
89
|
-
|
90
|
-
Link.new
|
89
|
+
cover = Spotify.link_create_from_album_cover!(pointer)
|
90
|
+
Link.new cover unless cover.null?
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
data/lib/hallon/album_browse.rb
CHANGED
@@ -24,6 +24,8 @@ module Hallon
|
|
24
24
|
|
25
25
|
@callback = proc { trigger(:load) }
|
26
26
|
@pointer = Spotify.albumbrowse_create!(session.pointer, pointer, @callback, nil)
|
27
|
+
|
28
|
+
raise FFI::NullPointerError, "album browsing failed" if @pointer.null?
|
27
29
|
end
|
28
30
|
|
29
31
|
# @return [Boolean] true if the album browser is loaded.
|
@@ -75,7 +77,7 @@ module Hallon
|
|
75
77
|
size = Spotify.albumbrowse_num_tracks(pointer)
|
76
78
|
Enumerator.new(size) do |i|
|
77
79
|
track = Spotify.albumbrowse_track!(pointer, i)
|
78
|
-
Track.new(track)
|
80
|
+
Track.new(track)
|
79
81
|
end
|
80
82
|
end
|
81
83
|
end
|
data/lib/hallon/artist.rb
CHANGED
@@ -49,10 +49,10 @@ module Hallon
|
|
49
49
|
def portrait(as_image = true)
|
50
50
|
if as_image
|
51
51
|
portrait = Spotify.artist_portrait(pointer)
|
52
|
-
Image.new
|
52
|
+
Image.new portrait.read_bytes(20) unless portrait.null?
|
53
53
|
else
|
54
54
|
portrait = Spotify.link_create_from_artist_portrait!(pointer)
|
55
|
-
Link.new
|
55
|
+
Link.new portrait unless portrait.null?
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
data/lib/hallon/artist_browse.rb
CHANGED
@@ -28,6 +28,8 @@ module Hallon
|
|
28
28
|
|
29
29
|
@callback = proc { trigger(:load) }
|
30
30
|
@pointer = Spotify.artistbrowse_create!(session.pointer, pointer, type, @callback, nil)
|
31
|
+
|
32
|
+
raise FFI::NullPointerError, "artist browsing failed" if @pointer.null?
|
31
33
|
end
|
32
34
|
|
33
35
|
# @return [Boolean] true if the artist browser is loaded.
|
data/lib/hallon/linkable.rb
CHANGED
@@ -65,15 +65,11 @@ module Hallon
|
|
65
65
|
type = as_object.to_s[/^(as_)?([^_]+)/, 2].to_sym
|
66
66
|
|
67
67
|
define_method(:from_link) do |link, *args|
|
68
|
-
|
69
|
-
link
|
70
|
-
else
|
71
|
-
unless Spotify::Pointer.typechecks?(link, :link)
|
72
|
-
link = Link.new(link).pointer(type)
|
73
|
-
end
|
74
|
-
|
75
|
-
instance_exec(link, *args, &block)
|
68
|
+
unless Spotify::Pointer.typechecks?(link, :link)
|
69
|
+
link = Link.new(link).pointer(type)
|
76
70
|
end
|
71
|
+
|
72
|
+
instance_exec(link, *args, &block)
|
77
73
|
end
|
78
74
|
|
79
75
|
private :from_link
|
@@ -94,11 +90,11 @@ module Hallon
|
|
94
90
|
# end
|
95
91
|
#
|
96
92
|
# @param [Symbol] cmethod name of the C method, say `from_artist` in `Spotify.link_create_from_artist`.
|
97
|
-
# @return [Link]
|
93
|
+
# @return [Link, nil]
|
98
94
|
def to_link(cmethod)
|
99
95
|
define_method(:to_link) do |*args|
|
100
96
|
link = Spotify.__send__(:"link_create_#{cmethod}!", pointer, *args)
|
101
|
-
Link.new(link)
|
97
|
+
Link.new(link) unless link.null?
|
102
98
|
end
|
103
99
|
end
|
104
100
|
|
data/lib/hallon/playlist.rb
CHANGED
@@ -17,15 +17,16 @@ module Hallon
|
|
17
17
|
# There is no way to refresh the information. You’ll have to retrieve the
|
18
18
|
# track again.
|
19
19
|
class Track < Hallon::Track
|
20
|
-
def initialize(playlist, index)
|
21
|
-
super
|
20
|
+
def initialize(pointer, playlist, index)
|
21
|
+
super(pointer)
|
22
22
|
|
23
23
|
@index = index
|
24
|
-
@
|
25
|
-
@
|
26
|
-
@
|
24
|
+
@playlist = playlist
|
25
|
+
@create_time = Time.at Spotify.playlist_track_create_time(playlist.pointer, index)
|
26
|
+
@message = Spotify.playlist_track_message(playlist.pointer, index)
|
27
|
+
@seen = Spotify.playlist_track_seen(playlist.pointer, index)
|
27
28
|
@creator = begin
|
28
|
-
creator = Spotify.playlist_track_creator!(playlist, index)
|
29
|
+
creator = Spotify.playlist_track_creator!(playlist.pointer, index)
|
29
30
|
User.new(creator) unless creator.null?
|
30
31
|
end
|
31
32
|
end
|
@@ -34,26 +35,42 @@ module Hallon
|
|
34
35
|
# @return [Integer] index this track was created with.
|
35
36
|
attr_reader :index
|
36
37
|
|
38
|
+
# @return [Playlist] playlist this track was created from.
|
39
|
+
attr_reader :playlist
|
40
|
+
|
37
41
|
# @return [Time] time when track at {#index} was added to playlist.
|
38
|
-
|
39
|
-
@create_time
|
40
|
-
end
|
42
|
+
attr_reader :create_time
|
41
43
|
|
42
44
|
# @return [User, nil] person who added track at {#index} to this playlist.
|
43
|
-
|
44
|
-
@creator
|
45
|
-
end
|
45
|
+
attr_reader :creator
|
46
46
|
|
47
47
|
# @return [String] message attached to this track at {#index}.
|
48
|
-
|
49
|
-
@message
|
50
|
-
end
|
48
|
+
attr_reader :message
|
51
49
|
|
52
50
|
# @see Playlist#seen
|
53
51
|
# @return [Boolean] true if track at {#index} has been seen.
|
54
52
|
def seen?
|
55
53
|
@seen
|
56
54
|
end
|
55
|
+
|
56
|
+
# Set seen status of the Playlist::Track at the given index.
|
57
|
+
#
|
58
|
+
# @note Word of warning; this method will update the value you get from {#seen?}!
|
59
|
+
# @raise [IndexError] if the underlying track has moved
|
60
|
+
# @raise [Error] if the operation could not be completed
|
61
|
+
#
|
62
|
+
# @param [Integer] index
|
63
|
+
# @param [Boolean] seen true if the track is now seen
|
64
|
+
# @return [Playlist::Track] track at the given index
|
65
|
+
def seen=(seen)
|
66
|
+
unless Spotify.playlist_track(playlist.pointer, index) == pointer
|
67
|
+
raise IndexError, "track has moved from #{index}"
|
68
|
+
end
|
69
|
+
|
70
|
+
error = Spotify.playlist_track_set_seen(playlist.pointer, index, !! seen)
|
71
|
+
Error.maybe_raise(error)
|
72
|
+
@seen = Spotify.playlist_track_seen(playlist.pointer, index)
|
73
|
+
end
|
57
74
|
end
|
58
75
|
|
59
76
|
from_link :playlist do |pointer|
|
@@ -176,16 +193,19 @@ module Hallon
|
|
176
193
|
# libspotify does not store more than 500 subscriber names
|
177
194
|
# @return [Array<String>] list of canonical usernames
|
178
195
|
def subscribers
|
179
|
-
ptr
|
180
|
-
struct = Spotify::Subscribers.new(ptr)
|
196
|
+
ptr = Spotify.playlist_subscribers(pointer)
|
181
197
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
struct[:
|
186
|
-
|
187
|
-
|
188
|
-
|
198
|
+
begin
|
199
|
+
struct = Spotify::Subscribers.new(ptr)
|
200
|
+
|
201
|
+
if struct[:count].zero?
|
202
|
+
[]
|
203
|
+
else
|
204
|
+
struct[:subscribers].map(&:read_string)
|
205
|
+
end
|
206
|
+
ensure
|
207
|
+
Spotify.playlist_subscribers_free(ptr)
|
208
|
+
end unless ptr.null?
|
189
209
|
end
|
190
210
|
|
191
211
|
# @return [Integer] total number of subscribers.
|
@@ -223,20 +243,10 @@ module Hallon
|
|
223
243
|
#
|
224
244
|
# @return [Enumerable<Playlist::Track>] a list of playlist tracks.
|
225
245
|
def tracks
|
226
|
-
Enumerator.new(size)
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
#
|
231
|
-
# @see #tracks
|
232
|
-
# @raise [Error] if the operation could not be completed
|
233
|
-
# @param [Integer] index
|
234
|
-
# @param [Boolean] seen true if the track is now seen
|
235
|
-
# @return [Playlist::Track] track at the given index
|
236
|
-
def seen(index, seen)
|
237
|
-
error = Spotify.playlist_track_set_seen(pointer, index, !! seen)
|
238
|
-
Error.maybe_raise(error)
|
239
|
-
tracks[index]
|
246
|
+
Enumerator.new(size) do |index|
|
247
|
+
track = Spotify.playlist_track!(pointer, index)
|
248
|
+
Playlist::Track.new(track, self, index) unless track.null?
|
249
|
+
end
|
240
250
|
end
|
241
251
|
|
242
252
|
# Add a list of tracks to the playlist starting at given position.
|
@@ -13,15 +13,59 @@ module Hallon
|
|
13
13
|
@pointer = to_pointer(pointer, :playlistcontainer)
|
14
14
|
end
|
15
15
|
|
16
|
-
# @return [Boolean] true if the container is loaded
|
16
|
+
# @return [Boolean] true if the container is loaded.
|
17
17
|
def loaded?
|
18
18
|
Spotify.playlistcontainer_is_loaded(pointer)
|
19
19
|
end
|
20
20
|
|
21
|
-
# @return [User, nil] owner of the container (nil if unknown or no owner)
|
21
|
+
# @return [User, nil] owner of the container (nil if unknown or no owner).
|
22
22
|
def owner
|
23
23
|
owner = Spotify.playlistcontainer_owner!(pointer)
|
24
24
|
User.new(owner) unless owner.null?
|
25
25
|
end
|
26
|
+
|
27
|
+
# @return [Integer] number of playlists and folders in this container.
|
28
|
+
def size
|
29
|
+
Spotify.playlistcontainer_num_playlists(pointer)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Enumerator<Playlist, Folder, nil>] an enumerator of folders and playlists.
|
33
|
+
def contents
|
34
|
+
Enumerator.new(size) do |i|
|
35
|
+
type = Spotify.playlistcontainer_playlist_type(pointer, i)
|
36
|
+
|
37
|
+
case type
|
38
|
+
when :playlist
|
39
|
+
playlist = Spotify.playlistcontainer_playlist!(pointer, i)
|
40
|
+
Playlist.new(playlist)
|
41
|
+
when :start_folder
|
42
|
+
when :end_folder
|
43
|
+
else # :unknown
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @overload add(name)
|
49
|
+
# Create a new playlist at the end of the container with the given name.
|
50
|
+
#
|
51
|
+
# @param [String] name
|
52
|
+
# @return [Playlist, nil] the new playlist, or nil if the operation failed
|
53
|
+
#
|
54
|
+
# @overload add(playlist)
|
55
|
+
# Add the given playlist to the end of the container.
|
56
|
+
#
|
57
|
+
# @param [Playlist, Link, #to_link] playlist
|
58
|
+
# @return [Playlist, nil] the added playlist, or nil if the operation failed
|
59
|
+
def add(name_or_playlist)
|
60
|
+
playlist = if name_or_playlist.is_a?(String)
|
61
|
+
Spotify.playlistcontainer_add_new_playlist!(pointer, name_or_playlist)
|
62
|
+
else
|
63
|
+
link = name_or_playlist
|
64
|
+
link = link.to_link unless link.is_a?(Link)
|
65
|
+
Spotify.playlistcontainer_add_playlist!(pointer, link.pointer)
|
66
|
+
end
|
67
|
+
|
68
|
+
Playlist.new(playlist) unless playlist.null?
|
69
|
+
end
|
26
70
|
end
|
27
71
|
end
|
data/lib/hallon/user.rb
CHANGED
@@ -56,35 +56,36 @@ module Hallon
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
# @return [Boolean] true if the user is loaded
|
59
|
+
# @return [Boolean] true if the user is loaded.
|
60
60
|
def loaded?
|
61
61
|
Spotify.user_is_loaded(pointer)
|
62
62
|
end
|
63
63
|
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# @return [String]
|
64
|
+
# @return [String] canonical name of the User.
|
67
65
|
def name
|
68
66
|
Spotify.user_canonical_name(pointer)
|
69
67
|
end
|
70
68
|
|
71
|
-
# Retrieve the dispaly name of the User.
|
72
|
-
#
|
73
69
|
# @note Unless {#loaded?} is true, this will return the same thing as {#name}.
|
74
|
-
# @return [String]
|
70
|
+
# @return [String] display name of the User.
|
75
71
|
def display_name
|
76
72
|
Spotify.user_display_name(pointer)
|
77
73
|
end
|
78
74
|
|
79
|
-
# Retrieve the users’ starred playlist.
|
80
|
-
#
|
81
75
|
# @note Returns nil unless {User#loaded?}
|
82
|
-
# @return [Playlist, nil]
|
76
|
+
# @return [Playlist, nil] starred playlist of the User.
|
83
77
|
def starred
|
84
78
|
playlist = Spotify.session_starred_for_user_create!(session.pointer, name)
|
85
79
|
Playlist.new(playlist) unless playlist.null?
|
86
80
|
end
|
87
81
|
|
82
|
+
# @note Returns nil unless {#loaded?}
|
83
|
+
# @return [PlaylistContainer, nil] published playlists of the User.
|
84
|
+
def published
|
85
|
+
container = Spotify.session_publishedcontainer_for_user_create!(session.pointer, name)
|
86
|
+
PlaylistContainer.new(container) unless container.null?
|
87
|
+
end
|
88
|
+
|
88
89
|
# Send tracks to this users’ inbox, with an optional message.
|
89
90
|
#
|
90
91
|
# @overload post(message, tracks)
|
data/lib/hallon/version.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::AlbumBrowse do
|
3
|
-
|
3
|
+
describe ".new" do
|
4
|
+
it "should raise an error if the browse request failed" do
|
5
|
+
Spotify.should_receive(:albumbrowse_create).and_return(null_pointer)
|
6
|
+
expect { mock_session { Hallon::AlbumBrowse.new(mock_album) } }.to raise_error(FFI::NullPointerError)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:browse) do
|
11
|
+
album = Hallon::Album.new(mock_album)
|
12
|
+
mock_session { Hallon::AlbumBrowse.new(album) }
|
13
|
+
end
|
14
|
+
|
4
15
|
subject { browse }
|
5
16
|
|
6
17
|
it { should be_loaded }
|
data/spec/hallon/album_spec.rb
CHANGED
@@ -32,6 +32,9 @@ describe Hallon::Album do
|
|
32
32
|
it "should be nil if there is no image" do
|
33
33
|
Spotify.should_receive(:album_cover).and_return(null_pointer)
|
34
34
|
album.cover.should be_nil
|
35
|
+
|
36
|
+
Spotify.should_receive(:link_create_from_album_cover).and_return(null_pointer)
|
37
|
+
album.cover(false).should be_nil
|
35
38
|
end
|
36
39
|
|
37
40
|
it "should be an image if it exists" do
|
@@ -1,5 +1,12 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::ArtistBrowse do
|
3
|
+
describe ".new" do
|
4
|
+
it "should raise an error if the browse request failed" do
|
5
|
+
Spotify.should_receive(:artistbrowse_create).and_return(null_pointer)
|
6
|
+
expect { mock_session { Hallon::ArtistBrowse.new(mock_artist) } }.to raise_error(FFI::NullPointerError)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
3
10
|
let(:browse) do
|
4
11
|
artist = Hallon::Artist.new(mock_artist)
|
5
12
|
mock_session { Hallon::ArtistBrowse.new(artist) }
|
data/spec/hallon/artist_spec.rb
CHANGED
@@ -30,19 +30,19 @@ describe Hallon::Artist do
|
|
30
30
|
let(:link) { Hallon::Link.new(mock_image_uri) }
|
31
31
|
|
32
32
|
specify "as an image" do
|
33
|
-
|
34
|
-
|
35
|
-
subject.portrait.should eq Hallon::Image.new(mock_image_id)
|
33
|
+
mock_session(2) { artist.portrait.should eq Hallon::Image.new(mock_image_id) }
|
36
34
|
end
|
37
35
|
|
38
36
|
specify "as a link" do
|
39
|
-
|
37
|
+
artist.portrait(false).should eq Hallon::Link.new(mock_image_uri)
|
40
38
|
end
|
41
39
|
|
42
40
|
it "should be nil if an image is not available" do
|
43
41
|
Spotify.should_receive(:artist_portrait).and_return(null_pointer)
|
42
|
+
artist.portrait.should be_nil
|
44
43
|
|
45
|
-
|
44
|
+
Spotify.should_receive(:link_create_from_artist_portrait).and_return(null_pointer)
|
45
|
+
artist.portrait(false).should be_nil
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -22,6 +22,19 @@ describe Hallon::Linkable do
|
|
22
22
|
object.respond_to?(:from_link, true).should be_true
|
23
23
|
end
|
24
24
|
|
25
|
+
describe "#to_link" do
|
26
|
+
it "should return nil if link creation failed" do
|
27
|
+
Spotify.should_receive(:link_create_from_user).and_return(null_pointer)
|
28
|
+
|
29
|
+
klass.instance_eval do
|
30
|
+
to_link(:from_user)
|
31
|
+
attr_reader :pointer
|
32
|
+
end
|
33
|
+
|
34
|
+
object.to_link.should be_nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
25
38
|
describe "#from_link" do
|
26
39
|
it "should call the appropriate Spotify function" do
|
27
40
|
Spotify.should_receive(:link_as_search!).and_return(pointer)
|
@@ -6,14 +6,44 @@ describe Hallon::PlaylistContainer do
|
|
6
6
|
|
7
7
|
it { should be_loaded }
|
8
8
|
its(:owner) { should eq Hallon::User.new("burgestrand") }
|
9
|
+
its(:size) { should eq 1 }
|
9
10
|
|
10
11
|
describe "#add" do
|
11
|
-
|
12
|
+
context "given a string" do
|
13
|
+
it "should create a new Playlist at the end of the playlist" do
|
14
|
+
expect do
|
15
|
+
playlist = container.add("Bogus")
|
16
|
+
|
17
|
+
playlist.name.should eq "Bogus"
|
18
|
+
container.contents[-1].should eq playlist
|
19
|
+
end.to change{ container.size }.by(1)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add the given Playlist to the end of the container" do
|
24
|
+
expect do
|
25
|
+
playlist = container.add Hallon::Playlist.new(mock_playlist)
|
26
|
+
container.contents[-1].should eq Hallon::Playlist.new(mock_playlist)
|
27
|
+
end.to change{ container.size }.by(1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should add the given Playlist Link to the end of the container" do
|
31
|
+
expect do
|
32
|
+
playlist = container.add Hallon::Link.new("spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi")
|
33
|
+
container.contents[-1].should eq Hallon::Playlist.new(mock_playlist)
|
34
|
+
end.to change{ container.size }.by(1)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return nil when failing to add the item" do
|
38
|
+
Spotify.should_receive(:playlistcontainer_add_playlist).and_return(null_pointer)
|
39
|
+
playlist = container.add Hallon::Link.new("spotify:user:burgestrand")
|
40
|
+
playlist.should be_nil
|
41
|
+
end
|
12
42
|
end
|
13
43
|
|
14
44
|
describe "#insert" do
|
15
45
|
it "should add the given Playlist to the given index"
|
16
|
-
it "should add the given Folder to the given index"
|
46
|
+
it "should add the given Folder to the given index"
|
17
47
|
end
|
18
48
|
|
19
49
|
describe "#remove" do
|
@@ -50,12 +80,10 @@ describe Hallon::PlaylistContainer do
|
|
50
80
|
# (8) Playlist #8
|
51
81
|
#
|
52
82
|
it "should be a collection of folders and playlists"
|
53
|
-
end
|
54
83
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
its(:name) { should be "Awesome playlist" }
|
84
|
+
it "should support retrieving playlists" do
|
85
|
+
container.contents[0].should eq Hallon::Playlist.new(mock_playlist)
|
86
|
+
end
|
59
87
|
end
|
60
88
|
|
61
89
|
describe Hallon::PlaylistContainer::Folder, :pending do
|
@@ -31,26 +31,30 @@ describe Hallon::Playlist do
|
|
31
31
|
its(:size) { should eq 4 }
|
32
32
|
|
33
33
|
its('tracks.size') { should eq 4 }
|
34
|
-
its('tracks.to_a') { should eq instantiate(Hallon::Playlist::Track,
|
34
|
+
its('tracks.to_a') { should eq instantiate(Hallon::Playlist::Track, *(0...4).map { |index| [Spotify.playlist_track!(playlist.pointer, index), playlist, index] }) }
|
35
|
+
|
35
36
|
describe "tracks#[]" do
|
37
|
+
let(:track) { subject }
|
36
38
|
subject { playlist.tracks[0] }
|
37
39
|
|
38
40
|
it { should be_seen }
|
39
41
|
its(:create_time) { should eq Time.parse("2009-11-04") }
|
40
42
|
its(:creator) { should eq Hallon::User.new(mock_user) }
|
41
43
|
its(:message) { should eq "message this, YO!" }
|
42
|
-
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
describe "#seen=" do
|
46
|
+
it "should raise an error if the track has moved" do
|
47
|
+
track.should be_seen
|
48
|
+
track.playlist.move(1, 0)
|
49
|
+
expect { track.seen = false }.to raise_error(IndexError)
|
50
|
+
track.should be_seen
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
53
|
+
it "should update the value of #seen?" do
|
54
|
+
track.should be_seen
|
55
|
+
track.seen = false
|
56
|
+
track.should_not be_seen
|
57
|
+
end
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
@@ -63,6 +67,11 @@ describe Hallon::Playlist do
|
|
63
67
|
Spotify.should_receive(:playlist_subscribers).and_return(mock_empty_subscribers)
|
64
68
|
subject.subscribers.should eq []
|
65
69
|
end
|
70
|
+
|
71
|
+
it "should return nil when subscriber fetching failed" do
|
72
|
+
Spotify.should_receive(:playlist_subscribers).and_return(null_pointer)
|
73
|
+
playlist.subscribers.should be_nil
|
74
|
+
end
|
66
75
|
end
|
67
76
|
|
68
77
|
describe "#insert" do
|
data/spec/hallon/session_spec.rb
CHANGED
@@ -54,8 +54,7 @@ describe Hallon::Session do
|
|
54
54
|
describe "#container" do
|
55
55
|
it "should return the sessions’ playlist container" do
|
56
56
|
session.login 'burgestrand', 'pass'
|
57
|
-
session.container.should
|
58
|
-
session.container.owner.should eq session.user
|
57
|
+
session.container.should eq Hallon::PlaylistContainer.new(mock_container)
|
59
58
|
end
|
60
59
|
|
61
60
|
it "should return nil if not logged in" do
|
data/spec/hallon/user_spec.rb
CHANGED
@@ -70,5 +70,20 @@ describe Hallon::User do
|
|
70
70
|
mock_session { user.starred.should be_nil }
|
71
71
|
end
|
72
72
|
end
|
73
|
+
|
74
|
+
describe "#published" do
|
75
|
+
let(:published) { Hallon::PlaylistContainer.new(mock_container) }
|
76
|
+
|
77
|
+
it "should return the playlist container of the user" do
|
78
|
+
Spotify.registry_add("spotify:container:%s" % user.name, mock_container)
|
79
|
+
|
80
|
+
session.login('burgestrand', '')
|
81
|
+
mock_session { user.published.should eq published }
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return nil if not logged in" do
|
85
|
+
mock_session { user.published.should be_nil }
|
86
|
+
end
|
87
|
+
end
|
73
88
|
end
|
74
89
|
end
|
data/spec/mockspotify.rb
CHANGED
@@ -26,13 +26,24 @@ module Spotify
|
|
26
26
|
require 'spotify'
|
27
27
|
|
28
28
|
module Mock
|
29
|
+
def self.find_type(*args, &block)
|
30
|
+
Spotify.find_type(*args, &block)
|
31
|
+
end
|
32
|
+
|
29
33
|
class PlaylistTrack < FFI::Struct
|
30
|
-
layout :track, :
|
34
|
+
layout :track, :track,
|
31
35
|
:create_time, :int,
|
32
|
-
:creator, :
|
36
|
+
:creator, :user,
|
33
37
|
:message, :pointer,
|
34
38
|
:seen, :bool
|
35
39
|
end
|
40
|
+
|
41
|
+
class PlaylistContainerItem < FFI::Struct
|
42
|
+
layout :playlist, :playlist,
|
43
|
+
:type, :playlist_type,
|
44
|
+
:folder_name, :pointer,
|
45
|
+
:folder_id, :uint64
|
46
|
+
end
|
36
47
|
end
|
37
48
|
|
38
49
|
old_verbose, $VERBOSE = $VERBOSE, true
|
@@ -61,7 +72,7 @@ module Spotify
|
|
61
72
|
attach_function :mock_toplistbrowse, :mocksp_toplistbrowse_create, [:error, :int, :int, :array, :int, :array, :int, :array], :toplistbrowse
|
62
73
|
|
63
74
|
attach_mock_function :mock_playlist, :mocksp_playlist_create, [:string, :bool, :user, :bool, :string, :image_id, :bool, :uint, Spotify::Subscribers, :bool, :playlist_offline_status, :int, :int, :array], :playlist
|
64
|
-
attach_mock_function :mock_playlistcontainer, :mocksp_playlistcontainer_create, [:user, :bool], :playlistcontainer
|
75
|
+
attach_mock_function :mock_playlistcontainer, :mocksp_playlistcontainer_create, [:user, :bool, :int, :array, PlaylistContainerCallbacks, :userdata], :playlistcontainer
|
65
76
|
attach_function :mock_search, :mocksp_search_create, [:error, :string, :string, :int, :int, :array, :int, :int, :array, :int, :int, :array, :search_complete_cb, :pointer], :search
|
66
77
|
attach_function :mock_subscribers, :mocksp_subscribers, [:int, :array], Spotify::Subscribers
|
67
78
|
|
@@ -146,14 +146,23 @@ RSpec::Core::ExampleGroup.instance_eval do
|
|
146
146
|
end
|
147
147
|
|
148
148
|
let(:mock_container) do
|
149
|
-
|
150
|
-
|
149
|
+
num_items = 1
|
150
|
+
items_ptr = FFI::MemoryPointer.new(Spotify::Mock::PlaylistTrack, num_items)
|
151
|
+
items = num_items.times.map do |i|
|
152
|
+
Spotify::Mock::PlaylistContainerItem.new(items_ptr + Spotify::Mock::PlaylistContainerItem.size * i)
|
153
|
+
end
|
154
|
+
|
155
|
+
items[0][:playlist] = mock_playlist
|
156
|
+
items[0][:type] = :playlist
|
157
|
+
|
158
|
+
Spotify.mock_playlistcontainer(mock_user, true, num_items, items_ptr, nil, nil)
|
151
159
|
end
|
152
160
|
end
|
153
161
|
|
154
162
|
RSpec.configure do |config|
|
155
163
|
config.before do
|
156
164
|
Spotify.registry_add mock_image_uri, mock_image
|
165
|
+
Spotify.registry_add 'spotify:container:burgestrand', mock_container
|
157
166
|
Spotify.registry_add 'spotify:albumbrowse:1xvnWMz2PNFf7mXOSRuLws', mock_albumbrowse
|
158
167
|
Spotify.registry_add 'spotify:artistbrowse:3bftcFwl4vqRNNORRsqm1G', mock_artistbrowse
|
159
168
|
Spotify.registry_add 'spotify:artist:3bftcFwl4vqRNNORRsqm1G', mock_artist
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hallon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: spotify
|
16
|
-
requirement: &
|
16
|
+
requirement: &70199932063240 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 10.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70199932063240
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &70199932060440 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70199932060440
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &70199932058360 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0.8'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70199932058360
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70199932057240 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '2'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70199932057240
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: yard
|
60
|
-
requirement: &
|
60
|
+
requirement: &70199932056420 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70199932056420
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rdiscount
|
71
|
-
requirement: &
|
71
|
+
requirement: &70199932055320 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70199932055320
|
80
80
|
description:
|
81
81
|
email: kim@burgestrand.se
|
82
82
|
executables: []
|