spotify 12.5.2 → 12.5.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/Burgestrand/spotify.png?branch=master)](http://travis-ci.org/Burgestrand/spotify)
|
4
|
+
[![Dependency Status](https://gemnasium.com/Burgestrand/spotify.png)](https://gemnasium.com/Burgestrand/spotify)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/Burgestrand/spotify.png)](https://codeclimate.com/github/Burgestrand/spotify)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/spotify.png)](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
|