UNPKG

astro-image-exif-loader

Version:

Astro content collection loader for extracting EXIF data from images

149 lines (146 loc) 8.07 kB
import * as astro from 'astro'; import { Tags } from 'exiftool-vendored'; import { Loader } from 'astro/loaders'; import { ZodTypeAny } from 'astro/zod'; type ExifToolTagKeys = keyof Tags; type ExifPresets = "location" | "camera" | "exposure" | "datetime" | "technical" | "metadata" | "basic"; type ExifPresetTagMap = { basic: Extract<ExifToolTagKeys, "FileSize" | "ImageWidth" | "ImageHeight">; camera: Extract<ExifToolTagKeys, "Make" | "Model" | "LensModel" | "Lens" | "LensID" | "LensInfo" | "LensSerialNumber" | "SerialNumber" | "BodySerialNumber" | "CameraSerialNumber" | "LensMake" | "LensSpecification" | "MaxAperture" | "MinFocalLength" | "MaxFocalLength">; exposure: Extract<ExifToolTagKeys, "ISO" | "FNumber" | "ExposureTime" | "ShutterSpeed" | "FocalLength" | "FocalLengthIn35mmFormat" | "Flash" | "WhiteBalance" | "ExposureMode" | "MeteringMode">; datetime: Extract<ExifToolTagKeys, "DateTimeOriginal" | "CreateDate" | "DateTime">; location: Extract<ExifToolTagKeys, "GPSLatitude" | "GPSLongitude" | "GPSAltitude" | "Country" | "State" | "City" | "Location" | "Sub-location" | "GPSAreaInformation" | "Country-PrimaryLocationCode" | "Province-State">; technical: Extract<ExifToolTagKeys, "ColorSpace" | "Orientation" | "Software" | "SceneType" | "SceneCaptureType">; metadata: Extract<ExifToolTagKeys, "Artist" | "Copyright" | "ImageDescription" | "Keywords" | "Title" | "Subject">; }; interface ExifDirectoryOptions { pattern: string | string[]; base?: string; } interface ExifLoaderOptions { imagesDir?: ExifDirectoryOptions; extensions?: string[]; presets?: ExifPresets[]; tags?: ExifToolTagKeys[]; excludeTags?: ExifToolTagKeys[]; extractAll?: boolean; includeRawExif?: boolean; } interface ExifCollectionDefinition<S extends ZodTypeAny = ZodTypeAny> { loader: Loader; schema: S; } type PresetsToTagUnion<PSel extends readonly ExifPresets[] | undefined> = PSel extends readonly ExifPresets[] ? ExifPresetTagMap[PSel[number]] : never; type CombinedSelectedTagElement<TSel extends readonly ExifToolTagKeys[] | undefined, PSel extends readonly ExifPresets[] | undefined> = (TSel extends readonly ExifToolTagKeys[] ? TSel[number] : never) | PresetsToTagUnion<PSel>; type MaybeUndefinedSelected<TSel extends readonly ExifToolTagKeys[] | undefined, PSel extends readonly ExifPresets[] | undefined> = [TSel] extends [undefined] ? [PSel] extends [undefined] ? undefined : ReadonlyArray<CombinedSelectedTagElement<TSel, PSel>> : ReadonlyArray<CombinedSelectedTagElement<TSel, PSel>>; interface ExifLocation { coordinates: { latitude: number; longitude: number; altitude: number | null; } | null; country: string | null; state: string | null; city: string | null; location: string | null; sublocation: string | null; gpsAreaInformation: string | null; countryCode: string | null; provinceState: string | null; } interface ExifMetadata { artist: string | null; copyright: string | null; description: string | null; keywords: string | string[] | null; rating: number | null; title: string | null; subject: string | string[] | null; } interface BaseExifData { fileName: string; mtime: string; } interface BasicExifData { fileSize: number; width: number | null; height: number | null; } interface CameraExifData { make: string | null; model: string | null; lens: string | null; } interface ExposureExifData { iso: number | string | null; aperture: number | string | null; shutterSpeed: number | string | null; focalLength: number | string | null; focalLength35mm: number | string | null; flash: number | string | null; whiteBalance: number | string | null; exposureMode: number | string | null; meteringMode: number | string | null; } interface DateTimeExifData { dateTime: string | null; } interface LocationExifData { location: ExifLocation; } interface TechnicalExifData { colorSpace: number | string | null; orientation: number | string | null; quality: number | string | null; software: string | null; sceneMode: number | string | null; } interface MetadataExifData { metadata: ExifMetadata; } interface RawExifData { rawExif: ExifMetadata; } interface CompleteExifData extends BaseExifData, BasicExifData, CameraExifData, ExposureExifData, DateTimeExifData, LocationExifData, TechnicalExifData, MetadataExifData { } type ExifData<T extends Record<string, boolean | undefined>> = BaseExifData & (T["basic"] extends false ? {} : BasicExifData) & (T["camera"] extends true ? CameraExifData : {}) & (T["exposure"] extends true ? ExposureExifData : {}) & (T["datetime"] extends true ? DateTimeExifData : {}) & (T["location"] extends true ? LocationExifData : {}) & (T["technical"] extends true ? TechnicalExifData : {}) & (T["metadata"] extends true ? MetadataExifData : {}); interface ImportedExifCollectionEntry<T = any> { id: string; collection: string; data: T; defaultImport: astro.ImageMetadata | null; } type SerializableValue<T> = T extends Date ? string : T extends { toDate(): any; } ? string : T extends (infer U)[] ? SerializableValue<U>[] : T extends { num: number; den: number; } ? number : T extends string | number | boolean ? T : string | number | boolean | null; type AllSerializedExifTags = { [K in ExifToolTagKeys]?: SerializableValue<Tags[K]> | null | undefined; }; interface BaseAlwaysFields { fileName: string; mtime: string; FileSize?: number; } type UniversalExifData = BaseAlwaysFields & AllSerializedExifTags; type RawExifShape = { rawExif?: Record<string, string | number | boolean | (string | number | boolean)[] | null | undefined>; }; type NarrowedExifData<T extends readonly ExifToolTagKeys[] | undefined, E extends readonly ExifToolTagKeys[] | undefined = undefined> = BaseAlwaysFields & (T extends readonly any[] ? E extends readonly ExifToolTagKeys[] ? Omit<Pick<AllSerializedExifTags, T[number]>, E[number]> : Pick<AllSerializedExifTags, T[number]> : T extends undefined ? {} : E extends readonly ExifToolTagKeys[] ? Omit<AllSerializedExifTags, E[number]> : AllSerializedExifTags) & RawExifShape; type ExtractAllExifData<E extends readonly ExifToolTagKeys[] | undefined = undefined> = BaseAlwaysFields & (E extends readonly ExifToolTagKeys[] ? Omit<AllSerializedExifTags, E[number]> : AllSerializedExifTags) & RawExifShape; type ExtractAllExifDataNoRaw<E extends readonly ExifToolTagKeys[] | undefined = undefined> = BaseAlwaysFields & (E extends readonly ExifToolTagKeys[] ? Omit<AllSerializedExifTags, E[number]> : AllSerializedExifTags); type NarrowedExifDataNoRaw<T extends readonly ExifToolTagKeys[] | undefined, E extends readonly ExifToolTagKeys[] | undefined = undefined> = BaseAlwaysFields & (T extends readonly any[] ? E extends readonly ExifToolTagKeys[] ? Omit<Pick<AllSerializedExifTags, T[number]>, E[number]> : Pick<AllSerializedExifTags, T[number]> : T extends undefined ? {} : E extends readonly ExifToolTagKeys[] ? Omit<AllSerializedExifTags, E[number]> : AllSerializedExifTags); declare function exifTags<T extends readonly ExifToolTagKeys[]>(...tags: T): T; type InferExifData<T> = T extends { schema: infer S; } ? S extends { _type: infer U; } ? U : S extends { shape: infer R; } ? { [K in keyof R]: any; } : unknown : unknown; export { exifTags }; export type { AllSerializedExifTags, BaseAlwaysFields, BaseExifData, BasicExifData, CameraExifData, CombinedSelectedTagElement, CompleteExifData, DateTimeExifData, ExifCollectionDefinition, ExifData, ExifDirectoryOptions, ExifLoaderOptions, ExifLocation, ExifMetadata, ExifPresetTagMap, ExifPresets, ExifToolTagKeys, ExposureExifData, ExtractAllExifData, ExtractAllExifDataNoRaw, ImportedExifCollectionEntry, InferExifData, LocationExifData, MaybeUndefinedSelected, MetadataExifData, NarrowedExifData, NarrowedExifDataNoRaw, PresetsToTagUnion, RawExifData, RawExifShape, SerializableValue, TechnicalExifData, UniversalExifData };