spotify 12.5.3 → 12.6.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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +20 -5
  4. data/CHANGELOG.md +29 -1
  5. data/Gemfile +5 -0
  6. data/MIT-LICENSE +21 -0
  7. data/README.markdown +75 -50
  8. data/Rakefile +1 -1
  9. data/examples/example-audio_delivery_speed.rb +48 -0
  10. data/examples/{audio-stream_example.rb → example-audio_stream.rb} +14 -29
  11. data/examples/example-console.rb +9 -0
  12. data/examples/example-listing_playlists.rb +89 -0
  13. data/examples/example-loading_object.rb +25 -0
  14. data/examples/example-random_related_artists.rb +53 -0
  15. data/examples/support.rb +106 -0
  16. data/lib/spotify.rb +36 -55
  17. data/lib/spotify/api.rb +54 -26
  18. data/lib/spotify/api/album.rb +45 -2
  19. data/lib/spotify/api/album_browse.rb +81 -3
  20. data/lib/spotify/api/artist.rb +21 -2
  21. data/lib/spotify/api/artist_browse.rb +121 -3
  22. data/lib/spotify/api/error.rb +5 -1
  23. data/lib/spotify/api/image.rb +72 -6
  24. data/lib/spotify/api/inbox.rb +33 -4
  25. data/lib/spotify/api/link.rb +117 -4
  26. data/lib/spotify/api/miscellaneous.rb +12 -0
  27. data/lib/spotify/api/playlist.rb +321 -16
  28. data/lib/spotify/api/playlist_container.rb +168 -9
  29. data/lib/spotify/api/search.rb +156 -3
  30. data/lib/spotify/api/session.rb +390 -26
  31. data/lib/spotify/api/toplist_browse.rb +74 -3
  32. data/lib/spotify/api/track.rb +134 -4
  33. data/lib/spotify/api/user.rb +18 -2
  34. data/lib/spotify/api_helpers.rb +47 -0
  35. data/lib/spotify/data_converters.rb +7 -0
  36. data/lib/spotify/{types → data_converters}/best_effort_string.rb +1 -1
  37. data/lib/spotify/{types → data_converters}/byte_string.rb +0 -0
  38. data/lib/spotify/data_converters/country_code.rb +30 -0
  39. data/lib/spotify/{types → data_converters}/image_id.rb +1 -1
  40. data/lib/spotify/{type_safety.rb → data_converters/type_safety.rb} +0 -0
  41. data/lib/spotify/{types → data_converters}/utf8_string.rb +2 -2
  42. data/lib/spotify/{types → data_converters}/utf8_string_pointer.rb +2 -2
  43. data/lib/spotify/error.rb +180 -47
  44. data/lib/spotify/managed_pointer.rb +32 -12
  45. data/lib/spotify/monkey_patches/ffi_buffer.rb +11 -0
  46. data/lib/spotify/monkey_patches/ffi_enums.rb +4 -0
  47. data/lib/spotify/monkey_patches/ffi_pointer.rb +1 -0
  48. data/lib/spotify/structs.rb +4 -0
  49. data/lib/spotify/structs/session_callbacks.rb +97 -26
  50. data/lib/spotify/structs/session_config.rb +1 -1
  51. data/lib/spotify/structs/subscribers.rb +4 -3
  52. data/lib/spotify/types.rb +104 -5
  53. data/lib/spotify/{objects → types}/album.rb +0 -0
  54. data/lib/spotify/{objects → types}/album_browse.rb +0 -0
  55. data/lib/spotify/{objects → types}/artist.rb +0 -0
  56. data/lib/spotify/{objects → types}/artist_browse.rb +0 -0
  57. data/lib/spotify/{objects → types}/image.rb +0 -0
  58. data/lib/spotify/{objects → types}/inbox.rb +0 -0
  59. data/lib/spotify/{objects → types}/link.rb +0 -0
  60. data/lib/spotify/{objects → types}/playlist.rb +0 -0
  61. data/lib/spotify/{objects → types}/playlist_container.rb +0 -0
  62. data/lib/spotify/{objects → types}/search.rb +0 -0
  63. data/lib/spotify/{objects → types}/session.rb +0 -0
  64. data/lib/spotify/{objects → types}/toplist_browse.rb +0 -0
  65. data/lib/spotify/{objects → types}/track.rb +0 -0
  66. data/lib/spotify/{objects → types}/user.rb +0 -0
  67. data/lib/spotify/util.rb +38 -35
  68. data/lib/spotify/version.rb +1 -1
  69. data/spec/spec_helper.rb +24 -13
  70. data/spec/spotify/api/image_spec.rb +32 -0
  71. data/spec/spotify/api/inbox_spec.rb +34 -0
  72. data/spec/spotify/api/link_spec.rb +40 -0
  73. data/spec/spotify/api/playlist_spec.rb +99 -0
  74. data/spec/spotify/api/playlistcontainer_spec.rb +82 -0
  75. data/spec/spotify/api/session_spec.rb +97 -0
  76. data/spec/spotify/api/track_spec.rb +29 -0
  77. data/spec/spotify/api_error_spec.rb +55 -0
  78. data/spec/spotify/api_spec.rb +17 -11
  79. data/spec/spotify/{types → data_converters}/best_effort_string_spec.rb +4 -4
  80. data/spec/spotify/{types → data_converters}/byte_string_spec.rb +0 -0
  81. data/spec/spotify/data_converters/country_code_spec.rb +16 -0
  82. data/spec/spotify/{types → data_converters}/image_id_spec.rb +1 -1
  83. data/spec/spotify/{type_safety_spec.rb → data_converters/type_safety_spec.rb} +0 -0
  84. data/spec/spotify/{types → data_converters}/utf8_string_pointer_spec.rb +0 -0
  85. data/spec/spotify/{types → data_converters}/utf8_string_spec.rb +1 -1
  86. data/spec/spotify/{api/functions_spec.rb → functions_spec.rb} +2 -0
  87. data/spec/spotify/managed_pointer_spec.rb +13 -13
  88. data/spec/spotify/structs/subscribers_spec.rb +5 -3
  89. data/spec/spotify/{defines_spec.rb → types_spec.rb} +16 -3
  90. data/spec/spotify/util_spec.rb +24 -0
  91. data/spec/spotify_spec.rb +74 -0
  92. data/spec/support/spotify_util.rb +6 -2
  93. data/spec/support/spy_output.rb +16 -0
  94. data/spotify.gemspec +4 -2
  95. metadata +111 -71
  96. data/examples/README.md +0 -15
  97. data/examples/console_example.rb +0 -22
  98. data/examples/example_support.rb +0 -66
  99. data/examples/loading-object_example.rb +0 -43
  100. data/examples/logging-in_example.rb +0 -58
  101. data/lib/spotify/defines.rb +0 -109
  102. data/lib/spotify/objects.rb +0 -17
  103. data/spec/spotify/enums_spec.rb +0 -9
  104. data/spec/spotify/spotify_spec.rb +0 -69
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require_relative "support"
5
+
6
+ session = Support.initialize_spotify!
7
+
8
+ track_uri = Support.prompt("Please enter a track URI", "spotify:track:1612JQ4JxS8bm5ky53N3bH")
9
+ link = Spotify.link_create_from_string(track_uri)
10
+
11
+ if link.nil?
12
+ $logger.error "Invalid URI. Aborting."
13
+ abort
14
+ elsif (link_type = Spotify.link_type(link)) != :track
15
+ $logger.error "Was #{link_type} URI. Needs track. Aborting."
16
+ abort
17
+ else
18
+ track = Spotify.link_as_track(link)
19
+ end
20
+
21
+ $logger.info "Attempting to load track. Waiting forever until successful."
22
+ Support.poll(session) { Spotify.track_is_loaded(track) }
23
+ $logger.info "Track loaded."
24
+
25
+ puts Spotify.track_name(track)
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require_relative "support"
5
+
6
+ session = Support.initialize_spotify!
7
+
8
+ artist_uri = Support.prompt("Please enter an artist URI to start with", "spotify:artist:7sVQKNtdP2NylxMgbNOJMM")
9
+ link = Spotify.link_create_from_string(artist_uri)
10
+
11
+ if link.null?
12
+ $logger.error "Invalid URI. Aborting."
13
+ abort
14
+ elsif (link_type = Spotify.link_type(link)) != :artist
15
+ $logger.error "Was #{link_type} URI. Needs artist. Aborting."
16
+ abort
17
+ end
18
+
19
+ target = Spotify.link_as_artist(link)
20
+
21
+ # Spotify.enum & :no_tracks & :no_albums
22
+ no_tracks = Spotify::Util.enum_value!(:no_tracks, "album type")
23
+ no_albums = Spotify::Util.enum_value!(:no_albums, "album type")
24
+ $dummy_callback = proc { }
25
+
26
+ artists = Set.new
27
+ count = 0
28
+
29
+ while target
30
+ $logger.info "Stats: #{artists.length} artists, #{count} browses."
31
+
32
+ browser = Spotify.artistbrowse_create(session, target, no_tracks | no_albums, $dummy_callback, nil)
33
+
34
+ Support.poll(session) do
35
+ begin
36
+ Spotify.try(:artistbrowse_error, browser)
37
+ rescue Spotify::IsLoadingError
38
+ # Ignore it
39
+ end
40
+
41
+ Spotify.artistbrowse_is_loaded(browser)
42
+ end
43
+
44
+ similar_artists = Spotify.artistbrowse_num_similar_artists(browser).times.map do |index|
45
+ Spotify.artistbrowse_similar_artist(browser, index)
46
+ end
47
+
48
+ similar_artists_names = similar_artists.map { |artist| Spotify.artist_name(artist) }
49
+
50
+ target = similar_artists.sample
51
+ artists << Spotify.artist_name(target)
52
+ count += 1
53
+ end
@@ -0,0 +1,106 @@
1
+ require "bundler/setup"
2
+ require "spotify"
3
+ require "logger"
4
+ require "pry"
5
+ require "io/console"
6
+
7
+ # Kill main thread if any other thread dies.
8
+ Thread.abort_on_exception = true
9
+
10
+ # We use a logger to print some information on when things are happening.
11
+ $stderr.sync = true
12
+ $logger = Logger.new($stderr)
13
+ $logger.level = Logger::INFO
14
+ $logger.formatter = proc do |severity, datetime, progname, msg|
15
+ progname = if progname
16
+ " (#{progname}) "
17
+ else
18
+ " "
19
+ end
20
+ "\n[#{severity} @ #{datetime.strftime("%H:%M:%S")}]#{progname}#{msg}"
21
+ end
22
+
23
+ #
24
+ # Some utility.
25
+ #
26
+
27
+ module Support
28
+ module_function
29
+
30
+ DEFAULT_CONFIG = {
31
+ api_version: Spotify::API_VERSION.to_i,
32
+ application_key: File.binread("./spotify_appkey.key"),
33
+ cache_location: ".spotify/",
34
+ settings_location: ".spotify/",
35
+ user_agent: "spotify for ruby",
36
+ callbacks: Spotify::SessionCallbacks.new
37
+ }
38
+
39
+ def logger
40
+ $logger
41
+ end
42
+
43
+ class << self
44
+ attr_accessor :silenced
45
+ end
46
+
47
+ # libspotify supports callbacks, but they are not useful for waiting on
48
+ # operations (how they fire can be strange at times, and sometimes they
49
+ # might not fire at all). As a result, polling is the way to go.
50
+ def poll(session, idle_time = 0.05)
51
+ until yield
52
+ print "." unless silenced
53
+ process_events(session)
54
+ sleep(idle_time)
55
+ end
56
+ end
57
+
58
+ # Process libspotify events once.
59
+ def process_events(session)
60
+ Spotify.session_process_events(session)
61
+ end
62
+
63
+ # Ask the user for input with a prompt explaining what kind of input.
64
+ def prompt(message, default = nil)
65
+ if default
66
+ print "\n#{message} [#{default}]: "
67
+ input = gets.chomp
68
+
69
+ if input.empty?
70
+ default
71
+ else
72
+ input
73
+ end
74
+ else
75
+ print "\n#{message}: "
76
+ gets.chomp
77
+ end
78
+ end
79
+
80
+ def initialize_spotify!(config = DEFAULT_CONFIG)
81
+ error, session = Spotify.session_create(config)
82
+ raise error if error.is_a?(Spotify::APIError)
83
+
84
+ if username = Spotify.session_remembered_user(session)
85
+ logger.info "Using remembered login for: #{username}."
86
+ Spotify.try(:session_relogin, session)
87
+ else
88
+ username = prompt("Spotify username, or Facebook e-mail")
89
+ password = $stdin.noecho { prompt("Spotify password, or Facebook password") }
90
+
91
+ logger.info "Attempting login with #{username}."
92
+ Spotify.try(:session_login, session, username, password, true, nil)
93
+ end
94
+
95
+ logger.info "Log in requested. Waiting forever until logged in."
96
+ Support.poll(session) { Spotify.session_connectionstate(session) == :logged_in }
97
+
98
+ at_exit do
99
+ logger.info "Logging out."
100
+ Spotify.session_logout(session)
101
+ Support.poll(session) { Spotify.session_connectionstate(session) != :logged_in }
102
+ end
103
+
104
+ session
105
+ end
106
+ end
@@ -1,8 +1,15 @@
1
1
  # encoding: utf-8
2
2
  require 'ffi'
3
3
  require 'spotify/monkey_patches/ffi_pointer'
4
+ require 'spotify/monkey_patches/ffi_buffer'
5
+ require 'spotify/monkey_patches/ffi_enums'
6
+
4
7
  require 'libspotify'
5
- require 'monitor'
8
+ require 'performer'
9
+
10
+ require 'spotify/version'
11
+ require 'spotify/util'
12
+ require 'spotify/api'
6
13
 
7
14
  # Spotify module allows you to place calls against the Spotify::API.
8
15
  #
@@ -10,61 +17,38 @@ require 'monitor'
10
17
  # @see Spotify::API Spotify::API on available libspotify methods
11
18
  # @see http://developer.spotify.com/en/libspotify/docs/ official libspotify documentation
12
19
  module Spotify
13
- # API is the class which has all libspotify functions attached.
14
- #
15
- # All functions are attached as both instance methods and class methods, mainly
16
- # because that’s how FFI works it’s magic with attach_function. However, as this
17
- # is a class it allows to be instantiated.
18
- #
19
- # @note The API is private because this class is an implementation detail.
20
- #
21
- # @note You should never call any Spotify::API.method() directly, but instead
22
- # you should call them via Spotify.method(). libspotify is not thread-safe,
23
- # but it is documented to be okay to call the API from multiple threads *if*
24
- # you only call one function at a time, which is ensured by the lock in the
25
- # Spotify module.
26
- #
27
- # @api private
28
- class API
29
- extend FFI::Library
30
-
31
- begin
32
- ffi_lib [LIBSPOTIFY_BIN, 'spotify', 'libspotify', '/Library/Frameworks/libspotify.framework/libspotify']
33
- ffi_convention :stdcall if FFI::Platform.windows?
34
- rescue LoadError
35
- puts <<-ERROR.gsub(/^ */, '')
36
- Failed to load the `libspotify` library. It is possible that the libspotify gem
37
- does not exist for your platform, in which case you’ll need to install it manually.
20
+ # @return [String] libspotify build ID.
21
+ API_BUILD = Spotify::API.build_id
38
22
 
39
- For manual installation instructions, please see:
40
- https://github.com/Burgestrand/Hallon/wiki/How-to-install-libspotify
41
- ERROR
42
- raise
43
- end
23
+ unless API_BUILD.include?(Spotify::API_VERSION)
24
+ warn "[WARNING:#{__FILE__}] libspotify v#{build_id} might be incompatible with ruby spotify v#{VERSION}(#{API_VERSION})"
44
25
  end
45
26
 
27
+ @performer = Performer.new
46
28
  @__api__ = Spotify::API
47
- @__api__.extend(MonitorMixin)
48
29
 
49
30
  class << self
31
+ # @see https://rubygems.org/gems/performer
32
+ # @return [Performer]
33
+ attr_reader :performer
34
+
50
35
  # Like send, but raises an error if the method returns a non-OK error.
51
36
  #
52
37
  # @example calling a method that returns an error
53
38
  # Spotify.relogin(session) # => :invalid_indata
54
- # Spotify.try(:relogin, session) # => raises Spotify::Error
39
+ # Spotify.try(:relogin, session) # => raises APIError
55
40
  #
56
41
  # @note Works for non-error returning methods as well, it just does
57
42
  # not do anything interesting.
58
43
  #
59
44
  # @param [#to_s] name
60
45
  # @param args
61
- # @raise [Spotify::Error] if an error other than :ok is returned
46
+ # @raise [APIError] if an error other than :ok is returned
62
47
  def try(name, *args, &block)
63
48
  public_send(name, *args, &block).tap do |error|
64
- error, symbol = Spotify::Error.disambiguate(error)
65
- next if symbol.nil?
66
- next if symbol == :ok
67
- raise Error.new(symbol)
49
+ if error.is_a?(APIError)
50
+ raise error unless error.is_a?(IsLoadingError)
51
+ end
68
52
  end
69
53
  end
70
54
 
@@ -80,9 +64,7 @@ module Spotify
80
64
  # @param [Boolean] include_private
81
65
  # @return [Boolean] true if the API supports the given method.
82
66
  def respond_to_missing?(name, include_private = false)
83
- @__api__.synchronize do
84
- @__api__.respond_to?(name, include_private)
85
- end
67
+ @__api__.respond_to?(name, include_private)
86
68
  end
87
69
 
88
70
  # Calls the any method on the underlying {Spotify::API}.
@@ -90,25 +72,24 @@ module Spotify
90
72
  # @example calling the API
91
73
  # Spotify.link_create_from_string("spotify:user:burgestrand") # => #<Spotify::Link address=0x0deadbeef>
92
74
  #
93
- # @note Spotify protects all calls to {Spotify::API} with a lock, so it is
94
- # considered safe to call the API from different threads. The lock
95
- # is re-entrant.
75
+ # @note Spotify protects all calls to {Spotify::API} by calling all
76
+ # API methods in the {.performer} thread.
96
77
  #
97
78
  # @param [Symbol, String] name
98
79
  # @param [Object, …] args
99
80
  def method_missing(name, *args, &block)
100
- @__api__.synchronize do
101
- @__api__.send(name, *args, &block)
81
+ if respond_to?(name)
82
+ performer.sync { @__api__.public_send(name, *args, &block) }
83
+ else
84
+ super
102
85
  end
103
86
  end
87
+
88
+ # Print debug messages, if $DEBUG is true.
89
+ #
90
+ # @param [String] message
91
+ def log(message)
92
+ $stdout.puts "[#{caller[0]}] #{message}" if $DEBUG
93
+ end
104
94
  end
105
95
  end
106
-
107
- require 'spotify/version'
108
- require 'spotify/util'
109
- require 'spotify/types'
110
- require 'spotify/error'
111
- require 'spotify/objects'
112
- require 'spotify/defines'
113
- require 'spotify/structs'
114
- require 'spotify/api'
@@ -1,49 +1,77 @@
1
1
  module Spotify
2
+ # API is the class which has all libspotify functions attached.
3
+ #
4
+ # All functions are attached as both instance methods and class methods, mainly
5
+ # because that’s how FFI works it’s magic with attach_function. However, as this
6
+ # is a class it allows to be instantiated.
7
+ #
8
+ # @note The API is private because this class is an implementation detail.
9
+ #
10
+ # @note You should never call any Spotify::API.method() directly, but instead
11
+ # you should call them via Spotify.method(). libspotify is not thread-safe,
12
+ # but it is documented to be okay to call the API from multiple threads *if*
13
+ # you only call one function at a time, which is ensured by the lock in the
14
+ # Spotify module.
15
+ #
16
+ # @api private
2
17
  class API
3
- # @!macro [attach] attach_function
4
- # @!method $1(…)
5
- # @!scope class
6
- # @!scope instance
7
- # @example method signature (shows arguments)
8
- # $*
9
- # @return [${-1}]
10
- #
18
+ extend FFI::Library
19
+
20
+ begin
21
+ ffi_lib [LIBSPOTIFY_BIN, 'spotify', 'libspotify', '/Library/Frameworks/libspotify.framework/libspotify']
22
+ ffi_convention :stdcall if FFI::Platform.windows?
23
+ rescue LoadError
24
+ $stderr.puts <<-ERROR.gsub(/^ */, '')
25
+ Failed to load the `libspotify` library. It is possible that the libspotify gem
26
+ does not exist for your platform, in which case you'll need to install it manually.
27
+
28
+ For manual installation instructions, please see:
29
+ https://github.com/Burgestrand/Hallon/wiki/How-to-install-libspotify
30
+ ERROR
31
+ raise
32
+ end
33
+
11
34
  # Overloaded to ensure all methods are defined as blocking,
12
35
  # and they return a managed pointer with the correct refcount.
13
36
  #
14
37
  # @param [#to_s] name function name sans `sp_` prefix.
15
38
  # @param [Array] args
16
39
  # @param [Object] returns
17
- def self.attach_function(c_name = nil, name, args, returns)
40
+ def self.attach_function(c_name = nil, name, args, returns, &block)
18
41
  if returns.respond_to?(:retaining_class) && name !~ /create/
19
42
  returns = returns.retaining_class
20
43
  end
21
44
 
22
- options = { :blocking => true }
23
- c_name ||= "sp_#{name}"
45
+ options = { blocking: true }
46
+ name = name.to_sym
47
+ c_name ||= :"sp_#{name}"
24
48
  super(name, c_name, args, returns, options)
25
- end
26
49
 
27
- # Now, make sure we have the right libspotify version.
50
+ if block_given?
51
+ alias_method c_name, name
52
+ define_method name, &block
28
53
 
29
- # @!group Miscellaneous
54
+ singleton_class.instance_eval do
55
+ alias_method c_name, name
56
+ define_method name, &block
57
+ end
30
58
 
31
- # @see Spotify::API_BUILD
32
- attach_function :build_id, [], UTF8String
33
-
34
- # @!endgroup
35
- end
36
-
37
- # @return [String] libspotify build ID.
38
- API_BUILD = Spotify.build_id
59
+ name
60
+ end
61
+ end
39
62
 
40
- # No support yet for "similar" versions, so it’s a hard requirement
41
- # on the libspotify version. It *must* be the same, even patch version.
42
- unless API_BUILD.include?(Spotify::API_VERSION)
43
- raise LoadError, "libspotify v#{build_id} is incompatible with ruby spotify v#{VERSION}(#{API_VERSION})"
63
+ require "spotify/api_helpers"
64
+ extend APIHelpers
65
+ include APIHelpers
44
66
  end
45
67
  end
46
68
 
69
+ require 'spotify/error'
70
+ require 'spotify/data_converters'
71
+ require 'spotify/types'
72
+ require 'spotify/structs'
73
+
74
+ require 'spotify/api/miscellaneous'
47
75
  require 'spotify/api/album'
48
76
  require 'spotify/api/album_browse'
49
77
  require 'spotify/api/artist'
@@ -1,14 +1,57 @@
1
1
  module Spotify
2
2
  class API
3
3
  # @!group Album
4
+
5
+ # @param [Album] album
6
+ # @return [Boolean] true if the album is populated with data
7
+ # @method album_is_loaded(album)
4
8
  attach_function :album_is_loaded, [ Album ], :bool
9
+
10
+ # @see #album_is_loaded
11
+ # @note the album must be loaded, or this function always return false.
12
+ # @param [Album] album
13
+ # @return [Boolean] true if the album is available for playback
14
+ # @method album_is_available(album)
5
15
  attach_function :album_is_available, [ Album ], :bool
16
+
17
+ # @see #album_is_loaded
18
+ # @note the album must be loaded, or this function always return nil.
19
+ # @param [Album] album
20
+ # @return [Artist, nil] authoring artist of the album
21
+ # @method album_artist(album)
6
22
  attach_function :album_artist, [ Album ], Artist
23
+
24
+ # @see #image_create
25
+ # @see #album_is_loaded
26
+ # @note the album must be loaded, or this function always return nil.
27
+ # @param [Album] album
28
+ # @param [Symbol] image_size one of :normal, :small, :large
29
+ # @return [String, nil] image ID to pass to {#image_create}, or nil if the album has no image
30
+ # @method album_cover(album, image_size)
7
31
  attach_function :album_cover, [ Album, :image_size ], ImageID
32
+
33
+ # @see #album_is_loaded
34
+ # @note the album must be loaded, or this function always return an empty string.
35
+ # @param [Album] album
36
+ # @return [String] name of the album
37
+ # @method album_name(album)
8
38
  attach_function :album_name, [ Album ], UTF8String
39
+
40
+ # @see #album_is_loaded
41
+ # @note the album must be loaded, or this function always return 0.
42
+ # @param [Album] album
43
+ # @return [String] release year of the album
44
+ # @method album_year(album)
9
45
  attach_function :album_year, [ Album ], :int
46
+
47
+ # @see #album_is_loaded
48
+ # @note the album must be loaded, or this function always return :unknown.
49
+ # @param [Album] album
50
+ # @return [Symbol] album type, one of :album, :single, :compilation, :unknown
51
+ # @method album_type(album)
10
52
  attach_function :album_type, [ Album ], :albumtype
11
- attach_function :album_add_ref, [ Album ], :error
12
- attach_function :album_release, [ Album ], :error
53
+
54
+ attach_function :album_add_ref, [ Album ], APIError
55
+ attach_function :album_release, [ Album ], APIError
13
56
  end
14
57
  end