turntabler 0.1.4 → 0.2.0
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.
- 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:
|