mirror of
https://github.com/immich-app/immich.git
synced 2025-11-07 15:25:20 -05:00
* refactor: asset media endpoints * refactor: mobile upload livePhoto as separate request * refactor: change mobile backup flow to use new asset upload endpoints * chore: format and analyze dart code * feat: mark motion as hidden when linked * feat: upload video portion of live photo before image portion * fix: incorrect assetApi calls in mobile code * fix: download asset --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Zack Pollard <zackpollard@ymail.com>
130 lines
2.7 KiB
TypeScript
130 lines
2.7 KiB
TypeScript
import { ApiProperty } from '@nestjs/swagger';
|
|
import { Type } from 'class-transformer';
|
|
import {
|
|
IsDateString,
|
|
IsEnum,
|
|
IsInt,
|
|
IsLatitude,
|
|
IsLongitude,
|
|
IsNotEmpty,
|
|
IsPositive,
|
|
IsString,
|
|
ValidateIf,
|
|
} from 'class-validator';
|
|
import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
|
import { AssetType } from 'src/entities/asset.entity';
|
|
import { AssetStats } from 'src/interfaces/asset.interface';
|
|
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
|
|
|
|
export class DeviceIdDto {
|
|
@IsNotEmpty()
|
|
@IsString()
|
|
deviceId!: string;
|
|
}
|
|
|
|
const hasGPS = (o: { latitude: undefined; longitude: undefined }) =>
|
|
o.latitude !== undefined || o.longitude !== undefined;
|
|
const ValidateGPS = () => ValidateIf(hasGPS);
|
|
|
|
export class UpdateAssetBase {
|
|
@ValidateBoolean({ optional: true })
|
|
isFavorite?: boolean;
|
|
|
|
@ValidateBoolean({ optional: true })
|
|
isArchived?: boolean;
|
|
|
|
@Optional()
|
|
@IsDateString()
|
|
dateTimeOriginal?: string;
|
|
|
|
@ValidateGPS()
|
|
@IsLatitude()
|
|
@IsNotEmpty()
|
|
latitude?: number;
|
|
|
|
@ValidateGPS()
|
|
@IsLongitude()
|
|
@IsNotEmpty()
|
|
longitude?: number;
|
|
}
|
|
|
|
export class AssetBulkUpdateDto extends UpdateAssetBase {
|
|
@ValidateUUID({ each: true })
|
|
ids!: string[];
|
|
|
|
@ValidateUUID({ optional: true })
|
|
stackParentId?: string;
|
|
|
|
@ValidateBoolean({ optional: true })
|
|
removeParent?: boolean;
|
|
|
|
@Optional()
|
|
duplicateId?: string | null;
|
|
}
|
|
|
|
export class UpdateAssetDto extends UpdateAssetBase {
|
|
@Optional()
|
|
@IsString()
|
|
description?: string;
|
|
}
|
|
|
|
export class RandomAssetsDto {
|
|
@Optional()
|
|
@IsInt()
|
|
@IsPositive()
|
|
@Type(() => Number)
|
|
count?: number;
|
|
}
|
|
|
|
export class AssetBulkDeleteDto extends BulkIdsDto {
|
|
@ValidateBoolean({ optional: true })
|
|
force?: boolean;
|
|
}
|
|
|
|
export class AssetIdsDto {
|
|
@ValidateUUID({ each: true })
|
|
assetIds!: string[];
|
|
}
|
|
|
|
export enum AssetJobName {
|
|
REGENERATE_THUMBNAIL = 'regenerate-thumbnail',
|
|
REFRESH_METADATA = 'refresh-metadata',
|
|
TRANSCODE_VIDEO = 'transcode-video',
|
|
}
|
|
|
|
export class AssetJobsDto extends AssetIdsDto {
|
|
@ApiProperty({ enumName: 'AssetJobName', enum: AssetJobName })
|
|
@IsEnum(AssetJobName)
|
|
name!: AssetJobName;
|
|
}
|
|
|
|
export class AssetStatsDto {
|
|
@ValidateBoolean({ optional: true })
|
|
isArchived?: boolean;
|
|
|
|
@ValidateBoolean({ optional: true })
|
|
isFavorite?: boolean;
|
|
|
|
@ValidateBoolean({ optional: true })
|
|
isTrashed?: boolean;
|
|
}
|
|
|
|
export class AssetStatsResponseDto {
|
|
@ApiProperty({ type: 'integer' })
|
|
images!: number;
|
|
|
|
@ApiProperty({ type: 'integer' })
|
|
videos!: number;
|
|
|
|
@ApiProperty({ type: 'integer' })
|
|
total!: number;
|
|
}
|
|
|
|
export const mapStats = (stats: AssetStats): AssetStatsResponseDto => {
|
|
return {
|
|
images: stats[AssetType.IMAGE],
|
|
videos: stats[AssetType.VIDEO],
|
|
total: Object.values(stats).reduce((total, value) => total + value, 0),
|
|
};
|
|
};
|