hallon 0.4.0 → 0.8.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/.gitmodules +3 -0
- data/.travis.yml +2 -0
- data/CHANGELOG +30 -6
- data/README.markdown +7 -7
- data/Rakefile +70 -16
- data/examples/logging_in.rb +3 -3
- data/examples/printing_link_information.rb +1 -1
- data/examples/show_published_playlists_of_user.rb +92 -0
- data/hallon.gemspec +7 -4
- data/lib/hallon.rb +16 -4
- data/lib/hallon/album.rb +16 -6
- data/lib/hallon/album_browse.rb +78 -0
- data/lib/hallon/artist.rb +59 -0
- data/lib/hallon/artist_browse.rb +89 -0
- data/lib/hallon/base.rb +7 -0
- data/lib/hallon/enumerator.rb +64 -0
- data/lib/hallon/error.rb +8 -6
- data/lib/hallon/ext/spotify.rb +3 -3
- data/lib/hallon/image.rb +25 -12
- data/lib/hallon/link.rb +4 -4
- data/lib/hallon/linkable.rb +4 -2
- data/lib/hallon/observable.rb +1 -4
- data/lib/hallon/player.rb +130 -0
- data/lib/hallon/search.rb +128 -0
- data/lib/hallon/session.rb +226 -25
- data/lib/hallon/toplist.rb +83 -0
- data/lib/hallon/track.rb +62 -7
- data/lib/hallon/user.rb +6 -6
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +20 -0
- data/spec/hallon/album_spec.rb +12 -7
- data/spec/hallon/artist_browse_spec.rb +29 -0
- data/spec/hallon/artist_spec.rb +32 -0
- data/spec/hallon/enumerator_spec.rb +106 -0
- data/spec/hallon/error_spec.rb +10 -0
- data/spec/hallon/hallon_spec.rb +5 -1
- data/spec/hallon/image_spec.rb +39 -25
- data/spec/hallon/linkable_spec.rb +12 -4
- data/spec/hallon/observable_spec.rb +5 -0
- data/spec/hallon/player_spec.rb +73 -0
- data/spec/hallon/search_spec.rb +80 -0
- data/spec/hallon/session_spec.rb +187 -6
- data/spec/hallon/toplist_spec.rb +40 -0
- data/spec/hallon/track_spec.rb +43 -8
- data/spec/mockspotify.rb +47 -0
- data/spec/mockspotify/.gitignore +5 -0
- data/spec/mockspotify/extconf.rb +5 -0
- data/spec/mockspotify/mockspotify_spec.rb +41 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/common_objects.rb +84 -7
- metadata +72 -20
- data/lib/hallon/ext/object.rb +0 -16
data/.gitmodules
ADDED
data/.travis.yml
ADDED
data/CHANGELOG
CHANGED
@@ -1,16 +1,40 @@
|
|
1
1
|
Hallon’s Changelog
|
2
2
|
==================
|
3
3
|
|
4
|
-
|
4
|
+
v0.8.0
|
5
5
|
------------------
|
6
|
-
|
6
|
+
[ Added ]
|
7
|
+
- Add example for listing track information in playlists
|
8
|
+
- Updated to (lib)Spotify v9
|
9
|
+
- Full Track subsystem support
|
10
|
+
- Full Album subsystem support
|
11
|
+
- Full AlbumBrowse subsystem support
|
12
|
+
- Full Artist subsystem support
|
13
|
+
- Full ArtistBrowse subsystem support
|
14
|
+
- Full Toplist subsystem support
|
15
|
+
- Full Search subsystem support
|
16
|
+
- Allow setting Session connection type/rules
|
17
|
+
- Session offline query methods (offline_time_left et al)
|
18
|
+
- Work-in-progress Player
|
19
|
+
- Add Session relogin support
|
20
|
+
- Add Enumerator
|
21
|
+
- Use libmockspotify for testing (spec/mockspotify)
|
7
22
|
- Add Hallon::Base class
|
8
|
-
- Cleaned up specs to use same mocks everywhere
|
9
|
-
- Album subsystem support (except for #cover and #artist)
|
10
23
|
- Add optional parameter to have Image#id return raw id
|
11
|
-
- Make Hallon::URI match image URIs
|
12
24
|
- Allow Image.new to accept an image id
|
13
|
-
- Add
|
25
|
+
- Add Hallon::API_BUILD
|
26
|
+
|
27
|
+
[ Fixed ]
|
28
|
+
- Improve speed of Session#wait_for for already-loaded cases
|
29
|
+
- Error.maybe_raise no longer errors out on timeout
|
30
|
+
- from_link now checks for null pointers
|
31
|
+
- No longer uses autotest as development dependency
|
32
|
+
- Cleaned up specs to use same mocks everywhere
|
33
|
+
- Make Hallon::URI match image URIs
|
34
|
+
|
35
|
+
[ Broke ]
|
36
|
+
- Ignore Ruby v1.8.x compatibility
|
37
|
+
|
14
38
|
|
15
39
|
v0.3.0
|
16
40
|
------------------
|
data/README.markdown
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
What is Hallon?
|
1
|
+
[What is Hallon?][] [![Build Status][]](http://travis-ci.org/Burgestrand/Hallon) ([but that’s okay](https://github.com/Burgestrand/Hallon/issues/33))
|
2
2
|
===============
|
3
3
|
|
4
|
-
> [Hallon, delicious Ruby bindings for libspotify](http://burgestrand.se/articles/hallon-delicious-ruby-bindings-to-libspotify.html)
|
5
|
-
|
6
4
|
We rubyists have this awesome [spotify gem][] allowing us to use [libspotify][] from within Ruby, but it has a significant drawback: the `libspotify` API is very hard to use. Now, we can’t have that, so what do we do? We make Hallon!
|
7
5
|
|
8
6
|
Hallon is Swedish for “Raspberry”, and has been written to satisfy my needs for API simplicity. It provides you with a wrapper around the spotify gem, making the experience of using `libspotify` from Ruby much more enjoyable.
|
@@ -11,7 +9,7 @@ Hallon would not have been possible if not for these people:
|
|
11
9
|
|
12
10
|
- Per Reimers, cracking synchronization bugs with me in the deep night (4 AM) and correcting me when I didn’t know better
|
13
11
|
- [Spotify](http://www.spotify.com/), providing a service worth attention (and my money!)
|
14
|
-
- [Linus Oleander](https://github.com/oleander), involving me with the
|
12
|
+
- [Linus Oleander](https://github.com/oleander), involving me with the [radiofy.se](http://radiofy.se) project, ultimately spawning the necessity of Hallon
|
15
13
|
- [Jesper Särnesjö][], creator of [Greenstripes][], making me think of Hallon as an achievable goal
|
16
14
|
|
17
15
|
Code samples can be found under `examples/` directory.
|
@@ -55,7 +53,9 @@ License
|
|
55
53
|
-------
|
56
54
|
Hallon is licensed under a 2-clause (Simplified) BSD license. More information can be found in the `LICENSE.txt` file.
|
57
55
|
|
58
|
-
[spotify gem]:
|
59
|
-
[libspotify]:
|
60
|
-
[Greenstripes]:
|
56
|
+
[spotify gem]: https://rubygems.org/gems/spotify
|
57
|
+
[libspotify]: http://developer.spotify.com/en/libspotify/overview/
|
58
|
+
[Greenstripes]: http://github.com/sarnesjo/greenstripes
|
61
59
|
[Jesper Särnesjö]: http://jesper.sarnesjo.org/
|
60
|
+
[What is Hallon?]: http://burgestrand.se/articles/hallon-delicious-ruby-bindings-to-libspotify.html
|
61
|
+
[Build Status]: https://secure.travis-ci.org/Burgestrand/Hallon.png
|
data/Rakefile
CHANGED
@@ -27,24 +27,58 @@ task 'spotify:coverage' do
|
|
27
27
|
require 'set'
|
28
28
|
require 'spotify'
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
dynamicly_used << "user_release" # lib/ext/spotify.rb
|
39
|
-
dynamicly_used << "link_as_track" # IGNORE
|
40
|
-
dynamicly_used << "link_release" # lib/ext/spotify.rb
|
41
|
-
|
42
|
-
methods = Spotify.methods(false).map(&:to_s) - dynamicly_used
|
30
|
+
begin
|
31
|
+
require 'ruby_parser'
|
32
|
+
rescue LoadError
|
33
|
+
puts "You need ruby_parser for the spotify:coverage rake task"
|
34
|
+
abort
|
35
|
+
end
|
36
|
+
|
37
|
+
methods = Spotify.methods(false).map(&:to_s)
|
43
38
|
covered = Set.new(methods)
|
44
|
-
|
39
|
+
ignored = [
|
40
|
+
'session_release', # segfaults on libspotify <= 9
|
41
|
+
'session_userdata', # wont support this
|
42
|
+
'link_as_track', # using link_as_track_and_offset instead
|
43
|
+
'toplistbrowse_add_ref', # toplistbrowse creates its’ own pointer
|
44
|
+
'artistbrowse_add_ref', # artistbrowse creates its’ own pointer
|
45
|
+
'albumbrowse_add_ref', # albumbrowse creates its’ own pointer
|
46
|
+
'link_add_ref', # all creation of links has +1 ref
|
47
|
+
'image_add_ref', # all creation of image has +1 ref
|
48
|
+
'search_add_ref', # search creates its’ own pointer
|
49
|
+
]
|
50
|
+
|
51
|
+
covered -= ignored
|
52
|
+
|
53
|
+
# Handlers for different AST nodes
|
54
|
+
printer = proc { |*args| p args }
|
55
|
+
silencer = proc { }
|
56
|
+
handlers = Hash.new(Hash.new(silencer))
|
57
|
+
|
58
|
+
# Direct calls
|
59
|
+
handlers[Sexp.new(:const, :Spotify)] = Hash.new(proc { |_, meth, _| meth })
|
60
|
+
|
61
|
+
# Spotify Pointer
|
62
|
+
pointer = handlers[Sexp.new(:colon2, [:const, :Spotify], :Pointer)] = Hash.new(printer)
|
63
|
+
pointer[:new] = proc do |recv, meth, (_, ptr, name, release)|
|
64
|
+
name = name.value
|
65
|
+
release &&= release.value != :false
|
66
|
+
["#{name}_release", "#{name if release}_add_ref"]
|
67
|
+
end
|
68
|
+
|
69
|
+
# DSL Methods
|
70
|
+
no_receiver = handlers[nil] = Hash.new(silencer)
|
71
|
+
no_receiver[:from_link] = no_receiver[:to_link] = proc do |recv, meth, (_, name)|
|
72
|
+
prefix = meth == :to_link ? "link_create" : "link"
|
73
|
+
"%s_%s" % [prefix, name.value]
|
74
|
+
end
|
45
75
|
|
46
76
|
FileList['lib/**/*.rb'].each do |file|
|
47
|
-
File.read(file)
|
77
|
+
ast = RubyParser.new.parse File.read(file)
|
78
|
+
ast.each_of_type(:call) do |_, recv, meth, args, *rest|
|
79
|
+
name = handlers[recv][meth].call(recv, meth, args)
|
80
|
+
covered.subtract Array(name).map(&:to_s)
|
81
|
+
end
|
48
82
|
end
|
49
83
|
|
50
84
|
covered.group_by { |m| m[/[^_]+/] }.each_pair do |group, methods|
|
@@ -55,9 +89,24 @@ task 'spotify:coverage' do
|
|
55
89
|
puts
|
56
90
|
end
|
57
91
|
|
92
|
+
puts "Ignored:"
|
93
|
+
ignored.each_slice(3) do |slice|
|
94
|
+
puts "\t#{slice.join(', ')}"
|
95
|
+
end
|
96
|
+
puts
|
97
|
+
|
58
98
|
puts "Coverage: %.02f%%" % (100 * (1 - covered.size.fdiv(methods.size)))
|
59
99
|
end
|
60
100
|
|
101
|
+
desc "Compile mockspotify"
|
102
|
+
task 'mock:compile' do
|
103
|
+
Dir.chdir 'spec/mockspotify' do
|
104
|
+
sh 'ruby extconf.rb'
|
105
|
+
sh 'make'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
task :spec => 'mock:compile'
|
61
110
|
task :test => :spec
|
62
111
|
|
63
112
|
#
|
@@ -70,7 +119,12 @@ end
|
|
70
119
|
|
71
120
|
desc "Remove generated files"
|
72
121
|
task :clean do
|
73
|
-
|
122
|
+
print "Do you really want to delete all non-git tracked files? (y/n) [n]: "
|
123
|
+
if STDIN.gets.chomp == 'y'
|
124
|
+
sh 'git clean -fdx --exclude Gemfile.lock --exclude spec/support/config.rb'
|
125
|
+
else
|
126
|
+
puts "Whew. Close one!"
|
127
|
+
end
|
74
128
|
end
|
75
129
|
|
76
130
|
task :default => [:spec]
|
data/examples/logging_in.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'hallon'
|
3
3
|
require './spec/support/config'
|
4
4
|
|
5
|
-
session = Hallon::Session.
|
5
|
+
session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
|
6
6
|
on(:log_message) do |message|
|
7
7
|
puts "[LOG] #{message}"
|
8
8
|
end
|
@@ -10,8 +10,8 @@ end
|
|
10
10
|
|
11
11
|
session.login ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD']
|
12
12
|
|
13
|
-
session.
|
14
|
-
session.
|
13
|
+
session.wait_for(:logged_in) { |error| Hallon::Error.maybe_raise(error) }
|
14
|
+
session.wait_for(:connection_error) do |error|
|
15
15
|
session.logged_in? or Hallon::Error.maybe_raise(error)
|
16
16
|
end
|
17
17
|
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# DISCLAIMER:
|
4
|
+
# This file was written without extensive testing, and is merely a proof
|
5
|
+
# of concept. Before using this yourself, I advice you to look through
|
6
|
+
# the code carefully.
|
7
|
+
#
|
8
|
+
# The below code uses the raw Spotify FFI API, and does not represent how
|
9
|
+
# this will be done when Hallon has API support for below operations!
|
10
|
+
#
|
11
|
+
# Hallon API in this file is only used for:
|
12
|
+
# - logging in
|
13
|
+
# - querying track information
|
14
|
+
#
|
15
|
+
# Raw Spotify FFI API is used for:
|
16
|
+
# - fetching playlist container
|
17
|
+
# - fetching playlists
|
18
|
+
# - fetching tracks from playlists
|
19
|
+
require 'hallon'
|
20
|
+
require './spec/support/config'
|
21
|
+
|
22
|
+
# Utility
|
23
|
+
def prompt(str)
|
24
|
+
print str
|
25
|
+
gets.chomp
|
26
|
+
end
|
27
|
+
|
28
|
+
session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
|
29
|
+
on(:log_message) do |message|
|
30
|
+
puts "[LOG] #{message}"
|
31
|
+
end
|
32
|
+
|
33
|
+
on(:connection_error) do |error|
|
34
|
+
Hallon::Error.maybe_raise(error)
|
35
|
+
end
|
36
|
+
|
37
|
+
on(:logged_out) do
|
38
|
+
abort "[FAIL] Logged out!"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
session.login ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD']
|
43
|
+
|
44
|
+
session.wait_for(:logged_in) { |error| Hallon::Error.maybe_raise(error) }
|
45
|
+
session.wait_for(:connection_error) do |error|
|
46
|
+
session.logged_in? or Hallon::Error.maybe_raise(error)
|
47
|
+
end
|
48
|
+
|
49
|
+
puts "Successfully logged in!"
|
50
|
+
|
51
|
+
# Hallon does not have support for the below operations, so we resort
|
52
|
+
# to using the raw Spotify gem and FFI for now.
|
53
|
+
while username = prompt("Enter a Spotify username: ")
|
54
|
+
begin
|
55
|
+
username = nil if username.empty?
|
56
|
+
|
57
|
+
puts "Fetching container for #{username || "current user"}..."
|
58
|
+
container = Spotify::session_publishedcontainer_for_user_create(session.pointer, username)
|
59
|
+
if container.null?
|
60
|
+
puts "Failed (unknown reason)."
|
61
|
+
next
|
62
|
+
end
|
63
|
+
|
64
|
+
session.wait_for { Spotify::playlistcontainer_is_loaded(container) }
|
65
|
+
|
66
|
+
num_playlists = Spotify::playlistcontainer_num_playlists(container)
|
67
|
+
puts "Listing #{num_playlists} playlists."
|
68
|
+
|
69
|
+
num_playlists.times do |i|
|
70
|
+
playlist = Spotify::playlistcontainer_playlist(container, i)
|
71
|
+
session.wait_for { Spotify::playlist_is_loaded(playlist) }
|
72
|
+
|
73
|
+
puts
|
74
|
+
puts Spotify::playlist_name(playlist) << ": "
|
75
|
+
|
76
|
+
num_tracks = Spotify::playlist_num_tracks(playlist)
|
77
|
+
num_tracks.times do |j|
|
78
|
+
# Here we go back into Hallon API, passing the raw pointer
|
79
|
+
# to Hallon::Track.new; this means all of Hallon::Track API
|
80
|
+
# is supported on “track” here!
|
81
|
+
track = Hallon::Track.new(Spotify::playlist_track(playlist, j))
|
82
|
+
session.wait_for { track.loaded? }
|
83
|
+
|
84
|
+
puts "\t (#{j+1}/#{num_tracks}) #{track.name}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
rescue Interrupt
|
88
|
+
# do nothing, continue with loop
|
89
|
+
ensure
|
90
|
+
Spotify::playlistcontainer_release(container) unless container.nil?
|
91
|
+
end
|
92
|
+
end
|
data/hallon.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
require 'hallon/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |gem|
|
5
7
|
gem.name = "hallon"
|
@@ -7,9 +9,10 @@ Gem::Specification.new do |gem|
|
|
7
9
|
gem.homepage = "http://github.com/Burgestrand/Hallon"
|
8
10
|
gem.authors = ["Kim Burgestrand"]
|
9
11
|
gem.email = 'kim@burgestrand.se'
|
10
|
-
gem.license = '
|
12
|
+
gem.license = 'X11 License'
|
11
13
|
|
12
14
|
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.files += `cd spec/mockspotify/libmockspotify && git ls-files src`.split("\n").map { |path| "spec/mockspotify/libmockspotify/#{path}" }
|
13
16
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
17
|
gem.executables = []
|
15
18
|
gem.require_paths = ["lib"]
|
@@ -18,8 +21,8 @@ Gem::Specification.new do |gem|
|
|
18
21
|
gem.platform = Gem::Platform::RUBY
|
19
22
|
gem.required_ruby_version = '~> 1.8'
|
20
23
|
|
21
|
-
gem.add_dependency 'spotify', '~>
|
22
|
-
gem.add_development_dependency '
|
24
|
+
gem.add_dependency 'spotify', '~> 9.0.0'
|
25
|
+
gem.add_development_dependency 'bundler', '~> 1.0'
|
23
26
|
gem.add_development_dependency 'rake', '~> 0.8'
|
24
27
|
gem.add_development_dependency 'rspec', '~> 2'
|
25
28
|
gem.add_development_dependency 'yard'
|
data/lib/hallon.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
require 'spotify'
|
3
3
|
require 'hallon/ext/spotify'
|
4
4
|
require 'hallon/ext/ffi'
|
5
|
-
require 'hallon/ext/object'
|
6
5
|
|
7
6
|
require 'hallon/synchronizable'
|
8
7
|
require 'hallon/observable'
|
@@ -11,12 +10,20 @@ require 'hallon/linkable'
|
|
11
10
|
require 'hallon/version'
|
12
11
|
require 'hallon/error'
|
13
12
|
require 'hallon/base'
|
13
|
+
require 'hallon/enumerator'
|
14
14
|
require 'hallon/session'
|
15
15
|
require 'hallon/link'
|
16
16
|
require 'hallon/user'
|
17
17
|
require 'hallon/image'
|
18
18
|
require 'hallon/track'
|
19
19
|
require 'hallon/album'
|
20
|
+
require 'hallon/artist'
|
21
|
+
require 'hallon/toplist'
|
22
|
+
|
23
|
+
require 'hallon/album_browse'
|
24
|
+
require 'hallon/artist_browse'
|
25
|
+
require 'hallon/player'
|
26
|
+
require 'hallon/search'
|
20
27
|
|
21
28
|
# The Hallon module wraps around all Hallon objects to avoid polluting
|
22
29
|
# the global namespace. To start using Hallon, you most likely want to
|
@@ -25,15 +32,20 @@ module Hallon
|
|
25
32
|
# @see Spotify::API_VERSION
|
26
33
|
API_VERSION = Spotify::API_VERSION
|
27
34
|
|
35
|
+
# Spotify API build.
|
36
|
+
#
|
37
|
+
# @see Spotify#api_build
|
38
|
+
API_BUILD = Spotify.build_id
|
39
|
+
|
28
40
|
# A regex that matches all Spotify URIs
|
29
41
|
#
|
30
42
|
# @example
|
31
43
|
# Hallon::URI === "spotify:user:burgestrand" # => true
|
32
44
|
URI = /(spotify:(?:
|
33
|
-
(?:artist|album|track|user:[^:]+:playlist)
|
45
|
+
(?:artist|album|track|user:[^:]+:playlist):[a-fA-F0-9]+
|
34
46
|
|user:[^:]+
|
35
|
-
|search:(?:[-\w$\.+!*'(),]
|
36
|
-
|image
|
47
|
+
|search:(?:[-\w$\.+!*'(),]+|%[a-fA-F0-9]{2})+
|
48
|
+
|image:[a-fA-F0-9]{40}
|
37
49
|
))
|
38
50
|
/x
|
39
51
|
end
|
data/lib/hallon/album.rb
CHANGED
@@ -9,8 +9,9 @@ module Hallon
|
|
9
9
|
#
|
10
10
|
# @see http://developer.spotify.com/en/libspotify/docs/group__album.html
|
11
11
|
class Album < Base
|
12
|
+
# An array of different kinds of albums. Singles, compilations etc.
|
12
13
|
def self.types
|
13
|
-
Spotify.enum_type(:albumtype).
|
14
|
+
Spotify.enum_type(:albumtype).symbols
|
14
15
|
end
|
15
16
|
|
16
17
|
extend Linkable
|
@@ -63,15 +64,24 @@ module Hallon
|
|
63
64
|
# Retrieve album cover art.
|
64
65
|
#
|
65
66
|
# @return [Image]
|
66
|
-
def cover
|
67
|
+
def cover
|
67
68
|
image_id = Spotify.album_cover(@pointer)
|
68
|
-
|
69
|
+
Image.new(image_id.read_string(20)) unless image_id.null?
|
69
70
|
end
|
70
71
|
|
71
|
-
#
|
72
|
+
# Retrieve the album Artist.
|
73
|
+
#
|
74
|
+
# @return [Artist, nil]
|
72
75
|
def artist
|
73
|
-
|
74
|
-
|
76
|
+
artist = Spotify.album_artist(@pointer)
|
77
|
+
Artist.new(artist) unless artist.null?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Retrieve an AlbumBrowse object for this Album.
|
81
|
+
#
|
82
|
+
# @return [AlbumBrowse]
|
83
|
+
def browse
|
84
|
+
AlbumBrowse.new(pointer)
|
75
85
|
end
|
76
86
|
end
|
77
87
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Hallon
|
2
|
+
# AlbumBrowse objects are for retrieving additional data from
|
3
|
+
# an album that cannot otherwise be acquired. This includes
|
4
|
+
# tracks, reviews, copyright information.
|
5
|
+
#
|
6
|
+
# AlbumBrowse object triggers the `:load` callback on itself
|
7
|
+
# when it loads.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# browse = album.browse # album is a Hallon::Album
|
11
|
+
# browse.on(:load) do
|
12
|
+
# puts "Album browser for #{browse.album.name} has been loaded!"
|
13
|
+
# end
|
14
|
+
# session.wait_for { browse.loaded? } # will eventually trigger above callback
|
15
|
+
#
|
16
|
+
# @see Album
|
17
|
+
# @see http://developer.spotify.com/en/libspotify/docs/group__albumbrowse.html
|
18
|
+
class AlbumBrowse < Base
|
19
|
+
include Observable
|
20
|
+
|
21
|
+
# Creates an AlbumBrowse instance from an Album or an Album pointer.
|
22
|
+
#
|
23
|
+
# @note Use {Album#browse} to browse an Album.
|
24
|
+
# @param [Album, FFI::Pointer] album
|
25
|
+
def initialize(album)
|
26
|
+
album = album.pointer if album.respond_to?(:pointer)
|
27
|
+
@callback = proc { trigger(:load) }
|
28
|
+
|
29
|
+
albumbrowse = Spotify.albumbrowse_create(session.pointer, album, @callback, nil)
|
30
|
+
@pointer = Spotify::Pointer.new(albumbrowse, :albumbrowse, false)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Boolean] true if the album is loaded
|
34
|
+
def loaded?
|
35
|
+
Spotify.albumbrowse_is_loaded(@pointer)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @see Error
|
39
|
+
# @return [Symbol] album browser error status
|
40
|
+
def error
|
41
|
+
Spotify.albumbrowse_error(@pointer)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [String] album review
|
45
|
+
def review
|
46
|
+
Spotify.albumbrowse_review(@pointer)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Artist] artist performing this album
|
50
|
+
def artist
|
51
|
+
pointer = Spotify.albumbrowse_artist(@pointer)
|
52
|
+
Artist.new(pointer) unless pointer.null?
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Album] album this object is browsing
|
56
|
+
def album
|
57
|
+
pointer = Spotify.albumbrowse_album(@pointer)
|
58
|
+
Album.new(pointer) unless pointer.null?
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Enumerator<String>] list of copyright notices
|
62
|
+
def copyrights
|
63
|
+
size = Spotify.albumbrowse_num_copyrights(@pointer)
|
64
|
+
Enumerator.new(size) do |i|
|
65
|
+
Spotify.albumbrowse_copyright(@pointer, i)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Enumerator<Track>] list of tracks
|
70
|
+
def tracks
|
71
|
+
size = Spotify.albumbrowse_num_tracks(@pointer)
|
72
|
+
Enumerator.new(size) do |i|
|
73
|
+
pointer = Spotify.albumbrowse_track(@pointer, i)
|
74
|
+
Track.new(pointer) unless pointer.null?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|