mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(server): Fix exif data parsing (#1326)
* Trying to get exifdata working with different lib. * Got the new library working. * Addressing PR comments. * Removed not used vars and proper place for the eslint disable. * Fix time-utils to use the exiftool-vendored lib. Fixed also one test, as that would be valid. * Using filename for timestamp as well if possible. * Add new tests for time-utils. * Remember to gracefully terminate the exiftool instance when not needed. * eslint ignore... * Apperantly Dockerfile changes were not pushed. * feat(dockerfile): Tweak the Server Dockerfile * feat(server): getTimestampFromFilename should return string or undefined. * feat(server): If we don't have exifData or timestamp from filename, raise an error. * Apparently test was already right, but my local system disagrees. * More utilities for parsing and fix the timestampFromFilename. It was returning an incorrect date as the regex doesn't seem to be the best for this as files named `IMG_0115.HEIC` will want to get parsed incorrectly due to it. * feat(server/docker): Install perl as it seems to be required. * feat(server): remember to include exposureTime and focalLength in new exif data. * feat(server): Remove the parsing from filename as requested. * feat(server): Import exiftool differently in time-utils. * feat(server): Error handling when there is no exifData. * feat(server): Fixes for the error handling when there is no exifData. * feat(server): Remember to include modifyDate despite no exif. * feat(server): Remember to include model of Camera. * feat(server): Fixing up Exiftool usage. Including proper logging for it, which had to be done in wrapped fashion due to it expecting all the logging levels which NextJS logger doesn't implement. * feat(server): Do not use a wrapper for ExifTool logging. * fix merge conflicts in metadata-extractor
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							693adf8488
						
					
				
				
					commit
					dff10e89fe
				
			@@ -1,6 +1,12 @@
 | 
			
		||||
import exifr from 'exifr';
 | 
			
		||||
// This is needed as resolving for the vendored
 | 
			
		||||
// exiftool fails in tests otherwise but as it's not meant to be a requirement
 | 
			
		||||
// of a project directly I had to include the line below the comment.
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
import { exiftool } from 'exiftool-vendored.pl';
 | 
			
		||||
 | 
			
		||||
function createTimeUtils() {
 | 
			
		||||
  const floatRegex = /[+-]?([0-9]*[.])?[0-9]+/;
 | 
			
		||||
  const checkValidTimestamp = (timestamp: string): boolean => {
 | 
			
		||||
    const parsedTimestamp = Date.parse(timestamp);
 | 
			
		||||
 | 
			
		||||
@@ -19,22 +25,12 @@ function createTimeUtils() {
 | 
			
		||||
 | 
			
		||||
  const getTimestampFromExif = async (originalPath: string): Promise<string> => {
 | 
			
		||||
    try {
 | 
			
		||||
      const exifData = await exifr.parse(originalPath, {
 | 
			
		||||
        tiff: true,
 | 
			
		||||
        ifd0: true as any,
 | 
			
		||||
        ifd1: true,
 | 
			
		||||
        exif: true,
 | 
			
		||||
        gps: true,
 | 
			
		||||
        interop: true,
 | 
			
		||||
        xmp: true,
 | 
			
		||||
        icc: true,
 | 
			
		||||
        iptc: true,
 | 
			
		||||
        jfif: true,
 | 
			
		||||
        ihdr: true,
 | 
			
		||||
      });
 | 
			
		||||
      const exifData = await exiftool.read(originalPath);
 | 
			
		||||
 | 
			
		||||
      if (exifData && exifData['DateTimeOriginal']) {
 | 
			
		||||
        return exifData['DateTimeOriginal'];
 | 
			
		||||
        await exiftool.end();
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | 
			
		||||
        return exifData['DateTimeOriginal'].toString()!;
 | 
			
		||||
      } else {
 | 
			
		||||
        return new Date().toISOString();
 | 
			
		||||
      }
 | 
			
		||||
@@ -42,7 +38,17 @@ function createTimeUtils() {
 | 
			
		||||
      return new Date().toISOString();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  return { checkValidTimestamp, getTimestampFromExif };
 | 
			
		||||
 | 
			
		||||
  const parseStringToNumber = async (original: string | undefined): Promise<number | null> => {
 | 
			
		||||
    const match = original?.match(floatRegex)?.[0];
 | 
			
		||||
    if (match) {
 | 
			
		||||
      return parseFloat(match);
 | 
			
		||||
    } else {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return { checkValidTimestamp, getTimestampFromExif, parseStringToNumber };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const timeUtils = createTimeUtils();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user