2013-07-06 15:25:12 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
Copyright (c) 2013 Calvin Montgomery
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2013-07-03 21:29:49 +00:00
|
|
|
ULList = require("./ullist").ULList;
|
2013-07-01 22:45:55 +00:00
|
|
|
var Media = require("./media").Media;
|
2013-07-14 02:19:47 +00:00
|
|
|
var AllPlaylists = {};
|
2013-07-01 22:45:55 +00:00
|
|
|
|
2013-06-29 22:09:20 +00:00
|
|
|
function PlaylistItem(media, uid) {
|
|
|
|
this.media = media;
|
|
|
|
this.uid = uid;
|
|
|
|
this.temp = false;
|
|
|
|
this.queueby = "";
|
|
|
|
this.prev = null;
|
|
|
|
this.next = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
PlaylistItem.prototype.pack = function() {
|
|
|
|
return {
|
2013-07-01 22:45:55 +00:00
|
|
|
media: this.media.pack(),
|
2013-06-29 22:09:20 +00:00
|
|
|
uid: this.uid,
|
|
|
|
temp: this.temp,
|
|
|
|
queueby: this.queueby
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-06-30 00:59:33 +00:00
|
|
|
function Playlist(chan) {
|
2013-07-27 14:40:49 +00:00
|
|
|
var name = chan.canonical_name;
|
|
|
|
if(name in AllPlaylists && AllPlaylists[name]) {
|
|
|
|
var pl = AllPlaylists[name];
|
2013-07-16 15:46:09 +00:00
|
|
|
if(!pl.dead)
|
2013-07-14 02:19:47 +00:00
|
|
|
pl.die();
|
|
|
|
}
|
2013-07-02 15:38:13 +00:00
|
|
|
this.items = new ULList();
|
2013-07-09 22:29:01 +00:00
|
|
|
this.current = null;
|
2013-06-29 22:09:20 +00:00
|
|
|
this.next_uid = 0;
|
2013-06-30 00:59:33 +00:00
|
|
|
this._leadInterval = false;
|
|
|
|
this._lastUpdate = 0;
|
|
|
|
this._counter = 0;
|
|
|
|
this.leading = true;
|
|
|
|
this.callbacks = {
|
|
|
|
"changeMedia": [],
|
2013-06-30 19:33:38 +00:00
|
|
|
"mediaUpdate": [],
|
|
|
|
"remove": [],
|
2013-06-30 00:59:33 +00:00
|
|
|
};
|
2013-07-02 15:38:13 +00:00
|
|
|
this.lock = false;
|
2013-07-03 21:29:49 +00:00
|
|
|
this.action_queue = [];
|
2013-07-02 15:38:13 +00:00
|
|
|
this._qaInterval = false;
|
2013-07-27 14:40:49 +00:00
|
|
|
AllPlaylists[name] = this;
|
2013-06-29 22:09:20 +00:00
|
|
|
|
2013-08-03 14:58:21 +00:00
|
|
|
this.channel = chan;
|
|
|
|
this.server = chan.server;
|
|
|
|
var pl = this;
|
|
|
|
this.on("mediaUpdate", function(m) {
|
|
|
|
chan.sendAll("mediaUpdate", m.timeupdate());
|
|
|
|
});
|
|
|
|
this.on("changeMedia", function(m) {
|
|
|
|
chan.onVideoChange();
|
|
|
|
chan.sendAll("setCurrent", pl.current.uid);
|
|
|
|
chan.sendAll("changeMedia", m.fullupdate());
|
|
|
|
});
|
|
|
|
this.on("remove", function(item) {
|
|
|
|
chan.broadcastPlaylistMeta();
|
|
|
|
chan.sendAll("delete", {
|
|
|
|
uid: item.uid
|
2013-06-30 19:33:38 +00:00
|
|
|
});
|
2013-08-03 14:58:21 +00:00
|
|
|
});
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
Playlist.prototype.queueAction = function(data) {
|
2013-07-03 21:29:49 +00:00
|
|
|
this.action_queue.push(data);
|
2013-07-02 15:38:13 +00:00
|
|
|
if(this._qaInterval)
|
|
|
|
return;
|
|
|
|
var pl = this;
|
|
|
|
this._qaInterval = setInterval(function() {
|
2013-07-03 21:29:49 +00:00
|
|
|
var data = pl.action_queue.shift();
|
|
|
|
if(data.waiting) {
|
|
|
|
if(!("expire" in data))
|
|
|
|
data.expire = Date.now() + 10000;
|
|
|
|
if(Date.now() < data.expire)
|
|
|
|
pl.action_queue.unshift(data);
|
|
|
|
}
|
|
|
|
else
|
2013-07-03 03:19:17 +00:00
|
|
|
data.fn();
|
2013-07-03 21:29:49 +00:00
|
|
|
if(pl.action_queue.length == 0) {
|
|
|
|
clearInterval(pl._qaInterval);
|
|
|
|
pl._qaInterval = false;
|
2013-07-02 15:38:13 +00:00
|
|
|
}
|
|
|
|
}, 100);
|
|
|
|
}
|
|
|
|
|
2013-07-01 22:45:55 +00:00
|
|
|
Playlist.prototype.dump = function() {
|
2013-07-02 15:38:13 +00:00
|
|
|
var arr = this.items.toArray();
|
2013-07-02 19:01:12 +00:00
|
|
|
var pos = 0;
|
|
|
|
for(var i in arr) {
|
2013-07-03 03:19:17 +00:00
|
|
|
if(this.current && arr[i].uid == this.current.uid) {
|
2013-07-02 19:01:12 +00:00
|
|
|
pos = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-07-01 22:45:55 +00:00
|
|
|
|
|
|
|
var time = 0;
|
|
|
|
if(this.current)
|
|
|
|
time = this.current.media.currentTime;
|
|
|
|
|
|
|
|
return {
|
|
|
|
pl: arr,
|
|
|
|
pos: pos,
|
|
|
|
time: time
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2013-07-03 19:51:35 +00:00
|
|
|
Playlist.prototype.die = function () {
|
|
|
|
this.clear();
|
|
|
|
if(this._leadInterval) {
|
|
|
|
clearInterval(this._leadInterval);
|
|
|
|
this._leadInterval = false;
|
|
|
|
}
|
2013-07-14 21:59:40 +00:00
|
|
|
if(this._qaInterval) {
|
|
|
|
clearInterval(this._qaInterval);
|
|
|
|
this._qaInterval = false;
|
|
|
|
}
|
2013-07-16 15:56:33 +00:00
|
|
|
//for(var key in this)
|
|
|
|
// delete this[key];
|
2013-07-16 15:46:09 +00:00
|
|
|
this.dead = true;
|
2013-07-03 19:51:35 +00:00
|
|
|
}
|
|
|
|
|
2013-07-01 22:45:55 +00:00
|
|
|
Playlist.prototype.load = function(data, callback) {
|
|
|
|
this.clear();
|
|
|
|
for(var i in data.pl) {
|
|
|
|
var e = data.pl[i].media;
|
|
|
|
var m = new Media(e.id, e.title, e.seconds, e.type);
|
|
|
|
var it = this.makeItem(m);
|
|
|
|
it.temp = data.pl[i].temp;
|
|
|
|
it.queueby = data.pl[i].queueby;
|
2013-07-02 15:38:13 +00:00
|
|
|
this.items.append(it);
|
2013-07-01 22:45:55 +00:00
|
|
|
if(i == parseInt(data.pos)) {
|
|
|
|
this.current = it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(callback)
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
|
2013-06-30 00:59:33 +00:00
|
|
|
Playlist.prototype.on = function(ev, fn) {
|
|
|
|
if(typeof fn === "undefined") {
|
|
|
|
var pl = this;
|
|
|
|
return function() {
|
|
|
|
for(var i = 0; i < pl.callbacks[ev].length; i++) {
|
|
|
|
pl.callbacks[ev][i].apply(this, arguments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(typeof fn === "function") {
|
|
|
|
this.callbacks[ev].push(fn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-29 22:09:20 +00:00
|
|
|
Playlist.prototype.makeItem = function(media) {
|
|
|
|
return new PlaylistItem(media, this.next_uid++);
|
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
Playlist.prototype.add = function(item, pos) {
|
2013-08-26 21:37:09 +00:00
|
|
|
var self = this;
|
|
|
|
if(this.items.length >= 4000) {
|
2013-08-26 15:36:47 +00:00
|
|
|
return "Playlist limit reached (4,000)";
|
2013-08-26 21:37:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var it = this.items.findVideoId(item.media.id);
|
|
|
|
if(it) {
|
|
|
|
if(pos === "append" || it == this.current) {
|
|
|
|
return "This item is already on the playlist";
|
|
|
|
}
|
2013-08-26 15:36:47 +00:00
|
|
|
|
2013-08-26 21:37:09 +00:00
|
|
|
self.remove(it.uid, function () {
|
|
|
|
self.channel.sendAll("delete", {
|
|
|
|
uid: it.uid
|
|
|
|
});
|
2013-08-28 15:38:24 +00:00
|
|
|
self.channel.broadcastPlaylistMeta();
|
2013-08-26 21:37:09 +00:00
|
|
|
});
|
|
|
|
}
|
2013-08-26 15:36:47 +00:00
|
|
|
|
|
|
|
if(pos == "append") {
|
2013-08-26 21:37:09 +00:00
|
|
|
if(!this.items.append(item)) {
|
2013-08-26 15:36:47 +00:00
|
|
|
return "Playlist failure";
|
2013-08-26 21:37:09 +00:00
|
|
|
}
|
2013-08-26 15:36:47 +00:00
|
|
|
} else if(pos == "prepend") {
|
2013-08-26 21:37:09 +00:00
|
|
|
if(!this.items.prepend(item)) {
|
2013-08-26 15:36:47 +00:00
|
|
|
return "Playlist failure";
|
2013-08-26 21:37:09 +00:00
|
|
|
}
|
2013-08-26 15:36:47 +00:00
|
|
|
} else {
|
2013-08-26 21:37:09 +00:00
|
|
|
if(!this.items.insertAfter(item, pos)) {
|
2013-08-26 15:36:47 +00:00
|
|
|
return "Playlist failure";
|
2013-08-26 21:37:09 +00:00
|
|
|
}
|
2013-08-26 15:36:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(this.items.length == 1) {
|
2013-07-03 03:19:17 +00:00
|
|
|
this.current = item;
|
|
|
|
this.startPlayback();
|
|
|
|
}
|
|
|
|
|
2013-08-26 15:36:47 +00:00
|
|
|
return false;
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-03 21:29:49 +00:00
|
|
|
Playlist.prototype.addCachedMedia = function(data, callback) {
|
|
|
|
var pos = "append";
|
|
|
|
if(data.pos == "next") {
|
|
|
|
if(!this.current)
|
|
|
|
pos = "prepend";
|
|
|
|
else
|
|
|
|
pos = this.current.uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
var it = this.makeItem(data.media);
|
|
|
|
it.temp = data.temp;
|
|
|
|
it.queueby = data.queueby;
|
|
|
|
|
|
|
|
var pl = this;
|
|
|
|
|
|
|
|
var action = {
|
|
|
|
fn: function() {
|
2013-08-26 15:36:47 +00:00
|
|
|
var err = pl.add(it, pos);
|
|
|
|
callback(err, err ? null : it);
|
2013-07-03 21:29:49 +00:00
|
|
|
},
|
|
|
|
waiting: false
|
|
|
|
};
|
|
|
|
this.queueAction(action);
|
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
Playlist.prototype.addMedia = function(data, callback) {
|
2013-07-03 15:26:10 +00:00
|
|
|
|
|
|
|
if(data.type == "yp") {
|
|
|
|
this.addYouTubePlaylist(data, callback);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
var pos = "append";
|
|
|
|
if(data.pos == "next") {
|
|
|
|
if(!this.current)
|
|
|
|
pos = "prepend";
|
|
|
|
else
|
|
|
|
pos = this.current.uid;
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-03 03:19:17 +00:00
|
|
|
var it = this.makeItem(null);
|
2013-07-02 15:38:13 +00:00
|
|
|
var pl = this;
|
2013-07-03 03:19:17 +00:00
|
|
|
var action = {
|
|
|
|
fn: function() {
|
2013-08-26 15:36:47 +00:00
|
|
|
var err = pl.add(it, pos);
|
|
|
|
callback(err, err ? null : it);
|
2013-07-03 03:19:17 +00:00
|
|
|
},
|
|
|
|
waiting: true
|
|
|
|
};
|
|
|
|
this.queueAction(action);
|
|
|
|
|
2013-07-30 13:07:30 +00:00
|
|
|
// Pre-cached data
|
|
|
|
if(typeof data.title === "string" &&
|
|
|
|
typeof data.seconds === "number") {
|
|
|
|
if(data.maxlength && data.seconds > data.maxlength) {
|
|
|
|
action.expire = 0;
|
|
|
|
callback("Media is too long!", null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
it.media = new Media(data.id, data.title, data.seconds, data.type);
|
|
|
|
action.waiting = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-03 14:58:21 +00:00
|
|
|
this.server.infogetter.getMedia(data.id, data.type, function(err, media) {
|
2013-07-02 15:38:13 +00:00
|
|
|
if(err) {
|
2013-07-03 03:19:17 +00:00
|
|
|
action.expire = 0;
|
2013-07-02 15:38:13 +00:00
|
|
|
callback(err, null);
|
|
|
|
return;
|
|
|
|
}
|
2013-06-29 22:09:20 +00:00
|
|
|
|
2013-07-04 23:11:13 +00:00
|
|
|
if(data.maxlength && media.seconds > data.maxlength) {
|
|
|
|
action.expire = 0;
|
|
|
|
callback("Media is too long!", null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-03 03:19:17 +00:00
|
|
|
it.media = media;
|
2013-07-02 15:38:13 +00:00
|
|
|
it.temp = data.temp;
|
|
|
|
it.queueby = data.queueby;
|
2013-07-03 03:19:17 +00:00
|
|
|
action.waiting = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist.prototype.addMediaList = function(data, callback) {
|
2013-07-03 21:29:49 +00:00
|
|
|
var start = false;
|
|
|
|
if(data.pos == "next") {
|
2013-07-03 03:19:17 +00:00
|
|
|
data.list = data.list.reverse();
|
2013-07-03 21:29:49 +00:00
|
|
|
start = data.list[data.list.length - 1];
|
|
|
|
}
|
2013-07-03 03:19:17 +00:00
|
|
|
|
2013-07-09 16:38:48 +00:00
|
|
|
if(this.items.length != 0)
|
|
|
|
start = false;
|
|
|
|
|
2013-07-03 03:19:17 +00:00
|
|
|
var pl = this;
|
2013-07-10 02:55:40 +00:00
|
|
|
for(var i = 0; i < data.list.length; i++) {
|
|
|
|
var x = data.list[i];
|
2013-08-07 00:41:29 +00:00
|
|
|
x.pos = data.pos;
|
|
|
|
if(start && x == start) {
|
|
|
|
pl.addMedia(x, function (err, item) {
|
|
|
|
if(err) {
|
|
|
|
callback(err, item);
|
2013-07-03 21:29:49 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-08-07 00:41:29 +00:00
|
|
|
callback(err, item);
|
|
|
|
pl.current = item;
|
|
|
|
pl.startPlayback();
|
2013-07-03 21:29:49 +00:00
|
|
|
}
|
2013-08-07 00:41:29 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pl.addMedia(x, callback);
|
|
|
|
}
|
2013-07-10 02:55:40 +00:00
|
|
|
}
|
2013-07-01 22:45:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-03 15:26:10 +00:00
|
|
|
Playlist.prototype.addYouTubePlaylist = function(data, callback) {
|
|
|
|
var pos = "append";
|
|
|
|
if(data.pos == "next") {
|
|
|
|
if(!this.current)
|
|
|
|
pos = "prepend";
|
|
|
|
else
|
|
|
|
pos = this.current.uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
var pl = this;
|
2013-08-03 14:58:21 +00:00
|
|
|
this.server.infogetter.getMedia(data.id, data.type, function(err, vids) {
|
2013-07-03 15:26:10 +00:00
|
|
|
if(err) {
|
|
|
|
callback(err, null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-16 15:46:09 +00:00
|
|
|
if(data.pos === "next")
|
|
|
|
vids.reverse();
|
|
|
|
|
2013-07-03 15:26:10 +00:00
|
|
|
vids.forEach(function(media) {
|
2013-07-16 15:46:09 +00:00
|
|
|
if(data.maxlength && media.seconds > data.maxlength) {
|
|
|
|
callback("Media is too long!", null);
|
|
|
|
return;
|
|
|
|
}
|
2013-07-03 15:26:10 +00:00
|
|
|
var it = pl.makeItem(media);
|
|
|
|
it.temp = data.temp;
|
|
|
|
it.queueby = data.queueby;
|
|
|
|
pl.queueAction({
|
|
|
|
fn: function() {
|
2013-08-26 15:36:47 +00:00
|
|
|
var err = pl.add(it, pos);
|
|
|
|
callback(err, err ? null : it);
|
2013-07-03 15:26:10 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
Playlist.prototype.remove = function(uid, callback) {
|
2013-07-03 03:19:17 +00:00
|
|
|
var pl = this;
|
|
|
|
this.queueAction({
|
|
|
|
fn: function() {
|
|
|
|
var item = pl.items.find(uid);
|
|
|
|
if(pl.items.remove(uid)) {
|
|
|
|
if(callback)
|
|
|
|
callback();
|
2013-07-27 14:30:12 +00:00
|
|
|
if(item == pl.current)
|
|
|
|
pl._next();
|
2013-07-03 03:19:17 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
waiting: false
|
|
|
|
});
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
Playlist.prototype.move = function(from, after, callback) {
|
2013-07-03 03:19:17 +00:00
|
|
|
var pl = this;
|
|
|
|
this.queueAction({
|
|
|
|
fn: function() {
|
|
|
|
pl._move(from, after, callback);
|
|
|
|
},
|
|
|
|
waiting: false
|
|
|
|
});
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
Playlist.prototype._move = function(from, after, callback) {
|
|
|
|
var it = this.items.find(from);
|
|
|
|
if(!this.items.remove(from))
|
2013-07-01 22:45:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if(after === "prepend") {
|
2013-07-02 15:38:13 +00:00
|
|
|
if(!this.items.prepend(it))
|
2013-07-01 22:45:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(after === "append") {
|
2013-07-02 15:38:13 +00:00
|
|
|
if(!this.items.append(it))
|
2013-07-01 22:45:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
else if(!this.items.insertAfter(it, after))
|
2013-07-01 22:45:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
|
2013-06-29 22:09:20 +00:00
|
|
|
Playlist.prototype.next = function() {
|
|
|
|
if(!this.current)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var it = this.current;
|
|
|
|
|
|
|
|
if(it.temp) {
|
2013-07-02 15:38:13 +00:00
|
|
|
var pl = this;
|
|
|
|
this.remove(it.uid, function() {
|
|
|
|
pl.on("remove")(it);
|
|
|
|
});
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
2013-07-27 14:30:12 +00:00
|
|
|
else {
|
|
|
|
this._next();
|
|
|
|
}
|
2013-06-29 22:09:20 +00:00
|
|
|
|
|
|
|
return this.current;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist.prototype._next = function() {
|
|
|
|
if(!this.current)
|
|
|
|
return;
|
|
|
|
this.current = this.current.next;
|
2013-07-02 15:38:13 +00:00
|
|
|
if(this.current === null && this.items.first !== null)
|
|
|
|
this.current = this.items.first;
|
2013-06-29 22:09:20 +00:00
|
|
|
|
|
|
|
if(this.current) {
|
2013-06-30 00:59:33 +00:00
|
|
|
this.startPlayback();
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist.prototype.jump = function(uid) {
|
|
|
|
if(!this.current)
|
|
|
|
return false;
|
|
|
|
|
2013-07-02 15:38:13 +00:00
|
|
|
var jmp = this.items.find(uid);
|
2013-06-29 22:09:20 +00:00
|
|
|
if(!jmp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
var it = this.current;
|
|
|
|
|
|
|
|
this.current = jmp;
|
|
|
|
|
|
|
|
if(this.current) {
|
2013-06-30 00:59:33 +00:00
|
|
|
this.startPlayback();
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(it.temp) {
|
2013-07-03 21:29:49 +00:00
|
|
|
var pl = this;
|
|
|
|
this.remove(it.uid, function () {
|
|
|
|
pl.on("remove")(it);
|
|
|
|
});
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.current;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist.prototype.clear = function() {
|
2013-07-02 15:38:13 +00:00
|
|
|
this.items.clear();
|
2013-06-29 22:09:20 +00:00
|
|
|
this.next_uid = 0;
|
2013-07-03 21:29:49 +00:00
|
|
|
this.current = null;
|
2013-06-30 00:59:33 +00:00
|
|
|
clearInterval(this._leadInterval);
|
|
|
|
}
|
|
|
|
|
2013-08-13 15:18:06 +00:00
|
|
|
Playlist.prototype.count = function (id) {
|
|
|
|
var count = 0;
|
|
|
|
this.items.forEach(function (i) {
|
|
|
|
if(i.media.id === id)
|
|
|
|
count++;
|
|
|
|
});
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2013-06-30 00:59:33 +00:00
|
|
|
Playlist.prototype.lead = function(lead) {
|
|
|
|
this.leading = lead;
|
2013-06-30 19:33:38 +00:00
|
|
|
var pl = this;
|
2013-06-30 00:59:33 +00:00
|
|
|
if(!this.leading && this._leadInterval) {
|
|
|
|
clearInterval(this._leadInterval);
|
|
|
|
this._leadInterval = false;
|
|
|
|
}
|
|
|
|
else if(this.leading && !this._leadInterval) {
|
2013-08-09 00:42:46 +00:00
|
|
|
this._lastUpdate = Date.now();
|
2013-06-30 00:59:33 +00:00
|
|
|
this._leadInterval = setInterval(function() {
|
|
|
|
pl._leadLoop();
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-01 22:45:55 +00:00
|
|
|
Playlist.prototype.startPlayback = function(time) {
|
2013-07-03 20:04:50 +00:00
|
|
|
if(!this.current || !this.current.media)
|
|
|
|
return false;
|
2013-07-02 15:38:13 +00:00
|
|
|
this.current.media.paused = false;
|
|
|
|
this.current.media.currentTime = time || -1;
|
2013-06-30 00:59:33 +00:00
|
|
|
var pl = this;
|
2013-07-03 19:51:35 +00:00
|
|
|
if(this._leadInterval) {
|
|
|
|
clearInterval(this._leadInterval);
|
|
|
|
this._leadInterval = false;
|
|
|
|
}
|
|
|
|
this.on("changeMedia")(this.current.media);
|
|
|
|
if(this.leading && !isLive(this.current.media.type)) {
|
2013-07-01 22:45:55 +00:00
|
|
|
this._lastUpdate = Date.now();
|
2013-06-30 00:59:33 +00:00
|
|
|
this._leadInterval = setInterval(function() {
|
|
|
|
pl._leadLoop();
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isLive(type) {
|
|
|
|
return type == "li" // Livestream.com
|
|
|
|
|| type == "tw" // Twitch.tv
|
|
|
|
|| type == "jt" // Justin.tv
|
|
|
|
|| type == "rt" // RTMP
|
|
|
|
|| type == "jw" // JWPlayer
|
|
|
|
|| type == "us" // Ustream.tv
|
2013-08-03 15:12:53 +00:00
|
|
|
|| type == "im" // Imgur album
|
|
|
|
|| type == "cu";// Custom embed
|
2013-06-30 00:59:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const UPDATE_INTERVAL = 5;
|
|
|
|
|
|
|
|
Playlist.prototype._leadLoop = function() {
|
|
|
|
if(this.current == null)
|
|
|
|
return;
|
|
|
|
|
2013-07-27 14:40:49 +00:00
|
|
|
if(this.channel.name == "") {
|
|
|
|
this.die();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-30 00:59:33 +00:00
|
|
|
this.current.media.currentTime += (Date.now() - this._lastUpdate) / 1000.0;
|
|
|
|
this._lastUpdate = Date.now();
|
|
|
|
this._counter++;
|
|
|
|
|
|
|
|
if(this.current.media.currentTime >= this.current.media.seconds + 2) {
|
|
|
|
this.next();
|
|
|
|
}
|
|
|
|
else if(this._counter % UPDATE_INTERVAL == 0) {
|
|
|
|
this.on("mediaUpdate")(this.current.media);
|
|
|
|
}
|
2013-06-29 22:09:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Playlist;
|