Published your App
Replit-Commit-Author: Deployment Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 2b7650db-b0d4-4415-b9bb-cc11e719c2b7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/ncMMRQ9 Replit-Commit-Deployment-Build-Id: 55db64a6-94a6-4850-b7bf-6b5712a636c3 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { uploadToCloudinary, generateImageUrls } from "./cloudinary";
|
||||
|
||||
const TOKEN_PATH = path.join(process.cwd(), "server/dropbox-token.json");
|
||||
const GALLERY_ROOT = "/family room/photos/oddaje/izvajalci selekcija";
|
||||
const CLOUDINARY_MAP_PATH = path.join(process.cwd(), "server/cloudinary-gallery-map.json");
|
||||
|
||||
interface DropboxTokens {
|
||||
access_token: string;
|
||||
@@ -22,6 +24,23 @@ interface GalleryImage {
|
||||
artist: string;
|
||||
}
|
||||
|
||||
interface CloudinaryMap {
|
||||
[fileName: string]: string;
|
||||
}
|
||||
|
||||
function loadCloudinaryMap(): CloudinaryMap {
|
||||
try {
|
||||
if (fs.existsSync(CLOUDINARY_MAP_PATH)) {
|
||||
return JSON.parse(fs.readFileSync(CLOUDINARY_MAP_PATH, "utf-8"));
|
||||
}
|
||||
} catch {}
|
||||
return {};
|
||||
}
|
||||
|
||||
function saveCloudinaryMap(map: CloudinaryMap): void {
|
||||
fs.writeFileSync(CLOUDINARY_MAP_PATH, JSON.stringify(map, null, 2));
|
||||
}
|
||||
|
||||
function extractArtistFromFileName(fileName: string): string {
|
||||
if (/^DSC\d/i.test(fileName) || /^IMG[\s_]\d/i.test(fileName)) return "";
|
||||
const withoutExt = fileName.replace(/\.\w+$/, "");
|
||||
@@ -233,6 +252,28 @@ export async function fetchGalleryFromDropbox(): Promise<GalleryImage[]> {
|
||||
return galleryCache.data;
|
||||
}
|
||||
|
||||
const cloudinaryMap = loadCloudinaryMap();
|
||||
const hasCloudinaryImages = Object.keys(cloudinaryMap).length > 0;
|
||||
|
||||
if (hasCloudinaryImages) {
|
||||
const images: GalleryImage[] = [];
|
||||
for (const [fileName, publicId] of Object.entries(cloudinaryMap)) {
|
||||
const urls = generateImageUrls(publicId);
|
||||
images.push({
|
||||
folder: "Foto All",
|
||||
fileName,
|
||||
thumb: urls.thumb,
|
||||
large: urls.large,
|
||||
mobile: urls.mobile,
|
||||
full: urls.full,
|
||||
artist: extractArtistFromFileName(fileName),
|
||||
});
|
||||
}
|
||||
galleryCache.data = images;
|
||||
galleryCache.timestamp = Date.now();
|
||||
return images;
|
||||
}
|
||||
|
||||
const accessToken = await getValidAccessToken();
|
||||
if (!accessToken) return [];
|
||||
|
||||
@@ -305,3 +346,55 @@ export async function fetchGalleryFromDropbox(): Promise<GalleryImage[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateGalleryToCloudinary(): Promise<{ uploaded: number; skipped: number; failed: number }> {
|
||||
const accessToken = await getValidAccessToken();
|
||||
if (!accessToken) throw new Error("Dropbox not connected");
|
||||
|
||||
const originalEntries = await listFolder(accessToken, ORIGINAL_FOLDER.toLowerCase());
|
||||
const imgFilter = (e: any) => e[".tag"] === "file" && /\.(jpg|jpeg|png|webp|gif)$/i.test(e.name);
|
||||
const originalFiles = originalEntries.filter(imgFilter);
|
||||
|
||||
const cloudinaryMap = loadCloudinaryMap();
|
||||
let uploaded = 0;
|
||||
let skipped = 0;
|
||||
let failed = 0;
|
||||
|
||||
const batchSize = 5;
|
||||
for (let i = 0; i < originalFiles.length; i += batchSize) {
|
||||
const batch = originalFiles.slice(i, i + batchSize);
|
||||
const links = await getTemporaryLinks(accessToken, batch.map((f: any) => f.path_lower));
|
||||
|
||||
const uploadPromises = batch.map(async (file: any) => {
|
||||
const fileName = file.name;
|
||||
|
||||
if (cloudinaryMap[fileName]) {
|
||||
skipped++;
|
||||
return;
|
||||
}
|
||||
|
||||
const link = links.get(file.path_lower);
|
||||
if (!link) {
|
||||
failed++;
|
||||
return;
|
||||
}
|
||||
|
||||
const publicId = await uploadToCloudinary(link, fileName);
|
||||
if (publicId) {
|
||||
cloudinaryMap[fileName] = publicId;
|
||||
uploaded++;
|
||||
console.log(`[cloudinary] Uploaded: ${fileName} -> ${publicId}`);
|
||||
} else {
|
||||
failed++;
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
saveCloudinaryMap(cloudinaryMap);
|
||||
}
|
||||
|
||||
galleryCache.data = [];
|
||||
galleryCache.timestamp = 0;
|
||||
|
||||
return { uploaded, skipped, failed };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user