From 703ac3ce4f3dd785ce72b6307ec4bda8dec8a1ae Mon Sep 17 00:00:00 2001 From: calzoneman Date: Sat, 4 May 2013 17:54:28 -0500 Subject: [PATCH] Add temporary videos --- channel.js | 117 ++++++++++++++++++++++------------- media.js | 22 ++++++- package.json | 2 +- rank.js | 1 + server.js | 2 +- user.js | 6 ++ www/assets/css/darkstrap.css | 9 +++ www/assets/js/callbacks.js | 25 +++++++- www/assets/js/client.js | 1 + www/assets/js/functions.js | 22 +++++++ www/assets/js/media.js | 2 +- www/channel.html | 4 ++ 12 files changed, 163 insertions(+), 50 deletions(-) diff --git a/channel.js b/channel.js index 54547ef4..7249eec6 100644 --- a/channel.js +++ b/channel.js @@ -46,6 +46,7 @@ var Channel = function(name) { qopen_allow_move: false, qopen_allow_playnext: false, qopen_allow_delete: false, + qopen_temp: true, allow_voteskip: true, voteskip_ratio: 0.5, pagetitle: this.name, @@ -93,6 +94,9 @@ Channel.prototype.loadDump = function() { var m = new Media(e.id, e.title, e.seconds, e.type); m.queueby = data.queue[i].queueby ? data.queue[i].queueby : ""; + if(e.temp !== undefined) { + m.temp = e.temp; + } this.queue.push(m); } this.sendAll("playlist", { @@ -236,6 +240,9 @@ Channel.prototype.saveRank = function(user) { } Channel.prototype.cacheMedia = function(media) { + if(media.temp) { + return; + } this.library[media.id] = media; if(this.registered) { return Database.cacheMedia(this.name, media); @@ -479,7 +486,7 @@ Channel.prototype.sendPlaylist = function(user) { Channel.prototype.sendMediaUpdate = function(user) { if(this.media != null) { - user.socket.emit("mediaUpdate", this.media.packupdate()); + user.socket.emit("mediaUpdate", this.media.fullupdate()); } } @@ -649,12 +656,12 @@ function mediaUpdate(chan, id) { chan.time = new Date().getTime(); // Show's over, move on to the next thing - if(chan.media.currentTime > chan.media.seconds) { + if(chan.media.currentTime > chan.media.seconds + 1) { chan.playNext(); } // Send updates about every 5 seconds else if(chan.i % 5 == 0) { - chan.sendAll("mediaUpdate", chan.media.packupdate()); + chan.sendAll("mediaUpdate", chan.media.timeupdate()); } chan.i++; @@ -680,13 +687,23 @@ Channel.prototype.queueAdd = function(media, idx) { } } +Channel.prototype.autoTemp = function(media, user) { + if(isLive(media.type)) { + media.temp = true; + } + if(user.rank < Rank.Moderator && this.opts.qopen_temp) { + media.temp = true; + } +} + Channel.prototype.enqueue = function(data, user) { var idx = data.pos == "next" ? this.position + 1 : this.queue.length; // Prefer cache over looking up new data if(data.id in this.library) { - var media = this.library[data.id]; + var media = this.library[data.id].dup(); media.queueby = user ? user.name : ""; + this.autoTemp(media, user); this.queueAdd(media, idx); this.logger.log("*** Queued from cache: id=" + data.id); } @@ -699,6 +716,7 @@ Channel.prototype.enqueue = function(data, user) { case "sc": InfoGetter.getMedia(data.id, data.type, function(media) { media.queueby = user ? user.name : ""; + this.autoTemp(media, user); this.queueAdd(media, idx); this.cacheMedia(media); if(data.type == "yp") @@ -708,21 +726,25 @@ Channel.prototype.enqueue = function(data, user) { case "li": var media = new Media(data.id, "Livestream - " + data.id, "--:--", "li"); media.queueby = user ? user.name : ""; + this.autoTemp(media, user); this.queueAdd(media, idx); break; case "tw": var media = new Media(data.id, "Twitch - " + data.id, "--:--", "tw"); media.queueby = user ? user.name : ""; + this.autoTemp(media, user); this.queueAdd(media, idx); break; case "rt": var media = new Media(data.id, "Livestream", "--:--", "rt"); media.queueby = user ? user.name : ""; + this.autoTemp(media, user); this.queueAdd(media, idx); break; case "jw": var media = new Media(data.id, "JWPlayer Stream - " + data.id, "--:--", "jw"); media.queueby = user ? user.name : ""; + this.autoTemp(media, user); this.queueAdd(media, idx); break; default: @@ -759,6 +781,38 @@ Channel.prototype.tryQueue = function(user, data) { this.enqueue(data, user); } +Channel.prototype.setTemp = function(idx, temp) { + var med = this.queue[idx]; + med.temp = temp; + this.sendAll("setTemp", { + idx: idx, + temp: temp + }); + + if(temp) { + if(Database.uncacheMedia(this.name, med.id)) { + delete this.library[med.id]; + } + } + else { + this.cacheMedia(med); + } +} + +Channel.prototype.trySetTemp = function(user, data) { + if(!Rank.hasPermission(user, "settemp")) { + return; + } + if(typeof data.idx != "number" || typeof data.temp != "boolean") { + return; + } + if(data.idx < 0 || data.idx >= this.queue.length) { + return; + } + + this.setTemp(data.idx, data.temp); +} + Channel.prototype.dequeue = function(data) { if(data.pos < 0 || data.pos >= this.queue.length) { return; @@ -771,7 +825,7 @@ Channel.prototype.dequeue = function(data) { this.broadcastPlaylistMeta(); // If you remove the currently playing video, play the next one - if(data.pos == this.position) { + if(data.pos == this.position && !data.removeonly) { this.position--; this.playNext(); return; @@ -811,41 +865,8 @@ Channel.prototype.tryUncache = function(user, data) { } Channel.prototype.playNext = function() { - // Nothing to play - if(this.queue.length == 0) { - return; - } - - // Reset voteskip - this.voteskip = false; - this.broadcastVoteskipUpdate(); - this.drinks = 0; - this.broadcastDrinks(); - - var old = this.position; - // Wrap around if the end is hit - if(this.position + 1 >= this.queue.length) { - this.position = -1; - } - - this.position++; - var oid = this.media ? this.media.id : ""; - this.media = this.queue[this.position]; - this.media.currentTime = -1; - - this.sendAll("mediaUpdate", this.media.packupdate()); - this.sendAll("updatePlaylistIdx", { - old: old, - idx: this.position - }); - - // If it's not a livestream, enable autolead - if(this.leader == null && !isLive(this.media.type)) { - this.time = new Date().getTime(); - if(this.media.id != oid) { - mediaUpdate(this, this.media.id); - } - } + var pos = this.position + 1 >= this.queue.length ? 0 : this.position + 1; + this.jumpTo(pos); } Channel.prototype.tryPlayNext = function(user) { @@ -871,12 +892,24 @@ Channel.prototype.jumpTo = function(pos) { this.broadcastDrinks(); var old = this.position; + if(this.media && this.media.temp && old != pos) { + this.dequeue({pos: old, removeonly: true}); + if(pos > old) { + pos--; + } + } + if(pos >= this.queue.length || pos < 0) { + return; + } + if(this.media) { + delete this.media["currentTime"]; + } this.position = pos; var oid = this.media ? this.media.id : ""; this.media = this.queue[this.position]; this.media.currentTime = -1; - this.sendAll("mediaUpdate", this.media.packupdate()); + this.sendAll("changeMedia", this.media.fullupdate()); this.sendAll("updatePlaylistIdx", { old: old, idx: this.position @@ -969,7 +1002,7 @@ Channel.prototype.tryUpdate = function(user, data) { } this.media.currentTime = data.currentTime; - this.sendAll("mediaUpdate", this.media.packupdate()); + this.sendAll("mediaUpdate", this.media.timeupdate()); } Channel.prototype.move = function(data) { diff --git a/media.js b/media.js index db71ce3a..aaa1ea1f 100644 --- a/media.js +++ b/media.js @@ -52,6 +52,14 @@ var Media = function(id, title, seconds, type) { } this.type = type; this.queueby = ""; + this.temp = false; +} + +Media.prototype.dup = function() { + var m = new Media(this.id, this.title, this.seconds, this.type); + m.queueby = this.queueby; + m.temp = this.temp; + return m; } // Returns an object containing the data in this Media but not the @@ -63,13 +71,14 @@ Media.prototype.pack = function() { seconds: this.seconds, duration: this.duration, type: this.type, - queueby: this.queueby + queueby: this.queueby, + temp: this.temp }; } // Same as pack() but includes the currentTime variable set by the channel // when the media is being synchronized -Media.prototype.packupdate = function() { +Media.prototype.fullupdate = function() { return { id: this.id, title: this.title, @@ -77,7 +86,14 @@ Media.prototype.packupdate = function() { duration: this.duration, type: this.type, currentTime: this.currentTime, - queueby: this.queueby + queueby: this.queueby, + temp: this.temp + }; +} + +Media.prototype.timeupdate = function() { + return { + currentTime: this.currentTime }; } diff --git a/package.json b/package.json index 2a7a93ca..067399cc 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "1.5.5", + "version": "1.6.0", "repository": { "url": "http://github.com/calzoneman/sync" }, diff --git a/rank.js b/rank.js index 6b8a6cb7..f757953b 100644 --- a/rank.js +++ b/rank.js @@ -36,6 +36,7 @@ var permissions = { seeVoteskip : exports.Moderator, uncache : exports.Moderator, seenlogins : exports.Moderator, + settemp : exports.Moderator, search : exports.Guest, chat : exports.Guest, }; diff --git a/server.js b/server.js index 81f943d8..63d20c59 100644 --- a/server.js +++ b/server.js @@ -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.5.5"; +const VERSION = "1.6.0"; var fs = require("fs"); var Logger = require("./logger.js"); diff --git a/user.js b/user.js index a0534278..f052ee96 100644 --- a/user.js +++ b/user.js @@ -166,6 +166,12 @@ User.prototype.initCallbacks = function() { } }.bind(this)); + this.socket.on("setTemp", function(data) { + if(this.channel != null) { + this.channel.trySetTemp(this, data); + } + }.bind(this)); + this.socket.on("unqueue", function(data) { if(this.channel != null) { this.channel.tryDequeue(this, data); diff --git a/www/assets/css/darkstrap.css b/www/assets/css/darkstrap.css index 5b570971..fdd581d7 100644 --- a/www/assets/css/darkstrap.css +++ b/www/assets/css/darkstrap.css @@ -955,6 +955,15 @@ li.alert-info { color: #ff9900; } +li.alert-error { + border: 1px solid #cc0000; + color: #cc0000; +} + +li.alert-error.alert-info { + color: #ff9900; +} + .btn, .btn:hover { text-shadow: none; color: #aaaaaa; diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index f374a5b8..70d0b4d8 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -71,6 +71,7 @@ function initCallbacks() { $("#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_qopen_temp").prop("checked", opts.qopen_temp); $("#opt_pagetitle").attr("placeholder", opts.pagetitle); document.title = opts.pagetitle; PAGETITLE = opts.pagetitle; @@ -284,6 +285,20 @@ function initCallbacks() { $(li).show("blind"); }); + socket.on("setTemp", function(data) { + var li = $("#queue").children()[data.idx]; + var buttons = $(li).find(".qe_btn"); + if(buttons.length == 5) { + $(buttons[4]).text(data.temp ? "Untemp" : "Temp"); + } + if(data.temp) { + $(li).addClass("alert alert-error"); + } + else { + $(li).removeClass("alert alert-error"); + } + }); + socket.on("unqueue", function(data) { var li = $("#queue").children()[data.pos]; $(li).remove(); @@ -308,7 +323,7 @@ function initCallbacks() { $("#voteskip").attr("disabled", false); }); - socket.on("mediaUpdate", function(data) { + socket.on("changeMedia", function(data) { $("#currenttitle").text("Currently Playing: " + data.title); if(data.type != "sc" && MEDIATYPE == "sc") // [](/goddamnitmango) @@ -317,7 +332,13 @@ function initCallbacks() { MEDIATYPE = data.type; PLAYER = new Media(data); } - else if(PLAYER.update) { + if(PLAYER.update) { + PLAYER.update(data); + } + }); + + socket.on("mediaUpdate", function(data) { + if(PLAYER.update) { PLAYER.update(data); } }); diff --git a/www/assets/js/client.js b/www/assets/js/client.js index d0be639f..4ae49901 100644 --- a/www/assets/js/client.js +++ b/www/assets/js/client.js @@ -381,6 +381,7 @@ $("#opt_submit").click(function() { 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"), + qopen_temp: $("#opt_qopen_temp").prop("checked"), allow_voteskip: $("#opt_allow_voteskip").prop("checked"), voteskip_ratio: ratio, pagetitle: ptitle, diff --git a/www/assets/js/functions.js b/www/assets/js/functions.js index 3c6a929b..5ab7d1cf 100644 --- a/www/assets/js/functions.js +++ b/www/assets/js/functions.js @@ -256,6 +256,9 @@ function makeQueueEntry(video) { var time = $("").addClass("qe_time").appendTo(li); time.text(video.duration); var clear = $("
").addClass("qe_clear").appendTo(li); + if(video.temp) { + li.addClass("alert alert-error"); + } return li; } @@ -326,6 +329,25 @@ function addQueueButtons(li) { }); } + if(RANK >= Rank.Moderator) { + var btnTemp = $("