From 792ecc6cacb22d1a7accf2ec8feddeae1100282c Mon Sep 17 00:00:00 2001 From: Thomas <9749173+uhthomas@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:21:42 +0100 Subject: [PATCH] fix(server): add missing avi mime types and add tests (#3001) See https://github.com/immich-app/immich/pull/2952#pullrequestreview-1497194041 Fixes: #2975 --- server/src/domain/domain.constant.spec.ts | 21 +++++++ server/src/domain/domain.constant.ts | 57 ++++++++++--------- .../immich/config/asset-upload.config.spec.ts | 57 ++++++++++--------- web/src/lib/utils/asset-utils.spec.ts | 33 +---------- web/src/lib/utils/asset-utils.ts | 2 +- 5 files changed, 83 insertions(+), 87 deletions(-) create mode 100644 server/src/domain/domain.constant.spec.ts diff --git a/server/src/domain/domain.constant.spec.ts b/server/src/domain/domain.constant.spec.ts new file mode 100644 index 0000000000..25b3e781b3 --- /dev/null +++ b/server/src/domain/domain.constant.spec.ts @@ -0,0 +1,21 @@ +import { validMimeTypes } from './domain.constant'; + +describe('valid mime types', () => { + it('should be a sorted list', () => { + expect(validMimeTypes).toEqual(validMimeTypes.sort()); + }); + + it('should contain only unique values', () => { + expect(validMimeTypes).toEqual([...new Set(validMimeTypes)]); + }); + + it('should contain only image or video mime types', () => { + expect(validMimeTypes).toEqual( + validMimeTypes.filter((mimeType) => mimeType.startsWith('image/') || mimeType.startsWith('video/')), + ); + }); + + it('should contain only lowercase mime types', () => { + expect(validMimeTypes).toEqual(validMimeTypes.map((mimeType) => mimeType.toLowerCase())); + }); +}); diff --git a/server/src/domain/domain.constant.ts b/server/src/domain/domain.constant.ts index c691d7be6f..9b976faa41 100644 --- a/server/src/domain/domain.constant.ts +++ b/server/src/domain/domain.constant.ts @@ -28,16 +28,40 @@ export function assertMachineLearningEnabled() { } } -const validMimeTypes = [ +export const validMimeTypes = [ + 'image/3fr', + 'image/ari', + 'image/arw', 'image/avif', + 'image/cap', + 'image/cin', + 'image/cr2', 'image/cr3', + 'image/crw', + 'image/dcr', + 'image/dng', + 'image/erf', + 'image/fff', 'image/gif', 'image/heic', 'image/heif', + 'image/iiq', 'image/jpeg', 'image/jxl', + 'image/k25', + 'image/kdc', + 'image/mrw', + 'image/nef', + 'image/orf', + 'image/ori', + 'image/pef', 'image/png', - 'image/dng', + 'image/raf', + 'image/raw', + 'image/rwl', + 'image/sr2', + 'image/srf', + 'image/srw', 'image/tiff', 'image/webp', 'image/x-adobe-dng', @@ -67,38 +91,15 @@ const validMimeTypes = [ 'image/x-sony-arw', 'image/x-sony-sr2', 'image/x-sony-srf', - 'image/dng', - 'image/ari', - 'image/cr2', - 'image/cr3', - 'image/crw', - 'image/erf', - 'image/raf', - 'image/3fr', - 'image/fff', - 'image/dcr', - 'image/k25', - 'image/kdc', - 'image/rwl', - 'image/mrw', - 'image/nef', - 'image/orf', - 'image/ori', - 'image/raw', - 'image/pef', - 'image/cin', - 'image/cap', - 'image/iiq', - 'image/srw', 'image/x3f', - 'image/arw', - 'image/sr2', - 'image/srf', 'video/3gpp', + 'video/avi', 'video/mp2t', 'video/mp4', 'video/mpeg', + 'video/msvideo', 'video/quicktime', + 'video/vnd.avi', 'video/webm', 'video/x-flv', 'video/x-matroska', diff --git a/server/src/immich/config/asset-upload.config.spec.ts b/server/src/immich/config/asset-upload.config.spec.ts index 783cd0d75e..0eb9a31e42 100644 --- a/server/src/immich/config/asset-upload.config.spec.ts +++ b/server/src/immich/config/asset-upload.config.spec.ts @@ -50,14 +50,41 @@ describe('assetUploadOption', () => { }); for (const { mimetype, extension } of [ + // Please ensure this list is sorted. + { mimetype: 'image/3fr', extension: '3fr' }, + { mimetype: 'image/ari', extension: 'ari' }, + { mimetype: 'image/arw', extension: 'arw' }, { mimetype: 'image/avif', extension: 'avif' }, + { mimetype: 'image/cap', extension: 'cap' }, + { mimetype: 'image/cin', extension: 'cin' }, + { mimetype: 'image/cr2', extension: 'cr2' }, + { mimetype: 'image/cr3', extension: 'cr3' }, + { mimetype: 'image/crw', extension: 'crw' }, + { mimetype: 'image/dcr', extension: 'dcr' }, + { mimetype: 'image/dng', extension: 'dng' }, + { mimetype: 'image/erf', extension: 'erf' }, + { mimetype: 'image/fff', extension: 'fff' }, { mimetype: 'image/gif', extension: 'gif' }, { mimetype: 'image/heic', extension: 'heic' }, { mimetype: 'image/heif', extension: 'heif' }, + { mimetype: 'image/iiq', extension: 'iiq' }, { mimetype: 'image/jpeg', extension: 'jpeg' }, { mimetype: 'image/jpeg', extension: 'jpg' }, { mimetype: 'image/jxl', extension: 'jxl' }, + { mimetype: 'image/k25', extension: 'k25' }, + { mimetype: 'image/kdc', extension: 'kdc' }, + { mimetype: 'image/mrw', extension: 'mrw' }, + { mimetype: 'image/nef', extension: 'nef' }, + { mimetype: 'image/orf', extension: 'orf' }, + { mimetype: 'image/ori', extension: 'ori' }, + { mimetype: 'image/pef', extension: 'pef' }, { mimetype: 'image/png', extension: 'png' }, + { mimetype: 'image/raf', extension: 'raf' }, + { mimetype: 'image/raw', extension: 'raw' }, + { mimetype: 'image/rwl', extension: 'rwl' }, + { mimetype: 'image/sr2', extension: 'sr2' }, + { mimetype: 'image/srf', extension: 'srf' }, + { mimetype: 'image/srw', extension: 'srw' }, { mimetype: 'image/tiff', extension: 'tiff' }, { mimetype: 'image/webp', extension: 'webp' }, { mimetype: 'image/x-adobe-dng', extension: 'dng' }, @@ -87,40 +114,16 @@ describe('assetUploadOption', () => { { mimetype: 'image/x-sony-arw', extension: 'arw' }, { mimetype: 'image/x-sony-sr2', extension: 'sr2' }, { mimetype: 'image/x-sony-srf', extension: 'srf' }, - - { mimetype: 'image/dng', extension: 'dng' }, - { mimetype: 'image/ari', extension: 'ari' }, - { mimetype: 'image/cr2', extension: 'cr2' }, - { mimetype: 'image/cr3', extension: 'cr3' }, - { mimetype: 'image/crw', extension: 'crw' }, - { mimetype: 'image/erf', extension: 'erf' }, - { mimetype: 'image/raf', extension: 'raf' }, - { mimetype: 'image/3fr', extension: '3fr' }, - { mimetype: 'image/fff', extension: 'fff' }, - { mimetype: 'image/dcr', extension: 'dcr' }, - { mimetype: 'image/k25', extension: 'k25' }, - { mimetype: 'image/kdc', extension: 'kdc' }, - { mimetype: 'image/rwl', extension: 'rwl' }, - { mimetype: 'image/mrw', extension: 'mrw' }, - { mimetype: 'image/nef', extension: 'nef' }, - { mimetype: 'image/orf', extension: 'orf' }, - { mimetype: 'image/ori', extension: 'ori' }, - { mimetype: 'image/raw', extension: 'raw' }, - { mimetype: 'image/pef', extension: 'pef' }, - { mimetype: 'image/cin', extension: 'cin' }, - { mimetype: 'image/cap', extension: 'cap' }, - { mimetype: 'image/iiq', extension: 'iiq' }, - { mimetype: 'image/srw', extension: 'srw' }, { mimetype: 'image/x3f', extension: 'x3f' }, - { mimetype: 'image/arw', extension: 'arw' }, - { mimetype: 'image/sr2', extension: 'sr2' }, - { mimetype: 'image/srf', extension: 'srf' }, { mimetype: 'video/3gpp', extension: '3gp' }, + { mimetype: 'video/avi', extension: 'avi' }, { mimetype: 'video/mp2t', extension: 'm2ts' }, { mimetype: 'video/mp2t', extension: 'mts' }, { mimetype: 'video/mp4', extension: 'mp4' }, { mimetype: 'video/mpeg', extension: 'mpg' }, + { mimetype: 'video/msvideo', extension: 'avi' }, { mimetype: 'video/quicktime', extension: 'mov' }, + { mimetype: 'video/vnd.avi', extension: 'avi' }, { mimetype: 'video/webm', extension: 'webm' }, { mimetype: 'video/x-flv', extension: 'flv' }, { mimetype: 'video/x-matroska', extension: 'mkv' }, diff --git a/web/src/lib/utils/asset-utils.spec.ts b/web/src/lib/utils/asset-utils.spec.ts index 341b89c1aa..9105420e39 100644 --- a/web/src/lib/utils/asset-utils.spec.ts +++ b/web/src/lib/utils/asset-utils.spec.ts @@ -98,36 +98,8 @@ describe('get file mime type', () => { { mimetype: 'image/x-sony-arw', extension: 'arw' }, { mimetype: 'image/x-sony-sr2', extension: 'sr2' }, { mimetype: 'image/x-sony-srf', extension: 'srf' }, - /*** The following MIME types are allowed for upload but not returned by getFileMimeType() *** - { mimetype: 'image/dng', extension: 'dng' }, - { mimetype: 'image/ari', extension: 'ari' }, - { mimetype: 'image/cr2', extension: 'cr2' }, - { mimetype: 'image/cr3', extension: 'cr3' }, - { mimetype: 'image/crw', extension: 'crw' }, - { mimetype: 'image/erf', extension: 'erf' }, - { mimetype: 'image/raf', extension: 'raf' }, - { mimetype: 'image/3fr', extension: '3fr' }, - { mimetype: 'image/fff', extension: 'fff' }, - { mimetype: 'image/dcr', extension: 'dcr' }, - { mimetype: 'image/k25', extension: 'k25' }, - { mimetype: 'image/kdc', extension: 'kdc' }, - { mimetype: 'image/rwl', extension: 'rwl' }, - { mimetype: 'image/mrw', extension: 'mrw' }, - { mimetype: 'image/nef', extension: 'nef' }, - { mimetype: 'image/orf', extension: 'orf' }, - { mimetype: 'image/ori', extension: 'ori' }, - { mimetype: 'image/raw', extension: 'raw' }, - { mimetype: 'image/pef', extension: 'pef' }, - { mimetype: 'image/cin', extension: 'cin' }, - { mimetype: 'image/cap', extension: 'cap' }, - { mimetype: 'image/iiq', extension: 'iiq' }, - { mimetype: 'image/srw', extension: 'srw' }, - { mimetype: 'image/x3f', extension: 'x3f' }, - { mimetype: 'image/arw', extension: 'arw' }, - { mimetype: 'image/sr2', extension: 'sr2' }, - { mimetype: 'image/srf', extension: 'srf' }, -**/ { mimetype: 'video/3gpp', extension: '3gp' }, + { mimetype: 'video/avi', extension: 'avi' }, { mimetype: 'video/mp2t', extension: 'm2ts' }, { mimetype: 'video/mp2t', extension: 'mts' }, { mimetype: 'video/mp4', extension: 'mp4' }, @@ -136,8 +108,7 @@ describe('get file mime type', () => { { mimetype: 'video/webm', extension: 'webm' }, { mimetype: 'video/x-flv', extension: 'flv' }, { mimetype: 'video/x-matroska', extension: 'mkv' }, - { mimetype: 'video/x-ms-wmv', extension: 'wmv' }, - { mimetype: 'video/x-msvideo', extension: 'avi' } + { mimetype: 'video/x-ms-wmv', extension: 'wmv' } ]) { it(`returns the mime type for ${extension}`, () => { expect(getFileMimeType({ name: `filename.${extension}` } as File)).toEqual(mimetype); diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts index 7d0b9a7a35..1e4ad8066f 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -130,7 +130,7 @@ export function getFileMimeType(file: File): string { '3gp': 'video/3gpp', ari: 'image/x-arriflex-ari', arw: 'image/x-sony-arw', - avi: 'video/x-msvideo', + avi: 'video/avi', avif: 'image/avif', cap: 'image/x-phaseone-cap', cin: 'image/x-phantom-cin',