主要更新: 1. 按H5网页端完全重构匹配功能(match页面) - 4种匹配类型: 创业合伙/资源对接/导师顾问/团队招募 - 资源对接等类型弹出手机号/微信号输入框 - 去掉重新匹配按钮,改为返回按钮 2. 修复所有卡片对齐和宽度问题 - 目录页附录卡片居中 - 首页阅读进度卡片满宽度 - 我的页面菜单卡片对齐 - 推广中心分享卡片统一宽度 3. 修复目录页图标和文字对齐 - section-icon固定40rpx宽高 - section-title与图标垂直居中 4. 更新真实完整文章标题(62篇) - 从book目录读取真实markdown文件名 - 替换之前的简化标题 5. 新增文章数据API - /api/db/chapters - 获取完整书籍结构 - 支持按ID获取单篇文章内容
99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
/**
|
|
* 页面截图工具
|
|
* 开发: 卡若
|
|
* 技术支持: 存客宝
|
|
*/
|
|
import type { DocumentationPage } from "@/lib/documentation/catalog"
|
|
|
|
export type ScreenshotResult = {
|
|
page: DocumentationPage
|
|
screenshotPng?: Buffer
|
|
error?: string
|
|
}
|
|
|
|
type CaptureOptions = {
|
|
baseUrl: string
|
|
timeoutMs: number
|
|
viewport: { width: number; height: number }
|
|
}
|
|
|
|
export async function captureScreenshots(
|
|
pages: DocumentationPage[],
|
|
options: CaptureOptions,
|
|
): Promise<ScreenshotResult[]> {
|
|
const { chromium } = await import("playwright")
|
|
const browser = await chromium.launch({
|
|
headless: true,
|
|
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
})
|
|
|
|
try {
|
|
const results: ScreenshotResult[] = []
|
|
|
|
for (const pageInfo of pages) {
|
|
const page = await browser.newPage({ viewport: options.viewport })
|
|
try {
|
|
const captureUrl = new URL("/documentation/capture", options.baseUrl)
|
|
captureUrl.searchParams.set("path", pageInfo.path)
|
|
|
|
console.log(`[Karuo] Capturing: ${pageInfo.path}`)
|
|
|
|
await page.goto(captureUrl.toString(), {
|
|
waitUntil: "networkidle",
|
|
timeout: options.timeoutMs,
|
|
})
|
|
|
|
const iframeHandle = await page.waitForSelector('iframe[data-doc-iframe="true"]', {
|
|
timeout: options.timeoutMs,
|
|
})
|
|
|
|
const frame = await iframeHandle.contentFrame()
|
|
if (!frame) {
|
|
throw new Error("无法获取iframe内容")
|
|
}
|
|
|
|
await frame.waitForLoadState("domcontentloaded", { timeout: options.timeoutMs })
|
|
|
|
// Allow network to settle
|
|
await frame.waitForLoadState("networkidle", { timeout: options.timeoutMs }).catch(() => {
|
|
console.log(`[Karuo] Network idle timeout for ${pageInfo.path}, continuing...`)
|
|
})
|
|
|
|
if (pageInfo.waitForSelector) {
|
|
await frame
|
|
.waitForSelector(pageInfo.waitForSelector, {
|
|
timeout: options.timeoutMs,
|
|
})
|
|
.catch(() => {
|
|
console.log(`[Karuo] Selector timeout for ${pageInfo.path}, continuing...`)
|
|
})
|
|
}
|
|
|
|
await page.waitForTimeout(500)
|
|
|
|
const screenshot = await iframeHandle.screenshot({
|
|
type: "png",
|
|
animations: "disabled",
|
|
})
|
|
|
|
results.push({
|
|
page: pageInfo,
|
|
screenshotPng: Buffer.from(screenshot),
|
|
})
|
|
|
|
console.log(`[Karuo] Success: ${pageInfo.path}`)
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error)
|
|
console.log(`[Karuo] Error capturing ${pageInfo.path}: ${message}`)
|
|
results.push({ page: pageInfo, error: message })
|
|
} finally {
|
|
await page.close().catch(() => undefined)
|
|
}
|
|
}
|
|
|
|
return results
|
|
} finally {
|
|
await browser.close().catch(() => undefined)
|
|
}
|
|
}
|