import { PrismaClient } from '@prisma/client' import crypto from 'crypto' import fs from 'fs' import path from 'path' import axios from 'axios' import FormData from 'form-data' const prisma = new PrismaClient() const baseUrl = process.env.OPENINARY_API_URL?.replace(/\/+$/, '') || 'https://media.ayris.tech'; const key = process.env.OPENINARY_API_KEY; function getSafeFolder(folder: string): string { return folder .split('/') .filter(Boolean) .map(part => { if (part.length > 25) { const hash = crypto.createHash('md5').update(part).digest('hex').substring(0, 5); return `${part.substring(0, 20)}-${hash}`; } return part; }) .join('/'); } function getSafeFileName(fileName: string): string { const lastDotIndex = fileName.lastIndexOf('.'); const ext = lastDotIndex !== -1 ? fileName.substring(lastDotIndex) : ''; let nameWithoutExt = lastDotIndex !== -1 ? fileName.substring(0, lastDotIndex) : fileName; if (nameWithoutExt.length > 25) { const hash = crypto.createHash('md5').update(nameWithoutExt).digest('hex').substring(0, 5); nameWithoutExt = `${nameWithoutExt.substring(0, 20)}-${hash}`; } return `${nameWithoutExt}${ext}`; } async function uploadFile(filePath: string, folder: string, safeFileName: string): Promise { const form = new FormData(); form.append('files', fs.createReadStream(filePath), { filename: safeFileName, contentType: 'image/jpeg' }); form.append('folder', folder); const res = await axios.post(`${baseUrl}/api/upload`, form, { headers: { ...form.getHeaders(), "Authorization": `Bearer ${key}` } }); const data = res.data; if (Array.isArray(data) && data.length > 0) { const fileUrl = data[0].url || data[0].secure_url; return fileUrl.startsWith('/') ? `${baseUrl}${fileUrl}` : fileUrl; } else if (data && typeof data === "object") { const fileUrl = data.url || data.secure_url || (data.files && data.files[0]?.url); return fileUrl.startsWith('/') ? `${baseUrl}${fileUrl}` : fileUrl; } throw new Error("Invalid response format"); } async function processUrl(url: string): Promise { if (!url || !url.startsWith(baseUrl)) return null; try { const urlObj = new URL(url); const pathParts = urlObj.pathname.split('/').filter(Boolean); // Check if it has a part longer than 25 characters const isBad = pathParts.some(p => p.length > 25); if (!isBad) return null; console.log(`Found long URL: ${url}`); const originalFileName = decodeURIComponent(pathParts.pop() || 'image.jpg'); let folderParts = pathParts; if (folderParts[0] === 't') { folderParts.shift(); } const originalFolder = decodeURIComponent(folderParts.join('/')); const safeFolder = getSafeFolder(originalFolder); const safeFileName = getSafeFileName(originalFileName); if (safeFolder === originalFolder && safeFileName === originalFileName) { return null; } console.log(`-> Safe folder: ${safeFolder}`); console.log(`-> Safe filename: ${safeFileName}`); const res = await axios.get(url, { responseType: 'arraybuffer' }); const buffer = Buffer.from(res.data); const tmpPath = path.join('/tmp', safeFileName); fs.writeFileSync(tmpPath, buffer); const newUrl = await uploadFile(tmpPath, safeFolder, safeFileName); console.log(`-> New URL: ${newUrl}`); fs.unlinkSync(tmpPath); return newUrl; } catch (error) { console.error(`Error processing ${url}:`, error.message); return null; } } async function main() { const galleries = await prisma.gallery.findMany(); for (const g of galleries) { const newUrl = await processUrl(g.url); if (newUrl) await prisma.gallery.update({ where: { id: g.id }, data: { url: newUrl }}); } const posts = await prisma.blogPost.findMany({ where: { coverImage: { not: null } } }); for (const p of posts) { if (p.coverImage) { const newUrl = await processUrl(p.coverImage); if (newUrl) await prisma.blogPost.update({ where: { id: p.id }, data: { coverImage: newUrl }}); } } const events = await prisma.event.findMany({ where: { coverImage: { not: null } } }); for (const e of events) { if (e.coverImage) { const newUrl = await processUrl(e.coverImage); if (newUrl) await prisma.event.update({ where: { id: e.id }, data: { coverImage: newUrl }}); } } const collections = await prisma.collection.findMany({ where: { coverImage: { not: null } } }); for (const c of collections) { if (c.coverImage) { const newUrl = await processUrl(c.coverImage); if (newUrl) await prisma.collection.update({ where: { id: c.id }, data: { coverImage: newUrl }}); } } } main().catch(console.error).finally(() => prisma.$disconnect());