ajout d'une option permettant de nettoyer les médias inutilisés
This commit is contained in:
parent
d5754b0277
commit
6ec572ef0c
125
admin/api/clean-media.php
Normal file
125
admin/api/clean-media.php
Normal 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()
|
||||
]);
|
||||
}
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user