瀏覽代碼

fix: live photo uploads (#4167)

* fix: live photo uploads

* fix: format

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Jason Rasmussen 1 年之前
父節點
當前提交
f0a5d39625

+ 7 - 6
server/src/immich/api-v1/asset/asset-repository.ts

@@ -19,11 +19,14 @@ export interface AssetOwnerCheck extends AssetCheck {
   ownerId: string;
 }
 
+export type AssetCreate = Omit<
+  AssetEntity,
+  'id' | 'createdAt' | 'updatedAt' | 'owner' | 'livePhotoVideoId' | 'library'
+>;
+
 export interface IAssetRepository {
   get(id: string): Promise<AssetEntity | null>;
-  create(
-    asset: Omit<AssetEntity, 'id' | 'createdAt' | 'updatedAt' | 'ownerId' | 'libraryId' | 'livePhotoVideoId'>,
-  ): Promise<AssetEntity>;
+  create(asset: AssetCreate): Promise<AssetEntity>;
   remove(asset: AssetEntity): Promise<void>;
   getAllByUserId(userId: string, dto: AssetSearchDto): Promise<AssetEntity[]>;
   getAllByDeviceId(userId: string, deviceId: string): Promise<string[]>;
@@ -151,9 +154,7 @@ export class AssetRepository implements IAssetRepository {
     });
   }
 
-  create(
-    asset: Omit<AssetEntity, 'id' | 'createdAt' | 'updatedAt' | 'ownerId' | 'livePhotoVideoId'>,
-  ): Promise<AssetEntity> {
+  create(asset: AssetCreate): Promise<AssetEntity> {
     return this.assetRepository.save(asset);
   }
 

+ 4 - 4
server/src/immich/api-v1/asset/asset.core.ts

@@ -1,5 +1,5 @@
 import { AuthUserDto, IJobRepository, JobName, mimeTypes, UploadFile } from '@app/domain';
-import { AssetEntity, LibraryEntity, UserEntity } from '@app/infra/entities';
+import { AssetEntity } from '@app/infra/entities';
 import { parse } from 'node:path';
 import { IAssetRepository } from './asset-repository';
 import { CreateAssetDto, ImportAssetDto } from './dto/create-asset.dto';
@@ -12,14 +12,14 @@ export class AssetCore {
 
   async create(
     authUser: AuthUserDto,
-    dto: CreateAssetDto | ImportAssetDto,
+    dto: (CreateAssetDto | ImportAssetDto) & { libraryId: string },
     file: UploadFile,
     livePhotoAssetId?: string,
     sidecarPath?: string,
   ): Promise<AssetEntity> {
     const asset = await this.repository.create({
-      owner: { id: authUser.id } as UserEntity,
-      library: { id: dto.libraryId } as LibraryEntity,
+      ownerId: authUser.id,
+      libraryId: dto.libraryId,
 
       checksum: file.checksum,
       originalPath: file.originalPath,

+ 32 - 13
server/src/immich/api-v1/asset/asset.service.ts

@@ -90,22 +90,19 @@ export class AssetService {
     let livePhotoAsset: AssetEntity | null = null;
 
     try {
+      const libraryId = await this.getLibraryId(authUser, dto.libraryId);
       if (livePhotoFile) {
-        const livePhotoDto = { ...dto, assetType: AssetType.VIDEO, isVisible: false };
+        const livePhotoDto = { ...dto, assetType: AssetType.VIDEO, isVisible: false, libraryId };
         livePhotoAsset = await this.assetCore.create(authUser, livePhotoDto, livePhotoFile);
       }
 
-      if (!dto.libraryId) {
-        // No library given, fall back to default upload library
-        const defaultUploadLibrary = await this.libraryRepository.getDefaultUploadLibrary(authUser.id);
-
-        if (!defaultUploadLibrary) {
-          throw new InternalServerErrorException('Cannot find default upload library for user ' + authUser.id);
-        }
-        dto.libraryId = defaultUploadLibrary.id;
-      }
-
-      const asset = await this.assetCore.create(authUser, dto, file, livePhotoAsset?.id, sidecarFile?.originalPath);
+      const asset = await this.assetCore.create(
+        authUser,
+        { ...dto, libraryId },
+        file,
+        livePhotoAsset?.id,
+        sidecarFile?.originalPath,
+      );
 
       return { id: asset.id, duplicate: false };
     } catch (error: any) {
@@ -164,7 +161,8 @@ export class AssetService {
     };
 
     try {
-      const asset = await this.assetCore.create(authUser, dto, assetFile, undefined, dto.sidecarPath);
+      const libraryId = await this.getLibraryId(authUser, dto.libraryId);
+      const asset = await this.assetCore.create(authUser, { ...dto, libraryId }, assetFile, undefined, dto.sidecarPath);
       return { id: asset.id, duplicate: false };
     } catch (error: QueryFailedError | Error | any) {
       // handle duplicates with a success response
@@ -505,4 +503,25 @@ export class AssetService {
       }
     });
   }
+
+  private async getLibraryId(authUser: AuthUserDto, libraryId?: string) {
+    if (libraryId) {
+      return libraryId;
+    }
+
+    let library = await this.libraryRepository.getDefaultUploadLibrary(authUser.id);
+    if (!library) {
+      library = await this.libraryRepository.create({
+        ownerId: authUser.id,
+        name: 'Default Library',
+        assets: [],
+        type: LibraryType.UPLOAD,
+        importPaths: [],
+        exclusionPatterns: [],
+        isVisible: true,
+      });
+    }
+
+    return library.id;
+  }
 }