Actualiser js/admin.js

This commit is contained in:
2026-06-16 20:49:43 +02:00
parent 8290a4f3cc
commit ec815787ed
+18 -20
View File
@@ -5,7 +5,7 @@
* ========================================================================= * =========================================================================
*/ */
// ── PARSEUR CSV UNIVERSEL (Gestion avancée des guillemets et séparateurs) ── // ── PARSEUR CSV UNIVERSEL (Gestion des guillemets et séparateurs) ──
function parseFlexibleCSV(text) { function parseFlexibleCSV(text) {
const rows = []; const rows = [];
let row = [""]; let row = [""];
@@ -42,7 +42,7 @@ function parseFlexibleCSV(text) {
return rows; return rows;
} }
// ── FONCTION D'IMPORTATION REVISITÉE ── // ── FONCTION D'IMPORTATION SÉCURISÉE (Latin-1 / Multi-formats) ──
function importFromCSV(input) { function importFromCSV(input) {
const file = input.files[0]; const file = input.files[0];
if (!file) return; if (!file) return;
@@ -58,11 +58,11 @@ function importFromCSV(input) {
return; return;
} }
// Nettoyage et normalisation des entêtes pour ignorer les accents et la casse // Nettoyage et normalisation des en-têtes (ignore les accents et la casse)
const cleanHeader = (h) => h.trim().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""); const cleanHeader = (h) => h.trim().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
const headers = rows[0].map(cleanHeader); const headers = rows[0].map(cleanHeader);
// Mappage ultra-large des colonnes (gère vos deux structures de fichiers) // Mappage des colonnes (gère 'importcinetest.csv' et votre catalogue global)
const idxTitle = headers.findIndex(h => h === 'titre' || h === 'title' || h === 'name'); const idxTitle = headers.findIndex(h => h === 'titre' || h === 'title' || h === 'name');
const idxYear = headers.findIndex(h => h === 'annee' || h === 'year' || h === 'publish_date'); const idxYear = headers.findIndex(h => h === 'annee' || h === 'year' || h === 'publish_date');
const idxDirector = headers.findIndex(h => h === 'realisateur' || h === 'director' || h === 'creators'); const idxDirector = headers.findIndex(h => h === 'realisateur' || h === 'director' || h === 'creators');
@@ -71,7 +71,7 @@ function importFromCSV(input) {
const idxPoster = headers.findIndex(h => h === 'url_affiche' || h === 'url'); const idxPoster = headers.findIndex(h => h === 'url_affiche' || h === 'url');
if (idxTitle === -1) { if (idxTitle === -1) {
alert("Erreur : Impossible de trouver la colonne des titres. Entêtes détectés : " + rows[0].join(', ')); alert("Erreur : Impossible de trouver la colonne des titres.");
input.value = ''; input.value = '';
return; return;
} }
@@ -86,10 +86,10 @@ function importFromCSV(input) {
const titleRaw = cols[idxTitle]?.trim(); const titleRaw = cols[idxTitle]?.trim();
if (!titleRaw) continue; if (!titleRaw) continue;
// Nettoyage des chaînes parasites // Nettoyage des suffixes d'éditions
let title = titleRaw.replace(/\s*\[.*?\]/g, "").replace(/\s*- Édition.*/gi, ""); let title = titleRaw.replace(/\s*\[.*?\]/g, "").replace(/\s*- Édition.*/gi, "");
// Année (on extrait les 4 premiers chiffres) // Extraction propre de l'année (4 chiffres)
let year = ''; let year = '';
if (idxYear >= 0 && cols[idxYear]) { if (idxYear >= 0 && cols[idxYear]) {
const match = cols[idxYear].trim().match(/\d{4}/); const match = cols[idxYear].trim().match(/\d{4}/);
@@ -102,7 +102,7 @@ function importFromCSV(input) {
director = cols[idxDirector].split(',')[0].trim(); director = cols[idxDirector].split(',')[0].trim();
} }
// Note (de 1 à 5) // Note (Normalisée entre 1 et 5)
let rating = 0; let rating = 0;
if (idxRating >= 0 && cols[idxRating]) { if (idxRating >= 0 && cols[idxRating]) {
const ratingRaw = parseFloat(cols[idxRating]); const ratingRaw = parseFloat(cols[idxRating]);
@@ -110,15 +110,15 @@ function importFromCSV(input) {
rating = Math.round(Math.min(5, Math.max(1, ratingRaw))); rating = Math.round(Math.min(5, Math.max(1, ratingRaw)));
} }
} }
if (rating === 0) rating = 3; // Note par défaut if (rating === 0) rating = 3;
// Critique ou description longue // Critique ou description de l'œuvre
let review = idxReview >= 0 && cols[idxReview] ? cols[idxReview].trim() : ''; let review = idxReview >= 0 && cols[idxReview] ? cols[idxReview].trim() : '';
// Lien vers l'affiche // URL de l'affiche
let filePoster = idxPoster >= 0 && cols[idxPoster] ? cols[idxPoster].trim() : ''; let filePoster = idxPoster >= 0 && cols[idxPoster] ? cols[idxPoster].trim() : '';
// Vérification des doublons élargie (titre + année identiques, peu importe le type) // Déduplication (titre + année)
const alreadyExists = films.some( const alreadyExists = films.some(
f => f.title.toLowerCase() === title.toLowerCase() && (year === '' || f.year === year) f => f.title.toLowerCase() === title.toLowerCase() && (year === '' || f.year === year)
); );
@@ -132,7 +132,7 @@ function importFromCSV(input) {
} }
if (toImport.length === 0) { if (toImport.length === 0) {
alert(`Aucun nouveau film inséré.\n⚠️ ${duplicateCount} doublon(s) filtré(s) ou lignes vides.`); alert(`Aucun nouveau film inséré.\n⚠️ ${duplicateCount} doublon(s) filtré(s).`);
input.value = ''; input.value = '';
return; return;
} }
@@ -149,7 +149,6 @@ function importFromCSV(input) {
let poster = filePoster; let poster = filePoster;
let streaming = "Disponible sur vos étagères ou au cinéma"; let streaming = "Disponible sur vos étagères ou au cinéma";
// Si l'affiche locale manque et que TMDB est configuré, on interroge l'API
if (!poster && hasTmdb) { if (!poster && hasTmdb) {
const details = await fetchTmdbDetails(title, year); const details = await fetchTmdbDetails(title, year);
poster = details.poster; poster = details.poster;
@@ -160,11 +159,11 @@ function importFromCSV(input) {
if (details.streaming) streaming = details.streaming; if (details.streaming) streaming = details.streaming;
} }
// Structure globale unifiée pour 'critique' ou 'film' // Injection forcée en type 'critique' pour correspondre à votre vue principale
films.push({ films.push({
id: Date.now() + Math.floor(Math.random() * 1000) + i, id: Date.now() + Math.floor(Math.random() * 1000) + i,
title, title,
type: 'critique', // Forcer le type attendu par l'affichage principal de vos onglets type: 'critique',
year, year,
director, director,
rating, rating,
@@ -180,7 +179,6 @@ function importFromCSV(input) {
await new Promise(r => setTimeout(r, 300)); await new Promise(r => setTimeout(r, 300));
hideImportProgress(); hideImportProgress();
// Tri et persistance immédiate
films.sort((a, b) => b.id - a.id); films.sort((a, b) => b.id - a.id);
persist(); persist();
switchTab('critique'); switchTab('critique');
@@ -189,11 +187,11 @@ function importFromCSV(input) {
input.value = ''; input.value = '';
}; };
// Utilisation de ISO-8859-1 (Latin-1) pour lire sans encombre les exports Windows/Excel contenant des accents // Utilisation obligatoire de ISO-8859-1 (Latin-1) pour préserver les accents sous Excel / Windows
reader.readAsText(file, 'ISO-8859-1'); reader.readAsText(file, 'ISO-8859-1');
} }
// ── COMPOSANTS ET OUTILS DE SUIVI DE L'IMPORT ── // ── COMPOSANTS INTERFACES DE PROGRESSION ──
function showImportProgress(total) { function showImportProgress(total) {
let overlay = document.getElementById('import-overlay'); let overlay = document.getElementById('import-overlay');
if (!overlay) { if (!overlay) {
@@ -269,7 +267,7 @@ function persist() {
} }
} }
// ── COMMUTATION DE L'ONGLET ACTIF ── // ── NAVIGATION ONGLETS ──
function switchTab(tabName) { function switchTab(tabName) {
document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active'));
document.querySelectorAll('.tab-btn').forEach(el => el.classList.remove('active')); document.querySelectorAll('.tab-btn').forEach(el => el.classList.remove('active'));