diff --git a/channel.js b/channel.js index 3cf027a6..3460e139 100644 --- a/channel.js +++ b/channel.js @@ -88,7 +88,7 @@ var Channel = function(name, Server) { }; this.filters = [ new Filter("monospace", "`([^`]+)`", "g", "$1"), - new Filter("bold", "(.)\\*([^\\*]+)\\*", "g", "$1$2"), + new Filter("bold", "(^|\\s)\\*([^\\*]+)\\*", "g", "$1$2"), new Filter("italic", "(^| )_([^_]+)_", "g", "$1$2"), new Filter("strikethrough", "~~([^~]+)~~", "g", "$1"), new Filter("inline spoiler", "\\[spoiler\\](.*)\\[\\/spoiler\\]", "ig", "$1"), @@ -1144,6 +1144,7 @@ Channel.prototype.tryQueue = function(user, data) { } data.queueby = user ? user.name : ""; + data.temp = !this.hasPermission(user, "addnontemp"); if(data.list) this.addMediaList(data, user); @@ -1160,7 +1161,7 @@ Channel.prototype.addMedia = function(data, user) { user.socket.emit("queueFail", "You don't have permission to add cusstom embeds"); return; } - data.temp = isLive(data.type) || !this.hasPermission(user, "addnontemp"); + data.temp = data.temp || isLive(data.type); data.queueby = user ? user.name : ""; data.maxlength = this.hasPermission(user, "exceedmaxlength") ? 0 : this.opts.maxlength; var chan = this; @@ -1516,9 +1517,8 @@ Channel.prototype.tryVoteskip = function(user) { return; } // Voteskip = auto-unafk - if(user.meta.afk) { - user.setAFK(false); - } + user.setAFK(false); + user.autoAFK(); if(!this.voteskip) { this.voteskip = new Poll("voteskip", "voteskip", ["yes"]); } diff --git a/get-info.js b/get-info.js index 24ef4071..c545926d 100644 --- a/get-info.js +++ b/get-info.js @@ -17,18 +17,22 @@ var CustomEmbedFilter = require("./customembed").filter; module.exports = function (Server) { function urlRetrieve(transport, options, callback) { - var req = transport.request(options, function (res) { - var buffer = ""; - res.setEncoding("utf-8"); - res.on("data", function (chunk) { - buffer += chunk; + try { + var req = transport.request(options, function (res) { + var buffer = ""; + res.setEncoding("utf-8"); + res.on("data", function (chunk) { + buffer += chunk; + }); + res.on("end", function () { + callback(res.statusCode, buffer); + }); }); - res.on("end", function () { - callback(res.statusCode, buffer); - }); - }); - req.end(); + req.end(); + } catch(e) { + callback(503, ""); + } } var Getters = { diff --git a/package.json b/package.json index 42902bea..faa921eb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "2.3.1", + "version": "2.3.2", "repository": { "url": "http://github.com/calzoneman/sync" }, diff --git a/playlist.js b/playlist.js index d10a68ba..c91de926 100644 --- a/playlist.js +++ b/playlist.js @@ -458,6 +458,7 @@ Playlist.prototype.lead = function(lead) { this._leadInterval = false; } else if(this.leading && !this._leadInterval) { + this._lastUpdate = Date.now(); this._leadInterval = setInterval(function() { pl._leadLoop(); }, 1000); diff --git a/server.js b/server.js index 0fccc6ce..70c2fb81 100644 --- a/server.js +++ b/server.js @@ -6,7 +6,7 @@ var Logger = require("./logger"); var Channel = require("./channel"); var User = require("./user"); -const VERSION = "2.3.1"; +const VERSION = "2.3.2"; function getIP(req) { var raw = req.connection.remoteAddress; diff --git a/user.js b/user.js index dfec554e..6395c6c8 100644 --- a/user.js +++ b/user.js @@ -205,7 +205,7 @@ User.prototype.initCallbacks = function() { this.socket.on("chatMsg", function(data) { if(this.channel != null) { - if(data.msg.indexOf("/afk") == -1) { + if(data.msg.indexOf("/afk") != 0) { this.setAFK(false); this.autoAFK(); } diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 7abc0769..04f9928c 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -627,15 +627,8 @@ Callbacks = { var nametag = $("").text(data.name).appendTo(div); formatUserlistItem(div, data); addUserDropdown(div, data); - var users = $("#userlist").children(); - for(var i = 0; i < users.length; i++) { - var othername = users[i].children[1].innerHTML; - if(othername.toLowerCase() > data.name.toLowerCase()) { - div.insertBefore(users[i]); - return; - } - } div.appendTo($("#userlist")); + sortUserlist(); }, updateUser: function(data) { @@ -647,16 +640,7 @@ Callbacks = { // I'm a leader! Set up sync function if(LEADTMR) clearInterval(LEADTMR); - LEADTMR = setInterval(function() { - PLAYER.getTime(function(seconds) { - socket.emit("mediaUpdate", { - id: PLAYER.id, - currentTime: seconds, - paused: PLAYER.paused, - type: PLAYER.type - }); - }); - }, 5000); + LEADTMR = setInterval(sendVideoUpdate, 5000); } // I'm not a leader. Don't send syncs to the server else { @@ -670,6 +654,8 @@ Callbacks = { if(user !== null) { formatUserlistItem(user, data); addUserDropdown(user, data); + if(USEROPTS.sort_rank) + sortUserlist(); } }, @@ -684,6 +670,8 @@ Callbacks = { .appendTo(user[0].children[0]); $(user[0].children[1]).css("font-style", "italic"); } + if(USEROPTS.sort_afk) + sortUserlist(); }, userLeave: function(data) { diff --git a/www/assets/js/data.js b/www/assets/js/data.js index dd324cc9..f7948d08 100644 --- a/www/assets/js/data.js +++ b/www/assets/js/data.js @@ -115,7 +115,9 @@ var USEROPTS = { qbtn_idontlikechange : getOrDefault("qbtn_idontlikechange", false), first_visit : getOrDefault("first_visit", true), ignore_channelcss : getOrDefault("ignore_channelcss", false), - ignore_channeljs : getOrDefault("ignore_channeljs", false) + ignore_channeljs : getOrDefault("ignore_channeljs", false), + sort_rank : getOrDefault("sort_rank", false), + sort_afk : getOrDefault("sort_afk", false) }; var NO_WEBSOCKETS = USEROPTS.altsocket; diff --git a/www/assets/js/paginator.js b/www/assets/js/paginator.js index efaa6ad6..e2fcac53 100644 --- a/www/assets/js/paginator.js +++ b/www/assets/js/paginator.js @@ -48,7 +48,7 @@ .appendTo(sep); } } - for(var i = s; i < s + this.opts.maxPages; i++) { + for(var i = s; i < s + this.opts.maxPages && i < s + pages; i++) { (function (i) { var li = $("
  • ").appendTo(ul); if(i == p) diff --git a/www/assets/js/player.js b/www/assets/js/player.js index 40661b5c..ca451fc7 100644 --- a/www/assets/js/player.js +++ b/www/assets/js/player.js @@ -37,7 +37,6 @@ var YouTubePlayer = function (data) { autoplay: 1, // Autoplay video controls: 1, // Show controls iv_load_policy: 3, // No annotations - modestbranding: 1, // No logo rel: 0, // No related videos wmode: wmode }, diff --git a/www/assets/js/ui.js b/www/assets/js/ui.js index e3dbb61c..399a8c6f 100644 --- a/www/assets/js/ui.js +++ b/www/assets/js/ui.js @@ -68,6 +68,38 @@ $("#logout").click(function() { }); /* chatbox */ + +$("#usercountwrap").mouseenter(function (ev) { + var breakdown = calcUserBreakdown(); + // re-using profile-box class for convenience + var popup = $("
    ") + .addClass("profile-box") + .css("top", (ev.pageY + 5) + "px") + .css("left", (ev.pageX) + "px") + .appendTo($("#usercountwrap")); + + var contents = ""; + for(var key in breakdown) { + contents += "" + key + ": " + breakdown[key]; + contents += "
    " + } + + popup.html(contents); +}); + +$("#usercountwrap").mousemove(function (ev) { + var popup = $("#usercountwrap").find(".profile-box"); + if(popup.length == 0) + return; + + popup.css("top", (ev.pageY + 5) + "px"); + popup.css("left", (ev.pageX) + "px"); +}); + +$("#usercountwrap").mouseleave(function () { + $("#usercountwrap").find(".profile-box").remove(); +}); + $("#messagebuffer").mouseenter(function() { SCROLLCHAT = false; }); $("#messagebuffer").mouseleave(function() { SCROLLCHAT = true; }); diff --git a/www/assets/js/util.js b/www/assets/js/util.js index e13ebfd2..f1d0fa36 100644 --- a/www/assets/js/util.js +++ b/www/assets/js/util.js @@ -253,6 +253,71 @@ function addUserDropdown(entry, data) { }); } +function calcUserBreakdown() { + var breakdown = { + "Site Admins": 0, + "Channel Admins": 0, + "Moderators": 0, + "Regular Users": 0, + "Guests": 0, + "AFK": 0 + }; + $("#userlist .userlist_item").each(function (index, item) { + var data = $(item).data("dropdown-info"); + if(data.rank >= 255) + breakdown["Site Admins"]++; + else if(data.rank >= 3) + breakdown["Channel Admins"]++; + else if(data.rank == 2) + breakdown["Moderators"]++; + else if(data.rank >= 1) + breakdown["Regular Users"]++; + else + breakdown["Guests"]++; + + if($(item).find(".icon-time").length > 0) + breakdown["AFK"]++; + }); + + return breakdown; +} + +function sortUserlist() { + var slice = Array.prototype.slice; + var list = slice.call($("#userlist .userlist_item")); + list.sort(function (a, b) { + var r1 = $(a).data("dropdown-info").rank; + var r2 = $(b).data("dropdown-info").rank; + var afk1 = $(a).find(".icon-time").length > 0; + var afk2 = $(b).find(".icon-time").length > 0; + var name1 = a.children[1].innerHTML.toLowerCase(); + var name2 = b.children[1].innerHTML.toLowerCase(); + + if(USEROPTS.sort_afk) { + if(afk1 && !afk2) + return 1; + if(!afk1 && afk2) + return -1; + } + + if(USEROPTS.sort_rank) { + if(r1 < r2) + return 1; + if(r1 > r2) + return -1; + } + + return name1 === name2 ? 0 : (name1 < name2 ? -1 : 1); + }); + + list.forEach(function (item) { + $(item).detach(); + }); + list.forEach(function (item) { + $(item).appendTo($("#userlist")); + }); +} + /* queue stuff */ function scrollQueue() { @@ -522,6 +587,18 @@ function showOptionsMenu() { showts.prop("checked", USEROPTS.show_timestamps); addOption("Show timestamps", tscontainer); + var srcontainer = $("