mirror of https://github.com/calzoneman/sync.git
Start rewriting channel.js
This commit is contained in:
parent
e27667b6d2
commit
ba0664641e
|
@ -0,0 +1,210 @@
|
||||||
|
var DEFAULT_FILTERS = [
|
||||||
|
new Filter("monospace", "`(.+?)`", "g", "<code>$1</code>"),
|
||||||
|
new Filter("bold", "\\*(.+?)\\*", "g", "<strong>$1</strong>"),
|
||||||
|
new Filter("italic", "_(.+?)_", "g", "<em>$1</em>"),
|
||||||
|
new Filter("strike", "~~(.+?)~~", "g", "<s>$1</s>"),
|
||||||
|
new Filter("inline spoiler", "\\[sp\\](.*?)\\[\\/sp\\]", "ig", "<span class=\"spoiler\">$1</span>")
|
||||||
|
];
|
||||||
|
|
||||||
|
function Channel(name) {
|
||||||
|
var self = this; // Alias `this` to prevent scoping issues
|
||||||
|
Logger.syslog.log("Loading channel " + name);
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
self.ready = false;
|
||||||
|
self.name = name;
|
||||||
|
self.uniqueName = name.toLowerCase(); // To prevent casing issues
|
||||||
|
self.registered = false; // set to true if the channel exists in the database
|
||||||
|
self.users = [];
|
||||||
|
self.mutedUsers = new $util.Set();
|
||||||
|
self.playlist = new Playlist(self);
|
||||||
|
self.plqueue = new AsyncQueue(); // For synchronizing playlist actions
|
||||||
|
self.drinks = 0;
|
||||||
|
self.leader = null;
|
||||||
|
self.chatbuffer = [];
|
||||||
|
self.playlistLock = true;
|
||||||
|
self.poll = null;
|
||||||
|
self.voteskip = null;
|
||||||
|
self.permissions = {
|
||||||
|
playlistadd: 1.5, // Add video to the playlist
|
||||||
|
playlistnext: 1.5, // TODO I don't think this is used
|
||||||
|
playlistmove: 1.5, // Move a video on the playlist
|
||||||
|
playlistdelete: 2, // Delete a video from the playlist
|
||||||
|
playlistjump: 1.5, // Start a different video on the playlist
|
||||||
|
playlistaddlist: 1.5, // Add a list of videos to the playlist
|
||||||
|
oplaylistadd: -1, // Same as above, but for open (unlocked) playlist
|
||||||
|
oplaylistnext: 1.5,
|
||||||
|
oplaylistmove: 1.5,
|
||||||
|
oplaylistdelete: 2,
|
||||||
|
oplaylistjump: 1.5,
|
||||||
|
oplaylistaddlist: 1.5,
|
||||||
|
playlistaddcustom: 3, // Add custom embed to the playlist
|
||||||
|
playlistaddlive: 1.5, // Add a livestream to the playlist
|
||||||
|
exceedmaxlength: 2, // Add a video longer than the maximum length set
|
||||||
|
addnontemp: 2, // Add a permanent video to the playlist
|
||||||
|
settemp: 2, // Toggle temporary status of a playlist item
|
||||||
|
playlistgeturl: 1.5, // TODO is this even used?
|
||||||
|
playlistshuffle: 2, // Shuffle the playlist
|
||||||
|
playlistclear: 2, // Clear the playlist
|
||||||
|
pollctl: 1.5, // Open/close polls
|
||||||
|
pollvote: -1, // Vote in polls
|
||||||
|
viewhiddenpoll: 1.5, // View results of hidden polls
|
||||||
|
voteskip: -1, // Vote to skip the current video
|
||||||
|
mute: 1.5, // Mute other users
|
||||||
|
kick: 1.5, // Kick other users
|
||||||
|
ban: 2, // Ban other users
|
||||||
|
motdedit: 3, // Edit the MOTD
|
||||||
|
filteredit: 3, // Control chat filters
|
||||||
|
drink: 1.5, // Use the /d command
|
||||||
|
chat: 0 // Send chat messages
|
||||||
|
};
|
||||||
|
self.opts = {
|
||||||
|
allow_voteskip: true, // Allow users to voteskip
|
||||||
|
voteskip_ratio: 0.5, // Ratio of skip votes:non-afk users needed to skip the video
|
||||||
|
afk_timeout: 600, // Number of seconds before a user is automatically marked afk
|
||||||
|
pagetitle: self.name, // Title of the browser tab
|
||||||
|
maxlength: 0, // Maximum length (in seconds) of a video queued
|
||||||
|
externalcss: "", // Link to external stylesheet
|
||||||
|
externaljs: "", // Link to external script
|
||||||
|
chat_antiflood: false, // Throttle chat messages
|
||||||
|
chat_antiflood_params: {
|
||||||
|
burst: 4, // Number of messages to allow with no throttling
|
||||||
|
sustained: 1, // Throttle rate (messages/second)
|
||||||
|
cooldown: 4 // Number of seconds with no messages before burst is reset
|
||||||
|
},
|
||||||
|
show_public: false, // List the channel on the index page
|
||||||
|
enable_link_regex: true, // Use the built-in link filter
|
||||||
|
password: false // Channel password (false -> no password required for entry)
|
||||||
|
};
|
||||||
|
self.motd = {
|
||||||
|
motd: "", // Raw MOTD text
|
||||||
|
html: "" // Filtered MOTD text (XSS removed; \n replaced by <br>)
|
||||||
|
};
|
||||||
|
self.filters = DEFAULT_FILTERS;
|
||||||
|
self.banlist = new Banlist();
|
||||||
|
self.logger = new Logger.Logger(path.join(__dirname, "../chanlogs",
|
||||||
|
self.uniqueName + ".log"));
|
||||||
|
self.css = ""; // Up to 20KB of inline CSS
|
||||||
|
self.js = ""; // Up to 20KB of inline Javascript
|
||||||
|
|
||||||
|
self.error = false; // Set to true if something bad happens => don't save state
|
||||||
|
|
||||||
|
self.on("ready", function () {
|
||||||
|
self.ready = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load from database
|
||||||
|
db.channels.load(self, function (err) {
|
||||||
|
if (err && err !== "Channel is not registered") {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Load state from JSON blob
|
||||||
|
self.tryLoadState();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Channel.prototype = EventEmitter;
|
||||||
|
|
||||||
|
Channel.prototype.tryLoadState = function () {
|
||||||
|
var self = this;
|
||||||
|
if (self.name === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't load state if the channel isn't registered
|
||||||
|
if (!self.registered) {
|
||||||
|
self.emit("ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var file = path.join(__dirname, "../chandump", self.uniqueName);
|
||||||
|
fs.stat(file, function (err, stats) {
|
||||||
|
if (!err) {
|
||||||
|
var mb = stats.size / 1048576;
|
||||||
|
mb = Math.floor(mb * 100) / 100;
|
||||||
|
if (mb > 1) {
|
||||||
|
Logger.errlog.log("Large chandump detected: " + self.uniqueName +
|
||||||
|
" (" + mb + " MiB)");
|
||||||
|
self.setMOTD("Your channel file has exceeded the maximum size of 1MB " +
|
||||||
|
"and cannot be loaded. Please ask an administrator for " +
|
||||||
|
"assistance in restoring it.");
|
||||||
|
self.error = true;
|
||||||
|
self.emit("ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.loadState();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the channel state from disk.
|
||||||
|
*
|
||||||
|
* SHOULD ONLY BE CALLED FROM tryLoadState
|
||||||
|
*/
|
||||||
|
Channel.prototype.loadState = function () {
|
||||||
|
var self = this;
|
||||||
|
if (self.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.readFile(path.join(__dirname, "../chandump", self.name),
|
||||||
|
function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
// File didn't exist => start fresh
|
||||||
|
if (err.code === "ENOENT") {
|
||||||
|
self.emit("ready");
|
||||||
|
self.saveState();
|
||||||
|
} else {
|
||||||
|
Logger.errlog.log("Failed to open channel dump " + self.uniqueName);
|
||||||
|
Logger.errlog.log(err);
|
||||||
|
self.setMOTD("Internal error when loading channel");
|
||||||
|
self.error = true;
|
||||||
|
self.emit("ready");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
self.logger.log("*** Loading channel state");
|
||||||
|
data = JSON.parse(data);
|
||||||
|
|
||||||
|
// Load the playlist
|
||||||
|
if ("playlist" in data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Playlist lock
|
||||||
|
self.setLock(data.playlistLock || false);
|
||||||
|
|
||||||
|
// Configurables
|
||||||
|
if ("opts" in data) {
|
||||||
|
for (var key in data.opts) {
|
||||||
|
self.opts[key] = data.opts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permissions
|
||||||
|
if ("permissions" in data) {
|
||||||
|
for (var key in data.permissions) {
|
||||||
|
self.permissions[key] = data.permissions[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chat filters
|
||||||
|
if ("filters" in data) {
|
||||||
|
for (var i = 0; i < data.filters.length; i++) {
|
||||||
|
var f = data.filters[i];
|
||||||
|
var filt = new Filter(f.name, f.source, f.flags, f.replace);
|
||||||
|
filt.active = f.active;
|
||||||
|
filt.filterlinks = f.filterlinks;
|
||||||
|
self.updateFilter(filt, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -1315,20 +1315,25 @@ Channel.prototype.calcVoteskipMax = function () {
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
Channel.prototype.broadcastVoteskipUpdate = function() {
|
Channel.prototype.getVoteskipPacket = function() {
|
||||||
var amt = this.voteskip ? this.voteskip.counts[0] : 0;
|
var amt = this.voteskip ? this.voteskip.counts[0] : 0;
|
||||||
var count = this.calcVoteskipMax();
|
var count = this.calcVoteskipMax();
|
||||||
var need = this.voteskip ? Math.ceil(count * this.opts.voteskip_ratio) : 0;
|
var need = this.voteskip ? Math.ceil(count * this.opts.voteskip_ratio) : 0;
|
||||||
for(var i = 0; i < this.users.length; i++) {
|
return {
|
||||||
if(this.users[i].rank >= 1.5) {
|
|
||||||
this.users[i].socket.emit("voteskip", {
|
|
||||||
count: amt,
|
count: amt,
|
||||||
need: need
|
need: need
|
||||||
});
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Channel.prototype.broadcastVoteskipUpdate = function () {
|
||||||
|
var pkt = this.getVoteskipPacket();
|
||||||
|
this.users.forEach(function (u) {
|
||||||
|
if (u.rank >= 1.5) {
|
||||||
|
u.socket.emit("voteskip", pkt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Channel.prototype.broadcastMotd = function() {
|
Channel.prototype.broadcastMotd = function() {
|
||||||
this.sendAll("setMotd", this.motd);
|
this.sendAll("setMotd", this.motd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,8 @@ var User = function (socket) {
|
||||||
this.name = "";
|
this.name = "";
|
||||||
this.meta = {
|
this.meta = {
|
||||||
afk: false,
|
afk: false,
|
||||||
icon: false
|
icon: false,
|
||||||
|
aliases: []
|
||||||
};
|
};
|
||||||
this.queueLimiter = $util.newRateLimiter();
|
this.queueLimiter = $util.newRateLimiter();
|
||||||
this.chatLimiter = $util.newRateLimiter();
|
this.chatLimiter = $util.newRateLimiter();
|
||||||
|
|
|
@ -67,7 +67,8 @@ function handleLoginPage(req, res) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendJade(res, 'login', {
|
sendJade(res, 'login', {
|
||||||
loggedIn: false
|
loggedIn: false,
|
||||||
|
redirect: req.header('Referrer')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,15 @@ html(lang="en")
|
||||||
ul.nav.navbar-nav
|
ul.nav.navbar-nav
|
||||||
mixin navdefaultlinks("/login")
|
mixin navdefaultlinks("/login")
|
||||||
if loggedIn
|
if loggedIn
|
||||||
|
if redirect
|
||||||
|
mixin navlogoutform(redirect)
|
||||||
|
else
|
||||||
mixin navlogoutform("/login")
|
mixin navlogoutform("/login")
|
||||||
section#mainpage.container
|
section#mainpage.container
|
||||||
if wasAlreadyLoggedIn
|
if wasAlreadyLoggedIn
|
||||||
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||||
.alert.alert-info.messagebox.center
|
.alert.alert-info.messagebox.center
|
||||||
h3(style="margin: 5px auto") Logged in as #{loginName}
|
h3(style="margin: 5px auto") Logged in as #{loginName}
|
||||||
// TODO Link to My Account page
|
|
||||||
else if !loggedIn
|
else if !loggedIn
|
||||||
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||||
if loginError
|
if loginError
|
||||||
|
@ -27,6 +29,8 @@ html(lang="en")
|
||||||
p= loginError
|
p= loginError
|
||||||
h2 Login
|
h2 Login
|
||||||
form(role="form", action="/login", method="post")
|
form(role="form", action="/login", method="post")
|
||||||
|
if redirect
|
||||||
|
input(type="hidden", name="redirect", value=redirect)
|
||||||
.form-group
|
.form-group
|
||||||
label(for="username") Username
|
label(for="username") Username
|
||||||
input#username.form-control(type="text", name="name")
|
input#username.form-control(type="text", name="name")
|
||||||
|
|
|
@ -55,7 +55,7 @@ mixin navloginform(redirect)
|
||||||
|
|
||||||
mixin navlogoutform(redirect)
|
mixin navlogoutform(redirect)
|
||||||
if redirect
|
if redirect
|
||||||
- url = "/logout?redirect=#{redirect}"
|
- url = "/logout?redirect=" + redirect
|
||||||
else
|
else
|
||||||
- url = "/logout"
|
- url = "/logout"
|
||||||
p#logoutform.navbar-text.pull-right
|
p#logoutform.navbar-text.pull-right
|
||||||
|
|
Loading…
Reference in New Issue