Here we go, merging v2.0
This commit is contained in:
commit
f149f9a658
145
acp.js
Normal file
145
acp.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
var Server = require("./server");
|
||||
var Auth = require("./auth");
|
||||
var Database = require("./database");
|
||||
var ActionLog = require("./actionlog");
|
||||
|
||||
module.exports = {
|
||||
init: function(user) {
|
||||
ActionLog.record(user.ip, user.name, "acp-init");
|
||||
user.socket.on("acp-announce", function(data) {
|
||||
ActionLog.record(user.ip, user.name, "acp-announce", [data]);
|
||||
Server.announcement = data;
|
||||
Server.io.sockets.emit("announcement", data);
|
||||
});
|
||||
|
||||
user.socket.on("acp-announce-clear", function() {
|
||||
ActionLog.record(user.ip, user.name, "acp-announce-clear");
|
||||
Server.announcement = null;
|
||||
});
|
||||
|
||||
user.socket.on("acp-global-ban", function(data) {
|
||||
ActionLog.record(user.ip, user.name, "acp-global-ban", [data.ip]);
|
||||
Database.globalBanIP(data.ip, data.note);
|
||||
user.socket.emit("acp-global-banlist", Database.refreshGlobalBans());
|
||||
});
|
||||
|
||||
user.socket.on("acp-global-unban", function(ip) {
|
||||
ActionLog.record(user.ip, user.name, "acp-global-unban", [data.ip]);
|
||||
Database.globalUnbanIP(ip);
|
||||
user.socket.emit("acp-global-banlist", Database.refreshGlobalBans());
|
||||
});
|
||||
|
||||
user.socket.emit("acp-global-banlist", Database.refreshGlobalBans());
|
||||
|
||||
user.socket.on("acp-lookup-user", function(name) {
|
||||
var db = Database.getConnection();
|
||||
if(!db) {
|
||||
return;
|
||||
}
|
||||
|
||||
var query = Database.createQuery(
|
||||
"SELECT id,uname,global_rank,profile_image,profile_text,email FROM registrations WHERE uname LIKE ?",
|
||||
["%"+name+"%"]
|
||||
);
|
||||
|
||||
var res = db.querySync(query);
|
||||
if(!res)
|
||||
return;
|
||||
|
||||
var rows = res.fetchAllSync();
|
||||
user.socket.emit("acp-userdata", rows);
|
||||
});
|
||||
|
||||
user.socket.on("acp-reset-password", function(data) {
|
||||
if(Auth.getGlobalRank(data.name) >= user.global_rank)
|
||||
return;
|
||||
try {
|
||||
var hash = Database.generatePasswordReset(user.ip, data.name, data.email);
|
||||
ActionLog.record(user.ip, user.name, "acp-reset-password", [data.name]);
|
||||
}
|
||||
catch(e) {
|
||||
user.socket.emit("acp-reset-password", {
|
||||
success: false,
|
||||
error: e
|
||||
});
|
||||
return;
|
||||
}
|
||||
if(hash) {
|
||||
user.socket.emit("acp-reset-password", {
|
||||
success: true,
|
||||
hash: hash
|
||||
});
|
||||
}
|
||||
else {
|
||||
user.socket.emit("acp-reset-password", {
|
||||
success: false,
|
||||
error: "Reset failed"
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
user.socket.on("acp-set-rank", function(data) {
|
||||
if(data.rank < 1 || data.rank >= user.global_rank)
|
||||
return;
|
||||
|
||||
if(Auth.getGlobalRank(data.name) >= user.global_rank)
|
||||
return;
|
||||
|
||||
var db = Database.getConnection();
|
||||
if(!db)
|
||||
return;
|
||||
|
||||
ActionLog.record(user.ip, user.name, "acp-set-rank", [data]);
|
||||
var query = Database.createQuery(
|
||||
"UPDATE registrations SET global_rank=? WHERE uname=?",
|
||||
[data.name, data.rank]
|
||||
);
|
||||
|
||||
var res = db.querySync(query);
|
||||
if(!res)
|
||||
return;
|
||||
|
||||
user.socket.emit("acp-set-rank", data);
|
||||
});
|
||||
|
||||
user.socket.on("acp-list-loaded", function() {
|
||||
var chans = [];
|
||||
for(var c in Server.channels) {
|
||||
var chan = Server.channels[c];
|
||||
if(!chan)
|
||||
continue;
|
||||
|
||||
chans.push({
|
||||
name: c,
|
||||
title: chan.opts.pagetitle,
|
||||
usercount: chan.users.length,
|
||||
mediatitle: chan.media ? chan.media.title : "-",
|
||||
is_public: chan.opts.show_public,
|
||||
registered: chan.registered
|
||||
});
|
||||
}
|
||||
|
||||
user.socket.emit("acp-list-loaded", chans);
|
||||
});
|
||||
|
||||
user.socket.on("acp-channel-unload", function(data) {
|
||||
if(data.name in Server.channels) {
|
||||
var c = Server.channels[data.name];
|
||||
if(!c)
|
||||
return;
|
||||
ActionLog.record(user.ip, user.name, "acp-channel-unload");
|
||||
c.initialized = data.save;
|
||||
c.users.forEach(function(u) {
|
||||
c.kick(u, "Channel shutting down");
|
||||
});
|
||||
Server.unload(c);
|
||||
}
|
||||
});
|
||||
|
||||
user.socket.on("acp-actionlog-clear", function(data) {
|
||||
ActionLog.clear(data);
|
||||
ActionLog.record(user.ip, user.name, "acp-actionlog-clear", data);
|
||||
});
|
||||
}
|
||||
}
|
65
actionlog.js
Normal file
65
actionlog.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
var fs = require("fs");
|
||||
var Logger = require("./logger");
|
||||
|
||||
var buffer = [];
|
||||
|
||||
exports.record = function(ip, name, action, args) {
|
||||
buffer.push(JSON.stringify({
|
||||
ip: ip,
|
||||
name: name,
|
||||
action: action,
|
||||
args: args ? args : [],
|
||||
time: Date.now()
|
||||
}));
|
||||
}
|
||||
|
||||
exports.flush = function() {
|
||||
if(buffer.length == 0)
|
||||
return;
|
||||
var text = buffer.join("\n") + "\n";
|
||||
buffer = [];
|
||||
fs.appendFile("action.log", text, function(err) {
|
||||
if(err) {
|
||||
errlog.log("Append to actionlog failed: ");
|
||||
errlog.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.clear = function(actions) {
|
||||
clearInterval(FLUSH_TMR);
|
||||
var rs = fs.createReadStream("action.log");
|
||||
var ws = fs.createWriteStream("action.log.tmp");
|
||||
function handleLine(ln) {
|
||||
try {
|
||||
js = JSON.parse(ln);
|
||||
if(actions.indexOf(js.action) == -1)
|
||||
ws.write(ln + "\n");
|
||||
}
|
||||
catch(e) { }
|
||||
}
|
||||
var buffer = "";
|
||||
rs.on("data", function(chunk) {
|
||||
buffer += chunk;
|
||||
if(buffer.indexOf("\n") != -1) {
|
||||
var lines = buffer.split("\n");
|
||||
buffer = lines[lines.length - 1];
|
||||
lines.length = lines.length - 1;
|
||||
lines.forEach(handleLine);
|
||||
}
|
||||
});
|
||||
rs.on("end", function() {
|
||||
handleLine(buffer);
|
||||
ws.end();
|
||||
});
|
||||
try {
|
||||
fs.renameSync("action.log.tmp", "action.log");
|
||||
}
|
||||
catch(e) {
|
||||
Logger.errlog.log("Failed to move action.log.tmp => action.log");
|
||||
Logger.errlog.log(e);
|
||||
}
|
||||
FLUSH_TMR = setInterval(exports.flush, 15000);
|
||||
}
|
||||
|
||||
var FLUSH_TMR = setInterval(exports.flush, 15000);
|
126
api.js
126
api.js
|
@ -15,6 +15,7 @@ var Logger = require("./logger.js");
|
|||
var apilog = new Logger.Logger("api.log");
|
||||
var Database = require("./database.js");
|
||||
var Config = require("./config.js");
|
||||
var ActionLog = require("./actionlog.js");
|
||||
var fs = require("fs");
|
||||
|
||||
var plainHandlers = {
|
||||
|
@ -32,11 +33,21 @@ var jsonHandlers = {
|
|||
"setprofile" : handleProfileChange,
|
||||
"getprofile" : handleProfileGet,
|
||||
"setemail" : handleEmailChange,
|
||||
"globalbans" : handleGlobalBans,
|
||||
"admreports" : handleAdmReports,
|
||||
"acppwreset" : handleAcpPasswordReset
|
||||
};
|
||||
|
||||
function getClientIP(req) {
|
||||
var ip;
|
||||
var forward = req.header("x-forwarded-for");
|
||||
if(forward) {
|
||||
ip = forward.split(",")[0];
|
||||
}
|
||||
if(!ip) {
|
||||
ip = req.connection.remoteAddress;
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
function handle(path, req, res) {
|
||||
var parts = path.split("/");
|
||||
var last = parts[parts.length - 1];
|
||||
|
@ -193,12 +204,14 @@ function handleLogin(params, req, res) {
|
|||
|
||||
var row = Auth.login(name, pw, session);
|
||||
if(row) {
|
||||
ActionLog.record(getClientIP(req), name, "login-success");
|
||||
sendJSON(res, {
|
||||
success: true,
|
||||
session: row.session_hash
|
||||
});
|
||||
}
|
||||
else {
|
||||
ActionLog.record(getClientIP(req), name, "login-failure");
|
||||
sendJSON(res, {
|
||||
error: "Invalid username/password",
|
||||
success: false
|
||||
|
@ -219,6 +232,7 @@ function handlePasswordChange(params, req, res) {
|
|||
}
|
||||
var row = Auth.login(name, oldpw);
|
||||
if(row) {
|
||||
ActionLog.record(getClientIP(req), name, "password-change");
|
||||
var success = Auth.setUserPassword(name, newpw);
|
||||
sendJSON(res, {
|
||||
success: success,
|
||||
|
@ -237,11 +251,12 @@ function handlePasswordChange(params, req, res) {
|
|||
function handlePasswordReset(params, req, res) {
|
||||
var name = params.name || "";
|
||||
var email = unescape(params.email || "");
|
||||
var ip = req.socket.address().address;
|
||||
var ip = getClientIP(req);
|
||||
|
||||
var hash = false;
|
||||
try {
|
||||
hash = Database.generatePasswordReset(ip, name, email);
|
||||
ActionLog.record(ip, name, "password-reset-generate");
|
||||
}
|
||||
catch(e) {
|
||||
sendJSON(res, {
|
||||
|
@ -301,7 +316,7 @@ function handlePasswordReset(params, req, res) {
|
|||
|
||||
function handlePasswordRecover(params, req, res) {
|
||||
var hash = params.hash || "";
|
||||
var ip = req.socket.address().address;
|
||||
var ip = getClientIP(req);
|
||||
|
||||
try {
|
||||
var info = Database.recoverPassword(hash);
|
||||
|
@ -310,10 +325,12 @@ function handlePasswordRecover(params, req, res) {
|
|||
name: info[0],
|
||||
pw: info[1]
|
||||
});
|
||||
ActionLog.record(ip, name, "password-recover-success");
|
||||
Logger.syslog.log(ip + " recovered password for " + name);
|
||||
return;
|
||||
}
|
||||
catch(e) {
|
||||
ActionLog.record(ip, name, "password-recover-failure");
|
||||
sendJSON(res, {
|
||||
success: false,
|
||||
error: e
|
||||
|
@ -412,6 +429,7 @@ function handleEmailChange(params, req, res) {
|
|||
var row = Auth.login(name, pw);
|
||||
if(row) {
|
||||
var success = Database.setUserEmail(name, email);
|
||||
ActionLog.record(getClientIP(req), name, "email-update", [email]);
|
||||
sendJSON(res, {
|
||||
success: success,
|
||||
error: success ? "" : "Email update failed",
|
||||
|
@ -438,6 +456,7 @@ function handleRegister(params, req, res) {
|
|||
return;
|
||||
}
|
||||
else if(Auth.isRegistered(name)) {
|
||||
ActionLog.record(getClientIP(req), name, "register-failure");
|
||||
sendJSON(res, {
|
||||
success: false,
|
||||
error: "That username is already taken"
|
||||
|
@ -445,6 +464,7 @@ function handleRegister(params, req, res) {
|
|||
return false;
|
||||
}
|
||||
else if(!Auth.validateName(name)) {
|
||||
ActionLog.record(getClientIP(req), name, "register-failure");
|
||||
sendJSON(res, {
|
||||
success: false,
|
||||
error: "Invalid username. Usernames must be 1-20 characters long and consist only of alphanumeric characters and underscores"
|
||||
|
@ -453,7 +473,8 @@ function handleRegister(params, req, res) {
|
|||
else {
|
||||
var session = Auth.register(name, pw);
|
||||
if(session) {
|
||||
Logger.syslog.log(this.ip + " registered " + name);
|
||||
ActionLog.record(getClientIP(req), name, "register-success");
|
||||
Logger.syslog.log(getClientIP(req) + " registered " + name);
|
||||
sendJSON(res, {
|
||||
success: true,
|
||||
session: session
|
||||
|
@ -468,103 +489,12 @@ function handleRegister(params, req, res) {
|
|||
}
|
||||
}
|
||||
|
||||
function handleGlobalBans(params, req, res) {
|
||||
var name = params.name || "";
|
||||
var pw = params.pw || "";
|
||||
var session = params.session || "";
|
||||
var row = Auth.login(name, pw, session);
|
||||
if(!row || row.global_rank < 255) {
|
||||
res.send(403);
|
||||
return;
|
||||
}
|
||||
|
||||
var action = params.action || "list";
|
||||
if(action == "list") {
|
||||
var gbans = Database.refreshGlobalBans();
|
||||
sendJSON(res, gbans);
|
||||
}
|
||||
else if(action == "add") {
|
||||
var ip = params.ip || "";
|
||||
var reason = params.reason || "";
|
||||
if(!ip.match(/\d+\.\d+\.(\d+\.(\d+)?)?/)) {
|
||||
sendJSON(res, {
|
||||
error: "Invalid IP address"
|
||||
});
|
||||
return;
|
||||
}
|
||||
var result = Database.globalBanIP(ip, reason);
|
||||
sendJSON(res, {
|
||||
success: result,
|
||||
ip: ip,
|
||||
reason: reason
|
||||
});
|
||||
}
|
||||
else if(action == "remove") {
|
||||
var ip = params.ip || "";
|
||||
if(!ip.match(/\d+\.\d+\.(\d+\.(\d+)?)?/)) {
|
||||
sendJSON(res, {
|
||||
error: "Invalid IP address"
|
||||
});
|
||||
return;
|
||||
}
|
||||
var result = Database.globalUnbanIP(ip);
|
||||
sendJSON(res, {
|
||||
success: result,
|
||||
ip: ip,
|
||||
});
|
||||
}
|
||||
else {
|
||||
sendJSON(res, {
|
||||
error: "Invalid action: " + action
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdmReports(params, req, res) {
|
||||
sendJSON(res, {
|
||||
error: "Not implemented"
|
||||
});
|
||||
}
|
||||
|
||||
function handleAcpPasswordReset(params, req, res) {
|
||||
var name = params.name || "";
|
||||
var pw = params.pw || "";
|
||||
var session = params.session || "";
|
||||
var row = Auth.login(name, pw, session);
|
||||
if(!row || row.global_rank < 255) {
|
||||
res.send(403);
|
||||
return;
|
||||
}
|
||||
|
||||
var action = params.action || "";
|
||||
if(action == "reset") {
|
||||
var uname = params.reset_name;
|
||||
if(Auth.getGlobalRank(uname) > row.global_rank) {
|
||||
sendJSON(res, {
|
||||
success: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
var new_pw = Database.resetPassword(uname);
|
||||
if(new_pw) {
|
||||
sendJSON(res, {
|
||||
success: true,
|
||||
pw: new_pw
|
||||
});
|
||||
}
|
||||
else {
|
||||
sendJSON(res, {
|
||||
success: false
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
sendJSON(res, {
|
||||
success: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function
|
||||
function pipeLast(res, file, len) {
|
||||
fs.stat(file, function(err, data) {
|
||||
|
@ -599,6 +529,10 @@ function handleReadLog(params, req, res) {
|
|||
else if(type == "err") {
|
||||
pipeLast(res, "error.log", 1024*1024);
|
||||
}
|
||||
else if(type == "action") {
|
||||
ActionLog.flush();
|
||||
pipeLast(res, "action.log", 1024*1024*100);
|
||||
}
|
||||
else if(type == "channel") {
|
||||
var chan = params.channel || "";
|
||||
fs.exists("chanlogs/" + chan + ".log", function(exists) {
|
||||
|
|
8
auth.js
8
auth.js
|
@ -20,7 +20,7 @@ var Logger = require("./logger.js");
|
|||
exports.isRegistered = function(name) {
|
||||
var db = Database.getConnection();
|
||||
if(!db) {
|
||||
return true;
|
||||
throw "Database failure";
|
||||
}
|
||||
var query = Database.createQuery(
|
||||
"SELECT * FROM `registrations` WHERE uname=?",
|
||||
|
@ -90,7 +90,7 @@ exports.login = function(name, pw, session) {
|
|||
exports.loginPassword = function(name, pw) {
|
||||
var db = Database.getConnection();
|
||||
if(!db) {
|
||||
return false;
|
||||
throw "Database failure";
|
||||
}
|
||||
var query = Database.createQuery(
|
||||
"SELECT * FROM `registrations` WHERE uname=?",
|
||||
|
@ -140,7 +140,7 @@ exports.createSession = function(name) {
|
|||
var hash = hashlib.sha256(salt + name);
|
||||
var db = Database.getConnection();
|
||||
if(!db) {
|
||||
return false;
|
||||
throw "Database failure";
|
||||
}
|
||||
var query = Database.createQuery(
|
||||
["UPDATE `registrations` SET ",
|
||||
|
@ -156,7 +156,7 @@ exports.createSession = function(name) {
|
|||
exports.loginSession = function(name, hash) {
|
||||
var db = Database.getConnection();
|
||||
if(!db) {
|
||||
return false;
|
||||
throw "Database failure";
|
||||
}
|
||||
var query = Database.createQuery(
|
||||
"SELECT * FROM `registrations` WHERE `uname`=?",
|
||||
|
|
615
channel.js
615
channel.js
File diff suppressed because it is too large
Load diff
|
@ -32,6 +32,29 @@ function handle(chan, user, msg, data) {
|
|||
chan.chainMessage(user, msg.substring(3), {modflair: user.rank})
|
||||
}
|
||||
}
|
||||
else if(msg.indexOf("/a ") == 0) {
|
||||
if(user.rank >= Rank.Siteadmin) {
|
||||
var flair = {
|
||||
superadminflair: {
|
||||
labelclass: "label-important",
|
||||
icon: "icon-globe"
|
||||
}
|
||||
};
|
||||
var args = msg.substring(3).split(" ");
|
||||
var cargs = [];
|
||||
for(var i = 0; i < args.length; i++) {
|
||||
var a = args[i];
|
||||
if(a.indexOf("!icon-") == 0)
|
||||
flair.superadminflair.icon = a.substring(1);
|
||||
else if(a.indexOf("!label-") == 0)
|
||||
flair.superadminflair.labelclass = a.substring(1);
|
||||
else {
|
||||
cargs.push(a);
|
||||
}
|
||||
}
|
||||
chan.chainMessage(user, cargs.join(" "), flair);
|
||||
}
|
||||
}
|
||||
else if(msg.indexOf("/kick ") == 0) {
|
||||
handleKick(chan, user, msg.substring(6).split(" "));
|
||||
}
|
||||
|
@ -77,29 +100,13 @@ function handleKick(chan, user, args) {
|
|||
}
|
||||
|
||||
function handleIPBan(chan, user, args) {
|
||||
if(chan.hasPermission(user, "ban") && args.length > 0) {
|
||||
args[0] = args[0].toLowerCase();
|
||||
var kickee;
|
||||
for(var i = 0; i < chan.users.length; i++) {
|
||||
if(chan.users[i].name.toLowerCase() == args[0]) {
|
||||
kickee = chan.users[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(kickee) {
|
||||
chan.tryIPBan(user, {
|
||||
id: chan.hideIP(kickee.ip),
|
||||
name: kickee.name
|
||||
});
|
||||
}
|
||||
}
|
||||
chan.tryIPBan(user, args[0], args[1]);
|
||||
// Ban the name too for good measure
|
||||
chan.tryNameBan(user, args[0]);
|
||||
}
|
||||
|
||||
function handleBan(chan, user, args) {
|
||||
if(chan.hasPermission(user, "ban") && args.length > 0) {
|
||||
args[0] = args[0].toLowerCase();
|
||||
chan.banName(user, args[0]);
|
||||
}
|
||||
chan.tryNameBan(user, args[0]);
|
||||
}
|
||||
|
||||
function handleUnban(chan, user, args) {
|
||||
|
|
116
database.js
116
database.js
|
@ -38,7 +38,7 @@ function getConnection() {
|
|||
db = mysql.createConnectionSync();
|
||||
db.connectSync(SERVER, USER, PASSWORD, DATABASE);
|
||||
if(!db.connectedSync()) {
|
||||
//Logger.errlog.log("DB connection failed");
|
||||
Logger.errlog.log("DB connection failed");
|
||||
return false;
|
||||
}
|
||||
if(CONFIG.DEBUG) {
|
||||
|
@ -173,6 +173,19 @@ function init() {
|
|||
if(!results) {
|
||||
Logger.errlog.log("! Failed to create playlist table");
|
||||
}
|
||||
|
||||
// Create user aliases table
|
||||
query = ["CREATE TABLE IF NOT EXISTS `aliases` (",
|
||||
"`visit_id` INT NOT NULL AUTO_INCREMENT,",
|
||||
"`ip` VARCHAR(15) NOT NULL,",
|
||||
"`name` VARCHAR(20) NOT NULL,",
|
||||
"`time` BIGINT NOT NULL,",
|
||||
"PRIMARY KEY (`visit_id`), INDEX (`ip`))",
|
||||
"ENGINE = MyISAM;"].join("");
|
||||
results = db.querySync(query);
|
||||
if(!results) {
|
||||
Logger.errlog.log("! Failed to create aliases table");
|
||||
}
|
||||
}
|
||||
|
||||
/* REGION Global Bans */
|
||||
|
@ -672,6 +685,16 @@ function setUserEmail(name, email) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function genSalt() {
|
||||
var chars = "abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
+ "0123456789!@#$%^&*_+=~";
|
||||
var salt = [];
|
||||
for(var i = 0; i < 32; i++) {
|
||||
salt.push(chars[parseInt(Math.random()*chars.length)]);
|
||||
}
|
||||
return salt.join('');
|
||||
}
|
||||
|
||||
function generatePasswordReset(ip, name, email) {
|
||||
var db = getConnection();
|
||||
if(!db) {
|
||||
|
@ -698,7 +721,7 @@ function generatePasswordReset(ip, name, email) {
|
|||
}
|
||||
|
||||
// Validation complete, now time to reset it
|
||||
var hash = hashlib.sha256(Date.now() + name);
|
||||
var hash = hashlib.sha256(genSalt() + name);
|
||||
var exp = Date.now() + 24*60*60*1000;
|
||||
query = createQuery(
|
||||
["INSERT INTO `password_reset` (",
|
||||
|
@ -885,6 +908,92 @@ function deleteUserPlaylist(user, name) {
|
|||
return results;
|
||||
}
|
||||
|
||||
/* User Aliases */
|
||||
|
||||
function recordVisit(ip, name) {
|
||||
var db = getConnection();
|
||||
if(!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var time = Date.now();
|
||||
db.querySync(createQuery(
|
||||
"DELETE FROM aliases WHERE ip=? AND name=?",
|
||||
[ip, name]
|
||||
));
|
||||
var query = createQuery(
|
||||
"INSERT INTO aliases VALUES (NULL, ?, ?, ?)",
|
||||
[ip, name, time]
|
||||
);
|
||||
|
||||
var results = db.querySync(query);
|
||||
if(!results) {
|
||||
Logger.errlog.log("! Failed to record visit");
|
||||
}
|
||||
|
||||
// Keep most recent 5 records per IP
|
||||
results = db.querySync(createQuery(
|
||||
["DELETE FROM aliases WHERE ip=? AND visit_id NOT IN (",
|
||||
"SELECT visit_id FROM (",
|
||||
"SELECT visit_id,time FROM aliases WHERE ip=? ORDER BY time DESC LIMIT 5",
|
||||
") foo",
|
||||
");"].join(""),
|
||||
[ip, ip]
|
||||
));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function getAliases(ip) {
|
||||
var db = getConnection();
|
||||
if(!db) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var query = createQuery(
|
||||
"SELECT name FROM aliases WHERE ip=?",
|
||||
[ip]
|
||||
);
|
||||
|
||||
var results = db.querySync(query);
|
||||
if(!results) {
|
||||
Logger.errlog.log("! Failed to retrieve aliases");
|
||||
return [];
|
||||
}
|
||||
|
||||
var names = [];
|
||||
results.fetchAllSync().forEach(function(row) {
|
||||
names.push(row.name);
|
||||
});
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
function ipForName(name) {
|
||||
var db = getConnection();
|
||||
if(!db) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var query = createQuery(
|
||||
"SELECT ip FROM aliases WHERE name=?",
|
||||
[name]
|
||||
);
|
||||
|
||||
var results = db.querySync(query);
|
||||
if(!results) {
|
||||
Logger.errlog.log("! Failed to retrieve IP for name");
|
||||
return [];
|
||||
}
|
||||
|
||||
var ips = [];
|
||||
results.fetchAllSync().forEach(function(row) {
|
||||
ips.push(row.ip);
|
||||
});
|
||||
|
||||
return ips;
|
||||
}
|
||||
|
||||
exports.setup = setup;
|
||||
exports.getConnection = getConnection;
|
||||
exports.createQuery = createQuery;
|
||||
|
@ -914,3 +1023,6 @@ exports.getUserPlaylists = getUserPlaylists;
|
|||
exports.loadUserPlaylist = loadUserPlaylist;
|
||||
exports.saveUserPlaylist = saveUserPlaylist;
|
||||
exports.deleteUserPlaylist = deleteUserPlaylist;
|
||||
exports.recordVisit = recordVisit;
|
||||
exports.getAliases = getAliases;
|
||||
exports.ipForName = ipForName;
|
||||
|
|
|
@ -16,6 +16,7 @@ var Filter = function(name, regex, flags, replace) {
|
|||
this.regex = new RegExp(this.source, this.flags);
|
||||
this.replace = replace;
|
||||
this.active = true;
|
||||
this.filterlinks = false;
|
||||
}
|
||||
|
||||
Filter.prototype.pack = function() {
|
||||
|
@ -24,7 +25,8 @@ Filter.prototype.pack = function() {
|
|||
source: this.source,
|
||||
flags: this.flags,
|
||||
replace: this.replace,
|
||||
active: this.active
|
||||
active: this.active,
|
||||
filterlinks: this.filterlinks
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ function newConnection(req, res) {
|
|||
exports.newConnection = newConnection;
|
||||
|
||||
function msgReceived(req, res) {
|
||||
res.callback = req.query.callback;
|
||||
var h = req.params.hash;
|
||||
if(h in clients && clients[h] != null) {
|
||||
var str = req.params.str;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"author": "Calvin Montgomery",
|
||||
"name": "CyTube",
|
||||
"description": "Online media synchronizer and chat",
|
||||
"version": "1.9.5",
|
||||
"version": "2.0.0",
|
||||
"repository": {
|
||||
"url": "http://github.com/calzoneman/sync"
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
const VERSION = "1.9.5";
|
||||
const VERSION = "2.0.0";
|
||||
|
||||
var fs = require("fs");
|
||||
var Logger = require("./logger.js");
|
||||
|
|
259
user.js
259
user.js
|
@ -17,6 +17,8 @@ var Server = require("./server.js");
|
|||
var Database = require("./database.js");
|
||||
var Logger = require("./logger.js");
|
||||
var Config = require("./config.js");
|
||||
var ACP = require("./acp");
|
||||
var ActionLog = require("./actionlog");
|
||||
|
||||
// Represents a client connected via socket.io
|
||||
var User = function(socket, ip) {
|
||||
|
@ -24,6 +26,7 @@ var User = function(socket, ip) {
|
|||
this.socket = socket;
|
||||
this.loggedIn = false;
|
||||
this.rank = Rank.Anonymous;
|
||||
this.global_rank = Rank.Anonymous;
|
||||
this.channel = null;
|
||||
this.name = "";
|
||||
this.meta = {
|
||||
|
@ -206,7 +209,7 @@ User.prototype.initCallbacks = function() {
|
|||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("unqueue", function(data) {
|
||||
this.socket.on("delete", function(data) {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryDequeue(this, data);
|
||||
}
|
||||
|
@ -236,21 +239,21 @@ User.prototype.initCallbacks = function() {
|
|||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("clearqueue", function() {
|
||||
this.socket.on("clearPlaylist", function() {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryClearqueue(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("shufflequeue", function() {
|
||||
this.socket.on("shufflePlaylist", function() {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryShufflequeue(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("queueLock", function(data) {
|
||||
this.socket.on("togglePlaylistLock", function() {
|
||||
if(this.channel != null) {
|
||||
this.channel.trySetLock(this, data);
|
||||
this.channel.tryToggleLock(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
|
@ -260,18 +263,18 @@ User.prototype.initCallbacks = function() {
|
|||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("searchLibrary", function(data) {
|
||||
this.socket.on("searchMedia", function(data) {
|
||||
if(this.channel != null) {
|
||||
if(data.yt) {
|
||||
if(data.source == "yt") {
|
||||
var callback = function(vids) {
|
||||
this.socket.emit("librarySearchResults", {
|
||||
this.socket.emit("searchResults", {
|
||||
results: vids
|
||||
});
|
||||
}.bind(this);
|
||||
this.channel.search(data.query, callback);
|
||||
}
|
||||
else {
|
||||
this.socket.emit("librarySearchResults", {
|
||||
this.socket.emit("searchResults", {
|
||||
results: this.channel.search(data.query)
|
||||
});
|
||||
}
|
||||
|
@ -331,12 +334,6 @@ User.prototype.initCallbacks = function() {
|
|||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("adm", function(data) {
|
||||
if(Rank.hasPermission(this, "acp")) {
|
||||
this.handleAdm(data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("announce", function(data) {
|
||||
if(Rank.hasPermission(this, "announce")) {
|
||||
if(data.clear) {
|
||||
|
@ -349,7 +346,7 @@ User.prototype.initCallbacks = function() {
|
|||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("channelOpts", function(data) {
|
||||
this.socket.on("setOptions", function(data) {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryUpdateOptions(this, data);
|
||||
}
|
||||
|
@ -373,31 +370,53 @@ User.prototype.initCallbacks = function() {
|
|||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("chatFilter", function(data) {
|
||||
this.socket.on("updateFilter", function(data) {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryChangeFilter(this, data);
|
||||
this.channel.tryUpdateFilter(this, data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("updateMotd", function(data) {
|
||||
this.socket.on("removeFilter", function(data) {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryRemoveFilter(this, data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("moveFilter", function(data) {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryMoveFilter(this, data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("setMotd", function(data) {
|
||||
if(this.channel != null) {
|
||||
this.channel.tryUpdateMotd(this, data);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("requestAcl", function() {
|
||||
this.socket.on("requestLoginHistory", function() {
|
||||
if(this.channel != null) {
|
||||
this.channel.sendACL(this);
|
||||
this.noflood("requestAcl", 0.25);
|
||||
this.channel.sendLoginHistory(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("requestSeenlogins", function() {
|
||||
this.socket.on("requestBanlist", function() {
|
||||
if(this.channel != null) {
|
||||
if(this.noflood("requestSeenLogins", 0.25)) {
|
||||
this.channel.sendBanlist(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("requestChatFilters", function() {
|
||||
if(this.channel != null) {
|
||||
this.channel.sendChatFilters(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("requestChannelRanks", function() {
|
||||
if(this.channel != null) {
|
||||
if(this.noflood("requestChannelRanks", 0.25))
|
||||
return;
|
||||
}
|
||||
this.channel.sendSeenLogins(this);
|
||||
this.channel.sendChannelRanks(this);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
|
@ -498,39 +517,29 @@ User.prototype.initCallbacks = function() {
|
|||
pllist: list,
|
||||
});
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// Handle administration
|
||||
User.prototype.handleAdm = function(data) {
|
||||
if(data.cmd == "listchannels") {
|
||||
var chans = [];
|
||||
for(var chan in Server.channels) {
|
||||
var nowplaying = "-";
|
||||
if(Server.channels[chan].media != null)
|
||||
nowplaying = Server.channels[chan].media.title;
|
||||
chans.push({
|
||||
name: chan,
|
||||
usercount: Server.channels[chan].users.length,
|
||||
nowplaying: nowplaying
|
||||
});
|
||||
}
|
||||
this.socket.emit("adm", {
|
||||
cmd: "listchannels",
|
||||
chans: chans
|
||||
});
|
||||
}
|
||||
};
|
||||
this.socket.on("acp-init", function() {
|
||||
if(this.global_rank >= Rank.Siteadmin)
|
||||
ACP.init(this);
|
||||
}.bind(this));
|
||||
|
||||
this.socket.on("borrow-rank", function(rank) {
|
||||
if(this.global_rank < 255)
|
||||
return;
|
||||
if(rank > this.global_rank)
|
||||
return;
|
||||
|
||||
this.rank = rank;
|
||||
this.socket.emit("rank", rank);
|
||||
if(this.channel != null)
|
||||
this.channel.broadcastUserUpdate(this);
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
var lastguestlogin = {};
|
||||
// Attempt to login
|
||||
User.prototype.login = function(name, pw, session) {
|
||||
if(this.channel != null && name != "") {
|
||||
for(var i = 0; i < this.channel.users.length; i++) {
|
||||
if(this.channel.users[i].name == name) {
|
||||
this.channel.kick(this.channel.users[i], "Duplicate login");
|
||||
}
|
||||
}
|
||||
}
|
||||
// No password => try guest login
|
||||
if(pw == "" && session == "") {
|
||||
if(this.ip in lastguestlogin) {
|
||||
|
@ -546,73 +555,99 @@ User.prototype.login = function(name, pw, session) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
// Sorry bud, can't take that name
|
||||
if(Auth.isRegistered(name)) {
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: "That username is already taken"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// YOUR ARGUMENT IS INVALID
|
||||
else if(!Auth.validateName(name)) {
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: "Invalid username. Usernames must be 1-20 characters long and consist only of alphanumeric characters and underscores"
|
||||
});
|
||||
}
|
||||
else {
|
||||
lastguestlogin[this.ip] = Date.now();
|
||||
this.rank = Rank.Guest;
|
||||
Logger.syslog.log(this.ip + " signed in as " + name);
|
||||
this.name = name;
|
||||
this.loggedIn = false;
|
||||
this.socket.emit("login", {
|
||||
success: true
|
||||
});
|
||||
this.socket.emit("rank", {
|
||||
rank: this.rank
|
||||
});
|
||||
if(this.channel != null) {
|
||||
this.channel.logger.log(this.ip + " signed in as " + name);
|
||||
this.channel.broadcastNewUser(this);
|
||||
try {
|
||||
// Sorry bud, can't take that name
|
||||
if(Auth.isRegistered(name)) {
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: "That username is already taken"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// YOUR ARGUMENT IS INVALID
|
||||
else if(!Auth.validateName(name)) {
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: "Invalid username. Usernames must be 1-20 characters long and consist only of alphanumeric characters and underscores"
|
||||
});
|
||||
}
|
||||
else {
|
||||
lastguestlogin[this.ip] = Date.now();
|
||||
this.rank = Rank.Guest;
|
||||
Logger.syslog.log(this.ip + " signed in as " + name);
|
||||
Database.recordVisit(this.ip, name);
|
||||
this.name = name;
|
||||
this.loggedIn = false;
|
||||
this.socket.emit("login", {
|
||||
success: true,
|
||||
name: name
|
||||
});
|
||||
this.socket.emit("rank", this.rank);
|
||||
if(this.channel != null) {
|
||||
this.channel.logger.log(this.ip + " signed in as " + name);
|
||||
this.channel.broadcastNewUser(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: e
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
var row;
|
||||
if((row = Auth.login(name, pw, session))) {
|
||||
this.loggedIn = true;
|
||||
this.socket.emit("login", {
|
||||
success: true,
|
||||
session: row.session_hash
|
||||
});
|
||||
Logger.syslog.log(this.ip + " logged in as " + name);
|
||||
this.profile = {
|
||||
image: row.profile_image,
|
||||
text: row.profile_text
|
||||
};
|
||||
var chanrank = (this.channel != null) ? this.channel.getRank(name)
|
||||
: Rank.Guest;
|
||||
var rank = (chanrank > row.global_rank) ? chanrank
|
||||
: row.global_rank;
|
||||
this.rank = (this.rank > rank) ? this.rank : rank;
|
||||
this.socket.emit("rank", {
|
||||
rank: this.rank
|
||||
});
|
||||
this.name = name;
|
||||
if(this.channel != null) {
|
||||
this.channel.logger.log(this.ip + " logged in as " + name);
|
||||
this.channel.broadcastNewUser(this);
|
||||
try {
|
||||
var row;
|
||||
if((row = Auth.login(name, pw, session))) {
|
||||
if(this.channel != null) {
|
||||
for(var i = 0; i < this.channel.users.length; i++) {
|
||||
if(this.channel.users[i].name == name) {
|
||||
this.channel.kick(this.channel.users[i], "Duplicate login");
|
||||
}
|
||||
}
|
||||
}
|
||||
ActionLog.record(this.ip, name, "login-success");
|
||||
this.loggedIn = true;
|
||||
this.socket.emit("login", {
|
||||
success: true,
|
||||
session: row.session_hash,
|
||||
name: name
|
||||
});
|
||||
Logger.syslog.log(this.ip + " logged in as " + name);
|
||||
Database.recordVisit(this.ip, name);
|
||||
this.profile = {
|
||||
image: row.profile_image,
|
||||
text: row.profile_text
|
||||
};
|
||||
var chanrank = (this.channel != null) ? this.channel.getRank(name)
|
||||
: Rank.Guest;
|
||||
var rank = (chanrank > row.global_rank) ? chanrank
|
||||
: row.global_rank;
|
||||
this.rank = (this.rank > rank) ? this.rank : rank;
|
||||
this.global_rank = row.global_rank;
|
||||
this.socket.emit("rank", this.rank);
|
||||
this.name = name;
|
||||
if(this.channel != null) {
|
||||
this.channel.logger.log(this.ip + " logged in as " + name);
|
||||
this.channel.broadcastNewUser(this);
|
||||
}
|
||||
}
|
||||
// Wrong password
|
||||
else {
|
||||
ActionLog.record(this.ip, this.name, "login-failure");
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: "Invalid session"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Wrong password
|
||||
else {
|
||||
catch(e) {
|
||||
this.socket.emit("login", {
|
||||
success: false,
|
||||
error: "Invalid session"
|
||||
error: e
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<div class="">
|
||||
<ul class="nav">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="help.html">Help</a></li>
|
||||
<li><a href="https://github.com/calzoneman/sync/wiki/Beginner%27s-Guide-and-FAQ" target="_blank">Help</a></li>
|
||||
<li class="active"><a href="account.html">Account</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
327
www/acp.html
327
www/acp.html
|
@ -13,13 +13,6 @@
|
|||
body {
|
||||
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
||||
}
|
||||
.loginform {
|
||||
margin: 100px auto 20px;
|
||||
padding: 19px 29px 29px;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
border: 1px solid #dedede;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
#log {
|
||||
max-height: 500px;
|
||||
|
@ -39,31 +32,43 @@
|
|||
<div class="">
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="index.html">Home</a></li>
|
||||
<li><a href="help.html">Help</a></li>
|
||||
<li><a href="javascript:void(0)" id="optlink">Options</a></li>
|
||||
</ul>
|
||||
<div class="navbar-form pull-right" id="loginform">
|
||||
<button class="btn" id="login">Login</button>
|
||||
</div>
|
||||
<div class="navbar-form pull-right" id="logoutform" style="display: none;">
|
||||
<span id="welcome"></span>
|
||||
<button class="btn" id="logout">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<div class="row">
|
||||
<div id="loggedin" class="span6" style="display: none;">
|
||||
<h3 id="welcome"></h3>
|
||||
<div class="span12">
|
||||
<div class="btn-group">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">
|
||||
<span id="menudd_title">Menu</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" id="menudd">
|
||||
<li id="li_logview"><a href="javascript:void(0)" id="show_logview">Log Viewer</a></li>
|
||||
<li id="li_announce"><a href="javascript:void(0)" id="show_announce">Announcement Manager</a></li>
|
||||
<li id="li_gbans"><a href="javascript:void(0)" id="show_gbans">Global Bans</a></li>
|
||||
<li id="li_userlookup"><a href="javascript:void(0)" id="show_userlookup">Users</a></li>
|
||||
<li id="li_chanloaded"><a href="javascript:void(0)" id="show_chanloaded">Loaded Channels</a></li>
|
||||
<li id="li_actionlog"><a href="javascript:void(0)" id="show_actionlog">Action Log</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<form class="form-horizontal loginform" action="javascript:void(0);">
|
||||
<div class="control-group">
|
||||
<input id="name" type="text" placeholder="Username" class="input-block-level">
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<input id="pw" type="password" placeholder="Password" class="input-block-level">
|
||||
</div>
|
||||
<button id="login" class="btn btn-block">Authenticate</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
|
||||
<div class="row" id="panels">
|
||||
<div class="span12" id="logview">
|
||||
<h3>Log Viewer</h3>
|
||||
<form class="form-inline" action="javascript:void(0);">
|
||||
<button id="syslog" class="btn">Syslog</button>
|
||||
|
@ -75,30 +80,124 @@
|
|||
</form>
|
||||
<pre id="log"></pre>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<h3>Password Reset</h3>
|
||||
<form class="form-inline" action="javascript:void(0)">
|
||||
<div class="input-append">
|
||||
<input type="text" id="reset_uname" placeholder="Username">
|
||||
<button class="btn" id="reset_pw">Reset</button>
|
||||
<div class="span12" id="announcepanel">
|
||||
<h3 id="announce_current_h3">Current Announcement</h3>
|
||||
<h3>New Announcement</h3>
|
||||
<form class="form-horizontal" action="javascript:void(0)">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="announce_title">
|
||||
Title
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" id="announce_title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="announce_text">
|
||||
Body (HTML)
|
||||
</label>
|
||||
<div class="controls">
|
||||
<textarea class="input-block-level" rows="15" id="announce_text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button class="btn btn-primary" id="announce_submit">Announce</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<div class="span12" id="gbanpanel">
|
||||
<h3>Global Bans</h3>
|
||||
<table id="banlist" class="table table-striped table-bordered">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>IP</th>
|
||||
<th>Reason</th>
|
||||
<th style="width: 80px;">Remove</th>
|
||||
<th style="width: 160px;">IP Address</th>
|
||||
<th>Note</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<h3>Add global ban</h3>
|
||||
<form class="form-horizontal" action="javascript:void(0)">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="gban_ip">
|
||||
IP address
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="gban_ip">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="gban_note">
|
||||
Note
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="gban_note">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button class="btn btn-primary" id="gban_submit">Add Ban</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="span12" id="userlookup">
|
||||
<h3>Users</h3>
|
||||
<form class="form-inline" action="javascript:void(0)">
|
||||
<input type="text" id="userlookup_name" placeholder="Name">
|
||||
<button class="btn" id="userlookup_submit">Search</button>
|
||||
</form>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="userlookup_uid">UID</th>
|
||||
<th id="userlookup_uname">Name</th>
|
||||
<th id="userlookup_rank">Global Rank</th>
|
||||
<th id="userlookup_email">Email</th>
|
||||
<th>Password Reset</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="span12" id="channellist">
|
||||
<h3>Loaded Channels</h3>
|
||||
<button class="btn" id="listloaded_refresh">Refresh</button>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>User Count</th>
|
||||
<th>Now Playing</th>
|
||||
<th>Registered</th>
|
||||
<th>Public</th>
|
||||
<th>Force Unload</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="span12" id="actionlog">
|
||||
<h3>Action Log</h3>
|
||||
<select multiple="multiple" id="actionlog_filter">
|
||||
</select>
|
||||
<button class="btn btn-danger" id="actionlog_clear">Clear Selected</button>
|
||||
<button class="btn" id="actionlog_refresh">Refresh</button>
|
||||
<table class="table table-bordered table-striped table-compact">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="actionlog_ip">IP Address</th>
|
||||
<th id="actionlog_name">Name</th>
|
||||
<th id="actionlog_action">Action</th>
|
||||
<th>Args</th>
|
||||
<th id="actionlog_time">Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
<div class="push"></div>
|
||||
<div id="sitefooter">
|
||||
|
@ -120,160 +219,8 @@
|
|||
|
||||
<!-- Mine -->
|
||||
<script src="./assets/js/iourl.js"></script>
|
||||
<script type="text/javascript">
|
||||
var host = document.location+"";
|
||||
host = host.replace("http://", "");
|
||||
if(host.indexOf("/") != -1)
|
||||
host = host.substring(0, host.indexOf("/"));
|
||||
host = "http://" + host;
|
||||
var session = readCookie("sync_session") || "";
|
||||
var uname = readCookie("sync_uname") || "";
|
||||
var p = "";
|
||||
if(uname && session) {
|
||||
$.getJSON(WEB_URL+"/api/json/login?name="+uname+"&session="+session+"&callback=?", function(data) {
|
||||
if(data.success) {
|
||||
$(".loginform").remove();
|
||||
createCookie("sync_uname", uname, 7);
|
||||
createCookie("sync_session", session, 7);
|
||||
p = "name=" + uname + "&session=" + session;
|
||||
loadBanlist();
|
||||
}
|
||||
});
|
||||
}
|
||||
var q = "";
|
||||
$("#login").click(function() {
|
||||
uname = $("#name").val();
|
||||
q = "name=" + $("#name").val() + "&pw=" + $("#pw").val();
|
||||
$.getJSON(WEB_URL+"/api/json/login?"+q+"&callback=?", function(data) {
|
||||
console.log(data);
|
||||
if(data.success) {
|
||||
$(".loginform").remove();
|
||||
session = data.session;
|
||||
createCookie("sync_uname", uname, 7);
|
||||
createCookie("sync_session", session, 7);
|
||||
p = "name=" + uname + "&session=" + session;
|
||||
loadBanlist();
|
||||
}
|
||||
});
|
||||
});
|
||||
function getSyslog() {
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=sys&"+p).done(function(data) {
|
||||
$("#log").text(data);
|
||||
});
|
||||
}
|
||||
$("#syslog").click(getSyslog);
|
||||
function getErrlog() {
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=err&"+p).done(function(data) {
|
||||
$("#log").text(data);
|
||||
});
|
||||
}
|
||||
$("#errlog").click(getErrlog);
|
||||
function getChanlog() {
|
||||
var chan = $("#channame").val();
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=channel&channel="+chan+"&"+p).done(function(data) {
|
||||
$("#log").text(data);
|
||||
});
|
||||
}
|
||||
$("#chanlog").click(getChanlog);
|
||||
$("#channame").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
getChanlog();
|
||||
}
|
||||
});
|
||||
|
||||
$("#reset_pw").click(function() {
|
||||
$.getJSON(WEB_URL+"/api/json/pwreset?action=reset&reset_name="+$("#reset_uname").val()+"&"+p+"&callback=?", function(data) {
|
||||
if(data.success) {
|
||||
alert("Success. New password: " + data.pw);
|
||||
}
|
||||
else {
|
||||
alert("Failure.");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
function loadBanlist() {
|
||||
$.getJSON(WEB_URL+"/api/json/globalbans?action=list&"+p+"&callback=?", function(data) {
|
||||
handleBanlist(data);
|
||||
});
|
||||
}
|
||||
function handleBanlist(data) {
|
||||
var tbl = $("#banlist");
|
||||
if(tbl.children().length > 1) {
|
||||
$(tbl.children()[1]).remove();
|
||||
}
|
||||
for(var ip in data) {
|
||||
var tr = $("<tr/>").appendTo($("#banlist"));
|
||||
var btntd = $("<td/>").appendTo(tr);
|
||||
var remove = $("<button/>").addClass("btn btn-danger")
|
||||
.appendTo(btntd);
|
||||
$("<i/>").addClass("icon-minus").appendTo(remove);
|
||||
remove.click(function(ip) { return function() {
|
||||
var b = "ip=" + ip;
|
||||
$.getJSON(WEB_URL+"/api/json/globalbans?action=remove&"+b+"&"+p+"&callback=?", function(data) {
|
||||
if(data.error) {
|
||||
alert(data.error);
|
||||
}
|
||||
else if(!data.success) {
|
||||
alert("Remove ban failed");
|
||||
}
|
||||
loadBanlist();
|
||||
});
|
||||
} }(ip));
|
||||
var iptd = $("<td/>").appendTo(tr);
|
||||
$("<code/>").text(ip).appendTo(iptd);
|
||||
var reason = $("<td/>").appendTo(tr);
|
||||
$("<code/>").text(data[ip]).appendTo(reason);
|
||||
}
|
||||
// Add new
|
||||
var tr = $("<tr/>").appendTo($("#banlist"));
|
||||
var add = $("<button/>").addClass("btn btn-success")
|
||||
.appendTo($("<td/>").appendTo(tr));
|
||||
$("<i/>").addClass("icon-plus").appendTo(add);
|
||||
var ip = $("<input/>").attr("type", "text")
|
||||
.appendTo($("<td/>").appendTo(tr));
|
||||
var reason = $("<input/>").attr("type", "text")
|
||||
.appendTo($("<td/>").appendTo(tr));
|
||||
|
||||
add.click(function() {
|
||||
var b = "ip=" + ip.val() + "&reason=" + reason.val();
|
||||
$.getJSON(WEB_URL+"/api/json/globalbans?action=add&"+b+"&"+p+"&callback=?", function(data) {
|
||||
if(data.error) {
|
||||
alert(data.error);
|
||||
}
|
||||
else if(!data.success) {
|
||||
alert("Add ban failed");
|
||||
}
|
||||
loadBanlist();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createCookie(name,value,days) {
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
var expires = "; expires="+date.toGMTString();
|
||||
}
|
||||
else var expires = "";
|
||||
document.cookie = name+"="+value+expires+"; path=/";
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(";");
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==" ") c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function eraseCookie(name) {
|
||||
createCookie(name,"",-1);
|
||||
}
|
||||
</script>
|
||||
<script src="./assets/js/data.js"></script>
|
||||
<script src="./assets/js/util.js"></script>
|
||||
<script src="./assets/js/acp.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -153,7 +153,7 @@ textarea::-webkit-input-placeholder {
|
|||
/* line 18, ../bootstrap/bootstrap/_sprites.scss */
|
||||
[class^="icon-"],
|
||||
[class*=" icon-"] {
|
||||
background-image: url("../img/glyphicons-halflings.png");
|
||||
background-image: url("../img/glyphicons-halflings-white.png");
|
||||
}
|
||||
|
||||
/* White icons with optional class, or on hover/active states of certain elements */
|
||||
|
@ -946,6 +946,19 @@ select:focus:invalid:focus {
|
|||
color: #ff9900;
|
||||
}
|
||||
|
||||
#usercountwrap, #currenttitle, #videowrap {
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
.queue_entry {
|
||||
background-color: #111111;
|
||||
}
|
||||
|
||||
.queue_active {
|
||||
border-color: #ff9900;
|
||||
background-color: #332200;
|
||||
}
|
||||
|
||||
#plmeta {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
|
26
www/assets/css/semidark.css
Normal file
26
www/assets/css/semidark.css
Normal file
|
@ -0,0 +1,26 @@
|
|||
body, #videowrap {
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
.queue_entry {
|
||||
background-color: #111111;
|
||||
}
|
||||
|
||||
.queue_active {
|
||||
border-color: #ff9900;
|
||||
background-color: #332200;
|
||||
}
|
||||
|
||||
#currenttitle {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.qe_time {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
#plmeta {
|
||||
color: #cccccc;
|
||||
background-color: #2f2f2f;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
|
@ -1,271 +1,324 @@
|
|||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
margin: 0 auto -90px;
|
||||
}
|
||||
|
||||
#footer, .push {
|
||||
margin: 90px 0 0 0;
|
||||
height: 30px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#welcome {
|
||||
font-size: 10pt;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.videolist {
|
||||
list-style: none outside none;
|
||||
margin-left: 0;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.videolist li {
|
||||
margin: 2px 0 0 auto;
|
||||
padding: 2px;
|
||||
font-size: 8pt;
|
||||
border: 1px solid #aaaaaa; // [](/w21)
|
||||
}
|
||||
|
||||
.qe_btn {
|
||||
height: 20px;
|
||||
font-family: Monospace;
|
||||
padding: 0 5px 0 5px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.qe_buttons {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.qe_title {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.qe_time {
|
||||
font-family: Monospace;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.qe_clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#userpl_list {
|
||||
list-style: none outside none;
|
||||
margin-left: 0;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#userpl_list li {
|
||||
clear: both;
|
||||
margin: 2px 0 0 auto;
|
||||
padding: 2px;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
#queue {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#usercountcontainer, #currenttitle {
|
||||
border: 1px solid #aaaaaa;
|
||||
border-bottom: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#usercount {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#ulistchevron {
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#plmeta {
|
||||
border: 1px solid #aaaaaa;
|
||||
background-color: #ffffff;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
#plcount {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#pllength {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#userlist {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 347px;
|
||||
float: left;
|
||||
width: 150px;
|
||||
border: 1px solid #aaaaaa; // [](/z13)
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#messagebuffer {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 347px;
|
||||
border: 1px solid #aaaaaa; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#messagebuffer div, #messagebuffer code {
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
.userlist_siteadmin {
|
||||
color: #cc0000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.userlist_owner {
|
||||
color: #0000cc;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.userlist_op {
|
||||
color: #00aa00;
|
||||
}
|
||||
|
||||
.userlist_guest {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.action {
|
||||
font-style: italic;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
color: #000000;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.spoiler:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.greentext {
|
||||
color: #789922; /* Color value directly from 4chan */
|
||||
}
|
||||
|
||||
.shout {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
.server-msg-disconnect {
|
||||
border: 1px solid #ff0000;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.server-msg-reconnect {
|
||||
border: 1px solid #009900;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
color: #009900;
|
||||
}
|
||||
|
||||
.poll-notify {
|
||||
color: #0000aa;
|
||||
font-weight: bold;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
.option button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.nick-highlight {
|
||||
background-color: #ddffdd;
|
||||
}
|
||||
|
||||
.nick-hover {
|
||||
background-color: #ffff99;
|
||||
}
|
||||
|
||||
.drink {
|
||||
margin: 10px 10px;
|
||||
padding: 10px 0px;
|
||||
border: 2px solid #0000cc;
|
||||
}
|
||||
|
||||
#drinkbar {
|
||||
margin-left: 0;
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#motdtext, #csstext, #jstext {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#csstext, #jstext {
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
#queue_next, #queue_end, #library_search, #youtube_search {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#footer {
|
||||
background-color: #f5f5f5;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#footer p {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
.profile-box {
|
||||
z-index: 9999;
|
||||
position: absolute;
|
||||
border: 1px solid #aaaaaa;
|
||||
border-radius: 5px;
|
||||
background-color: #ffffff;
|
||||
max-width: 200px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.profile-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px solid #aaaaaa;
|
||||
border-radius: 5px;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
margin: 0 auto -90px;
|
||||
}
|
||||
|
||||
#footer, .push {
|
||||
margin: 90px 0 0 0;
|
||||
height: 30px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#welcome {
|
||||
font-size: 10pt;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#usercountwrap, #userlist, #messagebuffer, #videowrap {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#librarywrap, #userplaylistwrap, #playlist_controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.videolist {
|
||||
list-style: none outside none;
|
||||
margin-left: 0;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.qe_btn {
|
||||
height: 20px;
|
||||
font-family: Monospace;
|
||||
padding: 0 5px 0 5px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.qe_buttons {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.qe_title {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.qe_time {
|
||||
font-family: Monospace;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.qe_clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#userpl_list {
|
||||
list-style: none outside none;
|
||||
margin-left: 0;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#userpl_list li {
|
||||
clear: both;
|
||||
margin: 2px 0 0 auto;
|
||||
padding: 2px;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
#usercountwrap, #currenttitle {
|
||||
border: 1px solid #aaaaaa;
|
||||
border-bottom: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#usercount {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#leftpane-inner div.span12, #rightpane-inner div.span12,
|
||||
#leftpane-inner ul, #rightpane-inner ul,
|
||||
#channelsettingswrap div.span12 {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#queue {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.queue_sortable li {
|
||||
cursor: row-resize;
|
||||
}
|
||||
|
||||
.queue_entry {
|
||||
background-color: #ffffff;
|
||||
margin: 2px 0 0 auto;
|
||||
padding: 2px;
|
||||
font-size: 8pt;
|
||||
border: 1px solid #aaaaaa; // [](/w21)
|
||||
}
|
||||
|
||||
.queue_temp {
|
||||
background-image: url(../img/stripe-diagonal.png);
|
||||
}
|
||||
|
||||
.queue_active {
|
||||
background-color: #d9edf7;
|
||||
border-color: #bce8f1;
|
||||
}
|
||||
|
||||
#plmeta {
|
||||
border: 1px solid #aaaaaa;
|
||||
border-top: 0;
|
||||
background-color: #ffffff;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
#plcount {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#pllength {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#userlist {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 347px;
|
||||
float: left;
|
||||
width: 150px;
|
||||
border: 1px solid #aaaaaa; // [](/z13)
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#messagebuffer {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 347px;
|
||||
border: 1px solid #aaaaaa; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#messagebuffer div, #messagebuffer code, #filteredit code {
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
#filteredit td {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.userlist_siteadmin {
|
||||
color: #cc0000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.userlist_owner {
|
||||
color: #0000cc;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.userlist_op {
|
||||
color: #00aa00;
|
||||
}
|
||||
|
||||
.userlist_guest {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.action {
|
||||
font-style: italic;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.server-whisper {
|
||||
font-style: italic;
|
||||
color: #888888;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
color: #000000;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.spoiler:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.greentext {
|
||||
color: #789922; /* Color value directly from 4chan */
|
||||
}
|
||||
|
||||
.shout {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
.server-msg-disconnect {
|
||||
border: 1px solid #ff0000;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.server-msg-reconnect {
|
||||
border: 1px solid #009900;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
color: #009900;
|
||||
}
|
||||
|
||||
.poll-notify {
|
||||
color: #0000aa;
|
||||
font-weight: bold;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
.option button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.nick-highlight {
|
||||
background-color: #ddffdd;
|
||||
}
|
||||
|
||||
.nick-hover {
|
||||
background-color: #ffff99;
|
||||
}
|
||||
|
||||
.drink {
|
||||
margin: 10px 10px;
|
||||
padding: 10px 0px;
|
||||
border: 2px solid #0000cc;
|
||||
}
|
||||
|
||||
#drinkbar {
|
||||
margin-left: 0;
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#motdtext, #csstext, #jstext {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#csstext, #jstext {
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
#queue_next, #queue_end, #library_search, #youtube_search {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#footer {
|
||||
background-color: #f5f5f5;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#footer p {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
.profile-box {
|
||||
z-index: 9999;
|
||||
position: absolute;
|
||||
border: 1px solid #aaaaaa;
|
||||
border-radius: 5px;
|
||||
background-color: #ffffff;
|
||||
max-width: 200px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.user-dropdown {
|
||||
z-index: 9999;
|
||||
position: absolute;
|
||||
border: 1px solid #aaaaaa;
|
||||
border-radius: 5px;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
max-width: 200px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.profile-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px solid #aaaaaa;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#channelsettingswrap3 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
|
BIN
www/assets/img/stripe-diagonal.png
Normal file
BIN
www/assets/img/stripe-diagonal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 206 B |
|
@ -9,8 +9,8 @@ The above copyright notice and this permission notice shall be included in all c
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
var uname = readCookie("sync_uname") || "";
|
||||
var session = readCookie("sync_session") || "";
|
||||
var uname = readCookie("cytube_uname") || "";
|
||||
var session = readCookie("cytube_session") || "";
|
||||
var api = WEB_URL + "/api/json/";
|
||||
var loggedin = false;
|
||||
|
||||
|
@ -31,8 +31,8 @@ function onLogin() {
|
|||
$("#register").hide();
|
||||
loggedin = true;
|
||||
$("#login").text("Logout");
|
||||
createCookie("sync_uname", uname, 7);
|
||||
createCookie("sync_session", session, 7);
|
||||
createCookie("cytube_uname", uname, 7);
|
||||
createCookie("cytube_session", session, 7);
|
||||
}
|
||||
|
||||
function makeTabCallback(tabid, paneid) {
|
||||
|
@ -341,8 +341,8 @@ $("#login").click(function() {
|
|||
else {
|
||||
uname = "";
|
||||
session = "";
|
||||
eraseCookie("sync_uname");
|
||||
eraseCookie("sync_session");
|
||||
eraseCookie("cytube_uname");
|
||||
eraseCookie("cytube_session");
|
||||
$("#accountnav li")[0].innerHTML = "Not Logged In";
|
||||
$("#register").show();
|
||||
$("#login").text("Login");
|
||||
|
|
|
@ -1,113 +1,441 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
var BASE = WEB_URL + "/api/json/";
|
||||
var AUTH = "";
|
||||
|
||||
var RANK = 0;
|
||||
var uname = readCookie("sync_uname");
|
||||
var pw = readCookie("sync_pw");
|
||||
var manageChannel = false;
|
||||
|
||||
var Rank = {
|
||||
Guest: 0,
|
||||
Member: 1,
|
||||
Moderator: 2,
|
||||
Owner: 3,
|
||||
Siteadmin: 255
|
||||
};
|
||||
|
||||
var socket = io.connect(IO_URL);
|
||||
initCallbacks();
|
||||
|
||||
function initCallbacks() {
|
||||
|
||||
socket.on("adm", function(data) {
|
||||
console.log(data);
|
||||
if(data.cmd == "listchannels")
|
||||
handleChannelList(data);
|
||||
});
|
||||
|
||||
socket.on("login", function(data) {
|
||||
if(data.success && $("#password").val()) {
|
||||
createCookie("sync_uname", uname, 1);
|
||||
createCookie("sync_pw", pw, 1);
|
||||
/* init socket connection */
|
||||
$.getScript(IO_URL+"/socket.io/socket.io.js", function() {
|
||||
try {
|
||||
if(NO_WEBSOCKETS) {
|
||||
var i = io.transports.indexOf("websocket");
|
||||
if(i >= 0)
|
||||
io.transports.splice(i, 1);
|
||||
}
|
||||
if(data.success) {
|
||||
$("#loggedin").css("display", "");
|
||||
$("#logoutform").css("display", "");
|
||||
$("#loginform").css("display", "none");
|
||||
}
|
||||
setInterval(function() {
|
||||
socket.emit("adm", {
|
||||
cmd: "listchannels"
|
||||
});
|
||||
}, 10000);
|
||||
socket.emit("adm", {
|
||||
cmd: "listchannels"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleChannelList(data) {
|
||||
if($("#chanlist").children.length > 1)
|
||||
$($("#chanlist").children()[1]).remove();
|
||||
for(var i = 0; i < data.chans.length; i++) {
|
||||
var row = $("<tr/>").appendTo($("#chanlist"));
|
||||
var name = $("<td/>").appendTo(row).text(data.chans[i].name);
|
||||
var usercount = $("<td/>").appendTo(row).text(data.chans[i].usercount);
|
||||
var nowplaying = $("<td/>").appendTo(row).text(data.chans[i].nowplaying);
|
||||
socket = io.connect(IO_URL);
|
||||
setupCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
var params = {};
|
||||
if(window.location.search) {
|
||||
var parameters = window.location.search.substring(1).split("&");
|
||||
for(var i = 0; i < parameters.length; i++) {
|
||||
var s = parameters[i].split("=");
|
||||
if(s.length != 2)
|
||||
continue;
|
||||
params[s[0]] = s[1];
|
||||
catch(e) {
|
||||
Callbacks.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if(uname != null && pw != null && pw != "false") {
|
||||
socket.emit("login", {
|
||||
name: uname,
|
||||
pw: pw
|
||||
});
|
||||
}
|
||||
|
||||
function loginClick() {
|
||||
uname = $("#username").val();
|
||||
pw = $("#password").val();
|
||||
socket.emit("login", {
|
||||
name: uname,
|
||||
pw: pw
|
||||
});
|
||||
};
|
||||
|
||||
$("#login").click(loginClick);
|
||||
$("#username").keydown(function(ev) {
|
||||
if(ev.key == 13)
|
||||
loginClick();
|
||||
});
|
||||
$("#password").keydown(function(ev) {
|
||||
if(ev.key == 13)
|
||||
loginClick();
|
||||
});
|
||||
|
||||
$("#login").click(showLoginMenu);
|
||||
$("#logout").click(function() {
|
||||
eraseCookie("sync_uname");
|
||||
eraseCookie("sync_pw");
|
||||
eraseCookie("cytube_uname");
|
||||
eraseCookie("cytube_session");
|
||||
document.location.reload(true);
|
||||
});
|
||||
|
||||
$("#panels .span12").each(function() {
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
function menuHandler(liselect, panelselect) {
|
||||
$(liselect).click(function() {
|
||||
$("#panels .span12").each(function() {
|
||||
$(this).hide();
|
||||
});
|
||||
$(panelselect).show();
|
||||
$("#menudd_title").text($(liselect).text());
|
||||
});
|
||||
}
|
||||
|
||||
menuHandler("#show_logview", "#logview");
|
||||
menuHandler("#show_announce", "#announcepanel");
|
||||
menuHandler("#show_gbans", "#gbanpanel");
|
||||
menuHandler("#show_userlookup", "#userlookup");
|
||||
function tableResort(tbl, sortby) {
|
||||
if(tbl.data("sortby") == sortby)
|
||||
tbl.data("sort_desc", !tbl.data("sort_desc"));
|
||||
else
|
||||
tbl.data("sortby", sortby)
|
||||
loadPage(tbl, 0);
|
||||
}
|
||||
$("#userlookup_uid").click(function() {
|
||||
tableResort($("#userlookup table"), "id");
|
||||
});
|
||||
$("#userlookup_uname").click(function() {
|
||||
tableResort($("#userlookup table"), "uname");
|
||||
});
|
||||
$("#userlookup_rank").click(function() {
|
||||
tableResort($("#userlookup table"), "global_rank");
|
||||
});
|
||||
$("#userlookup_email").click(function() {
|
||||
tableResort($("#userlookup table"), "email");
|
||||
});
|
||||
|
||||
menuHandler("#show_chanloaded", "#channellist");
|
||||
$("#show_chanloaded").click(function() {
|
||||
socket.emit("acp-list-loaded");
|
||||
});
|
||||
$("#listloaded_refresh").click(function() {
|
||||
socket.emit("acp-list-loaded");
|
||||
});
|
||||
menuHandler("#show_actionlog", "#actionlog");
|
||||
$("#show_actionlog").click(getActionLog);
|
||||
$("#actionlog_filter").click(function() {
|
||||
var actions = $(this).val();
|
||||
$("#actionlog tbody").remove();
|
||||
var entries = [];
|
||||
$("#actionlog table").data("allentries").forEach(function(e) {
|
||||
if(actions.indexOf(e.action) == -1)
|
||||
return;
|
||||
entries.push(e);
|
||||
});
|
||||
$("#actionlog_pagination").remove();
|
||||
if(entries.length > 20) {
|
||||
var pag = $("<div/>").addClass("pagination")
|
||||
.attr("id", "actionlog_pagination")
|
||||
.insertAfter($("#actionlog table"));
|
||||
var btns = $("<ul/>").appendTo(pag);
|
||||
for(var i = 0; i < data.length / 20; i++) {
|
||||
var li = $("<li/>").appendTo(btns);
|
||||
(function(i) {
|
||||
$("<a/>").attr("href", "javascript:void(0)")
|
||||
.text(i+1)
|
||||
.click(function() {
|
||||
loadPage(tbl, i);
|
||||
})
|
||||
.appendTo(li);
|
||||
})(i);
|
||||
}
|
||||
tbl.data("pagination", pag);
|
||||
}
|
||||
|
||||
$("#actionlog table").data("entries", entries);
|
||||
loadPage($("#actionlog table"), 0);
|
||||
});
|
||||
$("#actionlog_clear").click(function() {
|
||||
socket.emit("acp-actionlog-clear", $("#actionlog_filter").val());
|
||||
getActionLog();
|
||||
});
|
||||
$("#actionlog_refresh").click(function() {
|
||||
getActionLog();
|
||||
});
|
||||
$("#actionlog_ip").click(function() {
|
||||
tableResort($("#actionlog table"), "ip");
|
||||
});
|
||||
$("#actionlog_name").click(function() {
|
||||
tableResort($("#actionlog table"), "name");
|
||||
});
|
||||
$("#actionlog_action").click(function() {
|
||||
tableResort($("#actionlog table"), "action");
|
||||
});
|
||||
$("#actionlog_time").click(function() {
|
||||
tableResort($("#actionlog table"), "time");
|
||||
});
|
||||
|
||||
function getSyslog() {
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=sys&"+AUTH).done(function(data) {
|
||||
$("#log").text(data);
|
||||
});
|
||||
}
|
||||
$("#syslog").click(getSyslog);
|
||||
function getErrlog() {
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=err&"+AUTH).done(function(data) {
|
||||
$("#log").text(data);
|
||||
});
|
||||
}
|
||||
$("#errlog").click(getErrlog);
|
||||
function getActionLog() {
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=action&"+AUTH).done(function(data) {
|
||||
var entries = [];
|
||||
var actions = [];
|
||||
data.split("\n").forEach(function(ln) {
|
||||
var entry;
|
||||
try {
|
||||
entry = JSON.parse(ln);
|
||||
if(actions.indexOf(entry.action) == -1)
|
||||
actions.push(entry.action);
|
||||
entries.push(entry);
|
||||
}
|
||||
catch(e) { }
|
||||
});
|
||||
var tbl = $("#actionlog table");
|
||||
tbl.data("sortby", "time");
|
||||
tbl.data("sort_desc", true);
|
||||
tbl.data("entries", entries);
|
||||
tbl.data("allentries", entries);
|
||||
tbl.data("generator", function(e) {
|
||||
var tr = $("<tr/>").appendTo($("#actionlog table"));
|
||||
$("<td/>").text(e.ip).appendTo(tr);
|
||||
$("<td/>").text(e.name).appendTo(tr);
|
||||
$("<td/>").text(e.action).appendTo(tr);
|
||||
$("<td/>").text(e.args.join(", ")).appendTo(tr);
|
||||
$("<td/>").text(new Date(e.time).toTimeString()).appendTo(tr);
|
||||
});
|
||||
$("#actionlog table").data("entries", entries);
|
||||
$("#actionlog_filter").html("");
|
||||
actions.sort(function(a, b) {
|
||||
return a == b ? 0 : (a < b ? -1 : 1);
|
||||
});
|
||||
actions.forEach(function(a) {
|
||||
$("<option/>").text(a).val(a).appendTo($("#actionlog_filter"));
|
||||
});
|
||||
loadPage(tbl, 0);
|
||||
});
|
||||
}
|
||||
function getChanlog() {
|
||||
var chan = $("#channame").val();
|
||||
$.ajax(WEB_URL+"/api/plain/readlog?type=channel&channel="+chan+"&"+AUTH).done(function(data) {
|
||||
$("#log").text(data);
|
||||
});
|
||||
}
|
||||
$("#chanlog").click(getChanlog);
|
||||
$("#channame").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
getChanlog();
|
||||
}
|
||||
});
|
||||
|
||||
$("#announce_submit").click(function() {
|
||||
socket.emit("acp-announce", {
|
||||
title: $("#announce_title").val(),
|
||||
text: $("#announce_text").val()
|
||||
});
|
||||
$("#announce_title").val(""),
|
||||
$("#announce_text").val("")
|
||||
});
|
||||
|
||||
$("#gban_submit").click(function() {
|
||||
socket.emit("acp-global-ban", {
|
||||
ip: $("#gban_ip").val(),
|
||||
note: $("#gban_note").val()
|
||||
});
|
||||
|
||||
$("#gban_ip").val("");
|
||||
$("#gban_note").val("");
|
||||
});
|
||||
|
||||
$("#userlookup_submit").click(function() {
|
||||
socket.emit("acp-lookup-user", $("#userlookup_name").val());
|
||||
});
|
||||
|
||||
function loadPage(tbl, page) {
|
||||
var sort_field = tbl.data("sortby");
|
||||
var sort_desc = tbl.data("sort_desc");
|
||||
var generator = tbl.data("generator");
|
||||
var pag = tbl.data("pagination");
|
||||
if(pag) {
|
||||
pag.find("li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(pag.find("li")[page]).addClass("active");
|
||||
}
|
||||
var e = tbl.data("entries");
|
||||
|
||||
tbl.find("tbody").remove();
|
||||
|
||||
if(sort_field) {
|
||||
e.sort(function(a, b) {
|
||||
var x = a[sort_field];
|
||||
if(typeof x == "string")
|
||||
x = x.toLowerCase();
|
||||
var y = b[sort_field];
|
||||
if(typeof y == "string")
|
||||
y = y.toLowerCase();
|
||||
var z = x == y ? 0 : (x < y ? -1 : 1);
|
||||
if(sort_desc)
|
||||
z = -z;
|
||||
return z;
|
||||
});
|
||||
}
|
||||
|
||||
for(var i = page * 20; i < page * 20 + 20 && i < e.length; i++) {
|
||||
generator(e[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function setupCallbacks() {
|
||||
socket.on("connect", function() {
|
||||
if(NAME && SESSION) {
|
||||
socket.emit("login", {
|
||||
name: NAME,
|
||||
session: SESSION
|
||||
});
|
||||
}
|
||||
});
|
||||
socket.on("login", function(data) {
|
||||
if(!data.success) {
|
||||
if(data.error != "Invalid session") {
|
||||
alert(data.error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("#welcome").text("Logged in as " + data.name);
|
||||
$("#loginform").css("display", "none");
|
||||
$("#logoutform").css("display", "");
|
||||
$("#loggedin").css("display", "");
|
||||
SESSION = data.session || "";
|
||||
CLIENT.name = data.name;
|
||||
CLIENT.logged_in = true;
|
||||
socket.emit("acp-init");
|
||||
if(SESSION) {
|
||||
AUTH = "name=" + CLIENT.name + "&session=" + SESSION;
|
||||
createCookie("cytube_uname", CLIENT.name, 7);
|
||||
createCookie("cytube_session", SESSION, 7);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("rank", function(data) {
|
||||
CLIENT.rank = data;
|
||||
});
|
||||
|
||||
socket.on("announcement", function(data) {
|
||||
var al = makeAlert(data.title, data.text)
|
||||
.insertAfter($("#announce_current_h3"));
|
||||
al.find(".close").click(function() {
|
||||
socket.emit("acp-announce-clear");
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("acp-global-banlist", function(data) {
|
||||
$("#gbanpanel tbody").remove();
|
||||
for(var ip in data) {
|
||||
var tr = $("<tr/>").appendTo($("#gbanpanel table"));
|
||||
(function(ip, note) {
|
||||
$("<button/>").addClass("btn btn-mini btn-danger")
|
||||
.html("<i class='icon-trash'></i>")
|
||||
.appendTo($("<td/>").appendTo(tr))
|
||||
.click(function() {
|
||||
socket.emit("acp-global-unban", ip);
|
||||
});
|
||||
$("<td/>").html("<code>"+ip+"</code>").appendTo(tr);
|
||||
$("<td/>").text(note).appendTo(tr);
|
||||
})(ip, data[ip]);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("acp-userdata", function(data) {
|
||||
var tbl = $("#userlookup table");
|
||||
if(data.length > 20) {
|
||||
var pag = $("<div/>").addClass("pagination")
|
||||
.attr("id", "userlookup_pagination")
|
||||
.insertAfter($("#userlookup table"));
|
||||
var btns = $("<ul/>").appendTo(pag);
|
||||
for(var i = 0; i < data.length / 20; i++) {
|
||||
var li = $("<li/>").appendTo(btns);
|
||||
(function(i) {
|
||||
$("<a/>").attr("href", "javascript:void(0)")
|
||||
.text(i+1)
|
||||
.click(function() {
|
||||
loadPage(tbl, i);
|
||||
})
|
||||
.appendTo(li);
|
||||
})(i);
|
||||
}
|
||||
tbl.data("pagination", pag);
|
||||
}
|
||||
tbl.data("entries", data);
|
||||
tbl.data("sortby", "uname");
|
||||
tbl.data("sort_desc", false);
|
||||
tbl.data("generator", function(u) {
|
||||
var tr = $("<tr/>").appendTo($("#userlookup table"));
|
||||
$("<td/>").text(u.id).appendTo(tr);
|
||||
$("<td/>").text(u.uname).appendTo(tr);
|
||||
var rank = $("<td/>").text(u.global_rank).appendTo(tr);
|
||||
$("<td/>").text(u.email).appendTo(tr);
|
||||
$("<button/>").addClass("btn btn-mini")
|
||||
.text("Reset password")
|
||||
.appendTo($("<td/>").appendTo(tr))
|
||||
.click(function() {
|
||||
var reset = confirm("Really reset password?");
|
||||
if(reset) {
|
||||
socket.emit("acp-reset-password", {
|
||||
name: u.uname,
|
||||
email: u.email
|
||||
});
|
||||
}
|
||||
});
|
||||
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();
|
||||
|
||||
function save() {
|
||||
var r = this.val();
|
||||
var r2 = r;
|
||||
if(r.trim() == "")
|
||||
r = this.attr("placeholder");
|
||||
this.parent().text(this.attr("placeholder"));
|
||||
socket.emit("acp-set-rank", {
|
||||
name: u.uname,
|
||||
rank: parseInt(r)
|
||||
});
|
||||
}
|
||||
edit.blur(save.bind(edit));
|
||||
edit.keydown(function(ev) {
|
||||
if(ev.keyCode == 13)
|
||||
save.bind(edit)();
|
||||
});
|
||||
}.bind(rank));
|
||||
});
|
||||
loadPage($("#userlookup table"), 0);
|
||||
});
|
||||
|
||||
socket.on("acp-set-rank", function(data) {
|
||||
$("#userlookup tr").each(function() {
|
||||
if($($(this).children()[1]).text() == data.name)
|
||||
$($(this).children()[2]).text(data.rank);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("acp-reset-password", function(data) {
|
||||
if(!data.success)
|
||||
alert(data.error);
|
||||
else
|
||||
alert("Password reset successful. Reset hash: " + data.hash);
|
||||
});
|
||||
|
||||
socket.on("acp-list-loaded", function(data) {
|
||||
$("#channellist tbody").remove();
|
||||
data.sort(function(a, b) {
|
||||
if(a.usercount == b.usercount) {
|
||||
var x = a.name, y = b.name;
|
||||
return x == y ? 0 : (x < y ? -1 : 1);
|
||||
}
|
||||
return a.usercount < b.usercount ? -1 : 1;
|
||||
});
|
||||
var total = 0;
|
||||
data.forEach(function(c) {
|
||||
total += c.usercount;
|
||||
var tr = $("<tr/>").appendTo($("#channellist table"));
|
||||
$("<td/>").text(c.title + " (" + c.name + ")").appendTo(tr);
|
||||
$("<td/>").text(c.usercount).appendTo(tr);
|
||||
$("<td/>").text(c.mediatitle).appendTo(tr);
|
||||
$("<td/>").text(c.registered ? "Yes" : "No").appendTo(tr);
|
||||
$("<td/>").text(c.is_public ? "Yes" : "No").appendTo(tr);
|
||||
$("<button/>").addClass("btn btn-danger btn-mini")
|
||||
.text("Force Unload")
|
||||
.appendTo($("<td/>").appendTo(tr))
|
||||
.click(function() {
|
||||
var go = confirm("Really force unload?");
|
||||
if(go) {
|
||||
socket.emit("acp-channel-unload", {
|
||||
name: c.name,
|
||||
save: true
|
||||
});
|
||||
socket.emit("acp-list-loaded");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var tr = $("<tr/>").appendTo($("#channellist table"));
|
||||
$("<td/>").text("Total").appendTo(tr);
|
||||
$("<td/>").text(total).appendTo(tr);
|
||||
$("<td/>").appendTo(tr);
|
||||
$("<td/>").appendTo(tr);
|
||||
$("<td/>").appendTo(tr);
|
||||
$("<td/>").appendTo(tr);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* cookie util */
|
||||
|
||||
function createCookie(name,value,days) {
|
||||
if (days) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
132
www/assets/js/channelsettings.js
Normal file
132
www/assets/js/channelsettings.js
Normal file
|
@ -0,0 +1,132 @@
|
|||
(function() {
|
||||
|
||||
$("#channelsettingswrap div.span12").each(function() {
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
function clickHandler(selector, div) {
|
||||
$(selector).click(function() {
|
||||
$("#csdropdown_title").text($(selector).text());
|
||||
$("#channelsettingswrap div.span12").each(function() {
|
||||
$(this).hide();
|
||||
});
|
||||
$(div).show();
|
||||
});
|
||||
}
|
||||
|
||||
$("#hide_settings").click(function() {
|
||||
$("#csdropdown_title").text("Moderation Menu");
|
||||
$("#channelsettingswrap div.span12").each(function() {
|
||||
$(this).hide();
|
||||
});
|
||||
});
|
||||
|
||||
clickHandler("#show_optedit", "#optedit");
|
||||
$("#optedit input[type='text']").keydown(function(ev) {
|
||||
return ev.keyCode != 13;
|
||||
});
|
||||
clickHandler("#show_permedit", "#permedit");
|
||||
clickHandler("#show_motdedit", "#motdedit");
|
||||
clickHandler("#show_filteredit", "#filteredit");
|
||||
$("#show_filteredit").click(function() {
|
||||
socket.emit("requestChatFilters");
|
||||
});
|
||||
clickHandler("#show_cssedit", "#cssedit");
|
||||
clickHandler("#show_jsedit", "#jsedit");
|
||||
clickHandler("#show_banlist", "#banlist");
|
||||
$("#show_banlist").click(function() {
|
||||
socket.emit("requestBanlist");
|
||||
});
|
||||
clickHandler("#show_loginhistory", "#loginhistory");
|
||||
$("#show_loginhistory").click(function() {
|
||||
socket.emit("requestLoginHistory");
|
||||
});
|
||||
clickHandler("#show_channelranks", "#channelranks");
|
||||
$("#show_channelranks").click(function() {
|
||||
socket.emit("requestChannelRanks");
|
||||
});
|
||||
|
||||
genPermissionsEditor();
|
||||
|
||||
$("#chanopts_submit").click(function() {
|
||||
socket.emit("setOptions", {
|
||||
allow_voteskip: $("#opt_allow_voteskip").prop("checked"),
|
||||
voteskip_ratio: parseFloat($("#opt_voteskip_ratio").val()),
|
||||
pagetitle: $("#opt_pagetitle").val() || CHANNEL.name,
|
||||
externalcss: $("#opt_externalcss").val(),
|
||||
externaljs: $("#opt_externaljs").val(),
|
||||
chat_antiflood: $("#opt_chat_antiflood").prop("checked"),
|
||||
show_public: $("#opt_show_public").prop("checked"),
|
||||
enable_link_regex: $("#opt_enable_link_regex").prop("checked")
|
||||
});
|
||||
});
|
||||
|
||||
$("#chanopts_unregister").click(function() {
|
||||
var res = confirm("You are about to unregister your channel. This will PERMANENTLY delete your channel data, including ranks, bans, and library videos. This cannot be undone. Are you sure you want to continue?");
|
||||
if(res) {
|
||||
socket.emit("unregisterChannel");
|
||||
}
|
||||
});
|
||||
|
||||
$("#save_motd").click(function() {
|
||||
socket.emit("setMotd", {
|
||||
motd: $("#motdtext").val()
|
||||
});
|
||||
});
|
||||
$("#csstext").keydown(function(ev) {
|
||||
if(ev.keyCode == 9) {
|
||||
$("#csstext").text($("#csstext").val() + " ");
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$("#save_css").click(function() {
|
||||
socket.emit("setChannelCSS", {
|
||||
css: $("#csstext").val()
|
||||
});
|
||||
});
|
||||
$("#jstext").keydown(function(ev) {
|
||||
if(ev.keyCode == 9) {
|
||||
$("#jstext").text($("#jstext").val() + " ");
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$("#save_js").click(function() {
|
||||
socket.emit("setChannelJS", {
|
||||
js: $("#jstext").val()
|
||||
});
|
||||
});
|
||||
|
||||
$("#newfilter_submit").click(function() {
|
||||
var re = $("#newfilter_regex").val();
|
||||
if(re === "") {
|
||||
makeAlert("Invalid Regex", e, "alert-error")
|
||||
.insertAfter($("#filteredit form"));
|
||||
return;
|
||||
}
|
||||
var flags = $("#newfilter_flags").val();
|
||||
try {
|
||||
new RegExp(re, flags);
|
||||
}
|
||||
catch(e) {
|
||||
makeAlert("Invalid Regex", e, "alert-error")
|
||||
.insertAfter($("#filteredit form"));
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit("updateFilter", {
|
||||
name: $("#newfilter_name").val(),
|
||||
source: re,
|
||||
flags: flags,
|
||||
replace: $("#newfilter_replace").val(),
|
||||
filterlinks: $("#newfilter_filterlinks").prop("checked"),
|
||||
active: true
|
||||
});
|
||||
|
||||
$("#newfilter_name").val("");
|
||||
$("#newfilter_regex").val("");
|
||||
$("#newfilter_flags").val("g");
|
||||
$("#newfilter_replace").val("");
|
||||
});
|
||||
})();
|
|
@ -1,756 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
var socket;
|
||||
var LEADER = false;
|
||||
var PLAYER = new Media();
|
||||
var MEDIATYPE = "null";
|
||||
var POSITION = -1;
|
||||
var RANK = -1;
|
||||
var OPENQUEUE = false;
|
||||
var CHANNELOPTS = {};
|
||||
var CHANPERMS = {};
|
||||
var GRABBEDLI = null;
|
||||
var OLDINDEX = -1;
|
||||
var CHATHIST = [];
|
||||
var CHATHISTIDX = 0;
|
||||
var FOCUSED = true;
|
||||
var SCROLLCHAT = true;
|
||||
var LASTCHATNAME = "";
|
||||
var LASTCHATTIME = 0;
|
||||
var PAGETITLE = "Sync";
|
||||
var TITLE_BLINK;
|
||||
var VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");//670
|
||||
var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
||||
$("#messagebuffer").css("height", (VHEIGHT - 31) + "px");
|
||||
$("#userlist").css("height", (VHEIGHT - 31) + "px");
|
||||
var IGNORED = [];
|
||||
var KICKED = false;
|
||||
var CHANNEL = "";
|
||||
var CUSTOMJS = "";
|
||||
var uname = readCookie("sync_uname");
|
||||
var session = readCookie("sync_session");
|
||||
var PROFILE = {
|
||||
image: "",
|
||||
text: ""
|
||||
};
|
||||
|
||||
function parseBool(x) {
|
||||
if(typeof x == "boolean")
|
||||
return x;
|
||||
else if(x == "true")
|
||||
return true;
|
||||
else if(x == "false")
|
||||
return false;
|
||||
else return Boolean(x);
|
||||
}
|
||||
|
||||
getOrDefault = function(k, def) {
|
||||
var v = localStorage.getItem(k);
|
||||
if(v === null)
|
||||
return def;
|
||||
if(v === "true")
|
||||
return true;
|
||||
if(v === "false")
|
||||
return false;
|
||||
if(v.match(/[0-9]+/))
|
||||
return parseInt(v);
|
||||
if(v.match(/[0-9\.]+/))
|
||||
return parseFloat(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
var USEROPTS = {
|
||||
theme : getOrDefault("theme", "default"),
|
||||
css : getOrDefault("css", ""),
|
||||
layout : getOrDefault("layout", "default"),
|
||||
synch : getOrDefault("synch", true),
|
||||
hidevid : getOrDefault("hidevid", false),
|
||||
show_timestamps : getOrDefault("show_timestamps", true),
|
||||
modhat : getOrDefault("modhat", false),
|
||||
blink_title : getOrDefault("blink_title", false),
|
||||
sync_accuracy : getOrDefault("sync_accuracy", 2),
|
||||
chatbtn : getOrDefault("chatbtn", false),
|
||||
altsocket : getOrDefault("altsocket", false)
|
||||
};
|
||||
applyOpts();
|
||||
$("#optlink").click(showUserOpts);
|
||||
$("#sitefooter").load("footer.html");
|
||||
|
||||
var Rank = {
|
||||
Guest: 0,
|
||||
Member: 1,
|
||||
Moderator: 2,
|
||||
Owner: 3,
|
||||
Siteadmin: 255
|
||||
};
|
||||
|
||||
|
||||
$(window).focus(function() {
|
||||
FOCUSED = true;
|
||||
onWindowFocus();
|
||||
})
|
||||
.blur(function() {
|
||||
FOCUSED = false;
|
||||
});
|
||||
|
||||
$(window).resize(function() {
|
||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
||||
var 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);
|
||||
});
|
||||
|
||||
// Match URLs of the form http://site.tld/r/channel
|
||||
var loc = document.location+"";
|
||||
var m = loc.match(/\/r\/([a-zA-Z0-9-_]+)$/);
|
||||
if(m) {
|
||||
CHANNEL = m[1];
|
||||
}
|
||||
else {
|
||||
var main = $($(".container")[1]);
|
||||
var container = $("<div/>").addClass("container").insertBefore(main);
|
||||
var row = $("<div/>").addClass("row").appendTo(container);
|
||||
var div = $("<div/>").addClass("span6").appendTo(row);
|
||||
main.css("display", "none");
|
||||
var label = $("<label/>").text("Enter Channel:").appendTo(div);
|
||||
var entry = $("<input/>").attr("type", "text").appendTo(div);
|
||||
entry.keydown(function(ev) {
|
||||
var host = ""+document.location;
|
||||
host = host.replace("http://", "");
|
||||
host = host.substring(0, host.indexOf("/"));
|
||||
if(ev.keyCode == 13) {
|
||||
document.location = "http://" + host + "/r/" + entry.val();
|
||||
socket.emit("joinChannel", {
|
||||
name: entry.val()
|
||||
});
|
||||
container.remove();
|
||||
main.css("display", "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Load the youtube iframe API
|
||||
if(!USEROPTS.hidevid) {
|
||||
var tag = document.createElement("script");
|
||||
tag.src = "http://www.youtube.com/iframe_api";
|
||||
var firstScriptTag = document.getElementsByTagName("script")[0];
|
||||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
||||
}
|
||||
|
||||
$("#ulistchevron").click(function() {
|
||||
var state = $("#userlist").css("display");
|
||||
if(state == "none") {
|
||||
$("#userlist").show();
|
||||
$("#ulistchevron").removeClass().addClass("icon-chevron-up");
|
||||
}
|
||||
else {
|
||||
$("#userlist").hide();
|
||||
$("#ulistchevron").removeClass().addClass("icon-chevron-down");
|
||||
}
|
||||
});
|
||||
|
||||
var sendVideoUpdate = function() { }
|
||||
setInterval(function() {
|
||||
sendVideoUpdate();
|
||||
}, 5000);
|
||||
|
||||
function queueEnd() {
|
||||
var urls = $("#mediaurl").val().split(",");
|
||||
for(var i = 0; i < urls.length; i++) {
|
||||
if(!urls[i].trim())
|
||||
continue;
|
||||
var parsed = parseVideoURL(urls[i].trim());
|
||||
var id = parsed[0];
|
||||
var type = parsed[1];
|
||||
if(id) {
|
||||
$("#mediaurl").val("");
|
||||
}
|
||||
if(type == "jw") {
|
||||
makeAlert("JWPlayer",
|
||||
"If you are queueing a file (not a livestream) with JWPlayer, please note it will only synchronize if you assign a leader.",
|
||||
"alert-warning")
|
||||
.insertAfter($("#playlist_controls"));
|
||||
}
|
||||
socket.emit("queue", {
|
||||
id: id,
|
||||
pos: "end",
|
||||
type: type
|
||||
});
|
||||
}
|
||||
}
|
||||
$("#queue_end").click(queueEnd);
|
||||
$("#mediaurl").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
queueEnd();
|
||||
}
|
||||
});
|
||||
|
||||
$("#queue_next").click(function() {
|
||||
var urls = $("#mediaurl").val().split(",");
|
||||
for(var i = urls.length - 1; i >= 0; i--) {
|
||||
if(!urls[i].trim())
|
||||
continue;
|
||||
var parsed = parseVideoURL(urls[i].trim());
|
||||
var id = parsed[0];
|
||||
var type = parsed[1];
|
||||
if(id) {
|
||||
$("#mediaurl").val("");
|
||||
}
|
||||
if(type == "jw") {
|
||||
makeAlert("JWPlayer",
|
||||
"If you are queueing a file (not a livestream) with JWPlayer, please note it will only synchronize if you assign a leader.",
|
||||
"alert-warning")
|
||||
.insertAfter($("#playlist_controls"));
|
||||
}
|
||||
socket.emit("queue", {
|
||||
id: id,
|
||||
pos: "next",
|
||||
type: type
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("#play_next").click(function() {
|
||||
socket.emit("playNext");
|
||||
});
|
||||
|
||||
$("#voteskip").click(function() {
|
||||
socket.emit("voteskip");
|
||||
$("#voteskip").attr("disabled", true);
|
||||
});
|
||||
|
||||
$("#qlockbtn").click(function() {
|
||||
socket.emit("queueLock", {
|
||||
locked: OPENQUEUE
|
||||
});
|
||||
});
|
||||
|
||||
$("#login").click(showLoginFrame);
|
||||
|
||||
function guestLogin() {
|
||||
uname = $("#guestname").val();
|
||||
socket.emit("login", {
|
||||
name: $("#guestname").val()
|
||||
});
|
||||
}
|
||||
$("#guestlogin").click(guestLogin);
|
||||
$("#guestname").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
guestLogin();
|
||||
}
|
||||
});
|
||||
|
||||
$("#logout").click(function() {
|
||||
eraseCookie("sync_uname");
|
||||
eraseCookie("sync_session");
|
||||
document.location.reload(true);
|
||||
});
|
||||
|
||||
$("#chatline").keydown(function(ev) {
|
||||
if(ev.keyCode == 13 && $("#chatline").val() != "") {
|
||||
if($("#chatline").val().trim() == "/poll") {
|
||||
newPollMenu();
|
||||
$("#chatline").val("");
|
||||
}
|
||||
else {
|
||||
var msg = $("#chatline").val();
|
||||
if(USEROPTS.modhat && RANK >= Rank.Moderator) {
|
||||
msg = "/m " + msg
|
||||
}
|
||||
socket.emit("chatMsg", {
|
||||
msg: msg
|
||||
});
|
||||
}
|
||||
CHATHIST.push($("#chatline").val());
|
||||
if(CHATHIST.length > 10)
|
||||
CHATHIST.shift();
|
||||
CHATHISTIDX = CHATHIST.length;
|
||||
$("#chatline").val("");
|
||||
}
|
||||
else if(ev.keyCode == 9) { // Tab completion
|
||||
var words = $("#chatline").val().split(" ");
|
||||
var current = words[words.length - 1].toLowerCase();
|
||||
var users = $("#userlist").children();
|
||||
var match = null;
|
||||
for(var i = 0; i < users.length; i++) {
|
||||
var name = users[i].children[1].innerHTML.toLowerCase();
|
||||
if(name.indexOf(current) == 0 && match == null) {
|
||||
match = users[i].children[1].innerHTML;
|
||||
}
|
||||
else if(name.indexOf(current) == 0) {
|
||||
match = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(match != null) {
|
||||
words[words.length - 1] = match;
|
||||
if(words.length == 1)
|
||||
words[0] += ": ";
|
||||
else
|
||||
words[words.length - 1] += " ";
|
||||
$("#chatline").val(words.join(" "));
|
||||
}
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else if(ev.keyCode == 38) {
|
||||
if(CHATHISTIDX == CHATHIST.length) {
|
||||
CHATHIST.push($("#chatline").val());
|
||||
}
|
||||
if(CHATHISTIDX > 0) {
|
||||
CHATHISTIDX--;
|
||||
$("#chatline").val(CHATHIST[CHATHISTIDX]);
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else if(ev.keyCode == 40) {
|
||||
if(CHATHISTIDX < CHATHIST.length - 1) {
|
||||
CHATHISTIDX++;
|
||||
$("#chatline").val(CHATHIST[CHATHISTIDX]);
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$("#messagebuffer").mouseenter(function() { SCROLLCHAT = false; });
|
||||
$("#messagebuffer").mouseleave(function() { SCROLLCHAT = true; });
|
||||
|
||||
$("#clearplaylist").click(function() {
|
||||
socket.emit("clearqueue");
|
||||
});
|
||||
|
||||
$("#shuffleplaylist").click(function() {
|
||||
socket.emit("shufflequeue");
|
||||
});
|
||||
|
||||
$("#getplaylist").click(function() {
|
||||
var callback = function(data) {
|
||||
socket.listeners("playlist").splice(
|
||||
socket.listeners("playlist").indexOf(callback));
|
||||
var list = [];
|
||||
for(var i = 0; i < data.pl.length; i++) {
|
||||
var entry = idToURL(data.pl[i]);
|
||||
list.push(entry);
|
||||
}
|
||||
var urls = list.join(",");
|
||||
|
||||
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("Playlist URLs").appendTo(head);
|
||||
var body = $("<div/>").addClass("modal-body").appendTo(modal);
|
||||
$("<input/>").attr("type", "text")
|
||||
.val(urls)
|
||||
.appendTo(body);
|
||||
$("<div/>").addClass("modal-footer").appendTo(modal);
|
||||
modal.on("hidden", function() {
|
||||
modal.remove();
|
||||
});
|
||||
modal.modal();
|
||||
}
|
||||
socket.on("playlist", callback);
|
||||
socket.emit("requestPlaylist");
|
||||
});
|
||||
|
||||
$("#opt_submit").click(function() {
|
||||
var ptitle = $("#opt_pagetitle").val();
|
||||
if(ptitle == "")
|
||||
ptitle = $("#opt_pagetitle").attr("placeholder")
|
||||
var css = $("#opt_customcss").val();
|
||||
var ratio = +$("#opt_voteskip_ratio").val() || 0.5;
|
||||
opts = {
|
||||
allow_voteskip: $("#opt_allow_voteskip").prop("checked"),
|
||||
voteskip_ratio: ratio,
|
||||
pagetitle: ptitle,
|
||||
customcss: css,
|
||||
customjs: $("#opt_customjs").val(),
|
||||
chat_antiflood: $("#opt_chat_antiflood").prop("checked"),
|
||||
show_public: $("#opt_show_public").prop("checked"),
|
||||
enable_link_regex: $("#opt_enable_link_regex").prop("checked")
|
||||
};
|
||||
socket.emit("channelOpts", opts);
|
||||
});
|
||||
|
||||
$("#updatemotd").click(function() {
|
||||
var motd = $("#motdtext").val();
|
||||
socket.emit("updateMotd", {
|
||||
motd: motd
|
||||
});
|
||||
});
|
||||
|
||||
$("#show_chancontrols").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_chancontrols").parent().addClass("active");
|
||||
$("#chancontrols").show();
|
||||
});
|
||||
|
||||
$("#show_chanperms").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_chanperms").parent().addClass("active");
|
||||
$("#chanperms").show();
|
||||
});
|
||||
|
||||
$("#show_banlist").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_banlist").parent().addClass("active");
|
||||
$("#banlist").show();
|
||||
});
|
||||
|
||||
$("#show_loginlog").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_loginlog").parent().addClass("active");
|
||||
$("#loginlog").show();
|
||||
socket.emit("requestSeenlogins");
|
||||
});
|
||||
|
||||
$("#show_motdeditor").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_motdeditor").parent().addClass("active");
|
||||
$("#motdeditor").show();
|
||||
});
|
||||
|
||||
$("#show_csseditor").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_csseditor").parent().addClass("active");
|
||||
$("#csseditor").show();
|
||||
});
|
||||
|
||||
$("#updatecss").click(function() {
|
||||
socket.emit("setChannelCSS", {
|
||||
css: $("#csstext").val()
|
||||
});
|
||||
});
|
||||
|
||||
$("#show_jseditor").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_jseditor").parent().addClass("active");
|
||||
$("#jseditor").show();
|
||||
});
|
||||
|
||||
$("#updatejs").click(function() {
|
||||
socket.emit("setChannelJS", {
|
||||
js: $("#jstext").val()
|
||||
});
|
||||
});
|
||||
|
||||
$("#show_filtereditor").click(function() {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_filtereditor").parent().addClass("active");
|
||||
$("#filtereditor").show();
|
||||
});
|
||||
|
||||
$("#show_acl").click(function() {
|
||||
if(RANK >= Rank.Owner) {
|
||||
$("#modnav li").each(function() {
|
||||
$(this).removeClass("active");
|
||||
});
|
||||
$(".modonly").hide();
|
||||
$("#show_acl").parent().addClass("active");
|
||||
$("#channelranks").show();
|
||||
socket.emit("requestAcl");
|
||||
}
|
||||
else {
|
||||
alert("Only channel administrators can use the ACL");
|
||||
}
|
||||
});
|
||||
|
||||
$("#drop_channel").click(function() {
|
||||
var res = confirm("You are about to unregister your channel. This will PERMANENTLY delete your channel data, including ranks, bans, and library videos. This cannot be undone. Are you sure you want to continue?");
|
||||
if(res) {
|
||||
socket.emit("unregisterChannel");
|
||||
}
|
||||
});
|
||||
|
||||
function splitreEntry(str) {
|
||||
var split = [];
|
||||
var current = [];
|
||||
for(var i = 0; i < str.length; i++) {
|
||||
if(str[i] == "\\" && i+1 < str.length && str[i+1].match(/\s/)) {
|
||||
current.push(str[i+1]);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if(str[i].match(/\s/)) {
|
||||
split.push(current.join(""));
|
||||
current = [];
|
||||
}
|
||||
else {
|
||||
current.push(str[i]);
|
||||
}
|
||||
}
|
||||
split.push(current.join(""));
|
||||
return split;
|
||||
}
|
||||
|
||||
$("#multifilter").click(function() {
|
||||
var input = $("#multifiltereditor").val();
|
||||
var lines = input.split("\n");
|
||||
for(var i = 0; i < lines.length; i++) {
|
||||
var fields = splitreEntry(lines[i]);
|
||||
var name = "";
|
||||
var regex = "";
|
||||
var flags = "";
|
||||
var replace = "";
|
||||
if(fields.length < 3) {
|
||||
alert("Minimum of 3 fields per filter: (optional: name), regex, flags, replacement");
|
||||
return;
|
||||
}
|
||||
else if(fields.length == 3) {
|
||||
regex = fields[0];
|
||||
flags = fields[1];
|
||||
replace = fields[2];
|
||||
}
|
||||
else if(fields.length == 4) {
|
||||
name = fields[0];
|
||||
regex = fields[1];
|
||||
flags = fields[2];
|
||||
replace = fields[3];
|
||||
}
|
||||
else {
|
||||
alert("Too many paramters: " + fields.join(" "));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
new RegExp(regex, flags);
|
||||
}
|
||||
catch(e) {
|
||||
alert("Invalid regex: " + e);
|
||||
return;
|
||||
}
|
||||
socket.emit("chatFilter", {
|
||||
cmd: "update",
|
||||
filter: {
|
||||
name: name,
|
||||
source: regex,
|
||||
flags: flags,
|
||||
replace: replace,
|
||||
active: true
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function searchLibrary() {
|
||||
socket.emit("searchLibrary", {
|
||||
query: $("#library_query").val()
|
||||
});
|
||||
}
|
||||
$("#library_search").click(searchLibrary);
|
||||
$("#library_query").keydown(function(ev) {
|
||||
if(ev.keyCode == 13)
|
||||
searchLibrary();
|
||||
});
|
||||
|
||||
function savePlaylist() {
|
||||
if($("#userpl_name").val().trim() == "") {
|
||||
makeAlert("Invalid Name", "Playlist name cannot be empty", "alert-error")
|
||||
.addClass("span12")
|
||||
.css("margin-left", "0")
|
||||
.insertAfter($("#userpl_save").parent());
|
||||
return;
|
||||
}
|
||||
socket.emit("savePlaylist", {
|
||||
name: $("#userpl_name").val()
|
||||
});
|
||||
}
|
||||
|
||||
$("#userpl_save").click(savePlaylist);
|
||||
$("#userpl_name").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
savePlaylist();
|
||||
}
|
||||
});
|
||||
|
||||
$("#show_userpl").click(function() {
|
||||
$("#show_library").parent().removeClass("active");
|
||||
$("#show_userpl").parent().addClass("active");
|
||||
$("#libcontainer").hide();
|
||||
$("#userplcontainer").show();
|
||||
socket.emit("listPlaylists");
|
||||
});
|
||||
|
||||
$("#show_library").click(function() {
|
||||
$("#show_userpl").parent().removeClass("active");
|
||||
$("#show_library").parent().addClass("active");
|
||||
$("#userplcontainer").hide();
|
||||
$("#libcontainer").show();
|
||||
});
|
||||
|
||||
$("#youtube_search").click(function() {
|
||||
socket.emit("searchLibrary", {
|
||||
query: $("#library_query").val(),
|
||||
yt: true
|
||||
});
|
||||
});
|
||||
|
||||
$("#search_clear").click(function() {
|
||||
clearSearchResults();
|
||||
});
|
||||
|
||||
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 largeLayout() {
|
||||
$("#videodiv").removeClass().addClass("span8 offset2");
|
||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");//770
|
||||
VHEIGHT = "430";
|
||||
$("#ytapiplayer").attr("width", VWIDTH).attr("height", "430");
|
||||
var chat = $("#chatdiv").detach();
|
||||
$("#layoutrow").remove();
|
||||
var r = $("<div />").addClass("row").insertAfter($("#videodiv").parent());
|
||||
r.attr("id", "layoutrow");
|
||||
chat.removeClass().addClass("span8 offset2").appendTo(r);
|
||||
$("#chatline").removeClass().addClass("span8");
|
||||
$("#userlist").css("width", "200px");
|
||||
}
|
||||
|
||||
function singleColumnLayout() {
|
||||
$("#videodiv").removeClass().addClass("span12");
|
||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
||||
VHEIGHT = parseInt(VWIDTH) * 9 / 16;
|
||||
$("#ytapiplayer").attr("width", VWIDTH).attr("height", VHEIGHT);
|
||||
var chat = $("#chatdiv").detach();
|
||||
$("#layoutrow").remove();
|
||||
var r = $("<div />").addClass("row").insertAfter($("#videodiv").parent());
|
||||
r.attr("id", "layoutrow");
|
||||
chat.removeClass().addClass("span12").appendTo(r);
|
||||
chat.css("height", "200px");
|
||||
$("#messagebuffer").css("height", "100%");
|
||||
$("#userlist").css("height", "100%");
|
||||
$("#chatline").removeClass().addClass("span12");
|
||||
$("#userlist").css("width", "200px");
|
||||
|
||||
var r2d2 = $("<div/>").addClass("row").insertBefore($("#queuerow"));
|
||||
r2d2.css("margin-top", "60px");
|
||||
var librow = $("#queuerow").attr("id", "");
|
||||
librow.css("margin-top", "5px");
|
||||
r2d2.attr("id", "queuerow");
|
||||
$("#pollcontainer").detach().appendTo(r2d2).removeClass().addClass("span12");
|
||||
$("#queuediv").detach().appendTo(r2d2).removeClass().addClass("span12");
|
||||
$(librow.find(".span5")[0]).removeClass().addClass("span12");
|
||||
|
||||
}
|
||||
|
||||
function hugeLayout() {
|
||||
$("#videodiv").removeClass().addClass("span12");
|
||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");//1170
|
||||
VHEIGHT = "658";
|
||||
$("#ytapiplayer").attr("width", VWIDTH).attr("height", "658");
|
||||
var chat = $("#chatdiv").detach();
|
||||
$("#layoutrow").remove();
|
||||
var r = $("<div />").addClass("row").insertAfter($("#videodiv").parent());
|
||||
r.attr("id", "layoutrow");
|
||||
chat.removeClass().addClass("span12").appendTo(r);
|
||||
$("#chatline").removeClass().addClass("span12");
|
||||
$("#userlist").css("width", "200px").css("height", "200px");
|
||||
$("#messagebuffer").css("height", "200px");
|
||||
}
|
||||
|
||||
function narrowLayout() {
|
||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");//570
|
||||
VHEIGHT = "321";
|
||||
$("#videodiv").removeClass().addClass("span6");
|
||||
$("#ytapiplayer").attr("width", VWIDTH).attr("height", "321");
|
||||
var chat = $("#chatdiv").detach();
|
||||
$("#layoutrow").remove();
|
||||
var r = $("<div />").addClass("row").insertAfter($("#videodiv").parent());
|
||||
r.attr("id", "layoutrow");
|
||||
chat.removeClass().addClass("span6").appendTo(r);
|
||||
$("#chatline").removeClass().addClass("span6");
|
||||
$("#userlist").css("width", "150px");
|
||||
}
|
||||
|
||||
function synchtubeLayout() {
|
||||
$("#videodiv").detach().insertBefore($("#chatdiv"));
|
||||
$("#queuediv").detach().prependTo($("#queuerow"));
|
||||
}
|
||||
|
||||
function onYouTubeIframeAPIReady() {
|
||||
if(PLAYER.type == "null")
|
||||
PLAYER = new Media({id: "", type: "yt"});
|
||||
if(USEROPTS.layout == "fluid") {
|
||||
fluidLayout();
|
||||
}
|
||||
}
|
||||
|
||||
function createCookie(name,value,days) {
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
var expires = "; expires="+date.toGMTString();
|
||||
}
|
||||
else var expires = "";
|
||||
document.cookie = name+"="+value+expires+"; path=/";
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(";");
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==" ") c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function eraseCookie(name) {
|
||||
createCookie(name,"",-1);
|
||||
}
|
136
www/assets/js/data.js
Normal file
136
www/assets/js/data.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
var CL_VERSION = "2.0.0";
|
||||
|
||||
var CLIENT = {
|
||||
rank: -1,
|
||||
leader: false,
|
||||
name: "",
|
||||
logged_in: false,
|
||||
profile: {
|
||||
image: "",
|
||||
text: ""
|
||||
}
|
||||
};
|
||||
|
||||
var CHANNEL = {
|
||||
opts: {},
|
||||
openqueue: false,
|
||||
perms: {},
|
||||
css: "",
|
||||
js: "",
|
||||
motd: "",
|
||||
name: false
|
||||
};
|
||||
|
||||
var PLAYER = false;
|
||||
var VIDEOQUALITY = false;
|
||||
var FLUIDLAYOUT = false;
|
||||
if($("#ytapiplayer").length > 0) {
|
||||
var VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
||||
var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
|
||||
}
|
||||
var POSITION = -1;
|
||||
var socket = {
|
||||
emit: function() {
|
||||
console.log("socket not initialized");
|
||||
console.log(arguments);
|
||||
}
|
||||
};
|
||||
var IGNORED = [];
|
||||
var CHATHIST = [];
|
||||
var CHATHISTIDX = 0;
|
||||
var SCROLLCHAT = true;
|
||||
var LASTCHATNAME = "";
|
||||
var LASTCHATTIME = 0;
|
||||
var FOCUSED = true;
|
||||
var PAGETITLE = "CyTube";
|
||||
var TITLE_BLINK;
|
||||
var KICKED = false;
|
||||
var NAME = readCookie("cytube_uname");
|
||||
var SESSION = readCookie("cytube_session");
|
||||
var LEADTMR = false;
|
||||
var PL_FROM = 0;
|
||||
var PL_TO = 0;
|
||||
var FILTER_FROM = 0;
|
||||
var FILTER_TO = 0;
|
||||
|
||||
function getOrDefault(k, def) {
|
||||
var v = localStorage.getItem(k);
|
||||
if(v === null)
|
||||
return def;
|
||||
if(v === "true")
|
||||
return true;
|
||||
if(v === "false")
|
||||
return false;
|
||||
if(v.match(/^[0-9]+$/))
|
||||
return parseInt(v);
|
||||
if(v.match(/^[0-9\.]+$/))
|
||||
return parseFloat(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
var USEROPTS = {
|
||||
theme : getOrDefault("theme", "default"),
|
||||
css : getOrDefault("css", ""),
|
||||
layout : getOrDefault("layout", "default"),
|
||||
synch : getOrDefault("synch", true),
|
||||
hidevid : getOrDefault("hidevid", false),
|
||||
show_timestamps : getOrDefault("show_timestamps", true),
|
||||
modhat : getOrDefault("modhat", false),
|
||||
blink_title : getOrDefault("blink_title", false),
|
||||
sync_accuracy : getOrDefault("sync_accuracy", 2),
|
||||
chatbtn : getOrDefault("chatbtn", false),
|
||||
altsocket : getOrDefault("altsocket", false),
|
||||
joinmessage : getOrDefault("joinmessage", true),
|
||||
qbtn_hide : getOrDefault("qbtn_hide", false),
|
||||
qbtn_idontlikechange : getOrDefault("qbtn_idontlikechange", false),
|
||||
first_visit : getOrDefault("first_visit", true)
|
||||
};
|
||||
|
||||
var Rank = {
|
||||
Guest: 0,
|
||||
Member: 1,
|
||||
Leader: 1.5,
|
||||
Moderator: 2,
|
||||
Admin: 3,
|
||||
Owner: 10,
|
||||
Siteadmin: 255
|
||||
};
|
||||
|
||||
function createCookie(name,value,days) {
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
var expires = "; expires="+date.toGMTString();
|
||||
}
|
||||
else var expires = "";
|
||||
document.cookie = name+"="+value+expires+"; path=/";
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(";");
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==" ") c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function eraseCookie(name) {
|
||||
createCookie(name,"",-1);
|
||||
}
|
||||
|
||||
/* to be implemented in callbacks.js */
|
||||
function setupCallbacks() { }
|
File diff suppressed because it is too large
Load diff
|
@ -11,3 +11,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||
|
||||
var IO_URL = "http://localhost:1337";
|
||||
var WEB_URL = "http://localhost:8080";
|
||||
var NO_WEBSOCKETS = false;
|
||||
|
|
|
@ -12,7 +12,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||
var NotWebsocket = function() {
|
||||
this.connected = false;
|
||||
this.polltmr = false;
|
||||
$.getJSON(WEB_URL + "/nws/connect", function(data) {
|
||||
this.nws = true;
|
||||
$.getJSON(WEB_URL + "/nws/connect?callback=?", function(data) {
|
||||
this.hash = data;
|
||||
this.connected = true;
|
||||
this.recv(["connect", undefined]);
|
||||
|
@ -76,7 +77,7 @@ NotWebsocket.prototype.emit = function(msg, data) {
|
|||
}
|
||||
var pkt = [msg, data];
|
||||
var str = escape(JSON.stringify(pkt)).replace(/\//g, "%2F");
|
||||
$.getJSON(WEB_URL+"/nws/"+this.hash+"/"+str, function() {
|
||||
$.getJSON(WEB_URL+"/nws/"+this.hash+"/"+str+"?callback=?", function() {
|
||||
// Poll more quickly because sending a packet usually means
|
||||
// expecting some data to come back
|
||||
this.pollint = 100;
|
||||
|
|
|
@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
var Media = function(data) {
|
||||
var Player = function(data) {
|
||||
if(!data) {
|
||||
data = {
|
||||
id: "",
|
||||
|
@ -60,7 +60,7 @@ var Media = function(data) {
|
|||
}
|
||||
}
|
||||
|
||||
Media.prototype.nullPlayer = function() {
|
||||
Player.prototype.nullPlayer = function() {
|
||||
this.player = null;
|
||||
this.load = function(data) { }
|
||||
this.play = function() { }
|
||||
|
@ -69,15 +69,19 @@ Media.prototype.nullPlayer = function() {
|
|||
this.seek = function(time) { }
|
||||
}
|
||||
|
||||
Media.prototype.initYouTube = function() {
|
||||
Player.prototype.initYouTube = function() {
|
||||
this.removeOld();
|
||||
this.player = new YT.Player("ytapiplayer", {
|
||||
height: VHEIGHT,
|
||||
width: VWIDTH,
|
||||
videoId: this.id,
|
||||
playerVars: {
|
||||
"autoplay": 1,
|
||||
"controls": 1,
|
||||
autohide: 1, // Autohide controls
|
||||
autoplay: 1, // Autoplay video
|
||||
controls: 1, // Show controls
|
||||
iv_load_policy: 3, // No annotations
|
||||
modestbranding: 1, // No logo
|
||||
rel: 0 // No related videos
|
||||
},
|
||||
events: {
|
||||
onReady: function() {
|
||||
|
@ -92,7 +96,7 @@ Media.prototype.initYouTube = function() {
|
|||
else {
|
||||
PLAYER.paused = (ev.data == YT.PlayerState.PAUSED);
|
||||
}
|
||||
if(LEADER && ev.data == YT.PlayerState.ENDED) {
|
||||
if(CLIENT.leader && ev.data == YT.PlayerState.ENDED) {
|
||||
socket.emit("playNext");
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +107,8 @@ Media.prototype.initYouTube = function() {
|
|||
this.load = function(data) {
|
||||
if(this.player.loadVideoById) {
|
||||
this.player.loadVideoById(data.id, data.currentTime);
|
||||
if(VIDEOQUALITY)
|
||||
this.player.setPlaybackQuality(VIDEOQUALITY);
|
||||
this.id = data.id;
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +130,7 @@ Media.prototype.initYouTube = function() {
|
|||
}
|
||||
}
|
||||
|
||||
Media.prototype.initVimeo = function() {
|
||||
Player.prototype.initVimeo = function() {
|
||||
var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
|
||||
$("#ytapiplayer").remove();
|
||||
iframe.attr("id", "ytapiplayer");
|
||||
|
@ -143,7 +149,7 @@ Media.prototype.initVimeo = function() {
|
|||
this.player.api("play");
|
||||
|
||||
this.player.addEvent("finish", function() {
|
||||
if(LEADER) {
|
||||
if(CLIENT.leader) {
|
||||
socket.emit("playNext");
|
||||
}
|
||||
});
|
||||
|
@ -184,7 +190,7 @@ Media.prototype.initVimeo = function() {
|
|||
}
|
||||
}
|
||||
|
||||
Media.prototype.initDailymotion = function() {
|
||||
Player.prototype.initDailymotion = function() {
|
||||
this.removeOld();
|
||||
this.player = DM.player("ytapiplayer", {
|
||||
video: this.id,
|
||||
|
@ -196,7 +202,7 @@ Media.prototype.initDailymotion = function() {
|
|||
this.player.addEventListener("apiready", function(e) {
|
||||
socket.emit("playerReady");
|
||||
this.player.addEventListener("ended", function(e) {
|
||||
if(LEADER) {
|
||||
if(CLIENT.leader) {
|
||||
socket.emit("playNext");
|
||||
}
|
||||
});
|
||||
|
@ -235,7 +241,7 @@ Media.prototype.initDailymotion = function() {
|
|||
}
|
||||
}
|
||||
|
||||
Media.prototype.initSoundcloud = function() {
|
||||
Player.prototype.initSoundcloud = function() {
|
||||
unfixSoundcloudShit();
|
||||
var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
|
||||
$("#ytapiplayer").remove();
|
||||
|
@ -262,7 +268,7 @@ Media.prototype.initSoundcloud = function() {
|
|||
});
|
||||
|
||||
this.player.bind(SC.Widget.Events.FINISH, function() {
|
||||
if(LEADER) {
|
||||
if(CLIENT.leader) {
|
||||
socket.emit("playNext");
|
||||
}
|
||||
});
|
||||
|
@ -292,7 +298,7 @@ Media.prototype.initSoundcloud = function() {
|
|||
}
|
||||
}
|
||||
|
||||
Media.prototype.initLivestream = function() {
|
||||
Player.prototype.initLivestream = function() {
|
||||
this.removeOld();
|
||||
var flashvars = {channel: this.id};
|
||||
var params = {AllowScriptAccess: "always"};
|
||||
|
@ -312,7 +318,7 @@ Media.prototype.initLivestream = function() {
|
|||
this.seek = function() { }
|
||||
}
|
||||
|
||||
Media.prototype.initTwitch = function() {
|
||||
Player.prototype.initTwitch = function() {
|
||||
this.removeOld();
|
||||
var url = "http://www.twitch.tv/widgets/live_embed_player.swf?channel="+this.id;
|
||||
var params = {
|
||||
|
@ -339,7 +345,7 @@ Media.prototype.initTwitch = function() {
|
|||
this.seek = function() { }
|
||||
}
|
||||
|
||||
Media.prototype.initJustinTV = function() {
|
||||
Player.prototype.initJustinTV = function() {
|
||||
this.removeOld();
|
||||
var url = "http://www.justin.tv/widgets/live_embed_player.swf?channel="+this.id;
|
||||
var params = {
|
||||
|
@ -366,16 +372,16 @@ Media.prototype.initJustinTV = function() {
|
|||
this.seek = function() { }
|
||||
}
|
||||
|
||||
Media.prototype.initRTMP = function() {
|
||||
Player.prototype.initRTMP = function() {
|
||||
this.removeOld();
|
||||
var url = "http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf";
|
||||
var url = "http://fpdownload.adobe.com/strobe/FlashPlayerPlayback_101.swf";
|
||||
var src = encodeURIComponent(this.id);
|
||||
var params = {
|
||||
allowFullScreen:"true",
|
||||
allowScriptAccess:"always",
|
||||
allowNetworking:"all",
|
||||
wMode:"direct",
|
||||
movie:"http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf",
|
||||
movie:"http://fpdownload.adobe.com/strobe/FlashPlayerPlayback_101.swf",
|
||||
flashvars:"src="+src+"&streamType=live&autoPlay=true"
|
||||
};
|
||||
swfobject.embedSWF(url, "ytapiplayer", VWIDTH, VHEIGHT, "8", null, null, params, {} );
|
||||
|
@ -394,7 +400,7 @@ Media.prototype.initRTMP = function() {
|
|||
this.seek = function() { }
|
||||
}
|
||||
|
||||
Media.prototype.initJWPlayer = function() {
|
||||
Player.prototype.initJWPlayer = function() {
|
||||
if(typeof jwplayer == "undefined") {
|
||||
setTimeout(function() {
|
||||
this.initJWPlayer();
|
||||
|
@ -445,7 +451,7 @@ Media.prototype.initJWPlayer = function() {
|
|||
}
|
||||
}
|
||||
|
||||
Media.prototype.initUstream = function() {
|
||||
Player.prototype.initUstream = function() {
|
||||
var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
|
||||
$("#ytapiplayer").remove();
|
||||
iframe.attr("id", "ytapiplayer");
|
||||
|
@ -470,7 +476,7 @@ Media.prototype.initUstream = function() {
|
|||
this.seek = function() { }
|
||||
}
|
||||
|
||||
Media.prototype.initImgur = function() {
|
||||
Player.prototype.initImgur = function() {
|
||||
var iframe = $("<iframe/>").insertBefore($("#ytapiplayer"));
|
||||
$("#ytapiplayer").remove();
|
||||
iframe.attr("id", "ytapiplayer");
|
||||
|
@ -495,12 +501,16 @@ Media.prototype.initImgur = function() {
|
|||
this.seek = function() { }
|
||||
}
|
||||
|
||||
Media.prototype.update = function(data) {
|
||||
Player.prototype.update = function(data) {
|
||||
if(data.id && data.id != this.id) {
|
||||
if(data.currentTime < 0) {
|
||||
data.currentTime = 0;
|
||||
}
|
||||
this.load(data);
|
||||
this.play();
|
||||
}
|
||||
if(CLIENT.leader) {
|
||||
return;
|
||||
}
|
||||
if(!USEROPTS.synch) {
|
||||
return;
|
||||
|
@ -512,9 +522,6 @@ Media.prototype.update = function(data) {
|
|||
else {
|
||||
this.play();
|
||||
}
|
||||
if(LEADER) {
|
||||
return;
|
||||
}
|
||||
this.getTime(function(seconds) {
|
||||
var time = data.currentTime;
|
||||
var diff = time - seconds || time;
|
||||
|
@ -528,14 +535,14 @@ Media.prototype.update = function(data) {
|
|||
}.bind(this));
|
||||
}
|
||||
|
||||
Media.prototype.removeOld = function() {
|
||||
Player.prototype.removeOld = function() {
|
||||
var old = $("#ytapiplayer");
|
||||
var placeholder = $("<div/>").insertBefore(old);
|
||||
old.remove();
|
||||
placeholder.attr("id", "ytapiplayer");
|
||||
}
|
||||
|
||||
Media.prototype.hide = function() {
|
||||
Player.prototype.hide = function() {
|
||||
if(!/chrome/ig.test(navigator.userAgent)) {
|
||||
return;
|
||||
}
|
||||
|
@ -547,7 +554,7 @@ Media.prototype.hide = function() {
|
|||
.attr("height", 1);
|
||||
}
|
||||
|
||||
Media.prototype.unhide = function() {
|
||||
Player.prototype.unhide = function() {
|
||||
if(!/chrome/ig.test(navigator.userAgent)) {
|
||||
return;
|
||||
}
|
414
www/assets/js/ui.js
Normal file
414
www/assets/js/ui.js
Normal file
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* window focus/blur */
|
||||
$(window).focus(function() {
|
||||
FOCUSED = true;
|
||||
clearInterval(TITLE_BLINK);
|
||||
TITLE_BLINK = false;
|
||||
document.title = PAGETITLE;
|
||||
}).blur(function() {
|
||||
FOCUSED = false;
|
||||
});
|
||||
|
||||
/* Generalized show/hide function */
|
||||
function generateToggle(chevron, div) {
|
||||
$(chevron).click(function() {
|
||||
if($(div).css("display") == "none") {
|
||||
$(chevron).html($(chevron).html().replace(/Show/, "Hide"));
|
||||
$(div).show();
|
||||
$(chevron+" i").removeClass("icon-plus")
|
||||
.addClass("icon-minus");
|
||||
}
|
||||
else {
|
||||
$(chevron).html($(chevron).html().replace(/Hide/, "Show"));
|
||||
$(div).hide();
|
||||
$(chevron+" i").removeClass("icon-minus")
|
||||
.addClass("icon-plus");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* setup show/hide toggles */
|
||||
generateToggle("#usercountwrap", "#userlist");
|
||||
$("#usercountwrap").click(scrollChat);
|
||||
generateToggle("#librarytoggle", "#librarywrap");
|
||||
generateToggle("#userpltoggle", "#userplaylistwrap");
|
||||
generateToggle("#playlisttoggle", "#playlist_controls");
|
||||
|
||||
/* navbar stuff */
|
||||
$("#optlink").click(showOptionsMenu);
|
||||
$("#chatonly").click(chatOnly);
|
||||
|
||||
function guestLogin() {
|
||||
socket.emit("login", {
|
||||
name: $("#guestname").val(),
|
||||
});
|
||||
}
|
||||
$("#guestlogin").click(guestLogin);
|
||||
$("#guestname").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
guestLogin();
|
||||
}
|
||||
});
|
||||
|
||||
$("#login").click(showLoginMenu);
|
||||
$("#logout").click(function() {
|
||||
eraseCookie("cytube_name");
|
||||
eraseCookie("cytube_session");
|
||||
document.location.reload(true);
|
||||
});
|
||||
|
||||
/* chatbox */
|
||||
$("#messagebuffer").mouseenter(function() { SCROLLCHAT = false; });
|
||||
$("#messagebuffer").mouseleave(function() { SCROLLCHAT = true; });
|
||||
|
||||
$("#chatline").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
var msg = $("#chatline").val();
|
||||
if(msg.trim()) {
|
||||
if(USEROPTS.modhat && CLIENT.rank >= Rank.Moderator) {
|
||||
msg = "/m " + msg;
|
||||
}
|
||||
socket.emit("chatMsg", {
|
||||
msg: msg
|
||||
});
|
||||
CHATHIST.push($("#chatline").val());
|
||||
CHATHISTIDX = CHATHIST.length;
|
||||
$("#chatline").val("");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(ev.keyCode == 9) {
|
||||
var words = $("#chatline").val().split(" ");
|
||||
var current = words[words.length - 1].toLowerCase();
|
||||
var users = $("#userlist").children();
|
||||
var match = null;
|
||||
for(var i = 0; i < users.length; i++) {
|
||||
var name = users[i].children[1].innerHTML.toLowerCase();
|
||||
if(name.indexOf(current) == 0 && match == null) {
|
||||
match = users[i].children[1].innerHTML;
|
||||
}
|
||||
else if(name.indexOf(current) == 0) {
|
||||
match = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(match != null) {
|
||||
words[words.length - 1] = match;
|
||||
if(words.length == 1)
|
||||
words[0] += ": ";
|
||||
else
|
||||
words[words.length - 1] += " ";
|
||||
$("#chatline").val(words.join(" "));
|
||||
}
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else if(ev.keyCode == 38) {
|
||||
if(CHATHISTIDX == CHATHIST.length) {
|
||||
CHATHIST.push($("#chatline").val());
|
||||
}
|
||||
if(CHATHISTIDX > 0) {
|
||||
CHATHISTIDX--;
|
||||
$("#chatline").val(CHATHIST[CHATHISTIDX]);
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else if(ev.keyCode == 40) {
|
||||
if(CHATHISTIDX < CHATHIST.length - 1) {
|
||||
CHATHISTIDX++;
|
||||
$("#chatline").val(CHATHIST[CHATHISTIDX]);
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
/* poll controls */
|
||||
$("#newpollbtn").click(showPollMenu);
|
||||
|
||||
/* search controls */
|
||||
$("#library_search").click(function() {
|
||||
socket.emit("searchMedia", {
|
||||
source: "library",
|
||||
query: $("#library_query").val().toLowerCase()
|
||||
});
|
||||
});
|
||||
|
||||
$("#library_query").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
socket.emit("searchMedia", {
|
||||
source: "library",
|
||||
query: $("#library_query").val().toLowerCase()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("#youtube_search").click(function() {
|
||||
socket.emit("searchMedia", {
|
||||
source: "yt",
|
||||
query: $("#library_query").val().toLowerCase()
|
||||
});
|
||||
});
|
||||
|
||||
/* user playlists */
|
||||
|
||||
$("#userpltoggle").click(function() {
|
||||
socket.emit("listPlaylists");
|
||||
});
|
||||
|
||||
$("#userpl_save").click(function() {
|
||||
if($("#userpl_name").val().trim() == "") {
|
||||
makeAlert("Invalid Name", "Playlist name cannot be empty", "alert-error")
|
||||
.addClass("span12")
|
||||
.insertAfter($("#userpl_save").parent());
|
||||
return;
|
||||
}
|
||||
socket.emit("savePlaylist", {
|
||||
name: $("#userpl_name").val()
|
||||
});
|
||||
});
|
||||
|
||||
/* video controls */
|
||||
(function() {
|
||||
function qualHandler(select, preset) {
|
||||
$(select).click(function() {
|
||||
VIDEOQUALITY = preset;
|
||||
var btn = $("#qualitywrap .btn.dropdown-toggle");
|
||||
var caret = btn.find(".caret").detach();
|
||||
btn.text($(select).text());
|
||||
caret.appendTo(btn);
|
||||
});
|
||||
}
|
||||
qualHandler("#quality_240p", "small");
|
||||
qualHandler("#quality_360p", "medium");
|
||||
qualHandler("#quality_480p", "large");
|
||||
qualHandler("#quality_720p", "hd720");
|
||||
qualHandler("#quality_1080p", "hd1080");
|
||||
})();
|
||||
|
||||
/* playlist controls */
|
||||
|
||||
$("#queue").sortable({
|
||||
start: function(ev, ui) {
|
||||
PL_FROM = ui.item.prevAll().length;
|
||||
},
|
||||
update: function(ev, ui) {
|
||||
PL_TO = ui.item.prevAll().length;
|
||||
if(PL_TO != PL_FROM) {
|
||||
socket.emit("moveMedia", {
|
||||
from: PL_FROM,
|
||||
to: PL_TO
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
$("#queue").disableSelection();
|
||||
|
||||
function queue(pos) {
|
||||
var links = $("#mediaurl").val().split(",");
|
||||
if(pos == "next") {
|
||||
links = links.reverse();
|
||||
}
|
||||
var parsed = [];
|
||||
links.forEach(function(link) {
|
||||
var data = parseMediaLink(link);
|
||||
if(data.id === null || data.type === null) {
|
||||
makeAlert("Error", "Invalid link. Please double check it and remove extraneous information", "alert-error")
|
||||
.addClass("span12")
|
||||
.insertBefore($("#extended_controls"));
|
||||
}
|
||||
else {
|
||||
$("#mediaurl").val("");
|
||||
}
|
||||
parsed.push({
|
||||
id: data.id,
|
||||
type: data.type
|
||||
});
|
||||
});
|
||||
|
||||
if(parsed.length > 1) {
|
||||
socket.emit("queue", {
|
||||
id: false,
|
||||
list: parsed,
|
||||
type: "list",
|
||||
pos: pos
|
||||
});
|
||||
}
|
||||
else {
|
||||
parsed[0].pos = pos;
|
||||
socket.emit("queue", parsed[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$("#queue_next").click(function() {
|
||||
queue("next");
|
||||
});
|
||||
|
||||
$("#queue_end").click(function() {
|
||||
queue("end");
|
||||
});
|
||||
|
||||
$("#mediaurl").keydown(function(ev) {
|
||||
if(ev.keyCode == 13) {
|
||||
queue("end");
|
||||
}
|
||||
});
|
||||
|
||||
$("#qlockbtn").click(function() {
|
||||
socket.emit("togglePlaylistLock");
|
||||
});
|
||||
|
||||
$("#voteskip").click(function() {
|
||||
socket.emit("voteskip");
|
||||
});
|
||||
|
||||
$("#getplaylist").click(function() {
|
||||
var callback = function(data) {
|
||||
PLAYER.hide();
|
||||
socket.listeners("playlist").splice(
|
||||
socket.listeners("playlist").indexOf(callback)
|
||||
);
|
||||
var list = [];
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
var entry = formatURL(data[i]);
|
||||
list.push(entry);
|
||||
}
|
||||
var urls = list.join(",");
|
||||
|
||||
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")
|
||||
.html("×")
|
||||
.appendTo(head);
|
||||
$("<h3/>").text("Playlist URLs").appendTo(head);
|
||||
var body = $("<div/>").addClass("modal-body").appendTo(modal);
|
||||
$("<input/>").attr("type", "text")
|
||||
.val(urls)
|
||||
.appendTo(body);
|
||||
$("<div/>").addClass("modal-footer").appendTo(modal);
|
||||
modal.on("hidden", function() {
|
||||
modal.remove();
|
||||
PLAYER.unhide();
|
||||
});
|
||||
modal.modal();
|
||||
}
|
||||
socket.on("playlist", callback);
|
||||
socket.emit("requestPlaylist");
|
||||
});
|
||||
|
||||
$("#clearplaylist").click(function() {
|
||||
var clear = confirm("Are you sure you want to clear the playlist?");
|
||||
if(clear) {
|
||||
socket.emit("clearPlaylist");
|
||||
}
|
||||
});
|
||||
|
||||
$("#shuffleplaylist").click(function() {
|
||||
var shuffle = confirm("Are you sure you want to shuffle the playlist?");
|
||||
if(shuffle) {
|
||||
socket.emit("shufflePlaylist");
|
||||
}
|
||||
});
|
||||
|
||||
/* layout stuff */
|
||||
$(window).resize(function() {
|
||||
VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
|
||||
var 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);
|
||||
});
|
||||
|
||||
/* first time */
|
||||
if(USEROPTS.first_visit) {
|
||||
var al = makeAlert("Playlist Options", [
|
||||
"From the Options menu, you can choose to automatically",
|
||||
" hide the buttons on each entry (and show them when",
|
||||
" you right click). You can also choose to use the old",
|
||||
" style of playlist buttons.",
|
||||
"<br>"].join(""))
|
||||
.addClass("span12")
|
||||
.insertBefore($("#queue"));
|
||||
|
||||
al.find(".close").remove();
|
||||
|
||||
$("<button/>").addClass("btn btn-primary")
|
||||
.text("Dismiss")
|
||||
.appendTo(al)
|
||||
.click(function() {
|
||||
USEROPTS.first_visit = false;
|
||||
saveOpts();
|
||||
al.hide("blind", function() {
|
||||
al.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* initial YouTube api */
|
||||
|
||||
if(!USEROPTS.hidevid) {
|
||||
var tag = document.createElement("script");
|
||||
tag.src = "http://www.youtube.com/iframe_api";
|
||||
var firstScriptTag = document.getElementsByTagName("script")[0];
|
||||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
||||
}
|
||||
|
||||
function onYouTubeIframeAPIReady() {
|
||||
if(!PLAYER)
|
||||
PLAYER = new Player({id:"", type: "yt"});
|
||||
if(FLUIDLAYOUT)
|
||||
fluid();
|
||||
}
|
||||
|
||||
/* load channel */
|
||||
|
||||
var loc = document.location+"";
|
||||
var m = loc.match(/\/r\/([a-zA-Z0-9-_]+)$/);
|
||||
if(m) {
|
||||
CHANNEL.name = m[1];
|
||||
}
|
||||
else {
|
||||
var main = $("#main");
|
||||
var container = $("<div/>").addClass("container").insertBefore(main);
|
||||
var row = $("<div/>").addClass("row").appendTo(container);
|
||||
var div = $("<div/>").addClass("span6").appendTo(row);
|
||||
main.css("display", "none");
|
||||
var label = $("<label/>").text("Enter Channel:").appendTo(div);
|
||||
var entry = $("<input/>").attr("type", "text").appendTo(div);
|
||||
entry.keydown(function(ev) {
|
||||
var host = ""+document.location;
|
||||
host = host.replace("http://", "");
|
||||
host = host.substring(0, host.indexOf("/"));
|
||||
if(ev.keyCode == 13) {
|
||||
document.location = "http://" + host + "/r/" + entry.val();
|
||||
socket.emit("joinChannel", {
|
||||
name: entry.val()
|
||||
});
|
||||
container.remove();
|
||||
main.css("display", "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* oh internet explorer, how I hate thee */
|
||||
$(":input:not(textarea)").keypress(function(ev) {
|
||||
return ev.keyCode != 13;
|
||||
});
|
1310
www/assets/js/util.js
Normal file
1310
www/assets/js/util.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,127 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Secure Hash Algorithm (SHA256)
|
||||
* http://www.webtoolkit.info/
|
||||
*
|
||||
* Original code by Angel Marin, Paul Johnston.
|
||||
*
|
||||
**/
|
||||
|
||||
function SHA256(s){
|
||||
|
||||
var chrsz = 8;
|
||||
var hexcase = 0;
|
||||
|
||||
function safe_add (x, y) {
|
||||
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
||||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xFFFF);
|
||||
}
|
||||
|
||||
function S (X, n) { return ( X >>> n ) | (X << (32 - n)); }
|
||||
function R (X, n) { return ( X >>> n ); }
|
||||
function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); }
|
||||
function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); }
|
||||
function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); }
|
||||
function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); }
|
||||
function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); }
|
||||
function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); }
|
||||
|
||||
function core_sha256 (m, l) {
|
||||
var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2);
|
||||
var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
|
||||
var W = new Array(64);
|
||||
var a, b, c, d, e, f, g, h, i, j;
|
||||
var T1, T2;
|
||||
|
||||
m[l >> 5] |= 0x80 << (24 - l % 32);
|
||||
m[((l + 64 >> 9) << 4) + 15] = l;
|
||||
|
||||
for ( var i = 0; i<m.length; i+=16 ) {
|
||||
a = HASH[0];
|
||||
b = HASH[1];
|
||||
c = HASH[2];
|
||||
d = HASH[3];
|
||||
e = HASH[4];
|
||||
f = HASH[5];
|
||||
g = HASH[6];
|
||||
h = HASH[7];
|
||||
|
||||
for ( var j = 0; j<64; j++) {
|
||||
if (j < 16) W[j] = m[j + i];
|
||||
else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
|
||||
|
||||
T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
|
||||
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = safe_add(d, T1);
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = safe_add(T1, T2);
|
||||
}
|
||||
|
||||
HASH[0] = safe_add(a, HASH[0]);
|
||||
HASH[1] = safe_add(b, HASH[1]);
|
||||
HASH[2] = safe_add(c, HASH[2]);
|
||||
HASH[3] = safe_add(d, HASH[3]);
|
||||
HASH[4] = safe_add(e, HASH[4]);
|
||||
HASH[5] = safe_add(f, HASH[5]);
|
||||
HASH[6] = safe_add(g, HASH[6]);
|
||||
HASH[7] = safe_add(h, HASH[7]);
|
||||
}
|
||||
return HASH;
|
||||
}
|
||||
|
||||
function str2binb (str) {
|
||||
var bin = Array();
|
||||
var mask = (1 << chrsz) - 1;
|
||||
for(var i = 0; i < str.length * chrsz; i += chrsz) {
|
||||
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
function Utf8Encode(string) {
|
||||
string = string.replace(/\r\n/g,"\n");
|
||||
var utftext = "";
|
||||
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
|
||||
var c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return utftext;
|
||||
}
|
||||
|
||||
function binb2hex (binarray) {
|
||||
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
var str = "";
|
||||
for(var i = 0; i < binarray.length * 4; i++) {
|
||||
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
|
||||
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
s = Utf8Encode(s);
|
||||
return binb2hex(core_sha256(str2binb(s), s.length * chrsz));
|
||||
|
||||
}
|
200
www/channel-new.html
Normal file
200
www/channel-new.html
Normal file
|
@ -0,0 +1,200 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CyTube</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="A free, open source synchtube replacement">
|
||||
<meta name="author" content="Calvin 'calzoneman' Montgomery">
|
||||
|
||||
<link href="./assets/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="./assets/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="./assets/css/ytsync.css" rel="stylesheet" id="defaultcss">
|
||||
<link href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<!-- begin navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="index.html">CyTube</a>
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="index.html">Home</a></li>
|
||||
<li><a href="help.html">Help</a></li>
|
||||
<li><a href="account.html">Account</a></li>
|
||||
<li><a href="javascript:void(0)" id="optlink">Options</a></li>
|
||||
</ul>
|
||||
<div class="navbar-form pull-right" id="loginform">
|
||||
<input type="text" id="guestname" placeholder="Name">
|
||||
<button class="btn" id="guestlogin">Guest Login</button>
|
||||
<button class="btn" id="login">Login/Register</button>
|
||||
</div>
|
||||
<div class="navbar-form pull-right" id="logoutform" style="display: none;">
|
||||
<span id="welcome"></span>
|
||||
<button class="btn" id="logout">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end navbar -->
|
||||
<!-- begin main page -->
|
||||
<div class="container" id="mainpage">
|
||||
<!-- top row (MOTD, drink count) -->
|
||||
<div class="row-fluid" id="toprow">
|
||||
<div class="well span12" id="motd">
|
||||
</div>
|
||||
<div class="span12" id="drinkbar">
|
||||
<h1 id="drinkcount"></h1>
|
||||
</div>
|
||||
</div>
|
||||
<!-- announcement area -->
|
||||
<div class="row-fluid" id="announcements">
|
||||
</div>
|
||||
<!-- main row -->
|
||||
<div class="row" id="main">
|
||||
<!-- chat container -->
|
||||
<div class="span5" id="chatwrap">
|
||||
<!-- user count -->
|
||||
<div id="usercountwrap" class="pointer">
|
||||
<i class="icon-chevron-up pull-left" id="userlisttoggle" title="Show/Hide Userlist"></i>
|
||||
<p id="usercount">Not connected</p>
|
||||
</div>
|
||||
<!-- userlist -->
|
||||
<div id="userlist">
|
||||
</div>
|
||||
<!-- message buffer -->
|
||||
<div id="messagebuffer">
|
||||
</div>
|
||||
<!-- chat input -->
|
||||
<input type="text" id="chatline" maxlength="240" class="span5">
|
||||
</div>
|
||||
<!-- video container -->
|
||||
<div class="span7" id="videowrap">
|
||||
<!-- current video display -->
|
||||
<p id="currenttitle">Nothing playing</p>
|
||||
<!-- video frame -->
|
||||
<div id="ytapiplayer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- playlist row -->
|
||||
<div class="row" id="playlistrow">
|
||||
<!-- left pane - Library + user playlists -->
|
||||
<div class="span5" id="leftpane-outer">
|
||||
<div class="row-fluid" id="leftpane-inner">
|
||||
<!-- poll container -->
|
||||
<div class="span12" id="pollwrap">
|
||||
<!-- new poll controls -->
|
||||
<button class="btn btn-primary btn-small" id="newpollbtn">New Poll</button>
|
||||
</div>
|
||||
<!-- library search -->
|
||||
<div class="span12 pointer" id="librarytoggle">
|
||||
<i class="icon-chevron-down pull-left"></i>
|
||||
<p>Show Library</p>
|
||||
</div>
|
||||
<div id="librarywrap">
|
||||
<div class="span7" id="querywrap">
|
||||
<input type="text" id="library_query" class="input-block-level" placeholder="Search Query">
|
||||
</div>
|
||||
<div class="span5 btn-group" id="searchbtns">
|
||||
<button class="btn" id="library_search">Library</button>
|
||||
<button class="btn" id="youtube_search">YouTube</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- user playlists -->
|
||||
<div class="span12 pointer" id="userpltoggle">
|
||||
<i class="icon-chevron-down pull-left"></i>
|
||||
<p>Show Playlist Manager</p>
|
||||
</div>
|
||||
<div id="userplaylistwrap">
|
||||
<div class="span7">
|
||||
<input type="text" id="userpl_name" class="input-block-level" placeholder="Playlist Name">
|
||||
</div>
|
||||
<div class="span5">
|
||||
<button class="btn btn-block" id="userpl_save">Save Playlist</button>
|
||||
</div>
|
||||
<ul class="span12" id="userpl_list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- right pane - channel playlist -->
|
||||
<div class="span7" id="rightpane-outer">
|
||||
<div class="row-fluid" id="rightpane-inner">
|
||||
<!-- account for left pane having the poll buffer -->
|
||||
<div class="span12" id="queue_align"></div>
|
||||
<!-- playlist controls -->
|
||||
<div class="span12 pointer" id="playlisttoggle">
|
||||
<i class="icon-chevron-down pull-left"></i>
|
||||
<p>Show Playlist Controls</p>
|
||||
</div>
|
||||
<div id="playlist_controls">
|
||||
<div class="span8">
|
||||
<input type="text" id="mediaurl" class="input-block-level" placeholder="Media URL">
|
||||
</div>
|
||||
<div class="span4 btn-group">
|
||||
<button class="btn" id="queue_next">Next</button>
|
||||
<button class="btn" id="queue_end">End</button>
|
||||
</div>
|
||||
<div id="extended_controls" class="span12">
|
||||
<button class="btn btn-danger btn-block" id="qlockbtn">Unlock Queue</button>
|
||||
<button class="btn btn-block" id="getplaylist">Get Playlist URLs</button>
|
||||
<button class="btn btn-block" id="clearplaylist">Clear Playlist</button>
|
||||
<button class="btn btn-block" id="shuffleplaylist">Shuffle Playlist</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- video queue -->
|
||||
<ul class="span12 videolist" id="queue">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="push"></div>
|
||||
<div id="sitefooter">
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="muted">
|
||||
CyTube Software Copyright © 2013 Calvin Montgomery · Available for free on <a href="http://github.com/calzoneman/sync">GitHub</a> ·
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5Y7PUVVGVSEWG&lc=US&item_name=CyTube¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">Donate</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="./assets/js/jquery.js"></script>
|
||||
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
|
||||
<!-- My Javascript -->
|
||||
<script src="./assets/js/data.js"></script>
|
||||
<script src="./assets/js/util.js"></script>
|
||||
<script src="./assets/js/ui.js"></script>
|
||||
<script src="./assets/js/callbacks.js"></script>
|
||||
<!--
|
||||
<script src="./assets/js/iourl.js"></script>
|
||||
<script src="./assets/js/notwebsocket.js"></script>
|
||||
<script src="./assets/js/media.js"></script>
|
||||
<script src="./assets/js/functions.js"></script>
|
||||
<script src="./assets/js/client.js"></script>
|
||||
<script src="./assets/js/callbacks.js"></script>
|
||||
-->
|
||||
<!-- APIs -->
|
||||
<!--
|
||||
<script src="http://api.dmcdn.net/all.js"></script>
|
||||
<script src="http://jwpsrv.com/library/QouFCLBMEeKC+CIACpYGxA.js"></script>
|
||||
<script src="./assets/js/sc.js"></script>
|
||||
<script src="./assets/js/froogaloop.min.js"></script>
|
||||
<script src="./assets/js/swf.js"></script>
|
||||
-->
|
||||
<!-- Third party -->
|
||||
<script src="./assets/js/bootstrap.js"></script>
|
||||
<script src="./assets/js/bootstrap-transition.js"></script>
|
||||
<script src="./assets/js/bootstrap-modal.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
465
www/channel.html
465
www/channel.html
|
@ -4,334 +4,241 @@
|
|||
<meta charset="utf-8">
|
||||
<title>CyTube</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="description" content="A free, open source synchtube replacement">
|
||||
<meta name="author" content="Calvin 'calzoneman' Montgomery">
|
||||
|
||||
<link href="./assets/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="./assets/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="./assets/css/ytsync.css" rel="stylesheet" id="defaultcss">
|
||||
<link href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
||||
padding-top: 60px;
|
||||
}
|
||||
</style>
|
||||
<link href="./assets/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="index.html">CyTube</a>
|
||||
<div class="">
|
||||
<!-- begin navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="index.html">CyTube</a>
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="index.html">Home</a></li>
|
||||
<li><a href="help.html">Help</a></li>
|
||||
<li><a href="account.html">Account</a></li>
|
||||
<li><a href="https://github.com/calzoneman/sync/wiki/Beginner%27s-Guide-and-FAQ" target="_blank">Help</a></li>
|
||||
<li><a href="account.html" target="_blank">Account</a></li>
|
||||
<li><a href="javascript:void(0)" id="optlink">Options</a></li>
|
||||
<li><a href="javascript:void(0)" id="chatonly">Chat Only</a></li>
|
||||
</ul>
|
||||
<div class="navbar-form pull-right" id="loginform">
|
||||
<input type="text" id="guestname" placeholder="Name">
|
||||
<button class="btn" id="guestlogin">Guest Login</button>
|
||||
<button class="btn" id="login">Login/Register</button>
|
||||
<input type="text" id="guestname" placeholder="Name">
|
||||
<button class="btn" id="guestlogin">Guest Login</button>
|
||||
<button class="btn" id="login">Login/Register</button>
|
||||
</div>
|
||||
<div class="navbar-form pull-right" id="logoutform" style="display: none;">
|
||||
<span id="welcome"></span>
|
||||
<button class="btn" id="logout">Logout</button>
|
||||
<span id="welcome"></span>
|
||||
<button class="btn" id="logout">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row-fluid" id="motdrow">
|
||||
<div class="well span12">
|
||||
<p id="motd"></p>
|
||||
</div>
|
||||
<div class="span12" id="drinkbar">
|
||||
<h1 id="drinkcount"></h1>
|
||||
</div>
|
||||
<!-- end navbar -->
|
||||
<!-- begin main page -->
|
||||
<div class="container" id="mainpage">
|
||||
<!-- top row (MOTD, drink count) -->
|
||||
<div class="row-fluid" id="toprow">
|
||||
<div class="well span12" id="motd">
|
||||
</div>
|
||||
<div class="span12" id="drinkbar">
|
||||
<h1 id="drinkcount"></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid" id="announcerow" style="display: none">
|
||||
<!-- announcement area -->
|
||||
<div class="row-fluid" id="announcements">
|
||||
</div>
|
||||
<div class="row" id="main" style="margin-top: 20px;">
|
||||
<div class="span5" id="chatdiv">
|
||||
<div id="usercountcontainer">
|
||||
<i class="icon-chevron-up" id="ulistchevron" title="Show/Hide Userlist"></i>
|
||||
<p id="usercount"></p>
|
||||
<!-- main row -->
|
||||
<div class="row" id="main">
|
||||
<div class="span12" id="main-outer">
|
||||
<div class="row" id="main-inner">
|
||||
<!-- chat container -->
|
||||
<div class="span5" id="chatwrap">
|
||||
<!-- user count -->
|
||||
<div id="usercountwrap" class="pointer">
|
||||
<i class="icon-chevron-up pull-left" id="userlisttoggle" title="Show/Hide Userlist"></i>
|
||||
<p id="usercount">Not connected</p>
|
||||
</div>
|
||||
<!-- userlist -->
|
||||
<div id="userlist">
|
||||
</div>
|
||||
<!-- message buffer -->
|
||||
<div id="messagebuffer">
|
||||
</div>
|
||||
<!-- chat input -->
|
||||
<input type="text" id="chatline" maxlength="240" class="span5">
|
||||
</div>
|
||||
<div class="span7" id="videodiv">
|
||||
<p id="currenttitle">Currently Playing: </p>
|
||||
</div>
|
||||
<!-- video container -->
|
||||
<div class="span7" id="videowrap">
|
||||
<!-- current video display -->
|
||||
<p id="currenttitle">Nothing playing</p>
|
||||
<!-- video frame -->
|
||||
<div id="ytapiplayer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="queuerow">
|
||||
<div class="span5">
|
||||
<div class="row-fluid">
|
||||
<div class="span12" id="pollcontainer">
|
||||
<!-- playlist row -->
|
||||
<div class="row" id="playlistrow">
|
||||
<div class="span12" id="playlist-outer">
|
||||
<div class="row" id="playlist-inner">
|
||||
<!-- left pane - Library + user playlists -->
|
||||
<div class="span5" id="leftpane-outer">
|
||||
<div class="row-fluid" id="leftpane-inner">
|
||||
<!-- new poll controls -->
|
||||
<div class="span12" id="pollbtnwrap">
|
||||
<button class="btn btn-small" id="newpollbtn">New Poll</button>
|
||||
</div>
|
||||
<!-- poll container -->
|
||||
<div class="span12" id="pollwrap">
|
||||
</div>
|
||||
<!-- library search -->
|
||||
<div class="well well-small span12 row-fluid">
|
||||
<div class="span12 pointer" id="librarytoggle">
|
||||
<i class="icon-plus pull-left"></i>
|
||||
<p>Show Library</p>
|
||||
</div>
|
||||
<div id="librarywrap">
|
||||
<div class="span7" id="querywrap">
|
||||
<input type="text" id="library_query" class="input-block-level" placeholder="Search Query">
|
||||
</div>
|
||||
<div class="span12" id="leftpanetabs" style="margin-left: 0">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="active"><a href="javascript:void(0)" id="show_library">Library/YouTube Search</a></li>
|
||||
<li><a href="javascript:void(0)" id="show_userpl">User Playlists</a></li>
|
||||
<div class="span5 btn-group" id="searchbtns">
|
||||
<button class="btn" id="library_search">Library</button>
|
||||
<button class="btn" id="youtube_search">YouTube</button>
|
||||
</div>
|
||||
<div id="userplcontainer" style="display: none">
|
||||
<div class="span7" style="margin-left: 0;">
|
||||
<input type="text" id="userpl_name" class="input-block-level" placeholder="Playlist Name">
|
||||
</div>
|
||||
<div class="span5">
|
||||
<button class="btn btn-block" id="userpl_save">Save Playlist</button>
|
||||
</div>
|
||||
<ul class="span12" id="userpl_list" style="margin-left: 0">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="libcontainer">
|
||||
<div class="span7" style="margin-left: 0;">
|
||||
<input type="text" id="library_query" class="input-block-level" placeholder="Search Query">
|
||||
</div>
|
||||
<div class="span5 btn-group">
|
||||
<button class="btn" id="library_search">Library</button>
|
||||
<button class="btn" id="youtube_search">YouTube</button>
|
||||
</div>
|
||||
<div class="span12" style="margin-left: 0;">
|
||||
<ul id="library" class="videolist">
|
||||
</ul>
|
||||
<button class="btn btn-block" id="search_clear">Clear Results</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span7" id="queuediv">
|
||||
<div class="row-fluid" id="qclear">
|
||||
<div class="span12"></div>
|
||||
</div>
|
||||
<div id="playlist_controls"style="display: none;">
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<input type="text" id="mediaurl" class="input-block-level" placeholder="Media URL">
|
||||
</div>
|
||||
<div class="span4 btn-group">
|
||||
<button class="btn" id="queue_next">Next</button>
|
||||
<button class="btn" id="queue_end">End</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-block" id="voteskip">Voteskip</button>
|
||||
<div class="row-fluid">
|
||||
<ul id="queue" class="span12 videolist">
|
||||
<ul class="span12 videolist" id="library">
|
||||
</ul>
|
||||
<div class="span12 well well-small" id="plmeta">
|
||||
<span id="plcount"></span>
|
||||
<span id="pllength"></span>
|
||||
<div class="clear: both;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- user playlists -->
|
||||
<div class="well well-small span12 row-fluid" id="userpltogglewrap">
|
||||
<div class="span12 pointer" id="userpltoggle">
|
||||
<i class="icon-plus pull-left"></i>
|
||||
<p>Show Playlist Manager</p>
|
||||
</div>
|
||||
<div id="userplaylistwrap">
|
||||
<div class="span7">
|
||||
<input type="text" id="userpl_name" class="input-block-level" placeholder="Playlist Name">
|
||||
</div>
|
||||
<button class="btn btn-danger btn-block" id="qlockbtn" style="display:none;">Unlock Queue</button>
|
||||
<button class="btn btn-block" id="getplaylist" style="display: none;">Get Playlist URLs</button>
|
||||
<button class="btn btn-block" id="clearplaylist" style="display: none;">Clear Playlist</button>
|
||||
<button class="btn btn-block" id="shuffleplaylist" style="display: none;">Shuffle Playlist</button>
|
||||
<div class="span5">
|
||||
<button class="btn btn-block" id="userpl_save">Save Playlist</button>
|
||||
</div>
|
||||
<ul class="span12" id="userpl_list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- right pane - channel playlist -->
|
||||
<div class="span7" id="rightpane-outer">
|
||||
<div class="row-fluid" id="rightpane-inner">
|
||||
<!-- account for left pane having the poll buffer -->
|
||||
<div class="span12" id="qualitywrap">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-small dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">
|
||||
Quality <span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="quality_240p" href="javascript:void(0)">240p</a></li>
|
||||
<li><a id="quality_360p" href="javascript:void(0)">360p</a></li>
|
||||
<li><a id="quality_480p" href="javascript:void(0)">480p</a></li>
|
||||
<li><a id="quality_720p" href="javascript:void(0)">720p</a></li>
|
||||
<li><a id="quality_1080p" href="javascript:void(0)">1080p</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- electric boogaloo -->
|
||||
<div class="span12" id="queue_align2"></div>
|
||||
<!-- playlist controls -->
|
||||
<div class="well well-small span12 row-fluid" id="playlisttogglewrap">
|
||||
<div class="span12 pointer" id="playlisttoggle">
|
||||
<i class="icon-plus pull-left"></i>
|
||||
<p>Show Playlist Controls</p>
|
||||
</div>
|
||||
<div id="playlist_controls">
|
||||
<div class="span8">
|
||||
<input type="text" id="mediaurl" class="input-block-level" placeholder="Media URL">
|
||||
</div>
|
||||
<div class="span4 btn-group">
|
||||
<button class="btn" id="queue_next">Next</button>
|
||||
<button class="btn" id="queue_end">End</button>
|
||||
</div>
|
||||
<div id="extended_controls" class="span12">
|
||||
<button class="btn btn-danger btn-block" id="qlockbtn">Unlock Queue</button>
|
||||
<button class="btn btn-block" id="clearplaylist">Clear Playlist</button>
|
||||
<button class="btn btn-block" id="shuffleplaylist">Shuffle Playlist</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group span12">
|
||||
<button class="btn" style="width: 50%" id="voteskip">Voteskip</button>
|
||||
<button class="btn" style="width: 50%" id="getplaylist">Get Playlist URLs</button>
|
||||
</div>
|
||||
<!-- video queue -->
|
||||
<ul class="span12 videolist" id="queue">
|
||||
</ul>
|
||||
<div class="span12" id="plmeta">
|
||||
<span id="plcount">0 items</span>
|
||||
<span id="pllength">00:00:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="display: none;" id="modnav">
|
||||
<div class="span12" id="modtabs">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active" id="chancontrols_tab">
|
||||
<a href="javascript:void(0)" id="show_chancontrols">Channel Controls</a>
|
||||
</li>
|
||||
<li id="chanperms_tab">
|
||||
<a href="javascript:void(0)" id="show_chanperms">Channel Permissions</a>
|
||||
</li>
|
||||
<li id="banlist_tab">
|
||||
<a href="javascript:void(0)" id="show_banlist">Ban List</a>
|
||||
</li>
|
||||
<li id="loginlog_tab">
|
||||
<a href="javascript:void(0)" id="show_loginlog">Connection Log</a>
|
||||
</li>
|
||||
<li id="motdeditor_tab">
|
||||
<a href="javascript:void(0)" id="show_motdeditor">MOTD</a>
|
||||
</li>
|
||||
<li style="display: none" id="csseditor_tab">
|
||||
<a href="javascript:void(0)" id="show_csseditor">CSS Editor</a>
|
||||
</li>
|
||||
<li style="display: none" id="jseditor_tab">
|
||||
<a href="javascript:void(0)" id="show_jseditor">JS Editor</a>
|
||||
</li>
|
||||
<li id="filtereditor_tab">
|
||||
<a href="javascript:void(0)" id="show_filtereditor">Chat Filters</a>
|
||||
</li>
|
||||
<li id="acl_tab">
|
||||
<a href="javascript:void(0)" id="show_acl">Channel Ranks</a>
|
||||
</li>
|
||||
<li style="display: none" id="dropchannel_tab">
|
||||
<a href="javascript:void(0)" id="drop_channel">Unregister Channel</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- moderator controls -->
|
||||
<!-- there has got to be a better way to nest this -->
|
||||
<div class="span12" id="channelsettingswrap3">
|
||||
<div class="well" id="channelsettingswrap2">
|
||||
<div class="row-fluid" id="channelsettingswrap">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" style="display: none" id="chancontrols">
|
||||
<div class="span12">
|
||||
<form action="javascript:void(0)">
|
||||
<fieldset>
|
||||
<div class="span5">
|
||||
<label>Page Title
|
||||
<input type="text" id="opt_pagetitle" placeholder="CyTube" class="pull-right">
|
||||
</label>
|
||||
<br>
|
||||
<label>External CSS
|
||||
<input type="text" id="opt_customcss" class="pull-right" placeholder="CSS URL">
|
||||
</label>
|
||||
<br>
|
||||
<label>External JS
|
||||
<input type="text" id="opt_customjs" class="pull-right" placeholder="JS URL">
|
||||
</label>
|
||||
<br>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="opt_allow_voteskip">
|
||||
Allow voteskip
|
||||
</label>
|
||||
<br>
|
||||
<label>Voteskip Ratio
|
||||
<input type="text" id="opt_voteskip_ratio" class="pull-right">
|
||||
</label>
|
||||
<br>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="opt_chat_antiflood">
|
||||
Prevent chat flood
|
||||
</label>
|
||||
<br>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="opt_show_public">
|
||||
Show channel publicly
|
||||
</label>
|
||||
<br>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="opt_enable_link_regex">
|
||||
Convert URLs to links in chat messages
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="span10">
|
||||
<button class="btn btn-primary" id="opt_submit">Save</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="chanperms" style="display: none;">
|
||||
</div>
|
||||
<div class="row modonly" id="banlist" style="display: none;">
|
||||
<div class="span12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<th></th>
|
||||
<th>IP</th>
|
||||
<th>Name</th>
|
||||
<th>Banned By</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="loginlog" style="display: none;">
|
||||
<div class="span12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<th></th>
|
||||
<th>IP</th>
|
||||
<th>Names</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="motdeditor" style="display: none;">
|
||||
<div class="span12">
|
||||
<textarea rows="10" id="motdtext"></textarea>
|
||||
<button class="btn btn-primary" id="updatemotd">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="csseditor" style="display: none;">
|
||||
<div class="span12">
|
||||
<p>Max 20KB. If you need more CSS, host the file somewhere and use the External CSS channel option</p>
|
||||
<textarea rows="10" id="csstext"></textarea>
|
||||
<button class="btn btn-primary" id="updatecss">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="jseditor" style="display: none;">
|
||||
<div class="span12">
|
||||
<p>Max 20KB. If you need more JS, host the file somewhere and use the External JS channel option</p>
|
||||
<textarea rows="10" id="jstext"></textarea>
|
||||
<button class="btn btn-primary" id="updatejs">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="filtereditor" style="display: none;">
|
||||
<div class="span12">
|
||||
<p><strong>Note:</strong> if you just want simple word replacement, like emoticons, put the word in the Regex field, use <code>ig</code> for the flags, and put the replacement in the Replacement field.</p>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Regex</th>
|
||||
<th>Flags</th>
|
||||
<th>Replacement</th>
|
||||
<th>Active</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="span12">
|
||||
<p>Multiple filters can be added at once below. They should contain 3-4 fields separated by whitespace: (name) regex flags replacement.<br>If any field contains whitespace, it must be escaped by a backslash, for example "what\ a\ story\ mark"</p>
|
||||
<textarea rows="10" class="input-block-level" id="multifiltereditor"></textarea>
|
||||
<button class="btn btn-primary" id="multifilter">Update Multiple</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row modonly" id="channelranks" style="display: none;">
|
||||
<div class="span12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Rank (Click to edit)</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
</div>
|
||||
<div class="push"></div>
|
||||
<div id="sitefooter">
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="muted">
|
||||
CyTube Software Copyright © 2013 Calvin Montgomery · Available for free on <a href="http://github.com/calzoneman/sync">GitHub</a> ·
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5Y7PUVVGVSEWG&lc=US&item_name=CyTube¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">Donate</a>
|
||||
</p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p class="muted">
|
||||
CyTube Software Copyright © 2013 Calvin Montgomery · Available for free on <a href="http://github.com/calzoneman/sync">GitHub</a> ·
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5Y7PUVVGVSEWG&lc=US&item_name=CyTube¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">Donate</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="./assets/js/jquery.js"></script>
|
||||
<!-- My Javascript -->
|
||||
<script src="./assets/js/iourl.js"></script>
|
||||
<script src="./assets/js/notwebsocket.js"></script>
|
||||
<script src="./assets/js/media.js"></script>
|
||||
<script src="./assets/js/functions.js"></script>
|
||||
<script src="./assets/js/client.js"></script>
|
||||
<script src="./assets/js/callbacks.js"></script>
|
||||
<!-- APIs -->
|
||||
<script src="http://api.dmcdn.net/all.js"></script>
|
||||
<script src="http://jwpsrv.com/library/QouFCLBMEeKC+CIACpYGxA.js"></script>
|
||||
<script src="./assets/js/sc.js"></script>
|
||||
<script src="./assets/js/froogaloop.min.js"></script>
|
||||
<script src="./assets/js/swf.js"></script>
|
||||
<!-- Third party -->
|
||||
<script src="./assets/js/bootstrap.js"></script>
|
||||
<script src="./assets/js/bootstrap-transition.js"></script>
|
||||
<script src="./assets/js/bootstrap-modal.js"></script>
|
||||
<script src="./assets/js/jquery.js"></script>
|
||||
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
|
||||
<!-- My Javascript -->
|
||||
<script src="./assets/js/data.js"></script>
|
||||
<script src="./assets/js/iourl.js"></script>
|
||||
<script src="./assets/js/player.js"></script>
|
||||
<script src="./assets/js/notwebsocket.js"></script>
|
||||
<script src="./assets/js/util.js"></script>
|
||||
<script src="./assets/js/ui.js"></script>
|
||||
<script src="./assets/js/callbacks.js"></script>
|
||||
<!-- APIs -->
|
||||
<script src="http://api.dmcdn.net/all.js"></script>
|
||||
<script src="http://jwpsrv.com/library/QouFCLBMEeKC+CIACpYGxA.js"></script>
|
||||
<script src="./assets/js/sc.js"></script>
|
||||
<script src="./assets/js/froogaloop.min.js"></script>
|
||||
<script src="./assets/js/swf.js"></script>
|
||||
<!-- Third party -->
|
||||
<script src="./assets/js/bootstrap.js"></script>
|
||||
<script src="./assets/js/bootstrap-transition.js"></script>
|
||||
<script src="./assets/js/bootstrap-modal.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -45,15 +45,15 @@
|
|||
<script src="assets/js/jquery.js" type="text/javascript"></script>
|
||||
<script src="assets/js/iourl.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
var session = readCookie("sync_session") || "";
|
||||
var uname = readCookie("sync_uname") || "";
|
||||
var session = readCookie("cytube_session") || "";
|
||||
var uname = readCookie("cytube_uname") || "";
|
||||
var p = "";
|
||||
if(uname && session) {
|
||||
$.getJSON(WEB_URL+"/api/json/login?name="+uname+"&session="+session+"&callback=?", function(data) {
|
||||
if(data.success) {
|
||||
$(".loginform").remove();
|
||||
createCookie("sync_uname", uname, 7);
|
||||
createCookie("sync_session", session, 7);
|
||||
createCookie("cytube_uname", uname, 7);
|
||||
createCookie("cytube_session", session, 7);
|
||||
p = "name=" + uname + "&session=" + session;
|
||||
refresh();
|
||||
setInterval(refresh, 5000);
|
||||
|
@ -68,8 +68,8 @@
|
|||
if(data.success) {
|
||||
$(".loginform").remove();
|
||||
session = data.session;
|
||||
createCookie("sync_uname", uname, 7);
|
||||
createCookie("sync_session", session, 7);
|
||||
createCookie("cytube_uname", uname, 7);
|
||||
createCookie("cytube_session", session, 7);
|
||||
p = "name=" + uname + "&session=" + session;
|
||||
}
|
||||
});
|
||||
|
|
208
www/channeloptions.html
Normal file
208
www/channeloptions.html
Normal file
|
@ -0,0 +1,208 @@
|
|||
<script src="/assets/js/channelsettings.js"></script>
|
||||
<button id="hide_settings" class="pull-right close">×</button>
|
||||
<div class="btn-group dropup">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">
|
||||
<span id="csdropdown_title">Moderation Menu</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" id="channelsettings_nav">
|
||||
<li id="optedit_tab"><a href="javascript:void(0);" id="show_optedit">Channel Options</a></li>
|
||||
<li id="permedit_tab"><a href="javascript:void(0);" id="show_permedit">Permissions</a></li>
|
||||
<li id="motdedit_tab"><a href="javascript:void(0);" id="show_motdedit">MOTD Editor</a></li>
|
||||
<li id="filteredit_tab"><a href="javascript:void(0);" id="show_filteredit">Chat Filters</a></li>
|
||||
<li id="cssedit_tab"><a href="javascript:void(0);" id="show_cssedit">CSS Editor</a></li>
|
||||
<li id="jsedit_tab"><a href="javascript:void(0);" id="show_jsedit">JS Editor</a></li>
|
||||
<li id="banlist_tab"><a href="javascript:void(0);" id="show_banlist">Ban List</a></li>
|
||||
<li id="channelranks_tab"><a href="javascript:void(0);" id="show_channelranks">Channel Ranks</a></li>
|
||||
<li id="loginhistory_tab"><a href="javascript:void(0);" id="show_loginhistory">Recent Connections</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div id="optedit" class="span12">
|
||||
<form class="form-horizontal" action="javascript:void(0)">
|
||||
<!-- prevent chat flood -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_chat_antiflood">Prevent Chat Flood</label>
|
||||
<div class="controls">
|
||||
<input type="checkbox" id="opt_chat_antiflood">
|
||||
</div>
|
||||
</div>
|
||||
<!-- convert URLs to links -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_enable_link_regex">Convert URLs in chat to links</label>
|
||||
<div class="controls">
|
||||
<input type="checkbox" id="opt_enable_link_regex">
|
||||
</div>
|
||||
</div>
|
||||
<!-- voteskip toggle -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_allow_voteskip">Allow Voteskip</label>
|
||||
<div class="controls">
|
||||
<input type="checkbox" id="opt_allow_voteskip">
|
||||
</div>
|
||||
</div>
|
||||
<!-- voteskip ratio -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_voteskip_ratio">Voteskip Ratio</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="opt_voteskip_ratio" placeholder="0.5">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<strong>Admin-Only Controls</strong>
|
||||
<!-- page title -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_pagetitle">Page Title</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="opt_pagetitle" placeholder="CyTube">
|
||||
</div>
|
||||
</div>
|
||||
<!-- external CSS -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_externalcss">External CSS</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="opt_externalcss" placeholder="Stylesheet URL">
|
||||
</div>
|
||||
</div>
|
||||
<!-- external JS -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_externaljs">External Javascript</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="opt_externaljs" placeholder="Script URL">
|
||||
</div>
|
||||
</div>
|
||||
<!-- show publicly -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="opt_show_public">List Channel Publicly</label>
|
||||
<div class="controls">
|
||||
<input type="checkbox" id="opt_show_public">
|
||||
</div>
|
||||
</div>
|
||||
<!-- unregister -->
|
||||
<div class="control-group" id="chanopts_unregister_wrap">
|
||||
<label class="control-label" for="chanopts_unregister">Unregister</label>
|
||||
<div class="controls">
|
||||
<button class="btn btn-danger" id="chanopts_unregister">Unregister Channel</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- submit -->
|
||||
<button class="btn btn-primary" id="chanopts_submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<div id="permedit" class="span12">
|
||||
</div>
|
||||
<div id="motdedit" class="span12">
|
||||
<textarea rows="10" id="motdtext"></textarea>
|
||||
<button class="btn btn-primary" id="save_motd">Save</button>
|
||||
</div>
|
||||
<div id="filteredit" class="span12">
|
||||
<p>Filters will be processed in the order that they are listed here. Click and drag a row to rearrange the order. Click a regex, flags, or replacement field to edit a filter. Changes are automatically saved when you finish editing.</p>
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Delete</th>
|
||||
<th>Name</th>
|
||||
<th>Regex</th>
|
||||
<th>Flags</th>
|
||||
<th>Replacement</th>
|
||||
<th>Affects Links</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<strong>Add Filter</strong>
|
||||
<form class="form-horizontal" action="javascript:void(0)">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="newfilter_name">
|
||||
Name
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="newfilter_name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="newfilter_regex">
|
||||
Regex
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="newfilter_regex">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="newfilter_flags">
|
||||
Flags
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="newfilter_flags" value="g">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="newfilter_replace">
|
||||
Replacement
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="newfilter_replace">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="newfilter_filterlinks">
|
||||
Filter Links
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="checkbox" id="newfilter_filterlinks">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button class="btn btn-primary" id="newfilter_submit">New Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="cssedit" class="span12">
|
||||
<p>Max 20KB. If you need more space, host the file externally and use the External CSS option</p>
|
||||
<textarea rows="10" id="csstext"></textarea>
|
||||
<button class="btn btn-primary" id="save_css">Save</button>
|
||||
</div>
|
||||
<div id="jsedit" class="span12">
|
||||
<p>Max 20KB. If you need more space, host the file externally and use the External JS option</p>
|
||||
<textarea rows="10" id="jstext"></textarea>
|
||||
<button class="btn btn-primary" id="save_js">Save</button>
|
||||
</div>
|
||||
<div id="banlist" class="span12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Unban</th>
|
||||
<th>IP</th>
|
||||
<th>Name</th>
|
||||
<th>Aliases</th>
|
||||
<th>Banned By</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div id="loginhistory" class="span12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Aliases</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div id="channelranks" class="span12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Rank (click to edit)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
|
@ -31,7 +31,7 @@
|
|||
<div class="">
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="index.html">Home</a></li>
|
||||
<li><a href="help.html">Help</a></li>
|
||||
<li><a href="https://github.com/calzoneman/sync/wiki/Beginner%27s-Guide-and-FAQ" target="_blank">Help</a></li>
|
||||
<li><a href="account.html">Account</a></li>
|
||||
<li><a href="javascript:void(0)" id="optlink">Options</a></li>
|
||||
</ul>
|
||||
|
|
Loading…
Reference in a new issue