diff --git a/channel.js b/channel.js index 14270bef..e0234893 100644 --- a/channel.js +++ b/channel.js @@ -47,11 +47,14 @@ var Channel = function(name) { oplaylistmove: 1.5, oplaylistdelete: 2, oplaylistjump: 1.5, + oplaylistaddlist: 1.5, playlistadd: 1.5, playlistnext: 1.5, playlistmove: 1.5, playlistdelete: 2, playlistjump: 1.5, + playlistaddlist: 1.5, + playlistadd: 1.5, addnontemp: 2, settemp: 2, playlistgeturl: 1.5, @@ -1080,7 +1083,7 @@ Channel.prototype.tryQueue = function(user, data) { } Channel.prototype.tryQueuePlaylist = function(user, data) { - if(!this.hasPermission(user, "playlistadd")) { + if(!this.hasPermission(user, "playlistaddlist")) { return; } diff --git a/database.js b/database.js index fa5c4f87..ea254f53 100644 --- a/database.js +++ b/database.js @@ -814,8 +814,9 @@ function saveUserPlaylist(pl, user, name) { var plstr = JSON.stringify(pl2); var query = createQuery( - "INSERT INTO user_playlists VALUES (?, ?, ?)", - [user, name, plstr] + "INSERT INTO user_playlists VALUES (?, ?, ?)" + + "ON DUPLICATE KEY UPDATE contents=?", + [user, name, plstr, plstr] ); var results = db.querySync(query); @@ -827,6 +828,24 @@ function saveUserPlaylist(pl, user, name) { return true; } +function deleteUserPlaylist(user, name) { + var db = getConnection(); + if(!db) { + return false; + } + + var query = createQuery( + "DELETE FROM user_playlists WHERE user=? AND name=?", + [user, name] + ); + + var results = db.querySync(query); + if(!results) { + Logger.errlog.log("! Failed to delete from user_playlists"); + } + return results; +} + exports.setup = setup; exports.getConnection = getConnection; exports.createQuery = createQuery; @@ -855,3 +874,4 @@ exports.resetPassword = resetPassword; exports.getUserPlaylists = getUserPlaylists; exports.loadUserPlaylist = loadUserPlaylist; exports.saveUserPlaylist = saveUserPlaylist; +exports.deleteUserPlaylist = deleteUserPlaylist; diff --git a/user.js b/user.js index 275b8d77..2227dec0 100644 --- a/user.js +++ b/user.js @@ -457,6 +457,10 @@ User.prototype.initCallbacks = function() { success: result, error: result ? false : "Unknown" }); + var list = Database.getUserPlaylists(this.name); + this.socket.emit("listPlaylists", { + pllist: list, + }); }.bind(this)); this.socket.on("queuePlaylist", function(data) { @@ -464,6 +468,18 @@ User.prototype.initCallbacks = function() { this.channel.tryQueuePlaylist(this, data); } }.bind(this)); + + this.socket.on("deletePlaylist", function(data) { + if(typeof data.name != "string") { + return; + } + + Database.deleteUserPlaylist(this.name, data.name); + var list = Database.getUserPlaylists(this.name); + this.socket.emit("listPlaylists", { + pllist: list, + }); + }.bind(this)); } // Handle administration diff --git a/www/assets/css/ytsync.css b/www/assets/css/ytsync.css index 7e6bfaa7..c7e3016b 100644 --- a/www/assets/css/ytsync.css +++ b/www/assets/css/ytsync.css @@ -59,6 +59,20 @@ html, body { clear: both; } +#userpl_list { + list-style: none outside none; + margin-left: 0; + max-height: 500px; + overflow-y: scroll; +} + +#userpl_list li { + clear: both; + margin: 2px 0 0 auto; + padding: 2px; + font-size: 8pt; +} + #queue { margin-bottom: 0; } diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 6852693a..31bf8416 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -760,11 +760,62 @@ Callbacks = { } else { var pls = data.pllist; - $("#userpl_dropdown").html(""); + pls.sort(function(a, b) { + var x = a.name.toLowerCase(); + var y = b.name.toLowerCase(); + if(x < y) return -1; + if(x > y) return 1; + return 0; + }); + $("#userpl_list").html(""); for(var i = 0; i < pls.length; i++) { - $("").attr("value", pls[i].name) - .text(pls[i].name) - .appendTo($("#userpl_dropdown")); + var li = $("
").appendTo($("#userpl_list")) + .addClass("well"); + li.data("pl-name", pls[i].name); + $("").text(pls[i].name).appendTo(li) + .css("float", "left") + .css("margin-left", "1em"); + var bg = $("").addClass("btn-group") + .css("float", "left") + .prependTo(li); + var del = $("") + .addClass("btn btn-mini btn-danger") + .prependTo(bg); + $("").addClass("icon-trash").appendTo(del); + (function(li) { + del.click(function() { + socket.emit("deletePlaylist", { + name: li.data("pl-name") + }); + }); + })(li); + if(hasPermission("playlistaddlist")) { + (function(li) { + $("").addClass("btn btn-mini") + .text("End") + .prependTo(bg) + .click(function() { + socket.emit("queuePlaylist", { + name: li.data("pl-name"), + pos: "end" + }); + }); + })(li); + + if(hasPermission("playlistnext")) { + (function(li) { + $("").addClass("btn btn-mini") + .text("Next") + .prependTo(bg) + .click(function() { + socket.emit("queuePlaylist", { + name: li.data("pl-name"), + pos: "next" + }); + }); + })(li); + } + } } } } diff --git a/www/assets/js/client.js b/www/assets/js/client.js index 6ecd55b5..0a7cd087 100644 --- a/www/assets/js/client.js +++ b/www/assets/js/client.js @@ -572,20 +572,6 @@ $("#userpl_name").keydown(function(ev) { } }); -$("#userpl_queuenext").click(function() { - socket.emit("queuePlaylist", { - name: $("#userpl_dropdown").val(), - pos: "next" - }); -}); - -$("#userpl_queueend").click(function() { - socket.emit("queuePlaylist", { - name: $("#userpl_dropdown").val(), - pos: "end" - }); -}); - $("#show_userpl").click(function() { $("#show_library").parent().removeClass("active"); $("#show_userpl").parent().addClass("active"); diff --git a/www/assets/js/functions.js b/www/assets/js/functions.js index 4cf07898..47890980 100644 --- a/www/assets/js/functions.js +++ b/www/assets/js/functions.js @@ -784,8 +784,8 @@ function handlePermissionChange() { setVisible("#clearplaylist", hasPermission("playlistclear")); setVisible("#shuffleplaylist", hasPermission("playlistshuffle")); - $("#userpl_queueend").attr("disabled", !hasPermission("playlistadd")); - $("#userpl_queuenext").attr("disabled", !hasPermission("playlistnext")); + $("#userpl_queueend").attr("disabled", !hasPermission("playlistaddlist")); + $("#userpl_queuenext").attr("disabled", !hasPermission("playlistaddlist") || !hasPermission("playlistnext")); setVisible("#modnav", RANK >= 2); setVisible("#chanperms_tab", RANK >= 3); @@ -1268,6 +1268,7 @@ function genPermissionsEditor() { makeOption("Move playlist items", "oplaylistmove", standard, CHANPERMS.oplaylistmove+""); makeOption("Delete playlist items", "oplaylistdelete", standard, CHANPERMS.oplaylistdelete+""); makeOption("Jump to video", "oplaylistjump", standard, CHANPERMS.oplaylistjump+""); + makeOption("Queue playlist", "oplaylistaddlist", standard, CHANPERMS.oplaylistaddlist+""); addDivider("General playlist permissions"); makeOption("Add to playlist", "playlistadd", standard, CHANPERMS.playlistadd+""); @@ -1275,6 +1276,7 @@ function genPermissionsEditor() { makeOption("Move playlist items", "playlistmove", standard, CHANPERMS.playlistmove+""); makeOption("Delete playlist items", "playlistdelete", standard, CHANPERMS.playlistdelete+""); makeOption("Jump to video", "playlistjump", standard, CHANPERMS.playlistjump+""); + makeOption("Queue playlist", "playlistaddlist", standard, CHANPERMS.playlistaddlist+""); makeOption("Add nontemporary media", "addnontemp", standard, CHANPERMS.addnontemp+""); makeOption("Temp/untemp playlist item", "settemp", standard, CHANPERMS.settemp+""); makeOption("Retrieve playlist URLs", "playlistgeturl", standard, CHANPERMS.playlistgeturl+""); diff --git a/www/channel.html b/www/channel.html index f4cf9491..a1977ff2 100644 --- a/www/channel.html +++ b/www/channel.html @@ -88,14 +88,8 @@