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 `
${escapeHtml(song.title)}
`; } return `
`; } function songLinksTemplate(song) { const links = []; if (song.youtube_url) { links.push(`► YouTube`); } if (song.spotify_url) { links.push(`♫ Spotify`); } return links.length ? `` : ''; } function songCardTemplate(song) { if (editing.has(song.id)) return editSongCardTemplate(song); const isOpen = expanded.has(song.id); return `
${songThumbTemplate(song)}
${escapeHtml(song.title)}
${escapeHtml(song.artist)}
${song.notes ? `

${escapeHtml(song.notes)}

` : ''} ${songLinksTemplate(song)}

Chargement…

`; } function editSongCardTemplate(song) { return `
`; } function tutorialCardTemplate(t) { const thumb = youtubeThumbnailUrl(t.url); if (thumb) { return `
${escapeHtml(t.label || t.instrument_name)}
${escapeHtml(t.instrument_name)}
${escapeHtml(t.label || 'Tuto')}
`; } return `
🔗
${escapeHtml(t.instrument_name)}
`; } function renderSongs() { const container = document.getElementById('songs-list'); renderList(container, songs, songCardTemplate, 'Aucun morceau au répertoire pour le moment.'); document.querySelectorAll('.toggle-tutorials').forEach((btn) => { btn.addEventListener('click', () => onToggleTutorials(parseInt(btn.dataset.id, 10))); }); document.querySelectorAll('.add-tutorial-form').forEach((form) => { form.addEventListener('submit', onAddTutorial); }); document.querySelectorAll('.edit-song').forEach((btn) => { btn.addEventListener('click', () => { editing.add(parseInt(btn.dataset.id, 10)); renderSongs(); }); }); document.querySelectorAll('.cancel-edit').forEach((btn) => { btn.addEventListener('click', () => { editing.delete(parseInt(btn.dataset.id, 10)); renderSongs(); }); }); document.querySelectorAll('.edit-song-form').forEach((form) => { form.addEventListener('submit', onSaveSong); }); document.querySelectorAll('.delete-song').forEach((btn) => { btn.addEventListener('click', () => onDeleteSong(parseInt(btn.dataset.id, 10))); }); } async function onToggleTutorials(songId) { if (expanded.has(songId)) { expanded.delete(songId); } else { expanded.add(songId); } renderSongs(); if (expanded.has(songId)) { await loadTutorials(songId); } } async function loadTutorials(songId) { try { const detail = await api.get(`/api/songs/${songId}`); const container = document.querySelector(`[data-tutorials-for="${songId}"]`); if (!container) return; if (!detail.tutorials.length) { container.innerHTML = '

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(); await loadSongs(); } catch (err) { showError(err.message); } } 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 = `
${escapeHtml(message)}
`; } (async function init() { me = await initNav('repertoire'); await loadInstruments(); document.getElementById('add-song-form').addEventListener('submit', onAddSong); await loadSongs(); })();