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.
Files changed (52) hide show
  1. data/.gitmodules +3 -0
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG +30 -6
  4. data/README.markdown +7 -7
  5. data/Rakefile +70 -16
  6. data/examples/logging_in.rb +3 -3
  7. data/examples/printing_link_information.rb +1 -1
  8. data/examples/show_published_playlists_of_user.rb +92 -0
  9. data/hallon.gemspec +7 -4
  10. data/lib/hallon.rb +16 -4
  11. data/lib/hallon/album.rb +16 -6
  12. data/lib/hallon/album_browse.rb +78 -0
  13. data/lib/hallon/artist.rb +59 -0
  14. data/lib/hallon/artist_browse.rb +89 -0
  15. data/lib/hallon/base.rb +7 -0
  16. data/lib/hallon/enumerator.rb +64 -0
  17. data/lib/hallon/error.rb +8 -6
  18. data/lib/hallon/ext/spotify.rb +3 -3
  19. data/lib/hallon/image.rb +25 -12
  20. data/lib/hallon/link.rb +4 -4
  21. data/lib/hallon/linkable.rb +4 -2
  22. data/lib/hallon/observable.rb +1 -4
  23. data/lib/hallon/player.rb +130 -0
  24. data/lib/hallon/search.rb +128 -0
  25. data/lib/hallon/session.rb +226 -25
  26. data/lib/hallon/toplist.rb +83 -0
  27. data/lib/hallon/track.rb +62 -7
  28. data/lib/hallon/user.rb +6 -6
  29. data/lib/hallon/version.rb +1 -1
  30. data/spec/hallon/album_browse_spec.rb +20 -0
  31. data/spec/hallon/album_spec.rb +12 -7
  32. data/spec/hallon/artist_browse_spec.rb +29 -0
  33. data/spec/hallon/artist_spec.rb +32 -0
  34. data/spec/hallon/enumerator_spec.rb +106 -0
  35. data/spec/hallon/error_spec.rb +10 -0
  36. data/spec/hallon/hallon_spec.rb +5 -1
  37. data/spec/hallon/image_spec.rb +39 -25
  38. data/spec/hallon/linkable_spec.rb +12 -4
  39. data/spec/hallon/observable_spec.rb +5 -0
  40. data/spec/hallon/player_spec.rb +73 -0
  41. data/spec/hallon/search_spec.rb +80 -0
  42. data/spec/hallon/session_spec.rb +187 -6
  43. data/spec/hallon/toplist_spec.rb +40 -0
  44. data/spec/hallon/track_spec.rb +43 -8
  45. data/spec/mockspotify.rb +47 -0
  46. data/spec/mockspotify/.gitignore +5 -0
  47. data/spec/mockspotify/extconf.rb +5 -0
  48. data/spec/mockspotify/mockspotify_spec.rb +41 -0
  49. data/spec/spec_helper.rb +20 -0
  50. data/spec/support/common_objects.rb +84 -7
  51. metadata +72 -20
  52. data/lib/hallon/ext/object.rb +0 -16
@@ -0,0 +1,3 @@
1
+ [submodule "spec/mockspotify/libmockspotify"]
2
+ path = spec/mockspotify/libmockspotify
3
+ url = git://github.com/Burgestrand/libmockspotify.git
@@ -0,0 +1,2 @@
1
+ rvm:
2
+ - 1.9.2
data/CHANGELOG CHANGED
@@ -1,16 +1,40 @@
1
1
  Hallon’s Changelog
2
2
  ==================
3
3
 
4
- NEXT
4
+ v0.8.0
5
5
  ------------------
6
- - No longer uses autotest as development dependency
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 Album#cover
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
  ------------------
@@ -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 `radiofy.se` project, ultimately spawning the necessity of Hallon
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]: https://rubygems.org/gems/spotify
59
- [libspotify]: http://developer.spotify.com/en/libspotify/overview/
60
- [Greenstripes]: http://github.com/sarnesjo/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
- dynamicly_used = []
31
- dynamicly_used << "link_create_from_track" # lib/hallon/track.rb
32
- dynamicly_used << "track_add_ref" # lib/ext/spotify.rb
33
- dynamicly_used << "track_release" # lib/ext/spotify.rb
34
- dynamicly_used << "link_create_from_image" # lib/hallon/image.rb
35
- dynamicly_used << "image_release" # lib/ext/spotify.rb
36
- dynamicly_used << "link_create_from_user" # lib/hallon/user.rb
37
- dynamicly_used << "user_add_ref" # lib/ext/spotify.rb
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
- matcher = /Spotify(?:::|\.)([\w_]+)[ \(]/
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).scan(matcher) { |method, _| covered.delete(method) }
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
- sh 'git clean -fdx --exclude Gemfile.lock --exclude spec/support/config.rb'
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]
@@ -2,7 +2,7 @@
2
2
  require 'hallon'
3
3
  require './spec/support/config'
4
4
 
5
- session = Hallon::Session.instance IO.read(ENV['HALLON_APPKEY']) do
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.process_events_on(:logged_in) { |error| Hallon::Error.maybe_raise(error) }
14
- session.process_events_on(:connection_error) do |error|
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
 
@@ -9,7 +9,7 @@ def prompt(str)
9
9
  end
10
10
 
11
11
  # Hallon
12
- session = Hallon::Session.instance IO.read(ENV['HALLON_APPKEY']) do
12
+ session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
13
13
  on(:log_message) do |message|
14
14
  $stderr.puts "[LOG] #{message}"
15
15
  end
@@ -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
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require './lib/hallon/version'
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 = 'GNU AGPL'
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', '~> 8.0.5'
22
- gem.add_development_dependency 'mockspotify', '~> 0.1.8'
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'
@@ -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):\h+
45
+ (?:artist|album|track|user:[^:]+:playlist):[a-fA-F0-9]+
34
46
  |user:[^:]+
35
- |search:(?:[-\w$\.+!*'(),]+|%\h{2})+
36
- |image:\h{40}
47
+ |search:(?:[-\w$\.+!*'(),]+|%[a-fA-F0-9]{2})+
48
+ |image:[a-fA-F0-9]{40}
37
49
  ))
38
50
  /x
39
51
  end
@@ -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).to_hash
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(session = Session.instance)
67
+ def cover
67
68
  image_id = Spotify.album_cover(@pointer)
68
- Hallon::Image.new(image_id.read_string(20), session) unless image_id.null?
69
+ Image.new(image_id.read_string(20)) unless image_id.null?
69
70
  end
70
71
 
71
- # Not yet implemented.
72
+ # Retrieve the album Artist.
73
+ #
74
+ # @return [Artist, nil]
72
75
  def artist
73
- return if (ptr = Spotify.album_artist(@pointer)).null?
74
- raise NotImplementedError
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