mirror of https://github.com/calzoneman/sync.git
1230 lines
38 KiB
JavaScript
1230 lines
38 KiB
JavaScript
function makeAlert(title, text, klass) {
|
|
if(!klass) {
|
|
klass = "alert-info";
|
|
}
|
|
|
|
var al = $("<div/>").addClass("alert")
|
|
.addClass(klass)
|
|
.text(text);
|
|
$("<br/>").prependTo(al);
|
|
$("<strong/>").text(title).prependTo(al);
|
|
$("<button/>").addClass("close pull-right").html("×")
|
|
.click(function() {
|
|
al.hide("blind", function() {
|
|
al.remove();
|
|
});
|
|
})
|
|
.prependTo(al);
|
|
return al;
|
|
}
|
|
|
|
function formatURL(data) {
|
|
switch(data.type) {
|
|
case "yt":
|
|
return "http://youtube.com/watch?v=" + data.id;
|
|
case "vi":
|
|
return "http://vimeo.com/" + data.id;
|
|
case "dm":
|
|
return "http://dailymotion.com/video/" + data.id;
|
|
case "sc":
|
|
return data.id;
|
|
case "li":
|
|
return "http://livestream.com/" + data.id;
|
|
case "tw":
|
|
return "http://twitch.tv/" + data.id;
|
|
case "jt":
|
|
return "http://justin.tv/" + data.id;
|
|
case "rt":
|
|
return data.id;
|
|
case "jw":
|
|
return data.id;
|
|
case "im":
|
|
return "http://imgur.com/a/" + data.id;
|
|
case "us":
|
|
return "http://ustream.tv/" + data.id;
|
|
default:
|
|
return "#";
|
|
}
|
|
}
|
|
|
|
function formatUserlistItem(div, data) {
|
|
var name = $(div.children()[1]);
|
|
name.removeClass();
|
|
name.css("font-style", "");
|
|
name.addClass(getNameColor(data.rank));
|
|
div.find(".profile-box").remove();
|
|
|
|
// TODO might remove this
|
|
var profile;
|
|
name.mouseenter(function(ev) {
|
|
profile = $("<div/>")
|
|
.addClass("profile-box")
|
|
.css("top", (ev.pageY + 5) + "px")
|
|
.css("left", ev.pageX + "px")
|
|
.appendTo(div);
|
|
if(data.profile.image) {
|
|
$("<img/>").addClass("profile-image")
|
|
.attr("src", data.profile.image)
|
|
.appendTo(profile);
|
|
}
|
|
$("<strong/>").text(data.name).appendTo(profile);
|
|
$("<p/>").text(data.profile.text).appendTo(profile);
|
|
});
|
|
name.mousemove(function(ev) {
|
|
profile.css("top", (ev.pageY + 5) + "px")
|
|
.css("left", ev.pageX + "px")
|
|
});
|
|
name.mouseleave(function() {
|
|
profile.remove();
|
|
});
|
|
|
|
var flair = div.children()[0];
|
|
flair.innerHTML = "";
|
|
// denote current leader with a star
|
|
if(data.leader) {
|
|
$("<i/>").addClass("icon-star-empty").appendTo(flair);
|
|
}
|
|
if(data.meta && data.meta.afk) {
|
|
name.css("font-style", "italic");
|
|
$("<i/>").addClass("icon-time").appendTo(flair);
|
|
}
|
|
}
|
|
|
|
function getNameColor(rank) {
|
|
if(rank >= Rank.Siteadmin)
|
|
return "userlist_siteadmin";
|
|
else if(rank >= Rank.Admin)
|
|
return "userlist_owner";
|
|
else if(rank >= Rank.Moderator)
|
|
return "userlist_op";
|
|
else if(rank == Rank.Guest)
|
|
return "userlist_guest";
|
|
else
|
|
return "";
|
|
}
|
|
|
|
function addUserDropdown(entry, name) {
|
|
entry.find(".user-dropdown").remove();
|
|
var menu = $("<div/>").addClass("user-dropdown")
|
|
.appendTo(entry);
|
|
menu.hide();
|
|
|
|
$("<strong/>").text(name).appendTo(menu);
|
|
$("<br/>").appendTo(menu);
|
|
if(CLIENT.rank >= 2)
|
|
$("<span/>").addClass("user-aliases").appendTo(menu);
|
|
if(hasPermission("kick")) {
|
|
$("<button/>").addClass("btn btn-mini btn-block")
|
|
.text("Kick")
|
|
.click(function() {
|
|
socket.emit("chatMsg", {
|
|
msg: "/kick " + name
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
if(CLIENT.rank >= 2) {
|
|
$("<button/>").addClass("btn btn-mini btn-block")
|
|
.text("Give Leader")
|
|
.click(function() {
|
|
socket.emit("assignLeader", {
|
|
name: name
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
$("<button/>").addClass("btn btn-mini btn-block")
|
|
.text("Take Leader")
|
|
.click(function() {
|
|
socket.emit("assignLeader", {
|
|
name: ""
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
if(hasPermission("ban")) {
|
|
$("<button/>").addClass("btn btn-mini btn-block")
|
|
.text("Name Ban")
|
|
.click(function() {
|
|
socket.emit("chatMsg", {
|
|
msg: "/ban " + name
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
$("<button/>").addClass("btn btn-mini btn-block")
|
|
.text("IP Ban")
|
|
.click(function() {
|
|
socket.emit("chatMsg", {
|
|
msg: "/ipban " + name
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
|
|
|
|
entry.contextmenu(function(ev) {
|
|
ev.preventDefault();
|
|
if(menu.css("display") == "none") {
|
|
menu.find(".user-aliases")
|
|
.text("Aliases: " + entry.data("aliases"));
|
|
menu.show();
|
|
}
|
|
else {
|
|
menu.hide();
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
/* queue stuff */
|
|
|
|
function makeQueueEntry(video, addbtns) {
|
|
var li = $("<li/>");
|
|
li.addClass("queue_entry");
|
|
li.data("media", video);
|
|
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(video.temp) {
|
|
li.addClass("queue_temp");
|
|
}
|
|
|
|
if(addbtns)
|
|
addQueueButtons(li);
|
|
return li;
|
|
}
|
|
|
|
function addQueueButtons(li) {
|
|
li.find(".btn-group").remove();
|
|
var menu = $("<div/>").addClass("btn-group").appendTo(li);
|
|
// Play
|
|
if(hasPermission("playlistjump")) {
|
|
$("<button/>").addClass("btn btn-mini qbtn-play")
|
|
.html("<i class='icon-play'></i>Play")
|
|
.click(function() {
|
|
var i = $("#queue").children().index(li);
|
|
socket.emit("jumpTo", i);
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
// Queue next
|
|
if(hasPermission("playlistnext")) {
|
|
$("<button/>").addClass("btn btn-mini qbtn-next")
|
|
.html("<i class='icon-share-alt'></i>Queue Next")
|
|
.click(function() {
|
|
var i = $("#queue").children().index(li);
|
|
socket.emit("moveMedia", {
|
|
from: i,
|
|
to: i < POSITION ? POSITION : POSITION + 1,
|
|
moveby: null
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
// Temp/Untemp
|
|
if(hasPermission("settemp")) {
|
|
$("<button/>").addClass("btn btn-mini qbtn-tmp")
|
|
.html("<i class='icon-flag'></i>Make Temporary")
|
|
.click(function() {
|
|
var i = $("#queue").children().index(li);
|
|
var temp = li.find(".qbtn-tmp").data("temp");
|
|
socket.emit("setTemp", {
|
|
position: i,
|
|
temp: !temp
|
|
});
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
// Delete
|
|
if(hasPermission("playlistdelete")) {
|
|
$("<button/>").addClass("btn btn-mini qbtn-delete")
|
|
.html("<i class='icon-trash'></i>Delete")
|
|
.click(function() {
|
|
var i = $("#queue").children().index(li);
|
|
socket.emit("delete", i);
|
|
})
|
|
.appendTo(menu);
|
|
}
|
|
|
|
menu.hide();
|
|
|
|
li.contextmenu(function(ev) {
|
|
ev.preventDefault();
|
|
if(menu.css("display") == "none")
|
|
menu.show("blind");
|
|
else
|
|
menu.hide("blind");
|
|
return false;
|
|
});
|
|
}
|
|
|
|
function rebuildPlaylist() {
|
|
$("#queue li").each(function() {
|
|
$(this).find(".btn-group").remove();
|
|
addQueueButtons($(this));
|
|
});
|
|
}
|
|
|
|
/* menus */
|
|
function showOptionsMenu() {
|
|
PLAYER.hide();
|
|
var modal = $("<div/>").addClass("modal hide fade")
|
|
.appendTo($("body"));
|
|
var head = $("<div/>").addClass("modal-header")
|
|
.appendTo(modal);
|
|
$("<button/>").addClass("close")
|
|
.attr("data-dismiss", "modal")
|
|
.attr("aria-hidden", "true")
|
|
.appendTo(head)[0].innerHTML = "×";
|
|
$("<h3/>").text("User Options").appendTo(head);
|
|
var body = $("<div/>").addClass("modal-body").appendTo(modal);
|
|
var form = $("<form/>").addClass("form-horizontal")
|
|
.appendTo(body);
|
|
|
|
function addOption(lbl, thing) {
|
|
var g = $("<div/>").addClass("control-group").appendTo(form);
|
|
$("<label/>").addClass("control-label").text(lbl).appendTo(g);
|
|
var c = $("<div/>").addClass("controls").appendTo(g);
|
|
thing.appendTo(c);
|
|
}
|
|
|
|
var themeselect = $("<select/>");
|
|
$("<option/>").attr("value", "default").text("Default").appendTo(themeselect);
|
|
$("<option/>").attr("value", "assets/css/darkstrap.css").text("Dark").appendTo(themeselect);
|
|
$("<option/>").attr("value", "assets/css/semidark.css").text("Semidark").appendTo(themeselect);
|
|
themeselect.val(USEROPTS.theme);
|
|
addOption("Theme", themeselect);
|
|
|
|
var usercss = $("<input/>").attr("type", "text")
|
|
.attr("placeholder", "Stylesheet URL");
|
|
usercss.val(USEROPTS.css);
|
|
addOption("User CSS", usercss);
|
|
|
|
var layoutselect = $("<select/>");
|
|
$("<option/>").attr("value", "default").text("Compact")
|
|
.appendTo(layoutselect);
|
|
$("<option/>").attr("value", "synchtube").text("Synchtube")
|
|
.appendTo(layoutselect);
|
|
$("<option/>").attr("value", "fluid").text("Fluid")
|
|
.appendTo(layoutselect);
|
|
layoutselect.val(USEROPTS.layout);
|
|
addOption("Layout", layoutselect);
|
|
var warn = $("<p/>").addClass("text-error")
|
|
.text("Changing layouts may require a refresh")
|
|
addOption("", warn);
|
|
$("<hr>").appendTo(form);
|
|
|
|
var synchcontainer = $("<label/>").addClass("checkbox")
|
|
.text("Synchronize Media");
|
|
var synch = $("<input/>").attr("type", "checkbox").appendTo(synchcontainer);
|
|
synch.prop("checked", USEROPTS.synch);
|
|
addOption("Synch", synchcontainer);
|
|
|
|
var syncacc = $("<input/>").attr("type", "text")
|
|
.attr("placeholder", "Seconds");
|
|
syncacc.val(USEROPTS.sync_accuracy);
|
|
addOption("Synch Accuracy", syncacc);
|
|
|
|
var vidcontainer = $("<label/>").addClass("checkbox")
|
|
.text("Hide Video");
|
|
var hidevid = $("<input/>").attr("type", "checkbox").appendTo(vidcontainer);
|
|
hidevid.prop("checked", USEROPTS.hidevid);
|
|
addOption("Hide Video", vidcontainer);
|
|
$("<hr>").appendTo(form);
|
|
|
|
var tscontainer = $("<label/>").addClass("checkbox")
|
|
.text("Show timestamps in chat");
|
|
var showts = $("<input/>").attr("type", "checkbox").appendTo(tscontainer);
|
|
showts.prop("checked", USEROPTS.show_timestamps);
|
|
addOption("Show timestamps", tscontainer);
|
|
|
|
var blinkcontainer = $("<label/>").addClass("checkbox")
|
|
.text("Flash title on every incoming message");
|
|
var blink = $("<input/>").attr("type", "checkbox").appendTo(blinkcontainer);
|
|
blink.prop("checked", USEROPTS.blink_title);
|
|
addOption("Chat Notice", blinkcontainer);
|
|
|
|
var sendbtncontainer = $("<label/>").addClass("checkbox")
|
|
.text("Add a send button to the chatbox");
|
|
var sendbtn = $("<input/>").attr("type", "checkbox").appendTo(sendbtncontainer);
|
|
sendbtn.prop("checked", USEROPTS.chatbtn);
|
|
addOption("Send Button", sendbtncontainer);
|
|
|
|
var altsocketcontainer = $("<label/>").addClass("checkbox")
|
|
.text("Use alternative socket connection");
|
|
var altsocket = $("<input/>").attr("type", "checkbox")
|
|
.appendTo(altsocketcontainer);
|
|
altsocket.prop("checked", USEROPTS.altsocket);
|
|
addOption("Alternate Socket", altsocketcontainer);
|
|
|
|
var profile = $("<a/>").attr("target", "_blank")
|
|
.addClass("btn")
|
|
.attr("href", "./account.html")
|
|
.text("Profile has moved to the account page");
|
|
addOption("Profile", profile);
|
|
|
|
if(CLIENT.rank >= Rank.Moderator) {
|
|
$("<hr>").appendTo(form);
|
|
var modhatcontainer = $("<label/>").addClass("checkbox")
|
|
.text("Show name color");
|
|
var modhat = $("<input/>").attr("type", "checkbox").appendTo(modhatcontainer);
|
|
modhat.prop("checked", USEROPTS.modhat);
|
|
addOption("Modflair", modhatcontainer);
|
|
|
|
var joincontainer = $("<label/>").addClass("checkbox")
|
|
.text("Show join messages");
|
|
var join = $("<input/>").attr("type", "checkbox").appendTo(joincontainer);
|
|
join.prop("checked", USEROPTS.joinmessage);
|
|
addOption("Join Messages", joincontainer);
|
|
}
|
|
|
|
var footer = $("<div/>").addClass("modal-footer").appendTo(modal);
|
|
var submit = $("<button/>").addClass("btn btn-primary pull-right")
|
|
.text("Save")
|
|
.appendTo(footer);
|
|
|
|
submit.click(function() {
|
|
USEROPTS.theme = themeselect.val();
|
|
USEROPTS.css = usercss.val();
|
|
USEROPTS.layout = layoutselect.val();
|
|
USEROPTS.synch = synch.prop("checked");
|
|
USEROPTS.sync_accuracy = parseFloat(syncacc.val()) || 2;
|
|
USEROPTS.hidevid = hidevid.prop("checked");
|
|
USEROPTS.show_timestamps = showts.prop("checked");
|
|
USEROPTS.blink_title = blink.prop("checked");
|
|
USEROPTS.chatbtn = sendbtn.prop("checked");
|
|
USEROPTS.altsocket = altsocket.prop("checked");
|
|
if(CLIENT.rank >= Rank.Moderator) {
|
|
USEROPTS.modhat = modhat.prop("checked");
|
|
USEROPTS.joinmessage = join.prop("checked");
|
|
}
|
|
saveOpts();
|
|
modal.modal("hide");
|
|
});
|
|
|
|
modal.on("hidden", function() {
|
|
PLAYER.unhide();
|
|
applyOpts();
|
|
modal.remove();
|
|
});
|
|
modal.modal();
|
|
}
|
|
|
|
function saveOpts() {
|
|
for(var key in USEROPTS) {
|
|
localStorage.setItem(key, USEROPTS[key]);
|
|
}
|
|
}
|
|
|
|
function applyOpts() {
|
|
$("#usertheme").remove();
|
|
if(USEROPTS.theme != "default") {
|
|
$("<link/>").attr("rel", "stylesheet")
|
|
.attr("type", "text/css")
|
|
.attr("id", "usertheme")
|
|
.attr("href", USEROPTS.theme)
|
|
.appendTo($("head"));
|
|
}
|
|
|
|
$("#usercss").remove();
|
|
if(USEROPTS.css) {
|
|
$("<link/>").attr("rel", "stylesheet")
|
|
.attr("type", "text/css")
|
|
.attr("id", "usercss")
|
|
.attr("href", USEROPTS.css)
|
|
.appendTo($("head"));
|
|
}
|
|
|
|
switch(USEROPTS.layout) {
|
|
case "synchtube":
|
|
synchtubeLayout();
|
|
break;
|
|
case "fluid":
|
|
fluidLayout();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(USEROPTS.hidevid) {
|
|
$("#videowrap").remove();
|
|
}
|
|
|
|
$("#chatbtn").remove();
|
|
if(USEROPTS.chatbtn) {
|
|
var btn = $("<button/>").addClass("btn btn-block")
|
|
.text("Send")
|
|
.attr("id", "chatbtn")
|
|
.appendTo($("#chatwrap"));
|
|
btn.click(function() {
|
|
if($("#chatline").val().trim()) {
|
|
socket.emit("chatMsg", {
|
|
msg: $("#chatline").val()
|
|
});
|
|
$("#chatline").val("");
|
|
}
|
|
});
|
|
}
|
|
|
|
if(USEROPTS.altsocket) {
|
|
if(socket)
|
|
socket.disconnect();
|
|
socket = new NotWebsocket();
|
|
setupCallbacks();
|
|
}
|
|
// Switch from NotWebsocket => Socket.io
|
|
else if(socket && typeof socket.poll !== "undefined") {
|
|
try {
|
|
socket = io.connect(IO_URL);
|
|
setupCallbacks();
|
|
}
|
|
catch(e) {
|
|
}
|
|
}
|
|
}
|
|
|
|
applyOpts();
|
|
|
|
function showLoginMenu() {
|
|
PLAYER.hide();
|
|
var modal = $("<div/>").addClass("modal hide fade")
|
|
.appendTo($("body"));
|
|
var head = $("<div/>").addClass("modal-header")
|
|
.appendTo(modal);
|
|
$("<button/>").addClass("close")
|
|
.attr("data-dismiss", "modal")
|
|
.attr("aria-hidden", "true")
|
|
.appendTo(head)
|
|
.html("×");
|
|
$("<h3/>").text("Login").appendTo(head);
|
|
var body = $("<div/>").addClass("modal-body").appendTo(modal);
|
|
var frame = $("<iframe/>")
|
|
.attr("id", "loginframe")
|
|
.attr("src", "login.html")
|
|
.css("border", "none")
|
|
.css("width", "100%")
|
|
.css("height", "300px")
|
|
.css("margin", "0")
|
|
.appendTo(body);
|
|
var timer = setInterval(function() {
|
|
frame[0].contentWindow.postMessage("cytube-syn", document.location);
|
|
}, 1000);
|
|
var respond = function(e) {
|
|
if(e.data == "cytube-ack") {
|
|
clearInterval(timer);
|
|
}
|
|
if(e.data.indexOf(":") == -1) {
|
|
return;
|
|
}
|
|
if(e.data.substring(0, e.data.indexOf(":")) == "cytube-login") {
|
|
var data = e.data.substring(e.data.indexOf(":")+1);
|
|
data = JSON.parse(data);
|
|
if(data.error) {
|
|
// Since this is the login page, invalid session implies bad credentials
|
|
if(data.error == "Invalid session") {
|
|
alert("Invalid username/password");
|
|
}
|
|
else {
|
|
alert(data.error);
|
|
}
|
|
}
|
|
else if(data.success) {
|
|
SESSION = data.session || "";
|
|
CLIENT.name = data.uname || "";
|
|
socket.emit("login", {
|
|
name: CLIENT.name,
|
|
session: SESSION
|
|
});
|
|
if(window.removeEventListener) {
|
|
window.removeEventListener("message", respond, false);
|
|
}
|
|
else if(window.detachEvent) {
|
|
// If an IE dev ever reads this, please tell your company
|
|
// to get their shit together
|
|
window.detachEvent("onmessage", respond);
|
|
}
|
|
modal.modal("hide");
|
|
}
|
|
}
|
|
}
|
|
if(window.addEventListener) {
|
|
window.addEventListener("message", respond, false);
|
|
}
|
|
else if(window.attachEvent) {
|
|
// If an IE dev ever reads this, please tell your company to get
|
|
// their shit together
|
|
window.attachEvent("onmessage", respond);
|
|
}
|
|
var footer = $("<div/>").addClass("modal-footer").appendTo(modal);
|
|
modal.on("hidden", function() {
|
|
PLAYER.unhide();
|
|
modal.remove();
|
|
});
|
|
modal.modal();
|
|
}
|
|
|
|
function showPollMenu() {
|
|
$("#pollwrap .poll-menu").remove();
|
|
var menu = $("<div/>").addClass("well poll-menu")
|
|
.insertAfter($("#newpollbtn"));
|
|
|
|
$("<button/>").addClass("btn btn-danger pull-right")
|
|
.text("Cancel")
|
|
.appendTo(menu)
|
|
.click(function() {
|
|
menu.remove();
|
|
});
|
|
|
|
$("<strong/>").text("Title").appendTo(menu);
|
|
$("<br/>").appendTo(menu);
|
|
|
|
var title = $("<input/>").attr("type", "text")
|
|
.appendTo(menu);
|
|
$("<br/>").appendTo(menu);
|
|
|
|
$("<strong/>").text("Options").appendTo(menu);
|
|
$("<br/>").appendTo(menu);
|
|
|
|
var addbtn = $("<button/>").addClass("btn")
|
|
.text("Add Option")
|
|
.appendTo(menu);
|
|
$("<br/>").appendTo(menu);
|
|
|
|
function addOption() {
|
|
$("<input/>").attr("type", "text")
|
|
.addClass("poll-menu-option")
|
|
.insertBefore(addbtn);
|
|
$("<br/>").insertBefore(addbtn);
|
|
}
|
|
|
|
addbtn.click(addOption);
|
|
addOption();
|
|
addOption();
|
|
|
|
$("<br/>").appendTo(menu);
|
|
$("<button/>").addClass("btn")
|
|
.text("Open Poll")
|
|
.addClass("btn-block")
|
|
.appendTo(menu)
|
|
.click(function() {
|
|
var opts = []
|
|
menu.find(".poll-menu-option").each(function() {
|
|
if($(this).val() != "")
|
|
opts.push($(this).val());
|
|
});
|
|
socket.emit("newPoll", {
|
|
title: title.val(),
|
|
opts: opts
|
|
});
|
|
});
|
|
}
|
|
|
|
function scrollChat() {
|
|
$("#messagebuffer").scrollTop($("#messagebuffer").prop("scrollHeight"));
|
|
}
|
|
|
|
function hasPermission(key) {
|
|
if(key.indexOf("playlist") == 0 && CHANNEL.openqueue) {
|
|
var key2 = "o" + key;
|
|
var v = CHANNEL.perms[key2];
|
|
if(typeof v == "number" && CLIENT.rank >= v) {
|
|
return true;
|
|
}
|
|
}
|
|
var v = CHANNEL.perms[key];
|
|
if(typeof v != "number") {
|
|
return false;
|
|
}
|
|
return CLIENT.rank >= v;
|
|
}
|
|
|
|
function handlePermissionChange() {
|
|
function setVisible(selector, bool) {
|
|
if($(selector) && $(selector).attr("id") != selector.substring(1)) {
|
|
setTimeout(function() {
|
|
setVisible(selector, bool);
|
|
}, 100);
|
|
return;
|
|
}
|
|
var disp = bool ? "" : "none";
|
|
$(selector).css("display", disp);
|
|
}
|
|
|
|
if(CLIENT.rank >= 2) {
|
|
$("#channelsettingswrap3").show();
|
|
if($("#channelsettingswrap").html() == "")
|
|
$("#channelsettingswrap").load("channeloptions.html");
|
|
/* update channel controls */
|
|
$("#opt_pagetitle").val(CHANNEL.opts.pagetitle);
|
|
$("#opt_externalcss").val(CHANNEL.opts.externalcss);
|
|
$("#opt_externaljs").val(CHANNEL.opts.externaljs);
|
|
$("#opt_chat_antiflood").prop("checked", CHANNEL.opts.chat_antiflood);
|
|
$("#opt_show_public").prop("checked", CHANNEL.opts.show_public);
|
|
$("#opt_enable_link_regex").prop("checked", CHANNEL.opts.enable_link_regex);
|
|
$("#opt_allow_voteskip").prop("checked", CHANNEL.opts.allow_voteskip);
|
|
$("#opt_voteskip_ratio").val(CHANNEL.opts.voteskip_ratio);
|
|
setVisible("#permedit_tab", CLIENT.rank >= 3);
|
|
setVisible("#banlist_tab", hasPermission("ban"));
|
|
setVisible("#motdedit_tab", hasPermission("motdedit"));
|
|
setVisible("#cssedit_tab", CLIENT.rank >= 3);
|
|
setVisible("#jsedit_tab", CLIENT.rank >= 3);
|
|
setVisible("#filteredit_tab", hasPermission("filteredit"));
|
|
setVisible("#channelranks_tab", CLIENT.rank >= 3);
|
|
}
|
|
else {
|
|
$("#channelsettingswrap").html("");
|
|
$("#channelsettingswrap3").hide();
|
|
}
|
|
|
|
setVisible("#userpltogglewrap", CLIENT.rank >= 1);
|
|
|
|
setVisible("#playlisttogglewrap", hasPermission("playlistadd"));
|
|
$("#queue_next").attr("disabled", !hasPermission("playlistnext"));
|
|
setVisible("#qlockbtn", CLIENT.rank >= 2);
|
|
|
|
if(hasPermission("playlistmove")) {
|
|
$("#queue").sortable("enable");
|
|
$("#queue").addClass("queue_sortable");
|
|
}
|
|
else {
|
|
$("#queue").sortable("disable");
|
|
$("#queue").removeClass("queue_sortable");
|
|
}
|
|
|
|
setVisible("#getplaylist", hasPermission("playlistgeturl"));
|
|
setVisible("#clearplaylist", hasPermission("playlistclear"));
|
|
setVisible("#shuffleplaylist", hasPermission("playlistshuffle"));
|
|
|
|
|
|
setVisible("#newpollbtn", hasPermission("pollctl"));
|
|
|
|
$("#pollcontainer .active").find(".btn-danger").remove();
|
|
if(hasPermission("pollctl")) {
|
|
var poll = $("#pollcontainer .active");
|
|
if(poll.length > 0) {
|
|
$("<button/>").addClass("btn btn-danger pull-right")
|
|
.text("End Poll")
|
|
.insertAfter(poll.find(".close"))
|
|
.click(function() {
|
|
socket.emit("closePoll");
|
|
});
|
|
}
|
|
}
|
|
var poll = $("#pollcontainer .active");
|
|
if(poll.length > 0) {
|
|
poll.find(".btn").attr("disabled", !hasPermission("pollvote"));
|
|
}
|
|
var users = $("#userlist").children();
|
|
for(var i = 0; i < users.length; i++) {
|
|
addUserDropdown($(users[i]), users[i].children[1].innerHTML);
|
|
}
|
|
rebuildPlaylist();
|
|
}
|
|
|
|
/* search stuff */
|
|
|
|
function clearSearchResults() {
|
|
$("#library").html("");
|
|
$("#search_pagination").remove();
|
|
}
|
|
|
|
function loadSearchPage(page) {
|
|
$("#library").html("");
|
|
var results = $("#library").data("entries");
|
|
var start = page * 100;
|
|
for(var i = start; i < start + 100 && i < results.length; i++) {
|
|
var li = makeQueueEntry(results[i], false);
|
|
if(hasPermission("playlistadd")) {
|
|
if(results[i].thumb) {
|
|
addLibraryButtons(li, results[i].id, "yt");
|
|
}
|
|
else {
|
|
addLibraryButtons(li, results[i].id);
|
|
}
|
|
}
|
|
$(li).appendTo($("#library"));
|
|
}
|
|
if($("#search_pagination").length > 0) {
|
|
$("#search_pagination").find("li").each(function() {
|
|
$(this).removeClass("active");
|
|
});
|
|
$($("#search_pagination").find("li")[page]).addClass("active");
|
|
}
|
|
}
|
|
|
|
function addLibraryButtons(li, id, type) {
|
|
var btns = $("<div/>").addClass("btn-group")
|
|
.addClass("pull-left")
|
|
.prependTo(li);
|
|
|
|
if(hasPermission("playlistadd")) {
|
|
if(hasPermission("playlistnext")) {
|
|
$("<button/>").addClass("btn btn-mini")
|
|
.text("Next")
|
|
.click(function() {
|
|
socket.emit("queue", {
|
|
id: id,
|
|
pos: "next",
|
|
type: type
|
|
});
|
|
})
|
|
.appendTo(btns);
|
|
}
|
|
$("<button/>").addClass("btn btn-mini")
|
|
.text("End")
|
|
.click(function() {
|
|
socket.emit("queue", {
|
|
id: id,
|
|
pos: "end",
|
|
type: type
|
|
});
|
|
})
|
|
.appendTo(btns);
|
|
}
|
|
if(CLIENT.rank >= 2) {
|
|
$("<button/>").addClass("btn btn-mini btn-danger")
|
|
.html("<i class='icon-trash'></i>")
|
|
.click(function() {
|
|
socket.emit("uncache", {
|
|
id: id
|
|
});
|
|
li.hide("blind", function() {
|
|
li.remove();
|
|
});
|
|
})
|
|
.appendTo(btns);
|
|
}
|
|
}
|
|
|
|
/* queue stuff */
|
|
|
|
function playlistMove(from, to) {
|
|
if(from < 0 || to < 0)
|
|
return false;
|
|
var q = $("#queue");
|
|
if(from >= q.children().length)
|
|
return false;
|
|
|
|
var old = $(q.children()[from]);
|
|
old.hide("blind", function() {
|
|
old.detach();
|
|
if(to >= q.children().length)
|
|
old.appendTo(q);
|
|
else
|
|
old.insertBefore(q.children()[to]);
|
|
old.show("blind");
|
|
});
|
|
}
|
|
|
|
function parseMediaLink(url) {
|
|
if(typeof url != "string") {
|
|
return {
|
|
id: null,
|
|
type: null
|
|
};
|
|
}
|
|
url = url.trim();
|
|
url = url.replace("feature=player_embedded&", "");
|
|
|
|
if(url.indexOf("jw:") == 0) {
|
|
return {
|
|
id: url.substring(3),
|
|
type: "jw"
|
|
};
|
|
}
|
|
|
|
if(url.indexOf("rtmp://") == 0) {
|
|
return {
|
|
id: url,
|
|
type: "rt"
|
|
};
|
|
}
|
|
|
|
var m;
|
|
if((m = url.match(/youtube\.com\/watch\?v=([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "yt"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/youtu\.be\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "yt"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/youtube\.com\/playlist\?list=([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "yp"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/twitch\.tv\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "tw"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/justin\.tv\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "jt"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/livestream\.com\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "li"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/ustream\.tv\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "us"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/vimeo\.com\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "vi"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/dailymotion\.com\/video\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "dm"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/imgur\.com\/a\/([^&#]+)/))) {
|
|
return {
|
|
id: m[1],
|
|
type: "im"
|
|
};
|
|
}
|
|
|
|
if((m = url.match(/soundcloud\.com\/([^&#]+)/))) {
|
|
return {
|
|
id: url,
|
|
type: "sc"
|
|
};
|
|
}
|
|
|
|
return {
|
|
id: null,
|
|
type: null
|
|
};
|
|
}
|
|
|
|
function sendVideoUpdate() {
|
|
PLAYER.getTime(function(seconds) {
|
|
socket.emit("mediaUpdate", {
|
|
id: PLAYER.id,
|
|
currentTime: seconds,
|
|
paused: PLAYER.paused,
|
|
type: PLAYER.type
|
|
});
|
|
});
|
|
}
|
|
|
|
/* chat */
|
|
|
|
function formatChatMessage(data) {
|
|
var skip = data.username == LASTCHATNAME;
|
|
if(data.msgclass == "drink" || data.msgclass == "shout") {
|
|
skip = false;
|
|
}
|
|
if(data.msgclass == "server-whisper") {
|
|
skip = true;
|
|
}
|
|
LASTCHATNAME = data.username;
|
|
LASTCHATTIME = data.time;
|
|
var div = $("<div/>");
|
|
if(USEROPTS.show_timestamps) {
|
|
var time = $("<span/>").addClass("timestamp").appendTo(div);
|
|
var timestamp = new Date(data.time).toTimeString().split(" ")[0];
|
|
time.text("["+timestamp+"] ");
|
|
if(data.msgclass != "greentext" && data.msgclass != "drink")
|
|
time.addClass(data.msgclass);
|
|
}
|
|
var name = $("<span/>");
|
|
if(!skip) {
|
|
name.appendTo(div);
|
|
}
|
|
$("<strong/>").addClass("username").text(data.username + ": ").appendTo(name);
|
|
var message = $("<span/>").appendTo(div);
|
|
message[0].innerHTML = data.msg;
|
|
if(data.modflair) {
|
|
name.addClass(getNameColor(data.modflair));
|
|
}
|
|
if(data.msgclass == "action") {
|
|
name.remove();
|
|
message.addClass("action");
|
|
message[0].innerHTML = data.username + " " + data.msg;
|
|
}
|
|
else if(data.msgclass == "drink") {
|
|
div.addClass("drink");
|
|
}
|
|
else if(data.msgclass == "shout") {
|
|
message.addClass("shout");
|
|
name.addClass("shout");
|
|
}
|
|
else {
|
|
message.addClass(data.msgclass);
|
|
}
|
|
return div;
|
|
}
|
|
|
|
function addChatMessage(data) {
|
|
if(IGNORED.indexOf(data.username) != -1) {
|
|
return;
|
|
}
|
|
var div = formatChatMessage(data);
|
|
div.data("sender", data.username);
|
|
div.appendTo($("#messagebuffer"));
|
|
div.mouseover(function() {
|
|
$("#messagebuffer").children().each(function() {
|
|
var name = $(this).data("sender");
|
|
if(name == data.username) {
|
|
$(this).addClass("nick-hover");
|
|
}
|
|
});
|
|
});
|
|
div.mouseleave(function() {
|
|
$("#messagebuffer").children().each(function() {
|
|
$(this).removeClass("nick-hover");
|
|
});
|
|
});
|
|
// Cap chatbox at most recent 100 messages
|
|
if($("#messagebuffer").children().length > 100) {
|
|
$($("#messagebuffer").children()[0]).remove();
|
|
}
|
|
if(SCROLLCHAT)
|
|
scrollChat();
|
|
if(USEROPTS.blink_title && !FOCUSED && !TITLE_BLINK) {
|
|
TITLE_BLINK = setInterval(function() {
|
|
if(document.title == "*Chat*")
|
|
document.title = PAGETITLE;
|
|
else
|
|
document.title = "*Chat*";
|
|
}, 1000);
|
|
}
|
|
if(CLIENT.name && data.username != CLIENT.name) {
|
|
if(data.msg.toUpperCase().indexOf(CLIENT.name.toUpperCase()) != -1) {
|
|
div.addClass("nick-highlight");
|
|
if(!FOCUSED && !TITLE_BLINK) {
|
|
TITLE_BLINK = setInterval(function() {
|
|
if(document.title == "*Chat*")
|
|
document.title = PAGETITLE;
|
|
else
|
|
document.title = "*Chat*";
|
|
}, 1000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* layouts */
|
|
|
|
function fluidLayout() {
|
|
$(".row").each(function() {
|
|
$(this).removeClass("row").addClass("row-fluid");
|
|
});
|
|
$(".container").each(function() {
|
|
$(this).removeClass("container").addClass("container-fluid");
|
|
});
|
|
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
|
VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
|
$("#messagebuffer").css("height", (VHEIGHT - 31) + "px");
|
|
$("#userlist").css("height", (VHEIGHT - 31) + "px");
|
|
$("#ytapiplayer").attr("width", VWIDTH);
|
|
$("#ytapiplayer").attr("height", VHEIGHT);
|
|
$("#chatline").removeClass().addClass("span12");
|
|
}
|
|
|
|
function synchtubeLayout() {
|
|
$("#videowrap").detach().insertBefore($("#chatwrap"));
|
|
$("#rightpane-outer").detach().insertBefore($("#leftpane-outer"));
|
|
}
|
|
|
|
function chatOnly() {
|
|
fluidLayout();
|
|
$("#toprow").remove()
|
|
$("#announcements").remove();
|
|
$("#playlistrow").remove();
|
|
$("#videowrap").remove();
|
|
$("#chatwrap").removeClass("span5").addClass("span12");
|
|
}
|
|
|
|
/* channel administration stuff */
|
|
|
|
function genPermissionsEditor() {
|
|
$("#permedit").html("");
|
|
var form = $("<form/>").addClass("form-horizontal")
|
|
.attr("action", "javascript:void(0)")
|
|
.appendTo($("#permedit"));
|
|
var fs = $("<fieldset/>").appendTo(form);
|
|
|
|
function makeOption(text, key, permset, defval) {
|
|
var group = $("<div/>").addClass("control-group")
|
|
.appendTo(fs);
|
|
$("<label/>").addClass("control-label")
|
|
.text(text)
|
|
.appendTo(group);
|
|
var controls = $("<div/>").addClass("controls")
|
|
.appendTo(group);
|
|
var select = $("<select/>").appendTo(controls);
|
|
select.data("key", key);
|
|
for(var i = 0; i < permset.length; i++) {
|
|
$("<option/>").attr("value", permset[i][1])
|
|
.text(permset[i][0])
|
|
.attr("selected", defval == permset[i][1])
|
|
.appendTo(select);
|
|
}
|
|
}
|
|
|
|
function addDivider(text) {
|
|
$("<hr/>").appendTo(fs);
|
|
$("<h3/>").text(text).appendTo(fs);
|
|
}
|
|
|
|
var standard = [
|
|
["Anonymous" , "-1"],
|
|
["Guest" , "0"],
|
|
["Registered" , "1"],
|
|
["Leader" , "1.5"],
|
|
["Moderator" , "2"],
|
|
["Channel Admin", "3"]
|
|
];
|
|
|
|
var modleader = [
|
|
["Leader" , "1.5"],
|
|
["Moderator" , "2"],
|
|
["Channel Admin", "3"]
|
|
];
|
|
|
|
var modplus = [
|
|
["Moderator" , "2"],
|
|
["Channel Admin", "3"]
|
|
];
|
|
|
|
$("<h3/>").text("Open playlist permissions").appendTo(fs);
|
|
makeOption("Add to playlist", "oplaylistadd", standard, CHANNEL.perms.oplaylistadd+"");
|
|
makeOption("Add/move to next", "oplaylistnext", standard, CHANNEL.perms.oplaylistnext+"");
|
|
makeOption("Move playlist items", "oplaylistmove", standard, CHANNEL.perms.oplaylistmove+"");
|
|
makeOption("Delete playlist items", "oplaylistdelete", standard, CHANNEL.perms.oplaylistdelete+"");
|
|
makeOption("Jump to video", "oplaylistjump", standard, CHANNEL.perms.oplaylistjump+"");
|
|
makeOption("Queue playlist", "oplaylistaddlist", standard, CHANNEL.perms.oplaylistaddlist+"");
|
|
|
|
addDivider("General playlist permissions");
|
|
makeOption("Add to playlist", "playlistadd", standard, CHANNEL.perms.playlistadd+"");
|
|
makeOption("Add/move to next", "playlistnext", standard, CHANNEL.perms.playlistnext+"");
|
|
makeOption("Move playlist items", "playlistmove", standard, CHANNEL.perms.playlistmove+"");
|
|
makeOption("Delete playlist items", "playlistdelete", standard, CHANNEL.perms.playlistdelete+"");
|
|
makeOption("Jump to video", "playlistjump", standard, CHANNEL.perms.playlistjump+"");
|
|
makeOption("Queue playlist", "playlistaddlist", standard, CHANNEL.perms.playlistaddlist+"");
|
|
makeOption("Queue livestream", "playlistaddlive", standard, CHANNEL.perms.playlistaddlive+"");
|
|
makeOption("Add nontemporary media", "addnontemp", standard, CHANNEL.perms.addnontemp+"");
|
|
makeOption("Temp/untemp playlist item", "settemp", standard, CHANNEL.perms.settemp+"");
|
|
makeOption("Retrieve playlist URLs", "playlistgeturl", standard, CHANNEL.perms.playlistgeturl+"");
|
|
makeOption("Shuffle playlist", "playlistshuffle", standard, CHANNEL.perms.playlistshuffle+"");
|
|
makeOption("Clear playlist", "playlistclear", standard, CHANNEL.perms.playlistclear+"");
|
|
|
|
addDivider("Polls");
|
|
makeOption("Open/Close poll", "pollctl", modleader, CHANNEL.perms.pollctl+"");
|
|
makeOption("Vote", "pollvote", standard, CHANNEL.perms.pollvote+"");
|
|
|
|
addDivider("Moderation");
|
|
makeOption("Kick users", "kick", modleader, CHANNEL.perms.kick+"");
|
|
makeOption("Ban users", "ban", modplus, CHANNEL.perms.ban+"");
|
|
makeOption("Edit MOTD", "motdedit", modplus, CHANNEL.perms.motdedit+"");
|
|
makeOption("Edit chat filters", "filteredit", modplus, CHANNEL.perms.filteredit+"");
|
|
|
|
addDivider("Misc");
|
|
makeOption("Drink calls", "drink", modleader, CHANNEL.perms.drink+"");
|
|
|
|
var submit = $("<button/>").addClass("btn btn-primary").appendTo(fs);
|
|
submit.text("Save");
|
|
submit.click(function() {
|
|
var perms = {};
|
|
fs.find("select").each(function() {
|
|
perms[$(this).data("key")] = parseFloat($(this).val());
|
|
});
|
|
socket.emit("setPermissions", perms);
|
|
});
|
|
}
|
|
|
|
function loadChannelRanksPage(page) {
|
|
var entries = $("#channelranks").data("entries");
|
|
$("#channelranks").data("page", page);
|
|
var start = page * 20;
|
|
var tbl = $("#channelranks table");
|
|
if(tbl.children().length > 1) {
|
|
$(tbl.children()[1]).remove();
|
|
}
|
|
for(var i = start; i < start + 20 && i < entries.length; i++) {
|
|
var tr = $("<tr/>").appendTo(tbl);
|
|
var name = $("<td/>").text(entries[i].name).appendTo(tr);
|
|
name.addClass(getNameColor(entries[i].rank));
|
|
var rank = $("<td/>").text(entries[i].rank)
|
|
.css("min-width", "220px")
|
|
.appendTo(tr);
|
|
(function(name) {
|
|
rank.click(function() {
|
|
if(this.find(".rank-edit").length > 0)
|
|
return;
|
|
var r = this.text();
|
|
this.text("");
|
|
var edit = $("<input/>").attr("type", "text")
|
|
.attr("placeholder", r)
|
|
.addClass("rank-edit")
|
|
.appendTo(this)
|
|
.focus();
|
|
if(parseInt(r) >= CLIENT.rank) {
|
|
edit.attr("disabled", true);
|
|
}
|
|
function save() {
|
|
var r = this.val();
|
|
var r2 = r;
|
|
if(r.trim() == "" || parseInt(r) >= CLIENT.rank || parseInt(r) < 1)
|
|
r = this.attr("placeholder");
|
|
r = parseInt(r) + "";
|
|
this.parent().text(r);
|
|
socket.emit("setChannelRank", {
|
|
user: name,
|
|
rank: parseInt(r)
|
|
});
|
|
}
|
|
edit.blur(save.bind(edit));
|
|
edit.keydown(function(ev) {
|
|
if(ev.keyCode == 13)
|
|
save.bind(edit)();
|
|
});
|
|
}.bind(rank));
|
|
})(entries[i].name);
|
|
}
|
|
if($("#channelranks_pagination").length > 0) {
|
|
$("#channelranks_pagination").find("li").each(function() {
|
|
$(this).removeClass("active");
|
|
});
|
|
$($("#channelranks_pagination").find("li")[page]).addClass("active");
|
|
}
|
|
}
|