From c8dbc505f418ddaabdaf320409c20917f05688ec Mon Sep 17 00:00:00 2001 From: Choco <94597336+ChocoMeow@users.noreply.github.com> Date: Wed, 31 May 2023 12:23:30 +0800 Subject: [PATCH] Added remove playlist function on dashboard --- web/ipc/methods.py | 14 +++++ web/static/css/main.css | 11 ++++ web/static/js/action.js | 129 +++++++++++++++++++++++++++++++-------- web/static/js/objects.js | 116 +++++++++++++++++------------------ 4 files changed, 185 insertions(+), 85 deletions(-) diff --git a/web/ipc/methods.py b/web/ipc/methods.py index 58bfa17..1cd01b2 100644 --- a/web/ipc/methods.py +++ b/web/ipc/methods.py @@ -292,6 +292,19 @@ async def getPlaylists(member: Member, data: dict): "user_id": member.id } +async def removePlaylist(member: Member, data:dict): + pId = data.get("pId") + isShare = data.get("isShare", False) + + if pId == 200: + return + + if isShare: + refer_user = data.get("refer_user") + await func.update_playlist(refer_user, {f"playlist.{pId}.perms.read": member.id}, pull=True, mode=False) + + await func.update_playlist(member.id, {f'playlist.{pId}': 1}, mode=False) + async def addPlaylistTrack(member: Member, data: dict): track_id = data.get("track") pId = data.get("pId") @@ -333,6 +346,7 @@ methods = { "updatePosition": [updatePosition, False], "toggleAutoplay": [toggleAutoplay, False], "getPlaylists": [getPlaylists, False], + "removePlaylist": [removePlaylist, False], "addPlaylistTrack": [addPlaylistTrack, False], "removePlaylistTrack": [removePlaylistTrack, False] } diff --git a/web/static/css/main.css b/web/static/css/main.css index f0d4056..4f623cd 100644 --- a/web/static/css/main.css +++ b/web/static/css/main.css @@ -123,6 +123,10 @@ a { transition: background-color 0.5s ease; } +.header.active { + background-color: #020202; +} + .header .left { display: flex; } @@ -730,6 +734,7 @@ input:checked+.slider:before { .playlists { flex-grow: 1; padding: 0rem 4rem; + transition: all 0.2s ease-in-out; } .playlists-grid { @@ -878,12 +883,18 @@ input:checked+.slider:before { width: 100%; } + .playlists { + padding: 0 1rem; + } + .playlists-grid { grid-gap: 1rem; padding: 1rem; grid-template-rows: repeat(auto-fit, 200px); grid-template-columns: repeat(auto-fit, minmax(150px, 150px)); grid-auto-rows: 200px; + justify-content: center; + align-items: center; } .images { diff --git a/web/static/js/action.js b/web/static/js/action.js index 0683379..ac5682c 100644 --- a/web/static/js/action.js +++ b/web/static/js/action.js @@ -8,6 +8,7 @@ $(document).ready(function () { var startPos = null; var selectedTrack = null; var selectedPlaylistId = null; + var selectedPlaylistTrack = null; var typingTimer; var doneTypingInterval = 2000; @@ -22,7 +23,7 @@ $(document).ready(function () { context.drawImage(largeImage, 0, startY, width, height, 0, 0, width, height); getMainColorsFromImage(4) .then(colors => { - var bg = $(".thumbnail-background"); + let bg = $(".thumbnail-background"); bg.css({ "background": `linear-gradient(-132deg, ${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]})`, "width": "70%", @@ -75,18 +76,19 @@ $(document).ready(function () { } $("#seek-bar").on('mousemove', function (e) { - var position = e.pageX - $(this).offset().left; - var duration = $(this).width(); - var percentage = (position / duration) * 100; + let position = e.pageX - $(this).offset().left; + let duration = $(this).width(); + let percentage = (position / duration) * 100; - var time = player.msToReadableTime(percentage * player.currentTrack?.length / 100); + let time = player.msToReadableTime(percentage * player.currentTrack?.length / 100); $positionInfo.text(time).css({ left: e.pageX - $positionInfo.outerWidth() / 2, }); }); $('body').click(function (event) { - var $target = $(event.target); + let $target = $(event.target); + if (!$target.closest(".search-container").length && !$target.is("#search-input") && $('#search-result-list').css("display") != 'none') { $("#search-result-list").fadeOut(200); } @@ -96,15 +98,29 @@ $(document).ready(function () { $(".users-bar").hasClass("active")) { $(".users-bar").removeClass("active"); $("#users-btn").css({ "color": "" }); - } - else if (!$target.closest(".action").is(".action") && - !$target.closest("#context-menu li").is("#context-menu li") && - $("#context-menu").css("display") != "none") { - $("#context-menu").fadeOut(200); - } + } else if ($target.closest(".action").is(".action") && + $target.closest(".playlists-tracks").is(".playlists-tracks")) { - else if ($target.closest(".images").is(".images")) { + selectedPlaylistTrack = $target.closest(".track").data("value"); + const $contextMenu = $("#context-menu"); + const menuHeight = $contextMenu.outerHeight(); + const windowHeight = $(window).height(); + const topPosition = event.pageY + 30; + if (topPosition + menuHeight > windowHeight) { + // If the menu would go out of the page, position it above the btn instead + $contextMenu.css({ "left": `${event.pageX - 130}px`, "top": `${event.pageY - menuHeight - 30}px` }).fadeIn(200); + } else { + $contextMenu.css({ "left": `${event.pageX - 130}px`, "top": `${topPosition}px` }).fadeIn(200); + } + + } else if ($target.closest(".playlists-tracks").is(".playlists-tracks") && + $target.closest(".track").is(".track")) { + + const track_id = $target.closest(".track").data("value"); + player.send({ "op": "addTracks", "tracks": [track_id] }) + + } else if ($target.closest(".playlist").is(".playlist")) { selectedPlaylistId = $target.closest(".playlist").data("value"); if ($target.closest(".action").is(".action")) { @@ -122,13 +138,33 @@ $(document).ready(function () { } else if ($target.closest(".play").is(".play")) { if (selectedPlaylistId in player.playlists) { if ("tracks" in player.playlists[selectedPlaylistId]) { - player.send({ "op": "addTracks", "tracks": player.playlists[selectedPlaylistId]["tracks"] }); + if (player.playlists[selectedPlaylistId]['tracks'].length != 0) { + player.send({ "op": "addTracks", "tracks": player.playlists[selectedPlaylistId]["tracks"] }); + } + } + } + } else { + const $pTracks = $("#playlists-tracks"); + if (selectedPlaylistId in player.playlists) { + $pTracks.empty(); + for (const track_id of player.playlists[selectedPlaylistId]["tracks"]) { + const track = decode(track_id); + + let $trackDiv = $(`
${(this.isDJ) ? '' : ''}

${track.title}

${track.author}

${player.msToReadableTime(track.length)}

`); + $pTracks.append($trackDiv); } } } } if (!$target.closest(".action").is(".action") && + !$target.closest("#context-menu li").is("#context-menu li") && + $("#context-menu").css("display") != "none") { + $("#context-menu").fadeOut(200); + } + + if (!$target.closest(".action").is(".action") || + !$target.closest(".images").is(".images") && $("#playlist-context-menu").css("display") != "none") { $("#playlist-context-menu").fadeOut(200); } @@ -144,7 +180,7 @@ $(document).ready(function () { }, stop: function (event, ui) { if (startPos != null) { - var newPos = ui.item.index(); + let newPos = ui.item.index(); if (startPos != newPos) { player.moveTrack(startPos, newPos) } @@ -154,8 +190,8 @@ $(document).ready(function () { }); $('#sortable').on('click', 'li', function (event) { - var index = $(this).index(); - var position = player.current_queue_position; + let index = $(this).index(); + let position = player.current_queue_position; if ($(event.target).hasClass('action')) { selectedTrack = { position: index, track: player.queue[index] }; @@ -181,8 +217,8 @@ $(document).ready(function () { }) $('#search-result-list').on('click', 'li', function () { - var index = $(this).index(); - var track = player.searchList[index]; + let index = $(this).index(); + let track = player.searchList[index]; if (track != undefined) { player.send({ "op": "addTracks", "tracks": [track] }); } @@ -193,7 +229,7 @@ $(document).ready(function () { clearTimeout(typingTimer); $("#search-loader").fadeIn(200); typingTimer = setTimeout(function () { - var input = $('#search-input').val(); + let input = $('#search-input').val(); if (input.replace(/\s+/g, '') != "") { player.send({ "op": "getTracks", "query": input }) } else { @@ -245,23 +281,62 @@ $(document).ready(function () { }) $("#auto-play").on("click", function () { - var checkbox = $(this).is(':checked'); + let checkbox = $(this).is(':checked'); player.send({ "op": "toggleAutoplay", "status": checkbox }) }); $("#remove-track-btn").on('click', function () { - player.removeTrack(selectedTrack?.position, selectedTrack?.track) + if ($("#main").css("display") == "none") { + if (selectedPlaylistId != null && selectedPlaylistId != null && player.playlists != null) { + const playlist = player.playlists[selectedPlaylistId]; + if (playlist["type"] == "playlist") { + player.send({ "op": "removePlaylistTrack", "pId": selectedPlaylistId, "track_id": selectedPlaylistTrack, "pType": playlist["type"] }) + let index = playlist["tracks"].indexOf(selectedPlaylistTrack); + if (index !== -1) { + playlist["tracks"].splice(index, 1); + } + $(`div [data-value=${selectedPlaylistTrack}]`).remove(); + } + } + } else { + player.removeTrack(selectedTrack?.position, selectedTrack?.track) + } $("#context-menu").fadeOut(200); }) $("#copy-track-btn").on('click', function () { - navigator.clipboard.writeText(selectedTrack?.track.uri); + if ($("#main").css("display") == "none") { + if (selectedPlaylistTrack != null) { + const track = decode(selectedPlaylistTrack); + navigator.clipboard.writeText(track.uri); + } + } else { + navigator.clipboard.writeText(selectedTrack?.track.uri); + } $("#context-menu").fadeOut(200); }) + $("#remove-playlist-btn").on('click', function () { + if (player.playlists != null && selectedPlaylistId in player.playlists) { + if (selectedPlaylistId != 200) { + playlist = player.playlists[selectedPlaylistId]; + console.log(player.playlists); + let payload = { "op": "removePlaylist", "pId": selectedPlaylistId } + if (playlist['type'] == "share") { + payload["refer_user"] = playlist["user"]; + payload["isShare"] = true; + } + player.send(payload); + delete player.playlists[selectedPlaylistId]; + player.updatePlaylists(); + } + } + }) + $("#homeBtn").on('click', function () { $("#playlists").fadeOut(200, function () { $("#main").fadeIn(200); + $(".header").removeClass("active"); }); }) @@ -272,22 +347,22 @@ $(document).ready(function () { player.send({ "op": "getPlaylists" }); } $("#playlists").fadeIn(200); + $(".header").addClass("active"); }); - }) $("#like-btn").on('click', function () { - var currentTrack = player.currentTrack; + let currentTrack = player.currentTrack; if (currentTrack != undefined) { if (currentTrack.isStream) { return player.showToast("error", "You are not allowed to add streaming videos to your playlist!"); } if ($(this).hasClass("fa-regular")) { $(this).removeClass("fa-regular").addClass("fa-solid"); - player.send({"op": "addPlaylistTrack", "track": currentTrack.track_id, "pId": "200"}) + player.send({ "op": "addPlaylistTrack", "track_id": currentTrack.track_id, "pId": "200" }) } else { $(this).removeClass("fa-solid").addClass("fa-regular"); - player.send({"op": "removePlaylistTrack", "track": currentTrack.track_id, "pId": "200"}) + player.send({ "op": "removePlaylistTrack", "track_id": currentTrack.track_id, "pId": "200" }) } } }) diff --git a/web/static/js/objects.js b/web/static/js/objects.js index c9976e7..bb50710 100644 --- a/web/static/js/objects.js +++ b/web/static/js/objects.js @@ -37,7 +37,7 @@ class DataInput { if (typeof bytes === "string") { var decodedString = atob(bytes); var bytes = new Uint8Array(decodedString.length); - for (var i = 0; i < decodedString.length; i++) { + for (let i = 0; i < decodedString.length; i++) { bytes[i] = decodedString.charCodeAt(i); } } @@ -165,7 +165,7 @@ const actions = { }, trackUpdate: function (player, data) { - var track = player.updateCurrentQueuePos(data['current_queue_position']); + let track = player.updateCurrentQueuePos(data['current_queue_position']); player.is_paused = data['is_paused']; if (track?.track_id != data["track_id"]) { player.send({ "op": "initPlayer" }) @@ -184,13 +184,13 @@ const actions = { }, getTracks: function (player, data) { - var tracks = data["tracks"]; + let tracks = data["tracks"]; if (tracks != undefined) { const resultList = $("#search-result-list"); resultList.empty(); player.searchList = tracks; - for (var i in tracks) { - var track = decode(tracks[i]) + for (let i in tracks) { + let track = decode(tracks[i]) resultList.append(`
  • ${track.title}

    ${track.author}

    ${player.msToReadableTime(track.length)}

  • `) } } @@ -229,11 +229,10 @@ const actions = { updatePause: function (player, data) { player.is_paused = data['pause']; - var msg = ""; if (data["pause"]) { - msg = "Paused the player." + var msg = "Paused the player." } else { - msg = "Resumed the player." + var msg = "Resumed the player." } player.showToast(data["requester_id"], msg) }, @@ -243,10 +242,10 @@ const actions = { }, swapTrack: function (player, data) { - var index1 = player.current_queue_position + data['position2']["index"]; - var index2 = player.current_queue_position + data['position1']["index"]; - var track1 = player.queue[index1]; - var track2 = player.queue[index2]; + let index1 = player.current_queue_position + data['position2']["index"]; + let index2 = player.current_queue_position + data['position1']["index"]; + let track1 = player.queue[index1]; + let track2 = player.queue[index2]; if (track1?.track_id != data['position1']["track_id"] || track2?.track_id != data['position2']["track_id"]) { return player.send({ "op": "initPlayer" }); @@ -274,12 +273,11 @@ const actions = { }, shuffleTrack: function (player, data) { - var tracks = data["tracks"]; + let tracks = data["tracks"]; if (tracks != undefined) { player.queue = []; tracks.forEach(rawTrack => { - - var track = new Track(rawTrack); + let track = new Track(rawTrack); player.queue.push(track); }); player.initSortable(); @@ -330,42 +328,13 @@ const actions = { }, errorMsg: function (player, data) { - console.log("hello") player.showToast(data["level"], data["msg"]); }, getPlaylists: function (player, data) { const playlists = data["playlists"] player.playlists = playlists; - - $("#playlists-grid").empty(); - for (let key in playlists) { - const pList = playlists[key]; - let pDiv = $(`
    `); - let iDiv = $("
    "); - let infoDiv = $("
    "); - - if (pList["tracks"] === 0) { - continue; - } else { - for (let i = 0; i < 4; i++) { - if (pList["tracks"][i] == undefined) { - continue; - } - var track = decode(pList["tracks"][i]) - let img = $("").attr("src", track.imageUrl); - iDiv.append(img); - - } - } - iDiv.append(``); - iDiv.append(``); - pDiv.append(iDiv); - infoDiv.append(`

    ${pList["name"]}

    `); - infoDiv.append(`

    ${pList["type"]} • ${pList["tracks"].length} Tracks

    `); - pDiv.append(infoDiv); - $("#playlists-grid").append(pDiv); - } + player.updatePlaylists(); } } @@ -454,8 +423,8 @@ class Player { }; } addTrack(tracks) { - for (var i in tracks) { - var track = decode(tracks[i]) + for (let i in tracks) { + let track = decode(tracks[i]) this.queue.push(track); $("#sortable").append(`
  • ${(this.isDJ) ? '' : ''}

    ${track.title}

    ${track.author}

    ${this.msToReadableTime(track.length)}

  • `) } @@ -483,7 +452,7 @@ class Player { } removeTrack(position, track) { - var rawTrack = this.queue[position]; + let rawTrack = this.queue[position]; if (position == this.current_queue_position) { return this.showToast("error", "You are not allow to remove playing track!"); } @@ -510,7 +479,7 @@ class Player { if (this.currentTrack == undefined) { return; } - var position = tempPosition / 500 * this.currentTrack.length; + let position = tempPosition / 500 * this.currentTrack.length; this.send({ "op": "updatePosition", "position": position }); } @@ -527,7 +496,7 @@ class Player { } send(payload) { - var json = JSON.stringify(payload) + let json = JSON.stringify(payload) this.socket.send(json); } @@ -564,7 +533,7 @@ class Player { var user = this.users[userId]; } if (user != null) { - var $element = $(`
    user-icon

    ${user['name']}

    ${msg}

    `) + let $element = $(`
    user-icon

    ${user['name']}

    ${msg}

    `) $(".toastContrainer").append($element) setTimeout(function () { @@ -586,14 +555,15 @@ class Player { this.current_position += 1000; $("#position").text(this.msToReadableTime(this.current_position)); - var time = (this.current_position / this.currentTrack?.length) * 500; + let time = (this.current_position / this.currentTrack?.length) * 500; $("#seek-bar").val(time); } updateInfo() { - var currentTrack = this.currentTrack; + let currentTrack = this.currentTrack; if (currentTrack == undefined) { - $(".control-container .center").fadeOut(); + $("#title").text(""); + $("#author").text(""); $("#position").text("00:00"); $("#length").text("00:00"); $("#image").fadeOut(100, function () { $(this).removeAttr("src"); }); @@ -603,11 +573,10 @@ class Player { } else { $("#title").text(currentTrack.title); $("#author").text(currentTrack.author); - $(".control-container .center").fadeIn(); $("#length").text(this.msToReadableTime(currentTrack.length)); $("#auto-play").prop('checked', this.autoplay); - var image = ""; + let image = ""; if (currentTrack.source == "youtube") { image += `${window.location.protocol}//${window.location.hostname}:${window.location.port}/`; } @@ -634,8 +603,8 @@ class Player { } $("#channel-name").text((this.channelName == "") ? "Not Found" : this.channelName); - var play_pause_btn = $("#play-pause-btn"); - var repeat_btn = $("#repeat-btn"); + let play_pause_btn = $("#play-pause-btn"); + let repeat_btn = $("#repeat-btn"); if (this.is_paused || currentTrack == undefined) { play_pause_btn.removeClass('fa-pause').addClass('fa-play'); if (this.timer.getIsRunning()) { @@ -656,4 +625,35 @@ class Player { } } + updatePlaylists() { + $("#playlists-grid").empty(); + for (let key in this.playlists) { + const pList = this.playlists[key]; + let pDiv = $(`
    `); + let iDiv = $("
    "); + let infoDiv = $("
    "); + + if (pList["tracks"] === 0) { + continue; + } else { + for (let i = 0; i < 4; i++) { + if (pList["tracks"][i] == undefined) { + continue; + } + let track = decode(pList["tracks"][i]) + let img = $("").attr("src", track.imageUrl); + iDiv.append(img); + + } + } + iDiv.append(``); + iDiv.append(``); + pDiv.append(iDiv); + infoDiv.append(`

    ${pList["name"]}

    `); + infoDiv.append(`

    ${pList["type"]} • ${pList["tracks"].length} Tracks

    `); + pDiv.append(infoDiv); + $("#playlists-grid").append(pDiv); + $("#playlists-tracks").empty() + } + } } \ No newline at end of file