Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
import "dotenv/config";
|
|
|
|
|
import { createClient } from "webdav";
|
2026-02-18 14:49:08 +01:00
|
|
|
import { mkdir, writeFile, stat, readdir, rm } from "fs/promises";
|
|
|
|
|
import { join, dirname, relative } from "path";
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
|
|
|
|
|
interface FileStat {
|
|
|
|
|
filename: string;
|
|
|
|
|
basename: string;
|
|
|
|
|
type: "file" | "directory";
|
|
|
|
|
size: number;
|
|
|
|
|
lastmod: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const WEBDAV_URL = process.env.WEBDAV_URL || "https://nas.arfaoui.net:6006";
|
|
|
|
|
const WEBDAV_PATH = process.env.WEBDAV_PATH || "/photo/Portfolio";
|
|
|
|
|
const WEBDAV_USER = process.env.WEBDAV_USER;
|
|
|
|
|
const WEBDAV_PASS = process.env.WEBDAV_PASS;
|
|
|
|
|
const DEST_DIR = "src/assets/images/photos";
|
|
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
|
if (!WEBDAV_USER || !WEBDAV_PASS) {
|
|
|
|
|
console.error("Error: WEBDAV_USER and WEBDAV_PASS environment variables are required");
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const client = createClient(WEBDAV_URL, {
|
|
|
|
|
username: WEBDAV_USER,
|
|
|
|
|
password: WEBDAV_PASS,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log(`Fetching images from ${WEBDAV_URL}${WEBDAV_PATH}...`);
|
|
|
|
|
|
2026-02-18 14:49:08 +01:00
|
|
|
// Collecter tous les fichiers/dossiers distants
|
|
|
|
|
const remoteItems = new Set<string>();
|
|
|
|
|
|
|
|
|
|
await syncDirectory(client, WEBDAV_PATH, DEST_DIR, remoteItems);
|
|
|
|
|
|
|
|
|
|
// Supprimer les fichiers locaux qui n'existent plus sur le NAS
|
|
|
|
|
await cleanupLocalFiles(DEST_DIR, remoteItems);
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
|
|
|
|
|
console.log("Done!");
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-18 14:49:08 +01:00
|
|
|
async function syncDirectory(
|
|
|
|
|
client: ReturnType<typeof createClient>,
|
|
|
|
|
remotePath: string,
|
|
|
|
|
localPath: string,
|
|
|
|
|
remoteItems: Set<string>
|
|
|
|
|
) {
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
await mkdir(localPath, { recursive: true });
|
2026-02-18 14:49:08 +01:00
|
|
|
remoteItems.add(localPath);
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
|
|
|
|
|
const items = (await client.getDirectoryContents(remotePath)) as FileStat[];
|
|
|
|
|
|
|
|
|
|
for (const item of items) {
|
|
|
|
|
const localItemPath = join(localPath, item.basename);
|
|
|
|
|
const remoteItemPath = item.filename;
|
|
|
|
|
|
|
|
|
|
if (item.type === "directory") {
|
|
|
|
|
console.log(` [dir] ${item.basename}/`);
|
2026-02-18 14:49:08 +01:00
|
|
|
await syncDirectory(client, remoteItemPath, localItemPath, remoteItems);
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
} else if (item.type === "file" && /\.(jpg|jpeg|png|webp)$/i.test(item.basename)) {
|
2026-02-18 14:49:08 +01:00
|
|
|
remoteItems.add(localItemPath);
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
const needsDownload = await shouldDownload(localItemPath, item);
|
|
|
|
|
|
|
|
|
|
if (needsDownload) {
|
|
|
|
|
console.log(` [download] ${remoteItemPath}`);
|
|
|
|
|
const content = (await client.getFileContents(remoteItemPath)) as Buffer;
|
|
|
|
|
await mkdir(dirname(localItemPath), { recursive: true });
|
|
|
|
|
await writeFile(localItemPath, content);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(` [skip] ${item.basename} (unchanged)`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function shouldDownload(localPath: string, remoteItem: FileStat): Promise<boolean> {
|
|
|
|
|
try {
|
|
|
|
|
const localStat = await stat(localPath);
|
|
|
|
|
const remoteSize = remoteItem.size;
|
|
|
|
|
const localSize = localStat.size;
|
|
|
|
|
|
|
|
|
|
if (remoteSize !== localSize) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const remoteDate = new Date(remoteItem.lastmod).getTime();
|
|
|
|
|
const localDate = localStat.mtime.getTime();
|
|
|
|
|
|
|
|
|
|
return remoteDate > localDate;
|
|
|
|
|
} catch {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-18 14:49:08 +01:00
|
|
|
async function cleanupLocalFiles(localDir: string, remoteItems: Set<string>) {
|
|
|
|
|
const localFiles = await collectLocalFiles(localDir);
|
|
|
|
|
let deletedCount = 0;
|
|
|
|
|
|
|
|
|
|
for (const localFile of localFiles) {
|
|
|
|
|
if (!remoteItems.has(localFile)) {
|
|
|
|
|
const relativePath = relative(localDir, localFile);
|
|
|
|
|
console.log(` [delete] ${relativePath}`);
|
|
|
|
|
await rm(localFile, { recursive: true, force: true });
|
|
|
|
|
deletedCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (deletedCount > 0) {
|
|
|
|
|
console.log(`Deleted ${deletedCount} orphaned file(s)/folder(s)`);
|
|
|
|
|
// Nettoyer les dossiers vides
|
|
|
|
|
await cleanupEmptyDirs(localDir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function collectLocalFiles(dir: string): Promise<string[]> {
|
|
|
|
|
const files: string[] = [];
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
|
|
|
|
|
|
|
|
for (const entry of entries) {
|
|
|
|
|
const fullPath = join(dir, entry.name);
|
|
|
|
|
|
|
|
|
|
if (entry.isDirectory()) {
|
|
|
|
|
files.push(fullPath);
|
|
|
|
|
const subFiles = await collectLocalFiles(fullPath);
|
|
|
|
|
files.push(...subFiles);
|
|
|
|
|
} else if (/\.(jpg|jpeg|png|webp)$/i.test(entry.name)) {
|
|
|
|
|
files.push(fullPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Dossier n'existe pas encore
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return files;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function cleanupEmptyDirs(dir: string) {
|
|
|
|
|
try {
|
|
|
|
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
|
|
|
|
|
|
|
|
for (const entry of entries) {
|
|
|
|
|
if (entry.isDirectory()) {
|
|
|
|
|
const subDir = join(dir, entry.name);
|
|
|
|
|
await cleanupEmptyDirs(subDir);
|
|
|
|
|
|
|
|
|
|
// Vérifier si le dossier est vide après nettoyage récursif
|
|
|
|
|
const subEntries = await readdir(subDir);
|
|
|
|
|
if (subEntries.length === 0) {
|
|
|
|
|
console.log(` [delete] ${relative(DEST_DIR, subDir)}/ (empty)`);
|
|
|
|
|
await rm(subDir, { recursive: true });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Ignore errors
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Ajout de la section galerie photo et nettoyage du template
Galerie photo :
- Ajout du layout photo avec slideshow plein écran
- Navigation par catégories (portraits, paysages, nature, etc.)
- Section "Fil Photo" avec posts illustrés (photoBlogPosts)
- Lightbox pour les albums de catégories
- Composants : Slideshow, CategoryNav, CategoryGrid, Lightbox, MasonryGallery
Nettoyage :
- Suppression du contenu démo du template (posts, images, about)
- Consolidation src/collections/ dans src/data/
- Suppression du config.js dupliqué (garde config.ts)
- Nettoyage des assets inutilisés (posts/, experiences/)
Corrections :
- Favicon récupéré du site actuel
- Chemins favicon corrigés dans les layouts
UI :
- Page d'accueil mise à jour
- Header/Footer simplifiés
- Nouvelle page À propos
2026-01-07 01:45:40 +01:00
|
|
|
main().catch((err) => {
|
|
|
|
|
console.error("Error:", err.message);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|