spotify_web 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/obrie/spotify_web.png "Build Status")](http://travis-ci.org/obrie/spotify_web) [![Dependency Status](https://gemnasium.com/obrie/spotify_web.png "Dependency Status")](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
|