This commit is contained in:
cangui 2025-08-18 21:41:40 +02:00
parent a9bf4d7403
commit 773ea9dc13

View File

@ -6,6 +6,7 @@ import (
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"gorm.io/gorm" "gorm.io/gorm"
@ -13,69 +14,122 @@ import (
) )
func CreateDefaultFolder(db *gorm.DB) { func CreateDefaultFolder(db *gorm.DB) {
type item struct { // noms “logiques” attendus en base
Name string targets := []string{"Film", "Série", "Manga", "Magazine"}
}
defs := []item{ // 0) Nettoyage global : si des lignes ont path "upload/XXX", on les normalise en "XXX"
{Name: "Film"}, if err := normalizeExistingPaths(db); err != nil {
{Name: "Série"}, log.Printf("[DB] Warning: normalisation initiale partielle: %v", err)
{Name: "Manga"},
{Name: "Magazine"},
} }
for _, it := range defs { for _, name := range targets {
path := filepath.Join("upload", it.Name) diskPath := filepath.Join("upload", name) // répertoire physique
// 1) Toujours créer le dossier physique
// 1) Dossier : on s'assure qu'il existe if err := os.MkdirAll(diskPath, 0o755); err != nil {
if err := os.MkdirAll(path, 0o755); err != nil { log.Printf("[FOLDER] Erreur création '%s' : %v", diskPath, err)
log.Printf("[FOLDER] Erreur création '%s' : %v", path, err)
continue continue
} }
// 2) Base : chercher une ligne existante par path OU path_name // 2) En base : on veut UNE ligne unique avec Path=Name et PathName=Name
var existing models.PathDownload // On cherche tout ce qui pourrait correspondre à ce nom (avec ou sans "upload/")
err := db.Where("path = ? OR path_name = ?", path, it.Name).First(&existing).Error var rows []models.PathDownload
if err := db.Where("path = ? OR path = ? OR path_name = ? OR path_name = ?",
name, "upload/"+name, name, "upload/"+name,
).Find(&rows).Error; err != nil {
log.Printf("[DB] Lookup '%s' échouée : %v", name, err)
continue
}
switch { switch len(rows) {
case errors.Is(err, gorm.ErrRecordNotFound): case 0:
// 2a) Pas trouvé -> on crée // 2a) Rien trouvé → créer la ligne normalisée
row := models.PathDownload{ row := models.PathDownload{Path: name, PathName: name}
Path: path,
PathName: it.Name,
}
if err := db.Create(&row).Error; err != nil { if err := db.Create(&row).Error; err != nil {
log.Printf("[DB] Échec création PathDownload(%s, %s) : %v", path, it.Name, err) log.Printf("[DB] Création PathDownload('%s') KO : %v", name, err)
} else { } else {
log.Printf("[DB] Ligne créée PathDownload id=%v (%s | %s)", row.ID, row.PathName, row.Path) log.Printf("[DB] Créé PathDownload id=%v (%s)", row.ID, name)
} }
case err != nil:
// 2b) Erreur DB
log.Printf("[DB] Erreur recherche PathDownload(%s | %s) : %v", path, it.Name, err)
default: default:
// 2c) Trouvé -> on normalise si besoin // 2b) On a des lignes → on les normalise et on garde une seule
updates := map[string]interface{}{} // 1) mettre à jour la première ligne en Path=Name, PathName=Name
if existing.Path != path { main := rows[0]
updates["path"] = path needUpdate := (main.Path != name) || (main.PathName != name)
} if needUpdate {
if existing.PathName != it.Name { if err := db.Model(&main).Updates(map[string]any{
updates["path_name"] = it.Name "path": name,
} "path_name": name,
if len(updates) > 0 { }).Error; err != nil {
if err := db.Model(&existing).Updates(updates).Error; err != nil { log.Printf("[DB] Update id=%v -> (%s|%s) KO : %v", main.ID, name, name, err)
log.Printf("[DB] Échec mise à jour PathDownload id=%v : %v", existing.ID, err)
} else { } else {
log.Printf("[DB] Mis à jour PathDownload id=%v -> %#v", existing.ID, updates) log.Printf("[DB] Normalisé id=%v -> (%s|%s)", main.ID, name, name)
}
}
// 2) supprimer les doublons résiduels (même nom logique)
if len(rows) > 1 {
var dupIDs []uint
for _, r := range rows[1:] {
dupIDs = append(dupIDs, r.ID)
}
if err := db.Where("id IN ?", dupIDs).Delete(&models.PathDownload{}).Error; err != nil {
log.Printf("[DB] Suppression doublons (%v) KO : %v", dupIDs, err)
} else {
log.Printf("[DB] Doublons supprimés pour '%s' : %v", name, dupIDs)
} }
} else {
log.Printf("[DB] OK PathDownload id=%v déjà synchro (%s | %s)", existing.ID, existing.PathName, existing.Path)
} }
} }
// 3) (Facultatif) log côté fichiers log.Printf("[FOLDER] OK : %s (DB='%s')", diskPath, name)
if fi, err := os.Stat(path); err == nil && fi.IsDir() {
fmt.Printf("[FOLDER] OK : %s\n", path)
}
} }
} }
// normalizeExistingPaths met à jour toutes les lignes dont path commence par "upload/"
// en supprimant ce préfixe, et aligne path_name si nécessaire. Elle supprime aussi
// déventuels doublons créés par cette normalisation.
func normalizeExistingPaths(db *gorm.DB) error {
// 1) Récupérer les lignes impactées
var rows []models.PathDownload
if err := db.Where("path LIKE ?", "upload/%").Find(&rows).Error; err != nil {
return err
}
for _, r := range rows {
trimmed := strings.TrimPrefix(r.Path, "upload/")
updates := map[string]any{"path": trimmed}
if r.PathName == "" || strings.HasPrefix(r.PathName, "upload/") {
updates["path_name"] = trimmed
}
if err := db.Model(&r).Updates(updates).Error; err != nil {
return fmt.Errorf("update id=%v (%s -> %s) : %w", r.ID, r.Path, trimmed, err)
}
}
// 2) Éliminer déventuels doublons (même path normalisé), on garde le plus petit id
type rec struct {
ID uint
Path string
}
var all []rec
if err := db.Model(&models.PathDownload{}).Select("id, path").Order("path, id").Scan(&all).Error; err != nil {
return err
}
seen := make(map[string]uint)
var dupIDs []uint
for _, r := range all {
if keep, ok := seen[r.Path]; ok {
// doublon : on marque pour suppression
dupIDs = append(dupIDs, r.ID)
_ = keep
} else {
seen[r.Path] = r.ID
}
}
if len(dupIDs) > 0 {
if err := db.Where("id IN ?", dupIDs).Delete(&models.PathDownload{}).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("delete dups %v : %w", dupIDs, err)
}
log.Printf("[DB] Doublons supprimés après normalisation: %v", dupIDs)
}
return nil
}