ManimCat / src /utils /render-cache-workspace.ts
Bin29's picture
Sync from main: c1ef036 chore: document docker persistence volumes
94e1b2f
import fs from 'fs'
import path from 'path'
import { createHash } from 'crypto'
const RENDER_CACHE_ROOT = path.join(process.cwd(), '.studio-workspace', 'render-cache')
export interface RenderCacheWorkspace {
key: string
rootDir: string
tempDir: string
mediaDir: string
codeFile: string
}
function normalizeRenderCacheKey(renderCacheKey: string): string {
const trimmed = renderCacheKey.trim()
if (!trimmed) {
throw new Error('renderCacheKey must not be empty')
}
return trimmed
}
function toDirectoryName(renderCacheKey: string): string {
const normalized = normalizeRenderCacheKey(renderCacheKey)
const readable = normalized
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.slice(0, 48) || 'render-cache'
const digest = createHash('sha1').update(normalized).digest('hex').slice(0, 12)
return `${readable}-${digest}`
}
function ensureWorkspace(rootDir: string): void {
fs.mkdirSync(rootDir, { recursive: true })
}
export function resolveRenderCacheWorkspace(
renderCacheKey: string,
scope: 'video' | 'image',
blockIndex?: number
): RenderCacheWorkspace {
const directoryName = toDirectoryName(renderCacheKey)
const scopeSuffix =
scope === 'video'
? 'video'
: `image-${String(blockIndex ?? 0).padStart(3, '0')}`
const rootDir = path.join(RENDER_CACHE_ROOT, directoryName, scopeSuffix)
const mediaDir = path.join(rootDir, 'media')
const codeFile = path.join(rootDir, 'scene.py')
ensureWorkspace(mediaDir)
return {
key: renderCacheKey,
rootDir,
tempDir: rootDir,
mediaDir,
codeFile
}
}
export function buildClassicRenderCacheKey(
clientId: string | undefined,
outputMode: 'video' | 'image',
requestedKey?: string
): string {
const normalizedRequested = requestedKey?.trim()
if (normalizedRequested) {
return normalizedRequested
}
const normalizedClientId = clientId?.trim() || 'anonymous'
return `classic-${normalizedClientId}-${outputMode}`
}
export function buildStudioRenderCacheKey(
sessionId: string,
outputMode: 'video' | 'image',
workId?: string
): string {
const normalizedWorkId = workId?.trim()
if (normalizedWorkId) {
return `studio-${sessionId}-${outputMode}-${normalizedWorkId}`
}
return `studio-${sessionId}-${outputMode}`
}