spotify 12.5.3 → 12.6.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d9e97a03f155c02b4b189899d152e51acc80c21
4
- data.tar.gz: 43731fc0330043a6885b08c669c2fb13418efb68
3
+ metadata.gz: 8e5e929a7c03551703eebf95485b6f4fc8d91d2b
4
+ data.tar.gz: 329f09f809e753dd0993bcd51c95dfcedeb84e13
5
5
  SHA512:
6
- metadata.gz: 519bd5a79bb4a76dd63cb2ad884cb42da3a7bc142cf851db490bdc6f35f21be15fc224911f80650a437e7152db3cd0ad4901ce25e0d62f414aea8aec900447cf
7
- data.tar.gz: f0b4bc4da8b176121aa4cb62c276142086084e8d8334fc291d76a740693ec218f170c6cf478023d0a971b04a27c68fab07b80f7a14c1c6625f66fbe00f1c5fbb
6
+ metadata.gz: 929d6bfcdec85e642e301f6278d9b2c52cf42975304ad0fc5aa7fbceee404af6dbf9598011a9bc8d43921d7a95d97f9f1ed41b6cbd41cdf10c872f6bdb4e92f2
7
+ data.tar.gz: fd761313e677f2556992ca4fde3fb2fe27bcb9e7af5af1b2de1b30c425b0647ef1241ce5bfaaf18e0774d216fa15132b81af05979e3d2115a8812fa72813f7f1
data/.gitignore CHANGED
@@ -7,3 +7,5 @@ doc/
7
7
  .yardoc
8
8
  .rbx
9
9
  *.rbc
10
+ .spotify/
11
+ spotify_appkey.key
@@ -1,6 +1,21 @@
1
+ language: ruby
2
+ script: "bundle exec ruby -W -S rspec spec"
3
+ cache: bundler
1
4
  rvm:
2
- - 1.9.2
3
- - 1.9.3
4
- - 2.0.0
5
- - rbx-19mode
6
- - jruby-19mode
5
+ - 2.0
6
+ - 2.1
7
+ - ruby-head
8
+ - rbx-2
9
+ - jruby
10
+ env:
11
+ - RUBY_PLATFORM="x86_64-linux"
12
+ - RUBY_PLATFORM="x86_64-darwin11.3.0"
13
+ matrix:
14
+ allow_failures:
15
+ - rvm: ruby-head
16
+ notifications:
17
+ email:
18
+ recipients:
19
+ - kim@burgestrand.se
20
+ on_success: change
21
+ on_failure: change
@@ -1,6 +1,34 @@
1
1
  [HEAD][]
2
2
  -----------
3
3
 
4
+ This change features a few large improvements:
5
+
6
+ - A bunch of API calls have been improved to remove FFI pointer juggling. Methods
7
+ such as e.g. #session_create, or #link_as_string are now much easier to use. See
8
+ https://github.com/Burgestrand/spotify/issues/19 for more details.
9
+ - Documentation has been much improved by (more or less) copying documentation
10
+ from libspotify docs, and adding some notes and examples to it.
11
+ - All API calls are now called in a specific background thread, powered by the
12
+ [Performer](https://rubygems.org/gems/performer) gem. This replaces the previous
13
+ mutex lock around all API calls, and possibly fixes a lot of random deadlocks.
14
+ See https://github.com/Burgestrand/spotify/issues/23.
15
+ - API reference documentation (YARD) has been added to all methods.
16
+ - Errors are no longer symbols, but actual errors inheriting from Spotify::APIError
17
+
18
+ Keep in mind that these changes are not backwards-compatible.
19
+
20
+ - [d80b9249] Make one class for each kind of error, instead of using symbols
21
+ - [0da56807] Move utility methods to Spotify::Util
22
+ - [72ee2526] Officially drop support for Ruby 1.9
23
+ - [dc492876] Perform *all* API calls in a specific Spotify thread
24
+ - [f5244743] A warning is now displayed on API mismatch instead of an error
25
+ - [dda1bc53] null pointers have been replaced by `nil`
26
+ - [98b5b1e0] Automatically encode country codes in #session_user_country
27
+ - [c8ad624e] Add #code and #symbol to Spotify::Error
28
+ - [77d1b978] Do not raise an error in Spotify.try when the resource is loading
29
+ - [f8293775] Print to stderr instead of stdout when libspotify cannot be found
30
+ - [c7042db6] Added Spotify.log (private API)
31
+
4
32
  [v12.5.3][]
5
33
  -----------
6
34
 
@@ -208,7 +236,7 @@ v0.0.0
208
236
 
209
237
  [HEAD]: https://github.com/Burgestrand/spotify/compare/v12.5.3...HEAD
210
238
 
211
- [v12.5.2]: https://github.com/Burgestrand/spotify/compare/v12.5.2...v12.5.3
239
+ [v12.5.3]: https://github.com/Burgestrand/spotify/compare/v12.5.2...v12.5.3
212
240
  [v12.5.2]: https://github.com/Burgestrand/spotify/compare/v12.5.1...v12.5.2
213
241
  [v12.5.1]: https://github.com/Burgestrand/spotify/compare/v12.5.0...v12.5.1
214
242
  [v12.5.0]: https://github.com/Burgestrand/spotify/compare/v12.4.0...v12.5.0
data/Gemfile CHANGED
@@ -6,3 +6,8 @@ gem 'pry'
6
6
  gem 'yard'
7
7
  gem 'maruku'
8
8
  gem "plaything", "~> 1.1"
9
+
10
+ platform :rbx do
11
+ gem "rubysl"
12
+ gem "racc"
13
+ end
@@ -0,0 +1,21 @@
1
+ License
2
+ -------
3
+ Copyright (c) 2011-2013 Kim Burgestrand <kim@burgestrand.se>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -20,85 +20,110 @@ The Spotify gem has:
20
20
 
21
21
  - [100% API coverage][], including callback support. You’ll be able to use any function from the libspotify library.
22
22
  - [Automatic garbage collection][]. Piggybacking on Ruby’s GC to manage pointer lifecycle.
23
- - [Parallell function call protection][]. libspotify is not thread-safe, but Spotify protects you by providing a re-entrant mutex around function calls.
23
+ - [Parallell function call protection][]. libspotify is not thread-safe, but Spotify protects you by making all API calls in a specific background thread.
24
24
  - [Type conversion and type safety][]. Special pointers for every Spotify type, protecting you from accidental mix-ups.
25
- - [Support for JRuby and Rubinius][]. Thanks to FFI, the gem runs fine on the main three Ruby implementations!
25
+ - [Support for Ruby, JRuby and Rubinius][]. Thanks to FFI, the gem runs fine on the main three Ruby implementations!
26
26
 
27
27
  [100% API coverage]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API
28
28
  [Automatic garbage collection]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/ManagedPointer
29
29
  [Parallell function call protection]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify#method_missing-class_method
30
30
  [Type conversion and type safety]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/ManagedPointer
31
- [Support for JRuby and Rubinius]: https://github.com/Burgestrand/spotify/blob/master/.travis.yml
31
+ [Support for Ruby, JRuby and Rubinius]: https://github.com/Burgestrand/spotify/blob/master/.travis.yml
32
32
 
33
33
  Contact details
34
34
  ---------------
35
35
 
36
- - __Got questions?__ Ask on the mailing list: [ruby-hallon@googlegroups.com][] (<https://groups.google.com/d/forum/ruby-hallon>)
36
+ - __Got questions?__ Ask on the mailing list: [ruby-spotify@googlegroups.com][] (<https://groups.google.com/d/forum/ruby-spotify>)
37
37
  - __Found a bug?__ Report an issue: <https://github.com/Burgestrand/spotify/issues/new>
38
38
  - __Have feedback?__ I ❤ feedback! Please send it to the mailing list.
39
39
 
40
- Spotify API is best used with a supporting library
41
- --------------------------------------------------
42
- As the raw libspotify API is exposed, the Spotify gem is best coupled with a supporting
43
- library. This library would take a more focused approach to which kind of applications
44
- you can write using it. The Spotify gem itself, however, has very few opinions.
40
+ Questions, notes and answers
41
+ ----------------------------
45
42
 
46
- Known supporting libraries:
43
+ ### Links to keep close at hand when using libspotify
47
44
 
48
- - [Hallon](https://github.com/Burgestrand/Hallon). Hallon attempted to be a one-gem-does-all,
49
- at a higher abstraction level than the Spotify gem. It features a slightly more convenient
50
- API for certain things, and requires no ruby FFI knowledge, but it is not really an expert
51
- on any use case.
45
+ - [spotify gem API reference](http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API) YARDoc reference for the spotify gem, maps to the [libspotify function list](https://developer.spotify.com/docs/libspotify/12.1.51/api_8h.html).
46
+ - [libspotify C API reference](https://developer.spotify.com/docs/libspotify/12.1.51/) the one true source of documentation.
47
+ - [libspotify FAQ](https://developer.spotify.com/technologies/libspotify/faq/) you should read this at least once.
48
+ - [spotify gem examples](https://github.com/Burgestrand/spotify/tree/master/examples) — located in the spotify gem repository.
49
+ - [spotify gem FAQ](#questions-notes-and-answers) — this README section.
52
50
 
53
- The Spotify API is well suited for experimentation, and it can be awfully fun to play with.
54
- The examples/ directory contains example code for achieving certain tasks with the Spotify gem.
55
51
 
56
- If you need any assitance feel free to post a message on the mailing list: [ruby-hallon@googlegroups.com][].
52
+ ### How to run the examples
57
53
 
58
- Manually installing libspotify
59
- ------------------------------
60
- By default, Spotify uses [the libspotify gem](https://rubygems.org/gems/libspotify) which means you do
61
- not need to install libspotify yourself. However, if your platform is not supported by the libspotify
62
- gem you will need to install libspotify yourself.
54
+ You’ll need:
63
55
 
64
- Please note, that if your platform is not supported by the libspotify gem Id very much appreciate it
65
- if you could create an issue on [libspotify gem issue tracker](https://github.com/Burgestrand/libspotify/issues)
66
- so I can fix the build for your platform.
56
+ 1. Your [Spotify](http://spotify.com/) premium account credentials. If you sign in with Facebook, youll need your Facebook account e-mail and password.
57
+ 2. Your [Spotify application key](https://developer.spotify.com/technologies/libspotify/keys/). Download the binary key, and put it in the `examples/` directory.
58
+
59
+ Running the examples is as simple as:
60
+
61
+ ```
62
+ ruby example-audio_stream.rb
63
+ ```
64
+
65
+ Available examples are:
66
+
67
+ - **example-audio_stream.rb**: plays songs from Spotify with the [plaything](https://github.com/Burgestrand/plaything) gem, using OpenAL.
68
+ - **example-console.rb**: logs in to Spotfify, and initiates a pry session to allow experimentation with the spotify gem API.
69
+ - **example-listing_playlists.rb**: list all playlists available for a certain user.
70
+ - **example-loading_object.rb**: loads a track using polling and the spotify gem API.
71
+ - **example-random_related_artists.rb**: looks up an artist and its similar artists on spotify, then it picks a similar artist at random and does the same to that artist, over and over. I have used this example file to test prolonged usage of the API.
72
+
73
+ ### Creating a Session, the first thing you should do
74
+
75
+ Almost all functions require you to have created a session before calling them. Forgetting to do so won’t work at best, and will segfault at worst. You'll also want to log in before doing things as well, or objects will never load.
76
+
77
+ See [Spotify::API#session_create](http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API#session_create-instance_method) for how to create a session.
78
+ See [Spotify::API#session_login](http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API#session_login-instance_method) for logging in.
79
+
80
+ ### libspotify is an asynchronous library
81
+
82
+ When creating objects in libspotify they are not populated with data instantly, instead libspotify schedules them for download from the Spotify backend. For libspotify to do it's work with downloading content, you need to call [Spotify::API#session_process_events](http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API#session_process_events-instance_method) regularly.
83
+
84
+ ### Facebook vs Spotify Classic
67
85
 
68
- While you’re waiting for the issue to resolve you could install libspotify manually. I’ve provided
69
- instructions on how to do this in Hallon’s wiki: [How to install libspotify](https://github.com/Burgestrand/Hallon/wiki/How-to-install-libspotify)!
86
+ Users who signed up to Spotify with their Facebook account will have numeric IDs as usernames, so a link to their profile looks like [spotify:user:11101648092](spotify:user:11101648092). Spotify Classic users instead have their usernames as canonical name, so a link to their profile looks like [spotify:user:burgestrand](spotify:user:burgestrand).
87
+
88
+ This matters, for example, when you use the function [Spotify::API#session_publishedcontainer_for_user_create](http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API#session_publishedcontainer_for_user_create-instance_method).
89
+
90
+ ### Callbacks can be dangerous
91
+
92
+ libspotify allows you to pass callbacks that will be invoked by libspotify when events of interest occur, such as being logged out, or receiving audio data when playing a track.
93
+
94
+ Callbacks can be very tricky. They must never be garbage collected while they are in use by libspotify, or you may get very weird bugs with your Ruby interpreter randomly crashing. Do use them, but be careful.
95
+
96
+ ### Opinions and the Spotify gem
97
+
98
+ The Spotify gem has very few opinions. It is build to closely resemble the libspotify C API, and has very little
99
+ to aid you in terms of how to structure your application. It aims to make calling the libspotify C API frictionless,
100
+ but not much more. It is up to you to decide your own path.
101
+
102
+ ### A note about gem versioning
70
103
 
71
- A note about versioning scheme
72
- ------------------------------
73
104
  Given a version `X.Y.Z`, each segment corresponds to:
74
105
 
75
- - X reflects supported libspotify version (12.1.45 => 12). There are __no guarantees__ of backwards-compatibility!
76
- - Y(major).Z(minor) follows [semantic versioning (semver.org)][]. Y is for backwards-**incompatible** changes, Z is for backwards-**compatible** changes.
106
+ - `X` reflects supported libspotify version (12.1.45 => 12). There are __no guarantees__ of backwards-compatibility!
107
+ - `Y` is for backwards-**incompatible** changes.
108
+ - `Z` is for backwards-**compatible** changes.
109
+
110
+ You should use the following version constraint: `gem "spotify", "~> 12.5.3"`.
77
111
 
78
- License
79
- -------
80
- Copyright (c) 2012 Kim Burgestrand <kim@burgestrand.se>
81
112
 
82
- Permission is hereby granted, free of charge, to any person obtaining a copy
83
- of this software and associated documentation files (the "Software"), to deal
84
- in the Software without restriction, including without limitation the rights
85
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
86
- copies of the Software, and to permit persons to whom the Software is
87
- furnished to do so, subject to the following conditions:
113
+ ### Manually installing libspotify
88
114
 
89
- The above copyright notice and this permission notice shall be included in
90
- all copies or substantial portions of the Software.
115
+ By default, Spotify uses [the libspotify gem](https://rubygems.org/gems/libspotify) which means you do
116
+ not need to install libspotify yourself. However, if your platform is not supported by the libspotify
117
+ gem you will need to install libspotify yourself.
118
+
119
+ Please note, that if your platform is not supported by the libspotify gem I’d very much appreciate it
120
+ if you could create an issue on [libspotify gem issue tracker](https://github.com/Burgestrand/libspotify/issues)
121
+ so I can fix the build for your platform.
91
122
 
92
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
94
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
95
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
96
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
97
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
98
- THE SOFTWARE.
123
+ Instructions on installing libspotify manually are in the wiki: [How to install libspotify](https://github.com/Burgestrand/spotify/wiki)
99
124
 
100
125
  [semantic versioning (semver.org)]: http://semver.org/
101
- [ruby-hallon@googlegroups.com]: mailto:ruby-hallon@googlegroups.com
126
+ [ruby-spotify@googlegroups.com]: mailto:ruby-spotify@googlegroups.com
102
127
  [libspotify]: https://developer.spotify.com/technologies/libspotify/
103
128
  [Spotify]: https://www.spotify.com/
104
129
  [Hallon]: https://github.com/Burgestrand/Hallon
data/Rakefile CHANGED
@@ -33,7 +33,7 @@ task :gen do
33
33
  end
34
34
 
35
35
  task :console do
36
- exec "irb", "-Ilib", "-rspotify"
36
+ exec "pry", "-Ilib", "-rspotify"
37
37
  end
38
38
 
39
39
  require 'rspec/core/rake_task'
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # NOTE: this example is merely here to count how fast audio frames
5
+ # can be delivered. It does not do anything useful.
6
+
7
+ require_relative "support"
8
+ require "json"
9
+
10
+ $frames = 0
11
+ $rate = 0
12
+
13
+ Support::DEFAULT_CONFIG[:callbacks] = Spotify::SessionCallbacks.new({
14
+ music_delivery: proc do |session, format, frames, num_frames|
15
+ $rate = format[:sample_rate]
16
+ $frames += num_frames
17
+ num_frames
18
+ end,
19
+
20
+ end_of_track: proc do |session|
21
+ puts "End of track!"
22
+ $end_of_track = true
23
+ end
24
+ })
25
+
26
+ session = Support.initialize_spotify!
27
+
28
+ link = Spotify.link_create_from_string("spotify:track:1Lm5kdSQX6x1uVz6ep3AIk")
29
+ track = Spotify.link_as_track(link)
30
+
31
+ Support.poll(session) { Spotify.track_is_loaded(track) }
32
+
33
+ Spotify.try(:session_player_load, session, track)
34
+ Spotify.try(:session_player_play, session, true)
35
+
36
+ measurer = Thread.new do
37
+ loop do
38
+ if $rate
39
+ frames, $frames = $frames, 0
40
+ puts "#{frames}f of #{$rate}f/s (#{frames.fdiv($rate).round(2)}s)"
41
+ end
42
+ sleep 1
43
+ end
44
+ end
45
+
46
+ $logger.info "Playing track until end. Use ^C to exit."
47
+ Support.silenced = true
48
+ Support.poll(session) { $end_of_track }
@@ -1,18 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
 
4
- require_relative "example_support"
4
+ require_relative "support"
5
5
 
6
6
  require "json"
7
7
  require "plaything"
8
8
 
9
- def play_track(uri)
9
+ def play_track(session, uri)
10
10
  link = Spotify.link_create_from_string(uri)
11
11
  track = Spotify.link_as_track(link)
12
- Support.poll($session) { Spotify.track_is_loaded(track) }
13
- Spotify.try(:session_player_play, $session, false)
14
- Spotify.try(:session_player_load, $session, track)
15
- Spotify.try(:session_player_play, $session, true)
12
+ Support.poll(session) { Spotify.track_is_loaded(track) }
13
+
14
+ # Pause before we load a new track. Fixes a quirk in libspotify.
15
+ Spotify.try(:session_player_play, session, false)
16
+ Spotify.try(:session_player_load, session, track)
17
+ Spotify.try(:session_player_play, session, true)
16
18
  end
17
19
 
18
20
  class FrameReader
@@ -55,7 +57,7 @@ $session_callbacks = {
55
57
  end,
56
58
 
57
59
  logged_in: proc do |session, error|
58
- $logger.debug("session (logged in)") { Spotify::Error.explain(error) }
60
+ $logger.debug("session (logged in)") { error.message }
59
61
  end,
60
62
 
61
63
  logged_out: proc do |session|
@@ -63,7 +65,7 @@ $session_callbacks = {
63
65
  end,
64
66
 
65
67
  streaming_error: proc do |session, error|
66
- $logger.error("session (player)") { "streaming error %s" % Spotify::Error.explain(error) }
68
+ $logger.error("session (player)") { "streaming error %s" % error.message }
67
69
  end,
68
70
 
69
71
  start_playback: proc do |session|
@@ -109,28 +111,11 @@ $session_callbacks = {
109
111
  # You can read about what these session configuration options do in the
110
112
  # libspotify documentation:
111
113
  # https://developer.spotify.com/technologies/libspotify/docs/12.1.45/structsp__session__config.html
112
- config = Spotify::SessionConfig.new({
113
- api_version: Spotify::API_VERSION.to_i,
114
- application_key: $appkey,
115
- cache_location: ".spotify/",
116
- settings_location: ".spotify/",
117
- tracefile: "spotify_tracefile.txt",
118
- user_agent: "spotify for ruby",
119
- callbacks: Spotify::SessionCallbacks.new($session_callbacks),
120
- })
121
-
122
- $logger.info "Creating session."
123
- $session = Support.create_session(config)
124
-
125
- $logger.info "Created! Logging in."
126
- Spotify.session_login($session, $username, $password, false, $blob)
127
-
128
- $logger.info "Log in requested. Waiting forever until logged in."
129
- Support.poll($session) { Spotify.session_connectionstate($session) == :logged_in }
114
+ Support::DEFAULT_CONFIG[:callbacks] = Spotify::SessionCallbacks.new($session_callbacks)
130
115
 
131
- $logger.info "Logged in as #{Spotify.session_user_name($session)}."
116
+ session = Support.initialize_spotify!
132
117
 
133
- play_track Support.prompt("Spotify track URI")
118
+ play_track(session, Support.prompt("Spotify track URI", "spotify:track:5iIeIeH3LBSMK92cMIXrVD"))
134
119
 
135
120
  $logger.info "Playing track until end. Use ^C to exit."
136
- Support.poll($session) { $end_of_track }
121
+ Support.poll(session) { $end_of_track }
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require_relative "support"
5
+
6
+ session = Support.initialize_spotify!
7
+
8
+ $logger.info "Logged in as #{Spotify.session_user_name(session)}! Entering interactive session…"
9
+ binding.pry
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require_relative "support"
5
+
6
+ session = Support.initialize_spotify!
7
+
8
+ username = Support.prompt("Please enter a username", "burgestrand")
9
+
10
+ # libspotify has no way of searching for users by name or e-mail, so
11
+ # this is the only way I know of to get a handle of a user from nothing,
12
+ # and probably won't work for users that do not have a classic Spotify
13
+ # username, i.e. users that only signed up through Facebook.
14
+ #
15
+ # If you can get a handle on a playlist created by that user, you'll be
16
+ # able to get the handle for them, but not otherwise!
17
+ #
18
+ # For users that signed up through Facebook only, I believe their Facebook
19
+ # user ID should work with this lookup.
20
+ user_link = "spotify:user:#{username}"
21
+ link = Spotify.link_create_from_string(user_link)
22
+
23
+ if link.null?
24
+ $logger.error "#{user_link} was apparently not parseable as a Spotify URI. Aborting."
25
+ abort
26
+ end
27
+
28
+ user = Spotify.link_as_user(link)
29
+ $logger.info "Attempting to load #{user_link}. Waiting forever until successful."
30
+ Support.poll(session) { Spotify.user_is_loaded(user) }
31
+
32
+ display_name = Spotify.user_display_name(user)
33
+ canonical_name = Spotify.user_canonical_name(user)
34
+ $logger.info "User loaded: #{display_name}."
35
+
36
+ $logger.info "Loading user playlists by loading their published container: #{canonical_name}."
37
+ container = Spotify.session_publishedcontainer_for_user_create(session, canonical_name)
38
+
39
+ $logger.info "Attempting to load container. Waiting forever until successful."
40
+ Support.poll(session) { Spotify.playlistcontainer_is_loaded(container) }
41
+
42
+ $logger.info "Container loaded. Loading playlists until no more are loaded for three tries!"
43
+
44
+ container_size = 0
45
+ previous_container_size = 0
46
+ break_counter = 0
47
+
48
+ loop do
49
+ container_size = Spotify.playlistcontainer_num_playlists(container)
50
+ new_playlists = container_size - previous_container_size
51
+ previous_container_size = container_size
52
+ $logger.info "Loaded #{new_playlists} more playlists."
53
+
54
+ # If we have loaded no new playlists for 4 tries, we assume we are done.
55
+ if new_playlists == 0
56
+ break_counter += 1
57
+ if break_counter >= 4
58
+ break
59
+ end
60
+ end
61
+
62
+ $logger.info "Loading…"
63
+ 5.times do
64
+ Support.process_events(session)
65
+ sleep 0.2
66
+ end
67
+ end
68
+
69
+ $logger.info "#{container_size} published playlists for #{display_name} found. Loading each playlists and printing it."
70
+ container_size.times do |index|
71
+ type = Spotify.playlistcontainer_playlist_type(container, index)
72
+ playlist = Spotify.playlistcontainer_playlist(container, index)
73
+ Support.poll(session) { Spotify.playlist_is_loaded(playlist) }
74
+
75
+ playlist_name = Spotify.playlist_name(playlist)
76
+ num_tracks = Spotify.playlist_num_tracks(playlist)
77
+
78
+ # Retrieving link for playlist:
79
+ playlist_link = Spotify.link_create_from_playlist(playlist)
80
+ link_string = if playlist_link.nil?
81
+ "(no link)"
82
+ else
83
+ Spotify.link_as_string(playlist_link)
84
+ end
85
+
86
+ $logger.info " (#{type}) #{playlist_name}: #{link_string} (#{num_tracks} tracks)"
87
+ end
88
+
89
+ $logger.info "All done."