diff --git a/docker/node/server.js b/docker/node/server.js index 74414f5c..92d6cb9d 100644 --- a/docker/node/server.js +++ b/docker/node/server.js @@ -197,6 +197,75 @@ LinkedList.Circular.prototype.toArray = function () { return out; }; + +LinkedList.Circular.prototype.some = function(cb) { + return this.find(cb) !== null; +} + +LinkedList.Circular.prototype.find = function(cb) { + let video = this.first; + + for (let i = 0; i < this.length; i++) { + if (cb(video, i)) { + return video; + } + + video = video.next; + } + + return null; +} +LinkedList.Circular.prototype.multiple = function(indexes) { + let map = new Map( + indexes.map(i => [i, null]) + ); + + let video = this.first; + let max = Math.max(...indexes); + + for (let i = 0; i <= max; i++) { + if (map.has(i)) { + map.set(i, video); + } + + video = video.next; + } + + return indexes.map(i => map.get(i)); +} +LinkedList.Circular.prototype.at = function(index) { + let video = this.first; + + for (let i = 0; i < index; i++) { + video = video.next; + } + + return video; +} + +LinkedList.Circular.prototype.each = function(cb) { + let video = this.first; + + for (let i = 0; i < this.length; i++) { + cb(video, i); + video = video.next; + } +} + +LinkedList.Circular.prototype.indexOf = function(cb) { + let video = this.first; + + for (let i = 0; i < this.length; i++) { + if (cb(video, i)) { + return i; + } + + video = video.next; + } + + return -1; +} + /* VAR INIT */ SERVER.PLAYLIST = new LinkedList.Circular(); SERVER.ACTIVE = null; @@ -279,20 +348,19 @@ function initPlaylist(callback) { } function initResumePosition(callback) { getMisc({ name: 'server_active_videoid' }, function (old_videoid) { - var elem = SERVER.PLAYLIST.first; - for (var i = 0; i < SERVER.PLAYLIST.length; i++) { - if (elem.videoid == old_videoid) { - SERVER.ACTIVE = elem; - getMisc({ name: 'server_time' }, function (old_time) { - if (+old_time) { - SERVER.TIME = +old_time + 1; - } - if (callback) { callback(); } - }); - return; - } - elem = elem.next; + const active = SERVER.PLAYLIST.find(video => video.videoid === old_videoid); + + if (active) { + SERVER.ACTIVE = active; + + getMisc({ name: 'server_time' }, function (old_time) { + if (+old_time) { + SERVER.TIME = +old_time + 1; + } + if (callback) { callback(); } + }); } + if (callback) { callback(); } }); } @@ -481,14 +549,14 @@ function doorStuck(socket) { } function playNext() { const active = { - position: getVideoPosition(SERVER.ACTIVE), + position: SERVER.PLAYLIST.indexOf(video => video.videoid === SERVER.ACTIVE.videoid), node: SERVER.ACTIVE }; SERVER.ACTIVE = SERVER.ACTIVE.next; if (!active.node.volat && 'colorTagVolat' in active.node.meta) { - _setVideoColorTag(active.node, active.position, false, false); + setVideoColorTag(active.node, active.position, false, false); } if (active.node.volat) { @@ -658,17 +726,15 @@ function kickUserByNick(socket, nick, reason) { sessionService.forNick(nick, session => session.kick(reason, getSocketName(socket))); } var commit = function () { - var elem = SERVER.PLAYLIST.first; - for (var i = 0; i < SERVER.PLAYLIST.length; i++) { + SERVER.PLAYLIST.each((video, i) => { var sql = `update ${SERVER.dbcon.video_table} set position = ? where videoid = ?`; - mysql.query(sql, [i, '' + elem.videoid], function (err) { + mysql.query(sql, [i, '' + video.videoid], function (err) { if (err) { DefaultLog.error(events.EVENT_DB_QUERY, "query \"{sql}\" failed", { sql }, err); return; } }); - elem = elem.next; - } + }); for (var i = 0; i < SERVER.AREAS.length; i++) { var sql = 'update areas set html = ? where name = ?'; @@ -867,30 +933,20 @@ function applyPluginFilters(msg, socket) { return msg; } -function setVideoVolatile(socket, pos, isVolat) { - var elem = SERVER.PLAYLIST.first; - for (var i = 0; i < pos; i++) { - elem = elem.next; - } - elem.volat = isVolat; - +function setVideoVolatile(socket, video, pos, isVolat) { + video.volat = isVolat; + DefaultLog.info(events.EVENT_ADMIN_SET_VOLATILE, "{mod} set {title} to {status}", - { mod: getSocketName(socket), type: "playlist", title: decodeURIComponent(elem.videotitle), status: isVolat ? "volatile" : "not volatile" }); + { mod: getSocketName(socket), type: "playlist", title: decodeURIComponent(video.videotitle), status: isVolat ? "volatile" : "not volatile" }); io.sockets.emit("setVidVolatile", { pos: pos, volat: isVolat }); } -function setVideoColorTag(pos, tag, volat) { - var elem = SERVER.PLAYLIST.first; - for (var i = 0; i < pos; i++) { - elem = elem.next; - } - _setVideoColorTag(elem, pos, tag, volat); -} -function _setVideoColorTag(elem, pos, tag, volat) { + +function setVideoColorTag(elem, pos, tag, volat) { if (tag == false) { delete elem.meta.colorTag; @@ -1342,41 +1398,6 @@ function sendToggleables(socket) { socket.emit("setToggleables", data); } -function getVideoPosition(node) { - let video = SERVER.PLAYLIST.first; - - for (let index = 0; index < SERVER.PLAYLIST.length; index++) { - if (video === node) { - return index; - } - - video = video.next; - } - - return -1; -} - -function getVideoAt(index) { - if (index < 0 || index > SERVER.PLAYLIST.length) { - return null; - } - - let video = SERVER.PLAYLIST.first; - - for (let i = 0; i < SERVER.PLAYLIST.length; i++) { - if (i === index) { - return { - position: index, - node: video - }; - } - - video = video.next; - } - - return null; -} - function saveToHistory(node) { const historyQuery = "insert into videos_history (videoid, videotitle, videolength, videotype, date_added, meta) values (?,?,?,?,NOW(),?)"; const historyQueryParams = [ @@ -2746,29 +2767,19 @@ io.sockets.on('connection', function (ioSocket) { return; } - if (data.from == data.to) { return; } //wat. - if (data.from < 0 || data.to < 0) { return; } //wat. - var elem = SERVER.PLAYLIST.first; - var fromelem, toelem; - for (var i = 0; i < SERVER.PLAYLIST.length; i++) { - if (i == data.from) { - fromelem = elem; - break; - } - elem = elem.next; - } - if (data.sanityid && elem.videoid != data.sanityid) { return doorStuck(socket); } - elem = SERVER.PLAYLIST.first; - for (var i = 0; i < SERVER.PLAYLIST.length; i++) { - if (i == data.to) { - toelem = elem; - break; - } - elem = elem.next; + const [fromelem, toelem] = SERVER.PLAYLIST.multiple([data.from, data.to]); + + if (data.sanityid && fromelem.videoid !== data.sanityid) { + return doorStuck(socket); } + SERVER.PLAYLIST.remove(fromelem); - if (data.to > data.from) { SERVER.PLAYLIST.insertAfter(toelem, fromelem); } - else { SERVER.PLAYLIST.insertBefore(toelem, fromelem); } + if (data.to > data.from) { + SERVER.PLAYLIST.insertAfter(toelem, fromelem); + } + else { + SERVER.PLAYLIST.insertBefore(toelem, fromelem); + } io.sockets.emit("sortPlaylist", data); @@ -2782,28 +2793,18 @@ io.sockets.on('connection', function (ioSocket) { return; } - let prev = null; - let next = null; - - let video = SERVER.PLAYLIST.first; - for (let index = 0; index < SERVER.PLAYLIST.length; index++) { - if (video === SERVER.ACTIVE) { - prev = {node: video, position: index}; - } - - if (index === data.index) { - next = {node: video, position: index}; - } - - if (next && prev) { - break; - } + const prev = { + node: SERVER.ACTIVE, + position: SERVER.PLAYLIST.indexOf(video => video.videoid === SERVER.ACTIVE.videoid) + }; - video = video.next; - } + const next = { + node: SERVER.PLAYLIST.at(data.index), + position: data.index + }; //check if we actually got both - if (!next || !prev) { + if (!next.node || prev.position === -1) { return doorStuck(socket); } @@ -2812,7 +2813,7 @@ io.sockets.on('connection', function (ioSocket) { } if (!prev.node.volat && 'colorTagVolat' in prev.node.meta) { - _setVideoColorTag(prev.node, prev.position, false, false); + setVideoColorTag(prev.node, prev.position, false, false); } SERVER.ACTIVE = next.node; @@ -2834,7 +2835,7 @@ io.sockets.on('connection', function (ioSocket) { return; } - const video = getVideoAt(data.index); + const video = SERVER.PLAYLIST.at(data.index); if (video.node.videoid !== data.sanityid) { return doorStuck(socket); @@ -3076,11 +3077,11 @@ io.sockets.on('connection', function (ioSocket) { }); socket.on("fondleVideo", function (data) { // New abstraction for messing with video details - var elem = SERVER.PLAYLIST.first; - for (var i = 0; i < data.info.pos; i++) { - elem = elem.next; + const video = SERVER.PLAYLIST.at(data.info.pos); + + if (data.sanityid && video.videoid != data.sanityid) { + return doorStuck(socket); } - if (data.sanityid && elem.videoid != data.sanityid) { return doorStuck(socket); } if ("action" in data) { if (data.action == "setVolatile") { @@ -3090,9 +3091,7 @@ io.sockets.on('connection', function (ioSocket) { return; } - pos = data.pos; - isVolat = data.volat; - setVideoVolatile(socket, pos, isVolat); + setVideoVolatile(socket, video, data.pos, data.volat); } if (data.action == "setColorTag") { data = data.info; // Drop action name. @@ -3101,10 +3100,12 @@ io.sockets.on('connection', function (ioSocket) { return; } - pos = ("pos" in data ? data.pos : 0); - tag = ("tag" in data ? data.tag : false); - volat = ("volat" in data ? data.volat : false); - setVideoColorTag(pos, tag, volat); + setVideoColorTag( + video, + data.pos, + data.tag, + data.volat + ); } } }); diff --git a/web/js/callbacks.js b/web/js/callbacks.js index 1093447a..234e518f 100644 --- a/web/js/callbacks.js +++ b/web/js/callbacks.js @@ -68,17 +68,19 @@ socket.on("renewPos", function (data) { }); socket.on("recvNewPlaylist", function (data) { PLAYLIST = new LinkedList.Circular(); - for (var i in data) { - PLAYLIST.append(data[i]); + for (const video of data) { + PLAYLIST.append(video); } + newPlaylist($("#plul")); socket.emit("renewPos"); }); socket.on("recvPlaylist", function (data) { PLAYLIST = new LinkedList.Circular(); - for (var i in data) { - PLAYLIST.append(data[i]); + for (const video of data) { + PLAYLIST.append(video); } + whenExists("#leftpane", function (obj) { initPlaylist($(obj)); setVal("PLREADY", true); @@ -306,15 +308,10 @@ socket.on( } ); socket.on("setVidVolatile", function (data) { - pos = data.pos; - isVolat = data.volat; - setVidVolatile(pos, isVolat); + setVidVolatile(data.pos, data.volat); }); socket.on("setVidColorTag", function (data) { - var pos = data.pos; - var tag = data.tag; - var volat = data.volat; - setVidColorTag(pos, tag, volat); + setVidColorTag(data.pos, data.tag, data.volat); }); socket.on("kicked", function (reason) { var msg = "You have been kicked"; diff --git a/web/js/functions.js b/web/js/functions.js index bcaf74e5..08a6c8fe 100644 --- a/web/js/functions.js +++ b/web/js/functions.js @@ -988,12 +988,11 @@ function recalcStats() { var timeMan = $("#plstats .totalLength"); var x = 0; - elem = PLAYLIST.first; - dbg(PLAYLIST.first.videolength); - for (var i = 0; i < PLAYLIST.length; i++) { - x += (elem.videolength); - elem = elem.next; - } + + PLAYLIST.each(video => { + x += video.videolength; + }); + timeMan.text(secToTime(x)); numberMan.text(PLAYLIST.length + " Videos"); @@ -1706,46 +1705,49 @@ function addNewMailMessage(nick, msg) { } } function plSearch(term) { + const refresh = (index) => { + smartRefreshScrollbar(); + scrollToPlEntry(index); + realignPosHelper(); + }; + if (typeof term == "undefined" || term.match(/^$/) || term.length < 3) { $("#playlist").removeClass("searching"); $("#plul li").removeClass("search-hidden"); $("#plul li.history").remove(); $("#plul li .title").removeAttr("active-offset"); - smartRefreshScrollbar(); - scrollToPlEntry(ACTIVE.domobj.index()); - realignPosHelper(); - } else { - if (TYPE >= 1 || (LEADER && getToggleable('berryqueue'))) { - socket.emit('searchHistory', { search: term }); - } - - $("#playlist").addClass("searching"); - $("#plul li").addClass("search-hidden"); - $("#plul li.active").removeClass("search-hidden"); - elem = PLAYLIST.first; - for (var i = 0; i < PLAYLIST.length; i++) { - name = decodeURI(elem.videotitle); - var rx = new RegExp(term, 'i'); - if (name.match(rx)) { - console.log(name); - var index = i - ACTIVE.domobj.index(); - if (index < 0) { - index = '(' + index + ') '; - } - else if (index > 0) { - index = '(+' + index + ') '; - } - else { - index = ''; - } - $(elem.domobj).removeClass("search-hidden").find(".title").attr("active-offset", index); + refresh(ACTIVE.domobj.index()); + + return; + } + + if (TYPE >= 1 || (LEADER && getToggleable('berryqueue'))) { + socket.emit('searchHistory', { search: term }); + } + + $("#playlist").addClass("searching"); + $("#plul li:not(.active)").addClass("search-hidden"); + + const rx = new RegExp(term, 'i'); + const activeIndex = ACTIVE.domobj.index(); + + PLAYLIST.each((video, index) => { + if (rx.test(decodeURI(video.videotitle))) { + const item = video.domobj[0]; + const diff = index - activeIndex; + + let offsetIndex = ''; + + if (diff !== 0) { + offsetIndex = diff < 0 ? `(${diff}) ` : `(+${diff}) `; } - elem = elem.next; + + item.classList.remove('search-hidden'); + item.querySelector('.title').setAttribute('active-offset', offsetIndex); } - smartRefreshScrollbar(); - scrollToPlEntry(0); - realignPosHelper(); - } + }) + + refresh(0); } function newPoll(data) { if (data.ghost && IGNORE_GHOST_MESSAGES) { @@ -2143,25 +2145,13 @@ function attachAreaEdit(elem, name) { } } function setVidVolatile(pos, isVolat) { - elem = PLAYLIST.first; - for (var i = 0; i < pos; i++) { - elem = elem.next; - } + const video = PLAYLIST.at(pos); - elem.volat = isVolat; - if (isVolat) { - $(elem.domobj).addClass("volatile"); - } else { - $(elem.domobj).removeClass("volatile"); - } - console.log(elem.domobj); + video.volat = isVolat; + video.domobj.toggleClass('volatile', isVolat); } function setVidColorTag(pos, tag, volat) { - elem = PLAYLIST.first; - for (var i = 0; i < pos; i++) { - elem = elem.next; - } - _setVidColorTag(elem.domobj, tag, volat); + _setVidColorTag(PLAYLIST.at(pos).domobj, tag, volat); } function _setVidColorTag(domobj, tag, volat) { var ct = $(domobj).find(".colorTag"); @@ -2599,21 +2589,17 @@ function setPlaylistPosition(to) { ACTIVE.domobj.removeClass("active"); } - var elem = PLAYLIST.first; - ACTIVE = PLAYLIST.first; - for (var i = 0; i < PLAYLIST.length; i++) { - //dbg(elem.videoid+" =?= "+to.video.videoid); - if (elem.videoid == to.video.videoid) { - ACTIVE = elem; - //scrollToPlEntry(i); - break; - } - elem = elem.next; + ACTIVE = PLAYLIST.find((video) => { + return video.videoid === to.video.videoid; + }); + + if (!ACTIVE) { + ACTIVE = PLAYLIST.first; } + if (typeof ACTIVE.domobj != "undefined") { ACTIVE.domobj.addClass("active"); } - //PL_POSITION = to; smartRefreshScrollbar(); realignPosHelper(); @@ -2739,53 +2725,34 @@ function notifyNewMsg(channel, isSquee, isRcv) { } function sortPlaylist(data) { - setVal("sorting", true); - var elem = PLAYLIST.first; - var fromelem, toelem; - for (var i = 0; i < PLAYLIST.length; i++) { - if (i == data.from) { - fromelem = elem; - break; - } - elem = elem.next; - } + const [from, to] = PLAYLIST.multiple([data.from, data.to]); + // Sanity check - if (fromelem.videoid != data.sanityid) { + if (from.videoid != data.sanityid) { // DOOR STUCK - setVal("sorting", false); - socket.emit("refreshMyPlaylist"); + return socket.emit("refreshMyPlaylist"); + } + + setVal("sorting", true); + + PLAYLIST.remove(from); + + if (data.to > data.from) { + PLAYLIST.insertAfter(to, from); + } else { + PLAYLIST.insertBefore(to, from); } - else { - elem = PLAYLIST.first; - for (var i = 0; i < PLAYLIST.length; i++) { - if (i == data.to) { - toelem = elem; - break; - } - elem = elem.next; - } - PLAYLIST.remove(fromelem); + from.domobj.hide("blind", function () { if (data.to > data.from) { - PLAYLIST.insertAfter(toelem, fromelem); - fromelem.domobj.hide("blind", function () { - fromelem.domobj.insertAfter(toelem.domobj).show("blind", function () { - fromelem.domobj.css("display", "list-item"); - realignPosHelper(); - setVal("sorting", false); - }); - }); + from.domobj.insertAfter(to.domobj).show("blind"); } else { - PLAYLIST.insertBefore(toelem, fromelem); - fromelem.domobj.hide("blind", function () { - fromelem.domobj.insertBefore(toelem.domobj).show("blind", function () { - fromelem.domobj.css("display", "list-item"); - realignPosHelper(); - setVal("sorting", false); - }); - }); + from.domobj.insertBefore(to.domobj).show("blind"); } - } + }); + + realignPosHelper(); + setVal("sorting", false); } function filterAdminLog() { diff --git a/web/js/init.js b/web/js/init.js index 4a061fcd..824f641a 100644 --- a/web/js/init.js +++ b/web/js/init.js @@ -96,6 +96,61 @@ LinkedList.Circular.prototype.remove = function (node) { node.next = null; this.length--; }; + +LinkedList.Circular.prototype.some = function(cb) { + return this.find(cb) !== null; +} + +LinkedList.Circular.prototype.find = function(cb) { + let video = this.first; + + for (let i = 0; i < this.length; i++) { + if (cb(video, i)) { + return video; + } + + video = video.next; + } + + return null; +} +LinkedList.Circular.prototype.multiple = function(indexes) { + let map = new Map( + indexes.map(i => [i, null]) + ); + + let video = this.first; + let max = Math.max(...indexes); + + for (let i = 0; i <= max; i++) { + if (map.has(i)) { + map.set(i, video); + } + + video = video.next; + } + + return indexes.map(i => map.get(i)); +} +LinkedList.Circular.prototype.at = function(index) { + let video = this.first; + + for (let i = 0; i < index; i++) { + video = video.next; + } + + return video; +} + +LinkedList.Circular.prototype.each = function(cb) { + let video = this.first; + + for (let i = 0; i < this.length; i++) { + cb(video, i); + video = video.next; + } +} + LinkedList.Circular.prototype.toArray = function () { var elem = this.first; var out = []; @@ -1200,17 +1255,11 @@ function initPlaylistControls(plwrap) { if (controlsPlaylist()) { var btn = $(this); parseVideoURL($(videoImport).val(), function (id, type, videotitle) { - elem = PLAYLIST.first; var found = false; - for (var i = 0; i < PLAYLIST.length; i++) { - if (elem.videoid == id) { - found = true; - doRequeue(elem.domobj); - console.log("found"); - break; - } - elem = elem.next; - } - if (!found) { + const video = PLAYLIST.find(video => video.videoid === id); + + if (video) { + doRequeue(video.domobj); + } else { btn.data('revertTxt', "Q"); btn.text('').addClass("loading"); LAST_QUEUE_ATTEMPT = { @@ -1231,17 +1280,11 @@ function initPlaylistControls(plwrap) { if (controlsPlaylist()) { var btn = $(this); parseVideoURL($(videoImport).val(), function (id, type, videotitle) { - elem = PLAYLIST.first; var found = false; - for (var i = 0; i < PLAYLIST.length; i++) { - if (elem.videoid == id) { - found = true; - doRequeue(elem.domobj); - console.log("found"); - break; - } - elem = elem.next; - } - if (!found) { + const video = PLAYLIST.find(video => video.videoid === id); + + if (video) { + doRequeue(video.domobj); + } else { btn.data('revertTxt', "V"); btn.text('').addClass("loading"); LAST_QUEUE_ATTEMPT = { @@ -1257,39 +1300,6 @@ function initPlaylistControls(plwrap) { } }); - /* - var vaddBtn = $('
').addClass("impele").addClass("btn").text("+").appendTo(container); - vaddBtn.click(function(){ - if(controlsPlaylist()){ - var btn = $(this); - parseVideoURL($(videoImport).val(),function(id,type,videotitle){ - elem=PLAYLIST.first; var found = false; - for(var i=0;i