spotify 12.5.2 → 12.5.3
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/CHANGELOG.md +10 -1
- data/Gemfile +2 -1
- data/README.markdown +16 -5
- data/examples/audio-stream_example.rb +8 -12
- data/examples/console_example.rb +1 -4
- data/examples/example_support.rb +41 -21
- data/examples/loading-object_example.rb +5 -8
- data/examples/logging-in_example.rb +7 -8
- data/lib/spotify.rb +1 -0
- data/lib/spotify/monkey_patches/ffi_pointer.rb +2 -0
- data/lib/spotify/structs/subscribers.rb +3 -0
- data/lib/spotify/type_safety.rb +2 -0
- data/lib/spotify/types/byte_string.rb +3 -0
- data/lib/spotify/util.rb +5 -1
- data/lib/spotify/version.rb +1 -1
- data/spec/spotify/managed_pointer_spec.rb +3 -4
- data/spotify.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d9e97a03f155c02b4b189899d152e51acc80c21
|
4
|
+
data.tar.gz: 43731fc0330043a6885b08c669c2fb13418efb68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 519bd5a79bb4a76dd63cb2ad884cb42da3a7bc142cf851db490bdc6f35f21be15fc224911f80650a437e7152db3cd0ad4901ce25e0d62f414aea8aec900447cf
|
7
|
+
data.tar.gz: f0b4bc4da8b176121aa4cb62c276142086084e8d8334fc291d76a740693ec218f170c6cf478023d0a971b04a27c68fab07b80f7a14c1c6625f66fbe00f1c5fbb
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
[HEAD][]
|
2
2
|
-----------
|
3
3
|
|
4
|
+
[v12.5.3][]
|
5
|
+
-----------
|
6
|
+
|
7
|
+
- [e09f64cc7] Add initial windows support
|
8
|
+
|
9
|
+
I’ve noticed callbacks cause libspotify to segfault. Not sure why; could
|
10
|
+
have something to do with with FFI callback support.
|
11
|
+
|
4
12
|
[v12.5.2][]
|
5
13
|
-----------
|
6
14
|
|
@@ -198,8 +206,9 @@ v0.0.0
|
|
198
206
|
------
|
199
207
|
- release to register rubygems.org name
|
200
208
|
|
201
|
-
[HEAD]: https://github.com/Burgestrand/spotify/compare/v12.5.
|
209
|
+
[HEAD]: https://github.com/Burgestrand/spotify/compare/v12.5.3...HEAD
|
202
210
|
|
211
|
+
[v12.5.2]: https://github.com/Burgestrand/spotify/compare/v12.5.2...v12.5.3
|
203
212
|
[v12.5.2]: https://github.com/Burgestrand/spotify/compare/v12.5.1...v12.5.2
|
204
213
|
[v12.5.1]: https://github.com/Burgestrand/spotify/compare/v12.5.0...v12.5.1
|
205
214
|
[v12.5.0]: https://github.com/Burgestrand/spotify/compare/v12.4.0...v12.5.0
|
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
Ruby bindings for [libspotify][]
|
2
|
-
|
1
|
+
Low-level Ruby bindings for [libspotify][], the official Spotify C API
|
2
|
+
======================================================================
|
3
|
+
[](http://travis-ci.org/Burgestrand/spotify)
|
4
|
+
[](https://gemnasium.com/Burgestrand/spotify)
|
5
|
+
[](https://codeclimate.com/github/Burgestrand/spotify)
|
6
|
+
[](http://badge.fury.io/rb/spotify)
|
3
7
|
|
4
8
|
The libspotify C API package allows third party developers to write
|
5
9
|
applications that utilize the Spotify music streaming service.
|
@@ -16,7 +20,7 @@ The Spotify gem has:
|
|
16
20
|
|
17
21
|
- [100% API coverage][], including callback support. You’ll be able to use any function from the libspotify library.
|
18
22
|
- [Automatic garbage collection][]. Piggybacking on Ruby’s GC to manage pointer lifecycle.
|
19
|
-
- [Parallell function call protection][]. libspotify is not thread-safe, but Spotify protects you.
|
23
|
+
- [Parallell function call protection][]. libspotify is not thread-safe, but Spotify protects you by providing a re-entrant mutex around function calls.
|
20
24
|
- [Type conversion and type safety][]. Special pointers for every Spotify type, protecting you from accidental mix-ups.
|
21
25
|
- [Support for JRuby and Rubinius][]. Thanks to FFI, the gem runs fine on the main three Ruby implementations!
|
22
26
|
|
@@ -26,7 +30,14 @@ The Spotify gem has:
|
|
26
30
|
[Type conversion and type safety]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/ManagedPointer
|
27
31
|
[Support for JRuby and Rubinius]: https://github.com/Burgestrand/spotify/blob/master/.travis.yml
|
28
32
|
|
29
|
-
|
33
|
+
Contact details
|
34
|
+
---------------
|
35
|
+
|
36
|
+
- __Got questions?__ Ask on the mailing list: [ruby-hallon@googlegroups.com][] (<https://groups.google.com/d/forum/ruby-hallon>)
|
37
|
+
- __Found a bug?__ Report an issue: <https://github.com/Burgestrand/spotify/issues/new>
|
38
|
+
- __Have feedback?__ I ❤ feedback! Please send it to the mailing list.
|
39
|
+
|
40
|
+
Spotify API is best used with a supporting library
|
30
41
|
--------------------------------------------------
|
31
42
|
As the raw libspotify API is exposed, the Spotify gem is best coupled with a supporting
|
32
43
|
library. This library would take a more focused approach to which kind of applications
|
@@ -88,6 +99,6 @@ THE SOFTWARE.
|
|
88
99
|
|
89
100
|
[semantic versioning (semver.org)]: http://semver.org/
|
90
101
|
[ruby-hallon@googlegroups.com]: mailto:ruby-hallon@googlegroups.com
|
91
|
-
[libspotify]:
|
102
|
+
[libspotify]: https://developer.spotify.com/technologies/libspotify/
|
92
103
|
[Spotify]: https://www.spotify.com/
|
93
104
|
[Hallon]: https://github.com/Burgestrand/Hallon
|
@@ -9,7 +9,7 @@ require "plaything"
|
|
9
9
|
def play_track(uri)
|
10
10
|
link = Spotify.link_create_from_string(uri)
|
11
11
|
track = Spotify.link_as_track(link)
|
12
|
-
poll($session) { Spotify.track_is_loaded(track) }
|
12
|
+
Support.poll($session) { Spotify.track_is_loaded(track) }
|
13
13
|
Spotify.try(:session_player_play, $session, false)
|
14
14
|
Spotify.try(:session_player_load, $session, track)
|
15
15
|
Spotify.try(:session_player_play, $session, true)
|
@@ -84,12 +84,12 @@ $session_callbacks = {
|
|
84
84
|
|
85
85
|
music_delivery: proc do |session, format, frames, num_frames|
|
86
86
|
if num_frames == 0
|
87
|
-
plaything.stop
|
88
87
|
$logger.debug("session (player)") { "music delivery audio discontuity" }
|
88
|
+
plaything.stop
|
89
|
+
0
|
89
90
|
else
|
90
91
|
frames = FrameReader.new(format[:channels], format[:sample_type], num_frames, frames)
|
91
92
|
consumed_frames = plaything.stream(frames, format.to_h)
|
92
|
-
$logger.info("session (player)") { "#{format.to_h}" }
|
93
93
|
$logger.debug("session (player)") { "music delivery #{consumed_frames} of #{num_frames}" }
|
94
94
|
consumed_frames
|
95
95
|
end
|
@@ -120,21 +120,17 @@ config = Spotify::SessionConfig.new({
|
|
120
120
|
})
|
121
121
|
|
122
122
|
$logger.info "Creating session."
|
123
|
-
|
124
|
-
Spotify.try(:session_create, config, ptr)
|
125
|
-
$session = Spotify::Session.new(ptr.read_pointer)
|
126
|
-
end
|
123
|
+
$session = Support.create_session(config)
|
127
124
|
|
128
125
|
$logger.info "Created! Logging in."
|
129
|
-
Spotify.session_login($session, $username, $password, false,
|
126
|
+
Spotify.session_login($session, $username, $password, false, $blob)
|
130
127
|
|
131
128
|
$logger.info "Log in requested. Waiting forever until logged in."
|
132
|
-
poll($session) { Spotify.session_connectionstate($session) == :logged_in }
|
129
|
+
Support.poll($session) { Spotify.session_connectionstate($session) == :logged_in }
|
133
130
|
|
134
131
|
$logger.info "Logged in as #{Spotify.session_user_name($session)}."
|
135
132
|
|
136
|
-
|
137
|
-
play_track gets.chomp
|
133
|
+
play_track Support.prompt("Spotify track URI")
|
138
134
|
|
139
135
|
$logger.info "Playing track until end. Use ^C to exit."
|
140
|
-
poll($session) { $end_of_track }
|
136
|
+
Support.poll($session) { $end_of_track }
|
data/examples/console_example.rb
CHANGED
@@ -13,10 +13,7 @@ config = Spotify::SessionConfig.new({
|
|
13
13
|
})
|
14
14
|
|
15
15
|
$logger.info "Creating session."
|
16
|
-
|
17
|
-
Spotify.try(:session_create, config, ptr)
|
18
|
-
$session = Spotify::Session.new(ptr.read_pointer)
|
19
|
-
end
|
16
|
+
$session = Support.create_session(config)
|
20
17
|
|
21
18
|
$logger.info "Created! Logging in."
|
22
19
|
Spotify.session_login($session, $username, $password, false, nil)
|
data/examples/example_support.rb
CHANGED
@@ -7,6 +7,7 @@ require "pry"
|
|
7
7
|
Thread.abort_on_exception = true
|
8
8
|
|
9
9
|
# We use a logger to print some information on when things are happening.
|
10
|
+
$stderr.sync = true
|
10
11
|
$logger = Logger.new($stderr)
|
11
12
|
$logger.level = Logger::INFO
|
12
13
|
|
@@ -14,33 +15,52 @@ $logger.level = Logger::INFO
|
|
14
15
|
# Some utility.
|
15
16
|
#
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
module Support
|
19
|
+
module_function
|
20
|
+
|
21
|
+
def logger
|
22
|
+
$logger
|
23
|
+
end
|
24
|
+
|
25
|
+
# libspotify supports callbacks, but they are not useful for waiting on
|
26
|
+
# operations (how they fire can be strange at times, and sometimes they
|
27
|
+
# might not fire at all). As a result, polling is the way to go.
|
28
|
+
def poll(session)
|
29
|
+
until yield
|
30
|
+
FFI::MemoryPointer.new(:int) do |ptr|
|
31
|
+
Spotify.session_process_events(session, ptr)
|
32
|
+
end
|
33
|
+
sleep(0.1)
|
24
34
|
end
|
25
|
-
sleep(0.1)
|
26
35
|
end
|
27
|
-
end
|
28
36
|
|
29
|
-
# For making sure fetching configuration options fail with a useful error
|
30
|
-
# message when running the examples.
|
31
|
-
def env(name)
|
32
|
-
|
33
|
-
|
37
|
+
# For making sure fetching configuration options fail with a useful error
|
38
|
+
# message when running the examples.
|
39
|
+
def env(name)
|
40
|
+
ENV.fetch(name) do
|
41
|
+
raise "Missing ENV['#{name}']. Please: export #{name}='your value'"
|
42
|
+
end
|
34
43
|
end
|
35
|
-
end
|
36
44
|
|
37
|
-
# Ask the user for input with a prompt explaining what kind of input.
|
38
|
-
def prompt(message)
|
39
|
-
|
40
|
-
|
45
|
+
# Ask the user for input with a prompt explaining what kind of input.
|
46
|
+
def prompt(message)
|
47
|
+
print "#{message}: "
|
48
|
+
gets.chomp
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_session(config)
|
52
|
+
FFI::MemoryPointer.new(Spotify::Session) do |ptr|
|
53
|
+
Spotify.try(:session_create, config, ptr)
|
54
|
+
return Spotify::Session.new(ptr.read_pointer)
|
55
|
+
end
|
56
|
+
end
|
41
57
|
end
|
42
58
|
|
43
59
|
# Load the configuration.
|
44
60
|
$appkey = IO.read("./spotify_appkey.key", encoding: "BINARY")
|
45
|
-
$username = env("SPOTIFY_USERNAME")
|
46
|
-
|
61
|
+
$username = Support.env("SPOTIFY_USERNAME")
|
62
|
+
if ENV.has_key?("SPOTIFY_BLOB")
|
63
|
+
$blob = ENV["SPOTIFY_BLOB"]
|
64
|
+
else
|
65
|
+
$password = Support.env("SPOTIFY_PASSWORD")
|
66
|
+
end
|
@@ -13,20 +13,17 @@ config = Spotify::SessionConfig.new({
|
|
13
13
|
})
|
14
14
|
|
15
15
|
$logger.info "Creating session."
|
16
|
-
|
17
|
-
Spotify.try(:session_create, config, ptr)
|
18
|
-
$session = Spotify::Session.new(ptr.read_pointer)
|
19
|
-
end
|
16
|
+
$session = Support.create_session(config)
|
20
17
|
|
21
18
|
$logger.info "Created! Logging in."
|
22
|
-
Spotify.session_login($session, $username, $password, false,
|
19
|
+
Spotify.session_login($session, $username, $password, false, $blob)
|
23
20
|
|
24
21
|
$logger.info "Log in requested. Waiting forever until logged in."
|
25
|
-
poll($session) { Spotify.session_connectionstate($session) == :logged_in }
|
22
|
+
Support.poll($session) { Spotify.session_connectionstate($session) == :logged_in }
|
26
23
|
|
27
24
|
$logger.info "Logged in as #{Spotify.session_user_name($session)}."
|
28
25
|
|
29
|
-
track_uri = prompt("Please enter an track URI")
|
26
|
+
track_uri = Support.prompt("Please enter an track URI")
|
30
27
|
link = Spotify.link_create_from_string(track_uri)
|
31
28
|
|
32
29
|
if link.null?
|
@@ -40,7 +37,7 @@ else
|
|
40
37
|
end
|
41
38
|
|
42
39
|
$logger.info "Attempting to load track. Waiting forever until successful."
|
43
|
-
poll($session) { Spotify.track_is_loaded(track) }
|
40
|
+
Support.poll($session) { Spotify.track_is_loaded(track) }
|
44
41
|
$logger.info "Track loaded."
|
45
42
|
|
46
43
|
puts Spotify.track_name(track)
|
@@ -24,6 +24,10 @@ $session_callbacks = {
|
|
24
24
|
logged_out: lambda do |session|
|
25
25
|
$logger.info('session (logged out)') { 'logged out!' }
|
26
26
|
end,
|
27
|
+
|
28
|
+
credentials_blob_updated: lambda do |session, blob|
|
29
|
+
$logger.info('session (blob)') { blob }
|
30
|
+
end
|
27
31
|
}
|
28
32
|
|
29
33
|
#
|
@@ -43,17 +47,12 @@ config = Spotify::SessionConfig.new({
|
|
43
47
|
})
|
44
48
|
|
45
49
|
$logger.info "Creating session."
|
46
|
-
|
47
|
-
# Spotify.try is a special method. It raises a ruby exception if the returned spotify
|
48
|
-
# error code is an error.
|
49
|
-
Spotify.try(:session_create, config, ptr)
|
50
|
-
$session = Spotify::Session.new(ptr.read_pointer)
|
51
|
-
end
|
50
|
+
$session = Support.create_session(config)
|
52
51
|
|
53
52
|
$logger.info "Created! Logging in."
|
54
|
-
Spotify.session_login($session, $username, $password, false,
|
53
|
+
Spotify.session_login($session, $username, $password, false, $blob)
|
55
54
|
|
56
55
|
$logger.info "Log in requested. Waiting forever until logged in."
|
57
|
-
poll($session) { Spotify.session_connectionstate($session) == :logged_in }
|
56
|
+
Support.poll($session) { Spotify.session_connectionstate($session) == :logged_in }
|
58
57
|
|
59
58
|
$logger.info "Logged in as #{Spotify.session_user_name($session)}."
|
data/lib/spotify.rb
CHANGED
@@ -30,6 +30,7 @@ module Spotify
|
|
30
30
|
|
31
31
|
begin
|
32
32
|
ffi_lib [LIBSPOTIFY_BIN, 'spotify', 'libspotify', '/Library/Frameworks/libspotify.framework/libspotify']
|
33
|
+
ffi_convention :stdcall if FFI::Platform.windows?
|
33
34
|
rescue LoadError
|
34
35
|
puts <<-ERROR.gsub(/^ */, '')
|
35
36
|
Failed to load the `libspotify` library. It is possible that the libspotify gem
|
@@ -13,6 +13,9 @@ module Spotify
|
|
13
13
|
include Enumerable
|
14
14
|
|
15
15
|
class << self
|
16
|
+
# Releases the given subscribers structure if it is not null.
|
17
|
+
#
|
18
|
+
# @param [FFI::Pointer] pointer pointing to a subscribers struct
|
16
19
|
def release(pointer)
|
17
20
|
unless pointer.null?
|
18
21
|
pointer = type_class.new(pointer)
|
data/lib/spotify/type_safety.rb
CHANGED
data/lib/spotify/util.rb
CHANGED
@@ -9,25 +9,29 @@ class << Spotify::API
|
|
9
9
|
# @example failing to retrieve a value
|
10
10
|
# Spotify.enum_value!(:moo, "connection rule") # => ArgumentError, invalid connection rule: :moo
|
11
11
|
#
|
12
|
+
# @api public
|
12
13
|
# @param [Symbol] symbol
|
13
14
|
# @param [#to_s] type used as error message when the symbol does not resolve
|
14
15
|
# @raise [ArgumentError] when the symbol does not exist as an enum value
|
16
|
+
# @return [Integer]
|
15
17
|
def enum_value!(symbol, type)
|
16
18
|
enum_value(symbol) or raise ArgumentError, "invalid #{type}: #{symbol}"
|
17
19
|
end
|
18
20
|
|
19
21
|
# @see platform
|
22
|
+
# @api public
|
20
23
|
# @return [Boolean] true if on Linux
|
21
24
|
def linux?
|
22
25
|
platform == :linux
|
23
26
|
end
|
24
27
|
|
28
|
+
# @api public
|
25
29
|
# @return [Symbol] platform as either :mac, :windows, or :linux
|
26
30
|
def platform
|
27
31
|
case FFI::Platform::OS
|
28
32
|
when /darwin/ then :mac
|
29
33
|
when /linux/ then :linux
|
30
|
-
when /
|
34
|
+
when /windows/ then :windows
|
31
35
|
else
|
32
36
|
$stderr.puts "[WARN] You are running the Spotify gem on an unknown platform. (#{__FILE__}:#{__LINE__})"
|
33
37
|
$stderr.puts "[WARN] Platform: #{FFI::Platform::OS}"
|
data/lib/spotify/version.rb
CHANGED
@@ -75,6 +75,7 @@ describe Spotify::ManagedPointer do
|
|
75
75
|
describe "garbage collection", :engine => "ruby" do
|
76
76
|
module Spotify
|
77
77
|
class << API
|
78
|
+
# Required by all ManagedPointers.
|
78
79
|
def bogus_add_ref(pointer)
|
79
80
|
end
|
80
81
|
|
@@ -89,14 +90,12 @@ describe Spotify::ManagedPointer do
|
|
89
90
|
let(:my_pointer) { FFI::Pointer.new(1) }
|
90
91
|
|
91
92
|
it "should work" do
|
92
|
-
api.stub(:bogus_add_ref)
|
93
|
-
|
94
93
|
# GC tests are a bit funky, but as long as we garbage_release at least once, then
|
95
94
|
# we can assume our GC works properly, but up the stakes just for the sake of it
|
96
95
|
api.should_receive(:bogus_release).at_least(1).times
|
97
96
|
|
98
|
-
|
99
|
-
|
97
|
+
10.times { Spotify::Bogus.new(FFI::Pointer.new(1)) }
|
98
|
+
10.times { GC.start; sleep 0.01 }
|
100
99
|
end
|
101
100
|
end
|
102
101
|
|
data/spotify.gemspec
CHANGED
@@ -3,7 +3,7 @@ require './lib/spotify/version'
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = 'spotify'
|
6
|
-
gem.summary = 'Low-level Ruby bindings for libspotify'
|
6
|
+
gem.summary = 'Low-level Ruby bindings for libspotify, the official Spotify C API'
|
7
7
|
|
8
8
|
gem.homepage = 'https://github.com/Burgestrand/spotify'
|
9
9
|
gem.authors = ["Kim Burgestrand"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 12.5.
|
4
|
+
version: 12.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kim Burgestrand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -211,10 +211,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
211
|
version: '0'
|
212
212
|
requirements: []
|
213
213
|
rubyforge_project:
|
214
|
-
rubygems_version: 2.
|
214
|
+
rubygems_version: 2.1.10
|
215
215
|
signing_key:
|
216
216
|
specification_version: 4
|
217
|
-
summary: Low-level Ruby bindings for libspotify
|
217
|
+
summary: Low-level Ruby bindings for libspotify, the official Spotify C API
|
218
218
|
test_files:
|
219
219
|
- spec/bench_helper.rb
|
220
220
|
- spec/benchmarks/managed_pointer_bench.rb
|