feat(image): complete reviewed generation delivery
Memind CI / Test, build, and release guards (pull_request) Successful in 2m47s

This commit is contained in:
john
2026-07-20 20:04:44 +08:00
parent fc3d27aae0
commit 4b15610aa8
42 changed files with 1764 additions and 97 deletions
+13 -3
View File
@@ -1,3 +1,4 @@
import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';
import { workspaceThumbnailRelativePath } from './mindspace-workspace-thumbnails.mjs';
@@ -329,6 +330,7 @@ function themeBackgroundLayers(signals) {
export function buildFeedThumbnailSvg(signals, options = {}) {
const coverDataUri = options.coverDataUri ?? null;
const sourceHash = String(options.sourceHash ?? '').trim();
const hasPhoto = Boolean(coverDataUri);
const useScenic = !hasPhoto && shouldUseScenicBackground(signals);
const palette = resolvePhotoPalette(signals);
@@ -371,7 +373,7 @@ export function buildFeedThumbnailSvg(signals, options = {}) {
const grainOpacity = hasPhoto ? '0.18' : '0.28';
return `<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="${FEED_WIDTH}" height="${FEED_HEIGHT}" viewBox="0 0 ${FEED_WIDTH} ${FEED_HEIGHT}">
<svg xmlns="http://www.w3.org/2000/svg" width="${FEED_WIDTH}" height="${FEED_HEIGHT}" viewBox="0 0 ${FEED_WIDTH} ${FEED_HEIGHT}"${sourceHash ? ` data-source-hash="${escapeXml(sourceHash)}"` : ''}>
<defs>
<linearGradient id="theme" x1="18%" y1="0%" x2="82%" y2="100%">
<stop offset="0%" stop-color="${escapeXml(lighten(signals.accent, 0.12))}"/>
@@ -474,14 +476,22 @@ export async function generateHtmlThumbnail(storageRoot, storageKey, html, meta
imageUrl: signals.image,
resolveAssetDataUri: meta.resolveAssetDataUri,
});
const svg = buildFeedThumbnailSvg(signals, { coverDataUri });
const sourceHash = crypto.createHash('sha256').update(String(html)).digest('hex');
const svg = buildFeedThumbnailSvg(signals, { coverDataUri, sourceHash });
await writeThumbnail(storageRoot, storageKey, svg);
return svg;
}
export async function ensureHtmlThumbnail(storageRoot, storageKey, html, meta = {}) {
const existing = await readThumbnailIfExists(storageRoot, storageKey);
if (existing && isModernFeedThumbnail(existing) && !meta.force) {
const sourceHash = crypto.createHash('sha256').update(String(html)).digest('hex');
const existingSourceHash = existing?.match(/\bdata-source-hash=["']([a-f0-9]{64})["']/i)?.[1] ?? null;
if (
existing &&
isModernFeedThumbnail(existing) &&
existingSourceHash === sourceHash &&
!meta.force
) {
return existing;
}
return generateHtmlThumbnail(storageRoot, storageKey, html, meta);