UNPKG

summarizely-cli

Version:

YouTube summarizer that respects your existing subscriptions. No API keys required.

205 lines 7.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.VideoSummaryCache = exports.FileCache = void 0; exports.getVideoCache = getVideoCache; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const crypto_1 = __importDefault(require("crypto")); const config_1 = require("./config"); class FileCache { constructor(dir, ttl) { const config = (0, config_1.getConfig)(); this.dir = dir || config.cache.dir; this.ttl = ttl || config.cache.ttl; this.ensureCacheDir(); } ensureCacheDir() { if (!fs_1.default.existsSync(this.dir)) { fs_1.default.mkdirSync(this.dir, { recursive: true }); } } hashKey(key) { return crypto_1.default.createHash('sha256').update(key).digest('hex'); } getFilePath(key) { const hash = this.hashKey(key); const subdir = hash.substring(0, 2); const dir = path_1.default.join(this.dir, subdir); if (!fs_1.default.existsSync(dir)) { fs_1.default.mkdirSync(dir, { recursive: true }); } return path_1.default.join(dir, `${hash}.json`); } async get(key) { try { const filePath = this.getFilePath(key); if (!fs_1.default.existsSync(filePath)) { return null; } const content = fs_1.default.readFileSync(filePath, 'utf8'); const entry = JSON.parse(content); // Check expiration if (entry.expires && entry.expires < Date.now()) { await this.delete(key); return null; } return entry.value; } catch (error) { // Cache read errors should not crash the app console.error(`Cache read error for key ${key}:`, error); return null; } } async set(key, value, ttl) { try { const filePath = this.getFilePath(key); const effectiveTtl = ttl !== undefined ? ttl : this.ttl; const entry = { value, created: Date.now(), expires: effectiveTtl > 0 ? Date.now() + effectiveTtl : undefined }; fs_1.default.writeFileSync(filePath, JSON.stringify(entry, null, 2), 'utf8'); } catch (error) { // Cache write errors should not crash the app console.error(`Cache write error for key ${key}:`, error); } } async has(key) { const value = await this.get(key); return value !== null; } async delete(key) { try { const filePath = this.getFilePath(key); if (fs_1.default.existsSync(filePath)) { fs_1.default.unlinkSync(filePath); } } catch (error) { console.error(`Cache delete error for key ${key}:`, error); } } async clear() { try { if (fs_1.default.existsSync(this.dir)) { fs_1.default.rmSync(this.dir, { recursive: true, force: true }); this.ensureCacheDir(); } } catch (error) { console.error('Cache clear error:', error); } } async size() { try { let count = 0; const subdirs = fs_1.default.readdirSync(this.dir); for (const subdir of subdirs) { const subdirPath = path_1.default.join(this.dir, subdir); if (fs_1.default.statSync(subdirPath).isDirectory()) { const files = fs_1.default.readdirSync(subdirPath); count += files.filter(f => f.endsWith('.json')).length; } } return count; } catch (error) { console.error('Cache size error:', error); return 0; } } async cleanup() { try { const subdirs = fs_1.default.readdirSync(this.dir); let cleaned = 0; for (const subdir of subdirs) { const subdirPath = path_1.default.join(this.dir, subdir); if (!fs_1.default.statSync(subdirPath).isDirectory()) continue; const files = fs_1.default.readdirSync(subdirPath); for (const file of files) { if (!file.endsWith('.json')) continue; const filePath = path_1.default.join(subdirPath, file); try { const content = fs_1.default.readFileSync(filePath, 'utf8'); const entry = JSON.parse(content); if (entry.expires && entry.expires < Date.now()) { fs_1.default.unlinkSync(filePath); cleaned++; } } catch { // Remove corrupted cache files fs_1.default.unlinkSync(filePath); cleaned++; } } } if (cleaned > 0) { console.log(`Cache cleanup: removed ${cleaned} expired entries`); } } catch (error) { console.error('Cache cleanup error:', error); } } } exports.FileCache = FileCache; class VideoSummaryCache { constructor(cache) { this.cache = cache || new FileCache(); } getCacheKey(url, provider, model) { const parts = ['summary', url]; if (provider) parts.push(provider); if (model) parts.push(model); return parts.join(':'); } async getSummary(url, provider, model) { const config = (0, config_1.getConfig)(); if (!config.cache.enabled) return null; const key = this.getCacheKey(url, provider, model); return await this.cache.get(key); } async setSummary(url, summary, provider, model, ttl) { const config = (0, config_1.getConfig)(); if (!config.cache.enabled) return; const key = this.getCacheKey(url, provider, model); await this.cache.set(key, summary, ttl); } async getTranscript(url) { const config = (0, config_1.getConfig)(); if (!config.cache.enabled) return null; const key = `transcript:${url}`; return await this.cache.get(key); } async setTranscript(url, transcript, ttl) { const config = (0, config_1.getConfig)(); if (!config.cache.enabled) return; const key = `transcript:${url}`; await this.cache.set(key, transcript, ttl); } } exports.VideoSummaryCache = VideoSummaryCache; // Singleton instance let cacheInstance = null; function getVideoCache() { if (!cacheInstance) { cacheInstance = new VideoSummaryCache(); } return cacheInstance; } //# sourceMappingURL=cache.js.map