let me = null; let instruments = []; let songs = []; const expanded = new Set(); const editing = new Set(); async function loadInstruments() { instruments = await api.get('/api/instruments'); } async function loadSongs() { songs = await api.get('/api/songs'); renderSongs(); } function instrumentOptions() { return instruments.map((i) => ``).join(''); } function songThumbTemplate(song) { const thumb = song.youtube_url ? youtubeThumbnailUrl(song.youtube_url) : null; if (thumb) { return `
`; } return `${escapeHtml(song.notes)}
` : ''} ${songLinksTemplate(song)}Aucun lien pour le moment.
'; return; } container.innerHTML = detail.tutorials.map(tutorialCardTemplate).join(''); container.querySelectorAll('.remove-tutorial').forEach((btn) => { btn.addEventListener('click', () => onRemoveTutorial(parseInt(btn.dataset.songId, 10), parseInt(btn.dataset.id, 10))); }); } catch (err) { showError(err.message); } } async function onAddTutorial(e) { e.preventDefault(); const form = e.target; const songId = parseInt(form.dataset.songId, 10); const instrumentId = parseInt(form.instrumentId.value, 10); const url = form.url.value.trim(); const label = form.label.value.trim(); try { await api.post(`/api/songs/${songId}/tutorials`, { instrumentId, url, label }); form.reset(); const song = songs.find((s) => s.id === songId); if (song) song.tutorial_count += 1; await loadTutorials(songId); renderSongs(); } catch (err) { showError(err.message); } } async function onRemoveTutorial(songId, tutorialId) { try { await api.del(`/api/songs/${songId}/tutorials/${tutorialId}`); const song = songs.find((s) => s.id === songId); if (song) song.tutorial_count -= 1; await loadTutorials(songId); renderSongs(); } catch (err) { showError(err.message); } } async function onAddSong(e) { e.preventDefault(); const form = e.target; const title = form.title.value.trim(); const artist = form.artist.value.trim(); const notes = form.notes.value.trim(); const youtubeUrl = form.youtubeUrl.value.trim(); const spotifyUrl = form.spotifyUrl.value.trim(); try { await api.post('/api/songs', { title, artist, notes, youtubeUrl, spotifyUrl }); form.reset(); document.getElementById('song-links-status').textContent = ''; closeAutocompleteDropdown(); setAddSongPanelOpen(false); await loadSongs(); } catch (err) { showError(err.message); } } function setAddSongPanelOpen(open) { document.getElementById('add-song-panel').style.display = open ? 'block' : 'none'; document.getElementById('toggle-add-song').textContent = open ? 'Annuler' : '+ Ajouter un morceau'; } async function onSaveSong(e) { e.preventDefault(); const form = e.target; const id = parseInt(form.dataset.id, 10); const title = form.title.value.trim(); const artist = form.artist.value.trim(); const notes = form.notes.value.trim(); const youtubeUrl = form.youtubeUrl.value.trim(); const spotifyUrl = form.spotifyUrl.value.trim(); try { await api.patch(`/api/songs/${id}`, { title, artist, notes, youtubeUrl, spotifyUrl }); editing.delete(id); await loadSongs(); } catch (err) { showError(err.message); } } async function onDeleteSong(id) { try { await api.del(`/api/songs/${id}`); editing.delete(id); await loadSongs(); } catch (err) { showError(err.message); } } function showError(message) { document.getElementById('error').innerHTML = ``; } let autocompleteTimer = null; let autocompleteCandidates = []; let autocompleteHighlight = -1; function candidateItemTemplate(c, index) { const img = c.artworkUrl ? `