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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +20 -5
- data/CHANGELOG.md +29 -1
- data/Gemfile +5 -0
- data/MIT-LICENSE +21 -0
- data/README.markdown +75 -50
- data/Rakefile +1 -1
- data/examples/example-audio_delivery_speed.rb +48 -0
- data/examples/{audio-stream_example.rb → example-audio_stream.rb} +14 -29
- data/examples/example-console.rb +9 -0
- data/examples/example-listing_playlists.rb +89 -0
- data/examples/example-loading_object.rb +25 -0
- data/examples/example-random_related_artists.rb +53 -0
- data/examples/support.rb +106 -0
- data/lib/spotify.rb +36 -55
- data/lib/spotify/api.rb +54 -26
- data/lib/spotify/api/album.rb +45 -2
- data/lib/spotify/api/album_browse.rb +81 -3
- data/lib/spotify/api/artist.rb +21 -2
- data/lib/spotify/api/artist_browse.rb +121 -3
- data/lib/spotify/api/error.rb +5 -1
- data/lib/spotify/api/image.rb +72 -6
- data/lib/spotify/api/inbox.rb +33 -4
- data/lib/spotify/api/link.rb +117 -4
- data/lib/spotify/api/miscellaneous.rb +12 -0
- data/lib/spotify/api/playlist.rb +321 -16
- data/lib/spotify/api/playlist_container.rb +168 -9
- data/lib/spotify/api/search.rb +156 -3
- data/lib/spotify/api/session.rb +390 -26
- data/lib/spotify/api/toplist_browse.rb +74 -3
- data/lib/spotify/api/track.rb +134 -4
- data/lib/spotify/api/user.rb +18 -2
- data/lib/spotify/api_helpers.rb +47 -0
- data/lib/spotify/data_converters.rb +7 -0
- data/lib/spotify/{types → data_converters}/best_effort_string.rb +1 -1
- data/lib/spotify/{types → data_converters}/byte_string.rb +0 -0
- data/lib/spotify/data_converters/country_code.rb +30 -0
- data/lib/spotify/{types → data_converters}/image_id.rb +1 -1
- data/lib/spotify/{type_safety.rb → data_converters/type_safety.rb} +0 -0
- data/lib/spotify/{types → data_converters}/utf8_string.rb +2 -2
- data/lib/spotify/{types → data_converters}/utf8_string_pointer.rb +2 -2
- data/lib/spotify/error.rb +180 -47
- data/lib/spotify/managed_pointer.rb +32 -12
- data/lib/spotify/monkey_patches/ffi_buffer.rb +11 -0
- data/lib/spotify/monkey_patches/ffi_enums.rb +4 -0
- data/lib/spotify/monkey_patches/ffi_pointer.rb +1 -0
- data/lib/spotify/structs.rb +4 -0
- data/lib/spotify/structs/session_callbacks.rb +97 -26
- data/lib/spotify/structs/session_config.rb +1 -1
- data/lib/spotify/structs/subscribers.rb +4 -3
- data/lib/spotify/types.rb +104 -5
- data/lib/spotify/{objects → types}/album.rb +0 -0
- data/lib/spotify/{objects → types}/album_browse.rb +0 -0
- data/lib/spotify/{objects → types}/artist.rb +0 -0
- data/lib/spotify/{objects → types}/artist_browse.rb +0 -0
- data/lib/spotify/{objects → types}/image.rb +0 -0
- data/lib/spotify/{objects → types}/inbox.rb +0 -0
- data/lib/spotify/{objects → types}/link.rb +0 -0
- data/lib/spotify/{objects → types}/playlist.rb +0 -0
- data/lib/spotify/{objects → types}/playlist_container.rb +0 -0
- data/lib/spotify/{objects → types}/search.rb +0 -0
- data/lib/spotify/{objects → types}/session.rb +0 -0
- data/lib/spotify/{objects → types}/toplist_browse.rb +0 -0
- data/lib/spotify/{objects → types}/track.rb +0 -0
- data/lib/spotify/{objects → types}/user.rb +0 -0
- data/lib/spotify/util.rb +38 -35
- data/lib/spotify/version.rb +1 -1
- data/spec/spec_helper.rb +24 -13
- data/spec/spotify/api/image_spec.rb +32 -0
- data/spec/spotify/api/inbox_spec.rb +34 -0
- data/spec/spotify/api/link_spec.rb +40 -0
- data/spec/spotify/api/playlist_spec.rb +99 -0
- data/spec/spotify/api/playlistcontainer_spec.rb +82 -0
- data/spec/spotify/api/session_spec.rb +97 -0
- data/spec/spotify/api/track_spec.rb +29 -0
- data/spec/spotify/api_error_spec.rb +55 -0
- data/spec/spotify/api_spec.rb +17 -11
- data/spec/spotify/{types → data_converters}/best_effort_string_spec.rb +4 -4
- data/spec/spotify/{types → data_converters}/byte_string_spec.rb +0 -0
- data/spec/spotify/data_converters/country_code_spec.rb +16 -0
- data/spec/spotify/{types → data_converters}/image_id_spec.rb +1 -1
- data/spec/spotify/{type_safety_spec.rb → data_converters/type_safety_spec.rb} +0 -0
- data/spec/spotify/{types → data_converters}/utf8_string_pointer_spec.rb +0 -0
- data/spec/spotify/{types → data_converters}/utf8_string_spec.rb +1 -1
- data/spec/spotify/{api/functions_spec.rb → functions_spec.rb} +2 -0
- data/spec/spotify/managed_pointer_spec.rb +13 -13
- data/spec/spotify/structs/subscribers_spec.rb +5 -3
- data/spec/spotify/{defines_spec.rb → types_spec.rb} +16 -3
- data/spec/spotify/util_spec.rb +24 -0
- data/spec/spotify_spec.rb +74 -0
- data/spec/support/spotify_util.rb +6 -2
- data/spec/support/spy_output.rb +16 -0
- data/spotify.gemspec +4 -2
- metadata +111 -71
- data/examples/README.md +0 -15
- data/examples/console_example.rb +0 -22
- data/examples/example_support.rb +0 -66
- data/examples/loading-object_example.rb +0 -43
- data/examples/logging-in_example.rb +0 -58
- data/lib/spotify/defines.rb +0 -109
- data/lib/spotify/objects.rb +0 -17
- data/spec/spotify/enums_spec.rb +0 -9
- 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
|
data/examples/support.rb
ADDED
|
@@ -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
|
data/lib/spotify.rb
CHANGED
|
@@ -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 '
|
|
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
|
-
#
|
|
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
|
-
|
|
40
|
-
|
|
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
|
|
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 [
|
|
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
|
|
65
|
-
|
|
66
|
-
|
|
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__.
|
|
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}
|
|
94
|
-
#
|
|
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
|
-
|
|
101
|
-
@__api__.
|
|
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'
|
data/lib/spotify/api.rb
CHANGED
|
@@ -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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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 = { :
|
|
23
|
-
|
|
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
|
-
|
|
50
|
+
if block_given?
|
|
51
|
+
alias_method c_name, name
|
|
52
|
+
define_method name, &block
|
|
28
53
|
|
|
29
|
-
|
|
54
|
+
singleton_class.instance_eval do
|
|
55
|
+
alias_method c_name, name
|
|
56
|
+
define_method name, &block
|
|
57
|
+
end
|
|
30
58
|
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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'
|
data/lib/spotify/api/album.rb
CHANGED
|
@@ -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
|
-
|
|
12
|
-
attach_function :
|
|
53
|
+
|
|
54
|
+
attach_function :album_add_ref, [ Album ], APIError
|
|
55
|
+
attach_function :album_release, [ Album ], APIError
|
|
13
56
|
end
|
|
14
57
|
end
|