- 新增 wpmind 主面板 + 插件列表截图 (PNG+WebP) - manifest.json 补齐 wpslug/wpavatar/wpdate/wpfonts/wpmind 共 11 场景 - play-deploy 同步目标增加 screenshots 目录 - 新增 play-capture 自动截图脚本 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
173 lines
6 KiB
JavaScript
Executable file
173 lines
6 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
// play-capture — 标准化产品截图生成工具
|
|
// 用法: play-capture <plugin-id> [--all] [--watermark] [--webp]
|
|
// 产出: ~/play/screenshots/{plugin-id}/ 下的 PNG + WebP 截图
|
|
|
|
const { chromium } = require('playwright');
|
|
const { execSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const SITE = 'https://play.wenpai.net';
|
|
const PLUGINS_JSON = path.join(process.env.HOME, 'play/plugins.json');
|
|
const BLUEPRINTS_DIR = path.join(process.env.HOME, 'play/blueprints');
|
|
const SCREENSHOTS_DIR = path.join(process.env.HOME, 'play/screenshots');
|
|
|
|
const args = process.argv.slice(2);
|
|
const doAll = args.includes('--all');
|
|
const doWatermark = args.includes('--watermark');
|
|
const doWebp = args.includes('--webp');
|
|
const pluginId = args.find(a => !a.startsWith('--'));
|
|
|
|
if (!pluginId && !doAll) {
|
|
console.log('用法: play-capture <plugin-id> [--all] [--watermark] [--webp]');
|
|
console.log(' play-capture wpslug 单个插件截图');
|
|
console.log(' play-capture --all 所有插件截图');
|
|
console.log(' play-capture wpslug --watermark 加水印');
|
|
console.log(' play-capture --all --webp 转 WebP');
|
|
process.exit(0);
|
|
}
|
|
|
|
// 每个插件的截图场景定义
|
|
const SCENES = {
|
|
wpslug: [
|
|
{ id: 'settings', name: '设置页', path: '/wp-admin/options-general.php?page=wpslug' },
|
|
{ id: 'plugins', name: '插件列表', path: '/wp-admin/plugins.php' },
|
|
{ id: 'editor', name: '编辑器', path: '/wp-admin/post-new.php', setup: async (frame) => {
|
|
// 关闭欢迎弹窗
|
|
const closeBtn = await frame.$('.components-modal__header button, [aria-label="Close"], [aria-label="关闭"]');
|
|
if (closeBtn) await closeBtn.click();
|
|
await frame.waitForTimeout(500);
|
|
// 输入中文标题触发 slug 生成
|
|
const titleInput = await frame.$('[aria-label="添加标题"], [aria-label="Add title"], .editor-post-title__input');
|
|
if (titleInput) {
|
|
await titleInput.click();
|
|
await titleInput.type('测试中文标题自动转拼音', { delay: 30 });
|
|
await frame.waitForTimeout(2000);
|
|
}
|
|
}},
|
|
],
|
|
wpavatar: [
|
|
{ id: 'settings', name: '设置页', path: '/wp-admin/admin.php?page=wpavatar-settings' },
|
|
{ id: 'plugins', name: '插件列表', path: '/wp-admin/plugins.php' },
|
|
{ id: 'discussion', name: '评论设置', path: '/wp-admin/options-discussion.php' },
|
|
],
|
|
wpdate: [
|
|
{ id: 'settings', name: '日历页', path: '/wp-admin/admin.php?page=wpdate-calendar' },
|
|
{ id: 'plugins', name: '插件列表', path: '/wp-admin/plugins.php' },
|
|
],
|
|
wpfonts: [
|
|
{ id: 'plugins', name: '插件列表', path: '/wp-admin/plugins.php' },
|
|
],
|
|
wpmind: [
|
|
{ id: 'settings', name: '主面板', path: '/wp-admin/admin.php?page=wpmind' },
|
|
{ id: 'plugins', name: '插件列表', path: '/wp-admin/plugins.php' },
|
|
],
|
|
};
|
|
|
|
function getPlugins() {
|
|
const data = JSON.parse(fs.readFileSync(PLUGINS_JSON, 'utf8'));
|
|
return data.filter(p => p.group === 'plugin');
|
|
}
|
|
|
|
async function capturePlugin(browser, pluginId) {
|
|
const outDir = path.join(SCREENSHOTS_DIR, pluginId);
|
|
fs.mkdirSync(outDir, { recursive: true });
|
|
|
|
const scenes = SCENES[pluginId];
|
|
if (!scenes) {
|
|
console.log(` [!] 未定义截图场景: ${pluginId}`);
|
|
return [];
|
|
}
|
|
|
|
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
|
|
const results = [];
|
|
|
|
try {
|
|
// 加载 Playground
|
|
await page.goto(`${SITE}/?plugin=${pluginId}`, { waitUntil: 'load', timeout: 60000 });
|
|
await page.waitForTimeout(35000);
|
|
|
|
// 找到 WordPress iframe
|
|
let wpFrame = null;
|
|
for (const frame of page.frames()) {
|
|
const url = frame.url();
|
|
if (url.includes('scope:') || (url.includes('wp-admin') && !url.includes('playground.html'))) {
|
|
wpFrame = frame;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!wpFrame) {
|
|
console.log(' [!] 未找到 WordPress iframe');
|
|
await page.close();
|
|
return [];
|
|
}
|
|
|
|
// 逐场景截图
|
|
for (const scene of scenes) {
|
|
try {
|
|
// 导航到目标页
|
|
await wpFrame.evaluate((p) => { window.location.href = p; }, scene.path);
|
|
await wpFrame.waitForLoadState('load').catch(() => {});
|
|
await wpFrame.waitForTimeout(3000);
|
|
|
|
// 执行场景特定设置
|
|
if (scene.setup) {
|
|
await scene.setup(wpFrame);
|
|
}
|
|
|
|
// 截图(整个页面,包含 Playground 外壳)
|
|
const pngPath = path.join(outDir, `${pluginId}-${scene.id}.png`);
|
|
await page.screenshot({ path: pngPath });
|
|
|
|
results.push({ scene: scene.id, name: scene.name, path: pngPath });
|
|
console.log(` [+] ${scene.name}: ${pngPath}`);
|
|
|
|
// 后处理
|
|
const imgArgs = ['--resize', '1280'];
|
|
if (doWatermark) imgArgs.push('--watermark', 'play.wenpai.net');
|
|
if (doWebp) imgArgs.push('--webp');
|
|
|
|
try {
|
|
execSync(`img-process "${pngPath}" ${imgArgs.join(' ')}`, { stdio: 'pipe' });
|
|
} catch (e) {
|
|
// img-process 可能不可用,静默跳过
|
|
}
|
|
} catch (err) {
|
|
console.log(` [!] ${scene.name} 失败: ${err.message.substring(0, 80)}`);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.log(` [!] 加载失败: ${err.message.substring(0, 80)}`);
|
|
} finally {
|
|
await page.close();
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
(async () => {
|
|
const browser = await chromium.launch({ headless: true });
|
|
const plugins = doAll ? getPlugins().map(p => p.id) : [pluginId];
|
|
const allResults = {};
|
|
|
|
for (const id of plugins) {
|
|
process.stdout.write(`\n截图 ${id} ...\n`);
|
|
const results = await capturePlugin(browser, id);
|
|
allResults[id] = results;
|
|
}
|
|
|
|
await browser.close();
|
|
|
|
// 汇总
|
|
const total = Object.values(allResults).reduce((sum, r) => sum + r.length, 0);
|
|
console.log(`\n=== 完成: ${total} 张截图, ${plugins.length} 个插件 ===`);
|
|
console.log(`目录: ${SCREENSHOTS_DIR}`);
|
|
|
|
// 保存清单
|
|
fs.writeFileSync(
|
|
path.join(SCREENSHOTS_DIR, 'manifest.json'),
|
|
JSON.stringify(allResults, null, 2)
|
|
);
|
|
})();
|