Initial commit with Email Import Wizard and Task Processor updates
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
import sharp from 'sharp';
|
||||
|
||||
const THUMBNAIL_WIDTH = 180;
|
||||
|
||||
@Injectable()
|
||||
export class PageCacheService {
|
||||
private readonly logger = new Logger(PageCacheService.name);
|
||||
private readonly inboxRoot: string;
|
||||
|
||||
constructor(configService: ConfigService) {
|
||||
this.inboxRoot = configService.get<string>('INBOX_DATA_DIR', '/mnt/data/inbox');
|
||||
}
|
||||
|
||||
documentDir(documentId: string): string {
|
||||
return path.join(this.inboxRoot, documentId);
|
||||
}
|
||||
|
||||
documentPdfPath(documentId: string): string {
|
||||
return path.join(this.documentDir(documentId), 'document.pdf');
|
||||
}
|
||||
|
||||
previewPath(documentId: string, page: number): string {
|
||||
return path.join(this.documentDir(documentId), `page-${page}.preview.png`);
|
||||
}
|
||||
|
||||
thumbnailPath(documentId: string, page: number): string {
|
||||
return path.join(this.documentDir(documentId), `page-${page}.thumb.png`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Übernimmt die bereits gerenderten 200-dpi-PNGs als preview.png und
|
||||
* erzeugt parallel eine kleinere thumb.png pro Seite.
|
||||
*/
|
||||
async generate(documentId: string, renderedImages: string[]): Promise<void> {
|
||||
const dir = this.documentDir(documentId);
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
|
||||
for (let i = 0; i < renderedImages.length; i++) {
|
||||
const page = i + 1;
|
||||
const src = renderedImages[i];
|
||||
const previewDest = this.previewPath(documentId, page);
|
||||
const thumbDest = this.thumbnailPath(documentId, page);
|
||||
|
||||
try {
|
||||
await fs.copyFile(src, previewDest);
|
||||
await sharp(src).resize({ width: THUMBNAIL_WIDTH }).png().toFile(thumbDest);
|
||||
} catch (err: any) {
|
||||
this.logger.warn(
|
||||
`Seiten-Cache fehlgeschlagen (${documentId} Seite ${page}): ${err.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt alle page-*.png-Dateien eines Dokuments (Original-PDF bleibt).
|
||||
*/
|
||||
async clear(documentId: string): Promise<void> {
|
||||
const dir = this.documentDir(documentId);
|
||||
let entries: string[];
|
||||
try {
|
||||
entries = await fs.readdir(dir);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const name of entries) {
|
||||
if (!/^page-\d+\.(preview|thumb)\.png$/.test(name)) continue;
|
||||
await fs.unlink(path.join(dir, name)).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verschiebt Page-Cache-Dateien nach dem Löschen einer Seite:
|
||||
* page-N.*.png weg, page-(N+1..oldPageCount) rutschen um 1 nach vorne.
|
||||
*/
|
||||
async shiftAfterPageDelete(
|
||||
documentId: string,
|
||||
deletedPage: number,
|
||||
oldPageCount: number,
|
||||
): Promise<void> {
|
||||
const dir = this.documentDir(documentId);
|
||||
await fs
|
||||
.unlink(path.join(dir, `page-${deletedPage}.thumb.png`))
|
||||
.catch(() => undefined);
|
||||
await fs
|
||||
.unlink(path.join(dir, `page-${deletedPage}.preview.png`))
|
||||
.catch(() => undefined);
|
||||
|
||||
for (let n = deletedPage + 1; n <= oldPageCount; n++) {
|
||||
for (const variant of ['thumb', 'preview'] as const) {
|
||||
const from = path.join(dir, `page-${n}.${variant}.png`);
|
||||
const to = path.join(dir, `page-${n - 1}.${variant}.png`);
|
||||
try {
|
||||
await fs.rename(from, to);
|
||||
} catch (err: any) {
|
||||
this.logger.warn(
|
||||
`Cache-Shift fehlgeschlagen (${documentId} Seite ${n} ${variant}): ${err.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async hasPreview(documentId: string, page: number): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(this.previewPath(documentId, page));
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user