返回 oh-my-ppt
template-thumbnail.ts
根目录 / src / main / templates / template-thumbnail.ts
1 import {
2 enqueueHtmlThumbnail,
3 enqueueHtmlThumbnails,
4 getFreshHtmlThumbnailPaths,
5 waitForHtmlThumbnailTask,
6 type HtmlThumbnailRequest
7 } from '../io/thumbnails/html-thumbnail-service'
8 import { TEMPLATE_THUMBNAIL_RESOURCE_TYPE } from '@shared/thumbnail'
9
10 const TEMPLATE_COVER_VARIANT = 'cover'
11
12 export type TemplateThumbnailEntry = {
13 templateId: string
14 pageId?: string | null
15 sourcePath?: string | null
16 width?: number
17 height?: number
18 }
19
20 function entryToRequest(entry: TemplateThumbnailEntry): HtmlThumbnailRequest | null {
21 const templateId = entry.templateId.trim()
22 const sourcePath = typeof entry.sourcePath === 'string' ? entry.sourcePath.trim() : ''
23 if (!templateId || !sourcePath) return null
24 return {
25 resourceType: TEMPLATE_THUMBNAIL_RESOURCE_TYPE,
26 resourceId: templateId,
27 variant: TEMPLATE_COVER_VARIANT,
28 sourcePath,
29 pageId: typeof entry.pageId === 'string' ? entry.pageId.trim() : '',
30 captureWidth: entry.width,
31 captureHeight: entry.height,
32 thumbnailWidth: 640,
33 thumbnailHeight:
34 entry.width && entry.height
35 ? Math.max(64, Math.round((640 * entry.height) / entry.width))
36 : undefined
37 }
38 }
39
40 function entriesToRequests(entries: TemplateThumbnailEntry[]): HtmlThumbnailRequest[] {
41 const requests: HtmlThumbnailRequest[] = []
42 for (const entry of entries) {
43 const request = entryToRequest(entry)
44 if (request) requests.push(request)
45 }
46 return requests
47 }
48
49 export async function captureTemplateCoverThumbnail(
50 entry: TemplateThumbnailEntry
51 ): Promise<string | null> {
52 const request = entryToRequest(entry)
53 if (!request) return null
54 try {
55 const task = await enqueueHtmlThumbnail(request)
56 if (task.status === 'completed') return task.thumbnailPath
57 const completed = await waitForHtmlThumbnailTask(
58 request.resourceType,
59 request.resourceId,
60 request.variant
61 )
62 return completed.thumbnailPath
63 } catch (error) {
64 console.warn('[template-thumbnail] cover capture failed', error)
65 return null
66 }
67 }
68
69 export async function warmTemplateCoverThumbnails(
70 entries: TemplateThumbnailEntry[],
71 delayMs = 300
72 ): Promise<Map<string, string>> {
73 const requests = entriesToRequests(entries)
74 let freshMap: Map<string, string>
75 try {
76 freshMap = await getFreshHtmlThumbnailPaths(requests)
77 } catch (error) {
78 console.warn('[template-thumbnail] fresh thumbnail lookup failed', error)
79 return new Map()
80 }
81
82 const missing = requests.filter((request) => !freshMap.has(request.resourceId))
83 if (missing.length > 0) {
84 void enqueueHtmlThumbnails(missing, { delayMs }).catch((error) => {
85 console.warn('[template-thumbnail] background warmup failed', error)
86 })
87 }
88 return freshMap
89 }
90
90 lines TYPESCRIPT