329 lines
11 KiB
HTML
329 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Manage Queue</title>
|
|
<style>
|
|
body {
|
|
display: flex;
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 100vh;
|
|
background-color: #0f0f0f;
|
|
}
|
|
.column {
|
|
flex: 1;
|
|
padding: 10px;
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
#musicQueue, #allMusic {
|
|
height: 80vh;
|
|
overflow-y: auto;
|
|
}
|
|
.queueItem {
|
|
padding: 5px;
|
|
margin: 5px;
|
|
background-color: #f0f0f0;
|
|
border-radius: 5px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.queueItem button {
|
|
margin-left: 10px;
|
|
}
|
|
input[type="text"] {
|
|
width: calc(100% - 22px); /* Full width minus padding and border */
|
|
padding: 10px;
|
|
box-sizing: border-box;
|
|
}
|
|
.loader {
|
|
border: 5px solid #f3f3f3; /* Light grey */
|
|
border-top: 5px solid #3498db; /* Blue */
|
|
border-radius: 50%;
|
|
width: 20px;
|
|
height: 20px;
|
|
animation: spin 2s linear infinite;
|
|
}
|
|
.musicItem {
|
|
padding: 5px;
|
|
margin: 5px;
|
|
background-color: #f0f0f0;
|
|
border-radius: 5px;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.musicItem button {
|
|
margin-right: 10px; /* Adds space between the button and the title */
|
|
}
|
|
|
|
.musicItem span {
|
|
flex-grow: 1; /* Allows the title span to take up the remaining space */
|
|
text-align: left; /* Ensures text is left-aligned */
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
/* Hide loader by default */
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
h2 {
|
|
color: #999;
|
|
font-size: 3vh;
|
|
}
|
|
|
|
.progress-container {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
position: relative;
|
|
height: 5vh;
|
|
width: 30vw;
|
|
}
|
|
|
|
.progress-bar {
|
|
width: 100%;
|
|
background-color: #eee;
|
|
height: 2vh;
|
|
border-radius: 1vh;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress {
|
|
height: 2vh;
|
|
background-color: #007BFF;
|
|
width: 0%;
|
|
border-radius: 1vh;
|
|
transition: width 0.5s ease;
|
|
}
|
|
#album-art {
|
|
/*width: 200px; /* Adjust width as needed */
|
|
height: 20vh; /* Maintain aspect ratio */
|
|
width: auto;
|
|
border-radius: 1vh; /* Rounded corners */
|
|
margin-bottom: 1vh; /* Space between the image and text */
|
|
}
|
|
span{
|
|
color:#999;
|
|
font-size: 1vw;
|
|
margin: 1vw;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="column">
|
|
<h2>Download New Song</h2>
|
|
<form id="downloadForm">
|
|
<input type="text" id="youtubeUrl" name="youtube_url" placeholder="Enter YouTube URL here" required>
|
|
<button type="button" id="downloadButton" onclick="submitDownload()">Download</button>
|
|
<div id="loader" class="loader hidden"></div>
|
|
</form>
|
|
<div>
|
|
<img id="album-art" src="mao.jpg" alt="Album Art">
|
|
<div class="progress-container">
|
|
<span id="current-time">0:00</span>
|
|
<div class="progress-bar">
|
|
<div class="progress" id="progress" style="width: 0%;"></div>
|
|
</div>
|
|
<span id="duration">4:00</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column" id="queueControls">
|
|
<h2>Music Queue</h2>
|
|
<!--<button onclick="skipTrack()">Skip</button>
|
|
<button onclick="toggleLoop()">Loop</button>
|
|
<button onclick="toggleShuffle()">Shuffle</button>
|
|
<button onclick="clearQueue()">Clear</button>-->
|
|
<div id="musicQueue">
|
|
<!-- Dynamically filled with JavaScript -->
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column">
|
|
<h2>All Music</h2>
|
|
<input type="text" id="searchMusic" placeholder="Search music..." onkeyup="filterMusic()">
|
|
<div id="allMusic">
|
|
<!-- Dynamically filled with JavaScript -->
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function skipTrack() {
|
|
// Implementation of skipping the current track
|
|
}
|
|
|
|
function toggleLoop() {
|
|
// Toggle loop mode
|
|
}
|
|
|
|
function toggleShuffle() {
|
|
// Toggle shuffle mode
|
|
}
|
|
|
|
function clearQueue() {
|
|
// Clear the entire queue
|
|
}
|
|
|
|
function playSong(songId, songTitle) {
|
|
fetch('/play', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ songId: songId, songTitle: songTitle })
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Failed to add song to queue');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
console.log('Song added to queue:', data);
|
|
})
|
|
.catch(error => console.error('Error adding song to queue:', error));
|
|
loadQueue(); // Reloads the queue after a song is added
|
|
}
|
|
|
|
function loadMusic() {
|
|
const musicList = document.getElementById('allMusic');
|
|
//musicList.innerHTML = ''; // Clear the list before populating it again
|
|
fetch('/music')
|
|
.then(response => response.json())
|
|
.then(musicFiles => {
|
|
musicList.innerHTML = '';
|
|
musicFiles.forEach(song => {
|
|
const div = document.createElement('div');
|
|
div.className = 'musicItem';
|
|
|
|
// Create a button for adding to the queue
|
|
const addButton = document.createElement('button');
|
|
addButton.textContent = 'Add to Queue';
|
|
addButton.onclick = function() { playSong(song.id,song.title); };
|
|
|
|
// Create a span to hold the song title
|
|
const titleSpan = document.createElement('span');
|
|
titleSpan.textContent = song.title;
|
|
|
|
|
|
// Append the button and title to the div
|
|
div.appendChild(addButton);
|
|
div.appendChild(titleSpan);
|
|
musicList.appendChild(div);
|
|
});
|
|
})
|
|
.catch(error => console.error('Failed to load music:', error));
|
|
}
|
|
|
|
function filterMusic() {
|
|
const search = document.getElementById('searchMusic').value.toLowerCase();
|
|
const musicItems = document.getElementById('allMusic').getElementsByClassName('musicItem');
|
|
for (let i = 0; i < musicItems.length; i++) {
|
|
let item = musicItems[i];
|
|
let text = item.textContent || item.innerText;
|
|
if (text.toLowerCase().indexOf(search) > -1) {
|
|
item.style.display = "";
|
|
} else {
|
|
item.style.display = "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
function loadQueue() {
|
|
const queueElement = document.getElementById('musicQueue');
|
|
//queueElement.innerHTML = ''; // Clear the queue before loading new items
|
|
|
|
fetch('/queue')
|
|
.then(response => response.json())
|
|
.then(queue => {
|
|
queueElement.innerHTML = '';
|
|
queue.forEach(song => {
|
|
const div = document.createElement('div');
|
|
div.className = 'queueItem';
|
|
|
|
// Create a button for removing from the queue
|
|
const removeButton = document.createElement('button');
|
|
removeButton.textContent = 'Remove';
|
|
removeButton.onclick = function() { removeFromQueue(song.id); };
|
|
|
|
// Create a span to hold the song title
|
|
const titleSpan = document.createElement('span');
|
|
titleSpan.textContent = song.title;
|
|
|
|
// Append the button and title to the div
|
|
div.appendChild(removeButton);
|
|
div.appendChild(titleSpan);
|
|
queueElement.appendChild(div);
|
|
});
|
|
})
|
|
.catch(error => console.error('Failed to load queue:', error));
|
|
}
|
|
|
|
function removeFromQueue(songId) {
|
|
fetch('/remove_from_queue', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ songId: songId })
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Failed to remove song from queue');
|
|
}
|
|
loadQueue(); // Reloads the queue after removing a song
|
|
})
|
|
.catch(error => console.error('Error removing song from queue:', error));
|
|
}
|
|
|
|
function submitDownload() {
|
|
const formData = new FormData(document.getElementById('downloadForm'));
|
|
const loader = document.getElementById('loader');
|
|
const youtubeUrl = document.getElementById('youtubeUrl');
|
|
const downloadButton = document.getElementById('downloadButton');
|
|
|
|
youtubeUrl.disabled = true;
|
|
downloadButton.disabled = true;
|
|
loader.classList.remove('hidden'); // Show the loader
|
|
|
|
fetch('/download', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(response => {
|
|
youtubeUrl.disabled = false;
|
|
downloadButton.disabled = false;
|
|
loader.classList.add('hidden'); // Hide the loader
|
|
youtubeUrl.value = ''; // Clear the input field
|
|
if (response.ok) {
|
|
loadMusic(); // Reloads the music list after successful download
|
|
} else {
|
|
throw new Error('Failed to download song');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
youtubeUrl.disabled = false;
|
|
downloadButton.disabled = false;
|
|
loader.classList.add('hidden'); // Ensure loader is hidden on error
|
|
});
|
|
}
|
|
|
|
setInterval(loadQueue, 1000);
|
|
//setInterval(loadMusic, 5000);
|
|
document.addEventListener('DOMContentLoaded', loadMusic); // Ensure music loads when the page is ready
|
|
|
|
// Functionality to dynamically populate queues and handle music items could be added here.
|
|
</script>
|
|
</body>
|
|
</html>
|