Added remove playlist function on dashboard

This commit is contained in:
Choco
2023-05-31 12:23:30 +08:00
parent a5cecd02e2
commit c8dbc505f4
4 changed files with 185 additions and 85 deletions

View File

@@ -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]
}

View File

@@ -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 {

View File

@@ -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 = $(`<div class="track" data-value=${track_id} ><div class="left">${(this.isDJ) ? '<i class="fa-solid fa-bars handle"></i>' : ''}<img src=${track.imageUrl} /><div class="info"><p>${track.title}</p><p class="desc">${track.author}</p></div></div><p class="time">${player.msToReadableTime(track.length)}</p><i class="fa-solid fa-ellipsis-vertical action"></i></div>`);
$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" })
}
}
})

View File

@@ -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(`<li class="search-result"><div class="search-result-left"><img src=${track.imageUrl} /><div class="search-result-info"><p class="info">${track.title}</p><p class="desc">${track.author}</p></div></div><p>${player.msToReadableTime(track.length)}</p></li>`)
}
}
@@ -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 = $(`<div class="playlist" data-value="${key}">`);
let iDiv = $("<div class='images'>");
let infoDiv = $("<div class='info'>");
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 = $("<img>").attr("src", track.imageUrl);
iDiv.append(img);
}
}
iDiv.append(`<i class="fa-solid fa-ellipsis-vertical action"></i>`);
iDiv.append(`<i class="fa-solid fa-play play"></i>`);
pDiv.append(iDiv);
infoDiv.append(`<p>${pList["name"]}</p>`);
infoDiv.append(`<p class="desc">${pList["type"]}${pList["tracks"].length} Tracks</p>`);
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(`<li><div class="track"><div class="left">${(this.isDJ) ? '<i class="fa-solid fa-bars handle"></i>' : ''}<img src=${track.imageUrl} /><div class="info"><p>${track.title}</p><p class="desc">${track.author}</p></div></div><p class="time">${this.msToReadableTime(track.length)}</p><i class="fa-solid fa-ellipsis-vertical action"></i></div></li>`)
}
@@ -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 = $(`<div class="toast"><img src=${user['avatar_url']} alt="user-icon"/><div class="content"><p class="username">${user['name']}</p><p class="message">${msg}</p></div></div>`)
let $element = $(`<div class="toast"><img src=${user['avatar_url']} alt="user-icon"/><div class="content"><p class="username">${user['name']}</p><p class="message">${msg}</p></div></div>`)
$(".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 = $(`<div class="playlist" data-value="${key}">`);
let iDiv = $("<div class='images'>");
let infoDiv = $("<div class='info'>");
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 = $("<img>").attr("src", track.imageUrl);
iDiv.append(img);
}
}
iDiv.append(`<i class="fa-solid fa-ellipsis-vertical action"></i>`);
iDiv.append(`<i class="fa-solid fa-play play"></i>`);
pDiv.append(iDiv);
infoDiv.append(`<p>${pList["name"]}</p>`);
infoDiv.append(`<p class="desc">${pList["type"]}${pList["tracks"].length} Tracks</p>`);
pDiv.append(infoDiv);
$("#playlists-grid").append(pDiv);
$("#playlists-tracks").empty()
}
}
}