turntabler 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +8 -0
- data/LICENSE +1 -1
- data/README.md +63 -18
- data/examples/Gemfile.lock +1 -1
- data/examples/modlist.rb +1 -1
- data/lib/turntabler/authorized_user.rb +10 -4
- data/lib/turntabler/client.rb +56 -16
- data/lib/turntabler/event.rb +21 -16
- data/lib/turntabler/handler.rb +2 -2
- data/lib/turntabler/playlist.rb +69 -0
- data/lib/turntabler/playlist_directory.rb +70 -0
- data/lib/turntabler/room_directory.rb +5 -5
- data/lib/turntabler/version.rb +2 -2
- data/lib/turntabler.rb +20 -0
- metadata +74 -97
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# master
|
2
2
|
|
3
|
+
## 0.2.0 / 2013-02-16
|
4
|
+
|
5
|
+
* Respect the keepalive update interval from API responses
|
6
|
+
* Add official support for trigger custom events
|
7
|
+
* Rename RoomDirectory#list to RoomDirectory#all
|
8
|
+
* Add full support for playlists API
|
9
|
+
* Fix Modlist example not sending messages to the room
|
10
|
+
|
3
11
|
## 0.1.4 / 2012-01-08
|
4
12
|
|
5
13
|
* Fix Bop / ChatBot / Switch examples not working
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -50,6 +50,7 @@ At a high level, this project features:
|
|
50
50
|
* HTTP / Web Socket interface implementations
|
51
51
|
* Room state / user list management
|
52
52
|
* DSL syntax support
|
53
|
+
* Custom events
|
53
54
|
|
54
55
|
Turntable features include management of:
|
55
56
|
|
@@ -117,40 +118,47 @@ Turntabler.run do
|
|
117
118
|
end
|
118
119
|
|
119
120
|
# Authorized user interactions
|
120
|
-
user = client.user # => #<Turntabler::AuthorizedUser
|
121
|
-
user.fan_of # => [#<Turntabler::User
|
122
|
-
user.fans # => [#<Turntabler::User
|
123
|
-
user.playlist.songs # => [#<Turntabler::Song
|
124
|
-
user.blocks # => [#<Turntabler::User
|
125
|
-
user.buddies # => [#<Turntabler::User
|
121
|
+
user = client.user # => #<Turntabler::AuthorizedUser @email="ben.zelano@gmail.com" ...>
|
122
|
+
user.fan_of # => [#<Turntabler::User @id="d5616b31654e8b22a7a1eef0">, ...]
|
123
|
+
user.fans # => [#<Turntabler::User @id="d5616b31654e8b22a7a1eef0">, ...]
|
124
|
+
user.playlist.songs # => [#<Turntabler::Song @album="Abbey Road" ...>, ...]
|
125
|
+
user.blocks # => [#<Turntabler::User @id="19125d4da3b09562b2cf68b6">, ...]
|
126
|
+
user.buddies # => [#<Turntabler::User @id="efff38aeb7b9334164c1b630">, ...]
|
126
127
|
|
127
128
|
# Room Directory
|
128
|
-
client.rooms.
|
129
|
-
client.rooms.
|
130
|
-
client.rooms.
|
131
|
-
# => [#<Turntabler::Room
|
132
|
-
client.rooms.with_friends # => [#<Turntabler::Room
|
133
|
-
client.room('4dff1eac14169c565800892e').listeners # => #<Set: {#<Turntabler::User
|
129
|
+
client.rooms.all(:favorites => true) # => []
|
130
|
+
client.rooms.all(:genre => :rock) # => [#<Turntabler::Room @id="4e4986bb14169c5f241318a6", ...>, ...]
|
131
|
+
client.rooms.all(:genre => :rock, :available_djs => true, :minimum_listeners => 5)
|
132
|
+
# => [#<Turntabler::Room @id="4f4a5874a3f75128aa006c17", ...>, ...]
|
133
|
+
client.rooms.with_friends # => [#<Turntabler::Room @id="50b4c1e2df5bcf4af666f876", ...>, ...]
|
134
|
+
client.room('4dff1eac14169c565800892e').listeners # => #<Set: {#<Turntabler::User @id="4e1341e2a3f75114d003c591" ...>, ...}>
|
134
135
|
|
135
136
|
# Room interaction
|
136
137
|
client.rooms.create("My Test Room #{rand}").enter # => true
|
137
|
-
room = client.room # => #<Turntabler::Room
|
138
|
+
room = client.room # => #<Turntabler::Room @name="My Test Room 0.24300857307298018" ...>
|
138
139
|
room.add_as_favorite # => true
|
139
140
|
room.become_dj # => true
|
140
141
|
room.say "Hey guys!" # => true
|
141
142
|
|
142
143
|
# User interaction
|
143
|
-
listeners = room.listeners # => #<Set: {#<Turntabler::User
|
144
|
+
listeners = room.listeners # => #<Set: {#<Turntabler::User @id="309ba75b6385b83e110923bd" ..., ...}>
|
144
145
|
listeners.each do |listener|
|
145
|
-
listener.messages # => [#<Turntabler::Message
|
146
|
+
listener.messages # => [#<Turntabler::Message @content="Hey man!" ...>, ...]
|
146
147
|
listener.website # => "http://mypersonalwebsite.com"
|
147
148
|
listener.facebook_url # => "https://www.facebook.com/firstname.lastname"
|
148
|
-
listener.sticker_placements # => [#<Turntabler::StickerPlacement
|
149
|
+
listener.sticker_placements # => [#<Turntabler::StickerPlacement @angle=0 ...>, ...]
|
149
150
|
listener.say "Welcome to the room!" # => true
|
150
151
|
end
|
151
152
|
|
153
|
+
# Playlist interaction
|
154
|
+
client.user.playlists.all # => [#<Turntabler::Playlist @id="default" ...>, ...]
|
155
|
+
client.user.playlists.create("rock") # => #<Turntabler::Playlist @id="rock" ...>
|
156
|
+
client.user.playlist # => #<Turntabler::Playlist @id="default" ...>
|
157
|
+
client.user.playlist("rock").activate # => true
|
158
|
+
client.user.playlist("rock").songs # => []
|
159
|
+
|
152
160
|
# Songs
|
153
|
-
songs = client.search_song('Rolling Stones') # => [#<Turntabler::Song
|
161
|
+
songs = client.search_song('Rolling Stones') # => [#<Turntabler::Song @album="Tattoo You (2009 Remaster)" ...>, ...]
|
154
162
|
songs.each do
|
155
163
|
song.enqueue # => true
|
156
164
|
end
|
@@ -171,6 +179,43 @@ can do with turntabler. For a *complete* list, see the API documentation, espec
|
|
171
179
|
For additional examples, see the [examples](https://github.com/obrie/turntabler/tree/master/examples)
|
172
180
|
directory in the repository.
|
173
181
|
|
182
|
+
### Custom events
|
183
|
+
|
184
|
+
In addition to the default Turntable events supported out of the box, turntabler
|
185
|
+
also allows you to define your own events. This is particularly useful in cases
|
186
|
+
where you may want to provide extensions on top of the turntabler library for
|
187
|
+
others to use. These extensions may be higher-order events, such as a user
|
188
|
+
reaching their maximum play count for a turn or a user timing out.
|
189
|
+
|
190
|
+
For example:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
require 'turntabler'
|
194
|
+
|
195
|
+
EMAIL = ENV['EMAIL']
|
196
|
+
PASSWORD = ENV['PASSWORD']
|
197
|
+
|
198
|
+
# Register custom events
|
199
|
+
Turntabler.events :user_greeted
|
200
|
+
|
201
|
+
Turntabler.run do
|
202
|
+
client = Turntabler::Client.new(EMAIL, PASSWORD)
|
203
|
+
|
204
|
+
# Events
|
205
|
+
client.on :user_spoke do |message|
|
206
|
+
if (message.content =~ /^\/hello$/)
|
207
|
+
# Trigger the custom event
|
208
|
+
client.trigger(:user_greeted, message.sender)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Handle custom event
|
213
|
+
client.on :user_greeted do |user|
|
214
|
+
client.room.say "Hey! How are you #{message.sender.name}?"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
174
219
|
## Additional Topics
|
175
220
|
|
176
221
|
### Differences with existing libraries
|
@@ -332,7 +377,7 @@ Notice that in this example the syntax is essentially the same except that we're
|
|
332
377
|
one level out and need to interact directly with the `Turntabler::Client`
|
333
378
|
instance itself.
|
334
379
|
|
335
|
-
##
|
380
|
+
## Deployment
|
336
381
|
|
337
382
|
### Web Server Usage
|
338
383
|
|
data/examples/Gemfile.lock
CHANGED
data/examples/modlist.rb
CHANGED
@@ -13,7 +13,7 @@ TT.run(EMAIL, PASSWORD, :room => ROOM) do
|
|
13
13
|
on :user_spoke do |message|
|
14
14
|
# Response to "/mod" command
|
15
15
|
if moderator_ids.include?(message.sender.id) && message.content =~ /^\/mod$/
|
16
|
-
|
16
|
+
room.say("Yo #{message.sender.name}, it looks like you are a bot moderator!")
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'turntabler/
|
1
|
+
require 'turntabler/playlist_directory'
|
2
2
|
require 'turntabler/preferences'
|
3
3
|
require 'turntabler/user'
|
4
4
|
require 'turntabler/sticker_placement'
|
@@ -32,6 +32,10 @@ module Turntabler
|
|
32
32
|
# @return [String]
|
33
33
|
attribute :password
|
34
34
|
|
35
|
+
# The user's custom playlists
|
36
|
+
# @return [Turntabler::PlaylistDirectory]
|
37
|
+
attr_reader :playlists
|
38
|
+
|
35
39
|
# The user's current Turntable preferences
|
36
40
|
# @return [Turntabler::Preferences]
|
37
41
|
attr_reader :preferences
|
@@ -39,7 +43,7 @@ module Turntabler
|
|
39
43
|
# @api private
|
40
44
|
def initialize(client, *)
|
41
45
|
@status = 'available'
|
42
|
-
@playlists =
|
46
|
+
@playlists = PlaylistDirectory.new(client)
|
43
47
|
@preferences = Preferences.new(client)
|
44
48
|
super
|
45
49
|
end
|
@@ -192,7 +196,7 @@ module Turntabler
|
|
192
196
|
# user.playlist # => #<Turntabler::Playlist id="default" ...>
|
193
197
|
# user.playlist("rock") # => #<Turntabler::Playlist id="rock" ...>
|
194
198
|
def playlist(id = 'default')
|
195
|
-
|
199
|
+
playlists.build(:_id => id)
|
196
200
|
end
|
197
201
|
|
198
202
|
# Gets the stickers that have been purchased by this user.
|
@@ -245,8 +249,10 @@ module Turntabler
|
|
245
249
|
def update_status(status = self.status)
|
246
250
|
assert_valid_values(status, *%w(available unavailable away))
|
247
251
|
|
248
|
-
api('presence.update', :status => status)
|
252
|
+
result = api('presence.update', :status => status)
|
253
|
+
client.reset_keepalive(result['interval']) if result['interval']
|
249
254
|
self.attributes = {'status' => status}
|
255
|
+
|
250
256
|
true
|
251
257
|
end
|
252
258
|
end
|
data/lib/turntabler/client.rb
CHANGED
@@ -99,7 +99,7 @@ module Turntabler
|
|
99
99
|
|
100
100
|
# Create a new connection to the given url
|
101
101
|
@connection = Connection.new(url, :timeout => timeout, :params => {:clientid => id, :userid => user.id, :userauth => user.auth})
|
102
|
-
@connection.handler = lambda {|data|
|
102
|
+
@connection.handler = lambda {|data| trigger(data.delete('command'), data)}
|
103
103
|
@connection.start
|
104
104
|
|
105
105
|
# Wait until the connection is authenticated
|
@@ -116,8 +116,8 @@ module Turntabler
|
|
116
116
|
# @return [true]
|
117
117
|
def close(allow_reconnect = false)
|
118
118
|
if @connection
|
119
|
-
@
|
120
|
-
@
|
119
|
+
@keepalive_timer.cancel if @keepalive_timer
|
120
|
+
@keepalive_timer = nil
|
121
121
|
@connection.close
|
122
122
|
|
123
123
|
wait do |&resume|
|
@@ -439,21 +439,64 @@ module Turntabler
|
|
439
439
|
songs || raise(Error, 'Search failed to complete')
|
440
440
|
end
|
441
441
|
|
442
|
-
#
|
443
|
-
#
|
442
|
+
# Triggers callback handlers for the given Turntable command. This should
|
443
|
+
# either be invoked when responses are received for Turntable or when
|
444
|
+
# triggering custom events.
|
444
445
|
#
|
445
|
-
# @
|
446
|
-
# @param [
|
447
|
-
# @
|
448
|
-
|
449
|
-
|
450
|
-
|
446
|
+
# @note If the command is unknown, it will simply get skipped and not raise an exception
|
447
|
+
# @param [Symbol] command The name of the command triggered. This is typically the same name as the event.
|
448
|
+
# @param [Array] args The arguments to be processed by the event
|
449
|
+
# @return [true]
|
450
|
+
#
|
451
|
+
# == Triggering custom events
|
452
|
+
#
|
453
|
+
# After defining custom events, `trigger` can be used to invoke any handler
|
454
|
+
# that's been registered for that event. The argument list passed into
|
455
|
+
# `trigger` will be passed, exactly as specified, to the registered
|
456
|
+
# handlers.
|
457
|
+
#
|
458
|
+
# @example
|
459
|
+
# # Define names of events
|
460
|
+
# Turntabler.events(:no_args, :one_arg, :multiple_args)
|
461
|
+
#
|
462
|
+
# # ...
|
463
|
+
#
|
464
|
+
# # Register handlers
|
465
|
+
# client.on(:no_args) { }
|
466
|
+
# client.on(:one_arg) {|arg| }
|
467
|
+
# client.on(:multiple_args) {|arg1, arg2| }
|
468
|
+
#
|
469
|
+
# # Trigger handlers registered for events
|
470
|
+
# client.trigger(:no_args) # => true
|
471
|
+
# client.trigger(:one_arg, 1) # => true
|
472
|
+
# client.trigger(:multiple_args, 1, 2) # => true
|
473
|
+
def trigger(command, *args)
|
474
|
+
command = command.to_sym if command
|
475
|
+
|
476
|
+
if Event.command?(command)
|
477
|
+
event = Event.new(self, command, args)
|
451
478
|
handlers = @event_handlers[event.name] || []
|
452
479
|
handlers.each do |handler|
|
453
480
|
success = handler.run(event)
|
454
481
|
handlers.delete(handler) if success && handler.once
|
455
482
|
end
|
456
483
|
end
|
484
|
+
|
485
|
+
true
|
486
|
+
end
|
487
|
+
|
488
|
+
# Resets the keepalive timer to run at the given interval.
|
489
|
+
#
|
490
|
+
# @param [Fixnum] interval The frequency with which keepalives get sent (in seconds)
|
491
|
+
# @api private
|
492
|
+
def reset_keepalive(interval = 10)
|
493
|
+
if !@keepalive_timer || @keepalive_interval != interval
|
494
|
+
@keepalive_interval = interval
|
495
|
+
|
496
|
+
# Periodically update the user's status to remain available
|
497
|
+
@keepalive_timer.cancel if @keepalive_timer
|
498
|
+
@keepalive_timer = EM::Synchrony.add_periodic_timer(interval) { user.update(:status => user.status) }
|
499
|
+
end
|
457
500
|
end
|
458
501
|
|
459
502
|
private
|
@@ -470,10 +513,7 @@ module Turntabler
|
|
470
513
|
user.authenticate
|
471
514
|
user.fan_of
|
472
515
|
user.update(:status => user.status)
|
473
|
-
|
474
|
-
# Periodically update the user's status to remain available
|
475
|
-
@update_timer.cancel if @update_timer
|
476
|
-
@update_timer = EM::Synchrony.add_periodic_timer(10) { user.update(:status => user.status) }
|
516
|
+
reset_keepalive
|
477
517
|
end
|
478
518
|
|
479
519
|
# Callback when the session has ended. This will automatically reconnect if
|
@@ -488,7 +528,7 @@ module Turntabler
|
|
488
528
|
if @reconnect && allow_reconnect
|
489
529
|
EM::Synchrony.add_timer(@reconnect_wait) do
|
490
530
|
room ? room.enter : connect(url)
|
491
|
-
|
531
|
+
trigger(:reconnected)
|
492
532
|
end
|
493
533
|
end
|
494
534
|
end
|
data/lib/turntabler/event.rb
CHANGED
@@ -35,7 +35,7 @@ module Turntabler
|
|
35
35
|
# @param [String] command The command to check for the existence of
|
36
36
|
# @return [Boolean] +true+ if the command exists, otherwise +false+
|
37
37
|
def command?(command)
|
38
|
-
|
38
|
+
commands.include?(command)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -79,7 +79,7 @@ module Turntabler
|
|
79
79
|
data['user'].map do |attrs|
|
80
80
|
user = room.build_user(attrs)
|
81
81
|
room.listeners << user
|
82
|
-
user
|
82
|
+
[user]
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -88,7 +88,7 @@ module Turntabler
|
|
88
88
|
data['user'].map do |attrs|
|
89
89
|
user = room.build_user(attrs)
|
90
90
|
room.listeners.delete(user)
|
91
|
-
user
|
91
|
+
[user]
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
@@ -122,7 +122,8 @@ module Turntabler
|
|
122
122
|
handle :dj_added, :add_dj do
|
123
123
|
new_djs = []
|
124
124
|
data['user'].each_with_index do |attrs, index|
|
125
|
-
|
125
|
+
user = room.build_user(attrs.merge('placements' => data['placements'][index]))
|
126
|
+
new_djs << [user]
|
126
127
|
room.djs << user
|
127
128
|
end
|
128
129
|
new_djs
|
@@ -133,7 +134,7 @@ module Turntabler
|
|
133
134
|
data['user'].map do |attrs|
|
134
135
|
user = room.build_user(attrs)
|
135
136
|
room.djs.delete(user)
|
136
|
-
user
|
137
|
+
[user]
|
137
138
|
end
|
138
139
|
end
|
139
140
|
|
@@ -153,14 +154,14 @@ module Turntabler
|
|
153
154
|
|
154
155
|
# There are no more songs to play in the room
|
155
156
|
handle :song_unavailable, :nosong do
|
156
|
-
client.
|
157
|
+
client.trigger(:song_ended) if room.current_song
|
157
158
|
room.attributes = data['room'].merge('current_song' => nil)
|
158
159
|
nil
|
159
160
|
end
|
160
161
|
|
161
162
|
# A new song has started playing
|
162
163
|
handle :song_started, :newsong do
|
163
|
-
client.
|
164
|
+
client.trigger(:song_ended) if room.current_song
|
164
165
|
room.attributes = data['room']
|
165
166
|
room.current_song
|
166
167
|
end
|
@@ -190,13 +191,13 @@ module Turntabler
|
|
190
191
|
|
191
192
|
# A song was skipped due to a copyright claim
|
192
193
|
handle :song_blocked do
|
193
|
-
client.
|
194
|
+
client.trigger(:song_ended) if room.current_song
|
194
195
|
Song.new(client, data)
|
195
196
|
end
|
196
197
|
|
197
198
|
# A song was skipped due to a limit on # of plays per hour
|
198
199
|
handle :song_limited, :dmca_error do
|
199
|
-
client.
|
200
|
+
client.trigger(:song_ended) if room.current_song
|
200
201
|
Song.new(client, data)
|
201
202
|
end
|
202
203
|
|
@@ -207,7 +208,7 @@ module Turntabler
|
|
207
208
|
|
208
209
|
# A song search has completed and the results are available
|
209
210
|
handle :search_completed, :search_complete do
|
210
|
-
[data['docs'].map {|attrs| Song.new(client, attrs)}]
|
211
|
+
[[data['docs'].map {|attrs| Song.new(client, attrs)}]]
|
211
212
|
end
|
212
213
|
|
213
214
|
# A song search failed to complete
|
@@ -217,25 +218,29 @@ module Turntabler
|
|
217
218
|
# @return [String]
|
218
219
|
attr_reader :name
|
219
220
|
|
221
|
+
# The raw arguments list from the event
|
222
|
+
# @return [Array<Object>]
|
223
|
+
attr_reader :args
|
224
|
+
|
220
225
|
# The raw hash of data parsed from the event
|
221
226
|
# @return [Hash<String, Object>]
|
222
227
|
attr_reader :data
|
223
228
|
|
224
|
-
# The typecasted results parsed from the
|
225
|
-
# @return [Array]
|
229
|
+
# The typecasted results args parsed from the event
|
230
|
+
# @return [Array<Array<Object>>]
|
226
231
|
attr_reader :results
|
227
232
|
|
228
233
|
# Creates a new event triggered with the given data
|
229
234
|
#
|
230
235
|
# @param [Turntabler::Client] client The client that this event is bound to
|
231
236
|
# @param [Hash] data The response data from Turntable
|
232
|
-
def initialize(client,
|
237
|
+
def initialize(client, command, args)
|
233
238
|
@client = client
|
234
|
-
@
|
235
|
-
|
239
|
+
@args = args
|
240
|
+
@data = args[0]
|
236
241
|
@name = self.class.commands[command]
|
237
242
|
@results = __send__("typecast_#{command}_event")
|
238
|
-
@results = [@results] unless @results.is_a?(Array)
|
243
|
+
@results = [[@results].compact] unless @results.is_a?(Array)
|
239
244
|
end
|
240
245
|
|
241
246
|
private
|
data/lib/turntabler/handler.rb
CHANGED
@@ -46,9 +46,9 @@ module Turntabler
|
|
46
46
|
def run(event)
|
47
47
|
if conditions_match?(event.data)
|
48
48
|
# Run the block for each individual result
|
49
|
-
event.results.each do |
|
49
|
+
event.results.each do |args|
|
50
50
|
begin
|
51
|
-
@block.call(*
|
51
|
+
@block.call(*args)
|
52
52
|
rescue StandardError => ex
|
53
53
|
logger.error(([ex.message] + ex.backtrace) * "\n")
|
54
54
|
end
|
data/lib/turntabler/playlist.rb
CHANGED
@@ -5,6 +5,14 @@ module Turntabler
|
|
5
5
|
# Represents a collection of songs managed by the user and that can be played
|
6
6
|
# within a room
|
7
7
|
class Playlist < Resource
|
8
|
+
# Allow the id to be set via the "name" attribute
|
9
|
+
# @return [String]
|
10
|
+
attribute :id, :name, :load => false
|
11
|
+
|
12
|
+
# Whether this is the currently active playlist
|
13
|
+
# @return [Boolean]
|
14
|
+
attribute :active, :load => false
|
15
|
+
|
8
16
|
# The songs that have been added to this playlist
|
9
17
|
# @return [Array<Turntabler::Song>]
|
10
18
|
attribute :songs, :list do |songs|
|
@@ -30,6 +38,60 @@ module Turntabler
|
|
30
38
|
super()
|
31
39
|
end
|
32
40
|
|
41
|
+
# Updates this playlist's information.
|
42
|
+
#
|
43
|
+
# @param [Hash] attributes The attributes to update
|
44
|
+
# @option attributes [String] :id
|
45
|
+
# @return [true]
|
46
|
+
# @raise [ArgumentError] if an invalid attribute or value is specified
|
47
|
+
# @raise [Turntabler::Error] if the command fails
|
48
|
+
# @example
|
49
|
+
# playlist.update(:id => "rock") # => true
|
50
|
+
def update(attributes = {})
|
51
|
+
assert_valid_keys(attributes, :id)
|
52
|
+
|
53
|
+
# Update id
|
54
|
+
id = attributes.delete(:id)
|
55
|
+
update_id(id) if id
|
56
|
+
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
# Whether this is the currently active playlist
|
61
|
+
#
|
62
|
+
# @return [Boolean]
|
63
|
+
# @raise [Turntabler::Error] if the command fails
|
64
|
+
# @example
|
65
|
+
# playlist.active # => true
|
66
|
+
def active
|
67
|
+
@active = client.user.playlists.all.any? {|playlist| playlist == self && playlist.active?} if @active.nil?
|
68
|
+
@active
|
69
|
+
end
|
70
|
+
|
71
|
+
# Changes this playlist to be used for queueing new songs with the room.
|
72
|
+
#
|
73
|
+
# @return [true]
|
74
|
+
# @raise [Turntabler::Error] if the command fails
|
75
|
+
# @example
|
76
|
+
# playlist.switch # => true
|
77
|
+
def activate
|
78
|
+
api('playlist.switch')
|
79
|
+
self.attributes = {'active' => true}
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
# Permanently deletes this playlist and the list of songs within it. If this
|
84
|
+
# is the currently active playlist, the "default" playlist will become active.
|
85
|
+
#
|
86
|
+
# @return [true]
|
87
|
+
# @raise [Turntabler::Error] if the command fails
|
88
|
+
# @example
|
89
|
+
# playlist.delete # => true
|
90
|
+
def delete
|
91
|
+
api('playlist.delete')
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
33
95
|
# Gets the song with the given id.
|
34
96
|
#
|
35
97
|
# @param [String] song_id The id for the song
|
@@ -42,6 +104,13 @@ module Turntabler
|
|
42
104
|
end
|
43
105
|
|
44
106
|
private
|
107
|
+
# Updates the name used to identify this playlist
|
108
|
+
def update_id(id)
|
109
|
+
client.api('playlist.rename', :old_playlist_name => self.id, :new_playlist_name => id)
|
110
|
+
self.attributes = {'name' => id}
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
45
114
|
def api(command, options = {})
|
46
115
|
options[:playlist_name] = id
|
47
116
|
super
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'turntabler/playlist'
|
2
|
+
|
3
|
+
module Turntabler
|
4
|
+
# Provides a set of helper methods for interacting with a user's playlists.
|
5
|
+
class PlaylistDirectory
|
6
|
+
include Assertions
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
def initialize(client)
|
10
|
+
@client = client
|
11
|
+
@playlists = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Creates a new playlist with the given id. This should only be used if
|
15
|
+
# the playlist doesn't already exist.
|
16
|
+
#
|
17
|
+
# @note This will automatically enter the playlist when it is created
|
18
|
+
# @param [String] id The unique identifier of the playlist
|
19
|
+
# @return [Turntabler::Playlist]
|
20
|
+
# @raise [Turntabler::Error] if the command fails
|
21
|
+
# @example
|
22
|
+
# playlists.create("Rock") # => #<Turntabler::Playlist ...>
|
23
|
+
def create(id)
|
24
|
+
api('playlist.create', :playlist_name => id)
|
25
|
+
build(:_id => id)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Gets the list of playlists created.
|
29
|
+
#
|
30
|
+
# @return [Array<Turntabler::Playlist>]
|
31
|
+
# @raise [Turntabler::Error] if the command fails
|
32
|
+
# @example
|
33
|
+
# playlists.all # => [#<Turntabler::Playlist ...>, ...]
|
34
|
+
def all
|
35
|
+
data = api('playlist.list_all')
|
36
|
+
data['list'].map {|attrs| build(attrs)}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Gets the playlist represented by the given attributes.
|
40
|
+
#
|
41
|
+
# If the playlist hasn't been previously accessed, then a new Playlist
|
42
|
+
# instance will get created.
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
# @param [Hash] attrs The attributes representing the playlist
|
46
|
+
# @return [Turntabler::Playlist]
|
47
|
+
def build(attrs)
|
48
|
+
playlist = Playlist.new(client, attrs)
|
49
|
+
|
50
|
+
# Update existing in cache or cache a new playlist
|
51
|
+
if existing = @playlists[playlist.id]
|
52
|
+
playlist = existing
|
53
|
+
playlist.attributes = attrs
|
54
|
+
else
|
55
|
+
@playlists[playlist.id] = playlist
|
56
|
+
end
|
57
|
+
|
58
|
+
playlist
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
# The client that all APIs filter through
|
63
|
+
attr_reader :client
|
64
|
+
|
65
|
+
# Runs the given API command on the client.
|
66
|
+
def api(command, options = {})
|
67
|
+
client.api(command, options)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -54,11 +54,11 @@ module Turntabler
|
|
54
54
|
# @raise [ArgumentError] if an invalid option or value is specified
|
55
55
|
# @raise [Turntabler::Error] if the command fails
|
56
56
|
# @example
|
57
|
-
# rooms.
|
58
|
-
# rooms.
|
59
|
-
# rooms.
|
60
|
-
# rooms.
|
61
|
-
def
|
57
|
+
# rooms.all # => [#<Turntabler::Room ...>, ...]
|
58
|
+
# rooms.all(:favorites => true) # => [#<Turntabler::Room ...>, ...]
|
59
|
+
# rooms.all(:available_djs => true, :genre => :rock) # => [#<Turntabler::Room ...>, ...]
|
60
|
+
# rooms.all(:sort => :random) # => [#<Turntabler::Room ...>, ...]
|
61
|
+
def all(options = {})
|
62
62
|
assert_valid_keys(options, :limit, :skip, :favorites, :available_djs, :genre, :minimum_listeners, :sort)
|
63
63
|
assert_valid_values(options[:genre], :rock, :electronic, :indie, :hiphop, :pop, :dubstep) if options[:genre]
|
64
64
|
assert_valid_values(options[:sort], :created, :listeners, :random) if options[:sort]
|
data/lib/turntabler/version.rb
CHANGED
data/lib/turntabler.rb
CHANGED
@@ -4,6 +4,7 @@ require 'em-synchrony'
|
|
4
4
|
# Turntable.FM API for Ruby
|
5
5
|
module Turntabler
|
6
6
|
autoload :Client, 'turntabler/client'
|
7
|
+
autoload :Event, 'turntabler/event'
|
7
8
|
|
8
9
|
class << self
|
9
10
|
# The logger to use for all Turntable messages. By default, everything is
|
@@ -97,6 +98,25 @@ module Turntabler
|
|
97
98
|
EM.synchrony { run(*args, &block) }
|
98
99
|
end
|
99
100
|
end
|
101
|
+
|
102
|
+
# Defines one or more custom events for which handlers can be registered
|
103
|
+
# and triggered via Turntabler::Client#on and Turntabler::Client#trigger,
|
104
|
+
# respectively.
|
105
|
+
#
|
106
|
+
# @note Events must be defined before handlers can be registered for them
|
107
|
+
# @param [Array<String>] names The names of the events to define
|
108
|
+
# @raise [ArgumentError] if the event has already been defined
|
109
|
+
# @example
|
110
|
+
# Turntabler::Client.events :custom_event1, :custom_event2
|
111
|
+
def events(*names)
|
112
|
+
names.each do |name|
|
113
|
+
if Event.command?(name)
|
114
|
+
raise ArgumentError, "Event :#{name} is already defined"
|
115
|
+
else
|
116
|
+
Event.handle(name) { [args] }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
100
120
|
end
|
101
121
|
|
102
122
|
@logger = Logger.new(STDOUT)
|
metadata
CHANGED
@@ -1,121 +1,94 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: turntabler
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.4
|
3
|
+
version: !ruby/object:Gem::Version
|
5
4
|
prerelease:
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Aaron Pfeifer
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
|
13
|
+
date: 2013-02-16 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
15
16
|
name: em-synchrony
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
17
|
prerelease: false
|
24
|
-
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
19
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: em-http-request
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
38
24
|
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: em-http-request
|
39
28
|
prerelease: false
|
40
|
-
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
30
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version:
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: faye-websocket
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
54
35
|
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: faye-websocket
|
55
39
|
prerelease: false
|
56
|
-
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
41
|
none: false
|
58
|
-
requirements:
|
59
|
-
- -
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
63
49
|
name: rake
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ! '>='
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
type: :development
|
71
50
|
prerelease: false
|
72
|
-
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ! '>='
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: '0'
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: rspec
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
81
52
|
none: false
|
82
|
-
requirements:
|
83
|
-
- -
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version:
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
86
57
|
type: :development
|
58
|
+
version_requirements: *id004
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rspec
|
87
61
|
prerelease: false
|
88
|
-
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
89
63
|
none: false
|
90
|
-
requirements:
|
64
|
+
requirements:
|
91
65
|
- - ~>
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version:
|
94
|
-
- !ruby/object:Gem::Dependency
|
95
|
-
name: simplecov
|
96
|
-
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
|
-
requirements:
|
99
|
-
- - ! '>='
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '0'
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "2.11"
|
102
68
|
type: :development
|
69
|
+
version_requirements: *id005
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: simplecov
|
103
72
|
prerelease: false
|
104
|
-
|
73
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
105
74
|
none: false
|
106
|
-
requirements:
|
107
|
-
- -
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version:
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: "0"
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id006
|
110
81
|
description: Turntable.FM API for Ruby
|
111
82
|
email: aaron.pfeifer@gmail.com
|
112
83
|
executables: []
|
84
|
+
|
113
85
|
extensions: []
|
114
|
-
|
86
|
+
|
87
|
+
extra_rdoc_files:
|
115
88
|
- README.md
|
116
89
|
- CHANGELOG.md
|
117
90
|
- LICENSE
|
118
|
-
files:
|
91
|
+
files:
|
119
92
|
- .gitignore
|
120
93
|
- .rspec
|
121
94
|
- .yardopts
|
@@ -149,6 +122,7 @@ files:
|
|
149
122
|
- lib/turntabler/loggable.rb
|
150
123
|
- lib/turntabler/message.rb
|
151
124
|
- lib/turntabler/playlist.rb
|
125
|
+
- lib/turntabler/playlist_directory.rb
|
152
126
|
- lib/turntabler/preferences.rb
|
153
127
|
- lib/turntabler/resource.rb
|
154
128
|
- lib/turntabler/room.rb
|
@@ -165,33 +139,36 @@ files:
|
|
165
139
|
- turntabler.gemspec
|
166
140
|
homepage: http://github.com/obrie/turntabler
|
167
141
|
licenses: []
|
142
|
+
|
168
143
|
post_install_message:
|
169
|
-
rdoc_options:
|
144
|
+
rdoc_options:
|
170
145
|
- --line-numbers
|
171
146
|
- --inline-source
|
172
147
|
- --title
|
173
148
|
- turntabler
|
174
149
|
- --main
|
175
150
|
- README.md
|
176
|
-
require_paths:
|
151
|
+
require_paths:
|
177
152
|
- lib
|
178
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
179
154
|
none: false
|
180
|
-
requirements:
|
181
|
-
- -
|
182
|
-
- !ruby/object:Gem::Version
|
183
|
-
version:
|
184
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: "0"
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
160
|
none: false
|
186
|
-
requirements:
|
187
|
-
- -
|
188
|
-
- !ruby/object:Gem::Version
|
189
|
-
version:
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: "0"
|
190
165
|
requirements: []
|
166
|
+
|
191
167
|
rubyforge_project:
|
192
168
|
rubygems_version: 1.8.24
|
193
169
|
signing_key:
|
194
170
|
specification_version: 3
|
195
171
|
summary: Turntable.FM API for Ruby
|
196
172
|
test_files: []
|
173
|
+
|
197
174
|
has_rdoc:
|