#!/usr/bin/env node import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { createDbPool } from '../db.mjs'; import { resolvePlazaPublicationCoverUrl } from '../plaza-posts.mjs'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); const shouldWrite = process.argv.includes('--write'); const batchPrefix = (() => { const idx = process.argv.indexOf('--batch-prefix'); return idx >= 0 ? String(process.argv[idx + 1] ?? '').trim() : ''; })(); function loadEnvFile(filePath) { if (!fs.existsSync(filePath)) return; for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; const eq = trimmed.indexOf('='); if (eq < 0) continue; const key = trimmed.slice(0, eq).trim(); const value = trimmed.slice(eq + 1).trim(); if (!process.env[key]) process.env[key] = value; } } loadEnvFile(path.join(root, '../../.env.local')); loadEnvFile(path.join(root, '.env')); const pool = createDbPool(); const params = []; let batchFilter = ''; if (batchPrefix) { batchFilter = ' AND p.workspace_relative_path LIKE ?'; params.push(`public/${batchPrefix}%`); } const [rows] = await pool.query( `SELECT pp.id, pp.title, pp.cover_url, pp.user_slug, pp.status, pr.public_url, pr.url_slug FROM plaza_posts pp JOIN h5_publish_records pr ON pr.id = pp.publication_id JOIN h5_page_records p ON p.id = pr.page_id WHERE pp.status IN ('published', 'pending_review', 'rejected') ${batchFilter} ORDER BY pp.published_at DESC, pp.id DESC`, params, ); const updates = rows .map((row) => ({ id: row.id, title: row.title, from: String(row.cover_url ?? ''), to: resolvePlazaPublicationCoverUrl({ inputCoverUrl: row.cover_url, publicUrl: row.public_url, publicationUrlSlug: row.url_slug, userSlug: row.user_slug, }), publicUrl: String(row.public_url ?? ''), })) .filter((row) => row.to && row.from !== row.to); console.log( `${shouldWrite ? '写入模式' : 'Dry-run'}:共扫描 ${rows.length} 条帖子,命中 ${updates.length} 条待补封面。`, ); for (const row of updates.slice(0, 20)) { console.log(`- ${row.id} | ${row.title}`); console.log(` ${row.from || '(empty)'} -> ${row.to}`); } if (updates.length > 20) { console.log(`... 其余 ${updates.length - 20} 条省略`); } if (shouldWrite && updates.length > 0) { const now = Date.now(); for (const row of updates) { await pool.query(`UPDATE plaza_posts SET cover_url = ?, updated_at = ? WHERE id = ?`, [ row.to, now, row.id, ]); } console.log(`已更新 ${updates.length} 条帖子封面。`); } else if (!shouldWrite) { console.log('未写入数据库;如需正式回填,请执行: node scripts/backfill-plaza-cover-urls.mjs --write'); } await pool.end();