diff --git a/js/admin.js b/js/admin.js index 02c0ae9..71de507 100644 --- a/js/admin.js +++ b/js/admin.js @@ -332,31 +332,18 @@ function openEditModal(id) { function closeAdminModal() { document.getElementById('admin-modal').classList.remove('open'); } +/ Nettoyage Config Modal (Suppression Fanart) async function openConfigModal() { document.getElementById('config-modal').classList.add('open'); try { - const res = await fetch(`${API_URL}?action=get_config_keys`, { - headers: { 'Authorization': localStorage.getItem('token') } - }); + const res = await fetch(`${API_URL}?action=get_config_keys`, { headers: { 'Authorization': localStorage.getItem('token') } }); const data = await res.json(); - const tmdbInput = document.getElementById('tmdb-key-input'); - if (tmdbInput) { - tmdbInput.value = ''; - tmdbInput.placeholder = data.tmdb_api_key ? '✅ Clé TMDB configurée (laisser vide pour garder)' : 'Entrez votre clé TMDB'; - } + const tmdbIn = document.getElementById('tmdb-key-input'); + if (tmdbIn) tmdbIn.placeholder = data.tmdb_api_key ? '✅ Clé TMDB configurée' : 'Entrez votre clé TMDB'; - const fanartInput = document.getElementById('fanart-key-input'); - if (fanartInput) { - fanartInput.value = ''; - fanartInput.placeholder = data.fanart_api_key ? '✅ Clé Fanart.tv configurée (laisser vide pour garder)' : 'Entrez votre clé Fanart.tv'; - } - - const upcmdbInput = document.getElementById('upcmdb-key-input'); - if (upcmdbInput) { - upcmdbInput.value = ''; - upcmdbInput.placeholder = data.upcmdb_api_key ? '✅ Clé UPCMDB configurée (laisser vide pour garder)' : 'Gratuite sur upcmdb.com — fallback EAN'; - } + const upcIn = document.getElementById('upcmdb-key-input'); + if (upcIn) upcIn.placeholder = data.upcmdb_api_key ? '✅ Clé UPCMDB configurée' : 'Clé gratuite sur upcmdb.com'; } catch(e) { console.error(e); } } @@ -425,89 +412,65 @@ async function handleCritiqueUpload(input) { loadDashboardData(); } -// Extraction EAN uniquement depuis le CSV vidéothèque +// Extraction stricte de l'EAN uniquement function normalizeVideothequeRow(row) { let ean = row['ean_isbn13'] || row['EAN'] || row['ean'] || row['Barcode'] || row['UPC'] || row['upc_isbn10'] || ''; - if (ean !== '') ean = String(ean).replace(/[^0-9]/g, ''); + if (ean) ean = String(ean).replace(/[^0-9]/g, ''); return { ean }; } function handleVideothequeUpload(input) { const file = input.files[0]; if (!file) return; - const reader = new FileReader(); reader.onload = async (e) => { const text = e.target.result; - const parsedData = parseCSV(text); + const parsed = parseCSV(text); + if (!parsed.length) { alert("❌ CSV vide."); return; } - if (parsedData.length === 0) { - alert("❌ Fichier CSV vide ou invalide."); - return; - } - - const items = parsedData.map(row => { + const items = parsed.map(row => { const { ean } = normalizeVideothequeRow(row); - if (!ean || ean.length < 8) return null; - return { ean }; - }).filter(item => item !== null); - - if (items.length === 0) { - alert("❌ Aucun code EAN valide trouvé dans le fichier CSV."); - return; - } - + return (ean && ean.length >= 8) ? { ean } : null; + }).filter(Boolean); + + if (!items.length) { alert("❌ Aucun EAN valide trouvé."); return; } + showImportModal(items.length, 'videotheque'); - let processed = 0; - - let totalImported = 0; - let totalSkipped = 0; - + let processed = 0, totalImp = 0, totalSkp = 0; + try { - // Lots de 2 : UPCitemdb impose ~2 s entre chaque requête EAN + // Lots de 2 pour respecter les limites UPCitemdb (2s/requête) for (let i = 0; i < items.length; i += 2) { const batch = items.slice(i, i + 2); - - const response = await fetch(`${API_URL}?action=import_batch`, { + const res = await fetch(`${API_URL}?action=import_batch`, { method: 'POST', - headers: { - 'Authorization': localStorage.getItem('token'), - 'Content-Type': 'application/json' - }, + headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'videotheque', items: batch }) }); - if (!response.ok) { - throw new Error(`Erreur serveur ${response.status}`); - } - - const data = await response.json(); - - if (!data.success) { - throw new Error(data.error || "Erreur inconnue"); - } - - totalImported += data.imported || 0; - totalSkipped += data.skipped || 0; + if (!res.ok) throw new Error(`Erreur HTTP ${res.status}`); + const data = await res.json(); + if (!data.success) throw new Error(data.error || "Échec API"); + totalImp += data.imported || 0; + totalSkp += data.skipped || 0; processed += batch.length; updateImportModal(processed, items.length); + await new Promise(r => setTimeout(r, 1500)); // Délai de sécurité } - + input.value = ''; closeImportModal(); - const skipMsg = totalSkipped > 0 ? ` (${totalSkipped} EAN ignoré(s) — introuvable dans UPCitemdb/UPCMDB)` : ''; - showSuccessModal(`${totalImported} édition(s) importée(s) (UPCitemdb + UPCMDB + TMDB).${skipMsg}`); + const msg = totalSkp > 0 ? ` (${totalSkp} EAN ignoré(s) — introuvables UPC/TMDB)` : ''; + showSuccessModal(`${totalImp} édition(s) importée(s) (UPC + TMDB).${msg}`); loadDashboardData(); - } catch (err) { - console.error("Erreur d'importation : ", err); + console.error(err); closeImportModal(); - alert("❌ Échec de l'import : " + err.message); + alert("❌ Échec import : " + err.message); input.value = ''; } }; - reader.readAsText(file); } @@ -528,49 +491,15 @@ function updateImportModal(current, total) { function closeImportModal() { document.getElementById('import-progress-modal').classList.remove('open'); } async function saveConfigKeys() { - const tmdbKeyValue = document.getElementById('tmdb-key-input').value.trim(); - const fanartKeyValue = document.getElementById('fanart-key-input').value.trim(); - const upcmdbKeyValue = document.getElementById('upcmdb-key-input').value.trim(); + const tmdb = document.getElementById('tmdb-key-input').value.trim(); + const upcmdb = document.getElementById('upcmdb-key-input').value.trim(); try { - if (tmdbKeyValue) { - await fetch(`${API_URL}?action=save_config`, { - method: 'POST', - headers: { - 'Authorization': localStorage.getItem('token'), - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ key_name: 'tmdb_api_key', key_value: tmdbKeyValue }) - }); - } - - if (upcmdbKeyValue) { - await fetch(`${API_URL}?action=save_config`, { - method: 'POST', - headers: { - 'Authorization': localStorage.getItem('token'), - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ key_name: 'upcmdb_api_key', key_value: upcmdbKeyValue }) - }); - } - - if (fanartKeyValue) { - await fetch(`${API_URL}?action=save_config`, { - method: 'POST', - headers: { - 'Authorization': localStorage.getItem('token'), - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ key_name: 'fanart_api_key', key_value: fanartKeyValue }) - }); - } - + if (tmdb) await fetch(`${API_URL}?action=save_config`, { method:'POST', headers:{'Authorization':localStorage.getItem('token'),'Content-Type':'application/json'}, body:JSON.stringify({key_name:'tmdb_api_key',key_value:tmdb}) }); + if (upcmdb) await fetch(`${API_URL}?action=save_config`, { method:'POST', headers:{'Authorization':localStorage.getItem('token'),'Content-Type':'application/json'}, body:JSON.stringify({key_name:'upcmdb_api_key',key_value:upcmdb}) }); alert('✅ Clés sauvegardées !'); closeConfigModal(); - } catch (err) { - alert('Erreur serveur.'); - } + } catch(e) { alert('Erreur serveur.'); } } async function saveNewPassword() { @@ -589,12 +518,12 @@ async function saveNewPassword() { function updateImportInterface() { const title = document.getElementById('import-title'); const desc = document.getElementById('import-desc'); - if (currentAdminTab === 'critique') { + if (currentAdminTab === 'videotheque') { + title.innerHTML = 'Importer ma Vidéothèque'; + desc.textContent = 'Import CSV (EAN seul) : UPCitemdb/UPCMDB pour le physique, TMDB pour l\'affiche, le casting et le synopsis.'; + } else { title.innerHTML = 'Importer Critiques & Notes'; desc.textContent = 'Sélectionnez vos fichiers "ratings.csv" et "reviews.csv" (Letterboxd).'; - } else { - title.innerHTML = 'Importer ma Vidéothèque'; - desc.textContent = 'Import CSV (EAN seul) : UPCitemdb puis UPCMDB en secours, TMDB pour affiche/synopsis/réalisateur/acteurs.'; } }