import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; import path from 'path'; import os from 'os'; import type { ChapterFile, ChapterView, TextFragment } from '../types.ts'; const TOC_FILENAME = 'toc.links'; function looksLikeFragments(content: string): boolean { try { const parsed = JSON.parse(content); return ( Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0] === 'object' && parsed[0] !== null && 'body' in (parsed[0] as object) ); } catch { return false; } } export class Cache { private readonly base: string; constructor(basePath: string) { this.base = basePath.replace(/^~/, os.homedir()); } private chapterPath(id: number, index: number): string { return path.join(this.base, String(id), String(index)); } private tocPath(id: number): string { return path.join(this.base, String(id), TOC_FILENAME); } private ensureDir(id: number): void { const dir = path.join(this.base, String(id)); if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); } tryGetChapters(id: number, from: number, to: number): ChapterView | null { if (from > to) return null; const chapters: ChapterFile[] = []; for (let i = from; i <= to; i++) { const p = this.chapterPath(id, i); if (!existsSync(p)) return null; const content = readFileSync(p, 'utf-8'); if (content.length < 10) return null; chapters.push({ path: p, hasStyle: looksLikeFragments(content) }); } return { id, min: from, max: to, chapters }; } tryGetToc(id: number): string[] | null { const p = this.tocPath(id); if (!existsSync(p)) return null; const lines = readFileSync(p, 'utf-8') .split('\n') .map(l => l.trim()) .filter(Boolean); if (lines.length === 0) return null; return lines; } saveChapters(id: number, chapters: { index: number; content: string }[]): ChapterFile[] { this.ensureDir(id); return chapters.map(({ index, content }) => { const p = this.chapterPath(id, index); writeFileSync(p, content, 'utf-8'); return { path: p, hasStyle: looksLikeFragments(content) }; }); } saveToc(id: number, urls: string[]): void { this.ensureDir(id); writeFileSync(this.tocPath(id), urls.join('\n'), 'utf-8'); } }