mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 15:11:58 +00:00
refactor(server): move files to separate table (#11861)
This commit is contained in:
parent
af3a793fe8
commit
7af6733665
32 changed files with 403 additions and 210 deletions
|
@ -6,6 +6,7 @@ import { SystemConfigCore } from 'src/cores/system-config.core';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { AssetPathType, PathType, PersonPathType } from 'src/entities/move.entity';
|
import { AssetPathType, PathType, PersonPathType } from 'src/entities/move.entity';
|
||||||
import { PersonEntity } from 'src/entities/person.entity';
|
import { PersonEntity } from 'src/entities/person.entity';
|
||||||
|
import { AssetFileType } from 'src/enum';
|
||||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
|
@ -13,6 +14,7 @@ import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
|
|
||||||
export enum StorageFolder {
|
export enum StorageFolder {
|
||||||
ENCODED_VIDEO = 'encoded-video',
|
ENCODED_VIDEO = 'encoded-video',
|
||||||
|
@ -130,12 +132,14 @@ export class StorageCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async moveAssetImage(asset: AssetEntity, pathType: GeneratedImageType, format: ImageFormat) {
|
async moveAssetImage(asset: AssetEntity, pathType: GeneratedImageType, format: ImageFormat) {
|
||||||
const { id: entityId, previewPath, thumbnailPath } = asset;
|
const { id: entityId, files } = asset;
|
||||||
|
const { thumbnailFile, previewFile } = getAssetFiles(files);
|
||||||
|
const oldFile = pathType === AssetPathType.PREVIEW ? previewFile : thumbnailFile;
|
||||||
return this.moveFile({
|
return this.moveFile({
|
||||||
entityId,
|
entityId,
|
||||||
pathType,
|
pathType,
|
||||||
oldPath: pathType === AssetPathType.PREVIEW ? previewPath : thumbnailPath,
|
oldPath: oldFile?.path || null,
|
||||||
newPath: StorageCore.getImagePath(asset, AssetPathType.THUMBNAIL, format),
|
newPath: StorageCore.getImagePath(asset, pathType, format),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,10 +289,10 @@ export class StorageCore {
|
||||||
return this.assetRepository.update({ id, originalPath: newPath });
|
return this.assetRepository.update({ id, originalPath: newPath });
|
||||||
}
|
}
|
||||||
case AssetPathType.PREVIEW: {
|
case AssetPathType.PREVIEW: {
|
||||||
return this.assetRepository.update({ id, previewPath: newPath });
|
return this.assetRepository.upsertFile({ assetId: id, type: AssetFileType.PREVIEW, path: newPath });
|
||||||
}
|
}
|
||||||
case AssetPathType.THUMBNAIL: {
|
case AssetPathType.THUMBNAIL: {
|
||||||
return this.assetRepository.update({ id, thumbnailPath: newPath });
|
return this.assetRepository.upsertFile({ assetId: id, type: AssetFileType.THUMBNAIL, path: newPath });
|
||||||
}
|
}
|
||||||
case AssetPathType.ENCODED_VIDEO: {
|
case AssetPathType.ENCODED_VIDEO: {
|
||||||
return this.assetRepository.update({ id, encodedVideoPath: newPath });
|
return this.assetRepository.update({ id, encodedVideoPath: newPath });
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
||||||
import { AssetType } from 'src/enum';
|
import { AssetType } from 'src/enum';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { mimeTypes } from 'src/utils/mime-types';
|
import { mimeTypes } from 'src/utils/mime-types';
|
||||||
|
|
||||||
export class SanitizedAssetResponseDto {
|
export class SanitizedAssetResponseDto {
|
||||||
|
@ -111,7 +112,7 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As
|
||||||
originalMimeType: mimeTypes.lookup(entity.originalFileName),
|
originalMimeType: mimeTypes.lookup(entity.originalFileName),
|
||||||
thumbhash: entity.thumbhash?.toString('base64') ?? null,
|
thumbhash: entity.thumbhash?.toString('base64') ?? null,
|
||||||
localDateTime: entity.localDateTime,
|
localDateTime: entity.localDateTime,
|
||||||
resized: !!entity.previewPath,
|
resized: !!getAssetFiles(entity.files).previewFile,
|
||||||
duration: entity.duration ?? '0:00:00.00000',
|
duration: entity.duration ?? '0:00:00.00000',
|
||||||
livePhotoVideoId: entity.livePhotoVideoId,
|
livePhotoVideoId: entity.livePhotoVideoId,
|
||||||
hasMetadata: false,
|
hasMetadata: false,
|
||||||
|
@ -130,7 +131,7 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As
|
||||||
originalPath: entity.originalPath,
|
originalPath: entity.originalPath,
|
||||||
originalFileName: entity.originalFileName,
|
originalFileName: entity.originalFileName,
|
||||||
originalMimeType: mimeTypes.lookup(entity.originalFileName),
|
originalMimeType: mimeTypes.lookup(entity.originalFileName),
|
||||||
resized: !!entity.previewPath,
|
resized: !!getAssetFiles(entity.files).previewFile,
|
||||||
thumbhash: entity.thumbhash?.toString('base64') ?? null,
|
thumbhash: entity.thumbhash?.toString('base64') ?? null,
|
||||||
fileCreatedAt: entity.fileCreatedAt,
|
fileCreatedAt: entity.fileCreatedAt,
|
||||||
fileModifiedAt: entity.fileModifiedAt,
|
fileModifiedAt: entity.fileModifiedAt,
|
||||||
|
|
38
server/src/entities/asset-files.entity.ts
Normal file
38
server/src/entities/asset-files.entity.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
|
import { AssetFileType } from 'src/enum';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
Index,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Unique,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Unique('UQ_assetId_type', ['assetId', 'type'])
|
||||||
|
@Entity('asset_files')
|
||||||
|
export class AssetFileEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id!: string;
|
||||||
|
|
||||||
|
@Index('IDX_asset_files_assetId')
|
||||||
|
@Column()
|
||||||
|
assetId!: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => AssetEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
|
||||||
|
asset?: AssetEntity;
|
||||||
|
|
||||||
|
@CreateDateColumn({ type: 'timestamptz' })
|
||||||
|
createdAt!: Date;
|
||||||
|
|
||||||
|
@UpdateDateColumn({ type: 'timestamptz' })
|
||||||
|
updatedAt!: Date;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
type!: AssetFileType;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
path!: string;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { AlbumEntity } from 'src/entities/album.entity';
|
import { AlbumEntity } from 'src/entities/album.entity';
|
||||||
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
||||||
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
||||||
import { ExifEntity } from 'src/entities/exif.entity';
|
import { ExifEntity } from 'src/entities/exif.entity';
|
||||||
import { LibraryEntity } from 'src/entities/library.entity';
|
import { LibraryEntity } from 'src/entities/library.entity';
|
||||||
|
@ -72,11 +73,8 @@ export class AssetEntity {
|
||||||
@Column()
|
@Column()
|
||||||
originalPath!: string;
|
originalPath!: string;
|
||||||
|
|
||||||
@Column({ type: 'varchar', nullable: true })
|
@OneToMany(() => AssetFileEntity, (assetFile) => assetFile.asset)
|
||||||
previewPath!: string | null;
|
files!: AssetFileEntity[];
|
||||||
|
|
||||||
@Column({ type: 'varchar', nullable: true, default: '' })
|
|
||||||
thumbnailPath!: string | null;
|
|
||||||
|
|
||||||
@Column({ type: 'bytea', nullable: true })
|
@Column({ type: 'bytea', nullable: true })
|
||||||
thumbhash!: Buffer | null;
|
thumbhash!: Buffer | null;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { AlbumUserEntity } from 'src/entities/album-user.entity';
|
||||||
import { AlbumEntity } from 'src/entities/album.entity';
|
import { AlbumEntity } from 'src/entities/album.entity';
|
||||||
import { APIKeyEntity } from 'src/entities/api-key.entity';
|
import { APIKeyEntity } from 'src/entities/api-key.entity';
|
||||||
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
||||||
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { AuditEntity } from 'src/entities/audit.entity';
|
import { AuditEntity } from 'src/entities/audit.entity';
|
||||||
|
@ -32,6 +33,7 @@ export const entities = [
|
||||||
APIKeyEntity,
|
APIKeyEntity,
|
||||||
AssetEntity,
|
AssetEntity,
|
||||||
AssetFaceEntity,
|
AssetFaceEntity,
|
||||||
|
AssetFileEntity,
|
||||||
AssetJobStatusEntity,
|
AssetJobStatusEntity,
|
||||||
AuditEntity,
|
AuditEntity,
|
||||||
ExifEntity,
|
ExifEntity,
|
||||||
|
|
|
@ -5,6 +5,11 @@ export enum AssetType {
|
||||||
OTHER = 'OTHER',
|
OTHER = 'OTHER',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AssetFileType {
|
||||||
|
PREVIEW = 'preview',
|
||||||
|
THUMBNAIL = 'thumbnail',
|
||||||
|
}
|
||||||
|
|
||||||
export enum AlbumUserRole {
|
export enum AlbumUserRole {
|
||||||
EDITOR = 'editor',
|
EDITOR = 'editor',
|
||||||
VIEWER = 'viewer',
|
VIEWER = 'viewer',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { ExifEntity } from 'src/entities/exif.entity';
|
import { ExifEntity } from 'src/entities/exif.entity';
|
||||||
import { AssetOrder, AssetType } from 'src/enum';
|
import { AssetFileType, AssetOrder, AssetType } from 'src/enum';
|
||||||
import { AssetSearchOptions, SearchExploreItem } from 'src/interfaces/search.interface';
|
import { AssetSearchOptions, SearchExploreItem } from 'src/interfaces/search.interface';
|
||||||
import { Paginated, PaginationOptions } from 'src/utils/pagination';
|
import { Paginated, PaginationOptions } from 'src/utils/pagination';
|
||||||
import { FindOptionsOrder, FindOptionsRelations, FindOptionsSelect } from 'typeorm';
|
import { FindOptionsOrder, FindOptionsRelations, FindOptionsSelect } from 'typeorm';
|
||||||
|
@ -191,4 +191,5 @@ export interface IAssetRepository {
|
||||||
getDuplicates(options: AssetBuilderOptions): Promise<AssetEntity[]>;
|
getDuplicates(options: AssetBuilderOptions): Promise<AssetEntity[]>;
|
||||||
getAllForUserFullSync(options: AssetFullSyncOptions): Promise<AssetEntity[]>;
|
getAllForUserFullSync(options: AssetFullSyncOptions): Promise<AssetEntity[]>;
|
||||||
getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]>;
|
getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]>;
|
||||||
|
upsertFile(options: { assetId: string; type: AssetFileType; path: string }): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
34
server/src/migrations/1724101822106-AddAssetFilesTable.ts
Normal file
34
server/src/migrations/1724101822106-AddAssetFilesTable.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class AddAssetFilesTable1724101822106 implements MigrationInterface {
|
||||||
|
name = 'AddAssetFilesTable1724101822106'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TABLE "asset_files" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "assetId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "type" character varying NOT NULL, "path" character varying NOT NULL, CONSTRAINT "UQ_assetId_type" UNIQUE ("assetId", "type"), CONSTRAINT "PK_c41dc3e9ef5e1c57ca5a08a0004" PRIMARY KEY ("id"))`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_asset_files_assetId" ON "asset_files" ("assetId") `);
|
||||||
|
await queryRunner.query(`ALTER TABLE "asset_files" ADD CONSTRAINT "FK_e3e103a5f1d8bc8402999286040" FOREIGN KEY ("assetId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
|
||||||
|
|
||||||
|
// preview path migration
|
||||||
|
await queryRunner.query(`INSERT INTO "asset_files" ("assetId", "type", "path") SELECT "id", 'preview', "previewPath" FROM "assets" WHERE "previewPath" IS NOT NULL AND "previewPath" != ''`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "previewPath"`);
|
||||||
|
|
||||||
|
// thumbnail path migration
|
||||||
|
await queryRunner.query(`INSERT INTO "asset_files" ("assetId", "type", "path") SELECT "id", 'thumbnail', "thumbnailPath" FROM "assets" WHERE "thumbnailPath" IS NOT NULL AND "thumbnailPath" != ''`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "thumbnailPath"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// undo preview path migration
|
||||||
|
await queryRunner.query(`ALTER TABLE "assets" ADD "previewPath" character varying`);
|
||||||
|
await queryRunner.query(`UPDATE "assets" SET "previewPath" = "asset_files".path FROM "asset_files" WHERE "assets".id = "asset_files".assetId AND "asset_files".type = 'preview'`);
|
||||||
|
|
||||||
|
// undo thumbnail path migration
|
||||||
|
await queryRunner.query(`ALTER TABLE "assets" ADD "thumbnailPath" character varying DEFAULT ''`);
|
||||||
|
await queryRunner.query(`UPDATE "assets" SET "thumbnailPath" = "asset_files".path FROM "asset_files" WHERE "assets".id = "asset_files".assetId AND "asset_files".type = 'thumbnail'`);
|
||||||
|
|
||||||
|
await queryRunner.query(`ALTER TABLE "asset_files" DROP CONSTRAINT "FK_e3e103a5f1d8bc8402999286040"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_asset_files_assetId"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "asset_files"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,8 +9,6 @@ SELECT
|
||||||
"entity"."deviceId" AS "entity_deviceId",
|
"entity"."deviceId" AS "entity_deviceId",
|
||||||
"entity"."type" AS "entity_type",
|
"entity"."type" AS "entity_type",
|
||||||
"entity"."originalPath" AS "entity_originalPath",
|
"entity"."originalPath" AS "entity_originalPath",
|
||||||
"entity"."previewPath" AS "entity_previewPath",
|
|
||||||
"entity"."thumbnailPath" AS "entity_thumbnailPath",
|
|
||||||
"entity"."thumbhash" AS "entity_thumbhash",
|
"entity"."thumbhash" AS "entity_thumbhash",
|
||||||
"entity"."encodedVideoPath" AS "entity_encodedVideoPath",
|
"entity"."encodedVideoPath" AS "entity_encodedVideoPath",
|
||||||
"entity"."createdAt" AS "entity_createdAt",
|
"entity"."createdAt" AS "entity_createdAt",
|
||||||
|
@ -59,16 +57,22 @@ SELECT
|
||||||
"exifInfo"."colorspace" AS "exifInfo_colorspace",
|
"exifInfo"."colorspace" AS "exifInfo_colorspace",
|
||||||
"exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
|
"exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
|
||||||
"exifInfo"."rating" AS "exifInfo_rating",
|
"exifInfo"."rating" AS "exifInfo_rating",
|
||||||
"exifInfo"."fps" AS "exifInfo_fps"
|
"exifInfo"."fps" AS "exifInfo_fps",
|
||||||
|
"files"."id" AS "files_id",
|
||||||
|
"files"."assetId" AS "files_assetId",
|
||||||
|
"files"."createdAt" AS "files_createdAt",
|
||||||
|
"files"."updatedAt" AS "files_updatedAt",
|
||||||
|
"files"."type" AS "files_type",
|
||||||
|
"files"."path" AS "files_path"
|
||||||
FROM
|
FROM
|
||||||
"assets" "entity"
|
"assets" "entity"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "entity"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "entity"."id"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "entity"."id"
|
||||||
WHERE
|
WHERE
|
||||||
(
|
(
|
||||||
"entity"."ownerId" IN ($1)
|
"entity"."ownerId" IN ($1)
|
||||||
AND "entity"."isVisible" = true
|
AND "entity"."isVisible" = true
|
||||||
AND "entity"."isArchived" = false
|
AND "entity"."isArchived" = false
|
||||||
AND "entity"."previewPath" IS NOT NULL
|
|
||||||
AND EXTRACT(
|
AND EXTRACT(
|
||||||
DAY
|
DAY
|
||||||
FROM
|
FROM
|
||||||
|
@ -93,8 +97,6 @@ SELECT
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -129,8 +131,6 @@ SELECT
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -216,8 +216,6 @@ SELECT
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."deviceId" AS "bd93d5747511a4dad4923546c51365bf1a803774_deviceId",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."deviceId" AS "bd93d5747511a4dad4923546c51365bf1a803774_deviceId",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."type" AS "bd93d5747511a4dad4923546c51365bf1a803774_type",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."type" AS "bd93d5747511a4dad4923546c51365bf1a803774_type",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."originalPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_originalPath",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."originalPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_originalPath",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."previewPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_previewPath",
|
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."thumbnailPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_thumbnailPath",
|
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."thumbhash" AS "bd93d5747511a4dad4923546c51365bf1a803774_thumbhash",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."thumbhash" AS "bd93d5747511a4dad4923546c51365bf1a803774_thumbhash",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."encodedVideoPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_encodedVideoPath",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."encodedVideoPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_encodedVideoPath",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."createdAt" AS "bd93d5747511a4dad4923546c51365bf1a803774_createdAt",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."createdAt" AS "bd93d5747511a4dad4923546c51365bf1a803774_createdAt",
|
||||||
|
@ -237,7 +235,13 @@ SELECT
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."originalFileName" AS "bd93d5747511a4dad4923546c51365bf1a803774_originalFileName",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."originalFileName" AS "bd93d5747511a4dad4923546c51365bf1a803774_originalFileName",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."sidecarPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_sidecarPath",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."sidecarPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_sidecarPath",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."stackId" AS "bd93d5747511a4dad4923546c51365bf1a803774_stackId",
|
"bd93d5747511a4dad4923546c51365bf1a803774"."stackId" AS "bd93d5747511a4dad4923546c51365bf1a803774_stackId",
|
||||||
"bd93d5747511a4dad4923546c51365bf1a803774"."duplicateId" AS "bd93d5747511a4dad4923546c51365bf1a803774_duplicateId"
|
"bd93d5747511a4dad4923546c51365bf1a803774"."duplicateId" AS "bd93d5747511a4dad4923546c51365bf1a803774_duplicateId",
|
||||||
|
"AssetEntity__AssetEntity_files"."id" AS "AssetEntity__AssetEntity_files_id",
|
||||||
|
"AssetEntity__AssetEntity_files"."assetId" AS "AssetEntity__AssetEntity_files_assetId",
|
||||||
|
"AssetEntity__AssetEntity_files"."createdAt" AS "AssetEntity__AssetEntity_files_createdAt",
|
||||||
|
"AssetEntity__AssetEntity_files"."updatedAt" AS "AssetEntity__AssetEntity_files_updatedAt",
|
||||||
|
"AssetEntity__AssetEntity_files"."type" AS "AssetEntity__AssetEntity_files_type",
|
||||||
|
"AssetEntity__AssetEntity_files"."path" AS "AssetEntity__AssetEntity_files_path"
|
||||||
FROM
|
FROM
|
||||||
"assets" "AssetEntity"
|
"assets" "AssetEntity"
|
||||||
LEFT JOIN "exif" "AssetEntity__AssetEntity_exifInfo" ON "AssetEntity__AssetEntity_exifInfo"."assetId" = "AssetEntity"."id"
|
LEFT JOIN "exif" "AssetEntity__AssetEntity_exifInfo" ON "AssetEntity__AssetEntity_exifInfo"."assetId" = "AssetEntity"."id"
|
||||||
|
@ -248,6 +252,7 @@ FROM
|
||||||
LEFT JOIN "person" "8258e303a73a72cf6abb13d73fb592dde0d68280" ON "8258e303a73a72cf6abb13d73fb592dde0d68280"."id" = "AssetEntity__AssetEntity_faces"."personId"
|
LEFT JOIN "person" "8258e303a73a72cf6abb13d73fb592dde0d68280" ON "8258e303a73a72cf6abb13d73fb592dde0d68280"."id" = "AssetEntity__AssetEntity_faces"."personId"
|
||||||
LEFT JOIN "asset_stack" "AssetEntity__AssetEntity_stack" ON "AssetEntity__AssetEntity_stack"."id" = "AssetEntity"."stackId"
|
LEFT JOIN "asset_stack" "AssetEntity__AssetEntity_stack" ON "AssetEntity__AssetEntity_stack"."id" = "AssetEntity"."stackId"
|
||||||
LEFT JOIN "assets" "bd93d5747511a4dad4923546c51365bf1a803774" ON "bd93d5747511a4dad4923546c51365bf1a803774"."stackId" = "AssetEntity__AssetEntity_stack"."id"
|
LEFT JOIN "assets" "bd93d5747511a4dad4923546c51365bf1a803774" ON "bd93d5747511a4dad4923546c51365bf1a803774"."stackId" = "AssetEntity__AssetEntity_stack"."id"
|
||||||
|
LEFT JOIN "asset_files" "AssetEntity__AssetEntity_files" ON "AssetEntity__AssetEntity_files"."assetId" = "AssetEntity"."id"
|
||||||
WHERE
|
WHERE
|
||||||
(("AssetEntity"."id" IN ($1)))
|
(("AssetEntity"."id" IN ($1)))
|
||||||
|
|
||||||
|
@ -298,8 +303,6 @@ FROM
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -397,8 +400,6 @@ SELECT
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -452,8 +453,6 @@ SELECT
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -525,8 +524,6 @@ SELECT
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -581,8 +578,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -603,6 +598,12 @@ SELECT
|
||||||
"asset"."sidecarPath" AS "asset_sidecarPath",
|
"asset"."sidecarPath" AS "asset_sidecarPath",
|
||||||
"asset"."stackId" AS "asset_stackId",
|
"asset"."stackId" AS "asset_stackId",
|
||||||
"asset"."duplicateId" AS "asset_duplicateId",
|
"asset"."duplicateId" AS "asset_duplicateId",
|
||||||
|
"files"."id" AS "files_id",
|
||||||
|
"files"."assetId" AS "files_assetId",
|
||||||
|
"files"."createdAt" AS "files_createdAt",
|
||||||
|
"files"."updatedAt" AS "files_updatedAt",
|
||||||
|
"files"."type" AS "files_type",
|
||||||
|
"files"."path" AS "files_path",
|
||||||
"exifInfo"."assetId" AS "exifInfo_assetId",
|
"exifInfo"."assetId" AS "exifInfo_assetId",
|
||||||
"exifInfo"."description" AS "exifInfo_description",
|
"exifInfo"."description" AS "exifInfo_description",
|
||||||
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
||||||
|
@ -642,8 +643,6 @@ SELECT
|
||||||
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
||||||
"stackedAssets"."type" AS "stackedAssets_type",
|
"stackedAssets"."type" AS "stackedAssets_type",
|
||||||
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
||||||
"stackedAssets"."previewPath" AS "stackedAssets_previewPath",
|
|
||||||
"stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
|
|
||||||
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
||||||
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
||||||
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
||||||
|
@ -666,6 +665,7 @@ SELECT
|
||||||
"stackedAssets"."duplicateId" AS "stackedAssets_duplicateId"
|
"stackedAssets"."duplicateId" AS "stackedAssets_duplicateId"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
||||||
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
||||||
|
@ -692,6 +692,7 @@ SELECT
|
||||||
)::timestamptz AS "timeBucket"
|
)::timestamptz AS "timeBucket"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
||||||
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
||||||
|
@ -723,8 +724,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -745,6 +744,12 @@ SELECT
|
||||||
"asset"."sidecarPath" AS "asset_sidecarPath",
|
"asset"."sidecarPath" AS "asset_sidecarPath",
|
||||||
"asset"."stackId" AS "asset_stackId",
|
"asset"."stackId" AS "asset_stackId",
|
||||||
"asset"."duplicateId" AS "asset_duplicateId",
|
"asset"."duplicateId" AS "asset_duplicateId",
|
||||||
|
"files"."id" AS "files_id",
|
||||||
|
"files"."assetId" AS "files_assetId",
|
||||||
|
"files"."createdAt" AS "files_createdAt",
|
||||||
|
"files"."updatedAt" AS "files_updatedAt",
|
||||||
|
"files"."type" AS "files_type",
|
||||||
|
"files"."path" AS "files_path",
|
||||||
"exifInfo"."assetId" AS "exifInfo_assetId",
|
"exifInfo"."assetId" AS "exifInfo_assetId",
|
||||||
"exifInfo"."description" AS "exifInfo_description",
|
"exifInfo"."description" AS "exifInfo_description",
|
||||||
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
||||||
|
@ -784,8 +789,6 @@ SELECT
|
||||||
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
||||||
"stackedAssets"."type" AS "stackedAssets_type",
|
"stackedAssets"."type" AS "stackedAssets_type",
|
||||||
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
||||||
"stackedAssets"."previewPath" AS "stackedAssets_previewPath",
|
|
||||||
"stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
|
|
||||||
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
||||||
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
||||||
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
||||||
|
@ -808,6 +811,7 @@ SELECT
|
||||||
"stackedAssets"."duplicateId" AS "stackedAssets_duplicateId"
|
"stackedAssets"."duplicateId" AS "stackedAssets_duplicateId"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
||||||
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
||||||
|
@ -841,8 +845,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -863,6 +865,12 @@ SELECT
|
||||||
"asset"."sidecarPath" AS "asset_sidecarPath",
|
"asset"."sidecarPath" AS "asset_sidecarPath",
|
||||||
"asset"."stackId" AS "asset_stackId",
|
"asset"."stackId" AS "asset_stackId",
|
||||||
"asset"."duplicateId" AS "asset_duplicateId",
|
"asset"."duplicateId" AS "asset_duplicateId",
|
||||||
|
"files"."id" AS "files_id",
|
||||||
|
"files"."assetId" AS "files_assetId",
|
||||||
|
"files"."createdAt" AS "files_createdAt",
|
||||||
|
"files"."updatedAt" AS "files_updatedAt",
|
||||||
|
"files"."type" AS "files_type",
|
||||||
|
"files"."path" AS "files_path",
|
||||||
"exifInfo"."assetId" AS "exifInfo_assetId",
|
"exifInfo"."assetId" AS "exifInfo_assetId",
|
||||||
"exifInfo"."description" AS "exifInfo_description",
|
"exifInfo"."description" AS "exifInfo_description",
|
||||||
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
||||||
|
@ -902,8 +910,6 @@ SELECT
|
||||||
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
||||||
"stackedAssets"."type" AS "stackedAssets_type",
|
"stackedAssets"."type" AS "stackedAssets_type",
|
||||||
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
||||||
"stackedAssets"."previewPath" AS "stackedAssets_previewPath",
|
|
||||||
"stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
|
|
||||||
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
||||||
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
||||||
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
||||||
|
@ -926,6 +932,7 @@ SELECT
|
||||||
"stackedAssets"."duplicateId" AS "stackedAssets_duplicateId"
|
"stackedAssets"."duplicateId" AS "stackedAssets_duplicateId"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
||||||
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id"
|
||||||
|
@ -957,6 +964,7 @@ SELECT DISTINCT
|
||||||
c.city AS "value"
|
c.city AS "value"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
INNER JOIN "exif" "e" ON "asset"."id" = e."assetId"
|
INNER JOIN "exif" "e" ON "asset"."id" = e."assetId"
|
||||||
INNER JOIN "cities" "c" ON c.city = "e"."city"
|
INNER JOIN "cities" "c" ON c.city = "e"."city"
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -987,6 +995,7 @@ SELECT DISTINCT
|
||||||
unnest("si"."tags") AS "value"
|
unnest("si"."tags") AS "value"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
INNER JOIN "smart_info" "si" ON "asset"."id" = si."assetId"
|
INNER JOIN "smart_info" "si" ON "asset"."id" = si."assetId"
|
||||||
INNER JOIN "random_tags" "t" ON "si"."tags" @> ARRAY[t.tag]
|
INNER JOIN "random_tags" "t" ON "si"."tags" @> ARRAY[t.tag]
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -1009,8 +1018,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -1031,6 +1038,12 @@ SELECT
|
||||||
"asset"."sidecarPath" AS "asset_sidecarPath",
|
"asset"."sidecarPath" AS "asset_sidecarPath",
|
||||||
"asset"."stackId" AS "asset_stackId",
|
"asset"."stackId" AS "asset_stackId",
|
||||||
"asset"."duplicateId" AS "asset_duplicateId",
|
"asset"."duplicateId" AS "asset_duplicateId",
|
||||||
|
"files"."id" AS "files_id",
|
||||||
|
"files"."assetId" AS "files_assetId",
|
||||||
|
"files"."createdAt" AS "files_createdAt",
|
||||||
|
"files"."updatedAt" AS "files_updatedAt",
|
||||||
|
"files"."type" AS "files_type",
|
||||||
|
"files"."path" AS "files_path",
|
||||||
"exifInfo"."assetId" AS "exifInfo_assetId",
|
"exifInfo"."assetId" AS "exifInfo_assetId",
|
||||||
"exifInfo"."description" AS "exifInfo_description",
|
"exifInfo"."description" AS "exifInfo_description",
|
||||||
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
||||||
|
@ -1065,6 +1078,7 @@ SELECT
|
||||||
"stack"."primaryAssetId" AS "stack_primaryAssetId"
|
"stack"."primaryAssetId" AS "stack_primaryAssetId"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -1086,8 +1100,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -1108,6 +1120,12 @@ SELECT
|
||||||
"asset"."sidecarPath" AS "asset_sidecarPath",
|
"asset"."sidecarPath" AS "asset_sidecarPath",
|
||||||
"asset"."stackId" AS "asset_stackId",
|
"asset"."stackId" AS "asset_stackId",
|
||||||
"asset"."duplicateId" AS "asset_duplicateId",
|
"asset"."duplicateId" AS "asset_duplicateId",
|
||||||
|
"files"."id" AS "files_id",
|
||||||
|
"files"."assetId" AS "files_assetId",
|
||||||
|
"files"."createdAt" AS "files_createdAt",
|
||||||
|
"files"."updatedAt" AS "files_updatedAt",
|
||||||
|
"files"."type" AS "files_type",
|
||||||
|
"files"."path" AS "files_path",
|
||||||
"exifInfo"."assetId" AS "exifInfo_assetId",
|
"exifInfo"."assetId" AS "exifInfo_assetId",
|
||||||
"exifInfo"."description" AS "exifInfo_description",
|
"exifInfo"."description" AS "exifInfo_description",
|
||||||
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
|
||||||
|
@ -1142,9 +1160,34 @@ SELECT
|
||||||
"stack"."primaryAssetId" AS "stack_primaryAssetId"
|
"stack"."primaryAssetId" AS "stack_primaryAssetId"
|
||||||
FROM
|
FROM
|
||||||
"assets" "asset"
|
"assets" "asset"
|
||||||
|
LEFT JOIN "asset_files" "files" ON "files"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id"
|
||||||
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId"
|
||||||
WHERE
|
WHERE
|
||||||
"asset"."isVisible" = true
|
"asset"."isVisible" = true
|
||||||
AND "asset"."ownerId" IN ($1)
|
AND "asset"."ownerId" IN ($1)
|
||||||
AND "asset"."updatedAt" > $2
|
AND "asset"."updatedAt" > $2
|
||||||
|
|
||||||
|
-- AssetRepository.upsertFile
|
||||||
|
INSERT INTO
|
||||||
|
"asset_files" (
|
||||||
|
"id",
|
||||||
|
"assetId",
|
||||||
|
"createdAt",
|
||||||
|
"updatedAt",
|
||||||
|
"type",
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(DEFAULT, $1, DEFAULT, DEFAULT, $2, $3)
|
||||||
|
ON CONFLICT ("assetId", "type") DO
|
||||||
|
UPDATE
|
||||||
|
SET
|
||||||
|
"assetId" = EXCLUDED."assetId",
|
||||||
|
"type" = EXCLUDED."type",
|
||||||
|
"path" = EXCLUDED."path",
|
||||||
|
"updatedAt" = DEFAULT
|
||||||
|
RETURNING
|
||||||
|
"id",
|
||||||
|
"createdAt",
|
||||||
|
"updatedAt"
|
||||||
|
|
|
@ -157,8 +157,6 @@ FROM
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."deviceId" AS "AssetFaceEntity__AssetFaceEntity_asset_deviceId",
|
"AssetFaceEntity__AssetFaceEntity_asset"."deviceId" AS "AssetFaceEntity__AssetFaceEntity_asset_deviceId",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."type" AS "AssetFaceEntity__AssetFaceEntity_asset_type",
|
"AssetFaceEntity__AssetFaceEntity_asset"."type" AS "AssetFaceEntity__AssetFaceEntity_asset_type",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."originalPath" AS "AssetFaceEntity__AssetFaceEntity_asset_originalPath",
|
"AssetFaceEntity__AssetFaceEntity_asset"."originalPath" AS "AssetFaceEntity__AssetFaceEntity_asset_originalPath",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."previewPath" AS "AssetFaceEntity__AssetFaceEntity_asset_previewPath",
|
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."thumbnailPath" AS "AssetFaceEntity__AssetFaceEntity_asset_thumbnailPath",
|
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."thumbhash" AS "AssetFaceEntity__AssetFaceEntity_asset_thumbhash",
|
"AssetFaceEntity__AssetFaceEntity_asset"."thumbhash" AS "AssetFaceEntity__AssetFaceEntity_asset_thumbhash",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."encodedVideoPath" AS "AssetFaceEntity__AssetFaceEntity_asset_encodedVideoPath",
|
"AssetFaceEntity__AssetFaceEntity_asset"."encodedVideoPath" AS "AssetFaceEntity__AssetFaceEntity_asset_encodedVideoPath",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."createdAt" AS "AssetFaceEntity__AssetFaceEntity_asset_createdAt",
|
"AssetFaceEntity__AssetFaceEntity_asset"."createdAt" AS "AssetFaceEntity__AssetFaceEntity_asset_createdAt",
|
||||||
|
@ -255,8 +253,6 @@ FROM
|
||||||
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
"AssetEntity"."deviceId" AS "AssetEntity_deviceId",
|
||||||
"AssetEntity"."type" AS "AssetEntity_type",
|
"AssetEntity"."type" AS "AssetEntity_type",
|
||||||
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
"AssetEntity"."originalPath" AS "AssetEntity_originalPath",
|
||||||
"AssetEntity"."previewPath" AS "AssetEntity_previewPath",
|
|
||||||
"AssetEntity"."thumbnailPath" AS "AssetEntity_thumbnailPath",
|
|
||||||
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
"AssetEntity"."thumbhash" AS "AssetEntity_thumbhash",
|
||||||
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
"AssetEntity"."encodedVideoPath" AS "AssetEntity_encodedVideoPath",
|
||||||
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
"AssetEntity"."createdAt" AS "AssetEntity_createdAt",
|
||||||
|
@ -386,8 +382,6 @@ SELECT
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."deviceId" AS "AssetFaceEntity__AssetFaceEntity_asset_deviceId",
|
"AssetFaceEntity__AssetFaceEntity_asset"."deviceId" AS "AssetFaceEntity__AssetFaceEntity_asset_deviceId",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."type" AS "AssetFaceEntity__AssetFaceEntity_asset_type",
|
"AssetFaceEntity__AssetFaceEntity_asset"."type" AS "AssetFaceEntity__AssetFaceEntity_asset_type",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."originalPath" AS "AssetFaceEntity__AssetFaceEntity_asset_originalPath",
|
"AssetFaceEntity__AssetFaceEntity_asset"."originalPath" AS "AssetFaceEntity__AssetFaceEntity_asset_originalPath",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."previewPath" AS "AssetFaceEntity__AssetFaceEntity_asset_previewPath",
|
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."thumbnailPath" AS "AssetFaceEntity__AssetFaceEntity_asset_thumbnailPath",
|
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."thumbhash" AS "AssetFaceEntity__AssetFaceEntity_asset_thumbhash",
|
"AssetFaceEntity__AssetFaceEntity_asset"."thumbhash" AS "AssetFaceEntity__AssetFaceEntity_asset_thumbhash",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."encodedVideoPath" AS "AssetFaceEntity__AssetFaceEntity_asset_encodedVideoPath",
|
"AssetFaceEntity__AssetFaceEntity_asset"."encodedVideoPath" AS "AssetFaceEntity__AssetFaceEntity_asset_encodedVideoPath",
|
||||||
"AssetFaceEntity__AssetFaceEntity_asset"."createdAt" AS "AssetFaceEntity__AssetFaceEntity_asset_createdAt",
|
"AssetFaceEntity__AssetFaceEntity_asset"."createdAt" AS "AssetFaceEntity__AssetFaceEntity_asset_createdAt",
|
||||||
|
|
|
@ -14,8 +14,6 @@ FROM
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -46,8 +44,6 @@ FROM
|
||||||
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
||||||
"stackedAssets"."type" AS "stackedAssets_type",
|
"stackedAssets"."type" AS "stackedAssets_type",
|
||||||
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
||||||
"stackedAssets"."previewPath" AS "stackedAssets_previewPath",
|
|
||||||
"stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
|
|
||||||
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
||||||
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
||||||
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
||||||
|
@ -111,8 +107,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
@ -143,8 +137,6 @@ SELECT
|
||||||
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
"stackedAssets"."deviceId" AS "stackedAssets_deviceId",
|
||||||
"stackedAssets"."type" AS "stackedAssets_type",
|
"stackedAssets"."type" AS "stackedAssets_type",
|
||||||
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
"stackedAssets"."originalPath" AS "stackedAssets_originalPath",
|
||||||
"stackedAssets"."previewPath" AS "stackedAssets_previewPath",
|
|
||||||
"stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath",
|
|
||||||
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
"stackedAssets"."thumbhash" AS "stackedAssets_thumbhash",
|
||||||
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
"stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath",
|
||||||
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
"stackedAssets"."createdAt" AS "stackedAssets_createdAt",
|
||||||
|
@ -353,8 +345,6 @@ SELECT
|
||||||
"asset"."deviceId" AS "asset_deviceId",
|
"asset"."deviceId" AS "asset_deviceId",
|
||||||
"asset"."type" AS "asset_type",
|
"asset"."type" AS "asset_type",
|
||||||
"asset"."originalPath" AS "asset_originalPath",
|
"asset"."originalPath" AS "asset_originalPath",
|
||||||
"asset"."previewPath" AS "asset_previewPath",
|
|
||||||
"asset"."thumbnailPath" AS "asset_thumbnailPath",
|
|
||||||
"asset"."thumbhash" AS "asset_thumbhash",
|
"asset"."thumbhash" AS "asset_thumbhash",
|
||||||
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
"asset"."encodedVideoPath" AS "asset_encodedVideoPath",
|
||||||
"asset"."createdAt" AS "asset_createdAt",
|
"asset"."createdAt" AS "asset_createdAt",
|
||||||
|
|
|
@ -28,8 +28,6 @@ FROM
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."deviceId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceId",
|
"SharedLinkEntity__SharedLinkEntity_assets"."deviceId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceId",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."type" AS "SharedLinkEntity__SharedLinkEntity_assets_type",
|
"SharedLinkEntity__SharedLinkEntity_assets"."type" AS "SharedLinkEntity__SharedLinkEntity_assets_type",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."originalPath" AS "SharedLinkEntity__SharedLinkEntity_assets_originalPath",
|
"SharedLinkEntity__SharedLinkEntity_assets"."originalPath" AS "SharedLinkEntity__SharedLinkEntity_assets_originalPath",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."previewPath" AS "SharedLinkEntity__SharedLinkEntity_assets_previewPath",
|
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."thumbnailPath" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbnailPath",
|
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."thumbhash" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbhash",
|
"SharedLinkEntity__SharedLinkEntity_assets"."thumbhash" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbhash",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."encodedVideoPath" AS "SharedLinkEntity__SharedLinkEntity_assets_encodedVideoPath",
|
"SharedLinkEntity__SharedLinkEntity_assets"."encodedVideoPath" AS "SharedLinkEntity__SharedLinkEntity_assets_encodedVideoPath",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_assets_createdAt",
|
"SharedLinkEntity__SharedLinkEntity_assets"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_assets_createdAt",
|
||||||
|
@ -96,8 +94,6 @@ FROM
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."deviceId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_deviceId",
|
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."deviceId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_deviceId",
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."type" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_type",
|
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."type" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_type",
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."originalPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_originalPath",
|
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."originalPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_originalPath",
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."previewPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_previewPath",
|
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."thumbnailPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_thumbnailPath",
|
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."thumbhash" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_thumbhash",
|
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."thumbhash" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_thumbhash",
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."encodedVideoPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_encodedVideoPath",
|
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."encodedVideoPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_encodedVideoPath",
|
||||||
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."createdAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_createdAt",
|
"4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."createdAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_createdAt",
|
||||||
|
@ -218,8 +214,6 @@ SELECT
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."deviceId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceId",
|
"SharedLinkEntity__SharedLinkEntity_assets"."deviceId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceId",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."type" AS "SharedLinkEntity__SharedLinkEntity_assets_type",
|
"SharedLinkEntity__SharedLinkEntity_assets"."type" AS "SharedLinkEntity__SharedLinkEntity_assets_type",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."originalPath" AS "SharedLinkEntity__SharedLinkEntity_assets_originalPath",
|
"SharedLinkEntity__SharedLinkEntity_assets"."originalPath" AS "SharedLinkEntity__SharedLinkEntity_assets_originalPath",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."previewPath" AS "SharedLinkEntity__SharedLinkEntity_assets_previewPath",
|
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."thumbnailPath" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbnailPath",
|
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."thumbhash" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbhash",
|
"SharedLinkEntity__SharedLinkEntity_assets"."thumbhash" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbhash",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."encodedVideoPath" AS "SharedLinkEntity__SharedLinkEntity_assets_encodedVideoPath",
|
"SharedLinkEntity__SharedLinkEntity_assets"."encodedVideoPath" AS "SharedLinkEntity__SharedLinkEntity_assets_encodedVideoPath",
|
||||||
"SharedLinkEntity__SharedLinkEntity_assets"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_assets_createdAt",
|
"SharedLinkEntity__SharedLinkEntity_assets"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_assets_createdAt",
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
|
import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
|
||||||
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { ExifEntity } from 'src/entities/exif.entity';
|
import { ExifEntity } from 'src/entities/exif.entity';
|
||||||
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
||||||
import { AssetOrder, AssetType } from 'src/enum';
|
import { AssetFileType, AssetOrder, AssetType } from 'src/enum';
|
||||||
import {
|
import {
|
||||||
AssetBuilderOptions,
|
AssetBuilderOptions,
|
||||||
AssetCreate,
|
AssetCreate,
|
||||||
|
@ -59,6 +60,7 @@ const dateTrunc = (options: TimeBucketOptions) =>
|
||||||
export class AssetRepository implements IAssetRepository {
|
export class AssetRepository implements IAssetRepository {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(AssetEntity) private repository: Repository<AssetEntity>,
|
@InjectRepository(AssetEntity) private repository: Repository<AssetEntity>,
|
||||||
|
@InjectRepository(AssetFileEntity) private fileRepository: Repository<AssetFileEntity>,
|
||||||
@InjectRepository(ExifEntity) private exifRepository: Repository<ExifEntity>,
|
@InjectRepository(ExifEntity) private exifRepository: Repository<ExifEntity>,
|
||||||
@InjectRepository(AssetJobStatusEntity) private jobStatusRepository: Repository<AssetJobStatusEntity>,
|
@InjectRepository(AssetJobStatusEntity) private jobStatusRepository: Repository<AssetJobStatusEntity>,
|
||||||
@InjectRepository(SmartInfoEntity) private smartInfoRepository: Repository<SmartInfoEntity>,
|
@InjectRepository(SmartInfoEntity) private smartInfoRepository: Repository<SmartInfoEntity>,
|
||||||
|
@ -84,7 +86,6 @@ export class AssetRepository implements IAssetRepository {
|
||||||
`entity.ownerId IN (:...ownerIds)
|
`entity.ownerId IN (:...ownerIds)
|
||||||
AND entity.isVisible = true
|
AND entity.isVisible = true
|
||||||
AND entity.isArchived = false
|
AND entity.isArchived = false
|
||||||
AND entity.previewPath IS NOT NULL
|
|
||||||
AND EXTRACT(DAY FROM entity.localDateTime AT TIME ZONE 'UTC') = :day
|
AND EXTRACT(DAY FROM entity.localDateTime AT TIME ZONE 'UTC') = :day
|
||||||
AND EXTRACT(MONTH FROM entity.localDateTime AT TIME ZONE 'UTC') = :month`,
|
AND EXTRACT(MONTH FROM entity.localDateTime AT TIME ZONE 'UTC') = :month`,
|
||||||
{
|
{
|
||||||
|
@ -94,6 +95,7 @@ export class AssetRepository implements IAssetRepository {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect('entity.exifInfo', 'exifInfo')
|
.leftJoinAndSelect('entity.exifInfo', 'exifInfo')
|
||||||
|
.leftJoinAndSelect('entity.files', 'files')
|
||||||
.orderBy('entity.localDateTime', 'ASC')
|
.orderBy('entity.localDateTime', 'ASC')
|
||||||
.getMany();
|
.getMany();
|
||||||
}
|
}
|
||||||
|
@ -128,6 +130,7 @@ export class AssetRepository implements IAssetRepository {
|
||||||
stack: {
|
stack: {
|
||||||
assets: true,
|
assets: true,
|
||||||
},
|
},
|
||||||
|
files: true,
|
||||||
},
|
},
|
||||||
withDeleted: true,
|
withDeleted: true,
|
||||||
});
|
});
|
||||||
|
@ -214,7 +217,7 @@ export class AssetRepository implements IAssetRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(pagination: PaginationOptions, options: AssetSearchOptions = {}): Paginated<AssetEntity> {
|
getAll(pagination: PaginationOptions, options: AssetSearchOptions = {}): Paginated<AssetEntity> {
|
||||||
let builder = this.repository.createQueryBuilder('asset');
|
let builder = this.repository.createQueryBuilder('asset').leftJoinAndSelect('asset.files', 'files');
|
||||||
builder = searchAssetBuilder(builder, options);
|
builder = searchAssetBuilder(builder, options);
|
||||||
builder.orderBy('asset.createdAt', options.orderDirection ?? 'ASC');
|
builder.orderBy('asset.createdAt', options.orderDirection ?? 'ASC');
|
||||||
return paginatedBuilder<AssetEntity>(builder, {
|
return paginatedBuilder<AssetEntity>(builder, {
|
||||||
|
@ -706,7 +709,11 @@ export class AssetRepository implements IAssetRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBuilder(options: AssetBuilderOptions) {
|
private getBuilder(options: AssetBuilderOptions) {
|
||||||
const builder = this.repository.createQueryBuilder('asset').where('asset.isVisible = true');
|
const builder = this.repository
|
||||||
|
.createQueryBuilder('asset')
|
||||||
|
.where('asset.isVisible = true')
|
||||||
|
.leftJoinAndSelect('asset.files', 'files');
|
||||||
|
|
||||||
if (options.assetType !== undefined) {
|
if (options.assetType !== undefined) {
|
||||||
builder.andWhere('asset.type = :assetType', { assetType: options.assetType });
|
builder.andWhere('asset.type = :assetType', { assetType: options.assetType });
|
||||||
}
|
}
|
||||||
|
@ -812,4 +819,9 @@ export class AssetRepository implements IAssetRepository {
|
||||||
.withDeleted();
|
.withDeleted();
|
||||||
return builder.getMany();
|
return builder.getMany();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GenerateSql({ params: [{ assetId: DummyValue.UUID, type: AssetFileType.PREVIEW, path: '/path/to/file' }] })
|
||||||
|
async upsertFile({ assetId, type, path }: { assetId: string; type: AssetFileType; path: string }): Promise<void> {
|
||||||
|
await this.fileRepository.upsert({ assetId, type, path }, { conflictPaths: ['assetId', 'type'] });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { BadRequestException, NotFoundException, UnauthorizedException } from '@
|
||||||
import { Stats } from 'node:fs';
|
import { Stats } from 'node:fs';
|
||||||
import { AssetMediaStatus, AssetRejectReason, AssetUploadAction } from 'src/dtos/asset-media-response.dto';
|
import { AssetMediaStatus, AssetRejectReason, AssetUploadAction } from 'src/dtos/asset-media-response.dto';
|
||||||
import { AssetMediaCreateDto, AssetMediaReplaceDto, UploadFieldName } from 'src/dtos/asset-media.dto';
|
import { AssetMediaCreateDto, AssetMediaReplaceDto, UploadFieldName } from 'src/dtos/asset-media.dto';
|
||||||
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity } from 'src/entities/asset.entity';
|
import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { AssetType } from 'src/enum';
|
import { AssetType } from 'src/enum';
|
||||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||||
|
@ -150,15 +151,14 @@ const assetEntity = Object.freeze({
|
||||||
deviceId: 'device_id_1',
|
deviceId: 'device_id_1',
|
||||||
type: AssetType.VIDEO,
|
type: AssetType.VIDEO,
|
||||||
originalPath: 'fake_path/asset_1.jpeg',
|
originalPath: 'fake_path/asset_1.jpeg',
|
||||||
previewPath: '',
|
|
||||||
fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
|
fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
|
||||||
fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
|
fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
|
||||||
updatedAt: new Date('2022-06-19T23:41:36.910Z'),
|
updatedAt: new Date('2022-06-19T23:41:36.910Z'),
|
||||||
isFavorite: false,
|
isFavorite: false,
|
||||||
isArchived: false,
|
isArchived: false,
|
||||||
thumbnailPath: '',
|
|
||||||
encodedVideoPath: '',
|
encodedVideoPath: '',
|
||||||
duration: '0:00:00.000000',
|
duration: '0:00:00.000000',
|
||||||
|
files: [] as AssetFileEntity[],
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
latitude: 49.533_547,
|
latitude: 49.533_547,
|
||||||
longitude: 10.703_075,
|
longitude: 10.703_075,
|
||||||
|
@ -418,7 +418,7 @@ describe(AssetMediaService.name, () => {
|
||||||
|
|
||||||
await expect(sut.downloadOriginal(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(NotFoundException);
|
await expect(sut.downloadOriginal(authStub.admin, 'asset-1')).rejects.toBeInstanceOf(NotFoundException);
|
||||||
|
|
||||||
expect(assetMock.getById).toHaveBeenCalledWith('asset-1');
|
expect(assetMock.getById).toHaveBeenCalledWith('asset-1', { files: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should download a file', async () => {
|
it('should download a file', async () => {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { IJobRepository, JobName } from 'src/interfaces/job.interface';
|
||||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
|
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
|
||||||
import { mimeTypes } from 'src/utils/mime-types';
|
import { mimeTypes } from 'src/utils/mime-types';
|
||||||
import { fromChecksum } from 'src/utils/request';
|
import { fromChecksum } from 'src/utils/request';
|
||||||
|
@ -238,9 +239,10 @@ export class AssetMediaService {
|
||||||
const asset = await this.findOrFail(id);
|
const asset = await this.findOrFail(id);
|
||||||
const size = dto.size ?? AssetMediaSize.THUMBNAIL;
|
const size = dto.size ?? AssetMediaSize.THUMBNAIL;
|
||||||
|
|
||||||
let filepath = asset.previewPath;
|
const { thumbnailFile, previewFile } = getAssetFiles(asset.files);
|
||||||
if (size === AssetMediaSize.THUMBNAIL && asset.thumbnailPath) {
|
let filepath = previewFile?.path;
|
||||||
filepath = asset.thumbnailPath;
|
if (size === AssetMediaSize.THUMBNAIL && thumbnailFile) {
|
||||||
|
filepath = thumbnailFile.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filepath) {
|
if (!filepath) {
|
||||||
|
@ -460,7 +462,7 @@ export class AssetMediaService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async findOrFail(id: string): Promise<AssetEntity> {
|
private async findOrFail(id: string): Promise<AssetEntity> {
|
||||||
const asset = await this.assetRepository.getById(id);
|
const asset = await this.assetRepository.getById(id, { files: true });
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
throw new NotFoundException('Asset not found');
|
throw new NotFoundException('Asset not found');
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,8 +299,8 @@ describe(AssetService.name, () => {
|
||||||
name: JobName.DELETE_FILES,
|
name: JobName.DELETE_FILES,
|
||||||
data: {
|
data: {
|
||||||
files: [
|
files: [
|
||||||
assetWithFace.thumbnailPath,
|
'/uploads/user-id/webp/path.ext',
|
||||||
assetWithFace.previewPath,
|
'/uploads/user-id/thumbs/path.jpg',
|
||||||
assetWithFace.encodedVideoPath,
|
assetWithFace.encodedVideoPath,
|
||||||
assetWithFace.sidecarPath,
|
assetWithFace.sidecarPath,
|
||||||
assetWithFace.originalPath,
|
assetWithFace.originalPath,
|
||||||
|
|
|
@ -39,7 +39,7 @@ import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||||
import { IStackRepository } from 'src/interfaces/stack.interface';
|
import { IStackRepository } from 'src/interfaces/stack.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
import { getMyPartnerIds } from 'src/utils/asset.util';
|
import { getAssetFiles, getMyPartnerIds } from 'src/utils/asset.util';
|
||||||
import { usePagination } from 'src/utils/pagination';
|
import { usePagination } from 'src/utils/pagination';
|
||||||
|
|
||||||
export class AssetService {
|
export class AssetService {
|
||||||
|
@ -71,9 +71,10 @@ export class AssetService {
|
||||||
const userIds = [auth.user.id, ...partnerIds];
|
const userIds = [auth.user.id, ...partnerIds];
|
||||||
|
|
||||||
const assets = await this.assetRepository.getByDayOfYear(userIds, dto);
|
const assets = await this.assetRepository.getByDayOfYear(userIds, dto);
|
||||||
|
const assetsWithThumbnails = assets.filter(({ files }) => !!getAssetFiles(files).thumbnailFile);
|
||||||
const groups: Record<number, AssetEntity[]> = {};
|
const groups: Record<number, AssetEntity[]> = {};
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
for (const asset of assets) {
|
for (const asset of assetsWithThumbnails) {
|
||||||
const yearsAgo = currentYear - asset.localDateTime.getFullYear();
|
const yearsAgo = currentYear - asset.localDateTime.getFullYear();
|
||||||
if (!groups[yearsAgo]) {
|
if (!groups[yearsAgo]) {
|
||||||
groups[yearsAgo] = [];
|
groups[yearsAgo] = [];
|
||||||
|
@ -126,6 +127,7 @@ export class AssetService {
|
||||||
exifInfo: true,
|
exifInfo: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
files: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
faces: {
|
faces: {
|
||||||
|
@ -170,6 +172,7 @@ export class AssetService {
|
||||||
faces: {
|
faces: {
|
||||||
person: true,
|
person: true,
|
||||||
},
|
},
|
||||||
|
files: true,
|
||||||
});
|
});
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
throw new BadRequestException('Asset not found');
|
throw new BadRequestException('Asset not found');
|
||||||
|
@ -223,6 +226,7 @@ export class AssetService {
|
||||||
library: true,
|
library: true,
|
||||||
stack: { assets: true },
|
stack: { assets: true },
|
||||||
exifInfo: true,
|
exifInfo: true,
|
||||||
|
files: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
|
@ -260,7 +264,8 @@ export class AssetService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = [asset.thumbnailPath, asset.previewPath, asset.encodedVideoPath];
|
const { thumbnailFile, previewFile } = getAssetFiles(asset.files);
|
||||||
|
const files = [thumbnailFile?.path, previewFile?.path, asset.encodedVideoPath];
|
||||||
if (deleteOnDisk) {
|
if (deleteOnDisk) {
|
||||||
files.push(asset.sidecarPath, asset.originalPath);
|
files.push(asset.sidecarPath, asset.originalPath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
} from 'src/dtos/audit.dto';
|
} from 'src/dtos/audit.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { AssetPathType, PersonPathType, UserPathType } from 'src/entities/move.entity';
|
import { AssetPathType, PersonPathType, UserPathType } from 'src/entities/move.entity';
|
||||||
import { DatabaseAction, Permission } from 'src/enum';
|
import { AssetFileType, DatabaseAction, Permission } from 'src/enum';
|
||||||
import { IAccessRepository } from 'src/interfaces/access.interface';
|
import { IAccessRepository } from 'src/interfaces/access.interface';
|
||||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||||
import { IAuditRepository } from 'src/interfaces/audit.interface';
|
import { IAuditRepository } from 'src/interfaces/audit.interface';
|
||||||
|
@ -24,6 +24,7 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { usePagination } from 'src/utils/pagination';
|
import { usePagination } from 'src/utils/pagination';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -97,12 +98,12 @@ export class AuditService {
|
||||||
}
|
}
|
||||||
|
|
||||||
case AssetPathType.PREVIEW: {
|
case AssetPathType.PREVIEW: {
|
||||||
await this.assetRepository.update({ id, previewPath: pathValue });
|
await this.assetRepository.upsertFile({ assetId: id, type: AssetFileType.PREVIEW, path: pathValue });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AssetPathType.THUMBNAIL: {
|
case AssetPathType.THUMBNAIL: {
|
||||||
await this.assetRepository.update({ id, thumbnailPath: pathValue });
|
await this.assetRepository.upsertFile({ assetId: id, type: AssetFileType.THUMBNAIL, path: pathValue });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +156,7 @@ export class AuditService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const track = (filename: string | null) => {
|
const track = (filename: string | null | undefined) => {
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,8 +176,9 @@ export class AuditService {
|
||||||
const orphans: FileReportItemDto[] = [];
|
const orphans: FileReportItemDto[] = [];
|
||||||
for await (const assets of pagination) {
|
for await (const assets of pagination) {
|
||||||
assetCount += assets.length;
|
assetCount += assets.length;
|
||||||
for (const { id, originalPath, previewPath, encodedVideoPath, thumbnailPath, isExternal, checksum } of assets) {
|
for (const { id, files, originalPath, encodedVideoPath, isExternal, checksum } of assets) {
|
||||||
for (const file of [originalPath, previewPath, encodedVideoPath, thumbnailPath]) {
|
const { previewFile, thumbnailFile } = getAssetFiles(files);
|
||||||
|
for (const file of [originalPath, previewFile?.path, encodedVideoPath, thumbnailFile?.path]) {
|
||||||
track(file);
|
track(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,11 +194,11 @@ export class AuditService {
|
||||||
) {
|
) {
|
||||||
orphans.push({ ...entity, pathType: AssetPathType.ORIGINAL, pathValue: originalPath });
|
orphans.push({ ...entity, pathType: AssetPathType.ORIGINAL, pathValue: originalPath });
|
||||||
}
|
}
|
||||||
if (previewPath && !hasFile(thumbFiles, previewPath)) {
|
if (previewFile && !hasFile(thumbFiles, previewFile.path)) {
|
||||||
orphans.push({ ...entity, pathType: AssetPathType.PREVIEW, pathValue: previewPath });
|
orphans.push({ ...entity, pathType: AssetPathType.PREVIEW, pathValue: previewFile.path });
|
||||||
}
|
}
|
||||||
if (thumbnailPath && !hasFile(thumbFiles, thumbnailPath)) {
|
if (thumbnailFile && !hasFile(thumbFiles, thumbnailFile.path)) {
|
||||||
orphans.push({ ...entity, pathType: AssetPathType.THUMBNAIL, pathValue: thumbnailPath });
|
orphans.push({ ...entity, pathType: AssetPathType.THUMBNAIL, pathValue: thumbnailFile.path });
|
||||||
}
|
}
|
||||||
if (encodedVideoPath && !hasFile(videoFiles, encodedVideoPath)) {
|
if (encodedVideoPath && !hasFile(videoFiles, encodedVideoPath)) {
|
||||||
orphans.push({ ...entity, pathType: AssetPathType.THUMBNAIL, pathValue: encodedVideoPath });
|
orphans.push({ ...entity, pathType: AssetPathType.THUMBNAIL, pathValue: encodedVideoPath });
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { AssetDuplicateResult, ISearchRepository } from 'src/interfaces/search.interface';
|
import { AssetDuplicateResult, ISearchRepository } from 'src/interfaces/search.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { isDuplicateDetectionEnabled } from 'src/utils/misc';
|
import { isDuplicateDetectionEnabled } from 'src/utils/misc';
|
||||||
import { usePagination } from 'src/utils/pagination';
|
import { usePagination } from 'src/utils/pagination';
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ export class DuplicateService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const asset = await this.assetRepository.getById(id, { smartSearch: true });
|
const asset = await this.assetRepository.getById(id, { files: true, smartSearch: true });
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
this.logger.error(`Asset ${id} not found`);
|
this.logger.error(`Asset ${id} not found`);
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
|
@ -80,7 +81,8 @@ export class DuplicateService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!asset.previewPath) {
|
const { previewFile } = getAssetFiles(asset.files);
|
||||||
|
if (!previewFile) {
|
||||||
this.logger.warn(`Asset ${id} is missing preview image`);
|
this.logger.warn(`Asset ${id} is missing preview image`);
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
VideoCodec,
|
VideoCodec,
|
||||||
} from 'src/config';
|
} from 'src/config';
|
||||||
import { ExifEntity } from 'src/entities/exif.entity';
|
import { ExifEntity } from 'src/entities/exif.entity';
|
||||||
import { AssetType } from 'src/enum';
|
import { AssetFileType, AssetType } from 'src/enum';
|
||||||
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
|
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
|
||||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||||
|
@ -298,18 +298,20 @@ describe(MediaService.name, () => {
|
||||||
colorspace: Colorspace.SRGB,
|
colorspace: Colorspace.SRGB,
|
||||||
processInvalidImages: false,
|
processInvalidImages: false,
|
||||||
});
|
});
|
||||||
expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', previewPath });
|
expect(assetMock.upsertFile).toHaveBeenCalledWith({
|
||||||
|
assetId: 'asset-id',
|
||||||
|
type: AssetFileType.PREVIEW,
|
||||||
|
path: previewPath,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete previous preview if different path', async () => {
|
it('should delete previous preview if different path', async () => {
|
||||||
const previousPreviewPath = assetStub.image.previewPath;
|
|
||||||
|
|
||||||
systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } });
|
systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } });
|
||||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||||
|
|
||||||
await sut.handleGeneratePreview({ id: assetStub.image.id });
|
await sut.handleGeneratePreview({ id: assetStub.image.id });
|
||||||
|
|
||||||
expect(storageMock.unlink).toHaveBeenCalledWith(previousPreviewPath);
|
expect(storageMock.unlink).toHaveBeenCalledWith('/uploads/user-id/thumbs/path.jpg');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate a P3 thumbnail for a wide gamut image', async () => {
|
it('should generate a P3 thumbnail for a wide gamut image', async () => {
|
||||||
|
@ -330,9 +332,10 @@ describe(MediaService.name, () => {
|
||||||
processInvalidImages: false,
|
processInvalidImages: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
expect(assetMock.update).toHaveBeenCalledWith({
|
expect(assetMock.upsertFile).toHaveBeenCalledWith({
|
||||||
id: 'asset-id',
|
assetId: 'asset-id',
|
||||||
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
|
type: AssetFileType.PREVIEW,
|
||||||
|
path: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -357,9 +360,10 @@ describe(MediaService.name, () => {
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
expect(assetMock.update).toHaveBeenCalledWith({
|
expect(assetMock.upsertFile).toHaveBeenCalledWith({
|
||||||
id: 'asset-id',
|
assetId: 'asset-id',
|
||||||
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
|
type: AssetFileType.PREVIEW,
|
||||||
|
path: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -384,9 +388,10 @@ describe(MediaService.name, () => {
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
expect(assetMock.update).toHaveBeenCalledWith({
|
expect(assetMock.upsertFile).toHaveBeenCalledWith({
|
||||||
id: 'asset-id',
|
assetId: 'asset-id',
|
||||||
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
|
type: AssetFileType.PREVIEW,
|
||||||
|
path: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -472,19 +477,21 @@ describe(MediaService.name, () => {
|
||||||
colorspace: Colorspace.SRGB,
|
colorspace: Colorspace.SRGB,
|
||||||
processInvalidImages: false,
|
processInvalidImages: false,
|
||||||
});
|
});
|
||||||
expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', thumbnailPath });
|
expect(assetMock.upsertFile).toHaveBeenCalledWith({
|
||||||
|
assetId: 'asset-id',
|
||||||
|
type: AssetFileType.THUMBNAIL,
|
||||||
|
path: thumbnailPath,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it('should delete previous thumbnail if different path', async () => {
|
it('should delete previous thumbnail if different path', async () => {
|
||||||
const previousThumbnailPath = assetStub.image.thumbnailPath;
|
|
||||||
|
|
||||||
systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } });
|
systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } });
|
||||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||||
|
|
||||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||||
|
|
||||||
expect(storageMock.unlink).toHaveBeenCalledWith(previousThumbnailPath);
|
expect(storageMock.unlink).toHaveBeenCalledWith('/uploads/user-id/webp/path.ext');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -504,9 +511,10 @@ describe(MediaService.name, () => {
|
||||||
processInvalidImages: false,
|
processInvalidImages: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
expect(assetMock.update).toHaveBeenCalledWith({
|
expect(assetMock.upsertFile).toHaveBeenCalledWith({
|
||||||
id: 'asset-id',
|
assetId: 'asset-id',
|
||||||
thumbnailPath: 'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
type: AssetFileType.THUMBNAIL,
|
||||||
|
path: 'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { SystemConfigCore } from 'src/cores/system-config.core';
|
||||||
import { SystemConfigFFmpegDto } from 'src/dtos/system-config.dto';
|
import { SystemConfigFFmpegDto } from 'src/dtos/system-config.dto';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { AssetPathType } from 'src/entities/move.entity';
|
import { AssetPathType } from 'src/entities/move.entity';
|
||||||
import { AssetType } from 'src/enum';
|
import { AssetFileType, AssetType } from 'src/enum';
|
||||||
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
|
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
|
||||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||||
import {
|
import {
|
||||||
|
@ -34,6 +34,7 @@ import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { BaseConfig, ThumbnailConfig } from 'src/utils/media';
|
import { BaseConfig, ThumbnailConfig } from 'src/utils/media';
|
||||||
import { mimeTypes } from 'src/utils/mime-types';
|
import { mimeTypes } from 'src/utils/mime-types';
|
||||||
import { usePagination } from 'src/utils/pagination';
|
import { usePagination } from 'src/utils/pagination';
|
||||||
|
@ -72,7 +73,11 @@ export class MediaService {
|
||||||
async handleQueueGenerateThumbnails({ force }: IBaseJob): Promise<JobStatus> {
|
async handleQueueGenerateThumbnails({ force }: IBaseJob): Promise<JobStatus> {
|
||||||
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
|
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
|
||||||
return force
|
return force
|
||||||
? this.assetRepository.getAll(pagination, { isVisible: true, withDeleted: true, withArchived: true })
|
? this.assetRepository.getAll(pagination, {
|
||||||
|
isVisible: true,
|
||||||
|
withDeleted: true,
|
||||||
|
withArchived: true,
|
||||||
|
})
|
||||||
: this.assetRepository.getWithout(pagination, WithoutProperty.THUMBNAIL);
|
: this.assetRepository.getWithout(pagination, WithoutProperty.THUMBNAIL);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -80,13 +85,17 @@ export class MediaService {
|
||||||
const jobs: JobItem[] = [];
|
const jobs: JobItem[] = [];
|
||||||
|
|
||||||
for (const asset of assets) {
|
for (const asset of assets) {
|
||||||
if (!asset.previewPath || force) {
|
const { previewFile, thumbnailFile } = getAssetFiles(asset.files);
|
||||||
|
|
||||||
|
if (!previewFile || force) {
|
||||||
jobs.push({ name: JobName.GENERATE_PREVIEW, data: { id: asset.id } });
|
jobs.push({ name: JobName.GENERATE_PREVIEW, data: { id: asset.id } });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!asset.thumbnailPath) {
|
|
||||||
|
if (!thumbnailFile) {
|
||||||
jobs.push({ name: JobName.GENERATE_THUMBNAIL, data: { id: asset.id } });
|
jobs.push({ name: JobName.GENERATE_THUMBNAIL, data: { id: asset.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!asset.thumbhash) {
|
if (!asset.thumbhash) {
|
||||||
jobs.push({ name: JobName.GENERATE_THUMBHASH, data: { id: asset.id } });
|
jobs.push({ name: JobName.GENERATE_THUMBHASH, data: { id: asset.id } });
|
||||||
}
|
}
|
||||||
|
@ -152,7 +161,7 @@ export class MediaService {
|
||||||
|
|
||||||
async handleAssetMigration({ id }: IEntityJob): Promise<JobStatus> {
|
async handleAssetMigration({ id }: IEntityJob): Promise<JobStatus> {
|
||||||
const { image } = await this.configCore.getConfig({ withCache: true });
|
const { image } = await this.configCore.getConfig({ withCache: true });
|
||||||
const [asset] = await this.assetRepository.getByIds([id]);
|
const [asset] = await this.assetRepository.getByIds([id], { files: true });
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
@ -182,12 +191,14 @@ export class MediaService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset.previewPath && asset.previewPath !== previewPath) {
|
const { previewFile } = getAssetFiles(asset.files);
|
||||||
|
if (previewFile && previewFile.path !== previewPath) {
|
||||||
this.logger.debug(`Deleting old preview for asset ${asset.id}`);
|
this.logger.debug(`Deleting old preview for asset ${asset.id}`);
|
||||||
await this.storageRepository.unlink(asset.previewPath);
|
await this.storageRepository.unlink(previewFile.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.assetRepository.update({ id: asset.id, previewPath });
|
await this.assetRepository.upsertFile({ assetId: asset.id, type: AssetFileType.PREVIEW, path: previewPath });
|
||||||
|
await this.assetRepository.update({ id: asset.id, updatedAt: new Date() });
|
||||||
await this.assetRepository.upsertJobStatus({ assetId: asset.id, previewAt: new Date() });
|
await this.assetRepository.upsertJobStatus({ assetId: asset.id, previewAt: new Date() });
|
||||||
|
|
||||||
return JobStatus.SUCCESS;
|
return JobStatus.SUCCESS;
|
||||||
|
@ -253,7 +264,7 @@ export class MediaService {
|
||||||
async handleGenerateThumbnail({ id }: IEntityJob): Promise<JobStatus> {
|
async handleGenerateThumbnail({ id }: IEntityJob): Promise<JobStatus> {
|
||||||
const [{ image }, [asset]] = await Promise.all([
|
const [{ image }, [asset]] = await Promise.all([
|
||||||
this.configCore.getConfig({ withCache: true }),
|
this.configCore.getConfig({ withCache: true }),
|
||||||
this.assetRepository.getByIds([id], { exifInfo: true }),
|
this.assetRepository.getByIds([id], { exifInfo: true, files: true }),
|
||||||
]);
|
]);
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
|
@ -268,19 +279,21 @@ export class MediaService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset.thumbnailPath && asset.thumbnailPath !== thumbnailPath) {
|
const { thumbnailFile } = getAssetFiles(asset.files);
|
||||||
|
if (thumbnailFile && thumbnailFile.path !== thumbnailPath) {
|
||||||
this.logger.debug(`Deleting old thumbnail for asset ${asset.id}`);
|
this.logger.debug(`Deleting old thumbnail for asset ${asset.id}`);
|
||||||
await this.storageRepository.unlink(asset.thumbnailPath);
|
await this.storageRepository.unlink(thumbnailFile.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.assetRepository.update({ id: asset.id, thumbnailPath });
|
await this.assetRepository.upsertFile({ assetId: asset.id, type: AssetFileType.THUMBNAIL, path: thumbnailPath });
|
||||||
|
await this.assetRepository.update({ id: asset.id, updatedAt: new Date() });
|
||||||
await this.assetRepository.upsertJobStatus({ assetId: asset.id, thumbnailAt: new Date() });
|
await this.assetRepository.upsertJobStatus({ assetId: asset.id, thumbnailAt: new Date() });
|
||||||
|
|
||||||
return JobStatus.SUCCESS;
|
return JobStatus.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleGenerateThumbhash({ id }: IEntityJob): Promise<JobStatus> {
|
async handleGenerateThumbhash({ id }: IEntityJob): Promise<JobStatus> {
|
||||||
const [asset] = await this.assetRepository.getByIds([id]);
|
const [asset] = await this.assetRepository.getByIds([id], { files: true });
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
@ -289,11 +302,12 @@ export class MediaService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!asset.previewPath) {
|
const { previewFile } = getAssetFiles(asset.files);
|
||||||
|
if (!previewFile) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const thumbhash = await this.mediaRepository.generateThumbhash(asset.previewPath);
|
const thumbhash = await this.mediaRepository.generateThumbhash(previewFile.path);
|
||||||
await this.assetRepository.update({ id: asset.id, thumbhash });
|
await this.assetRepository.update({ id: asset.id, thumbhash });
|
||||||
|
|
||||||
return JobStatus.SUCCESS;
|
return JobStatus.SUCCESS;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { defaults, SystemConfig } from 'src/config';
|
import { defaults, SystemConfig } from 'src/config';
|
||||||
import { AlbumUserEntity } from 'src/entities/album-user.entity';
|
import { AlbumUserEntity } from 'src/entities/album-user.entity';
|
||||||
import { UserMetadataKey } from 'src/enum';
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
|
import { AssetFileType, UserMetadataKey } from 'src/enum';
|
||||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||||
|
@ -333,7 +334,9 @@ describe(NotificationService.name, () => {
|
||||||
notificationMock.renderEmail.mockResolvedValue({ html: '', text: '' });
|
notificationMock.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||||
|
|
||||||
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
||||||
expect(assetMock.getById).toHaveBeenCalledWith(albumStub.emptyWithValidThumbnail.albumThumbnailAssetId);
|
expect(assetMock.getById).toHaveBeenCalledWith(albumStub.emptyWithValidThumbnail.albumThumbnailAssetId, {
|
||||||
|
files: true,
|
||||||
|
});
|
||||||
expect(jobMock.queue).toHaveBeenCalledWith({
|
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||||
name: JobName.SEND_EMAIL,
|
name: JobName.SEND_EMAIL,
|
||||||
data: expect.objectContaining({
|
data: expect.objectContaining({
|
||||||
|
@ -358,10 +361,15 @@ describe(NotificationService.name, () => {
|
||||||
});
|
});
|
||||||
systemMock.get.mockResolvedValue({ server: {} });
|
systemMock.get.mockResolvedValue({ server: {} });
|
||||||
notificationMock.renderEmail.mockResolvedValue({ html: '', text: '' });
|
notificationMock.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||||
assetMock.getById.mockResolvedValue({ ...assetStub.image, thumbnailPath: 'path-to-thumb.jpg' });
|
assetMock.getById.mockResolvedValue({
|
||||||
|
...assetStub.image,
|
||||||
|
files: [{ assetId: 'asset-id', type: AssetFileType.THUMBNAIL, path: 'path-to-thumb.jpg' } as AssetFileEntity],
|
||||||
|
});
|
||||||
|
|
||||||
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
||||||
expect(assetMock.getById).toHaveBeenCalledWith(albumStub.emptyWithValidThumbnail.albumThumbnailAssetId);
|
expect(assetMock.getById).toHaveBeenCalledWith(albumStub.emptyWithValidThumbnail.albumThumbnailAssetId, {
|
||||||
|
files: true,
|
||||||
|
});
|
||||||
expect(jobMock.queue).toHaveBeenCalledWith({
|
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||||
name: JobName.SEND_EMAIL,
|
name: JobName.SEND_EMAIL,
|
||||||
data: expect.objectContaining({
|
data: expect.objectContaining({
|
||||||
|
@ -389,7 +397,9 @@ describe(NotificationService.name, () => {
|
||||||
assetMock.getById.mockResolvedValue(assetStub.image);
|
assetMock.getById.mockResolvedValue(assetStub.image);
|
||||||
|
|
||||||
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
await expect(sut.handleAlbumInvite({ id: '', recipientId: '' })).resolves.toBe(JobStatus.SUCCESS);
|
||||||
expect(assetMock.getById).toHaveBeenCalledWith(albumStub.emptyWithValidThumbnail.albumThumbnailAssetId);
|
expect(assetMock.getById).toHaveBeenCalledWith(albumStub.emptyWithValidThumbnail.albumThumbnailAssetId, {
|
||||||
|
files: true,
|
||||||
|
});
|
||||||
expect(jobMock.queue).toHaveBeenCalledWith({
|
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||||
name: JobName.SEND_EMAIL,
|
name: JobName.SEND_EMAIL,
|
||||||
data: expect.objectContaining({
|
data: expect.objectContaining({
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { EmailImageAttachment, EmailTemplate, INotificationRepository } from 'src/interfaces/notification.interface';
|
import { EmailImageAttachment, EmailTemplate, INotificationRepository } from 'src/interfaces/notification.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { getFilenameExtension } from 'src/utils/file';
|
import { getFilenameExtension } from 'src/utils/file';
|
||||||
import { getPreferences } from 'src/utils/preferences';
|
import { getPreferences } from 'src/utils/preferences';
|
||||||
|
|
||||||
|
@ -268,14 +269,15 @@ export class NotificationService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const albumThumbnail = await this.assetRepository.getById(album.albumThumbnailAssetId);
|
const albumThumbnail = await this.assetRepository.getById(album.albumThumbnailAssetId, { files: true });
|
||||||
if (!albumThumbnail?.thumbnailPath) {
|
const { thumbnailFile } = getAssetFiles(albumThumbnail?.files);
|
||||||
|
if (!thumbnailFile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filename: `album-thumbnail${getFilenameExtension(albumThumbnail.thumbnailPath)}`,
|
filename: `album-thumbnail${getFilenameExtension(thumbnailFile.path)}`,
|
||||||
path: albumThumbnail.thumbnailPath,
|
path: thumbnailFile.path,
|
||||||
cid: 'album-thumbnail',
|
cid: 'album-thumbnail',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -716,7 +716,7 @@ describe(PersonService.name, () => {
|
||||||
await sut.handleDetectFaces({ id: assetStub.image.id });
|
await sut.handleDetectFaces({ id: assetStub.image.id });
|
||||||
expect(machineLearningMock.detectFaces).toHaveBeenCalledWith(
|
expect(machineLearningMock.detectFaces).toHaveBeenCalledWith(
|
||||||
'http://immich-machine-learning:3003',
|
'http://immich-machine-learning:3003',
|
||||||
assetStub.image.previewPath,
|
'/uploads/user-id/thumbs/path.jpg',
|
||||||
expect.objectContaining({ minScore: 0.7, modelName: 'buffalo_l' }),
|
expect.objectContaining({ minScore: 0.7, modelName: 'buffalo_l' }),
|
||||||
);
|
);
|
||||||
expect(personMock.createFaces).not.toHaveBeenCalled();
|
expect(personMock.createFaces).not.toHaveBeenCalled();
|
||||||
|
@ -946,7 +946,7 @@ describe(PersonService.name, () => {
|
||||||
|
|
||||||
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
||||||
|
|
||||||
expect(assetMock.getById).toHaveBeenCalledWith(faceStub.middle.assetId, { exifInfo: true });
|
expect(assetMock.getById).toHaveBeenCalledWith(faceStub.middle.assetId, { exifInfo: true, files: true });
|
||||||
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/admin_id/pe/rs');
|
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/admin_id/pe/rs');
|
||||||
expect(mediaMock.generateThumbnail).toHaveBeenCalledWith(
|
expect(mediaMock.generateThumbnail).toHaveBeenCalledWith(
|
||||||
assetStub.primaryImage.originalPath,
|
assetStub.primaryImage.originalPath,
|
||||||
|
@ -1032,7 +1032,7 @@ describe(PersonService.name, () => {
|
||||||
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
||||||
|
|
||||||
expect(mediaMock.generateThumbnail).toHaveBeenCalledWith(
|
expect(mediaMock.generateThumbnail).toHaveBeenCalledWith(
|
||||||
assetStub.video.previewPath,
|
'/uploads/user-id/thumbs/path.jpg',
|
||||||
'upload/thumbs/admin_id/pe/rs/person-1.jpeg',
|
'upload/thumbs/admin_id/pe/rs/person-1.jpeg',
|
||||||
{
|
{
|
||||||
format: 'jpeg',
|
format: 'jpeg',
|
||||||
|
|
|
@ -50,6 +50,7 @@ import { IPersonRepository, UpdateFacesData } from 'src/interfaces/person.interf
|
||||||
import { ISearchRepository } from 'src/interfaces/search.interface';
|
import { ISearchRepository } from 'src/interfaces/search.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
|
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
|
||||||
import { mimeTypes } from 'src/utils/mime-types';
|
import { mimeTypes } from 'src/utils/mime-types';
|
||||||
import { isFacialRecognitionEnabled } from 'src/utils/misc';
|
import { isFacialRecognitionEnabled } from 'src/utils/misc';
|
||||||
|
@ -333,9 +334,11 @@ export class PersonService {
|
||||||
faces: {
|
faces: {
|
||||||
person: false,
|
person: false,
|
||||||
},
|
},
|
||||||
|
files: true,
|
||||||
};
|
};
|
||||||
const [asset] = await this.assetRepository.getByIds([id], relations);
|
const [asset] = await this.assetRepository.getByIds([id], relations);
|
||||||
if (!asset || !asset.previewPath || asset.faces?.length > 0) {
|
const { previewFile } = getAssetFiles(asset.files);
|
||||||
|
if (!asset || !previewFile || asset.faces?.length > 0) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,11 +352,11 @@ export class PersonService {
|
||||||
|
|
||||||
const { imageHeight, imageWidth, faces } = await this.machineLearningRepository.detectFaces(
|
const { imageHeight, imageWidth, faces } = await this.machineLearningRepository.detectFaces(
|
||||||
machineLearning.url,
|
machineLearning.url,
|
||||||
asset.previewPath,
|
previewFile.path,
|
||||||
machineLearning.facialRecognition,
|
machineLearning.facialRecognition,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.debug(`${faces.length} faces detected in ${asset.previewPath}`);
|
this.logger.debug(`${faces.length} faces detected in ${previewFile.path}`);
|
||||||
|
|
||||||
if (faces.length > 0) {
|
if (faces.length > 0) {
|
||||||
await this.jobRepository.queue({ name: JobName.QUEUE_FACIAL_RECOGNITION, data: { force: false } });
|
await this.jobRepository.queue({ name: JobName.QUEUE_FACIAL_RECOGNITION, data: { force: false } });
|
||||||
|
@ -549,7 +552,10 @@ export class PersonService {
|
||||||
imageHeight: oldHeight,
|
imageHeight: oldHeight,
|
||||||
} = face;
|
} = face;
|
||||||
|
|
||||||
const asset = await this.assetRepository.getById(assetId, { exifInfo: true });
|
const asset = await this.assetRepository.getById(assetId, {
|
||||||
|
exifInfo: true,
|
||||||
|
files: true,
|
||||||
|
});
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
this.logger.error(`Could not generate person thumbnail: asset ${assetId} does not exist`);
|
this.logger.error(`Could not generate person thumbnail: asset ${assetId} does not exist`);
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
|
@ -646,7 +652,8 @@ export class PersonService {
|
||||||
throw new Error(`Asset ${asset.id} dimensions are unknown`);
|
throw new Error(`Asset ${asset.id} dimensions are unknown`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!asset.previewPath) {
|
const { previewFile } = getAssetFiles(asset.files);
|
||||||
|
if (!previewFile) {
|
||||||
throw new Error(`Asset ${asset.id} has no preview path`);
|
throw new Error(`Asset ${asset.id} has no preview path`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,8 +666,8 @@ export class PersonService {
|
||||||
return { width, height, inputPath: asset.originalPath };
|
return { width, height, inputPath: asset.originalPath };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { width, height } = await this.mediaRepository.getImageDimensions(asset.previewPath);
|
const { width, height } = await this.mediaRepository.getImageDimensions(previewFile.path);
|
||||||
return { width, height, inputPath: asset.previewPath };
|
return { width, height, inputPath: previewFile.path };
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCrop(dims: { old: ImageDimensions; new: ImageDimensions }, { x1, y1, x2, y2 }: BoundingBox): CropOptions {
|
private getCrop(dims: { old: ImageDimensions; new: ImageDimensions }, { x1, y1, x2, y2 }: BoundingBox): CropOptions {
|
||||||
|
|
|
@ -318,7 +318,7 @@ describe(SmartInfoService.name, () => {
|
||||||
|
|
||||||
expect(machineMock.encodeImage).toHaveBeenCalledWith(
|
expect(machineMock.encodeImage).toHaveBeenCalledWith(
|
||||||
'http://immich-machine-learning:3003',
|
'http://immich-machine-learning:3003',
|
||||||
assetStub.image.previewPath,
|
'/uploads/user-id/thumbs/path.jpg',
|
||||||
expect.objectContaining({ modelName: 'ViT-B-32__openai' }),
|
expect.objectContaining({ modelName: 'ViT-B-32__openai' }),
|
||||||
);
|
);
|
||||||
expect(searchMock.upsert).toHaveBeenCalledWith(assetStub.image.id, [0.01, 0.02, 0.03]);
|
expect(searchMock.upsert).toHaveBeenCalledWith(assetStub.image.id, [0.01, 0.02, 0.03]);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||||
import { ISearchRepository } from 'src/interfaces/search.interface';
|
import { ISearchRepository } from 'src/interfaces/search.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { getCLIPModelInfo, isSmartSearchEnabled } from 'src/utils/misc';
|
import { getCLIPModelInfo, isSmartSearchEnabled } from 'src/utils/misc';
|
||||||
import { usePagination } from 'src/utils/pagination';
|
import { usePagination } from 'src/utils/pagination';
|
||||||
|
|
||||||
|
@ -135,7 +136,7 @@ export class SmartInfoService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [asset] = await this.assetRepository.getByIds([id]);
|
const [asset] = await this.assetRepository.getByIds([id], { files: true });
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
@ -144,13 +145,14 @@ export class SmartInfoService {
|
||||||
return JobStatus.SKIPPED;
|
return JobStatus.SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!asset.previewPath) {
|
const { previewFile } = getAssetFiles(asset.files);
|
||||||
|
if (!previewFile) {
|
||||||
return JobStatus.FAILED;
|
return JobStatus.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const embedding = await this.machineLearning.encodeImage(
|
const embedding = await this.machineLearning.encodeImage(
|
||||||
machineLearning.url,
|
machineLearning.url,
|
||||||
asset.previewPath,
|
previewFile.path,
|
||||||
machineLearning.clip,
|
machineLearning.clip,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { AccessCore } from 'src/cores/access.core';
|
import { AccessCore } from 'src/cores/access.core';
|
||||||
import { BulkIdErrorReason, BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto';
|
import { BulkIdErrorReason, BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { Permission } from 'src/enum';
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
|
import { AssetFileType, Permission } from 'src/enum';
|
||||||
import { IAccessRepository } from 'src/interfaces/access.interface';
|
import { IAccessRepository } from 'src/interfaces/access.interface';
|
||||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||||
|
|
||||||
|
@ -11,6 +12,15 @@ export interface IBulkAsset {
|
||||||
removeAssetIds: (id: string, assetIds: string[]) => Promise<void>;
|
removeAssetIds: (id: string, assetIds: string[]) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getFileByType = (files: AssetFileEntity[] | undefined, type: AssetFileType) => {
|
||||||
|
return (files || []).find((file) => file.type === type);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAssetFiles = (files?: AssetFileEntity[]) => ({
|
||||||
|
previewFile: getFileByType(files, AssetFileType.PREVIEW),
|
||||||
|
thumbnailFile: getFileByType(files, AssetFileType.THUMBNAIL),
|
||||||
|
});
|
||||||
|
|
||||||
export const addAssets = async (
|
export const addAssets = async (
|
||||||
auth: AuthDto,
|
auth: AuthDto,
|
||||||
repositories: { accessRepository: IAccessRepository; repository: IBulkAsset },
|
repositories: { accessRepository: IAccessRepository; repository: IBulkAsset },
|
||||||
|
|
|
@ -71,7 +71,7 @@ export function searchAssetBuilder(
|
||||||
builder.andWhere(`${builder.alias}.ownerId IN (:...userIds)`, { userIds: options.userIds });
|
builder.andWhere(`${builder.alias}.ownerId IN (:...userIds)`, { userIds: options.userIds });
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = _.pick(options, ['encodedVideoPath', 'originalPath', 'previewPath', 'thumbnailPath']);
|
const path = _.pick(options, ['encodedVideoPath', 'originalPath']);
|
||||||
builder.andWhere(_.omitBy(path, _.isUndefined));
|
builder.andWhere(_.omitBy(path, _.isUndefined));
|
||||||
|
|
||||||
if (options.originalFileName) {
|
if (options.originalFileName) {
|
||||||
|
|
111
server/test/fixtures/asset.stub.ts
vendored
111
server/test/fixtures/asset.stub.ts
vendored
|
@ -1,12 +1,33 @@
|
||||||
|
import { AssetFileEntity } from 'src/entities/asset-files.entity';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { ExifEntity } from 'src/entities/exif.entity';
|
import { ExifEntity } from 'src/entities/exif.entity';
|
||||||
import { StackEntity } from 'src/entities/stack.entity';
|
import { StackEntity } from 'src/entities/stack.entity';
|
||||||
import { AssetType } from 'src/enum';
|
import { AssetFileType, AssetType } from 'src/enum';
|
||||||
import { authStub } from 'test/fixtures/auth.stub';
|
import { authStub } from 'test/fixtures/auth.stub';
|
||||||
import { fileStub } from 'test/fixtures/file.stub';
|
import { fileStub } from 'test/fixtures/file.stub';
|
||||||
import { libraryStub } from 'test/fixtures/library.stub';
|
import { libraryStub } from 'test/fixtures/library.stub';
|
||||||
import { userStub } from 'test/fixtures/user.stub';
|
import { userStub } from 'test/fixtures/user.stub';
|
||||||
|
|
||||||
|
const previewFile: AssetFileEntity = {
|
||||||
|
id: 'file-1',
|
||||||
|
assetId: 'asset-id',
|
||||||
|
type: AssetFileType.PREVIEW,
|
||||||
|
path: '/uploads/user-id/thumbs/path.jpg',
|
||||||
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const thumbnailFile: AssetFileEntity = {
|
||||||
|
id: 'file-2',
|
||||||
|
assetId: 'asset-id',
|
||||||
|
type: AssetFileType.THUMBNAIL,
|
||||||
|
path: '/uploads/user-id/webp/path.ext',
|
||||||
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const files: AssetFileEntity[] = [previewFile, thumbnailFile];
|
||||||
|
|
||||||
export const stackStub = (stackId: string, assets: AssetEntity[]): StackEntity => {
|
export const stackStub = (stackId: string, assets: AssetEntity[]): StackEntity => {
|
||||||
return {
|
return {
|
||||||
id: stackId,
|
id: stackId,
|
||||||
|
@ -29,10 +50,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: 'upload/library/IMG_123.jpg',
|
originalPath: 'upload/library/IMG_123.jpg',
|
||||||
previewPath: null,
|
files: [thumbnailFile],
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -63,10 +83,10 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: 'upload/library/IMG_456.jpg',
|
originalPath: 'upload/library/IMG_456.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
|
files: [previewFile],
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: null,
|
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -101,10 +121,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
files,
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -136,10 +155,9 @@ export const assetStub = {
|
||||||
ownerId: 'admin-id',
|
ownerId: 'admin-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/admin-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
|
files,
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/admin-id/webp/path.ext',
|
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -181,10 +199,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
files,
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -221,10 +238,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -261,10 +277,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -301,10 +316,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/data/user1/photo.jpg',
|
originalPath: '/data/user1/photo.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('path hash', 'utf8'),
|
checksum: Buffer.from('path hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -341,10 +355,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -379,10 +392,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/data/user1/photo.jpg',
|
originalPath: '/data/user1/photo.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('path hash', 'utf8'),
|
checksum: Buffer.from('path hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -419,10 +431,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -457,10 +468,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
files,
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2015-02-23T05:06:29.716Z'),
|
createdAt: new Date('2015-02-23T05:06:29.716Z'),
|
||||||
|
@ -496,10 +506,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.VIDEO,
|
type: AssetType.VIDEO,
|
||||||
thumbnailPath: null,
|
files: [previewFile],
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -548,8 +557,22 @@ export const assetStub = {
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
|
fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'),
|
||||||
fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
|
fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'),
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
files: [
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
{
|
||||||
|
assetId: 'asset-id',
|
||||||
|
type: AssetFileType.PREVIEW,
|
||||||
|
path: '/uploads/user-id/thumbs/path.ext',
|
||||||
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetId: 'asset-id',
|
||||||
|
type: AssetFileType.THUMBNAIL,
|
||||||
|
path: '/uploads/user-id/webp/path.ext',
|
||||||
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
},
|
||||||
|
],
|
||||||
exifInfo: {
|
exifInfo: {
|
||||||
fileSizeInByte: 100_000,
|
fileSizeInByte: 100_000,
|
||||||
timeZone: `America/New_York`,
|
timeZone: `America/New_York`,
|
||||||
|
@ -612,10 +635,9 @@ export const assetStub = {
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
sidecarPath: null,
|
sidecarPath: null,
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: null,
|
files: [previewFile],
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-22T05:06:29.716Z'),
|
createdAt: new Date('2023-02-22T05:06:29.716Z'),
|
||||||
|
@ -653,11 +675,10 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: null,
|
files: [previewFile],
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -687,11 +708,10 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: null,
|
files: [previewFile],
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -722,11 +742,10 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: null,
|
files: [previewFile],
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -758,10 +777,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.ext',
|
originalPath: '/original/path.ext',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.ext',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.VIDEO,
|
type: AssetType.VIDEO,
|
||||||
thumbnailPath: null,
|
files: [previewFile],
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
encodedVideoPath: '/encoded/video/path.mp4',
|
encodedVideoPath: '/encoded/video/path.mp4',
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -794,10 +812,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/data/user1/photo.jpg',
|
originalPath: '/data/user1/photo.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -833,10 +850,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/data/user1/photo.jpg',
|
originalPath: '/data/user1/photo.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -872,10 +888,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.dng',
|
originalPath: '/original/path.dng',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -911,10 +926,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
@ -952,10 +966,9 @@ export const assetStub = {
|
||||||
ownerId: 'user-id',
|
ownerId: 'user-id',
|
||||||
deviceId: 'device-id',
|
deviceId: 'device-id',
|
||||||
originalPath: '/original/path.jpg',
|
originalPath: '/original/path.jpg',
|
||||||
previewPath: '/uploads/user-id/thumbs/path.jpg',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
type: AssetType.IMAGE,
|
type: AssetType.IMAGE,
|
||||||
thumbnailPath: '/uploads/user-id/webp/path.ext',
|
files,
|
||||||
thumbhash: Buffer.from('blablabla', 'base64'),
|
thumbhash: Buffer.from('blablabla', 'base64'),
|
||||||
encodedVideoPath: null,
|
encodedVideoPath: null,
|
||||||
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
|
3
server/test/fixtures/shared-link.stub.ts
vendored
3
server/test/fixtures/shared-link.stub.ts
vendored
|
@ -196,7 +196,6 @@ export const sharedLinkStub = {
|
||||||
deviceId: 'device_id_1',
|
deviceId: 'device_id_1',
|
||||||
type: AssetType.VIDEO,
|
type: AssetType.VIDEO,
|
||||||
originalPath: 'fake_path/jpeg',
|
originalPath: 'fake_path/jpeg',
|
||||||
previewPath: '',
|
|
||||||
checksum: Buffer.from('file hash', 'utf8'),
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
fileModifiedAt: today,
|
fileModifiedAt: today,
|
||||||
fileCreatedAt: today,
|
fileCreatedAt: today,
|
||||||
|
@ -213,7 +212,7 @@ export const sharedLinkStub = {
|
||||||
objects: ['a', 'b', 'c'],
|
objects: ['a', 'b', 'c'],
|
||||||
asset: null as any,
|
asset: null as any,
|
||||||
},
|
},
|
||||||
thumbnailPath: '',
|
files: [],
|
||||||
thumbhash: null,
|
thumbhash: null,
|
||||||
encodedVideoPath: '',
|
encodedVideoPath: '',
|
||||||
duration: null,
|
duration: null,
|
||||||
|
|
|
@ -42,5 +42,6 @@ export const newAssetRepositoryMock = (): Mocked<IAssetRepository> => {
|
||||||
getAllForUserFullSync: vitest.fn(),
|
getAllForUserFullSync: vitest.fn(),
|
||||||
getChangedDeltaSync: vitest.fn(),
|
getChangedDeltaSync: vitest.fn(),
|
||||||
getDuplicates: vitest.fn(),
|
getDuplicates: vitest.fn(),
|
||||||
|
upsertFile: vitest.fn(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue