287 lines
9.6 KiB
JavaScript
287 lines
9.6 KiB
JavaScript
// DOM Elements
|
|
const queueTab = document.getElementById('queueTab');
|
|
const usersTab = document.getElementById('usersTab');
|
|
const cacheTab = document.getElementById('cacheTab');
|
|
const logoutButton = document.getElementById('logoutButton');
|
|
|
|
const queueSection = document.getElementById('queueSection');
|
|
const usersSection = document.getElementById('usersSection');
|
|
const cacheSection = document.getElementById('cacheSection');
|
|
|
|
const nowPlaying = document.getElementById('nowPlaying');
|
|
const queueList = document.getElementById('queueList');
|
|
const clearQueueButton = document.getElementById('clearQueueButton');
|
|
|
|
const usersTable = document.getElementById('usersTable');
|
|
const addUserButton = document.getElementById('addUserButton');
|
|
const addUserModal = document.getElementById('addUserModal');
|
|
const addUserForm = document.getElementById('addUserForm');
|
|
const cancelAddUser = document.getElementById('cancelAddUser');
|
|
|
|
const cacheSongCount = document.getElementById('cacheSongCount');
|
|
const cacheSize = document.getElementById('cacheSize');
|
|
const cacheMaxSize = document.getElementById('cacheMaxSize');
|
|
const cacheUsage = document.getElementById('cacheUsage');
|
|
const clearCacheButton = document.getElementById('clearCacheButton');
|
|
|
|
// Tab switching
|
|
function switchTab(tab, section) {
|
|
// Remove active class from all tabs and sections
|
|
[queueTab, usersTab, cacheTab].forEach(t => t.classList.remove('active'));
|
|
[queueSection, usersSection, cacheSection].forEach(s => s.classList.remove('active'));
|
|
|
|
// Add active class to selected tab and section
|
|
tab.classList.add('active');
|
|
section.classList.add('active');
|
|
}
|
|
|
|
queueTab.addEventListener('click', () => switchTab(queueTab, queueSection));
|
|
usersTab.addEventListener('click', () => switchTab(usersTab, usersSection));
|
|
cacheTab.addEventListener('click', () => switchTab(cacheTab, cacheSection));
|
|
|
|
// Logout
|
|
logoutButton.addEventListener('click', async () => {
|
|
try {
|
|
await fetch('/api/logout', {
|
|
method: 'POST',
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
window.location.href = '/login';
|
|
} catch (error) {
|
|
console.error('Logout failed:', error);
|
|
}
|
|
});
|
|
|
|
// Queue management
|
|
function formatDuration(seconds) {
|
|
const minutes = Math.floor(seconds / 60);
|
|
const secs = seconds % 60;
|
|
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
|
}
|
|
|
|
async function loadQueue() {
|
|
try {
|
|
const response = await fetch('/api/queue', {
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
const responseData = await response.json();
|
|
|
|
// Update now playing
|
|
if (responseData.current_song) {
|
|
nowPlaying.innerHTML = `
|
|
<div class="song-info">
|
|
<h4>${responseData.current_song.title}</h4>
|
|
<p>${formatDuration(responseData.current_song.duration)}</p>
|
|
</div>
|
|
<div class="song-status">
|
|
<span class="badge">${responseData.state}</span>
|
|
</div>
|
|
`;
|
|
} else {
|
|
nowPlaying.innerHTML = '<p>Nothing playing</p>';
|
|
}
|
|
|
|
// Update queue
|
|
if (responseData.queue && responseData.queue.length > 0) {
|
|
queueList.innerHTML = responseData.queue.map((songItem, idx) => {
|
|
if (songItem.is_current) {
|
|
return `
|
|
<li class="now-playing">
|
|
<div class="song-info">
|
|
<strong>${songItem.title}</strong>
|
|
<span>${formatDuration(songItem.duration)}</span>
|
|
</div>
|
|
<div class="song-status">
|
|
<span class="badge">Now Playing</span>
|
|
</div>
|
|
</li>
|
|
`;
|
|
} else {
|
|
return `
|
|
<li>
|
|
<div class="song-info">
|
|
<strong>${idx + 1}. ${songItem.title}</strong>
|
|
<span>${formatDuration(songItem.duration)}</span>
|
|
</div>
|
|
</li>
|
|
`;
|
|
}
|
|
}).join('');
|
|
} else {
|
|
queueList.innerHTML = '<li class="empty-message">Queue is empty</li>';
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load queue:', error);
|
|
queueList.innerHTML = '<li class="empty-message">Failed to load queue</li>';
|
|
}
|
|
}
|
|
|
|
clearQueueButton.addEventListener('click', async () => {
|
|
if (!confirm('Are you sure you want to clear the queue?')) return;
|
|
|
|
try {
|
|
await fetch('/api/queue', {
|
|
method: 'DELETE',
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
loadQueue();
|
|
} catch (error) {
|
|
console.error('Failed to clear queue:', error);
|
|
alert('Failed to clear queue');
|
|
}
|
|
});
|
|
|
|
// User management
|
|
async function loadUsers() {
|
|
try {
|
|
const response = await fetch('/api/users', {
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
const responseData = await response.json();
|
|
|
|
if (responseData.users && responseData.users.length > 0) {
|
|
const tbody = usersTable.querySelector('tbody');
|
|
tbody.innerHTML = responseData.users.map(userItem => `
|
|
<tr>
|
|
<td>${userItem.username}</td>
|
|
<td>
|
|
<select class="permission-select" data-username="${userItem.username}">
|
|
<option value="0" ${userItem.permission_level == 0 ? 'selected' : ''}>None</option>
|
|
<option value="1" ${userItem.permission_level == 1 ? 'selected' : ''}>View Only</option>
|
|
<option value="2" ${userItem.permission_level == 2 ? 'selected' : ''}>Read/Write</option>
|
|
<option value="3" ${userItem.permission_level == 3 ? 'selected' : ''}>Admin</option>
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<button class="save-permission" data-username="${userItem.username}">Save</button>
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
|
|
// Add event listeners to save buttons
|
|
document.querySelectorAll('.save-permission').forEach(button => {
|
|
button.addEventListener('click', async () => {
|
|
const username = button.dataset.username;
|
|
const select = document.querySelector(`.permission-select[data-username="${username}"]`);
|
|
const permissionLevel = parseInt(select.value);
|
|
|
|
try {
|
|
await fetch(`/api/users/${username}/permissions`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify({ permission_level: permissionLevel }),
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
alert(`Permission updated for ${username}`);
|
|
} catch (error) {
|
|
console.error('Failed to update permission:', error);
|
|
alert('Failed to update permission');
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
usersTable.querySelector('tbody').innerHTML = '<tr class="empty-message"><td colspan="3">No users found</td></tr>';
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load users:', error);
|
|
usersTable.querySelector('tbody').innerHTML = '<tr class="empty-message"><td colspan="3">Failed to load users</td></tr>';
|
|
}
|
|
}
|
|
|
|
// Add user modal
|
|
addUserButton.addEventListener('click', () => {
|
|
addUserModal.classList.add('active');
|
|
});
|
|
|
|
cancelAddUser.addEventListener('click', () => {
|
|
addUserModal.classList.remove('active');
|
|
addUserForm.reset();
|
|
});
|
|
|
|
addUserForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const username = document.getElementById('newUsername').value;
|
|
const permissionLevel = parseInt(document.getElementById('newPermissionLevel').value);
|
|
|
|
try {
|
|
await fetch('/api/users', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ username, permission_level: permissionLevel }),
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
|
|
addUserModal.classList.remove('active');
|
|
addUserForm.reset();
|
|
loadUsers();
|
|
} catch (error) {
|
|
console.error('Failed to add user:', error);
|
|
alert('Failed to add user');
|
|
}
|
|
});
|
|
|
|
// Cache management
|
|
async function loadCacheStats() {
|
|
try {
|
|
const response = await fetch('/api/cache', {
|
|
credentials: 'include', // Important for cookies to work
|
|
headers: {
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
const stats = await response.json();
|
|
|
|
cacheSongCount.textContent = stats.songCount;
|
|
cacheSize.textContent = `${stats.totalSizeMb} MB`;
|
|
cacheMaxSize.textContent = `${stats.maxSizeMb} MB`;
|
|
|
|
const usagePercent = stats.maxSizeMb > 0
|
|
? (stats.totalSizeMb / stats.maxSizeMb) * 100
|
|
: 0;
|
|
|
|
cacheUsage.style.width = `${Math.min(usagePercent, 100)}%`;
|
|
|
|
// Change color based on usage
|
|
if (usagePercent > 90) {
|
|
cacheUsage.style.backgroundColor = 'var(--danger-color)';
|
|
} else if (usagePercent > 70) {
|
|
cacheUsage.style.backgroundColor = 'var(--accent-color)';
|
|
} else {
|
|
cacheUsage.style.backgroundColor = 'var(--primary-color)';
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load cache stats:', error);
|
|
}
|
|
}
|
|
|
|
clearCacheButton.addEventListener('click', async () => {
|
|
if (!confirm('Are you sure you want to clear the cache? This will delete all downloaded audio files.')) return;
|
|
|
|
try {
|
|
await fetch('/api/cache', {
|
|
method: 'DELETE',
|
|
credentials: 'include', // Important for cookies to work
|
|
});
|
|
loadCacheStats();
|
|
} catch (error) {
|
|
console.error('Failed to clear cache:', error);
|
|
alert('Failed to clear cache');
|
|
}
|
|
});
|
|
|
|
// Initial load
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
loadQueue();
|
|
loadUsers();
|
|
loadCacheStats();
|
|
|
|
// Refresh data periodically
|
|
setInterval(loadQueue, 10000); // Every 10 seconds
|
|
setInterval(loadCacheStats, 30000); // Every 30 seconds
|
|
}); |