import dotenv from 'dotenv'; dotenv.config({ path: '/Volumes/sms/edtech/.env' }); const { R2_ACCOUNT_ID, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_PUBLIC_URL } = process.env; if (!R2_ACCOUNT_ID || !R2_BUCKET || !R2_ACCESS_KEY_ID || !R2_SECRET_ACCESS_KEY || !R2_PUBLIC_URL) { console.error('āŒ Missing R2 credentials'); process.exit(1); } import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; import fs from 'fs'; import path from 'path'; const ARTIFACTS = '/Users/macbookair/.gemini/antigravity/brain/ea618d02-1ee0-47c1-a2b7-aed00a3604bc'; const TRACKS_DIR = '/Volumes/sms/edtech/packages/database/content/tracks'; const base = R2_PUBLIC_URL!.replace(/\/$/, ''); const client = new S3Client({ region: 'auto', endpoint: `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { accessKeyId: R2_ACCESS_KEY_ID!, secretAccessKey: R2_SECRET_ACCESS_KEY! }, }); const IMAGE_MAP = [ { src: 't4_j3_credibilite_1772319157261.png', r2: 'images/t4/bes3_credibilite.png', track: 'T4', day: 3 }, { src: 't4_j4_organisation_1772319168678.png', r2: 'images/t4/bes4_organisation.png', track: 'T4', day: 4 }, { src: 't4_j5_stock_1772319180883.png', r2: 'images/t4/bes5_stock.png', track: 'T4', day: 5 }, { src: 't4_j6_cahier_cash_1772319194657.png', r2: 'images/t4/bes6_cahier_cash.png', track: 'T4', day: 6 }, { src: 't4_j7_plan_action_1772319265677.png', r2: 'images/t4/bes7_plan_action.png', track: 'T4', day: 7 }, { src: 't5_j1_banque_1772319281497.png', r2: 'images/t5/bes1_banque.png', track: 'T5', day: 1 }, { src: 't5_j2_5c_credit_1772319295980.png', r2: 'images/t5/bes2_5c_credit.png', track: 'T5', day: 2 }, { src: 't5_j3_chiffres_1772319309609.png', r2: 'images/t5/bes3_chiffres.png', track: 'T5', day: 3 }, { src: 't5_j4_garanties_1772319396014.png', r2: 'images/t5/bes4_garanties.png', track: 'T5', day: 4 }, { src: 't5_j5_pitch_financeur_1772319407304.png', r2: 'images/t5/bes5_pitch_financeur.png', track: 'T5', day: 5 }, { src: 't5_j6_certification_1772319420509.png', r2: 'images/t5/bes6_certification.png', track: 'T5', day: 6 }, ]; async function upload(srcFile: string, r2Key: string): Promise { const buf = fs.readFileSync(path.join(ARTIFACTS, srcFile)); await client.send(new PutObjectCommand({ Bucket: R2_BUCKET!, Key: r2Key, Body: buf, ContentType: 'image/png', CacheControl: 'public, max-age=31536000' })); return `${base}/${r2Key}`; } function inject(track: string, day: number, imageUrl: string) { for (const lang of ['FR', 'WO']) { const fp = path.join(TRACKS_DIR, `${track}-${lang}.json`); if (!fs.existsSync(fp)) continue; const data = JSON.parse(fs.readFileSync(fp, 'utf-8')); for (const d of data.days) { if (d.dayNumber === day) d.imageUrl = imageUrl; } fs.writeFileSync(fp, JSON.stringify(data, null, 2)); console.log(` šŸ“ ${track}-${lang}.json J${day} → ${imageUrl.split('/').pop()}`); } } async function main() { console.log(`\nšŸš€ Uploading ${IMAGE_MAP.length} images to R2...\n`); let ok = 0; for (const img of IMAGE_MAP) { try { const url = await upload(img.src, img.r2); console.log(`āœ… ${img.r2}`); inject(img.track, img.day, url); ok++; } catch (e: unknown) { console.error(`āŒ ${img.r2}: ${(e instanceof Error ? (e instanceof Error ? e.message : String(e)) : String(e))}`); } } console.log(`\nāœ… Done: ${ok}/${IMAGE_MAP.length} uploaded and injected.`); } main().catch(e => { console.error(e); process.exit(1); });