ajout d'une option permettant de nettoyer les médias inutilisés

This commit is contained in:
Esenjin 2025-02-18 00:43:11 +01:00
parent d5754b0277
commit 6ec572ef0c
4 changed files with 181 additions and 1 deletions

125
admin/api/clean-media.php Normal file
View File

@ -0,0 +1,125 @@
<?php
require_once '../../includes/config.php';
require_once '../../includes/auth.php';
require_once '../../includes/stories.php';
// Vérification de l'authentification
if (!Auth::check()) {
http_response_code(401);
exit(json_encode(['error' => 'Non autorisé']));
}
function extractImagePaths($content) {
$paths = [];
// Si le contenu est du JSON (format Delta de Quill)
if (is_string($content) && isJson($content)) {
$delta = json_decode($content, true);
if (isset($delta['ops'])) {
foreach ($delta['ops'] as $op) {
if (isset($op['insert']['image'])) {
$paths[] = normalizeImagePath($op['insert']['image']);
}
}
}
} else {
// Si le contenu est du HTML
preg_match_all('/src=["\']([^"\']+)["\']/', $content, $matches);
if (!empty($matches[1])) {
foreach ($matches[1] as $path) {
$paths[] = normalizeImagePath($path);
}
}
}
return $paths;
}
function normalizeImagePath($path) {
// Supprimer les "../" au début du chemin
$path = preg_replace('/^(?:\.\.\/)+/', '', $path);
return $path;
}
function isJson($string) {
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
try {
$unusedFiles = [];
$usedFiles = [];
$totalSpace = 0;
$freedSpace = 0;
// Collecter tous les fichiers dans le dossier chapters
$chaptersDir = __DIR__ . '/../../assets/images/chapters/';
$allFiles = [];
foreach (glob($chaptersDir . '*', GLOB_ONLYDIR) as $storyDir) {
$storyId = basename($storyDir);
foreach (glob($storyDir . '/*') as $file) {
if (is_file($file)) {
$relativePath = 'assets/images/chapters/' . $storyId . '/' . basename($file);
$allFiles[$relativePath] = $file;
$totalSpace += filesize($file);
}
}
}
// Parcourir tous les romans et leurs chapitres
$stories = Stories::getAll();
foreach ($stories as $story) {
// Vérifier la description du roman
if (!empty($story['description'])) {
$usedFiles = array_merge($usedFiles, extractImagePaths($story['description']));
}
// Vérifier les chapitres
if (!empty($story['chapters'])) {
foreach ($story['chapters'] as $chapter) {
if (!empty($chapter['content'])) {
$usedFiles = array_merge($usedFiles, extractImagePaths($chapter['content']));
}
}
}
}
// Identifier les fichiers non utilisés
foreach ($allFiles as $relativePath => $fullPath) {
if (!in_array($relativePath, $usedFiles)) {
$unusedFiles[] = [
'path' => $relativePath,
'size' => filesize($fullPath)
];
$freedSpace += filesize($fullPath);
// Supprimer le fichier
unlink($fullPath);
}
}
// Nettoyer les dossiers vides
foreach (glob($chaptersDir . '*', GLOB_ONLYDIR) as $storyDir) {
if (count(glob("$storyDir/*")) === 0) {
rmdir($storyDir);
}
}
echo json_encode([
'success' => true,
'stats' => [
'filesRemoved' => count($unusedFiles),
'totalSpace' => $totalSpace,
'freedSpace' => $freedSpace,
'details' => $unusedFiles
]
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}

View File

@ -212,8 +212,14 @@ $config = Config::load();
?>
</div>
<button type="button" id="addLink" class="button">Ajouter un lien</button>
<br />
<button type="submit" class="button submit-button">Enregistrer les modifications</button>
<!-- Section Nettoyage des médias -->
<h2>Maintenance</h2>
<div class="maintenance-actions">
<button type="button" id="cleanMedia" class="button">Nettoyer les médias inutilisés</button>
<small>Supprime les images qui ne sont plus utilisées dans les romans et chapitres.</small>
</div>
</form>
</section>
</div>

View File

@ -187,6 +187,23 @@
margin-top: var(--spacing-xl);
}
/* Nettoyage des médias */
.maintenance-actions {
margin: var(--spacing-lg) 0;
padding: var(--spacing-md);
background: var(--bg-secondary);
border-radius: var(--radius-sm);
}
.maintenance-actions button {
margin-bottom: var(--spacing-xs);
}
.maintenance-actions small {
display: block;
color: var(--text-secondary);
}
/* Responsive */
@media (max-width: 768px) {
.options-section {

View File

@ -192,4 +192,36 @@ document.addEventListener('DOMContentLoaded', function() {
setTimeout(() => notification.remove(), 300);
}, 3000);
}
// Gestion du nettoyage des médias
const cleanMediaBtn = document.getElementById('cleanMedia');
if (cleanMediaBtn) {
cleanMediaBtn.addEventListener('click', async () => {
confirmDialog.show({
title: 'Nettoyage des médias',
message: 'Voulez-vous vraiment supprimer toutes les images qui ne sont plus utilisées ? Cette action est irréversible.',
confirmText: 'Nettoyer',
confirmClass: 'danger',
onConfirm: async () => {
try {
const response = await fetch('api/clean-media.php');
if (!response.ok) throw new Error('Erreur réseau');
const result = await response.json();
if (result.success) {
const stats = result.stats;
const mbFreed = (stats.freedSpace / (1024 * 1024)).toFixed(2);
const message = `${stats.filesRemoved} fichier(s) supprimé(s).\n${mbFreed} Mo d'espace libéré.`;
showNotification(message);
} else {
throw new Error(result.error || 'Une erreur est survenue');
}
} catch (error) {
console.error('Erreur:', error);
showNotification(error.message, 'error');
}
}
});
});
}
});