lidarr-spotify-frontend/public/app.js

169 lines
4.9 KiB
JavaScript

const queryInput = document.getElementById('query');
const searchBtn = document.getElementById('searchBtn');
const results = document.getElementById('results');
const statusEl = document.getElementById('status');
const dialog = document.getElementById('albumDialog');
const dialogTitle = document.getElementById('dialogTitle');
const dialogArtist = document.getElementById('dialogArtist');
const trackList = document.getElementById('trackList');
const sendBtn = document.getElementById('sendBtn');
const cleanupToggle = document.getElementById('cleanupToggle');
let selectedAlbum = null;
let selectedTracks = [];
const CLEANUP_KEY = 'cleanupExtras';
cleanupToggle.checked = localStorage.getItem(CLEANUP_KEY) === 'true';
cleanupToggle.addEventListener('change', () => {
localStorage.setItem(CLEANUP_KEY, String(cleanupToggle.checked));
});
function setStatus(text, isError = false) {
statusEl.textContent = text;
statusEl.style.color = isError ? 'var(--danger)' : 'var(--text)';
}
function formatDuration(ms) {
const totalSec = Math.floor(ms / 1000);
const min = Math.floor(totalSec / 60);
const sec = totalSec % 60;
return `${min}:${String(sec).padStart(2, '0')}`;
}
async function fetchJson(url, options = {}) {
const response = await fetch(url, options);
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || `HTTP ${response.status}`);
}
return data;
}
function renderAlbums(albums) {
results.innerHTML = '';
if (!albums.length) {
results.innerHTML = '<p>Keine Alben gefunden.</p>';
return;
}
for (const album of albums) {
const card = document.createElement('article');
card.className = 'album-card';
card.innerHTML = `
${album.image ? `<img class="album-cover" src="${album.image}" alt="${album.name}" />` : '<div class="album-cover"></div>'}
<div class="album-body">
<h3>${album.name}</h3>
<p>${album.artist}</p>
<p>${album.totalTracks} Tracks - ${album.releaseDate || 'unbekannt'}</p>
<button type="button">Auswaehlen</button>
</div>
`;
card.querySelector('button').addEventListener('click', () => openAlbumDialog(album.id));
results.appendChild(card);
}
}
async function openAlbumDialog(albumId) {
setStatus('Lade Albumdetails...');
try {
const album = await fetchJson(`/api/spotify/album/${albumId}`);
selectedAlbum = album;
selectedTracks = album.tracks.map((t) => t.name);
dialogTitle.textContent = album.name;
dialogArtist.textContent = `Artist: ${album.artist}`;
trackList.innerHTML = '';
for (const track of album.tracks) {
const row = document.createElement('label');
row.className = 'track-row';
row.innerHTML = `
<input type="checkbox" checked data-track-name="${track.name.replace(/"/g, '&quot;')}" />
<span>${track.trackNumber}. ${track.name}</span>
<small>(${formatDuration(track.durationMs)})</small>
`;
trackList.appendChild(row);
}
dialog.showModal();
setStatus('Album bereit. Tracks auswaehlen und senden.');
} catch (err) {
setStatus(err.message, true);
}
}
async function searchAlbums() {
const q = queryInput.value.trim();
if (!q) {
setStatus('Bitte Suchbegriff eingeben.', true);
return;
}
setStatus('Suche in Spotify...');
results.innerHTML = '';
try {
const data = await fetchJson(`/api/spotify/search?q=${encodeURIComponent(q)}`);
renderAlbums(data.albums || []);
setStatus(`${data.albums.length} Alben gefunden.`);
} catch (err) {
setStatus(err.message, true);
}
}
async function sendToLidarr(event) {
event.preventDefault();
if (!selectedAlbum) {
setStatus('Kein Album ausgewaehlt.', true);
return;
}
const checked = Array.from(trackList.querySelectorAll('input[type="checkbox"]:checked'));
const selectedTrackNames = checked.map((input) => input.dataset.trackName);
if (!selectedTrackNames.length) {
setStatus('Bitte mindestens einen Track auswaehlen.', true);
return;
}
setStatus('Sende Album an Lidarr...');
sendBtn.disabled = true;
try {
const data = await fetchJson('/api/lidarr/send-album', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
albumName: selectedAlbum.name,
artistName: selectedAlbum.artist,
selectedTrackNames,
cleanupExtras: cleanupToggle.checked
})
});
const cleanupMsg = data.cleanup?.attempted
? ` Cleanup: ${data.cleanup.deleted} Dateien geloescht.`
: '';
setStatus(`Album erfolgreich an Lidarr uebergeben (ID ${data.albumId}).${cleanupMsg}`);
dialog.close();
} catch (err) {
setStatus(`Fehler: ${err.message}`, true);
} finally {
sendBtn.disabled = false;
}
}
searchBtn.addEventListener('click', searchAlbums);
queryInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
searchAlbums();
}
});
sendBtn.addEventListener('click', sendToLidarr);