2022-07-13 07:23:48 -05:00
|
|
|
import { ApiProperty } from '@nestjs/swagger';
|
2024-04-29 09:48:28 -04:00
|
|
|
import { PropertyLifecycle } from 'src/decorators';
|
2024-03-20 23:53:07 +01:00
|
|
|
import { AuthDto } from 'src/dtos/auth.dto';
|
|
|
|
|
import { ExifResponseDto, mapExif } from 'src/dtos/exif.dto';
|
2024-06-05 09:26:00 +02:00
|
|
|
import {
|
|
|
|
|
AssetFaceWithoutPersonResponseDto,
|
|
|
|
|
PersonWithFacesResponseDto,
|
|
|
|
|
mapFacesWithoutPerson,
|
|
|
|
|
mapPerson,
|
|
|
|
|
} from 'src/dtos/person.dto';
|
2024-03-20 23:53:07 +01:00
|
|
|
import { TagResponseDto, mapTag } from 'src/dtos/tag.dto';
|
|
|
|
|
import { UserResponseDto, mapUser } from 'src/dtos/user.dto';
|
2024-03-20 16:02:51 -05:00
|
|
|
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
|
|
|
|
import { AssetEntity, AssetType } from 'src/entities/asset.entity';
|
2024-03-20 23:53:07 +01:00
|
|
|
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
2022-06-18 17:56:36 +02:00
|
|
|
|
2023-10-14 03:46:30 +02:00
|
|
|
export class SanitizedAssetResponseDto {
|
2022-07-08 21:26:50 -05:00
|
|
|
id!: string;
|
2023-10-14 03:46:30 +02:00
|
|
|
@ApiProperty({ enumName: 'AssetTypeEnum', enum: AssetType })
|
|
|
|
|
type!: AssetType;
|
|
|
|
|
thumbhash!: string | null;
|
|
|
|
|
resized!: boolean;
|
|
|
|
|
localDateTime!: Date;
|
|
|
|
|
duration!: string;
|
|
|
|
|
livePhotoVideoId?: string | null;
|
|
|
|
|
hasMetadata!: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class AssetResponseDto extends SanitizedAssetResponseDto {
|
2022-07-08 21:26:50 -05:00
|
|
|
deviceAssetId!: string;
|
|
|
|
|
deviceId!: string;
|
2023-09-06 05:14:44 +02:00
|
|
|
ownerId!: string;
|
|
|
|
|
owner?: UserResponseDto;
|
2024-05-20 18:09:10 -04:00
|
|
|
@PropertyLifecycle({ deprecatedAt: 'v1.106.0' })
|
|
|
|
|
libraryId?: string | null;
|
2022-07-08 21:26:50 -05:00
|
|
|
originalPath!: string;
|
2023-04-11 05:23:39 -05:00
|
|
|
originalFileName!: string;
|
2023-05-29 16:05:14 +02:00
|
|
|
fileCreatedAt!: Date;
|
|
|
|
|
fileModifiedAt!: Date;
|
|
|
|
|
updatedAt!: Date;
|
2022-07-08 21:26:50 -05:00
|
|
|
isFavorite!: boolean;
|
2023-04-12 18:37:52 +03:00
|
|
|
isArchived!: boolean;
|
2023-10-06 07:01:14 +00:00
|
|
|
isTrashed!: boolean;
|
2023-09-20 13:16:33 +02:00
|
|
|
isOffline!: boolean;
|
2022-06-18 17:56:36 +02:00
|
|
|
exifInfo?: ExifResponseDto;
|
|
|
|
|
smartInfo?: SmartInfoResponseDto;
|
2023-02-06 20:47:06 -06:00
|
|
|
tags?: TagResponseDto[];
|
2023-12-05 16:43:15 +01:00
|
|
|
people?: PersonWithFacesResponseDto[];
|
2024-06-05 09:26:00 +02:00
|
|
|
unassignedFaces?: AssetFaceWithoutPersonResponseDto[];
|
2023-05-27 21:56:17 -04:00
|
|
|
/**base64 encoded sha1 hash */
|
|
|
|
|
checksum!: string;
|
2023-10-22 02:38:07 +00:00
|
|
|
stackParentId?: string | null;
|
|
|
|
|
stack?: AssetResponseDto[];
|
|
|
|
|
@ApiProperty({ type: 'integer' })
|
2023-10-26 14:19:06 +00:00
|
|
|
stackCount!: number | null;
|
2024-05-18 13:15:56 -05:00
|
|
|
duplicateId?: string | null;
|
2022-06-18 17:56:36 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-22 02:38:07 +00:00
|
|
|
export type AssetMapOptions = {
|
|
|
|
|
stripMetadata?: boolean;
|
|
|
|
|
withStack?: boolean;
|
2024-03-03 00:01:24 +01:00
|
|
|
auth?: AuthDto;
|
2023-10-22 02:38:07 +00:00
|
|
|
};
|
|
|
|
|
|
2023-12-05 16:43:15 +01:00
|
|
|
const peopleWithFaces = (faces: AssetFaceEntity[]): PersonWithFacesResponseDto[] => {
|
|
|
|
|
const result: PersonWithFacesResponseDto[] = [];
|
|
|
|
|
if (faces) {
|
2024-02-02 04:18:00 +01:00
|
|
|
for (const face of faces) {
|
2023-12-05 16:43:15 +01:00
|
|
|
if (face.person) {
|
|
|
|
|
const existingPersonEntry = result.find((item) => item.id === face.person!.id);
|
|
|
|
|
if (existingPersonEntry) {
|
|
|
|
|
existingPersonEntry.faces.push(face);
|
|
|
|
|
} else {
|
2023-12-08 15:21:29 +01:00
|
|
|
result.push({ ...mapPerson(face.person!), faces: [mapFacesWithoutPerson(face)] });
|
2023-12-05 16:43:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-02 04:18:00 +01:00
|
|
|
}
|
2023-12-05 16:43:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-22 02:38:07 +00:00
|
|
|
export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): AssetResponseDto {
|
|
|
|
|
const { stripMetadata = false, withStack = false } = options;
|
|
|
|
|
|
2023-10-14 03:46:30 +02:00
|
|
|
if (stripMetadata) {
|
2024-02-22 14:48:27 +01:00
|
|
|
const sanitizedAssetResponse: SanitizedAssetResponseDto = {
|
|
|
|
|
id: entity.id,
|
|
|
|
|
type: entity.type,
|
|
|
|
|
thumbhash: entity.thumbhash?.toString('base64') ?? null,
|
|
|
|
|
localDateTime: entity.localDateTime,
|
2024-04-02 00:56:56 -04:00
|
|
|
resized: !!entity.previewPath,
|
2024-02-22 14:48:27 +01:00
|
|
|
duration: entity.duration ?? '0:00:00.00000',
|
|
|
|
|
livePhotoVideoId: entity.livePhotoVideoId,
|
|
|
|
|
hasMetadata: false,
|
|
|
|
|
};
|
2023-10-14 03:46:30 +02:00
|
|
|
return sanitizedAssetResponse as AssetResponseDto;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 17:56:36 +02:00
|
|
|
return {
|
|
|
|
|
id: entity.id,
|
|
|
|
|
deviceAssetId: entity.deviceAssetId,
|
2023-02-19 16:44:53 +00:00
|
|
|
ownerId: entity.ownerId,
|
2023-09-06 05:14:44 +02:00
|
|
|
owner: entity.owner ? mapUser(entity.owner) : undefined,
|
2022-06-18 17:56:36 +02:00
|
|
|
deviceId: entity.deviceId,
|
2023-09-20 13:16:33 +02:00
|
|
|
libraryId: entity.libraryId,
|
2022-06-18 17:56:36 +02:00
|
|
|
type: entity.type,
|
|
|
|
|
originalPath: entity.originalPath,
|
2023-04-11 05:23:39 -05:00
|
|
|
originalFileName: entity.originalFileName,
|
2024-04-02 00:56:56 -04:00
|
|
|
resized: !!entity.previewPath,
|
2023-06-17 23:22:31 -04:00
|
|
|
thumbhash: entity.thumbhash?.toString('base64') ?? null,
|
2023-02-19 16:44:53 +00:00
|
|
|
fileCreatedAt: entity.fileCreatedAt,
|
|
|
|
|
fileModifiedAt: entity.fileModifiedAt,
|
2023-10-04 18:11:11 -04:00
|
|
|
localDateTime: entity.localDateTime,
|
2023-02-06 10:24:58 -06:00
|
|
|
updatedAt: entity.updatedAt,
|
2024-03-03 00:01:24 +01:00
|
|
|
isFavorite: options.auth?.user.id === entity.ownerId ? entity.isFavorite : false,
|
2024-05-06 22:49:56 -05:00
|
|
|
isArchived: entity.isArchived,
|
2023-10-06 07:01:14 +00:00
|
|
|
isTrashed: !!entity.deletedAt,
|
2022-06-25 19:53:06 +02:00
|
|
|
duration: entity.duration ?? '0:00:00.00000',
|
2023-10-14 03:46:30 +02:00
|
|
|
exifInfo: entity.exifInfo ? mapExif(entity.exifInfo) : undefined,
|
2022-06-18 17:56:36 +02:00
|
|
|
smartInfo: entity.smartInfo ? mapSmartInfo(entity.smartInfo) : undefined,
|
2022-11-18 23:12:54 -06:00
|
|
|
livePhotoVideoId: entity.livePhotoVideoId,
|
2022-12-05 11:56:44 -06:00
|
|
|
tags: entity.tags?.map(mapTag),
|
2023-12-05 16:43:15 +01:00
|
|
|
people: peopleWithFaces(entity.faces),
|
2024-06-05 09:26:00 +02:00
|
|
|
unassignedFaces: entity.faces?.filter((face) => !face.person).map((a) => mapFacesWithoutPerson(a)),
|
2023-05-27 21:56:17 -04:00
|
|
|
checksum: entity.checksum.toString('base64'),
|
2024-01-27 18:52:14 +00:00
|
|
|
stackParentId: withStack ? entity.stack?.primaryAssetId : undefined,
|
|
|
|
|
stack: withStack
|
|
|
|
|
? entity.stack?.assets
|
|
|
|
|
.filter((a) => a.id !== entity.stack?.primaryAssetId)
|
2024-03-03 00:01:24 +01:00
|
|
|
.map((a) => mapAsset(a, { stripMetadata, auth: options.auth }))
|
2024-01-27 18:52:14 +00:00
|
|
|
: undefined,
|
|
|
|
|
stackCount: entity.stack?.assets?.length ?? null,
|
2023-09-20 13:16:33 +02:00
|
|
|
isOffline: entity.isOffline,
|
2023-10-14 03:46:30 +02:00
|
|
|
hasMetadata: true,
|
2024-05-18 13:15:56 -05:00
|
|
|
duplicateId: entity.duplicateId,
|
2022-06-18 17:56:36 +02:00
|
|
|
};
|
|
|
|
|
}
|
2023-01-21 22:15:16 -06:00
|
|
|
|
2023-08-24 21:28:50 +02:00
|
|
|
export class MemoryLaneResponseDto {
|
2024-03-27 22:27:26 -05:00
|
|
|
@ApiProperty({ type: 'integer' })
|
2024-03-27 16:14:29 -04:00
|
|
|
yearsAgo!: number;
|
2024-03-27 22:27:26 -05:00
|
|
|
|
2023-08-24 21:28:50 +02:00
|
|
|
assets!: AssetResponseDto[];
|
|
|
|
|
}
|
2024-03-20 23:53:07 +01:00
|
|
|
|
|
|
|
|
export class SmartInfoResponseDto {
|
|
|
|
|
tags?: string[] | null;
|
|
|
|
|
objects?: string[] | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function mapSmartInfo(entity: SmartInfoEntity): SmartInfoResponseDto {
|
|
|
|
|
return {
|
|
|
|
|
tags: entity.tags,
|
|
|
|
|
objects: entity.objects,
|
|
|
|
|
};
|
|
|
|
|
}
|