diff --git a/channel.js b/channel.js index a3fad52d..eef5a9e5 100644 --- a/channel.js +++ b/channel.js @@ -28,6 +28,14 @@ var Channel = function(name) { this.recentChat = []; this.qlocked = true; this.poll = false; + this.opts = { + qopen_allow_qnext: false, + qopen_allow_move: false, + qopen_allow_playnext: false, + qopen_allow_delete: false, + pagetitle: "Sync", + bgimage: "" + }; // Autolead stuff // Accumulator @@ -289,6 +297,7 @@ Channel.prototype.userJoin = function(user) { if(this.poll) { user.socket.emit('newPoll', this.poll.packUpdate()); } + user.socket.emit('channelOpts', this.opts); if(user.playerReady) this.sendMediaUpdate(user); console.log("/" + user.ip + " joined channel " + this.name); @@ -682,6 +691,10 @@ Channel.prototype.broadcastPollClose = function() { this.sendAll('closePoll'); } +Channel.prototype.broadcastOpts = function() { + this.sendAll('channelOpts', this.opts); +} + // Send to ALL the clients! Channel.prototype.sendAll = function(message, data) { io.sockets.in(this.name).emit(message, data); diff --git a/chatcommand.js b/chatcommand.js index 4af0d752..82228508 100644 --- a/chatcommand.js +++ b/chatcommand.js @@ -40,7 +40,7 @@ function handlePoll(chan, user, msg) { var args = msg.split(','); var title = args[0]; args.splice(0, 1); - var poll = new Poll(title, args); + var poll = new Poll(user.name, title, args); chan.poll = poll; chan.broadcastPoll(); } diff --git a/poll.js b/poll.js index ded3e7ce..a43c8ad5 100644 --- a/poll.js +++ b/poll.js @@ -1,5 +1,6 @@ -var Poll = function(title, options) { +var Poll = function(initiator, title, options) { + this.initiator = initiator; this.title = title; this.options = options; this.counts = new Array(options.length); @@ -30,7 +31,8 @@ Poll.prototype.packUpdate = function() { return { title: this.title, options: this.options, - counts: this.counts + counts: this.counts, + initiator: this.initiator } } diff --git a/rank.js b/rank.js index 520444ed..f69ab967 100644 --- a/rank.js +++ b/rank.js @@ -23,6 +23,7 @@ var permissions = { qlock : exports.Moderator, poll : exports.Moderator, shout : exports.Moderator, + channelOpts : exports.Moderator, search : exports.Guest, chat : exports.Guest, }; diff --git a/user.js b/user.js index 77874a7e..31b8a15a 100644 --- a/user.js +++ b/user.js @@ -99,34 +99,50 @@ User.prototype.initCallbacks = function() { }.bind(this)); this.socket.on('queue', function(data) { + if(this.channel == null) + return; if(Rank.hasPermission(this, "queue") || - (this.channel != null && !this.channel.qlocked)) { - if(this.channel != null) + this.channel.leader == this || + !this.channel.qlocked) { + if(data.pos == "next" && + !this.channel.qopts_allow_qnext && + this.channel.leader != this && + !Rank.hasPermission(this, "queue")) + return; this.channel.enqueue(data); } }.bind(this)); this.socket.on('unqueue', function(data) { - if(Rank.hasPermission(this, "queue")) { - if(this.channel != null) + if(this.channel == null) + return; + if(Rank.hasPermission(this, "queue") || + this.channel.leader == this || + this.channel.opts.qopen_allow_delete && !this.channel.qlocked) { this.channel.unqueue(data); } }.bind(this)); this.socket.on('moveMedia', function(data) { - if(Rank.hasPermission(this, "queue")) { - if(this.channel != null) + if(this.channel == null) + return; + if(Rank.hasPermission(this, "queue") || + this.channel.leader == this || + this.channel.opts.qopen_allow_move && !this.channel.qlocked ) { this.channel.moveMedia(data); } }.bind(this)); this.socket.on('playNext', function() { + if(this.channel == null) + return; if(Rank.hasPermission(this, "queue") || - (this.channel != null && this.channel.leader == this)) { - if(this.channel.currentPosition + 1 >= this.channel.queue.length) { - this.channel.currentPosition = -1; - } - this.channel.playNext(); + this.channel.leader == this || + this.channel.opts.qopen_allow_playnext && !this.channel.qlocked) { + if(this.channel.currentPosition + 1 >= this.channel.queue.length) { + this.channel.currentPosition = -1; + } + this.channel.playNext(); } }.bind(this)); @@ -197,6 +213,13 @@ User.prototype.initCallbacks = function() { } } }.bind(this)); + + this.socket.on('channelOpts', function(data) { + if(Rank.hasPermission(this, "channelOpts") && this.channel != null) { + this.channel.opts = data; + this.channel.broadcastOpts(); + } + }.bind(this)); } // Handle administration diff --git a/www/assets/css/ytsync.css b/www/assets/css/ytsync.css index 2555f3dd..153f2d8e 100644 --- a/www/assets/css/ytsync.css +++ b/www/assets/css/ytsync.css @@ -106,6 +106,12 @@ font-size: 18pt; } +.poll-notify { + color: #0000aa; + font-weight: bold; + font-size: 14pt; +} + .option button { margin-right: 15px; } diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index a7fd029e..6f96cdcc 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -35,6 +35,9 @@ function initCallbacks() { socket.on('rank', function(data) { if(data.rank >= Rank.Moderator) { $('#playlist_controls').css("display", "block"); + $('#playlist_controls button').each(function() { + $(this).attr('disabled', false); + }); $('#qlockbtn').css("display", "block"); var poll = $('#pollcontainer .active'); if(poll.length > 0) { @@ -48,6 +51,8 @@ function initCallbacks() { for(var i = 0; i < users.length; i++) { addUserDropdown(users[i], users[i].children[1].innerHTML); } + + $('#chancontrols').show(); } RANK = data.rank; }); @@ -73,6 +78,24 @@ function initCallbacks() { } }); + socket.on('channelOpts', function(opts) { + $('#opt_qopen_allow_qnext').prop('checked', opts.qopen_allow_qnext); + $('#opt_qopen_allow_move').prop('checked', opts.qopen_allow_move); + $('#opt_qopen_allow_delete').prop('checked', opts.qopen_allow_delete); + $('#opt_qopen_allow_playnext').prop('checked', opts.qopen_allow_playnext); + $('#opt_pagetitle').attr('placeholder', opts.pagetitle); + document.title = opts.pagetitle; + $('#opt_bgimage').attr('placeholder', opts.bgimage); + if(opts.bgimage != "") + $('body').css("background", "url('" + opts.bgimage + "') no-repeat fixed"); + CHANNELOPTS = opts; + if(opts.qopen_allow_qnext) + $('#queue_next').attr('disabled', false); + if(opts.qopen_allow_playnext) + $('#play_next').attr('disabled', false); + rebuildPlaylist(); + }); + socket.on('usercount', function(data) { $('#usercount').text(data.count + " connected users"); }); @@ -134,22 +157,25 @@ function initCallbacks() { $('#playlist_controls').css('display', ''); if(RANK < Rank.Moderator) { $('#qlockbtn').css('display', 'none'); + rebuildPlaylist(); + if(!CHANNELOPTS.qopen_allow_qnext) + $('#queue_next').attr('disabled', true); + if(!CHANNELOPTS.qopen_allow_playnext) + $('#play_next').attr('disabled', true); } } else if(RANK < Rank.Moderator) { $('#playlist_controls').css('display', 'none'); } - if(RANK >= Rank.Moderator) { - if(OPENQUEUE) { - $('#qlockbtn').removeClass('btn-danger') - .addClass('btn-success') - .text('Lock Queue'); - } - else { - $('#qlockbtn').removeClass('btn-success') - .addClass('btn-danger') - .text('Unlock Queue'); - } + if(OPENQUEUE) { + $('#qlockbtn').removeClass('btn-danger') + .addClass('btn-success') + .text('Lock Queue'); + } + else { + $('#qlockbtn').removeClass('btn-success') + .addClass('btn-danger') + .text('Unlock Queue'); } }); diff --git a/www/assets/js/client.js b/www/assets/js/client.js index 848d8613..33848229 100644 --- a/www/assets/js/client.js +++ b/www/assets/js/client.js @@ -13,6 +13,7 @@ var MEDIATYPE = "yt"; var POSITION = -1; var RANK = 0; var OPENQUEUE = false; +var CHANNELOPTS = {}; var uname = readCookie('sync_uname'); var pw = readCookie('sync_pw'); @@ -207,6 +208,24 @@ $('#chatline').keydown(function(ev) { } }); +$('#opt_submit').click(function() { + var ptitle = $('#opt_pagetitle').val(); + if(ptitle == '') + ptitle = $('#opt_pagetitle').attr('placeholder') + var bgimage = $('#opt_bgimage').val(); + if(bgimage == '') + bgimage = $('#opt_bgimage').attr('placeholder') + opts = { + qopen_allow_qnext: $('#opt_qopen_allow_qnext').prop('checked'), + qopen_allow_move: $('#opt_qopen_allow_move').prop('checked'), + qopen_allow_delete: $('#opt_qopen_allow_delete').prop('checked'), + qopen_allow_playnext: $('#opt_qopen_allow_playnext').prop('checked'), + pagetitle: ptitle, + bgimage: $('#opt_bgimage').val() + }; + socket.emit('channelOpts', opts); +}); + function searchLibrary() { socket.emit('searchLibrary', { diff --git a/www/assets/js/functions.js b/www/assets/js/functions.js index c24e6085..aa997488 100644 --- a/www/assets/js/functions.js +++ b/www/assets/js/functions.js @@ -198,6 +198,25 @@ function addQueueButtons(li) { dest: dest }); }); + + if(RANK < Rank.Moderator && !LEADER) { + if(!CHANNELOPTS.qopen_allow_delete) + $(btnRemove).attr('disabled', true); + if(!CHANNELOPTS.qopen_allow_move) { + $(btnUp).attr('disabled', true); + $(btnDown).attr('disabled', true); + } + if(!CHANNELOPTS.qopen_allow_qnext) + $(btnNext).attr('disabled', true); + } +} + +function rebuildPlaylist() { + $('#queue li').each(function() { + $(this).find('.btn-group').remove(); + if(RANK >= Rank.Moderator || LEADER || OPENQUEUE) + addQueueButtons(this); + }); } // Add buttons to a list entry for the library search results @@ -466,6 +485,9 @@ function closePoll() { function addPoll(data) { closePoll(); + var pollMsg = $('
').addClass('poll-notify') + .text(data.initiator + ' opened a poll: "' + data.title + '"') + .appendTo($('#messagebuffer')); var poll = $('').addClass('well active').prependTo($('#pollcontainer')); $('').addClass('close pull-right').text('×') .appendTo(poll) diff --git a/www/index.html b/www/index.html index f571297b..275b80a6 100644 --- a/www/index.html +++ b/www/index.html @@ -93,6 +93,47 @@ +