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 = $(`
`)
+ let $element = $(`

`)
$(".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