From 069c68bfe4935614a9a213ef672c6691f9d487b1 Mon Sep 17 00:00:00 2001 From: Thomas <9749173+uhthomas@users.noreply.github.com> Date: Wed, 21 Jun 2023 19:50:12 +0100 Subject: [PATCH] feat: M2TS (#2896) Support the Blu-ray disc Audio-Video (BDAV) MPEG-2 Transport Stream (M2TS) format. https://en.wikipedia.org/wiki/.m2ts Fixes: #2350 --- mobile/lib/utils/files_helper.dart | 6 ++ .../immich/config/asset-upload.config.spec.ts | 5 +- .../src/immich/config/asset-upload.config.ts | 4 +- server/tsconfig.build.json | 2 +- web/src/lib/utils/asset-utils.spec.ts | 86 +++++++++++-------- web/src/lib/utils/asset-utils.ts | 18 +++- web/src/lib/utils/file-uploader.ts | 2 + 7 files changed, 79 insertions(+), 44 deletions(-) diff --git a/mobile/lib/utils/files_helper.dart b/mobile/lib/utils/files_helper.dart index e3b0c174d1..ec93cd0974 100644 --- a/mobile/lib/utils/files_helper.dart +++ b/mobile/lib/utils/files_helper.dart @@ -137,6 +137,12 @@ class FileHelper { case 'jxl': return {"type": "image", "subType": "jxl"}; + case 'mts': + return {"type": "video", "subType": "mp2t"}; + + case 'm2ts': + return {"type": "video", "subType": "mp2t"}; + default: return {"type": "unsupport", "subType": "unsupport"}; } diff --git a/server/src/immich/config/asset-upload.config.spec.ts b/server/src/immich/config/asset-upload.config.spec.ts index 388bb381c1..6978547f1e 100644 --- a/server/src/immich/config/asset-upload.config.spec.ts +++ b/server/src/immich/config/asset-upload.config.spec.ts @@ -51,7 +51,6 @@ describe('assetUploadOption', () => { for (const { mimetype, extension } of [ { mimetype: 'image/avif', extension: 'avif' }, - { mimetype: 'image/dng', extension: 'dng' }, { mimetype: 'image/gif', extension: 'gif' }, { mimetype: 'image/heic', extension: 'heic' }, { mimetype: 'image/heif', extension: 'heif' }, @@ -89,8 +88,8 @@ describe('assetUploadOption', () => { { mimetype: 'image/x-sony-sr2', extension: 'sr2' }, { mimetype: 'image/x-sony-srf', extension: 'srf' }, { mimetype: 'video/3gpp', extension: '3gp' }, - { mimetype: 'video/avi', extension: 'avi' }, - { mimetype: 'video/mov', extension: 'mov' }, + { mimetype: 'video/mp2t', extension: 'm2ts' }, + { mimetype: 'video/mp2t', extension: 'mts' }, { mimetype: 'video/mp4', extension: 'mp4' }, { mimetype: 'video/mpeg', extension: 'mpg' }, { mimetype: 'video/quicktime', extension: 'mov' }, diff --git a/server/src/immich/config/asset-upload.config.ts b/server/src/immich/config/asset-upload.config.ts index 351c5a27c6..889fabe593 100644 --- a/server/src/immich/config/asset-upload.config.ts +++ b/server/src/immich/config/asset-upload.config.ts @@ -51,7 +51,6 @@ const logger = new Logger('AssetUploadConfig'); const validMimeTypes = [ 'image/avif', - 'image/dng', 'image/gif', 'image/heic', 'image/heif', @@ -88,8 +87,7 @@ const validMimeTypes = [ 'image/x-sony-sr2', 'image/x-sony-srf', 'video/3gpp', - 'video/avi', - 'video/mov', + 'video/mp2t', 'video/mp4', 'video/mpeg', 'video/quicktime', diff --git a/server/tsconfig.build.json b/server/tsconfig.build.json index 64f86c6bd2..0d7cd0873c 100644 --- a/server/tsconfig.build.json +++ b/server/tsconfig.build.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] + "exclude": ["dist", "node_modules", "upload", "test", "**/*spec.ts"] } diff --git a/web/src/lib/utils/asset-utils.spec.ts b/web/src/lib/utils/asset-utils.spec.ts index d84e9d42b9..e458bf03d6 100644 --- a/web/src/lib/utils/asset-utils.spec.ts +++ b/web/src/lib/utils/asset-utils.spec.ts @@ -60,44 +60,58 @@ describe('get asset filename', () => { }); describe('get file mime type', () => { - for (const { extension, mimeType } of [ - { extension: '3fr', mimeType: 'image/x-hasselblad-3fr' }, - { extension: '3gp', mimeType: 'video/3gpp' }, - { extension: 'ari', mimeType: 'image/x-arriflex-ari' }, - { extension: 'arw', mimeType: 'image/x-sony-arw' }, - { extension: 'avif', mimeType: 'image/avif' }, - { extension: 'cap', mimeType: 'image/x-phaseone-cap' }, - { extension: 'cin', mimeType: 'image/x-phantom-cin' }, - { extension: 'cr2', mimeType: 'image/x-canon-cr2' }, - { extension: 'cr3', mimeType: 'image/x-canon-cr3' }, - { extension: 'crw', mimeType: 'image/x-canon-crw' }, - { extension: 'dcr', mimeType: 'image/x-kodak-dcr' }, - { extension: 'dng', mimeType: 'image/dng' }, - { extension: 'erf', mimeType: 'image/x-epson-erf' }, - { extension: 'fff', mimeType: 'image/x-hasselblad-fff' }, - { extension: 'heic', mimeType: 'image/heic' }, - { extension: 'heif', mimeType: 'image/heif' }, - { extension: 'iiq', mimeType: 'image/x-phaseone-iiq' }, - { extension: 'insp', mimeType: 'image/jpeg' }, - { extension: 'insv', mimeType: 'video/mp4' }, - { extension: 'jxl', mimeType: 'image/jxl' }, - { extension: 'k25', mimeType: 'image/x-kodak-k25' }, - { extension: 'kdc', mimeType: 'image/x-kodak-kdc' }, - { extension: 'mrw', mimeType: 'image/x-minolta-mrw' }, - { extension: 'nef', mimeType: 'image/x-nikon-nef' }, - { extension: 'orf', mimeType: 'image/x-olympus-orf' }, - { extension: 'ori', mimeType: 'image/x-olympus-ori' }, - { extension: 'pef', mimeType: 'image/x-pentax-pef' }, - { extension: 'raf', mimeType: 'image/x-fuji-raf' }, - { extension: 'raw', mimeType: 'image/x-panasonic-raw' }, - { extension: 'rwl', mimeType: 'image/x-leica-rwl' }, - { extension: 'sr2', mimeType: 'image/x-sony-sr2' }, - { extension: 'srf', mimeType: 'image/x-sony-srf' }, - { extension: 'srw', mimeType: 'image/x-samsung-srw' }, - { extension: 'x3f', mimeType: 'image/x-sigma-x3f' } + for (const { mimetype, extension } of [ + { mimetype: 'image/avif', extension: 'avif' }, + { mimetype: 'image/gif', extension: 'gif' }, + { mimetype: 'image/heic', extension: 'heic' }, + { mimetype: 'image/heif', extension: 'heif' }, + { mimetype: 'image/jpeg', extension: 'jpeg' }, + { mimetype: 'image/jpeg', extension: 'jpg' }, + { mimetype: 'image/jxl', extension: 'jxl' }, + { mimetype: 'image/png', extension: 'png' }, + { mimetype: 'image/tiff', extension: 'tiff' }, + { mimetype: 'image/webp', extension: 'webp' }, + { mimetype: 'image/x-adobe-dng', extension: 'dng' }, + { mimetype: 'image/x-arriflex-ari', extension: 'ari' }, + { mimetype: 'image/x-canon-cr2', extension: 'cr2' }, + { mimetype: 'image/x-canon-cr3', extension: 'cr3' }, + { mimetype: 'image/x-canon-crw', extension: 'crw' }, + { mimetype: 'image/x-epson-erf', extension: 'erf' }, + { mimetype: 'image/x-fuji-raf', extension: 'raf' }, + { mimetype: 'image/x-hasselblad-3fr', extension: '3fr' }, + { mimetype: 'image/x-hasselblad-fff', extension: 'fff' }, + { mimetype: 'image/x-kodak-dcr', extension: 'dcr' }, + { mimetype: 'image/x-kodak-k25', extension: 'k25' }, + { mimetype: 'image/x-kodak-kdc', extension: 'kdc' }, + { mimetype: 'image/x-leica-rwl', extension: 'rwl' }, + { mimetype: 'image/x-minolta-mrw', extension: 'mrw' }, + { mimetype: 'image/x-nikon-nef', extension: 'nef' }, + { mimetype: 'image/x-olympus-orf', extension: 'orf' }, + { mimetype: 'image/x-olympus-ori', extension: 'ori' }, + { mimetype: 'image/x-panasonic-raw', extension: 'raw' }, + { mimetype: 'image/x-pentax-pef', extension: 'pef' }, + { mimetype: 'image/x-phantom-cin', extension: 'cin' }, + { mimetype: 'image/x-phaseone-cap', extension: 'cap' }, + { mimetype: 'image/x-phaseone-iiq', extension: 'iiq' }, + { mimetype: 'image/x-samsung-srw', extension: 'srw' }, + { mimetype: 'image/x-sigma-x3f', extension: 'x3f' }, + { mimetype: 'image/x-sony-arw', extension: 'arw' }, + { mimetype: 'image/x-sony-sr2', extension: 'sr2' }, + { mimetype: 'image/x-sony-srf', extension: 'srf' }, + { mimetype: 'video/3gpp', extension: '3gp' }, + { mimetype: 'video/mp2t', extension: 'm2ts' }, + { mimetype: 'video/mp2t', extension: 'mts' }, + { mimetype: 'video/mp4', extension: 'mp4' }, + { mimetype: 'video/mpeg', extension: 'mpg' }, + { mimetype: 'video/quicktime', extension: 'mov' }, + { 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' } ]) { it(`returns the mime type for ${extension}`, () => { - expect(getFileMimeType({ name: `filename.${extension}` } as File)).toEqual(mimeType); + 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 9a93a8806a..7d0b9a7a35 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -130,6 +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', avif: 'image/avif', cap: 'image/x-phaseone-cap', cin: 'image/x-phantom-cin', @@ -137,28 +138,43 @@ export function getFileMimeType(file: File): string { cr3: 'image/x-canon-cr3', crw: 'image/x-canon-crw', dcr: 'image/x-kodak-dcr', - dng: 'image/dng', + dng: 'image/x-adobe-dng', erf: 'image/x-epson-erf', fff: 'image/x-hasselblad-fff', + flv: 'video/x-flv', + gif: 'image/gif', heic: 'image/heic', heif: 'image/heif', iiq: 'image/x-phaseone-iiq', insp: 'image/jpeg', insv: 'video/mp4', + jpeg: 'image/jpeg', + jpg: 'image/jpeg', jxl: 'image/jxl', k25: 'image/x-kodak-k25', kdc: 'image/x-kodak-kdc', + m2ts: 'video/mp2t', + mkv: 'video/x-matroska', + mov: 'video/quicktime', + mp4: 'video/mp4', + mpg: 'video/mpeg', mrw: 'image/x-minolta-mrw', + mts: 'video/mp2t', nef: 'image/x-nikon-nef', orf: 'image/x-olympus-orf', ori: 'image/x-olympus-ori', pef: 'image/x-pentax-pef', + png: 'image/png', raf: 'image/x-fuji-raf', raw: 'image/x-panasonic-raw', rwl: 'image/x-leica-rwl', sr2: 'image/x-sony-sr2', srf: 'image/x-sony-srf', srw: 'image/x-samsung-srw', + tiff: 'image/tiff', + webm: 'video/webm', + webp: 'image/webp', + wmv: 'video/x-ms-wmv', x3f: 'image/x-sigma-x3f' }; // Return the MIME type determined by the browser or the MIME type based on the file extension. diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts index 5078c40584..908aec9708 100644 --- a/web/src/lib/utils/file-uploader.ts +++ b/web/src/lib/utils/file-uploader.ts @@ -47,8 +47,10 @@ export const openFileUploadDialog = async ( '.jxl', '.k25', '.kdc', + '.m2ts', '.mov', '.mrw', + '.mts', '.nef', '.orf', '.ori',