added initial draft for node upload server
This commit is contained in:
110
manage-audio/index.html
Normal file
110
manage-audio/index.html
Normal file
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Audio Uploader</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" />
|
||||
<script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
||||
<style>
|
||||
body { font-family: sans-serif; padding: 2rem; width:500px; margin: 0 auto; }
|
||||
.dropzn { border: 2px dashed #666; padding: 2rem; margin-bottom: 2rem; }
|
||||
#playlist { padding-left: 0; }
|
||||
#playlist li { margin-bottom: 0.5rem; background: #eee; padding: 0.5rem; border-radius: 4px; cursor: grab; display: flex; justify-content: space-between; align-items: center; }
|
||||
#playlist li span { width: 85%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Upload Audio</h1>
|
||||
<form action="http://localhost:3000/upload" class="dropzn" id="audio-dropzone">
|
||||
<div class="dz-message">Drop audio files here or click to upload</div>
|
||||
</form>
|
||||
|
||||
<h2>Playlist</h2>
|
||||
<ul id="playlist"></ul>
|
||||
|
||||
<script>
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
new Dropzone("#audio-dropzone", {
|
||||
url: "http://localhost:3000/upload",
|
||||
method: "post",
|
||||
paramName: "file", // matches Multer field
|
||||
maxFilesize: 20,
|
||||
acceptedFiles: "audio/*",
|
||||
init: function () {
|
||||
this.on("sending", function(file, xhr, formData) {
|
||||
const title = prompt("Enter title for: " + file.name);
|
||||
formData.append("title", title || file.name);
|
||||
const token = btoa("admin:supersecret");
|
||||
xhr.setRequestHeader("Authorization", "Basic " + token);
|
||||
});
|
||||
this.on("success", function() {
|
||||
setTimeout(loadPlaylist, 500);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
async function fetchPlaylist() {
|
||||
const res = await fetch("http://localhost:3000/api/playlist");
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
async function loadPlaylist() {
|
||||
const list = document.getElementById("playlist");
|
||||
list.innerHTML = "";
|
||||
const tracks = await fetchPlaylist();
|
||||
tracks.forEach(track => {
|
||||
const li = document.createElement("li");
|
||||
li.setAttribute("data-url", track.url);
|
||||
li.innerHTML = `
|
||||
🎵 <span>${track.title}</span>
|
||||
<button onclick="deleteTrack('${track.url}')">X </button>
|
||||
`;
|
||||
list.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteTrack(url) {
|
||||
const filename = url.split("/").pop();
|
||||
const res = await fetch("http://localhost:3000/delete", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Basic " + btoa("admin:supersecret")
|
||||
},
|
||||
body: JSON.stringify({ filename })
|
||||
});
|
||||
if (res.ok) loadPlaylist();
|
||||
}
|
||||
|
||||
function saveNewOrder() {
|
||||
const items = document.querySelectorAll("#playlist li");
|
||||
const newOrder = Array.from(items).map(li => ({
|
||||
title: li.querySelector("span").textContent.trim(),
|
||||
url: li.getAttribute("data-url")
|
||||
}));
|
||||
|
||||
fetch("http://localhost:3000/reorder", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Basic " + btoa("admin:supersecret")
|
||||
},
|
||||
body: JSON.stringify({ playlist: newOrder })
|
||||
});
|
||||
}
|
||||
|
||||
new Sortable(document.getElementById("playlist"), {
|
||||
animation: 150,
|
||||
onEnd: saveNewOrder
|
||||
});
|
||||
|
||||
loadPlaylist();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user