diff --git a/i18n/en.json b/i18n/en.json index b2923c89421..9b7ee261f2d 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -240,7 +240,7 @@ "storage_template_hash_verification_enabled_description": "Enables hash verification, don't disable this unless you're certain of the implications", "storage_template_migration": "Storage template migration", "storage_template_migration_description": "Apply the current {template} to previously uploaded assets", - "storage_template_migration_info": "Template changes will only apply to new assets. To retroactively apply the template to previously uploaded assets, run the {job}.", + "storage_template_migration_info": "The storage template will convert all extensions to lowercase. Template changes will only apply to new assets. To retroactively apply the template to previously uploaded assets, run the {job}.", "storage_template_migration_job": "Storage Template Migration Job", "storage_template_more_details": "For more details about this feature, refer to the Storage Template and its implications", "storage_template_onboarding_description": "When enabled, this feature will auto-organize files based on a user-defined template. Due to stability issues the feature has been turned off by default. For more information, please see the documentation.", diff --git a/server/src/services/storage-template.service.spec.ts b/server/src/services/storage-template.service.spec.ts index 0a055d0e6d6..9b5f5a483dd 100644 --- a/server/src/services/storage-template.service.spec.ts +++ b/server/src/services/storage-template.service.spec.ts @@ -105,7 +105,7 @@ describe(StorageTemplateService.name, () => { it('should migrate single moving picture', async () => { mocks.user.get.mockResolvedValue(userStub.user1); const newMotionPicturePath = `upload/library/${userStub.user1.id}/2022/2022-06-19/${assetStub.livePhotoStillAsset.id}.mp4`; - const newStillPicturePath = `upload/library/${userStub.user1.id}/2022/2022-06-19/${assetStub.livePhotoStillAsset.id}.jpeg`; + const newStillPicturePath = `upload/library/${userStub.user1.id}/2022/2022-06-19/${assetStub.livePhotoStillAsset.id}.jpg`; mocks.asset.getByIds.mockImplementation((ids) => { const assets = [assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset]; diff --git a/server/src/services/storage-template.service.ts b/server/src/services/storage-template.service.ts index ea8db9857db..53d93b709b1 100644 --- a/server/src/services/storage-template.service.ts +++ b/server/src/services/storage-template.service.ts @@ -226,10 +226,37 @@ export class StorageTemplateService extends BaseService { try { const source = asset.originalPath; - const extension = path.extname(source).split('.').pop() as string; + let extension = path.extname(source).split('.').pop() as string; const sanitized = sanitize(path.basename(filename, `.${extension}`)); + extension = extension?.toLowerCase(); const rootPath = StorageCore.getLibraryFolder({ id: asset.ownerId, storageLabel }); + switch (extension) { + case 'jpeg': + case 'jpe': { + extension = 'jpg'; + break; + } + case 'tif': { + extension = 'tiff'; + break; + } + case '3gpp': { + extension = '3gp'; + break; + } + case 'mpeg': + case 'mpe': { + extension = 'mpg'; + break; + } + case 'm2ts': + case 'm2t': { + extension = 'mts'; + break; + } + } + let albumName = null; if (this.template.needsAlbum) { const albums = await this.albumRepository.getByAssetId(asset.ownerId, asset.id);