spotify_web 0.0.1
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 +7 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +309 -0
- data/Rakefile +13 -0
- data/examples/playlists.rb +14 -0
- data/lib/spotify_web.rb +105 -0
- data/lib/spotify_web/album.rb +58 -0
- data/lib/spotify_web/artist.rb +54 -0
- data/lib/spotify_web/assertions.rb +36 -0
- data/lib/spotify_web/authorized_user.rb +119 -0
- data/lib/spotify_web/client.rb +369 -0
- data/lib/spotify_web/connection.rb +162 -0
- data/lib/spotify_web/error.rb +13 -0
- data/lib/spotify_web/event.rb +95 -0
- data/lib/spotify_web/handler.rb +74 -0
- data/lib/spotify_web/loggable.rb +13 -0
- data/lib/spotify_web/playlist.rb +48 -0
- data/lib/spotify_web/resource.rb +309 -0
- data/lib/spotify_web/resource_collection.rb +99 -0
- data/lib/spotify_web/restriction.rb +32 -0
- data/lib/spotify_web/schema.rb +120 -0
- data/lib/spotify_web/schema/core.pb.rb +31 -0
- data/lib/spotify_web/schema/mercury.pb.rb +66 -0
- data/lib/spotify_web/schema/metadata.pb.rb +257 -0
- data/lib/spotify_web/schema/playlist4.pb.rb +461 -0
- data/lib/spotify_web/schema/radio.pb.rb +110 -0
- data/lib/spotify_web/schema/socialgraph.pb.rb +106 -0
- data/lib/spotify_web/song.rb +58 -0
- data/lib/spotify_web/user.rb +7 -0
- data/lib/spotify_web/version.rb +9 -0
- data/lib/tasks/spotify_web.rake +1 -0
- data/lib/tasks/spotify_web.rb +9 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/spotify_web_spec.rb +4 -0
- data/spotify_web.gemspec +27 -0
- metadata +216 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ccebcb20e1139746afe7ca5f70693c2c945e656
|
4
|
+
data.tar.gz: 50db822ca1f7be0f0e3af6b2e5014c25c27e0b58
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 00d54b4013292872b94b2e19bce1a1fbb3df5cddb31023803b64bc49a07453986ffc433a7d91964358fe05f5cf01e6e3b2bd34bc69663d5fb802ba54d0de6cd2
|
7
|
+
data.tar.gz: f81b8a6a289e16a7ff57042ac867c556cc21ccc3d254457835777deb183762703bcc4ba1914be3be2b614540ae1ba3001e721687d69dd7cd70d6d179f147aea5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.yardopts
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Aaron Pfeifer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,309 @@
|
|
1
|
+
# spotify_web [](http://travis-ci.org/obrie/spotify_web) [](https://gemnasium.com/obrie/spotify_web)
|
2
|
+
|
3
|
+
*spotify_web* is an evented Spotify Web API for Ruby.
|
4
|
+
|
5
|
+
## Resources
|
6
|
+
|
7
|
+
API
|
8
|
+
|
9
|
+
* http://rdoc.info/github/obrie/spotify_web/master/frames
|
10
|
+
|
11
|
+
Bugs
|
12
|
+
|
13
|
+
* http://github.com/obrie/spotify_web/issues
|
14
|
+
|
15
|
+
Development
|
16
|
+
|
17
|
+
* http://github.com/obrie/spotify_web
|
18
|
+
|
19
|
+
Testing
|
20
|
+
|
21
|
+
* http://travis-ci.org/obrie/spotify_web
|
22
|
+
|
23
|
+
Source
|
24
|
+
|
25
|
+
* git://github.com/obrie/spotify_web.git
|
26
|
+
|
27
|
+
## Description
|
28
|
+
|
29
|
+
SpotifyWeb makes it dead-simple to interact with the unofficial Spotify Web API.
|
30
|
+
It is an opinionated library that attempts to hide the various complexities of
|
31
|
+
the Spotify API by providing a clean design around how data is accessed and
|
32
|
+
organized.
|
33
|
+
|
34
|
+
This project was built from the ground-up by Rubyists for Rubyists. While prior
|
35
|
+
projects in other languages were used for guidance on some of the implementation,
|
36
|
+
the design is meant to take advantage of the various features offered by Ruby 1.9+.
|
37
|
+
|
38
|
+
At a high level, this project features:
|
39
|
+
|
40
|
+
* Evented, non-blocking I/O
|
41
|
+
* Fiber-aware, untangled callbacks
|
42
|
+
* Interactive console support
|
43
|
+
* Clean, object-oriented APIs
|
44
|
+
* Detailed API documentation
|
45
|
+
* Lazy-loaded attributes
|
46
|
+
* Auto-reconnects for bots
|
47
|
+
* Consistent API / attribute naming schemes
|
48
|
+
* DSL syntax support
|
49
|
+
|
50
|
+
SpotifyWeb features include access to / management of:
|
51
|
+
|
52
|
+
* User playlists
|
53
|
+
* Artist / Album / Song metadata
|
54
|
+
* Others to be added...
|
55
|
+
|
56
|
+
Examples of the usage patterns for some of the above features are shown below.
|
57
|
+
You can find much more detailed documentation in the actual API.
|
58
|
+
|
59
|
+
## Usage
|
60
|
+
|
61
|
+
### Example
|
62
|
+
|
63
|
+
Below is an example of some of the features offered by this API:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
require 'spotify_web'
|
67
|
+
|
68
|
+
USERNAME = ENV['USERNAME']
|
69
|
+
PASSWORD = ENV['PASSWORD']
|
70
|
+
|
71
|
+
SpotifyWeb.run do
|
72
|
+
client = SpotifyWeb::Client.new(USERNAME, PASSWORD)
|
73
|
+
|
74
|
+
# Events
|
75
|
+
client.on :session_authenticated do
|
76
|
+
# ...
|
77
|
+
end
|
78
|
+
|
79
|
+
# Authorized user interactions
|
80
|
+
user = client.user # => #<SpotifyWeb::AuthorizedUser @username="benzelano" ...>
|
81
|
+
|
82
|
+
# Playlist interaction
|
83
|
+
user.playlists # => [#<SpotifyWeb::Playlist @uri="hm://playlist/user/..." ...>, ...]
|
84
|
+
user.playlist(:starred).songs.each do
|
85
|
+
song.artist.name
|
86
|
+
song.artist.albums
|
87
|
+
song.artist.top_songs
|
88
|
+
song.title
|
89
|
+
song.album.published_on
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
The example above is just a very, very small subset of the possible things you
|
95
|
+
can do with spotify_web. For a *complete* list, see the API documentation, especially:
|
96
|
+
|
97
|
+
* [SpotifyWeb::Album](http://rdoc.info/github/obrie/spotify_web/master/frames/SpotifyWeb/Album)
|
98
|
+
* [SpotifyWeb::Artist](http://rdoc.info/github/obrie/spotify_web/master/frames/SpotifyWeb/Artist)
|
99
|
+
* [SpotifyWeb::AuthorizedUser](http://rdoc.info/github/obrie/spotify_web/master/frames/SpotifyWeb/AuthorizedUser)
|
100
|
+
* [SpotifyWeb::Client](http://rdoc.info/github/obrie/spotify_web/master/frames/SpotifyWeb/Client)
|
101
|
+
* [SpotifyWeb::Playlist](http://rdoc.info/github/obrie/spotify_web/master/frames/SpotifyWeb/Playlist)
|
102
|
+
* [SpotifyWeb::Song](http://rdoc.info/github/obrie/spotify_web/master/frames/SpotifyWeb/Song)
|
103
|
+
|
104
|
+
For additional examples, see the [examples](https://github.com/obrie/spotify_web/tree/master/examples)
|
105
|
+
directory in the repository.
|
106
|
+
|
107
|
+
## Additional Topics
|
108
|
+
|
109
|
+
### Differences with existing libraries
|
110
|
+
|
111
|
+
So you may be asking "Why re-build this in Ruby when you have a stable
|
112
|
+
Javascript project?" There are two main reasons. First, one of the projects
|
113
|
+
that need this was in Ruby and preferred to have a Ruby interface to the APi.
|
114
|
+
Second, I felt that many of the high-level details highlighted in the
|
115
|
+
Description section of this document were missing in existing libraries.
|
116
|
+
|
117
|
+
Some of those details include untangled callbacks, object-oriented APIs,
|
118
|
+
external API consistency, auto lazy-loading, etc. This library also strives
|
119
|
+
to be a complete implementation and easy to use / play around with.
|
120
|
+
|
121
|
+
By no means does this discredit the significance and usefulness of the other
|
122
|
+
libraries -- they all have a user and all provided the foundation necessary
|
123
|
+
to build out this project.
|
124
|
+
|
125
|
+
### Authentication
|
126
|
+
|
127
|
+
spotify_web authenticates users with the username and password associated with
|
128
|
+
their account. For example:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
SpotifyWeb.run do
|
132
|
+
client = SpotifyWeb::Client.new(USERNAME, PASSWORD)
|
133
|
+
# ...
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
### Interactive Console
|
138
|
+
|
139
|
+
Typically it's difficult to debug or run simple tests within IRB when using
|
140
|
+
[EventMachine](http://rubyeventmachine.com/). However, spotify_web provides a
|
141
|
+
few simple ways to do this so that you can play around with the API interactively.
|
142
|
+
|
143
|
+
For example:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
1.9.3-p286 :001 > require 'spotify_web'
|
147
|
+
=> true
|
148
|
+
1.9.3-p286 :002 > SpotifyWeb.interactive
|
149
|
+
=> true
|
150
|
+
1.9.3-p286 :003 > client = nil
|
151
|
+
=> nil
|
152
|
+
1.9.3-p286 :004 > SpotifyWeb.run do
|
153
|
+
1.9.3-p286 :005 > client = SpotifyWeb::Client.new(USERAME, PASSWORD)
|
154
|
+
1.9.3-p286 :006 > end
|
155
|
+
=> nil
|
156
|
+
|
157
|
+
# later on...
|
158
|
+
1.9.3-p286 :008 > SpotifyWeb.run { puts client.playlists.inspect }
|
159
|
+
=> nil
|
160
|
+
[#<SpotifyWeb::Playlist:0xa0c7da8 @uri="...">, #<SpotifyWeb::Playlist:0xa0c7bf0 @uri="...">]
|
161
|
+
```
|
162
|
+
|
163
|
+
In this example, an instance of `SpotifyWeb::Client` is created and tracked in
|
164
|
+
the console. Later on, we can then run a command on that client by evaluating
|
165
|
+
it within a `SpotifyWeb.run` block.
|
166
|
+
|
167
|
+
### DSL syntax
|
168
|
+
|
169
|
+
spotify_web has basic support for a DSL language in order to simplify some of the
|
170
|
+
scripts you may be writing. The DSL is essentially made available by executing
|
171
|
+
blocks within the context of a `SpotifyWeb::Client` instance.
|
172
|
+
|
173
|
+
There are two ways to do this:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
# Using the SpotifyWeb.run shortcut:
|
177
|
+
|
178
|
+
SpotifyWeb.run(USERNAME, PASSWORD) do
|
179
|
+
playlists.each do
|
180
|
+
# ...
|
181
|
+
end
|
182
|
+
on :session_authenticated do
|
183
|
+
# ...
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Passing a block into SpotifyWeb::Client:
|
188
|
+
|
189
|
+
SpotifyWeb.run do
|
190
|
+
SpotifyWeb::Client.new(USERNAME, PASSWORD) do
|
191
|
+
playlists.each do
|
192
|
+
# ...
|
193
|
+
end
|
194
|
+
on :session_authenticated do
|
195
|
+
# ...
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
*Note* that you will likely not want to use the first example (using the
|
202
|
+
`SpotifyWeb.run` shortcut) when running in the context of a web request in a
|
203
|
+
web server, simply because it will start a new Fiber.
|
204
|
+
|
205
|
+
The equivalent, non-DSL example looks like so:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
SpotifyWeb.run do
|
209
|
+
client = SpotifyWeb::Client.new(USERNAME, PASSWORD)
|
210
|
+
client.playlists.each do
|
211
|
+
# ...
|
212
|
+
end
|
213
|
+
client.on :session_authenticated do
|
214
|
+
# ...
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
Notice that in this example the syntax is essentially the same except that we're
|
220
|
+
one level out and need to interact directly with the `SpotifyWeb::Client`
|
221
|
+
instance itself.
|
222
|
+
|
223
|
+
## Deployment
|
224
|
+
|
225
|
+
### Web Server Usage
|
226
|
+
|
227
|
+
You'll notice that in many places in the documentation, `SpotifyWeb.run` is
|
228
|
+
used to start running a block of code for interacting with the API. This is
|
229
|
+
done in order to ensure that the block of code is being run with a running
|
230
|
+
EventMachine and within a non-root Fiber.
|
231
|
+
|
232
|
+
When spotify_web is being used as part of a web server or anything else that's
|
233
|
+
already running EventMachine and already executing code within a non-root Fiber
|
234
|
+
(such as the rainbows web server) you *should not* using the `run` API. Instead
|
235
|
+
you can just run your block like normal:
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
client = SpotifyWeb::Client.new(USERNAME, PASSWORD)
|
239
|
+
playlists = client.user.playlists
|
240
|
+
# ...
|
241
|
+
```
|
242
|
+
|
243
|
+
### Persistent Usage
|
244
|
+
|
245
|
+
If you're using spotify_web for persistence, long-lived usage, the primary thing to keep
|
246
|
+
in mind is how to handle connection loss. This can occur as a result of a lost
|
247
|
+
internet connection or even just Spotify forcefully closing a socket for unknown
|
248
|
+
reasons. To protect against this, you can configure spotify_web to automatically
|
249
|
+
keep attempting to re-open a connection when it's been closed.
|
250
|
+
|
251
|
+
For example:
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
SpotifyWeb.run(USERNAME, PASSWORD, :reconnect => true, :reconnect_wait => 60) do
|
255
|
+
# ...
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
In this example, spotify_web will automatically attempt to reconnect if the socket
|
260
|
+
is ever closed by reasons other than you closing it yourself. However, rather
|
261
|
+
than constantly trying to hit Spotify's servers you can configure a reconnect
|
262
|
+
wait timeout that will cause spotify_web to wait a certain number of seconds before
|
263
|
+
attempting to open a connection. This will continue to happen until the connection
|
264
|
+
is successful.
|
265
|
+
|
266
|
+
## Testing
|
267
|
+
|
268
|
+
To run the core test suite:
|
269
|
+
|
270
|
+
```bash
|
271
|
+
bundle install
|
272
|
+
bundle exec rspec
|
273
|
+
```
|
274
|
+
|
275
|
+
## Caveats
|
276
|
+
|
277
|
+
The following caveats should be noted when using spotify_web:
|
278
|
+
|
279
|
+
* Since this library uses EventMachine / Fibers it will only be compatible with
|
280
|
+
web servers that support those technologies. Examples of such web servers include:
|
281
|
+
* [Thin](http://code.macournoyer.com/thin/)
|
282
|
+
* [Rainbows](http://rainbows.rubyforge.org/)
|
283
|
+
* [Goliath](http://postrank-labs.github.com/goliath/)
|
284
|
+
* This is *not* an official library and so Spotify may make changes to its API
|
285
|
+
that causes this to break. Hopefully we can build a community that can quickly
|
286
|
+
react and provide fixes to those changes.
|
287
|
+
|
288
|
+
## Things to do
|
289
|
+
|
290
|
+
* Add test coverage
|
291
|
+
* 100% complete Spotify Web API implementation
|
292
|
+
|
293
|
+
## Contributions
|
294
|
+
|
295
|
+
The largest contribution for this library is the reference material provided by
|
296
|
+
Nathan Rajlich's [node-spotify-web](https://github.com/TooTallNate/node-spotify-web)
|
297
|
+
and Hexxeh's [spotify-websocket-api](github.com/Hexxeh/spotify-websocket-api) libraries.
|
298
|
+
They provided much of the legwork to get understand how Spotify's Web API works and
|
299
|
+
made it much easier to bring a Ruby perspective to it.
|
300
|
+
|
301
|
+
## Dependencies
|
302
|
+
|
303
|
+
* Ruby 1.9.3 or later
|
304
|
+
* [beefcake](https://github.com/protobuf-ruby/beefcake)
|
305
|
+
* [em-http-request](https://github.com/igrigorik/em-http-request)
|
306
|
+
* [em-synchrony](https://github.com/igrigorik/em-synchrony)
|
307
|
+
* [execjs](https://github.com/sstephenson/execjs)
|
308
|
+
* [faye-websocket-ruby](https://github.com/faye/faye-websocket-ruby)
|
309
|
+
* [radix](https://github.com/rubyworks/radix)
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'rake'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
|
10
|
+
desc 'Default: run all specs.'
|
11
|
+
task :default => :spec
|
12
|
+
|
13
|
+
load File.dirname(__FILE__) + '/lib/tasks/spotify_web.rake'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# List all songs in the user's playlists
|
3
|
+
require 'spotify_web'
|
4
|
+
|
5
|
+
USERNAME = ENV['USERNAME'] # 'xxxxx'
|
6
|
+
PASSWORD = ENV['PASSWORD'] # 'xxxxx'
|
7
|
+
|
8
|
+
SpotifyWeb.run(EMAIL, PASSWORD) do
|
9
|
+
user.playlists.each do |playlist|
|
10
|
+
playlist.songs.each do |song|
|
11
|
+
puts "[#{playlist.name}] #{song.artist.name} - #{song.title}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/spotify_web.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'em-synchrony'
|
3
|
+
require 'em-synchrony/em-http'
|
4
|
+
|
5
|
+
# Spotify Web API for Ruby
|
6
|
+
module SpotifyWeb
|
7
|
+
# The user agent for Spotify access
|
8
|
+
USER_AGENT = 'node-spotify-web (Chrome/13.37 compatible-ish)'
|
9
|
+
|
10
|
+
autoload :Client, 'spotify_web/client'
|
11
|
+
autoload :Schema, 'spotify_web/schema'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# The logger to use for all Spotify messages. By default, everything is
|
15
|
+
# logged to STDOUT.
|
16
|
+
# @return [Logger]
|
17
|
+
attr_accessor :logger
|
18
|
+
|
19
|
+
# Whether this is going to be used in an interactive console such as IRB.
|
20
|
+
# If this is enabled then EventMachine will run in a separate thread. This
|
21
|
+
# will allow IRB to continue to actually be interactive.
|
22
|
+
#
|
23
|
+
# @note You must continue to run all commands on a client through SpotifyWeb#run.
|
24
|
+
# @example
|
25
|
+
# require 'spotify_web'
|
26
|
+
#
|
27
|
+
# SpotifyWeb.interactive
|
28
|
+
# SpotifyWeb.run do
|
29
|
+
# @client = SpotifyWeb::Client.new(...)
|
30
|
+
# @client.start
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # ...later on after the connection has started and you want to interact with it
|
34
|
+
# SpotifyWeb.run do
|
35
|
+
# @client.user.playlists
|
36
|
+
# # ...
|
37
|
+
# end
|
38
|
+
def interactive
|
39
|
+
Thread.new { EM.run }.abort_on_exception = true
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sets up the proper EventMachine reactor / Fiber to run commands against a
|
43
|
+
# client. If this is not in interactive mode, then the block won't return
|
44
|
+
# until the EventMachine reactor is stopped.
|
45
|
+
#
|
46
|
+
# @note If you're already running within an EventMachine reactor *and* a
|
47
|
+
# Fiber, then there's no need to call this method prior to interacting with
|
48
|
+
# a SpotifyWeb::Client instance.
|
49
|
+
# @example
|
50
|
+
# # Non-interactive, not in reactor / fiber
|
51
|
+
# SpotifyWeb.run do
|
52
|
+
# client = SpotifyWeb::Client.new(...)
|
53
|
+
# client.playlists
|
54
|
+
# # ...
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# # Interactive, not in reactor / fiber
|
58
|
+
# SpotifyWeb.interactive
|
59
|
+
# SpotifyWeb.run do
|
60
|
+
# @client = ...
|
61
|
+
# end
|
62
|
+
# SpotifyWeb.run do
|
63
|
+
# @client.playlists
|
64
|
+
# # ...
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# # Non-interactive, already in reactor / fiber
|
68
|
+
# client = SpotifyWeb::Client(...)
|
69
|
+
# client.playlists
|
70
|
+
#
|
71
|
+
# @example DSL
|
72
|
+
# # Takes the same arguments as SpotifyWeb::Client
|
73
|
+
# SpotifyWeb.run(USERNAME, PASSWORD) do
|
74
|
+
# user.playlists
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# == Exception handling
|
78
|
+
#
|
79
|
+
# Any exceptions that occur within the block will be automatically caught
|
80
|
+
# and logged. This prevents the EventMachine reactor from dying.
|
81
|
+
def run(*args, &block)
|
82
|
+
if EM.reactor_running?
|
83
|
+
EM.next_tick do
|
84
|
+
EM.synchrony do
|
85
|
+
begin
|
86
|
+
if args.any?
|
87
|
+
# Run the block within a client
|
88
|
+
Client.new(*args, &block)
|
89
|
+
else
|
90
|
+
# Just run the block within a fiber
|
91
|
+
block.call
|
92
|
+
end
|
93
|
+
rescue StandardError => ex
|
94
|
+
logger.error(([ex.message] + ex.backtrace) * "\n")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
else
|
99
|
+
EM.synchrony { run(*args, &block) }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
@logger = Logger.new(STDOUT)
|
105
|
+
end
|