jalil.arfaoui.net/scripts/fetch-images.ts

87 lines
2.6 KiB
TypeScript
Raw Permalink Normal View History

import "dotenv/config";
import { createClient } from "webdav";
import { mkdir, writeFile, stat } from "fs/promises";
import { join, dirname } from "path";
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}...`);
await syncDirectory(client, WEBDAV_PATH, DEST_DIR);
console.log("Done!");
}
async function syncDirectory(client: ReturnType<typeof createClient>, remotePath: string, localPath: string) {
await mkdir(localPath, { recursive: true });
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}/`);
await syncDirectory(client, remoteItemPath, localItemPath);
} else if (item.type === "file" && /\.(jpg|jpeg|png|webp)$/i.test(item.basename)) {
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;
}
}
main().catch((err) => {
console.error("Error:", err.message);
process.exit(1);
});