157 lines
3.4 KiB
TypeScript
157 lines
3.4 KiB
TypeScript
import { ApiProperty } from '@nestjs/swagger';
|
|
import { UploadSessionStatus } from '@prisma/client';
|
|
import { Type } from 'class-transformer';
|
|
import {
|
|
IsInt,
|
|
IsOptional,
|
|
IsString,
|
|
IsUUID,
|
|
Matches,
|
|
Max,
|
|
Min,
|
|
MinLength,
|
|
ValidateNested,
|
|
} from 'class-validator';
|
|
|
|
export class UploadPrepareRequestDto {
|
|
@ApiProperty({
|
|
format: 'uuid',
|
|
required: false,
|
|
description:
|
|
'Optional client metadata. Authorization: Bearer <deviceAccessToken> is required and determines access.',
|
|
})
|
|
@IsOptional()
|
|
@IsUUID()
|
|
deviceId?: string;
|
|
|
|
@ApiProperty({
|
|
example:
|
|
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
})
|
|
@Matches(/^[a-f0-9]{64}$/)
|
|
sha256!: string;
|
|
|
|
@ApiProperty({ example: 'track.mp3' })
|
|
@IsString()
|
|
@Matches(/\.mp3$/i)
|
|
originalFilename!: string;
|
|
|
|
@ApiProperty({ example: 10485760 })
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(Number.MAX_SAFE_INTEGER)
|
|
sizeBytes!: number;
|
|
}
|
|
|
|
export class UploadPrepareResponseDto {
|
|
@ApiProperty({ enum: ['exists', 'upload_required'] })
|
|
status!: 'exists' | 'upload_required';
|
|
|
|
@ApiProperty({ required: false, format: 'uuid' })
|
|
uploadId?: string;
|
|
|
|
@ApiProperty({ required: false, example: 0 })
|
|
nextOffset?: number;
|
|
|
|
@ApiProperty({ required: false, format: 'uuid' })
|
|
trackId?: string;
|
|
|
|
@ApiProperty({ required: false, format: 'uuid' })
|
|
assetId?: string;
|
|
}
|
|
|
|
export class UploadSessionStatusResponseDto {
|
|
@ApiProperty({ format: 'uuid' })
|
|
uploadId!: string;
|
|
|
|
@ApiProperty({ enum: UploadSessionStatus })
|
|
status!: UploadSessionStatus;
|
|
|
|
@ApiProperty({ example: 0 })
|
|
receivedBytes!: string;
|
|
|
|
@ApiProperty({ example: 10485760 })
|
|
expectedSizeBytes!: string;
|
|
|
|
@ApiProperty({ example: 0 })
|
|
nextOffset!: string;
|
|
|
|
@ApiProperty({ required: false, example: '2026-05-28T12:00:00.000Z' })
|
|
finalizedAt?: string;
|
|
}
|
|
|
|
export class UploadFinalizeArtworkDto {
|
|
@ApiProperty({ example: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ...' })
|
|
@IsString()
|
|
@MinLength(1)
|
|
dataBase64!: string;
|
|
|
|
@ApiProperty({
|
|
example:
|
|
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
|
})
|
|
@Matches(/^[a-f0-9]{64}$/)
|
|
sha256!: string;
|
|
|
|
@ApiProperty({ enum: ['image/jpeg', 'image/png'] })
|
|
@Matches(/^image\/(jpeg|png)$/)
|
|
mimeType!: string;
|
|
|
|
@ApiProperty({ required: false, example: 512 })
|
|
@IsOptional()
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(Number.MAX_SAFE_INTEGER)
|
|
width?: number;
|
|
|
|
@ApiProperty({ required: false, example: 512 })
|
|
@IsOptional()
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(Number.MAX_SAFE_INTEGER)
|
|
height?: number;
|
|
}
|
|
|
|
export class UploadFinalizeRequestDto {
|
|
static readonly artworkMimeTypes = ['image/jpeg', 'image/png'] as const;
|
|
|
|
@ApiProperty({ example: 'Track Title' })
|
|
@IsString()
|
|
@MinLength(1)
|
|
title!: string;
|
|
|
|
@ApiProperty({ example: 'Track Artist' })
|
|
@IsString()
|
|
@MinLength(1)
|
|
artist!: string;
|
|
|
|
@ApiProperty({ required: false, example: 'Album Title' })
|
|
@IsOptional()
|
|
@IsString()
|
|
album?: string;
|
|
|
|
@ApiProperty({ required: false, example: 245000 })
|
|
@IsOptional()
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(Number.MAX_SAFE_INTEGER)
|
|
durationMs?: number;
|
|
|
|
@ApiProperty({
|
|
required: false,
|
|
type: () => UploadFinalizeArtworkDto,
|
|
})
|
|
@IsOptional()
|
|
@ValidateNested()
|
|
@Type(() => UploadFinalizeArtworkDto)
|
|
artwork?: UploadFinalizeArtworkDto;
|
|
}
|
|
|
|
export class UploadFinalizeResponseDto {
|
|
@ApiProperty({ format: 'uuid' })
|
|
trackId!: string;
|
|
|
|
@ApiProperty({ format: 'uuid' })
|
|
assetId!: string;
|
|
}
|