/* Cover generator — run: npm run covers Produces 12 JPGs (1600x900) in public/covers/ plus per-category defaults. */ import sharp from 'sharp' import { mkdirSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' const dirname = path.dirname(fileURLToPath(import.meta.url)) const outDir = path.resolve(dirname, '../public/covers') mkdirSync(outDir, { recursive: true }) const W = 1600 const H = 900 const POSTS = [ // [file, title, category, kind: free|vip] ['agents-free', 'بناء أول وكيل بالعربية', 'وكلاء'], ['agents-vip', 'حلقة الوكيل: تخطيط وتنفيذ وتحقق', 'وكلاء'], ['models-free', 'كيف تختار نموذجك', 'نماذج'], ['models-vip', 'تقييم النماذج منهجياً', 'نماذج'], ['retrieval-free', 'الاسترجاع بلا تعقيد', 'استرجاع'], ['retrieval-vip', 'قواعد بيانات المتجهات عملياً', 'استرجاع'], ['safety-free', 'حدود الوكيل الآمنة', 'سلامة'], ['safety-vip', 'مراجعة مخرجات الوكلاء', 'سلامة'], ['tools-free', 'أدوات لا غنى عنها', 'أدوات'], ['tools-vip', 'أنابيب الأدوات والصلاحيات', 'أدوات'], ['business-free', 'الذكاء الاصطناعي في عملك', 'أعمال'], ['business-vip', 'من نموذج أولي إلى إنتاج', 'أعمال'], // fallback default cover for the agent API ['cover-default', 'أنور بي آي', 'وكلاء'], // per-category default covers for the agent API ['cover-agents', 'وكلاء', 'وكلاء'], ['cover-models', 'نماذج', 'نماذج'], ['cover-retrieval', 'استرجاع', 'استرجاع'], ['cover-safety', 'سلامة', 'سلامة'], ['cover-tools', 'أدوات', 'أدوات'], ['cover-business', 'أعمال', 'أعمال'], ['cover-default', 'أنور بي آي', 'وكلاء'], ] function svgCover(title, category) { const titleEsc = title.replace(/&/g, '&').replace(/ ${Array.from({ length: 9 }, (_, i) => ``).join('')} ${titleEsc} ${catEsc} · أنور بي آي `) } for (const [name, title, category] of POSTS) { await sharp(svgCover(title, category)) .jpeg({ quality: 82 }) .toFile(path.join(outDir, `${name}.jpg`)) console.log(`✓ ${name}.jpg`) } console.log(`Done: ${POSTS.length} covers → ${outDir}`)