mirror of https://github.com/calzoneman/sync.git
Merge branch 'dev' -- run update.js
This commit is contained in:
commit
ee1b6c3255
512
channel.js
512
channel.js
|
@ -25,6 +25,7 @@ var Auth = require("./auth.js");
|
||||||
var ChatCommand = require("./chatcommand.js");
|
var ChatCommand = require("./chatcommand.js");
|
||||||
var Filter = require("./filter.js").Filter;
|
var Filter = require("./filter.js").Filter;
|
||||||
var ActionLog = require("./actionlog");
|
var ActionLog = require("./actionlog");
|
||||||
|
var Playlist = require("./playlist");
|
||||||
var sanitize = require("validator").sanitize;
|
var sanitize = require("validator").sanitize;
|
||||||
|
|
||||||
var Channel = function(name) {
|
var Channel = function(name) {
|
||||||
|
@ -35,10 +36,9 @@ var Channel = function(name) {
|
||||||
// Initialize defaults
|
// Initialize defaults
|
||||||
this.registered = false;
|
this.registered = false;
|
||||||
this.users = [];
|
this.users = [];
|
||||||
this.queue = [];
|
this.playlist = new Playlist(this);
|
||||||
this.library = {};
|
this.library = {};
|
||||||
this.position = -1;
|
this.position = -1;
|
||||||
this.media = null;
|
|
||||||
this.drinks = 0;
|
this.drinks = 0;
|
||||||
this.leader = null;
|
this.leader = null;
|
||||||
this.chatbuffer = [];
|
this.chatbuffer = [];
|
||||||
|
@ -59,6 +59,7 @@ var Channel = function(name) {
|
||||||
playlistjump: 1.5,
|
playlistjump: 1.5,
|
||||||
playlistaddlist: 1.5,
|
playlistaddlist: 1.5,
|
||||||
playlistaddlive: 1.5,
|
playlistaddlive: 1.5,
|
||||||
|
exceedmaxlength: 2,
|
||||||
addnontemp: 2,
|
addnontemp: 2,
|
||||||
settemp: 2,
|
settemp: 2,
|
||||||
playlistgeturl: 1.5,
|
playlistgeturl: 1.5,
|
||||||
|
@ -78,6 +79,7 @@ var Channel = function(name) {
|
||||||
allow_voteskip: true,
|
allow_voteskip: true,
|
||||||
voteskip_ratio: 0.5,
|
voteskip_ratio: 0.5,
|
||||||
pagetitle: this.name,
|
pagetitle: this.name,
|
||||||
|
maxlength: 0,
|
||||||
externalcss: "",
|
externalcss: "",
|
||||||
externaljs: "",
|
externaljs: "",
|
||||||
chat_antiflood: false,
|
chat_antiflood: false,
|
||||||
|
@ -156,31 +158,35 @@ Channel.prototype.loadDump = function() {
|
||||||
try {
|
try {
|
||||||
this.logger.log("*** Loading channel dump from disk");
|
this.logger.log("*** Loading channel dump from disk");
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
for(var i = 0; i < data.queue.length; i++) {
|
/* Load the playlist */
|
||||||
var e = data.queue[i];
|
|
||||||
var m = new Media(e.id, e.title, e.seconds, e.type);
|
// Old
|
||||||
m.queueby = data.queue[i].queueby ? data.queue[i].queueby
|
if(data.queue) {
|
||||||
: "";
|
if(data.position < 0)
|
||||||
if(e.temp !== undefined) {
|
data.position = 0;
|
||||||
m.temp = e.temp;
|
for(var i = 0; i < data.queue.length; i++) {
|
||||||
|
var e = data.queue[i];
|
||||||
|
var m = new Media(e.id, e.title, e.seconds, e.type);
|
||||||
|
var p = this.playlist.makeItem(m);
|
||||||
|
p.queueby = data.queue[i].queueby ? data.queue[i].queueby
|
||||||
|
: "";
|
||||||
|
p.temp = e.temp;
|
||||||
|
this.playlist.items.append(p);
|
||||||
|
if(i == data.position)
|
||||||
|
this.playlist.current = p;
|
||||||
}
|
}
|
||||||
this.queue.push(m);
|
this.sendAll("playlist", this.playlist.items.toArray());
|
||||||
|
this.broadcastPlaylistMeta();
|
||||||
|
this.playlist.startPlayback();
|
||||||
}
|
}
|
||||||
this.sendAll("playlist", this.queue);
|
// Current
|
||||||
this.broadcastPlaylistMeta();
|
else if(data.playlist) {
|
||||||
// Backwards compatibility
|
var chan = this;
|
||||||
if(data.currentPosition != undefined) {
|
this.playlist.load(data.playlist, function() {
|
||||||
this.position = data.currentPosition - 1;
|
chan.sendAll("playlist", chan.playlist.items.toArray());
|
||||||
}
|
chan.broadcastPlaylistMeta();
|
||||||
else {
|
chan.playlist.startPlayback(data.playlist.time);
|
||||||
this.position = data.position - 1;
|
});
|
||||||
}
|
|
||||||
if(this.position < -1)
|
|
||||||
this.position = -1;
|
|
||||||
if(this.queue.length > 0)
|
|
||||||
this.playNext();
|
|
||||||
if(this.media && data.currentTime) {
|
|
||||||
this.media.currentTime = data.currentTime;
|
|
||||||
}
|
}
|
||||||
for(var key in data.opts) {
|
for(var key in data.opts) {
|
||||||
// Gotta love backwards compatibility
|
// Gotta love backwards compatibility
|
||||||
|
@ -204,13 +210,13 @@ Channel.prototype.loadDump = function() {
|
||||||
if(f[0] != undefined) {
|
if(f[0] != undefined) {
|
||||||
var filt = new Filter("", f[0], "g", f[1]);
|
var filt = new Filter("", f[0], "g", f[1]);
|
||||||
filt.active = f[2];
|
filt.active = f[2];
|
||||||
this.updateFilter(filt);
|
this.updateFilter(filt, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var filt = new Filter(f.name, f.source, f.flags, f.replace);
|
var filt = new Filter(f.name, f.source, f.flags, f.replace);
|
||||||
filt.active = f.active;
|
filt.active = f.active;
|
||||||
filt.filterlinks = f.filterlinks;
|
filt.filterlinks = f.filterlinks;
|
||||||
this.updateFilter(filt);
|
this.updateFilter(filt, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.broadcastChatFilters();
|
this.broadcastChatFilters();
|
||||||
|
@ -232,7 +238,7 @@ Channel.prototype.loadDump = function() {
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
Logger.errlog.log("Channel dump load failed: ");
|
Logger.errlog.log("Channel dump load failed: ");
|
||||||
Logger.errlog.log(e);
|
Logger.errlog.log(e.stack);
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -247,7 +253,7 @@ Channel.prototype.saveDump = function() {
|
||||||
var dump = {
|
var dump = {
|
||||||
position: this.position,
|
position: this.position,
|
||||||
currentTime: this.media ? this.media.currentTime : 0,
|
currentTime: this.media ? this.media.currentTime : 0,
|
||||||
queue: this.queue,
|
playlist: this.playlist.dump(),
|
||||||
opts: this.opts,
|
opts: this.opts,
|
||||||
permissions: this.permissions,
|
permissions: this.permissions,
|
||||||
filters: filts,
|
filters: filts,
|
||||||
|
@ -294,7 +300,7 @@ Channel.prototype.tryRegister = function(user) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(Database.registerChannel(this.name)) {
|
if(Database.registerChannel(this.name, user.name)) {
|
||||||
ActionLog.record(user.ip, user.name, "channel-register-success", [this.name]);
|
ActionLog.record(user.ip, user.name, "channel-register-success", [this.name]);
|
||||||
this.registered = true;
|
this.registered = true;
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
|
@ -728,14 +734,15 @@ Channel.prototype.sendChannelRanks = function(user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.sendPlaylist = function(user) {
|
Channel.prototype.sendPlaylist = function(user) {
|
||||||
user.socket.emit("playlist", this.queue);
|
user.socket.emit("playlist", this.playlist.items.toArray());
|
||||||
user.socket.emit("setPosition", this.position);
|
if(this.playlist.current)
|
||||||
|
user.socket.emit("setCurrent", this.playlist.current.uid);
|
||||||
user.socket.emit("setPlaylistMeta", this.plmeta);
|
user.socket.emit("setPlaylistMeta", this.plmeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.sendMediaUpdate = function(user) {
|
Channel.prototype.sendMediaUpdate = function(user) {
|
||||||
if(this.media != null) {
|
if(this.playlist.current != null) {
|
||||||
user.socket.emit("changeMedia", this.media.fullupdate());
|
user.socket.emit("changeMedia", this.playlist.current.media.fullupdate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,12 +787,15 @@ Channel.prototype.sendAllWithPermission = function(perm, msg, data) {
|
||||||
|
|
||||||
Channel.prototype.broadcastPlaylistMeta = function() {
|
Channel.prototype.broadcastPlaylistMeta = function() {
|
||||||
var total = 0;
|
var total = 0;
|
||||||
for(var i = 0; i < this.queue.length; i++) {
|
var iter = this.playlist.items.first;
|
||||||
total += this.queue[i].seconds;
|
while(iter !== null) {
|
||||||
|
if(iter.media !== null)
|
||||||
|
total += iter.media.seconds;
|
||||||
|
iter = iter.next;
|
||||||
}
|
}
|
||||||
var timestr = formatTime(total);
|
var timestr = formatTime(total);
|
||||||
var packet = {
|
var packet = {
|
||||||
count: this.queue.length,
|
count: this.playlist.items.length,
|
||||||
time: timestr
|
time: timestr
|
||||||
};
|
};
|
||||||
this.plmeta = packet;
|
this.plmeta = packet;
|
||||||
|
@ -1003,29 +1013,41 @@ function isLive(type) {
|
||||||
|| type == "im";// Imgur album
|
|| type == "im";// Imgur album
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.queueAdd = function(media, idx) {
|
Channel.prototype.queueAdd = function(item, after) {
|
||||||
this.queue.splice(idx, 0, media);
|
var chan = this;
|
||||||
this.sendAll("queue", {
|
function afterAdd() {
|
||||||
media: media.pack(),
|
chan.sendAll("queue", {
|
||||||
pos: idx
|
item: item.pack(),
|
||||||
});
|
after: after
|
||||||
this.broadcastPlaylistMeta();
|
});
|
||||||
if(this.queue.length == 1) {
|
chan.broadcastPlaylistMeta();
|
||||||
this.playNext();
|
|
||||||
}
|
}
|
||||||
|
if(after === "prepend")
|
||||||
|
this.playlist.prepend(item, afterAdd);
|
||||||
|
else if(after === "append")
|
||||||
|
this.playlist.append(item, afterAdd);
|
||||||
|
else
|
||||||
|
this.playlist.insertAfter(item, after, afterAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.autoTemp = function(media, user) {
|
Channel.prototype.autoTemp = function(item, user) {
|
||||||
if(isLive(media.type)) {
|
if(isLive(item.media.type)) {
|
||||||
media.temp = true;
|
item.temp = true;
|
||||||
}
|
}
|
||||||
if(!this.hasPermission(user, "addnontemp")) {
|
if(!this.hasPermission(user, "addnontemp")) {
|
||||||
media.temp = true;
|
item.temp = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.enqueue = function(data, user, callback) {
|
Channel.prototype.enqueue = function(data, user, callback) {
|
||||||
var idx = data.pos == "next" ? this.position + 1 : this.queue.length;
|
var after = "";
|
||||||
|
var current = this.playlist.current;
|
||||||
|
if(data.pos == "next") {
|
||||||
|
after = current ? current.uid : "prepend";
|
||||||
|
}
|
||||||
|
else if(data.pos == "end") {
|
||||||
|
after = "append";
|
||||||
|
}
|
||||||
|
|
||||||
if(isLive(data.type) && !this.hasPermission(user, "playlistaddlive")) {
|
if(isLive(data.type) && !this.hasPermission(user, "playlistaddlive")) {
|
||||||
user.socket.emit("queueFail", "You don't have permission to queue livestreams");
|
user.socket.emit("queueFail", "You don't have permission to queue livestreams");
|
||||||
|
@ -1035,9 +1057,10 @@ Channel.prototype.enqueue = function(data, user, callback) {
|
||||||
// Prefer cache over looking up new data
|
// Prefer cache over looking up new data
|
||||||
if(data.id in this.library) {
|
if(data.id in this.library) {
|
||||||
var media = this.library[data.id].dup();
|
var media = this.library[data.id].dup();
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
this.logger.log("*** Queued from cache: id=" + data.id);
|
this.logger.log("*** Queued from cache: id=" + data.id);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
|
@ -1058,71 +1081,79 @@ Channel.prototype.enqueue = function(data, user, callback) {
|
||||||
user.socket.emit("queueFail", err);
|
user.socket.emit("queueFail", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
this.cacheMedia(media);
|
this.cacheMedia(media);
|
||||||
if(data.type == "yp")
|
if(data.type == "yp")
|
||||||
idx++;
|
after = item.uid;
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
break;
|
break;
|
||||||
case "li":
|
case "li":
|
||||||
var media = new Media(data.id, "Livestream - " + data.id, "--:--", "li");
|
var media = new Media(data.id, "Livestream.com - " + data.id, "--:--", "li");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
break;
|
break;
|
||||||
case "tw":
|
case "tw":
|
||||||
var media = new Media(data.id, "Twitch - " + data.id, "--:--", "tw");
|
var media = new Media(data.id, "Twitch.tv - " + data.id, "--:--", "tw");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
break;
|
break;
|
||||||
case "jt":
|
case "jt":
|
||||||
var media = new Media(data.id, "JustinTV - " + data.id, "--:--", "jt");
|
var media = new Media(data.id, "Justin.tv - " + data.id, "--:--", "jt");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
break;
|
break;
|
||||||
case "us":
|
case "us":
|
||||||
InfoGetter.getUstream(data.id, function(id) {
|
InfoGetter.getUstream(data.id, function(id) {
|
||||||
var media = new Media(id, "Ustream - " + data.id, "--:--", "us");
|
var media = new Media(id, "Ustream.tv - " + data.id, "--:--", "us");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
break;
|
break;
|
||||||
case "rt":
|
case "rt":
|
||||||
var media = new Media(data.id, "Livestream", "--:--", "rt");
|
var media = new Media(data.id, "Livestream", "--:--", "rt");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
break;
|
break;
|
||||||
case "jw":
|
case "jw":
|
||||||
var media = new Media(data.id, "JWPlayer Stream - " + data.id, "--:--", "jw");
|
var media = new Media(data.id, "JWPlayer Stream - " + data.id, "--:--", "jw");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
break;
|
break;
|
||||||
case "im":
|
case "im":
|
||||||
var media = new Media(data.id, "Imgur Album", "--:--", "im");
|
var media = new Media(data.id, "Imgur Album", "--:--", "im");
|
||||||
media.queueby = user ? user.name : "";
|
var item = this.playlist.makeItem(media);
|
||||||
this.autoTemp(media, user);
|
item.queueby = user ? user.name : "";
|
||||||
this.queueAdd(media, idx);
|
this.autoTemp(item, user);
|
||||||
|
this.queueAdd(item, after);
|
||||||
if(callback)
|
if(callback)
|
||||||
callback();
|
callback();
|
||||||
break;
|
break;
|
||||||
|
@ -1157,37 +1188,89 @@ Channel.prototype.tryQueue = function(user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data.list)
|
if(data.list)
|
||||||
this.enqueueList(data, user);
|
this.addMediaList(data, user);
|
||||||
else
|
else
|
||||||
this.enqueue(data, user);
|
this.addMedia(data, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.enqueueList = function(data, user) {
|
Channel.prototype.addMedia = function(data, user) {
|
||||||
|
data.temp = isLive(data.type) || !this.hasPermission(user, "addnontemp");
|
||||||
|
data.queueby = user ? user.name : "";
|
||||||
|
data.maxlength = this.hasPermission(user, "exceedmaxlength") ? 0 : this.opts.maxlength;
|
||||||
|
var chan = this;
|
||||||
|
if(data.id in this.library) {
|
||||||
|
var m = this.library[data.id].dup();
|
||||||
|
if(data.maxlength && m.seconds > data.maxlength) {
|
||||||
|
user.socket.emit("queueFail", "Media is too long!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.media = m;
|
||||||
|
this.playlist.addCachedMedia(data, function (err, item) {
|
||||||
|
if(err) {
|
||||||
|
if(err === true)
|
||||||
|
err = false;
|
||||||
|
if(user)
|
||||||
|
user.socket.emit("queueFail", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chan.sendAll("queue", {
|
||||||
|
item: item.pack(),
|
||||||
|
after: item.prev ? item.prev.uid : "prepend"
|
||||||
|
});
|
||||||
|
chan.broadcastPlaylistMeta();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(isLive(data.type) && !this.hasPermission(user, "playlistaddlive")) {
|
||||||
|
user.socket.emit("queueFail", "You don't have permission to queue livestreams");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.temp = isLive(data.type) || !this.hasPermission(user, "addnontemp");
|
||||||
|
data.queueby = user ? user.name : "";
|
||||||
|
|
||||||
|
this.playlist.addMedia(data, function(err, item) {
|
||||||
|
if(err) {
|
||||||
|
if(err === true)
|
||||||
|
err = false;
|
||||||
|
if(user)
|
||||||
|
user.socket.emit("queueFail", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chan.sendAll("queue", {
|
||||||
|
item: item.pack(),
|
||||||
|
after: item.prev ? item.prev.uid : "prepend"
|
||||||
|
});
|
||||||
|
chan.broadcastPlaylistMeta();
|
||||||
|
chan.cacheMedia(item.media);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel.prototype.addMediaList = function(data, user) {
|
||||||
var pl = data.list;
|
var pl = data.list;
|
||||||
var chan = this;
|
var chan = this;
|
||||||
// Queue in reverse order for qnext
|
this.playlist.addMediaList(data, function(err, item) {
|
||||||
if(data.pos == "next") {
|
if(err) {
|
||||||
var i = pl.length;
|
if(err === true)
|
||||||
var cback = function() {
|
err = false;
|
||||||
i--;
|
if(user)
|
||||||
if(i > 0) {
|
user.socket.emit("queueFail", err);
|
||||||
pl[i].pos = "next";
|
return;
|
||||||
chan.enqueue(pl[i], user, cback);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.enqueue(pl[0], user, cback);
|
else {
|
||||||
}
|
chan.sendAll("queue", {
|
||||||
else {
|
item: item.pack(),
|
||||||
var i = 0;
|
after: item.prev ? item.prev.uid : "prepend"
|
||||||
var cback = function() {
|
});
|
||||||
i++;
|
chan.broadcastPlaylistMeta();
|
||||||
if(i < pl.length) {
|
chan.cacheMedia(item.media);
|
||||||
pl[i].pos = "end";
|
|
||||||
chan.enqueue(pl[i], user, cback);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.enqueue(pl[i], user, cback);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryQueuePlaylist = function(user, data) {
|
Channel.prototype.tryQueuePlaylist = function(user, data) {
|
||||||
|
@ -1206,19 +1289,21 @@ Channel.prototype.tryQueuePlaylist = function(user, data) {
|
||||||
|
|
||||||
var pl = Database.loadUserPlaylist(user.name, data.name);
|
var pl = Database.loadUserPlaylist(user.name, data.name);
|
||||||
data.list = pl;
|
data.list = pl;
|
||||||
this.enqueueList(data, user);
|
this.addMediaList(data, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.setTemp = function(idx, temp) {
|
Channel.prototype.setTemp = function(uid, temp) {
|
||||||
var med = this.queue[idx];
|
var item = this.playlist.items.find(uid);
|
||||||
med.temp = temp;
|
if(!item)
|
||||||
|
return;
|
||||||
|
item.temp = temp;
|
||||||
this.sendAll("setTemp", {
|
this.sendAll("setTemp", {
|
||||||
position: idx,
|
uid: uid,
|
||||||
temp: temp
|
temp: temp
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!temp) {
|
if(!temp) {
|
||||||
this.cacheMedia(med);
|
this.cacheMedia(item.media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,42 +1311,24 @@ Channel.prototype.trySetTemp = function(user, data) {
|
||||||
if(!this.hasPermission(user, "settemp")) {
|
if(!this.hasPermission(user, "settemp")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(typeof data.position != "number" || typeof data.temp != "boolean") {
|
if(typeof data.uid != "number" || typeof data.temp != "boolean") {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(data.position < 0 || data.position >= this.queue.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setTemp(data.position, data.temp);
|
this.setTemp(data.uid, data.temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Channel.prototype.dequeue = function(position, removeonly) {
|
Channel.prototype.dequeue = function(uid) {
|
||||||
if(position < 0 || position >= this.queue.length) {
|
var chan = this;
|
||||||
return;
|
function afterDelete() {
|
||||||
|
chan.sendAll("delete", {
|
||||||
|
uid: uid
|
||||||
|
});
|
||||||
|
chan.broadcastPlaylistMeta();
|
||||||
}
|
}
|
||||||
|
if(!this.playlist.remove(uid, afterDelete))
|
||||||
this.queue.splice(position, 1);
|
|
||||||
this.sendAll("delete", {
|
|
||||||
position: position
|
|
||||||
});
|
|
||||||
this.broadcastPlaylistMeta();
|
|
||||||
|
|
||||||
if(removeonly)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If you remove the currently playing video, play the next one
|
|
||||||
if(position == this.position) {
|
|
||||||
this.position--;
|
|
||||||
this.playNext();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If you remove a video whose position is before the one currently
|
|
||||||
// playing, you have to reduce the position of the one playing
|
|
||||||
if(position < this.position) {
|
|
||||||
this.position--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryDequeue = function(user, data) {
|
Channel.prototype.tryDequeue = function(user, data) {
|
||||||
|
@ -1288,59 +1355,19 @@ Channel.prototype.tryUncache = function(user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.playNext = function() {
|
Channel.prototype.playNext = function() {
|
||||||
var pos = this.position + 1 >= this.queue.length ? 0 : this.position + 1;
|
this.playlist.next();
|
||||||
this.jumpTo(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryPlayNext = function(user) {
|
Channel.prototype.tryPlayNext = function(user) {
|
||||||
if(!this.hasPermission(user, "playlistjump")) {
|
if(!this.hasPermission(user, "playlistjump")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.playNext();
|
this.playNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.jumpTo = function(pos) {
|
Channel.prototype.jumpTo = function(uid) {
|
||||||
if(pos >= this.queue.length || pos < 0) {
|
return this.playlist.jump(uid);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset voteskip
|
|
||||||
this.voteskip = false;
|
|
||||||
this.broadcastVoteskipUpdate();
|
|
||||||
this.drinks = 0;
|
|
||||||
this.broadcastDrinks();
|
|
||||||
|
|
||||||
var old = this.position;
|
|
||||||
if(this.media && this.media.temp && old != pos) {
|
|
||||||
this.dequeue(old, true);
|
|
||||||
if(pos > old && pos > 0) {
|
|
||||||
pos--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(pos >= this.queue.length || pos < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.media) {
|
|
||||||
delete this.media["currentTime"];
|
|
||||||
delete this.media["paused"];
|
|
||||||
}
|
|
||||||
this.position = pos;
|
|
||||||
var oid = this.media ? this.media.id : "";
|
|
||||||
this.media = this.queue[this.position];
|
|
||||||
this.media.currentTime = -1;
|
|
||||||
this.media.paused = false;
|
|
||||||
|
|
||||||
this.sendAll("changeMedia", this.media.fullupdate());
|
|
||||||
this.sendAll("setPosition", this.position);
|
|
||||||
|
|
||||||
// If it's not a livestream, enable autolead
|
|
||||||
if(this.leader == null && !isLive(this.media.type)) {
|
|
||||||
this.time = new Date().getTime();
|
|
||||||
if(this.media.id != oid) {
|
|
||||||
mediaUpdate(this, this.media.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryJumpTo = function(user, data) {
|
Channel.prototype.tryJumpTo = function(user, data) {
|
||||||
|
@ -1356,10 +1383,8 @@ Channel.prototype.tryJumpTo = function(user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.clearqueue = function() {
|
Channel.prototype.clearqueue = function() {
|
||||||
this.queue = [];
|
this.playlist.clear();
|
||||||
for(var i = 0; i < this.users.length; i++) {
|
this.sendAll("playlist", this.playlist.items.toArray());
|
||||||
this.sendPlaylist(this.users[i]);
|
|
||||||
}
|
|
||||||
this.broadcastPlaylistMeta();
|
this.broadcastPlaylistMeta();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1372,20 +1397,20 @@ Channel.prototype.tryClearqueue = function(user) {
|
||||||
|
|
||||||
Channel.prototype.shufflequeue = function() {
|
Channel.prototype.shufflequeue = function() {
|
||||||
var n = [];
|
var n = [];
|
||||||
var current = false;
|
var pl = this.playlist.items.toArray(false);
|
||||||
while(this.queue.length > 0) {
|
this.playlist.clear();
|
||||||
var i = parseInt(Math.random() * this.queue.length);
|
while(pl.length > 0) {
|
||||||
n.push(this.queue[i]);
|
var i = parseInt(Math.random() * pl.length);
|
||||||
if(!current && i == this.position) {
|
var item = this.playlist.makeItem(pl[i].media);
|
||||||
this.position = n.length - 1;
|
item.temp = pl[i].temp;
|
||||||
current = true;
|
item.queueby = pl[i].queueby;
|
||||||
}
|
this.playlist.items.append(item);
|
||||||
this.queue.splice(i, 1);
|
pl.splice(i, 1);
|
||||||
}
|
}
|
||||||
this.queue = n;
|
this.playlist.current = this.playlist.items.first;
|
||||||
this.sendAll("playlist", this.queue);
|
this.sendAll("playlist", this.playlist.items.toArray());
|
||||||
this.sendAll("setPosition", this.position);
|
|
||||||
this.sendAll("setPlaylistMeta", this.plmeta);
|
this.sendAll("setPlaylistMeta", this.plmeta);
|
||||||
|
this.playlist.startPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryShufflequeue = function(user) {
|
Channel.prototype.tryShufflequeue = function(user) {
|
||||||
|
@ -1400,73 +1425,53 @@ Channel.prototype.tryUpdate = function(user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data == null ||
|
if(typeof data.id !== "string" || typeof data.currentTime !== "number")
|
||||||
data.id == undefined || data.currentTime == undefined) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if(this.media == null) {
|
if(this.playlist.current === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isLive(this.media.type) && this.media.type != "jw") {
|
if(isLive(this.playlist.current.media.type)
|
||||||
|
&& this.playlist.current.media.type != "jw") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.media.id != data.id) {
|
if(this.playlist.current.media.id != data.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.media.currentTime = data.currentTime;
|
this.playlist.current.media.currentTime = data.currentTime;
|
||||||
this.media.paused = data.paused;
|
this.playlist.current.media.paused = data.paused;
|
||||||
this.sendAll("mediaUpdate", this.media.timeupdate());
|
this.sendAll("mediaUpdate", this.playlist.current.media.timeupdate());
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.move = function(data, user) {
|
Channel.prototype.move = function(data, user) {
|
||||||
if(data.from < 0 || data.from >= this.queue.length) {
|
var chan = this;
|
||||||
return;
|
function afterMove() {
|
||||||
}
|
var moveby = user && user.name ? user.name : null;
|
||||||
if(data.to < 0 || data.to > this.queue.length) {
|
if(typeof data.moveby !== "undefined")
|
||||||
return;
|
moveby = data.moveby;
|
||||||
|
|
||||||
|
chan.sendAll("moveVideo", {
|
||||||
|
from: data.from,
|
||||||
|
after: data.after,
|
||||||
|
moveby: moveby
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var media = this.queue[data.from];
|
this.playlist.move(data.from, data.after, afterMove);
|
||||||
var to = data.to > data.from ? data.to + 1 : data.to;
|
|
||||||
var from = data.to > data.from ? data.from : data.from + 1;
|
|
||||||
var moveby = user && user.name ? user.name : null;
|
|
||||||
if(typeof data.moveby !== "undefined")
|
|
||||||
moveby = data.moveby;
|
|
||||||
|
|
||||||
this.queue.splice(to, 0, media);
|
|
||||||
this.queue.splice(from, 1);
|
|
||||||
this.sendAll("moveVideo", {
|
|
||||||
from: data.from,
|
|
||||||
to: data.to,
|
|
||||||
moveby: moveby
|
|
||||||
});
|
|
||||||
|
|
||||||
// Account for moving things around the active video
|
|
||||||
if(data.from < this.position && data.to >= this.position) {
|
|
||||||
this.position--;
|
|
||||||
}
|
|
||||||
else if(data.from > this.position && data.to < this.position) {
|
|
||||||
this.position++
|
|
||||||
}
|
|
||||||
else if(data.from == this.position) {
|
|
||||||
this.position = data.to;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryMove = function(user, data) {
|
Channel.prototype.tryMove = function(user, data) {
|
||||||
if(!this.hasPermission(user, "playlistmove")) {
|
if(!this.hasPermission(user, "playlistmove")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof data.from !== "number" || typeof data.to !== "number") {
|
if(typeof data.from !== "number" || (typeof data.after !== "number" && typeof data.after !== "string"))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
this.move(data, user);
|
this.move(data, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* REGION Polls */
|
/* REGION Polls */
|
||||||
|
@ -1571,7 +1576,7 @@ Channel.prototype.removeFilter = function(filter) {
|
||||||
this.broadcastChatFilters();
|
this.broadcastChatFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.updateFilter = function(filter) {
|
Channel.prototype.updateFilter = function(filter, emit) {
|
||||||
if(filter.name == "")
|
if(filter.name == "")
|
||||||
filter.name = filter.source;
|
filter.name = filter.source;
|
||||||
var found = false;
|
var found = false;
|
||||||
|
@ -1585,7 +1590,8 @@ Channel.prototype.updateFilter = function(filter) {
|
||||||
if(!found) {
|
if(!found) {
|
||||||
this.filters.push(filter);
|
this.filters.push(filter);
|
||||||
}
|
}
|
||||||
this.broadcastChatFilters();
|
if(emit !== false)
|
||||||
|
this.broadcastChatFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.prototype.tryUpdateFilter = function(user, f) {
|
Channel.prototype.tryUpdateFilter = function(user, f) {
|
||||||
|
@ -1933,17 +1939,21 @@ Channel.prototype.changeLeader = function(name) {
|
||||||
}
|
}
|
||||||
if(name == "") {
|
if(name == "") {
|
||||||
this.logger.log("*** Resuming autolead");
|
this.logger.log("*** Resuming autolead");
|
||||||
if(this.media != null && !isLive(this.media.type)) {
|
/*
|
||||||
this.media.paused = false;
|
if(this.playlist.current != null && !isLive(this.playlist.current.media.type)) {
|
||||||
|
this.playlist.current.media.paused = false;
|
||||||
this.time = new Date().getTime();
|
this.time = new Date().getTime();
|
||||||
this.i = 0;
|
this.i = 0;
|
||||||
mediaUpdate(this, this.media.id);
|
mediaUpdate(this, this.playlist.current.media.id);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
this.playlist.lead(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(var i = 0; i < this.users.length; i++) {
|
for(var i = 0; i < this.users.length; i++) {
|
||||||
if(this.users[i].name == name) {
|
if(this.users[i].name == name) {
|
||||||
this.logger.log("*** Assigned leader: " + name);
|
this.logger.log("*** Assigned leader: " + name);
|
||||||
|
this.playlist.lead(false);
|
||||||
this.leader = this.users[i];
|
this.leader = this.users[i];
|
||||||
if(this.users[i].rank < 1.5) {
|
if(this.users[i].rank < 1.5) {
|
||||||
this.users[i].oldrank = this.users[i].rank;
|
this.users[i].oldrank = this.users[i].rank;
|
||||||
|
|
13
database.js
13
database.js
|
@ -105,6 +105,7 @@ function init() {
|
||||||
var query = ["CREATE TABLE IF NOT EXISTS `channels` (",
|
var query = ["CREATE TABLE IF NOT EXISTS `channels` (",
|
||||||
"`id` INT NOT NULL AUTO_INCREMENT,",
|
"`id` INT NOT NULL AUTO_INCREMENT,",
|
||||||
"`name` VARCHAR(255) NOT NULL,",
|
"`name` VARCHAR(255) NOT NULL,",
|
||||||
|
"`owner` VARCHAR(20) NOT NULL,",
|
||||||
"PRIMARY KEY(`id`))",
|
"PRIMARY KEY(`id`))",
|
||||||
"ENGINE = MyISAM;"].join("");
|
"ENGINE = MyISAM;"].join("");
|
||||||
var results = db.querySync(query);
|
var results = db.querySync(query);
|
||||||
|
@ -249,7 +250,7 @@ function globalUnbanIP(ip) {
|
||||||
|
|
||||||
/* REGION Channel Registration/Loading */
|
/* REGION Channel Registration/Loading */
|
||||||
|
|
||||||
function registerChannel(name) {
|
function registerChannel(name, owner) {
|
||||||
if(!name.match(/^[a-zA-Z0-9-_]+$/)) {
|
if(!name.match(/^[a-zA-Z0-9-_]+$/)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -305,8 +306,8 @@ function registerChannel(name) {
|
||||||
|
|
||||||
// Insert into channel table
|
// Insert into channel table
|
||||||
query = createQuery(
|
query = createQuery(
|
||||||
"INSERT INTO `channels` VALUES (NULL, ?)",
|
"INSERT INTO `channels` VALUES (NULL, ?, ?)",
|
||||||
[name]
|
[name, owner]
|
||||||
);
|
);
|
||||||
|
|
||||||
results = db.querySync(query);
|
results = db.querySync(query);
|
||||||
|
@ -866,10 +867,10 @@ function saveUserPlaylist(pl, user, name) {
|
||||||
var time = 0;
|
var time = 0;
|
||||||
for(var i = 0; i < pl.length; i++) {
|
for(var i = 0; i < pl.length; i++) {
|
||||||
var e = {
|
var e = {
|
||||||
id: pl[i].id,
|
id: pl[i].media.id,
|
||||||
type: pl[i].type
|
type: pl[i].media.type
|
||||||
};
|
};
|
||||||
time += pl[i].seconds;
|
time += pl[i].media.seconds;
|
||||||
pl2.push(e);
|
pl2.push(e);
|
||||||
}
|
}
|
||||||
var count = pl2.length;
|
var count = pl2.length;
|
||||||
|
|
44
get-info.js
44
get-info.js
|
@ -17,7 +17,7 @@ var Media = require("./media.js").Media;
|
||||||
// Helper function for making an HTTP request and getting the result
|
// Helper function for making an HTTP request and getting the result
|
||||||
// as JSON
|
// as JSON
|
||||||
function getJSON(options, callback) {
|
function getJSON(options, callback) {
|
||||||
var req = http.request(options, function(res){
|
var req = http.request(options, function(res) {
|
||||||
var buffer = "";
|
var buffer = "";
|
||||||
res.setEncoding("utf8");
|
res.setEncoding("utf8");
|
||||||
res.on("data", function (chunk) {
|
res.on("data", function (chunk) {
|
||||||
|
@ -47,7 +47,7 @@ function getJSON(options, callback) {
|
||||||
|
|
||||||
// Dailymotion uses HTTPS for anonymous requests... [](/picard)
|
// Dailymotion uses HTTPS for anonymous requests... [](/picard)
|
||||||
function getJSONHTTPS(options, callback) {
|
function getJSONHTTPS(options, callback) {
|
||||||
var req = https.request(options, function(res){
|
var req = https.request(options, function(res) {
|
||||||
var buffer = "";
|
var buffer = "";
|
||||||
res.setEncoding("utf8");
|
res.setEncoding("utf8");
|
||||||
res.on("data", function (chunk) {
|
res.on("data", function (chunk) {
|
||||||
|
@ -87,6 +87,7 @@ exports.getYTInfo = function(id, callback) {
|
||||||
timeout: 1000}, callback);
|
timeout: 1000}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up a YouTube playlist
|
||||||
exports.getYTPlaylist = function(id, callback, url) {
|
exports.getYTPlaylist = function(id, callback, url) {
|
||||||
var path = "/feeds/api/playlists/" + id + "?v=2&alt=json";
|
var path = "/feeds/api/playlists/" + id + "?v=2&alt=json";
|
||||||
if(url) {
|
if(url) {
|
||||||
|
@ -101,6 +102,7 @@ exports.getYTPlaylist = function(id, callback, url) {
|
||||||
timeout: 1000}, callback);
|
timeout: 1000}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search YouTube
|
||||||
exports.searchYT = function(terms, callback) {
|
exports.searchYT = function(terms, callback) {
|
||||||
// I really miss Python's list comprehensions
|
// I really miss Python's list comprehensions
|
||||||
for(var i = 0; i < terms.length; i++) {
|
for(var i = 0; i < terms.length; i++) {
|
||||||
|
@ -157,13 +159,8 @@ exports.getYTSearchResults = function(query, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up Soundcloud metadata
|
// Look up Soundcloud metadata
|
||||||
// Whoever designed this should rethink it. I'll submit a feedback
|
|
||||||
// form on their website.
|
|
||||||
exports.getSCInfo = function(url, callback) {
|
exports.getSCInfo = function(url, callback) {
|
||||||
const SC_CLIENT = "2e0c82ab5a020f3a7509318146128abd";
|
const SC_CLIENT = "2e0c82ab5a020f3a7509318146128abd";
|
||||||
// SoundCloud is dumb
|
|
||||||
// I have to request the API URL for the given input URL
|
|
||||||
// Because the sound ID isn"t in the URL
|
|
||||||
getJSON({
|
getJSON({
|
||||||
host: "api.soundcloud.com",
|
host: "api.soundcloud.com",
|
||||||
port: 80,
|
port: 80,
|
||||||
|
@ -254,7 +251,7 @@ exports.getMedia = function(id, type, callback) {
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
Logger.errlog.log("getMedia failed: ");
|
Logger.errlog.log("getMedia failed: ");
|
||||||
Logger.errlog.log(e);
|
Logger.errlog.log(e.stack);
|
||||||
callback(true, null);
|
callback(true, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -329,7 +326,7 @@ exports.getMedia = function(id, type, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
var vids = [];
|
||||||
for(var i = 0; i < data.feed.entry.length; i++) {
|
for(var i = 0; i < data.feed.entry.length; i++) {
|
||||||
try {
|
try {
|
||||||
var item = data.feed.entry[i];
|
var item = data.feed.entry[i];
|
||||||
|
@ -338,13 +335,15 @@ exports.getMedia = function(id, type, callback) {
|
||||||
var title = item.title.$t;
|
var title = item.title.$t;
|
||||||
var seconds = item.media$group.yt$duration.seconds;
|
var seconds = item.media$group.yt$duration.seconds;
|
||||||
var media = new Media(id, title, seconds, "yt");
|
var media = new Media(id, title, seconds, "yt");
|
||||||
callback(false, media);
|
vids.push(media);
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
Logger.errlog.log("getMedia failed: ");
|
Logger.errlog.log("getMedia failed: ");
|
||||||
Logger.errlog.log(e);
|
Logger.errlog.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
callback(false, vids);
|
||||||
|
|
||||||
|
|
||||||
var links = data.feed.link;
|
var links = data.feed.link;
|
||||||
for(var i = 0; i < links.length; i++) {
|
for(var i = 0; i < links.length; i++) {
|
||||||
|
@ -360,6 +359,31 @@ exports.getMedia = function(id, type, callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.getYTPlaylist(id, cback);
|
exports.getYTPlaylist(id, cback);
|
||||||
|
break;
|
||||||
|
case "li":
|
||||||
|
case "tw":
|
||||||
|
case "jt":
|
||||||
|
case "us":
|
||||||
|
case "jw":
|
||||||
|
const prefix = {
|
||||||
|
"li": "Livestream.com - ",
|
||||||
|
"tw": "Twitch.tv - ",
|
||||||
|
"jt": "Justin.tv - ",
|
||||||
|
"us": "Ustream.tv - ",
|
||||||
|
"jw": "JWPlayer Stream - "
|
||||||
|
};
|
||||||
|
var media = new Media(data.id, prefix[data.type] + data.id, "--:--", data.type);
|
||||||
|
callback(false, media);
|
||||||
|
break;
|
||||||
|
case "rt":
|
||||||
|
case "im":
|
||||||
|
const names = {
|
||||||
|
"rt": "Livestream",
|
||||||
|
"im": "Imgur Album"
|
||||||
|
};
|
||||||
|
var media = new Media(data.id, names[data.type], "--:--", data.type);
|
||||||
|
callback(false, media);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
8
media.js
8
media.js
|
@ -51,14 +51,10 @@ var Media = function(id, title, seconds, type) {
|
||||||
this.seconds = 0;
|
this.seconds = 0;
|
||||||
}
|
}
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.queueby = "";
|
|
||||||
this.temp = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Media.prototype.dup = function() {
|
Media.prototype.dup = function() {
|
||||||
var m = new Media(this.id, this.title, this.seconds, this.type);
|
var m = new Media(this.id, this.title, this.seconds, this.type);
|
||||||
m.queueby = this.queueby;
|
|
||||||
m.temp = this.temp;
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +67,6 @@ Media.prototype.pack = function() {
|
||||||
seconds: this.seconds,
|
seconds: this.seconds,
|
||||||
duration: this.duration,
|
duration: this.duration,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
queueby: this.queueby,
|
|
||||||
temp: this.temp
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +81,6 @@ Media.prototype.fullupdate = function() {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
currentTime: this.currentTime,
|
currentTime: this.currentTime,
|
||||||
paused: this.paused,
|
paused: this.paused,
|
||||||
queueby: this.queueby,
|
|
||||||
temp: this.temp
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,461 @@
|
||||||
|
ULList = require("./ullist").ULList;
|
||||||
|
var Media = require("./media").Media;
|
||||||
|
var InfoGetter = require("./get-info");
|
||||||
|
|
||||||
|
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.pack(),
|
||||||
|
uid: this.uid,
|
||||||
|
temp: this.temp,
|
||||||
|
queueby: this.queueby
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Playlist(chan) {
|
||||||
|
this.items = new ULList();
|
||||||
|
this.next_uid = 0;
|
||||||
|
this._leadInterval = false;
|
||||||
|
this._lastUpdate = 0;
|
||||||
|
this._counter = 0;
|
||||||
|
this.leading = true;
|
||||||
|
this.callbacks = {
|
||||||
|
"changeMedia": [],
|
||||||
|
"mediaUpdate": [],
|
||||||
|
"remove": [],
|
||||||
|
};
|
||||||
|
this.lock = false;
|
||||||
|
this.action_queue = [];
|
||||||
|
this._qaInterval = false;
|
||||||
|
|
||||||
|
if(chan) {
|
||||||
|
var pl = this;
|
||||||
|
this.on("mediaUpdate", function(m) {
|
||||||
|
chan.sendAll("mediaUpdate", m.timeupdate());
|
||||||
|
});
|
||||||
|
this.on("changeMedia", function(m) {
|
||||||
|
chan.sendAll("setCurrent", pl.current.uid);
|
||||||
|
chan.sendAll("changeMedia", m.fullupdate());
|
||||||
|
});
|
||||||
|
this.on("remove", function(item) {
|
||||||
|
chan.sendAll("delete", {
|
||||||
|
uid: item.uid
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.queueAction = function(data) {
|
||||||
|
this.action_queue.push(data);
|
||||||
|
if(this._qaInterval)
|
||||||
|
return;
|
||||||
|
var pl = this;
|
||||||
|
this._qaInterval = setInterval(function() {
|
||||||
|
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
|
||||||
|
data.fn();
|
||||||
|
if(pl.action_queue.length == 0) {
|
||||||
|
clearInterval(pl._qaInterval);
|
||||||
|
pl._qaInterval = false;
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.dump = function() {
|
||||||
|
var arr = this.items.toArray();
|
||||||
|
var pos = 0;
|
||||||
|
for(var i in arr) {
|
||||||
|
if(this.current && arr[i].uid == this.current.uid) {
|
||||||
|
pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var time = 0;
|
||||||
|
if(this.current)
|
||||||
|
time = this.current.media.currentTime;
|
||||||
|
|
||||||
|
return {
|
||||||
|
pl: arr,
|
||||||
|
pos: pos,
|
||||||
|
time: time
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.die = function () {
|
||||||
|
this.clear();
|
||||||
|
if(this._leadInterval) {
|
||||||
|
clearInterval(this._leadInterval);
|
||||||
|
this._leadInterval = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
this.items.append(it);
|
||||||
|
if(i == parseInt(data.pos)) {
|
||||||
|
this.current = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(callback)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.add = function(item, pos) {
|
||||||
|
var success;
|
||||||
|
if(pos == "append")
|
||||||
|
success = this.items.append(item);
|
||||||
|
else if(pos == "prepend")
|
||||||
|
success = this.items.prepend(item);
|
||||||
|
else
|
||||||
|
success = this.items.insertAfter(item, pos);
|
||||||
|
|
||||||
|
if(success && this.items.length == 1) {
|
||||||
|
this.current = item;
|
||||||
|
this.startPlayback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
if(pl.add(it, pos))
|
||||||
|
callback(false, it);
|
||||||
|
},
|
||||||
|
waiting: false
|
||||||
|
};
|
||||||
|
this.queueAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.addMedia = function(data, callback) {
|
||||||
|
|
||||||
|
if(data.type == "yp") {
|
||||||
|
this.addYouTubePlaylist(data, callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = "append";
|
||||||
|
if(data.pos == "next") {
|
||||||
|
if(!this.current)
|
||||||
|
pos = "prepend";
|
||||||
|
else
|
||||||
|
pos = this.current.uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = this.makeItem(null);
|
||||||
|
var pl = this;
|
||||||
|
var action = {
|
||||||
|
fn: function() {
|
||||||
|
if(pl.add(it, pos)) {
|
||||||
|
callback(false, it);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
waiting: true
|
||||||
|
};
|
||||||
|
this.queueAction(action);
|
||||||
|
|
||||||
|
InfoGetter.getMedia(data.id, data.type, function(err, media) {
|
||||||
|
if(err) {
|
||||||
|
action.expire = 0;
|
||||||
|
callback(err, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.maxlength && media.seconds > data.maxlength) {
|
||||||
|
action.expire = 0;
|
||||||
|
callback("Media is too long!", null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
it.media = media;
|
||||||
|
it.temp = data.temp;
|
||||||
|
it.queueby = data.queueby;
|
||||||
|
action.waiting = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.addMediaList = function(data, callback) {
|
||||||
|
var start = false;
|
||||||
|
if(data.pos == "next") {
|
||||||
|
data.list = data.list.reverse();
|
||||||
|
start = data.list[data.list.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var pl = this;
|
||||||
|
data.list.forEach(function(x) {
|
||||||
|
x.pos = data.pos;
|
||||||
|
if(start && x == start) {
|
||||||
|
pl.addMedia(x, function (err, item) {
|
||||||
|
if(err) {
|
||||||
|
callback(err, item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(err, item);
|
||||||
|
pl.current = item;
|
||||||
|
pl.startPlayback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pl.addMedia(x, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
InfoGetter.getMedia(data.id, data.type, function(err, vids) {
|
||||||
|
if(err) {
|
||||||
|
callback(err, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vids.forEach(function(media) {
|
||||||
|
var it = pl.makeItem(media);
|
||||||
|
it.temp = data.temp;
|
||||||
|
it.queueby = data.queueby;
|
||||||
|
pl.queueAction({
|
||||||
|
fn: function() {
|
||||||
|
if(pl.add(it, pos))
|
||||||
|
callback(false, it);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.remove = function(uid, callback) {
|
||||||
|
var pl = this;
|
||||||
|
this.queueAction({
|
||||||
|
fn: function() {
|
||||||
|
var item = pl.items.find(uid);
|
||||||
|
if(pl.items.remove(uid)) {
|
||||||
|
if(item == pl.current)
|
||||||
|
pl._next();
|
||||||
|
if(callback)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
waiting: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.move = function(from, after, callback) {
|
||||||
|
var pl = this;
|
||||||
|
this.queueAction({
|
||||||
|
fn: function() {
|
||||||
|
pl._move(from, after, callback);
|
||||||
|
},
|
||||||
|
waiting: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype._move = function(from, after, callback) {
|
||||||
|
var it = this.items.find(from);
|
||||||
|
if(!this.items.remove(from))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(after === "prepend") {
|
||||||
|
if(!this.items.prepend(it))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(after === "append") {
|
||||||
|
if(!this.items.append(it))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(!this.items.insertAfter(it, after))
|
||||||
|
return;
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.next = function() {
|
||||||
|
if(!this.current)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var it = this.current;
|
||||||
|
this._next();
|
||||||
|
|
||||||
|
if(it.temp) {
|
||||||
|
var pl = this;
|
||||||
|
this.remove(it.uid, function() {
|
||||||
|
pl.on("remove")(it);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.current;
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype._next = function() {
|
||||||
|
if(!this.current)
|
||||||
|
return;
|
||||||
|
this.current = this.current.next;
|
||||||
|
if(this.current === null && this.items.first !== null)
|
||||||
|
this.current = this.items.first;
|
||||||
|
|
||||||
|
if(this.current) {
|
||||||
|
this.startPlayback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.jump = function(uid) {
|
||||||
|
if(!this.current)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var jmp = this.items.find(uid);
|
||||||
|
if(!jmp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var it = this.current;
|
||||||
|
|
||||||
|
this.current = jmp;
|
||||||
|
|
||||||
|
if(this.current) {
|
||||||
|
this.startPlayback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(it.temp) {
|
||||||
|
var pl = this;
|
||||||
|
this.remove(it.uid, function () {
|
||||||
|
pl.on("remove")(it);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.current;
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.clear = function() {
|
||||||
|
this.items.clear();
|
||||||
|
this.next_uid = 0;
|
||||||
|
this.current = null;
|
||||||
|
clearInterval(this._leadInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist.prototype.lead = function(lead) {
|
||||||
|
this.leading = lead;
|
||||||
|
var pl = this;
|
||||||
|
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(time) {
|
||||||
|
if(!this.current || !this.current.media)
|
||||||
|
return false;
|
||||||
|
this.current.media.paused = false;
|
||||||
|
this.current.media.currentTime = time || -1;
|
||||||
|
var pl = this;
|
||||||
|
if(this._leadInterval) {
|
||||||
|
clearInterval(this._leadInterval);
|
||||||
|
this._leadInterval = false;
|
||||||
|
}
|
||||||
|
this.on("changeMedia")(this.current.media);
|
||||||
|
if(this.leading && !isLive(this.current.media.type)) {
|
||||||
|
this.on("changeMedia")(this.current.media);
|
||||||
|
this._lastUpdate = Date.now();
|
||||||
|
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
|
||||||
|
|| 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++;
|
||||||
|
|
||||||
|
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;
|
|
@ -185,6 +185,7 @@ exports.unload = function(chan) {
|
||||||
if(chan.registered) {
|
if(chan.registered) {
|
||||||
chan.saveDump();
|
chan.saveDump();
|
||||||
}
|
}
|
||||||
|
chan.playlist.die();
|
||||||
exports.channels[chan.name] = null;
|
exports.channels[chan.name] = null;
|
||||||
delete exports.channels[chan.name];
|
delete exports.channels[chan.name];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
ullist.js
|
||||||
|
|
||||||
|
Description: Defines ULList, which represents a doubly linked list
|
||||||
|
in which each item has a unique identifier stored in the `uid` field.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ULList() {
|
||||||
|
this.first = null;
|
||||||
|
this.last = null;
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an item to the beginning of the list */
|
||||||
|
ULList.prototype.prepend = function(item) {
|
||||||
|
if(this.first !== null) {
|
||||||
|
item.next = this.first;
|
||||||
|
this.first.prev = item;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.last = item;
|
||||||
|
}
|
||||||
|
this.first = item;
|
||||||
|
this.first.prev = null;
|
||||||
|
this.length++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an item to the end of the list */
|
||||||
|
ULList.prototype.append = function(item) {
|
||||||
|
if(this.last !== null) {
|
||||||
|
item.prev = this.last;
|
||||||
|
this.last.next = item;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.first = item;
|
||||||
|
}
|
||||||
|
this.last = item;
|
||||||
|
this.last.next = null;
|
||||||
|
this.length++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert an item after one which has a specified UID */
|
||||||
|
ULList.prototype.insertAfter = function(item, uid) {
|
||||||
|
var after = this.find(uid);
|
||||||
|
|
||||||
|
if(!after)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Update links
|
||||||
|
item.next = after.next;
|
||||||
|
if(item.next)
|
||||||
|
item.next.prev = item;
|
||||||
|
item.prev = after;
|
||||||
|
after.next = item;
|
||||||
|
|
||||||
|
// New end of list
|
||||||
|
if(after == this.last)
|
||||||
|
this.last = item;
|
||||||
|
|
||||||
|
this.length++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert an item before one that has a specified UID */
|
||||||
|
ULList.prototype.insertBefore = function(item, uid) {
|
||||||
|
var before = this.find(uid);
|
||||||
|
|
||||||
|
if(!before)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Update links
|
||||||
|
item.next = before;
|
||||||
|
item.prev = before.prev;
|
||||||
|
if(item.prev)
|
||||||
|
item.prev.next = item;
|
||||||
|
before.prev = item;
|
||||||
|
|
||||||
|
// New beginning of list
|
||||||
|
if(before == this.first)
|
||||||
|
this.first = item;
|
||||||
|
|
||||||
|
this.length++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove an item from the list */
|
||||||
|
ULList.prototype.remove = function(uid) {
|
||||||
|
var item = this.find(uid);
|
||||||
|
if(!item)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Boundary conditions
|
||||||
|
if(item == this.first)
|
||||||
|
this.first = item.next;
|
||||||
|
if(item == this.last)
|
||||||
|
this.last = item.prev;
|
||||||
|
|
||||||
|
// General case
|
||||||
|
if(item.prev)
|
||||||
|
item.prev.next = item.next;
|
||||||
|
if(item.next)
|
||||||
|
item.next.prev = item.prev;
|
||||||
|
|
||||||
|
this.length--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find an element in the list, return false if specified UID not found */
|
||||||
|
ULList.prototype.find = function(uid) {
|
||||||
|
// Can't possibly find it in an empty list
|
||||||
|
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;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear all elements from the list */
|
||||||
|
ULList.prototype.clear = function() {
|
||||||
|
this.first = null;
|
||||||
|
this.last = null;
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump the contents of the list into an array */
|
||||||
|
ULList.prototype.toArray = function(pack) {
|
||||||
|
var arr = new Array(this.length);
|
||||||
|
var item = this.first;
|
||||||
|
var i = 0;
|
||||||
|
while(item !== null) {
|
||||||
|
if(pack !== false && typeof item.pack == "function")
|
||||||
|
arr[i++] = item.pack();
|
||||||
|
else
|
||||||
|
arr[i++] = item;
|
||||||
|
item = item.next;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.ULList = ULList;
|
46
update.js
46
update.js
|
@ -1,21 +1,61 @@
|
||||||
var Config = require("./config.js");
|
var Config = require("./config.js");
|
||||||
var Database = require("./database.js");
|
var Database = require("./database.js");
|
||||||
|
|
||||||
Config.DEBUG = true;
|
//Config.DEBUG = true;
|
||||||
Database.setup(Config);
|
Database.setup(Config);
|
||||||
Database.init();
|
Database.init();
|
||||||
var query;
|
var query;
|
||||||
var db = Database.getConnection();
|
var db = Database.getConnection();
|
||||||
|
|
||||||
// Check for already existing
|
// Check for already existing
|
||||||
query = "SELECT email FROM registrations WHERE 1";
|
query = "SELECT owner FROM channels WHERE 1";
|
||||||
if(!db.querySync(query)) {
|
if(!db.querySync(query)) {
|
||||||
query = "ALTER TABLE registrations ADD email VARCHAR(255) NOT NULL";
|
query = "ALTER TABLE channels ADD owner VARCHAR(20) NOT NULL";
|
||||||
var res = db.querySync(query);
|
var res = db.querySync(query);
|
||||||
if(!res) {
|
if(!res) {
|
||||||
console.log(db);
|
console.log(db);
|
||||||
console.log("Update failed!");
|
console.log("Update failed!");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
populateChannelOwners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
db.closeSync();
|
db.closeSync();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
||||||
|
function populateChannelOwners() {
|
||||||
|
query = "SELECT * FROM channels WHERE 1";
|
||||||
|
var res = db.querySync(query);
|
||||||
|
if(!res) {
|
||||||
|
console.log(db);
|
||||||
|
console.log("Update failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var channels = res.fetchAllSync();
|
||||||
|
channels.forEach(function(chan) {
|
||||||
|
chan = chan.name;
|
||||||
|
query = "SELECT name FROM `chan_"+chan+"_ranks` WHERE rank>=10 ORDER BY rank";
|
||||||
|
res = db.querySync(query);
|
||||||
|
if(!res) {
|
||||||
|
console.log(db);
|
||||||
|
console.log("failed to fix "+chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = res.fetchAllSync();
|
||||||
|
if(results.length == 0) {
|
||||||
|
console.log("bad channel: " + chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var owner = results[0].name;
|
||||||
|
query = "UPDATE channels SET owner='"+owner+"' WHERE name='"+chan+"'";
|
||||||
|
console.log("setting owner=" + owner + " for /r/" + chan);
|
||||||
|
res = db.querySync(query);
|
||||||
|
if(!res) {
|
||||||
|
console.log(db);
|
||||||
|
console.log("Update failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
2
user.js
2
user.js
|
@ -484,7 +484,7 @@ User.prototype.initCallbacks = function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pl = this.channel.queue;
|
var pl = this.channel.playlist.items.toArray();
|
||||||
var result = Database.saveUserPlaylist(pl, this.name, data.name);
|
var result = Database.saveUserPlaylist(pl, this.name, data.name);
|
||||||
this.socket.emit("savePlaylist", {
|
this.socket.emit("savePlaylist", {
|
||||||
success: result,
|
success: result,
|
||||||
|
|
|
@ -650,25 +650,35 @@ Callbacks = {
|
||||||
},
|
},
|
||||||
|
|
||||||
queue: function(data) {
|
queue: function(data) {
|
||||||
// Wait until pending movements are completed
|
queueAction({
|
||||||
if(PL_MOVING || PL_ADDING || PL_DELETING) {
|
fn: function () {
|
||||||
setTimeout(function() {
|
var li = makeQueueEntry(data.item, true);
|
||||||
Callbacks.queue(data);
|
li.hide();
|
||||||
}, 100);
|
var q = $("#queue");
|
||||||
return;
|
li.attr("title", data.item.queueby
|
||||||
}
|
? ("Added by: " + data.item.queueby)
|
||||||
var li = makeQueueEntry(data.media, true);
|
: "Added by: Unknown");
|
||||||
li.hide();
|
if(data.after === "prepend") {
|
||||||
var idx = data.pos;
|
li.prependTo(q);
|
||||||
var q = $("#queue");
|
li.show("blind");
|
||||||
li.attr("title", data.media.queueby
|
return true;
|
||||||
? ("Added by: " + data.media.queueby)
|
}
|
||||||
: "Added by: Unknown");
|
else if(data.after === "append") {
|
||||||
if(idx < q.children().length - 1)
|
li.appendTo(q);
|
||||||
li.insertBefore(q.children()[idx])
|
li.show("blind");
|
||||||
else
|
return true;
|
||||||
li.appendTo(q);
|
}
|
||||||
li.show("blind");
|
else {
|
||||||
|
var liafter = playlistFind(data.after);
|
||||||
|
if(!liafter) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
li.insertAfter(liafter);
|
||||||
|
li.show("blind");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
queueFail: function(data) {
|
queueFail: function(data) {
|
||||||
|
@ -681,89 +691,77 @@ Callbacks = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setTemp: function(data) {
|
setTemp: function(data) {
|
||||||
var li = $("#queue").children()[data.position];
|
var li = $(".pluid-" + data.uid);
|
||||||
li = $(li);
|
if(li.length == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(data.temp)
|
if(data.temp)
|
||||||
li.addClass("queue_temp");
|
li.addClass("queue_temp");
|
||||||
else
|
else
|
||||||
li.removeClass("queue_temp");
|
li.removeClass("queue_temp");
|
||||||
|
|
||||||
var btn = li.find(".qbtn-tmp");
|
var btn = li.find(".qbtn-tmp");
|
||||||
btn.data("temp", data.temp);
|
if(btn.length > 0) {
|
||||||
if(data.temp) {
|
btn.data("temp", data.temp);
|
||||||
btn.html(btn.html().replace("Make Temporary",
|
if(data.temp) {
|
||||||
"Make Permanent"));
|
btn.html(btn.html().replace("Make Temporary",
|
||||||
}
|
"Make Permanent"));
|
||||||
else {
|
}
|
||||||
btn.html(btn.html().replace("Make Permanent",
|
else {
|
||||||
"Make Temporary"));
|
btn.html(btn.html().replace("Make Permanent",
|
||||||
|
"Make Temporary"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"delete": function(data) {
|
"delete": function(data) {
|
||||||
// Wait until any pending manipulation is finished
|
queueAction({
|
||||||
if(PL_MOVING || PL_ADDING || PL_DELETING) {
|
fn: function () {
|
||||||
setTimeout(function() {
|
var li = $(".pluid-" + data.uid);
|
||||||
Callbacks["delete"](data);
|
li.hide("blind", function() {
|
||||||
}, 100);
|
li.remove();
|
||||||
return;
|
});
|
||||||
}
|
return true;
|
||||||
var li = $("#queue").children()[data.position];
|
}
|
||||||
$(li).remove();
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
moveVideo: function(data) {
|
moveVideo: function(data) {
|
||||||
// Wait until any pending manipulation is finished
|
if(data.moveby != CLIENT.name) {
|
||||||
if(PL_MOVING || PL_ADDING || PL_DELETING) {
|
queueAction({
|
||||||
setTimeout(function() {
|
fn: function () {
|
||||||
Callbacks.moveVideo(position);
|
playlistMove(data.from, data.after);
|
||||||
}, 100);
|
return true;
|
||||||
return;
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if(data.from < POSITION && data.to >= POSITION)
|
|
||||||
POSITION--;
|
|
||||||
else if(data.from > POSITION && data.to <= POSITION)
|
|
||||||
POSITION++;
|
|
||||||
else if(data.from == POSITION)
|
|
||||||
POSITION = data.to;
|
|
||||||
if(data.moveby != CLIENT.name)
|
|
||||||
playlistMove(data.from, data.to);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setPosition: function(position) {
|
setCurrent: function(uid) {
|
||||||
// Wait until any pending manipulation is finished
|
queueAction({
|
||||||
if(PL_MOVING || PL_ADDING || PL_DELETING) {
|
fn: function () {
|
||||||
setTimeout(function() {
|
PL_CURRENT = uid;
|
||||||
Callbacks.setPosition(position);
|
var qli = $("#queue li");
|
||||||
}, 100);
|
qli.removeClass("queue_active");
|
||||||
return;
|
var li = $(".pluid-" + uid);
|
||||||
}
|
if(li.length == 0) {
|
||||||
$("#queue li").each(function() {
|
return false;
|
||||||
$(this).removeClass("queue_active");
|
}
|
||||||
|
|
||||||
|
li.addClass("queue_active");
|
||||||
|
scrollQueue();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
can_wait: true
|
||||||
});
|
});
|
||||||
if(position < 0)
|
|
||||||
return;
|
|
||||||
POSITION = position;
|
|
||||||
var linew = $("#queue").children()[POSITION];
|
|
||||||
// jQuery UI's sortable thingy kinda fucks this up initially
|
|
||||||
// Wait until it's done
|
|
||||||
if(!$(linew).hasClass("queue_entry")) {
|
|
||||||
setTimeout(function() {
|
|
||||||
Callbacks.setPosition(position);
|
|
||||||
}, 100);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$(linew).addClass("queue_active");
|
|
||||||
|
|
||||||
$("#queue").scrollTop(0);
|
|
||||||
var scroll = $(linew).position().top - $("#queue").position().top;
|
|
||||||
$("#queue").scrollTop(scroll);
|
|
||||||
|
|
||||||
if(CHANNEL.opts.allow_voteskip)
|
|
||||||
$("#voteskip").attr("disabled", false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
changeMedia: function(data) {
|
changeMedia: function(data) {
|
||||||
|
if(CHANNEL.opts.allow_voteskip)
|
||||||
|
$("#voteskip").attr("disabled", false);
|
||||||
|
|
||||||
$("#currenttitle").text("Currently Playing: " + data.title);
|
$("#currenttitle").text("Currently Playing: " + data.title);
|
||||||
|
|
||||||
if(data.type != "sc" && PLAYER.type == "sc")
|
if(data.type != "sc" && PLAYER.type == "sc")
|
||||||
// [](/goddamnitmango)
|
// [](/goddamnitmango)
|
||||||
fixSoundcloudShit();
|
fixSoundcloudShit();
|
||||||
|
@ -859,7 +857,6 @@ Callbacks = {
|
||||||
for(var i = 0; i < data.options.length; i++) {
|
for(var i = 0; i < data.options.length; i++) {
|
||||||
(function(i) {
|
(function(i) {
|
||||||
var callback = function() {
|
var callback = function() {
|
||||||
console.log("vote", i);
|
|
||||||
socket.emit("vote", {
|
socket.emit("vote", {
|
||||||
option: i
|
option: i
|
||||||
});
|
});
|
||||||
|
@ -990,11 +987,14 @@ Callbacks = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var SOCKET_DEBUG = true;
|
||||||
setupCallbacks = function() {
|
setupCallbacks = function() {
|
||||||
console.log(socket);
|
|
||||||
for(var key in Callbacks) {
|
for(var key in Callbacks) {
|
||||||
(function(key) {
|
(function(key) {
|
||||||
socket.on(key, function(data) {
|
socket.on(key, function(data) {
|
||||||
|
if(SOCKET_DEBUG)
|
||||||
|
console.log(key, data);
|
||||||
Callbacks[key](data);
|
Callbacks[key](data);
|
||||||
});
|
});
|
||||||
})(key);
|
})(key);
|
||||||
|
|
|
@ -49,9 +49,21 @@
|
||||||
genPermissionsEditor();
|
genPermissionsEditor();
|
||||||
|
|
||||||
$("#chanopts_submit").click(function() {
|
$("#chanopts_submit").click(function() {
|
||||||
|
var hms = $("#opt_maxlength").val().split(":");
|
||||||
|
var len = 0;
|
||||||
|
if(hms.length == 3) {
|
||||||
|
len = parseInt(hms[0]) * 3600 + parseInt(hms[1]) * 60 + parseInt(hms[2]);
|
||||||
|
}
|
||||||
|
else if(hms.length == 2) {
|
||||||
|
len = parseInt(hms[0]) * 60 + parseInt(hms[1]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = parseInt(hms[0]);
|
||||||
|
}
|
||||||
socket.emit("setOptions", {
|
socket.emit("setOptions", {
|
||||||
allow_voteskip: $("#opt_allow_voteskip").prop("checked"),
|
allow_voteskip: $("#opt_allow_voteskip").prop("checked"),
|
||||||
voteskip_ratio: parseFloat($("#opt_voteskip_ratio").val()),
|
voteskip_ratio: parseFloat($("#opt_voteskip_ratio").val()),
|
||||||
|
maxlength: len,
|
||||||
pagetitle: $("#opt_pagetitle").val() || CHANNEL.name,
|
pagetitle: $("#opt_pagetitle").val() || CHANNEL.name,
|
||||||
externalcss: $("#opt_externalcss").val(),
|
externalcss: $("#opt_externalcss").val(),
|
||||||
externaljs: $("#opt_externaljs").val(),
|
externaljs: $("#opt_externaljs").val(),
|
||||||
|
|
|
@ -40,7 +40,7 @@ if($("#ytapiplayer").length > 0) {
|
||||||
var VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
var VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
||||||
var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
||||||
}
|
}
|
||||||
var POSITION = -1;
|
var MEDIA = { hash: "" };
|
||||||
var PL_MOVING = false;
|
var PL_MOVING = false;
|
||||||
var PL_ADDING = false;
|
var PL_ADDING = false;
|
||||||
var PL_DELETING = false;
|
var PL_DELETING = false;
|
||||||
|
@ -64,8 +64,8 @@ var KICKED = false;
|
||||||
var NAME = readCookie("cytube_uname");
|
var NAME = readCookie("cytube_uname");
|
||||||
var SESSION = readCookie("cytube_session");
|
var SESSION = readCookie("cytube_session");
|
||||||
var LEADTMR = false;
|
var LEADTMR = false;
|
||||||
var PL_FROM = 0;
|
var PL_FROM = "";
|
||||||
var PL_TO = 0;
|
var PL_AFTER = "";
|
||||||
var FILTER_FROM = 0;
|
var FILTER_FROM = 0;
|
||||||
var FILTER_TO = 0;
|
var FILTER_TO = 0;
|
||||||
var NO_STORAGE = typeof localStorage == "undefined" || localStorage === null;
|
var NO_STORAGE = typeof localStorage == "undefined" || localStorage === null;
|
||||||
|
|
|
@ -211,16 +211,18 @@ $("#mediarefresh").click(function() {
|
||||||
|
|
||||||
$("#queue").sortable({
|
$("#queue").sortable({
|
||||||
start: function(ev, ui) {
|
start: function(ev, ui) {
|
||||||
PL_FROM = ui.item.prevAll().length;
|
PL_FROM = ui.item.data("uid");
|
||||||
},
|
},
|
||||||
update: function(ev, ui) {
|
update: function(ev, ui) {
|
||||||
PL_TO = ui.item.prevAll().length;
|
var prev = ui.item.prevAll();
|
||||||
if(PL_TO != PL_FROM) {
|
if(prev.length == 0)
|
||||||
socket.emit("moveMedia", {
|
PL_AFTER = "prepend";
|
||||||
from: PL_FROM,
|
else
|
||||||
to: PL_TO
|
PL_AFTER = $(prev[0]).data("uid");
|
||||||
});
|
socket.emit("moveMedia", {
|
||||||
}
|
from: PL_FROM,
|
||||||
|
after: PL_AFTER
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#queue").disableSelection();
|
$("#queue").disableSelection();
|
||||||
|
@ -337,12 +339,14 @@ $("#shuffleplaylist").click(function() {
|
||||||
|
|
||||||
/* layout stuff */
|
/* layout stuff */
|
||||||
$(window).resize(function() {
|
$(window).resize(function() {
|
||||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
VWIDTH = $("#queue").css("width").replace("px", "");
|
||||||
var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
||||||
$("#messagebuffer").css("height", (VHEIGHT - 31) + "px");
|
$("#messagebuffer").css("height", (VHEIGHT - 31) + "px");
|
||||||
$("#userlist").css("height", (VHEIGHT - 31) + "px");
|
$("#userlist").css("height", (VHEIGHT - 31) + "px");
|
||||||
$("#ytapiplayer").attr("width", VWIDTH);
|
if($("#ytapiplayer").length > 0) {
|
||||||
$("#ytapiplayer").attr("height", VHEIGHT);
|
$("#ytapiplayer").attr("width", VWIDTH);
|
||||||
|
$("#ytapiplayer").attr("height", VHEIGHT);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,48 @@ function addUserDropdown(entry, name) {
|
||||||
|
|
||||||
/* queue stuff */
|
/* queue stuff */
|
||||||
|
|
||||||
function makeQueueEntry(video, addbtns) {
|
function scrollQueue() {
|
||||||
|
var li = playlistFind(PL_CURRENT);
|
||||||
|
if(!li)
|
||||||
|
return;
|
||||||
|
|
||||||
|
li = $(li);
|
||||||
|
$("#queue").scrollTop(0);
|
||||||
|
var scroll = li.position().top - $("#queue").position().top;
|
||||||
|
$("#queue").scrollTop(scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeQueueEntry(item, addbtns) {
|
||||||
|
var video = item.media;
|
||||||
|
var li = $("<li/>");
|
||||||
|
li.addClass("queue_entry");
|
||||||
|
li.addClass("pluid-" + item.uid);
|
||||||
|
li.data("uid", item.uid);
|
||||||
|
li.data("media", video);
|
||||||
|
li.data("temp", item.temp);
|
||||||
|
if(video.thumb) {
|
||||||
|
$("<img/>").attr("src", video.thumb.url)
|
||||||
|
.css("float", "left")
|
||||||
|
.css("clear", "both")
|
||||||
|
.appendTo(li);
|
||||||
|
}
|
||||||
|
var title = $("<a/>").addClass("qe_title").appendTo(li)
|
||||||
|
.text(video.title)
|
||||||
|
.attr("href", formatURL(video))
|
||||||
|
.attr("target", "_blank");
|
||||||
|
var time = $("<span/>").addClass("qe_time").appendTo(li);
|
||||||
|
time.text(video.duration);
|
||||||
|
var clear = $("<div/>").addClass("qe_clear").appendTo(li);
|
||||||
|
if(item.temp) {
|
||||||
|
li.addClass("queue_temp");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addbtns)
|
||||||
|
addQueueButtons(li);
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSearchEntry(video) {
|
||||||
var li = $("<li/>");
|
var li = $("<li/>");
|
||||||
li.addClass("queue_entry");
|
li.addClass("queue_entry");
|
||||||
li.data("media", video);
|
li.data("media", video);
|
||||||
|
@ -221,12 +262,7 @@ function makeQueueEntry(video, addbtns) {
|
||||||
var time = $("<span/>").addClass("qe_time").appendTo(li);
|
var time = $("<span/>").addClass("qe_time").appendTo(li);
|
||||||
time.text(video.duration);
|
time.text(video.duration);
|
||||||
var clear = $("<div/>").addClass("qe_clear").appendTo(li);
|
var clear = $("<div/>").addClass("qe_clear").appendTo(li);
|
||||||
if(video.temp) {
|
|
||||||
li.addClass("queue_temp");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addbtns)
|
|
||||||
addQueueButtons(li);
|
|
||||||
return li;
|
return li;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,8 +274,7 @@ function addQueueButtons(li) {
|
||||||
$("<button/>").addClass("btn btn-mini qbtn-play")
|
$("<button/>").addClass("btn btn-mini qbtn-play")
|
||||||
.html("<i class='icon-play'></i>Play")
|
.html("<i class='icon-play'></i>Play")
|
||||||
.click(function() {
|
.click(function() {
|
||||||
var i = $("#queue").children().index(li);
|
socket.emit("jumpTo", li.data("uid"));
|
||||||
socket.emit("jumpTo", i);
|
|
||||||
})
|
})
|
||||||
.appendTo(menu);
|
.appendTo(menu);
|
||||||
}
|
}
|
||||||
|
@ -248,10 +283,9 @@ function addQueueButtons(li) {
|
||||||
$("<button/>").addClass("btn btn-mini qbtn-next")
|
$("<button/>").addClass("btn btn-mini qbtn-next")
|
||||||
.html("<i class='icon-share-alt'></i>Queue Next")
|
.html("<i class='icon-share-alt'></i>Queue Next")
|
||||||
.click(function() {
|
.click(function() {
|
||||||
var i = $("#queue").children().index(li);
|
|
||||||
socket.emit("moveMedia", {
|
socket.emit("moveMedia", {
|
||||||
from: i,
|
from: li.data("uid"),
|
||||||
to: i < POSITION ? POSITION : POSITION + 1,
|
after: PL_CURRENT,
|
||||||
moveby: null
|
moveby: null
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -259,14 +293,13 @@ function addQueueButtons(li) {
|
||||||
}
|
}
|
||||||
// Temp/Untemp
|
// Temp/Untemp
|
||||||
if(hasPermission("settemp")) {
|
if(hasPermission("settemp")) {
|
||||||
var tempstr = li.data("media").temp?"Make Permanent":"Make Temporary";
|
var tempstr = li.data("temp")?"Make Permanent":"Make Temporary";
|
||||||
$("<button/>").addClass("btn btn-mini qbtn-tmp")
|
$("<button/>").addClass("btn btn-mini qbtn-tmp")
|
||||||
.html("<i class='icon-flag'></i>" + tempstr)
|
.html("<i class='icon-flag'></i>" + tempstr)
|
||||||
.click(function() {
|
.click(function() {
|
||||||
var i = $("#queue").children().index(li);
|
|
||||||
var temp = li.find(".qbtn-tmp").data("temp");
|
var temp = li.find(".qbtn-tmp").data("temp");
|
||||||
socket.emit("setTemp", {
|
socket.emit("setTemp", {
|
||||||
position: i,
|
uid: li.data("uid"),
|
||||||
temp: !temp
|
temp: !temp
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -277,8 +310,7 @@ function addQueueButtons(li) {
|
||||||
$("<button/>").addClass("btn btn-mini qbtn-delete")
|
$("<button/>").addClass("btn btn-mini qbtn-delete")
|
||||||
.html("<i class='icon-trash'></i>Delete")
|
.html("<i class='icon-trash'></i>Delete")
|
||||||
.click(function() {
|
.click(function() {
|
||||||
var i = $("#queue").children().index(li);
|
socket.emit("delete", li.data("uid"));
|
||||||
socket.emit("delete", i);
|
|
||||||
})
|
})
|
||||||
.appendTo(menu);
|
.appendTo(menu);
|
||||||
}
|
}
|
||||||
|
@ -542,7 +574,10 @@ function applyOpts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(USEROPTS.hidevid) {
|
if(USEROPTS.hidevid) {
|
||||||
|
$("#qualitywrap").html("");
|
||||||
$("#videowrap").remove();
|
$("#videowrap").remove();
|
||||||
|
$("#chatwrap").removeClass("span5").addClass("span12");
|
||||||
|
$("#chatline").removeClass().addClass("span12");
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#chatbtn").remove();
|
$("#chatbtn").remove();
|
||||||
|
@ -765,6 +800,22 @@ function handleModPermissions() {
|
||||||
$("#opt_enable_link_regex").prop("checked", CHANNEL.opts.enable_link_regex);
|
$("#opt_enable_link_regex").prop("checked", CHANNEL.opts.enable_link_regex);
|
||||||
$("#opt_allow_voteskip").prop("checked", CHANNEL.opts.allow_voteskip);
|
$("#opt_allow_voteskip").prop("checked", CHANNEL.opts.allow_voteskip);
|
||||||
$("#opt_voteskip_ratio").val(CHANNEL.opts.voteskip_ratio);
|
$("#opt_voteskip_ratio").val(CHANNEL.opts.voteskip_ratio);
|
||||||
|
(function() {
|
||||||
|
if(typeof CHANNEL.opts.maxlength != "number") {
|
||||||
|
$("#opt_maxlength").val("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var h = parseInt(CHANNEL.opts.maxlength / 3600);
|
||||||
|
h = ""+h;
|
||||||
|
if(h.length < 2) h = "0" + h;
|
||||||
|
var m = parseInt((CHANNEL.opts.maxlength % 3600) / 60);
|
||||||
|
m = ""+m;
|
||||||
|
if(m.length < 2) m = "0" + m;
|
||||||
|
var s = parseInt(CHANNEL.opts.maxlength % 60);
|
||||||
|
s = ""+s;
|
||||||
|
if(s.length < 2) s = "0" + s;
|
||||||
|
$("#opt_maxlength").val(h + ":" + m + ":" + s);
|
||||||
|
})();
|
||||||
$("#csstext").val(CHANNEL.css);
|
$("#csstext").val(CHANNEL.css);
|
||||||
$("#jstext").val(CHANNEL.js);
|
$("#jstext").val(CHANNEL.js);
|
||||||
$("#motdtext").val(CHANNEL.motd_text);
|
$("#motdtext").val(CHANNEL.motd_text);
|
||||||
|
@ -882,7 +933,7 @@ function loadSearchPage(page) {
|
||||||
var results = $("#library").data("entries");
|
var results = $("#library").data("entries");
|
||||||
var start = page * 100;
|
var start = page * 100;
|
||||||
for(var i = start; i < start + 100 && i < results.length; i++) {
|
for(var i = start; i < start + 100 && i < results.length; i++) {
|
||||||
var li = makeQueueEntry(results[i], false);
|
var li = makeSearchEntry(results[i], false);
|
||||||
if(hasPermission("playlistadd")) {
|
if(hasPermission("playlistadd")) {
|
||||||
if(results[i].thumb) {
|
if(results[i].thumb) {
|
||||||
addLibraryButtons(li, results[i].id, "yt");
|
addLibraryButtons(li, results[i].id, "yt");
|
||||||
|
@ -947,24 +998,73 @@ function addLibraryButtons(li, id, type) {
|
||||||
|
|
||||||
/* queue stuff */
|
/* queue stuff */
|
||||||
|
|
||||||
function playlistMove(from, to) {
|
var PL_QUEUED_ACTIONS = [];
|
||||||
if(from < 0 || to < 0)
|
var PL_ACTION_INTERVAL = false;
|
||||||
return false;
|
|
||||||
var q = $("#queue");
|
function queueAction(data) {
|
||||||
if(from >= q.children().length)
|
PL_QUEUED_ACTIONS.push(data);
|
||||||
|
if(PL_ACTION_INTERVAL)
|
||||||
|
return;
|
||||||
|
PL_ACTION_INTERVAL = setInterval(function () {
|
||||||
|
var data = PL_QUEUED_ACTIONS.shift();
|
||||||
|
if(!("expire" in data))
|
||||||
|
data.expire = Date.now() + 5000;
|
||||||
|
if(!data.fn()) {
|
||||||
|
if(data.can_wait && Date.now() < data.expire)
|
||||||
|
PL_QUEUED_ACTIONS.push(data);
|
||||||
|
else if(Date.now() < data.expire)
|
||||||
|
PL_QUEUED_ACTIONS.unshift(data);
|
||||||
|
}
|
||||||
|
if(PL_QUEUED_ACTIONS.length == 0) {
|
||||||
|
clearInterval(PL_ACTION_INTERVAL);
|
||||||
|
PL_ACTION_INTERVAL = false;
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because jQuery UI does weird things
|
||||||
|
function playlistFind(uid) {
|
||||||
|
var children = document.getElementById("queue").children;
|
||||||
|
for(var i in children) {
|
||||||
|
if(typeof children[i].getAttribute != "function")
|
||||||
|
continue;
|
||||||
|
if(children[i].getAttribute("class").indexOf("pluid-" + uid) != -1)
|
||||||
|
return children[i];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function playlistMove(from, after) {
|
||||||
|
var lifrom = $(".pluid-" + from);
|
||||||
|
if(lifrom.length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MOVING = true;
|
var q = $("#queue");
|
||||||
var old = $(q.children()[from]);
|
|
||||||
old.hide("blind", function() {
|
if(after === "prepend") {
|
||||||
old.detach();
|
lifrom.hide("blind", function() {
|
||||||
if(to >= q.children().length)
|
lifrom.detach();
|
||||||
old.appendTo(q);
|
lifrom.prependTo(q);
|
||||||
else
|
lifrom.show("blind");
|
||||||
old.insertBefore(q.children()[to]);
|
});
|
||||||
old.show("blind");
|
}
|
||||||
MOVING = false;
|
else if(after === "append") {
|
||||||
});
|
lifrom.hide("blind", function() {
|
||||||
|
lifrom.detach();
|
||||||
|
lifrom.appendTo(q);
|
||||||
|
lifrom.show("blind");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var liafter = $(".pluid-" + after);
|
||||||
|
if(liafter.length == 0)
|
||||||
|
return false;
|
||||||
|
lifrom.hide("blind", function() {
|
||||||
|
lifrom.detach();
|
||||||
|
lifrom.insertAfter(liafter);
|
||||||
|
lifrom.show("blind");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseMediaLink(url) {
|
function parseMediaLink(url) {
|
||||||
|
@ -1201,12 +1301,15 @@ function fluidLayout() {
|
||||||
$(".container").each(function() {
|
$(".container").each(function() {
|
||||||
$(this).removeClass("container").addClass("container-fluid");
|
$(this).removeClass("container").addClass("container-fluid");
|
||||||
});
|
});
|
||||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
// Video might not be there, but the playlist is
|
||||||
|
VWIDTH = $("#queue").css("width").replace("px", "");
|
||||||
VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
||||||
|
if($("#ytapiplayer").length > 0) {
|
||||||
|
$("#ytapiplayer").attr("width", VWIDTH);
|
||||||
|
$("#ytapiplayer").attr("height", VHEIGHT);
|
||||||
|
}
|
||||||
$("#messagebuffer").css("height", (VHEIGHT - 31) + "px");
|
$("#messagebuffer").css("height", (VHEIGHT - 31) + "px");
|
||||||
$("#userlist").css("height", (VHEIGHT - 31) + "px");
|
$("#userlist").css("height", (VHEIGHT - 31) + "px");
|
||||||
$("#ytapiplayer").attr("width", VWIDTH);
|
|
||||||
$("#ytapiplayer").attr("height", VHEIGHT);
|
|
||||||
$("#chatline").removeClass().addClass("span12");
|
$("#chatline").removeClass().addClass("span12");
|
||||||
$("#channelsettingswrap3").css("margin-left", "0");
|
$("#channelsettingswrap3").css("margin-left", "0");
|
||||||
}
|
}
|
||||||
|
@ -1301,6 +1404,7 @@ function genPermissionsEditor() {
|
||||||
makeOption("Jump to video", "playlistjump", standard, CHANNEL.perms.playlistjump+"");
|
makeOption("Jump to video", "playlistjump", standard, CHANNEL.perms.playlistjump+"");
|
||||||
makeOption("Queue playlist", "playlistaddlist", standard, CHANNEL.perms.playlistaddlist+"");
|
makeOption("Queue playlist", "playlistaddlist", standard, CHANNEL.perms.playlistaddlist+"");
|
||||||
makeOption("Queue livestream", "playlistaddlive", standard, CHANNEL.perms.playlistaddlive+"");
|
makeOption("Queue livestream", "playlistaddlive", standard, CHANNEL.perms.playlistaddlive+"");
|
||||||
|
makeOption("Exceed maximum media length", "exceedmaxlength", standard, CHANNEL.perms.exceedmaxlength+"");
|
||||||
makeOption("Add nontemporary media", "addnontemp", standard, CHANNEL.perms.addnontemp+"");
|
makeOption("Add nontemporary media", "addnontemp", standard, CHANNEL.perms.addnontemp+"");
|
||||||
makeOption("Temp/untemp playlist item", "settemp", standard, CHANNEL.perms.settemp+"");
|
makeOption("Temp/untemp playlist item", "settemp", standard, CHANNEL.perms.settemp+"");
|
||||||
makeOption("Shuffle playlist", "playlistshuffle", standard, CHANNEL.perms.playlistshuffle+"");
|
makeOption("Shuffle playlist", "playlistshuffle", standard, CHANNEL.perms.playlistshuffle+"");
|
||||||
|
|
|
@ -49,6 +49,13 @@
|
||||||
<input type="text" id="opt_voteskip_ratio" placeholder="0.5">
|
<input type="text" id="opt_voteskip_ratio" placeholder="0.5">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- max video length -->
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="opt_maxlength">Maximum Video Length</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="opt_maxlength" placeholder="HH:MM:SS">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<strong>Admin-Only Controls</strong>
|
<strong>Admin-Only Controls</strong>
|
||||||
<!-- page title -->
|
<!-- page title -->
|
||||||
|
|
Loading…
Reference in New Issue