Actualiser js/admin.js
This commit is contained in:
+45
-64
@@ -1,6 +1,6 @@
|
|||||||
const API_URL = '../api.php';
|
const API_URL = '../api.php';
|
||||||
let allItems = [];
|
let allItems = [];
|
||||||
let currentAdminTab = 'critique';
|
let currentAdminTab = 'videotheque'; // Défaut sur vidéothèque
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
const itemsPerPage = 12;
|
const itemsPerPage = 12;
|
||||||
let selectedIds = new Set();
|
let selectedIds = new Set();
|
||||||
@@ -56,6 +56,8 @@ function parseCSV(text) {
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
loadDashboardData();
|
loadDashboardData();
|
||||||
initEventListeners();
|
initEventListeners();
|
||||||
|
updateImportInterface(); // Mise à jour initiale de l'interface d'import
|
||||||
|
|
||||||
const confirmBtn = document.getElementById('confirm-btn');
|
const confirmBtn = document.getElementById('confirm-btn');
|
||||||
if (confirmBtn) {
|
if (confirmBtn) {
|
||||||
confirmBtn.addEventListener('click', () => {
|
confirmBtn.addEventListener('click', () => {
|
||||||
@@ -68,6 +70,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
function initEventListeners() {
|
function initEventListeners() {
|
||||||
const filmForm = document.getElementById('film-form');
|
const filmForm = document.getElementById('film-form');
|
||||||
if (filmForm) filmForm.addEventListener('submit', saveFilmForm);
|
if (filmForm) filmForm.addEventListener('submit', saveFilmForm);
|
||||||
|
|
||||||
const csvInput = document.getElementById('csv-file');
|
const csvInput = document.getElementById('csv-file');
|
||||||
if (csvInput) {
|
if (csvInput) {
|
||||||
csvInput.addEventListener('change', (e) => {
|
csvInput.addEventListener('change', (e) => {
|
||||||
@@ -75,10 +78,13 @@ function initEventListeners() {
|
|||||||
else handleVideothequeUpload(e.target);
|
else handleVideothequeUpload(e.target);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchInput = document.getElementById('search-input');
|
const searchInput = document.getElementById('search-input');
|
||||||
if (searchInput) searchInput.addEventListener('input', () => { currentPage = 1; renderAdminTable(); });
|
if (searchInput) searchInput.addEventListener('input', () => { currentPage = 1; renderAdminTable(); });
|
||||||
|
|
||||||
const selectAll = document.getElementById('select-all-checkbox');
|
const selectAll = document.getElementById('select-all-checkbox');
|
||||||
if (selectAll) selectAll.addEventListener('change', (e) => toggleSelectAll(e.target));
|
if (selectAll) selectAll.addEventListener('change', (e) => toggleSelectAll(e.target));
|
||||||
|
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
if (e.target.classList.contains('modal-close') || e.target.closest('.modal-close')) {
|
if (e.target.classList.contains('modal-close') || e.target.closest('.modal-close')) {
|
||||||
const overlay = e.target.closest('.overlay');
|
const overlay = e.target.closest('.overlay');
|
||||||
@@ -86,6 +92,7 @@ function initEventListeners() {
|
|||||||
}
|
}
|
||||||
if (e.target.classList.contains('overlay')) e.target.classList.remove('open');
|
if (e.target.classList.contains('overlay')) e.target.classList.remove('open');
|
||||||
});
|
});
|
||||||
|
|
||||||
const physicalFilter = document.getElementById('admin-physical-checkbox');
|
const physicalFilter = document.getElementById('admin-physical-checkbox');
|
||||||
if (physicalFilter) physicalFilter.addEventListener('change', () => { currentPage = 1; renderAdminTable(); });
|
if (physicalFilter) physicalFilter.addEventListener('change', () => { currentPage = 1; renderAdminTable(); });
|
||||||
}
|
}
|
||||||
@@ -106,6 +113,7 @@ function renderAdminTable() {
|
|||||||
const tbody = document.getElementById('admin-table-body');
|
const tbody = document.getElementById('admin-table-body');
|
||||||
if (!tbody) return;
|
if (!tbody) return;
|
||||||
tbody.innerHTML = '';
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
const searchInput = document.getElementById('search-input');
|
const searchInput = document.getElementById('search-input');
|
||||||
const currentSearch = searchInput ? searchInput.value.toLowerCase() : '';
|
const currentSearch = searchInput ? searchInput.value.toLowerCase() : '';
|
||||||
const physicalFilter = document.getElementById('admin-physical-checkbox');
|
const physicalFilter = document.getElementById('admin-physical-checkbox');
|
||||||
@@ -337,26 +345,21 @@ async function openConfigModal() {
|
|||||||
try {
|
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 data = await res.json();
|
||||||
|
|
||||||
const tmdbIn = document.getElementById('tmdb-key-input');
|
const tmdbIn = document.getElementById('tmdb-key-input');
|
||||||
if (tmdbIn) tmdbIn.placeholder = data.tmdb_api_key ? '✅ Clé TMDB configurée' : 'Entrez votre clé TMDB';
|
if (tmdbIn) tmdbIn.placeholder = data.tmdb_api_key ? '✅ Clé TMDB configurée' : 'Entrez votre clé TMDB';
|
||||||
|
|
||||||
const upcIn = document.getElementById('upcmdb-key-input');
|
const upcIn = document.getElementById('upcmdb-key-input');
|
||||||
if (upcIn) upcIn.placeholder = data.upcmdb_api_key ? '✅ Clé UPCMDB configurée' : 'Clé gratuite sur upcmdb.com';
|
if (upcIn) upcIn.placeholder = data.upcmdb_api_key ? '✅ Clé UPCMDB configurée' : 'Clé gratuite sur upcmdb.com';
|
||||||
} catch(e) { console.error(e); }
|
} catch(e) { console.error(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeConfigModal() { document.getElementById('config-modal').classList.remove('open'); }
|
function closeConfigModal() { document.getElementById('config-modal').classList.remove('open'); }
|
||||||
|
|
||||||
function openPasswordModal() {
|
function openPasswordModal() {
|
||||||
document.getElementById('pwd-error').style.display = 'none';
|
document.getElementById('pwd-error').style.display = 'none';
|
||||||
document.getElementById('new-password-input').value = '';
|
document.getElementById('new-password-input').value = '';
|
||||||
document.getElementById('new-password-confirm').value = '';
|
document.getElementById('new-password-confirm').value = '';
|
||||||
document.getElementById('password-modal').classList.add('open');
|
document.getElementById('password-modal').classList.add('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
function closePasswordModal() { document.getElementById('password-modal').classList.remove('open'); }
|
function closePasswordModal() { document.getElementById('password-modal').classList.remove('open'); }
|
||||||
|
|
||||||
function logout() { localStorage.removeItem('token'); window.location.href = 'login.html'; }
|
function logout() { localStorage.removeItem('token'); window.location.href = 'login.html'; }
|
||||||
|
|
||||||
async function saveFilmForm(e) {
|
async function saveFilmForm(e) {
|
||||||
@@ -411,98 +414,76 @@ async function handleCritiqueUpload(input) {
|
|||||||
loadDashboardData();
|
loadDashboardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ CORRECTION : Extrait TOUTES les métadonnées du CSV pour ne rien perdre
|
||||||
function normalizeVideothequeRow(row) {
|
function normalizeVideothequeRow(row) {
|
||||||
// Recherche de l'EAN dans plusieurs colonnes possibles
|
|
||||||
let ean = row['ean_isbn13'] || row['EAN'] || row['ean'] || row['Barcode'] || row['UPC'] || row['upc_isbn10'] || '';
|
let ean = row['ean_isbn13'] || row['EAN'] || row['ean'] || row['Barcode'] || row['UPC'] || row['upc_isbn10'] || '';
|
||||||
ean = String(ean).replace(/[^0-9]/g, '');
|
if (ean) ean = String(ean).replace(/[^0-9]/g, '');
|
||||||
|
|
||||||
// Recherche du titre dans plusieurs colonnes
|
let title = row['title'] || row['Title'] || row['Titre'] || '';
|
||||||
let title = row['title'] || row['Title'] || row['Titre'] || row['titre'] || row['nom'] || row['Nom'] || '';
|
|
||||||
title = String(title).trim();
|
title = String(title).trim();
|
||||||
|
|
||||||
// Si on n'a ni EAN ni titre, on ignore
|
|
||||||
if (!ean && !title) return null;
|
if (!ean && !title) return null;
|
||||||
|
|
||||||
return { ean, title };
|
return {
|
||||||
|
ean: ean,
|
||||||
|
title: title,
|
||||||
|
year: row['publish_date'] ? String(row['publish_date']).substring(0, 4) : (row['Year'] || row['year'] || ''),
|
||||||
|
synopsis: row['description'] || '',
|
||||||
|
review: row['review'] || '',
|
||||||
|
rating: row['rating'] || '',
|
||||||
|
publisher: row['publisher'] || '',
|
||||||
|
length: row['length'] || '',
|
||||||
|
number_of_discs: row['number_of_discs'] || 1,
|
||||||
|
aspect_ratio: row['aspect_ratio'] || '',
|
||||||
|
actors: row['creators'] || row['ensemble'] || '' // 'creators' contient le casting dans votre CSV
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleVideothequeUpload(input) {
|
function handleVideothequeUpload(input) {
|
||||||
const file = input.files[0];
|
const file = input.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = async (e) => {
|
reader.onload = async (e) => {
|
||||||
const text = e.target.result;
|
const text = e.target.result;
|
||||||
const parsed = parseCSV(text);
|
const parsed = parseCSV(text);
|
||||||
if (!parsed.length) {
|
if (!parsed.length) { alert("❌ CSV vide."); return; }
|
||||||
alert("❌ CSV vide ou mal formaté.");
|
|
||||||
input.value = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transformer chaque ligne en objet {ean, title}
|
|
||||||
const items = parsed.map(row => normalizeVideothequeRow(row)).filter(Boolean);
|
const items = parsed.map(row => normalizeVideothequeRow(row)).filter(Boolean);
|
||||||
if (!items.length) {
|
if (!items.length) { alert("❌ Aucun titre ou EAN valide trouvé."); return; }
|
||||||
alert("❌ Aucun titre ou EAN valide trouvé dans le CSV.");
|
|
||||||
input.value = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Lignes parsées : ${parsed.length}, items valides : ${items.length}`);
|
|
||||||
|
|
||||||
// Ouvrir la modale de progression
|
|
||||||
showImportModal(items.length, 'videotheque');
|
showImportModal(items.length, 'videotheque');
|
||||||
let processed = 0;
|
let processed = 0, totalImp = 0, totalSkp = 0;
|
||||||
let totalImported = 0;
|
|
||||||
let totalSkipped = 0;
|
|
||||||
|
|
||||||
// Taille du lot : 10 films par requête
|
|
||||||
const BATCH_SIZE = 10;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// ✅ Envoi par lots de 5 pour que le throttle PHP fonctionne au sein du même script
|
||||||
|
const BATCH_SIZE = 5;
|
||||||
for (let i = 0; i < items.length; i += BATCH_SIZE) {
|
for (let i = 0; i < items.length; i += BATCH_SIZE) {
|
||||||
const batch = items.slice(i, i + BATCH_SIZE);
|
const batch = items.slice(i, i + BATCH_SIZE);
|
||||||
const response = await fetch(`${API_URL}?action=import_batch`, {
|
const res = await fetch(`${API_URL}?action=import_batch`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' },
|
||||||
'Authorization': localStorage.getItem('token'),
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ type: 'videotheque', items: batch })
|
body: JSON.stringify({ type: 'videotheque', items: batch })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!res.ok) throw new Error(`Erreur HTTP ${res.status}`);
|
||||||
throw new Error(`Erreur HTTP ${response.status} - ${response.statusText}`);
|
const data = await res.json();
|
||||||
}
|
if (!data.success) throw new Error(data.error || "Échec API ");
|
||||||
|
|
||||||
const result = await response.json();
|
totalImp += data.imported || 0;
|
||||||
if (!result.success) {
|
totalSkp += data.skipped || 0;
|
||||||
throw new Error(result.error || "Erreur inconnue lors de l'import.");
|
|
||||||
}
|
|
||||||
|
|
||||||
totalImported += result.imported || 0;
|
|
||||||
totalSkipped += result.skipped || 0;
|
|
||||||
processed += batch.length;
|
processed += batch.length;
|
||||||
|
|
||||||
// Mise à jour de la barre de progression
|
|
||||||
updateImportModal(processed, items.length);
|
updateImportModal(processed, items.length);
|
||||||
|
await new Promise(r => setTimeout(r, 500)); // Petit délai réseau
|
||||||
// Petit délai pour éviter de saturer le serveur
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 200));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fermer la modale
|
|
||||||
closeImportModal();
|
|
||||||
input.value = '';
|
input.value = '';
|
||||||
|
closeImportModal();
|
||||||
const msg = totalSkipped > 0 ? ` (${totalSkipped} ignoré(s))` : '';
|
const msg = totalSkp > 0 ? ` (${totalSkp} ignoré(s))` : '';
|
||||||
showSuccessModal(`${totalImported} film(s) importé(s) avec succès.${msg}`);
|
showSuccessModal(`${totalImp} édition(s) importée(s).${msg}`);
|
||||||
loadDashboardData();
|
loadDashboardData();
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
closeImportModal();
|
closeImportModal();
|
||||||
alert(`❌ Échec de l'import : ${err.message}`);
|
alert("❌ Échec import : " + err.message);
|
||||||
input.value = '';
|
input.value = '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -528,7 +509,6 @@ function closeImportModal() { document.getElementById('import-progress-modal').c
|
|||||||
async function saveConfigKeys() {
|
async function saveConfigKeys() {
|
||||||
const tmdb = document.getElementById('tmdb-key-input').value.trim();
|
const tmdb = document.getElementById('tmdb-key-input').value.trim();
|
||||||
const upcmdb = document.getElementById('upcmdb-key-input').value.trim();
|
const upcmdb = document.getElementById('upcmdb-key-input').value.trim();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
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 (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}) });
|
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}) });
|
||||||
@@ -550,15 +530,16 @@ async function saveNewPassword() {
|
|||||||
} catch (err) { console.error(err); }
|
} catch (err) { console.error(err); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ SÉPARATION CLAIRE DES IMPORTS
|
||||||
function updateImportInterface() {
|
function updateImportInterface() {
|
||||||
const title = document.getElementById('import-title');
|
const title = document.getElementById('import-title');
|
||||||
const desc = document.getElementById('import-desc');
|
const desc = document.getElementById('import-desc');
|
||||||
if (currentAdminTab === 'videotheque') {
|
if (currentAdminTab === 'videotheque') {
|
||||||
title.innerHTML = '<strong>Importer ma Vidéothèque</strong>';
|
title.innerHTML = '<strong>Importer ma Vidéothèque</strong>';
|
||||||
desc.textContent = 'Import CSV (EAN + Titre) : Blu-ray.com pour le physique, TMDB pour l\'affiche, le casting et le synopsis.';
|
desc.textContent = 'Importez votre CSV (ex: CLC, MediaControl). Le système récupérera les jaquettes HD via MovieCovers/Blu-ray.com et complétera avec TMDB.';
|
||||||
} else {
|
} else {
|
||||||
title.innerHTML = '<strong>Importer Critiques & Notes</strong>';
|
title.innerHTML = '<strong>Importer Critiques & Notes</strong>';
|
||||||
desc.textContent = 'Sélectionnez vos fichiers "ratings.csv" et "reviews.csv" (Letterboxd).';
|
desc.textContent = 'Importez vos fichiers CSV de notes et critiques (ex: Letterboxd ou export personnalisé).';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user