Add metadata Pinia store for ExifTool queue preview reads.
Introduce preview entry types, resolveErrorMessage, and nullcart-style resolveAxiosErrorMessage for upcoming upload API errors.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { parseMetadata } from '@uswriting/exiftool';
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import type { MetadataPreviewEntry } from '@/types/metadata/MetadataPreview';
|
||||
import { resolveErrorMessage } from '@/utils/resolveErrorMessage';
|
||||
|
||||
export const useMetadataStore = defineStore('metadata', () => {
|
||||
const previewsByKey = ref<Record<string, MetadataPreviewEntry>>({});
|
||||
|
||||
const readExifToolStdout = async (file: File): Promise<string> => {
|
||||
const result = await parseMetadata(file);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
|
||||
return result.data;
|
||||
};
|
||||
|
||||
const makeKeyFromFile = (file: File): string => `${file.name}\0${file.size}\0${file.lastModified}`;
|
||||
|
||||
const getPreview = (file: File): MetadataPreviewEntry => {
|
||||
const key = makeKeyFromFile(file);
|
||||
|
||||
return previewsByKey.value[key] ?? { status: 'idle' };
|
||||
};
|
||||
|
||||
const loadPreview = async (file: File): Promise<MetadataPreviewEntry> => {
|
||||
const key = makeKeyFromFile(file);
|
||||
|
||||
previewsByKey.value = { ...previewsByKey.value, [key]: { status: 'loading' } };
|
||||
|
||||
try {
|
||||
const output = await readExifToolStdout(file);
|
||||
|
||||
const entry: MetadataPreviewEntry = { status: 'ready', output };
|
||||
|
||||
previewsByKey.value = { ...previewsByKey.value, [key]: entry };
|
||||
|
||||
return entry;
|
||||
} catch (error) {
|
||||
const entry: MetadataPreviewEntry = {
|
||||
status: 'error',
|
||||
message: resolveErrorMessage(error, 'Could not read image metadata')
|
||||
};
|
||||
|
||||
previewsByKey.value = { ...previewsByKey.value, [key]: entry };
|
||||
|
||||
return entry;
|
||||
}
|
||||
};
|
||||
|
||||
const loadPreviews = async (files: readonly File[]): Promise<void> => {
|
||||
await Promise.all(files.map(file => loadPreview(file)));
|
||||
};
|
||||
|
||||
const clearPreview = (file: File): void => {
|
||||
const key = makeKeyFromFile(file);
|
||||
|
||||
if (!(key in previewsByKey.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const next = { ...previewsByKey.value };
|
||||
|
||||
delete next[key];
|
||||
previewsByKey.value = next;
|
||||
};
|
||||
|
||||
const clearAllPreviews = (): void => {
|
||||
previewsByKey.value = {};
|
||||
};
|
||||
|
||||
return {
|
||||
previewsByKey,
|
||||
makeKeyFromFile,
|
||||
getPreview,
|
||||
loadPreview,
|
||||
loadPreviews,
|
||||
clearPreview,
|
||||
clearAllPreviews
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user