@henteko/kumiki
Version:
A video generation tool that creates videos from JSON configurations
103 lines • 3.17 kB
JavaScript
import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';
import { getNarrationCacheDir } from '../utils/app-dirs.js';
import { logger } from '../utils/logger.js';
export class NarrationCacheService {
cacheDir;
constructor(cacheDir) {
this.cacheDir = cacheDir || getNarrationCacheDir();
}
async ensureCacheDir() {
await fs.mkdir(this.cacheDir, { recursive: true });
}
generateCacheKey(key) {
const content = JSON.stringify({
text: key.text,
voice: key.voice || {},
});
return crypto
.createHash('sha256')
.update(content)
.digest('hex');
}
getCachePath(key) {
const hash = this.generateCacheKey(key);
return path.join(this.cacheDir, `${hash}.wav`);
}
async exists(key) {
const cachePath = this.getCachePath(key);
try {
await fs.access(cachePath);
return true;
}
catch {
return false;
}
}
async get(key) {
const cachePath = this.getCachePath(key);
if (await this.exists(key)) {
logger.debug('Narration cache hit', {
text: key.text.substring(0, 50) + '...',
cachePath
});
return cachePath;
}
logger.debug('Narration cache miss', {
text: key.text.substring(0, 50) + '...',
cachePath
});
return null;
}
async set(key, audioPath) {
await this.ensureCacheDir();
const cachePath = this.getCachePath(key);
// Copy audio file to cache
await fs.copyFile(audioPath, cachePath);
logger.debug('Narration cached', {
text: key.text.substring(0, 50) + '...',
cachePath
});
return cachePath;
}
async clear() {
try {
const files = await fs.readdir(this.cacheDir);
await Promise.all(files
.filter(file => file.endsWith('.wav'))
.map(file => fs.unlink(path.join(this.cacheDir, file))));
logger.info('Narration cache cleared');
}
catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
}
async getCacheStats() {
try {
const files = await fs.readdir(this.cacheDir);
let totalSize = 0;
let count = 0;
for (const file of files) {
if (file.endsWith('.wav')) {
const filePath = path.join(this.cacheDir, file);
const stats = await fs.stat(filePath);
totalSize += stats.size;
count++;
}
}
return { count, size: totalSize };
}
catch (error) {
if (error.code === 'ENOENT') {
return { count: 0, size: 0 };
}
throw error;
}
}
}
// Singleton instance
export const narrationCacheService = new NarrationCacheService();
//# sourceMappingURL=narration-cache.js.map