feat: make cute design

This commit is contained in:
Radu C. Martin 2025-04-14 17:28:09 +02:00
parent 79f72d0531
commit a1fa762ea8
4 changed files with 159 additions and 97 deletions

148
index.html Normal file
View file

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Music Player</title>
<style>
body { font-family: sans-serif; padding: 1rem; }
button { margin: 0.5rem; }
#queueList { margin-top: 1rem; }
</style>
</head>
<body>
<div style="font-family: sans-serif; max-width: 600px; margin: auto;">
<h2>🎵 Dashdio</h2>
<div id="nowPlaying">
<strong>Artist:</strong> <span id="trackArtist">-</span><br>
<strong>Title:</strong> <span id="trackTitle">-</span><br>
<strong>Status:</strong> <span id="playbackState">-</span><br>
<div style="margin-top: 10px;">
<progress id="progressBar" value="0" max="100" style="width: 100%; height: 20px;"></progress>
<div style="text-align: right;">
<span id="elapsedTime">0:00</span> / <span id="totalTime">0:00</span>
</div>
</div>
</div>
<div style="margin-top: 20px;">
<label for="volumeSlider"><strong>🔊 Volume:</strong> <span id="volumeValue">1</span></label><br>
<input type="range" min="0" max="1" step="0.01" id="volumeSlider" oninput="setVolume(this.value)">
<button onclick="play()">Play/Pause</button>
<button onclick="stop()">Stop</button>
<button onclick="skip()">Skip</button>
</div>
<h3 style="margin-top: 30px;">📃 Queue</h3>
<input type="text" id="trackUrl" placeholder="Track URL">
<button onclick="addToQueue()">Add to Queue</button>
<table id="queueTable" style="width: 100%; border-collapse: collapse; font-size: 0.95em;">
<thead>
<tr style="background-color: #f0f0f0;">
<th style="text-align: left; padding: 8px;">#</th>
<th style="text-align: left; padding: 8px;">Artist</th>
<th style="text-align: left; padding: 8px;">Title</th>
<th style="text-align: right; padding: 8px;">Duration</th>
</tr>
</thead>
<tbody id="queueBody">
<!-- Filled by JS -->
</tbody>
</table>
</div>
<script>
function formatTime(seconds) {
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60).toString().padStart(2, '0');
return `${m}:${s}`;
}
function updateProgress(position, duration) {
const progressBar = document.getElementById("progressBar");
const elapsedTime = document.getElementById("elapsedTime");
const totalTime = document.getElementById("totalTime");
progressBar.max = duration;
progressBar.value = position;
elapsedTime.textContent = formatTime(position);
totalTime.textContent = formatTime(duration);
}
const api = (endpoint, options = {}) =>
fetch(endpoint, options).then(res => res.json()).catch(console.error);
const setVolume = async (val) => {
await api(`/player/volume?volume=${val}`, { method: "PUT" });
document.getElementById("volumeValue").textContent = val;
};
const addToQueue = async () => {
const url = document.getElementById("trackUrl").value;
await api(`/queue?url=${encodeURIComponent(url)}`, { method: "POST" });
updateQueue();
};
const play = async () => { await api("/player/play", { method: "POST" });};
const stop = async () => { await api("/player/stop", { method: "POST" });};
const skip = async () => { await api("/player/skip", { method: "POST" });};
// WebSocket connections
let playerSocket, queueSocket;
function connectWebSockets() {
const proto = location.protocol === "https:" ? "wss" : "ws";
const base = `${proto}://${location.host}`;
playerSocket = new WebSocket(`${base}/player`);
queueSocket = new WebSocket(`${base}/queue`);
playerSocket.onopen = () => playerSocket.send("ping");
queueSocket.onopen = () => queueSocket.send("ping");
playerSocket.onmessage = (event) => {
const state = JSON.parse(event.data);
const { playback_state, track, position, volume } = state;
document.getElementById("trackArtist").textContent = track?.artist || "-";
document.getElementById("trackTitle").textContent = track?.title || "-";
document.getElementById("playbackState").textContent = playback_state;
document.getElementById("volumeSlider").value = volume;
document.getElementById("volumeValue").textContent = volume;
if (track) {
updateProgress(position, track.duration);
}
};
queueSocket.onmessage = (event) => {
const queue = JSON.parse(event.data);
const queueBody = document.getElementById("queueBody");
queueBody.innerHTML = "";
(queue.items || queue).forEach((track, index) => {
const row = document.createElement("tr");
row.innerHTML = `
<td style="padding: 8px;">${index + 1}</td>
<td style="padding: 8px;">${track.artist}</td>
<td style="padding: 8px;">${track.title}</td>
<td style="padding: 8px; text-align: right;">${formatTime(track.duration)}</td>
`;
queueBody.appendChild(row);
});
};
playerSocket.onerror = queueSocket.onerror = console.error;
playerSocket.onclose = () => setTimeout(connectWebSockets, 1000);
queueSocket.onclose = () => setTimeout(connectWebSockets, 1000);
}
connectWebSockets();
</script>
</body>
</html>