/** * # 脚本 capture-screenshots * 说明:批量预热工具网站截图 —— 调用截图 API 并本地化到 * SCREENSHOT_STORAGE_DIR(默认 /.screenshots)。 * 工具详情页的 命中时即可直接回本地文件。 * 用法:bun scripts/capture-screenshots.ts [--force] [--limit N] * --force 忽略已有文件强制重截 * --limit 最多处理 N 个工具(默认全部) */ import { drizzle } from "drizzle-orm/postgres-js"; import postgres from "postgres"; import dotenv from "dotenv"; import { resolve } from "path"; import { eq } from "drizzle-orm"; import { tool } from "../src/lib/db/schema"; import { ensureScreenshot, isValidSlug } from "../src/lib/screenshot"; dotenv.config({ path: resolve(process.cwd(), ".env.local") }); const force = process.argv.includes("--force"); const limitIdx = process.argv.indexOf("--limit"); const limit = limitIdx > -1 ? Number(process.argv[limitIdx + 1]) : Infinity; const client = postgres(process.env.DATABASE_URL!, { prepare: false }); const db = drizzle(client); const tools = await db .select({ slug: tool.slug, name: tool.nameEn, websiteUrl: tool.websiteUrl }) .from(tool) .where(eq(tool.status, "published")); let ok = 0; let skip = 0; let fail = 0; let n = 0; for (const t of tools) { if (n >= limit) break; n++; if (!t.websiteUrl) { skip++; console.log(`○ ${t.slug}: 无 websiteUrl,跳过`); continue; } if (!isValidSlug(t.slug)) { skip++; console.log(`○ ${t.slug}: slug 不合法,跳过`); continue; } try { const started = Date.now(); await ensureScreenshot(t.slug, t.websiteUrl, { force }); ok++; console.log(`✓ ${t.slug} (${Date.now() - started}ms)`); } catch (err) { fail++; console.error(`✗ ${t.slug}:`, err instanceof Error ? err.message : err); } } console.log(`\n完成:成功 ${ok} / 跳过 ${skip} / 失败 ${fail},共 ${n}`); client.end(); process.exit(fail > 0 ? 1 : 0);