robut-rdio 0.1.0 → 0.1.2
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 +29 -0
- data/Gemfile +16 -7
- data/Gemfile.lock +44 -13
- data/Guardfile +10 -0
- data/README.md +124 -19
- data/VERSION +1 -1
- data/lib/robut-rdio.rb +191 -34
- data/lib/server/public/css/rdio.css +16 -0
- data/lib/server/public/images/buffering.png +0 -0
- data/lib/server/public/images/circle-east.png +0 -0
- data/lib/server/public/images/circle-pause.png +0 -0
- data/lib/server/public/images/circle-play.png +0 -0
- data/lib/server/public/images/circle-stop.png +0 -0
- data/lib/server/public/images/disconnected.png +0 -0
- data/lib/server/public/index.html +16 -6
- data/lib/server/public/js/rdio.js +300 -170
- data/lib/server/server.rb +35 -0
- data/plugin-tester.rb +1 -1
- data/robut-rdio.gemspec +34 -16
- data/spec/integration/robut-rdio_spec.rb +119 -0
- data/spec/robut-rdio_spec.rb +219 -76
- data/spec/server_spec.rb +28 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/shared_examples.rb +47 -0
- metadata +73 -31
- data/README.rdoc +0 -19
@@ -45,6 +45,22 @@ h2 {
|
|
45
45
|
visibility: hidden;
|
46
46
|
}
|
47
47
|
|
48
|
+
#player_state {
|
49
|
+
float: left;
|
50
|
+
vertical-align: middle;
|
51
|
+
padding-top: 5px;
|
52
|
+
padding-right: 20px;
|
53
|
+
}
|
54
|
+
|
55
|
+
#current_track {
|
56
|
+
min-height: 66px;
|
57
|
+
}
|
58
|
+
|
59
|
+
#current_track_name {
|
60
|
+
padding-top: 6px;
|
61
|
+
}
|
62
|
+
|
63
|
+
|
48
64
|
#filter {
|
49
65
|
background: none; /* Old browsers */
|
50
66
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1,5 +1,10 @@
|
|
1
1
|
<!doctype html>
|
2
|
-
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
|
2
|
+
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
|
3
|
+
<!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]-->
|
4
|
+
<!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]-->
|
5
|
+
<!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]-->
|
6
|
+
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
|
7
|
+
<head>
|
3
8
|
<meta charset="UTF-8">
|
4
9
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
5
10
|
|
@@ -11,13 +16,17 @@
|
|
11
16
|
<link rel="stylesheet" href="css/rdio.css">
|
12
17
|
<link rel="stylesheet" href="css/style_after.css?v=2">
|
13
18
|
|
14
|
-
<script src="js/libs/modernizr-1.7.min.js"></script>
|
15
|
-
|
19
|
+
<script src="js/libs/modernizr-1.7.min.js"></script>
|
20
|
+
</head>
|
21
|
+
<body>
|
16
22
|
<div id="apiswf"></div>
|
17
|
-
|
18
23
|
<div id="content">
|
19
24
|
<div id="player">
|
20
|
-
<h1 id="current_track">
|
25
|
+
<h1 id="current_track">
|
26
|
+
<div id="player_state"><img src="images/buffering.png"/>
|
27
|
+
<img src="images/circle-play.png"/></div>
|
28
|
+
<div id="current_track_name"></div>
|
29
|
+
</h1>
|
21
30
|
<div id="controls">
|
22
31
|
<img id="album_art" src="images/no-album.png" />
|
23
32
|
<div id="filter" >
|
@@ -39,5 +48,6 @@
|
|
39
48
|
<!--[if lt IE 7 ]>
|
40
49
|
<script src="js/libs/dd_belatedpng.js"></script>
|
41
50
|
<script> DD_belatedPNG.fix('img, .png_bg');</script>
|
42
|
-
<![endif]-->
|
51
|
+
<![endif]-->
|
52
|
+
</body>
|
43
53
|
</html>
|
@@ -1,170 +1,300 @@
|
|
1
|
-
RdioPlayer = (function () {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
'
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
var
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
}
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
}
|
161
|
-
|
162
|
-
$(
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
}
|
170
|
-
|
1
|
+
RdioPlayer = (function () {
|
2
|
+
|
3
|
+
var playerElement = {};
|
4
|
+
|
5
|
+
function initPlayer (options) {
|
6
|
+
// on page load use SWFObject to load the API swf into div#apiswf
|
7
|
+
var flashvars = {
|
8
|
+
'playbackToken': options.token, // from token.js
|
9
|
+
'domain': options.domain, // from token.js
|
10
|
+
'listener': options.callbackName // the global name of the object that will receive callbacks from the SWF
|
11
|
+
};
|
12
|
+
|
13
|
+
var params = {
|
14
|
+
'allowScriptAccess': 'always'
|
15
|
+
};
|
16
|
+
|
17
|
+
var attributes = {};
|
18
|
+
|
19
|
+
playerElement = options.elementId;
|
20
|
+
|
21
|
+
swfobject.embedSWF('http://www.rdio.com/api/swf/', // the location of the Rdio Playback API SWF
|
22
|
+
options.elementId, // the ID of the element that will be replaced with the SWF
|
23
|
+
1, 1, '9.0.0', 'expressInstall.swf', flashvars, params, attributes);
|
24
|
+
}
|
25
|
+
|
26
|
+
function establishControls(rdio) {
|
27
|
+
|
28
|
+
rdio.isPlaying = function () {
|
29
|
+
return rdio.callback.playing;
|
30
|
+
}
|
31
|
+
|
32
|
+
rdio.isPaused = function () {
|
33
|
+
return !rdio.callback.playing;
|
34
|
+
}
|
35
|
+
|
36
|
+
rdio.play = function () {
|
37
|
+
rdio.player.rdio_play();
|
38
|
+
$(rdio.player).attr("playingState","playing");
|
39
|
+
}
|
40
|
+
|
41
|
+
rdio.pause = function () {
|
42
|
+
rdio.player.rdio_pause();
|
43
|
+
$(rdio.player).attr("playingState","paused");
|
44
|
+
}
|
45
|
+
|
46
|
+
rdio.toggle = function () {
|
47
|
+
if ( rdio.isPlaying() ) {
|
48
|
+
rdio.pause();
|
49
|
+
} else {
|
50
|
+
rdio.play();
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
function reporting(rdio) {
|
56
|
+
|
57
|
+
rdio.announce = function(message,announcementType) {
|
58
|
+
|
59
|
+
announcementType = typeof(announcementType) != 'undefined' ? announcementType : 'announcement';
|
60
|
+
|
61
|
+
$.ajax({
|
62
|
+
url: '/' + announcementType + '/' + message,
|
63
|
+
dataType: 'json'
|
64
|
+
});
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
}
|
69
|
+
|
70
|
+
var checkCommand = function (callbackObject, element) {
|
71
|
+
|
72
|
+
$.ajax({
|
73
|
+
url: '/command.json',
|
74
|
+
dataType: 'json',
|
75
|
+
success: function (data) {
|
76
|
+
if (data.length > 0) {
|
77
|
+
var command = data[0];
|
78
|
+
if(command == 'next_album'){
|
79
|
+
element.rdio_next(true);
|
80
|
+
}
|
81
|
+
|
82
|
+
if (command == "pause") {
|
83
|
+
element.rdio_pause();
|
84
|
+
}
|
85
|
+
|
86
|
+
if (command == "unpause" || command == "play") {
|
87
|
+
element.rdio_play();
|
88
|
+
}
|
89
|
+
|
90
|
+
if (command == "next") {
|
91
|
+
element.rdio_next();
|
92
|
+
}
|
93
|
+
|
94
|
+
if (command == "restart") {
|
95
|
+
element.rdio_previous();
|
96
|
+
}
|
97
|
+
|
98
|
+
if(command == "clear") {
|
99
|
+
element.rdio_clearQueue();
|
100
|
+
element.rdio_next(true);
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
});
|
108
|
+
|
109
|
+
setTimeout(function () {
|
110
|
+
checkCommand(callbackObject, element)
|
111
|
+
}, 2000);
|
112
|
+
|
113
|
+
}
|
114
|
+
|
115
|
+
var updateQueue = function (callbackObject, element) {
|
116
|
+
|
117
|
+
$.ajax({
|
118
|
+
url: '/queue.json',
|
119
|
+
dataType: 'json',
|
120
|
+
success: function (data) {
|
121
|
+
if (data.length > 0) {
|
122
|
+
|
123
|
+
if (!callbackObject.playing) {
|
124
|
+
element.rdio_play(data[0]);
|
125
|
+
data = data.slice(1);
|
126
|
+
}
|
127
|
+
|
128
|
+
for (var i = 0, _length = data.length; i < _length; i++) {
|
129
|
+
element.rdio_queue(data[i]);
|
130
|
+
}
|
131
|
+
|
132
|
+
}
|
133
|
+
}
|
134
|
+
});
|
135
|
+
|
136
|
+
setTimeout(function () {
|
137
|
+
updateQueue(callbackObject, element)
|
138
|
+
}, 5000);
|
139
|
+
};
|
140
|
+
|
141
|
+
function createCallback(rdio, callbackName, elementId) {
|
142
|
+
var callback = {};
|
143
|
+
|
144
|
+
callback.ready = function () {
|
145
|
+
self.ready = true;
|
146
|
+
var element = document.getElementById(elementId);
|
147
|
+
rdio.player = element;
|
148
|
+
updateQueue(callback, element);
|
149
|
+
checkCommand(callback, element);
|
150
|
+
}
|
151
|
+
|
152
|
+
callback.playStateChanged = function (playState) {
|
153
|
+
if (playState === 0 || playState === 4) {
|
154
|
+
callback.playing = false;
|
155
|
+
$('#player_state').html("<img src=\"images/circle-pause.png\">");
|
156
|
+
rdio.announce("Pausing for station identification.");
|
157
|
+
} else if (playState === 1) {
|
158
|
+
callback.playing = true;
|
159
|
+
$('#player_state').html("<img src=\"images/circle-play.png\">");
|
160
|
+
} else if (playState === 2) {
|
161
|
+
callback.playing = false;
|
162
|
+
$('#player_state').html("<img src=\"images/circle-stop.png\">");
|
163
|
+
rdio.announce("Stopping for station identification.");
|
164
|
+
} else if (playState === 3) {
|
165
|
+
callback.playing = true;
|
166
|
+
$('#player_state').html("<img src=\"images/buffering.png\">");
|
167
|
+
//rdio.announce("We'll continue this song after we go to Traffic with our in the sky Chopper Dave!")
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
callback.playingSomewhereElse = function() {
|
172
|
+
rdio.announce("The FCC has called our bluff and we are being taken off the air. Good night and good luck!");
|
173
|
+
$('#player_state').html("<img src=\"images/disconnected.png\">");
|
174
|
+
}
|
175
|
+
|
176
|
+
callback.sourceTitle = function (source) {
|
177
|
+
return source.artist + " - " + source.name;
|
178
|
+
}
|
179
|
+
|
180
|
+
callback.sourceList = function (source) {
|
181
|
+
var queue = "";
|
182
|
+
for (var i = 0, _length = source.length; i < _length; i++) {
|
183
|
+
queue += "<li class=\"source\">" +
|
184
|
+
callback.sourceTitle(source[i]) +
|
185
|
+
"</li>";
|
186
|
+
}
|
187
|
+
return queue;
|
188
|
+
}
|
189
|
+
|
190
|
+
callback.queueChanged = function (newQueue) {
|
191
|
+
$('#queue').html(callback.sourceList(newQueue));
|
192
|
+
if (newQueue.length > 0) {
|
193
|
+
$('#queue_header').show().html('Queue (' + newQueue.length + ')');
|
194
|
+
} else {
|
195
|
+
$('#queue_header').hide();
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
callback.playingSourceChanged = function (playingSource) {
|
200
|
+
var source = []
|
201
|
+
if (playingSource.tracks) {
|
202
|
+
source = playingSource.tracks;
|
203
|
+
} else {
|
204
|
+
source = [playingSource];
|
205
|
+
}
|
206
|
+
$('#now_playing').html(callback.sourceList(source));
|
207
|
+
$('#album_art').attr('src', playingSource.icon);
|
208
|
+
}
|
209
|
+
|
210
|
+
callback.playingTrackChanged = function(playingTrack, sourcePosition) {
|
211
|
+
if (playingTrack) {
|
212
|
+
var title = callback.sourceTitle(playingTrack);
|
213
|
+
|
214
|
+
// Remove the current playing highlight on the current track and move it
|
215
|
+
// to the correct track.
|
216
|
+
|
217
|
+
$('#now_playing li').removeClass('playing');
|
218
|
+
$('#now_playing li').eq(sourcePosition).addClass('playing');
|
219
|
+
|
220
|
+
// Update the browser page title
|
221
|
+
|
222
|
+
$('title').html(title + " - Powered by Rdio");
|
223
|
+
|
224
|
+
// Update the playing header
|
225
|
+
$('#current_track').show();
|
226
|
+
$('#current_track_name').html(title);
|
227
|
+
|
228
|
+
rdio.announce(encodeURIComponent(title),"now_playing");
|
229
|
+
|
230
|
+
} else {
|
231
|
+
$('#current_track').hide();
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
window[callbackName] = callback;
|
236
|
+
return callback;
|
237
|
+
}
|
238
|
+
|
239
|
+
function RdioPlayer (options) {
|
240
|
+
this.options = options;
|
241
|
+
this.callback = createCallback(this, options.callbackName, options.elementId);
|
242
|
+
|
243
|
+
establishControls(this);
|
244
|
+
reporting(this);
|
245
|
+
|
246
|
+
initPlayer(options);
|
247
|
+
}
|
248
|
+
|
249
|
+
return RdioPlayer;
|
250
|
+
})();
|
251
|
+
|
252
|
+
function playerKeyboardShortcuts() {
|
253
|
+
if (window.top.frames.main) return;
|
254
|
+
|
255
|
+
$(document).keydown(function(evt) {
|
256
|
+
|
257
|
+
if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) return;
|
258
|
+
|
259
|
+
if (typeof evt.target !== "undefined" &&
|
260
|
+
(evt.target.nodeName == "INPUT" ||
|
261
|
+
evt.target.nodeName == "TEXTAREA")) return;
|
262
|
+
|
263
|
+
switch (evt.keyCode) {
|
264
|
+
|
265
|
+
// Space Bar is play/pause
|
266
|
+
case 32:
|
267
|
+
window.rdio.toggle();
|
268
|
+
return false;
|
269
|
+
break;
|
270
|
+
|
271
|
+
// Previous Track - Left Arrow, P
|
272
|
+
case 37: case 80: case 112:
|
273
|
+
window.rdio.player.rdio_previous();
|
274
|
+
return false;
|
275
|
+
break;
|
276
|
+
|
277
|
+
// Next Track - Right Arrow, N
|
278
|
+
case 39: case 78: case 110:
|
279
|
+
window.rdio.player.rdio_next();
|
280
|
+
return false;
|
281
|
+
break;
|
282
|
+
|
283
|
+
}
|
284
|
+
|
285
|
+
});
|
286
|
+
|
287
|
+
}
|
288
|
+
|
289
|
+
|
290
|
+
$(document).ready(function () {
|
291
|
+
window.rdio = new RdioPlayer({
|
292
|
+
token: rdio_token,
|
293
|
+
domain: rdio_domain,
|
294
|
+
elementId: 'apiswf',
|
295
|
+
callbackName: 'rdio_callback'
|
296
|
+
});
|
297
|
+
|
298
|
+
$(playerKeyboardShortcuts);
|
299
|
+
});
|
300
|
+
|