Files
papercrate/frontend/src/utils/ocr.ts
T
2025-11-13 02:37:16 +01:00

147 lines
3.5 KiB
TypeScript

import { createAssetView, resolveDocumentAssetUrl } from '../asset_manager';
import type {
DocumentLike as AssetManagerDocumentLike,
DocumentVersionLike,
AssetLike as AssetManagerAssetLike,
GetAsset as AssetManagerGetAsset,
} from '../asset_manager';
const BASE_FETCH_OPTIONS = { start: 1, limit: 1 } as const;
interface DocumentVersion extends DocumentVersionLike {
download_path?: string | null;
}
export interface DocumentLike extends AssetManagerDocumentLike {
current_version?: DocumentVersion | null;
}
export type AssetLike = AssetManagerAssetLike;
export type EnsurePreviewData = (id: string | number) => Promise<DocumentLike | null | undefined>;
export type EnsureAssetUrl = (
id: string | number,
asset: AssetLike,
options?: { start?: number; limit?: number; force?: boolean },
) => Promise<AssetLike | null | undefined>;
export type GetDocumentAsset = AssetManagerGetAsset;
interface ResolveOcrTextUrlOptions {
document: DocumentLike | null;
ensurePreviewData?: EnsurePreviewData;
getDocumentAsset?: GetDocumentAsset;
ensureAssetUrl?: EnsureAssetUrl;
}
const pickAsset = (doc: DocumentLike | null | undefined, getDocumentAsset?: GetDocumentAsset): AssetLike | null => {
if (!doc || !getDocumentAsset) {
return null;
}
return getDocumentAsset(doc, 'ocr-text') || null;
};
export async function resolveOcrTextUrl({
document,
ensurePreviewData,
getDocumentAsset,
ensureAssetUrl,
}: ResolveOcrTextUrlOptions): Promise<string | null> {
if (!document?.id) {
return null;
}
let docRef = document;
let asset = pickAsset(docRef, getDocumentAsset);
if (!asset && ensurePreviewData) {
const refreshed = await ensurePreviewData(docRef.id);
if (refreshed) {
docRef = refreshed;
}
asset = pickAsset(docRef, getDocumentAsset);
}
if (!asset) {
return null;
}
const baseView = createAssetView(asset);
const hasUrl = Boolean(baseView.getPrimaryUrl());
let entry: AssetLike = asset;
if (ensureAssetUrl) {
const ensureOptions = { ...BASE_FETCH_OPTIONS, force: !hasUrl };
const ensured = await ensureAssetUrl(docRef.id!, asset, ensureOptions);
if (ensured) {
entry = ensured;
}
}
const ensuredView = createAssetView(entry);
const directUrl = ensuredView.getPrimaryUrl();
if (directUrl) {
return directUrl;
}
return (
resolveDocumentAssetUrl(docRef, 'ocr-text', {
ensureAssetUrl,
getAsset: getDocumentAsset,
ensureOptions: { ...BASE_FETCH_OPTIONS, force: true },
objectOrdinal: 1,
}) || null
);
}
export async function openOcrTextInNewTab(options: ResolveOcrTextUrlOptions): Promise<boolean> {
const popup = window.open('', '_blank');
const popupAvailable = Boolean(popup);
if (popupAvailable) {
try {
popup.opener = null;
} catch {
/* ignore */
}
}
try {
const url = await resolveOcrTextUrl(options);
if (!url) {
if (popupAvailable) {
popup.close();
}
return false;
}
if (popupAvailable) {
try {
popup.location.replace(url);
} catch {
try {
popup.location.href = url;
} catch (secondError) {
popup.close();
throw secondError;
}
}
} else {
const finalWindow = window.open(url, '_blank');
if (finalWindow) {
try {
finalWindow.opener = null;
} catch {
/* ignore */
}
}
}
return true;
} catch (error) {
if (popupAvailable) {
popup.close();
}
throw error;
}
}