282 lines
6.2 KiB
JavaScript
282 lines
6.2 KiB
JavaScript
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 {
|
|
media: this.media,
|
|
uid: this.uid,
|
|
temp: this.temp,
|
|
queueby: this.queueby
|
|
};
|
|
}
|
|
|
|
function Playlist(chan) {
|
|
this.next_uid = 0;
|
|
this.first = null;
|
|
this.last = null;
|
|
this.current = null;
|
|
this.length = 0;
|
|
this._leadInterval = false;
|
|
this._lastUpdate = 0;
|
|
this._counter = 0;
|
|
this.leading = true;
|
|
this.callbacks = {
|
|
"changeMedia": [],
|
|
"mediaUpdate": []
|
|
};
|
|
|
|
if(chan) {
|
|
this.on("mediaUpdate", function(m) {
|
|
chan.sendAll("mediaUpdate", m.timeupdate());
|
|
});
|
|
this.on("changeMedia", function(m) {
|
|
chan.sendAll("changeMedia", m.fullupdate());
|
|
});
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
Playlist.prototype.makeItem = function(media) {
|
|
return new PlaylistItem(media, this.next_uid++);
|
|
}
|
|
|
|
Playlist.prototype.find = function(uid) {
|
|
if(this.first === null)
|
|
return false;
|
|
var item = this.first;
|
|
var iter = this.first;
|
|
while(iter != null && item.uid != uid) {
|
|
item = iter;
|
|
iter = iter.next;
|
|
}
|
|
|
|
if(item && item.uid == uid)
|
|
return item;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
Playlist.prototype.prepend = function(plitem) {
|
|
if(this.first !== null) {
|
|
plitem.next = this.first;
|
|
this.first.prev = plitem;
|
|
}
|
|
// prepending to empty list
|
|
else {
|
|
this.current = plitem;
|
|
this.last = plitem;
|
|
this.startPlayback();
|
|
}
|
|
this.first = plitem;
|
|
this.first.prev = null;
|
|
this.length++;
|
|
return true;
|
|
}
|
|
|
|
Playlist.prototype.append = function(plitem) {
|
|
if(this.last != null) {
|
|
plitem.prev = this.last;
|
|
this.last.next = plitem;
|
|
}
|
|
// appending to empty list
|
|
else {
|
|
this.first = plitem;
|
|
this.current = plitem;
|
|
this.startPlayback();
|
|
}
|
|
this.last = plitem;
|
|
this.last.next = null;
|
|
this.length++;
|
|
return true;
|
|
}
|
|
|
|
Playlist.prototype.insertAfter = function(plitem, uid) {
|
|
var item = this.find(uid);
|
|
|
|
if(item) {
|
|
plitem.next = item.next;
|
|
plitem.prev = item;
|
|
item.next = plitem;
|
|
if(item == this.last) {
|
|
this.last = plitem;
|
|
}
|
|
this.length++;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Playlist.prototype.remove = function(uid, next) {
|
|
var item = this.find(uid);
|
|
if(!item)
|
|
return false;
|
|
|
|
if(item == this.first)
|
|
this.first = item.next;
|
|
if(item == this.last)
|
|
this.last = item.prev;
|
|
|
|
if(item.prev)
|
|
item.prev.next = item.next;
|
|
if(item.next)
|
|
item.next.prev = item.prev;
|
|
|
|
if(this.current == item && next)
|
|
this._next();
|
|
|
|
this.length--;
|
|
return true;
|
|
}
|
|
|
|
Playlist.prototype.next = function() {
|
|
if(!this.current)
|
|
return;
|
|
|
|
var it = this.current;
|
|
this._next();
|
|
|
|
if(it.temp) {
|
|
this.remove(it.uid, true);
|
|
}
|
|
|
|
return this.current;
|
|
}
|
|
|
|
Playlist.prototype._next = function() {
|
|
if(!this.current)
|
|
return;
|
|
this.current = this.current.next;
|
|
if(this.current === null && this.first !== null)
|
|
this.current = this.first;
|
|
|
|
if(this.current) {
|
|
this.startPlayback();
|
|
}
|
|
}
|
|
|
|
Playlist.prototype.jump = function(uid) {
|
|
if(!this.current)
|
|
return false;
|
|
|
|
var jmp = this.find(uid);
|
|
if(!jmp)
|
|
return false;
|
|
|
|
var it = this.current;
|
|
|
|
this.current = jmp;
|
|
|
|
if(this.current) {
|
|
this.startPlayback();
|
|
}
|
|
|
|
if(it.temp) {
|
|
this.remove(it.uid);
|
|
}
|
|
|
|
return this.current;
|
|
}
|
|
|
|
Playlist.prototype.toArray = function() {
|
|
var arr = [];
|
|
var item = this.first;
|
|
while(item != null) {
|
|
arr.push(item.pack());
|
|
item = item.next;
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
Playlist.prototype.clear = function() {
|
|
this.first = null;
|
|
this.last = null;
|
|
this.current = null;
|
|
this.length = 0;
|
|
this.next_uid = 0;
|
|
clearInterval(this._leadInterval);
|
|
}
|
|
|
|
Playlist.prototype.lead = function(lead) {
|
|
this.leading = lead;
|
|
if(!this.leading && this._leadInterval) {
|
|
clearInterval(this._leadInterval);
|
|
this._leadInterval = false;
|
|
}
|
|
else if(this.leading && !this._leadInterval) {
|
|
this._leadInterval = setInterval(function() {
|
|
pl._leadLoop();
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
Playlist.prototype.startPlayback = function() {
|
|
this.current.media.paused = true;
|
|
this.current.media.currentTime = -2;
|
|
var pl = this;
|
|
setTimeout(function() {
|
|
pl.current.media.paused = false;
|
|
pl.on("mediaUpdate")(pl.current.media);
|
|
}, 2000);
|
|
if(this.leading && !this._leadInterval && !isLive(this.current.media.type)) {
|
|
this._leadInterval = setInterval(function() {
|
|
pl._leadLoop();
|
|
}, 1000);
|
|
}
|
|
else if(!this.leading && this._leadInterval) {
|
|
clearInterval(this._leadInterval);
|
|
this._leadInterval = false;
|
|
}
|
|
this.on("changeMedia")(this.current.media);
|
|
}
|
|
|
|
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
|
|
|| type == "im";// Imgur album
|
|
}
|
|
|
|
const UPDATE_INTERVAL = 5;
|
|
|
|
Playlist.prototype._leadLoop = function() {
|
|
if(this.current == null)
|
|
return;
|
|
|
|
this.current.media.currentTime += (Date.now() - this._lastUpdate) / 1000.0;
|
|
this._lastUpdate = Date.now();
|
|
this._counter++;
|
|
console.log("lead", 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);
|
|
}
|
|
}
|
|
|
|
module.exports = Playlist;
|