2023-12-14 11:55:40 -05:00
|
|
|
import { BadRequestException, Inject } from '@nestjs/common';
|
2023-10-04 18:11:11 -04:00
|
|
|
import _ from 'lodash';
|
2023-10-06 07:01:14 +00:00
|
|
|
import { DateTime, Duration } from 'luxon';
|
2024-03-20 21:20:38 +01:00
|
|
|
import { SystemConfigCore } from 'src/cores/system-config.core';
|
2023-08-24 21:28:50 +02:00
|
|
|
import {
|
|
|
|
|
AssetResponseDto,
|
|
|
|
|
MemoryLaneResponseDto,
|
2023-10-14 03:46:30 +02:00
|
|
|
SanitizedAssetResponseDto,
|
2023-09-04 15:45:59 -04:00
|
|
|
mapAsset,
|
2024-03-20 23:53:07 +01:00
|
|
|
} from 'src/dtos/asset-response.dto';
|
|
|
|
|
import {
|
|
|
|
|
AssetBulkDeleteDto,
|
|
|
|
|
AssetBulkUpdateDto,
|
|
|
|
|
AssetJobName,
|
|
|
|
|
AssetJobsDto,
|
|
|
|
|
AssetStatsDto,
|
|
|
|
|
UpdateAssetDto,
|
|
|
|
|
mapStats,
|
|
|
|
|
} from 'src/dtos/asset.dto';
|
|
|
|
|
import { AuthDto } from 'src/dtos/auth.dto';
|
2024-05-29 17:51:01 +02:00
|
|
|
import { MemoryLaneDto } from 'src/dtos/search.dto';
|
2024-03-20 16:02:51 -05:00
|
|
|
import { AssetEntity } from 'src/entities/asset.entity';
|
2024-08-15 06:57:01 -04:00
|
|
|
import { Permission } from 'src/enum';
|
2024-03-21 12:59:49 +01:00
|
|
|
import { IAccessRepository } from 'src/interfaces/access.interface';
|
2024-03-29 04:20:40 +01:00
|
|
|
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
2024-03-22 18:24:02 -04:00
|
|
|
import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface';
|
2024-03-20 22:15:09 -05:00
|
|
|
import {
|
2024-06-10 13:04:34 -04:00
|
|
|
IAssetDeleteJob,
|
2024-03-20 22:15:09 -05:00
|
|
|
IJobRepository,
|
|
|
|
|
ISidecarWriteJob,
|
|
|
|
|
JOBS_ASSET_PAGINATION_SIZE,
|
|
|
|
|
JobItem,
|
|
|
|
|
JobName,
|
|
|
|
|
JobStatus,
|
2024-03-21 12:59:49 +01:00
|
|
|
} from 'src/interfaces/job.interface';
|
2024-04-17 03:00:31 +05:30
|
|
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
2024-03-21 12:59:49 +01:00
|
|
|
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
2024-07-05 09:08:36 -04:00
|
|
|
import { IStackRepository } from 'src/interfaces/stack.interface';
|
2024-05-15 18:58:23 -04:00
|
|
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
2024-03-21 12:59:49 +01:00
|
|
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
2024-08-20 07:49:56 -04:00
|
|
|
import { requireAccess } from 'src/utils/access';
|
2024-09-11 16:26:29 -04:00
|
|
|
import { getAssetFiles, getMyPartnerIds, onAfterUnlink, onBeforeLink, onBeforeUnlink } from 'src/utils/asset.util';
|
2024-03-20 22:15:09 -05:00
|
|
|
import { usePagination } from 'src/utils/pagination';
|
2023-02-25 09:12:03 -05:00
|
|
|
|
|
|
|
|
export class AssetService {
|
2023-10-06 07:01:14 +00:00
|
|
|
private configCore: SystemConfigCore;
|
2023-06-30 12:24:28 -04:00
|
|
|
|
|
|
|
|
constructor(
|
2024-08-20 07:49:56 -04:00
|
|
|
@Inject(IAccessRepository) private access: IAccessRepository,
|
2023-06-30 12:24:28 -04:00
|
|
|
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
2023-08-18 10:31:48 -04:00
|
|
|
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
2024-05-15 18:58:23 -04:00
|
|
|
@Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository,
|
2024-01-12 18:43:36 -06:00
|
|
|
@Inject(IUserRepository) private userRepository: IUserRepository,
|
2024-03-22 18:24:02 -04:00
|
|
|
@Inject(IEventRepository) private eventRepository: IEventRepository,
|
2023-11-11 15:06:19 -06:00
|
|
|
@Inject(IPartnerRepository) private partnerRepository: IPartnerRepository,
|
2024-07-05 09:08:36 -04:00
|
|
|
@Inject(IStackRepository) private stackRepository: IStackRepository,
|
2024-04-17 03:00:31 +05:30
|
|
|
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
2023-06-30 12:24:28 -04:00
|
|
|
) {
|
2024-04-17 03:00:31 +05:30
|
|
|
this.logger.setContext(AssetService.name);
|
2024-05-15 18:58:23 -04:00
|
|
|
this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger);
|
2023-06-30 12:24:28 -04:00
|
|
|
}
|
2023-05-21 08:26:06 +02:00
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise<MemoryLaneResponseDto[]> {
|
2024-06-14 18:29:32 -04:00
|
|
|
const partnerIds = await getMyPartnerIds({
|
|
|
|
|
userId: auth.user.id,
|
|
|
|
|
repository: this.partnerRepository,
|
|
|
|
|
timelineEnabled: true,
|
|
|
|
|
});
|
|
|
|
|
const userIds = [auth.user.id, ...partnerIds];
|
2024-03-18 14:46:52 -05:00
|
|
|
|
|
|
|
|
const assets = await this.assetRepository.getByDayOfYear(userIds, dto);
|
2024-08-19 20:03:33 -04:00
|
|
|
const assetsWithThumbnails = assets.filter(({ files }) => !!getAssetFiles(files).thumbnailFile);
|
2024-03-27 16:14:29 -04:00
|
|
|
const groups: Record<number, AssetEntity[]> = {};
|
2024-06-14 18:29:32 -04:00
|
|
|
const currentYear = new Date().getFullYear();
|
2024-08-19 20:03:33 -04:00
|
|
|
for (const asset of assetsWithThumbnails) {
|
2024-03-27 16:14:29 -04:00
|
|
|
const yearsAgo = currentYear - asset.localDateTime.getFullYear();
|
|
|
|
|
if (!groups[yearsAgo]) {
|
|
|
|
|
groups[yearsAgo] = [];
|
|
|
|
|
}
|
|
|
|
|
groups[yearsAgo].push(asset);
|
|
|
|
|
}
|
2023-10-04 18:11:11 -04:00
|
|
|
|
2024-03-27 16:14:29 -04:00
|
|
|
return Object.keys(groups)
|
|
|
|
|
.map(Number)
|
2024-04-01 18:06:25 +02:00
|
|
|
.sort((a, b) => a - b)
|
2024-03-27 16:14:29 -04:00
|
|
|
.filter((yearsAgo) => yearsAgo > 0)
|
|
|
|
|
.map((yearsAgo) => ({
|
|
|
|
|
yearsAgo,
|
|
|
|
|
// TODO move this to clients
|
2024-04-23 11:08:02 -04:00
|
|
|
title: `${yearsAgo} year${yearsAgo > 1 ? 's' : ''} ago`,
|
2024-03-27 16:14:29 -04:00
|
|
|
assets: groups[yearsAgo].map((asset) => mapAsset(asset, { auth })),
|
|
|
|
|
}));
|
2023-06-14 20:47:18 -05:00
|
|
|
}
|
2023-06-30 12:24:28 -04:00
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async getStatistics(auth: AuthDto, dto: AssetStatsDto) {
|
|
|
|
|
const stats = await this.assetRepository.getStatistics(auth.user.id, dto);
|
2023-07-14 09:30:17 -04:00
|
|
|
return mapStats(stats);
|
|
|
|
|
}
|
2023-08-16 16:04:55 -04:00
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async getRandom(auth: AuthDto, count: number): Promise<AssetResponseDto[]> {
|
|
|
|
|
const assets = await this.assetRepository.getRandom(auth.user.id, count);
|
2024-03-03 00:01:24 +01:00
|
|
|
return assets.map((a) => mapAsset(a, { auth }));
|
2023-09-23 17:28:55 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async getUserAssetsByDeviceId(auth: AuthDto, deviceId: string) {
|
|
|
|
|
return this.assetRepository.getAllByDeviceId(auth.user.id, deviceId);
|
2023-11-25 15:46:20 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-25 12:52:21 -05:00
|
|
|
async get(auth: AuthDto, id: string): Promise<AssetResponseDto | SanitizedAssetResponseDto> {
|
2024-08-20 07:49:56 -04:00
|
|
|
await requireAccess(this.access, { auth, permission: Permission.ASSET_READ, ids: [id] });
|
2024-01-25 12:52:21 -05:00
|
|
|
|
2024-05-05 20:16:44 +02:00
|
|
|
const asset = await this.assetRepository.getById(
|
|
|
|
|
id,
|
|
|
|
|
{
|
|
|
|
|
exifInfo: true,
|
|
|
|
|
tags: true,
|
|
|
|
|
sharedLinks: true,
|
|
|
|
|
smartInfo: true,
|
|
|
|
|
owner: true,
|
|
|
|
|
faces: {
|
|
|
|
|
person: true,
|
|
|
|
|
},
|
|
|
|
|
stack: {
|
|
|
|
|
assets: {
|
|
|
|
|
exifInfo: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
2024-08-19 20:03:33 -04:00
|
|
|
files: true,
|
2024-01-25 12:52:21 -05:00
|
|
|
},
|
2024-05-05 20:16:44 +02:00
|
|
|
{
|
|
|
|
|
faces: {
|
|
|
|
|
boundingBoxX1: 'ASC',
|
2024-01-27 18:52:14 +00:00
|
|
|
},
|
2024-01-25 12:52:21 -05:00
|
|
|
},
|
2024-05-05 20:16:44 +02:00
|
|
|
);
|
2024-01-25 12:52:21 -05:00
|
|
|
|
|
|
|
|
if (!asset) {
|
|
|
|
|
throw new BadRequestException('Asset not found');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auth.sharedLink && !auth.sharedLink.showExif) {
|
2024-03-03 00:01:24 +01:00
|
|
|
return mapAsset(asset, { stripMetadata: true, withStack: true, auth });
|
2024-01-25 12:52:21 -05:00
|
|
|
}
|
|
|
|
|
|
2024-03-03 00:01:24 +01:00
|
|
|
const data = mapAsset(asset, { withStack: true, auth });
|
2024-01-25 12:52:21 -05:00
|
|
|
|
|
|
|
|
if (auth.sharedLink) {
|
|
|
|
|
delete data.owner;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-30 22:34:00 +01:00
|
|
|
if (data.ownerId !== auth.user.id || auth.sharedLink) {
|
2024-01-25 12:52:21 -05:00
|
|
|
data.people = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async update(auth: AuthDto, id: string, dto: UpdateAssetDto): Promise<AssetResponseDto> {
|
2024-08-20 07:49:56 -04:00
|
|
|
await requireAccess(this.access, { auth, permission: Permission.ASSET_UPDATE, ids: [id] });
|
2023-09-04 22:25:31 -04:00
|
|
|
|
2024-08-09 19:45:52 +02:00
|
|
|
const { description, dateTimeOriginal, latitude, longitude, rating, ...rest } = dto;
|
2024-09-11 16:26:29 -04:00
|
|
|
const repos = { asset: this.assetRepository, event: this.eventRepository };
|
2024-09-10 08:51:11 -04:00
|
|
|
|
2024-09-11 16:26:29 -04:00
|
|
|
let previousMotion: AssetEntity | null = null;
|
2024-09-10 08:51:11 -04:00
|
|
|
if (rest.livePhotoVideoId) {
|
2024-09-11 16:26:29 -04:00
|
|
|
await onBeforeLink(repos, { userId: auth.user.id, livePhotoVideoId: rest.livePhotoVideoId });
|
|
|
|
|
} else if (rest.livePhotoVideoId === null) {
|
|
|
|
|
const asset = await this.findOrFail(id);
|
|
|
|
|
if (asset.livePhotoVideoId) {
|
|
|
|
|
previousMotion = await onBeforeUnlink(repos, { livePhotoVideoId: asset.livePhotoVideoId });
|
|
|
|
|
}
|
2024-09-10 08:51:11 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-09 19:45:52 +02:00
|
|
|
await this.updateMetadata({ id, description, dateTimeOriginal, latitude, longitude, rating });
|
2023-09-04 22:25:31 -04:00
|
|
|
|
2024-03-19 22:42:10 -04:00
|
|
|
await this.assetRepository.update({ id, ...rest });
|
2024-09-11 16:26:29 -04:00
|
|
|
|
|
|
|
|
if (previousMotion) {
|
|
|
|
|
await onAfterUnlink(repos, { userId: auth.user.id, livePhotoVideoId: previousMotion.id });
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-19 22:42:10 -04:00
|
|
|
const asset = await this.assetRepository.getById(id, {
|
|
|
|
|
exifInfo: true,
|
|
|
|
|
owner: true,
|
|
|
|
|
smartInfo: true,
|
|
|
|
|
tags: true,
|
|
|
|
|
faces: {
|
|
|
|
|
person: true,
|
|
|
|
|
},
|
2024-08-19 20:03:33 -04:00
|
|
|
files: true,
|
2024-03-19 22:42:10 -04:00
|
|
|
});
|
2024-09-11 16:26:29 -04:00
|
|
|
|
2024-03-19 22:42:10 -04:00
|
|
|
if (!asset) {
|
|
|
|
|
throw new BadRequestException('Asset not found');
|
|
|
|
|
}
|
2024-09-11 16:26:29 -04:00
|
|
|
|
2024-03-03 00:01:24 +01:00
|
|
|
return mapAsset(asset, { auth });
|
2023-09-04 22:25:31 -04:00
|
|
|
}
|
|
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async updateAll(auth: AuthDto, dto: AssetBulkUpdateDto): Promise<void> {
|
2024-08-19 13:37:15 -04:00
|
|
|
const { ids, dateTimeOriginal, latitude, longitude, ...options } = dto;
|
2024-08-20 07:49:56 -04:00
|
|
|
await requireAccess(this.access, { auth, permission: Permission.ASSET_UPDATE, ids });
|
2023-10-22 02:38:07 +00:00
|
|
|
|
2023-12-08 11:15:46 -05:00
|
|
|
for (const id of ids) {
|
|
|
|
|
await this.updateMetadata({ id, dateTimeOriginal, latitude, longitude });
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-16 16:04:55 -04:00
|
|
|
await this.assetRepository.updateAll(ids, options);
|
|
|
|
|
}
|
2023-08-18 10:31:48 -04:00
|
|
|
|
2024-03-15 14:16:54 +01:00
|
|
|
async handleAssetDeletionCheck(): Promise<JobStatus> {
|
2024-06-12 07:07:35 -04:00
|
|
|
const config = await this.configCore.getConfig({ withCache: false });
|
2023-10-06 07:01:14 +00:00
|
|
|
const trashedDays = config.trash.enabled ? config.trash.days : 0;
|
|
|
|
|
const trashedBefore = DateTime.now()
|
|
|
|
|
.minus(Duration.fromObject({ days: trashedDays }))
|
|
|
|
|
.toJSDate();
|
|
|
|
|
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
|
|
|
|
|
this.assetRepository.getAll(pagination, { trashedBefore }),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
for await (const assets of assetPagination) {
|
2024-01-01 15:45:42 -05:00
|
|
|
await this.jobRepository.queueAll(
|
2024-06-10 13:04:34 -04:00
|
|
|
assets.map((asset) => ({
|
|
|
|
|
name: JobName.ASSET_DELETION,
|
|
|
|
|
data: {
|
|
|
|
|
id: asset.id,
|
|
|
|
|
deleteOnDisk: true,
|
|
|
|
|
},
|
|
|
|
|
})),
|
2024-01-01 15:45:42 -05:00
|
|
|
);
|
2023-10-06 07:01:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-03-15 14:16:54 +01:00
|
|
|
return JobStatus.SUCCESS;
|
2023-10-06 07:01:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-10 13:04:34 -04:00
|
|
|
async handleAssetDeletion(job: IAssetDeleteJob): Promise<JobStatus> {
|
|
|
|
|
const { id, deleteOnDisk } = job;
|
2023-10-06 07:01:14 +00:00
|
|
|
|
2024-01-15 09:04:29 -06:00
|
|
|
const asset = await this.assetRepository.getById(id, {
|
|
|
|
|
faces: {
|
|
|
|
|
person: true,
|
|
|
|
|
},
|
|
|
|
|
library: true,
|
2024-01-27 18:52:14 +00:00
|
|
|
stack: { assets: true },
|
2024-01-15 09:04:29 -06:00
|
|
|
exifInfo: true,
|
2024-08-19 20:03:33 -04:00
|
|
|
files: true,
|
2024-01-15 09:04:29 -06:00
|
|
|
});
|
|
|
|
|
|
2023-10-06 07:01:14 +00:00
|
|
|
if (!asset) {
|
2024-03-15 14:16:54 +01:00
|
|
|
return JobStatus.FAILED;
|
2023-10-06 07:01:14 +00:00
|
|
|
}
|
|
|
|
|
|
2023-10-22 02:38:07 +00:00
|
|
|
// Replace the parent of the stack children with a new asset
|
2024-01-27 18:52:14 +00:00
|
|
|
if (asset.stack?.primaryAssetId === id) {
|
|
|
|
|
const stackAssetIds = asset.stack.assets.map((a) => a.id);
|
|
|
|
|
if (stackAssetIds.length > 2) {
|
|
|
|
|
const newPrimaryAssetId = stackAssetIds.find((a) => a !== id)!;
|
2024-07-05 09:08:36 -04:00
|
|
|
await this.stackRepository.update({
|
2024-01-27 18:52:14 +00:00
|
|
|
id: asset.stack.id,
|
|
|
|
|
primaryAssetId: newPrimaryAssetId,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
2024-07-05 09:08:36 -04:00
|
|
|
await this.stackRepository.delete(asset.stack.id);
|
2024-01-27 18:52:14 +00:00
|
|
|
}
|
2023-10-22 02:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
2023-10-06 07:01:14 +00:00
|
|
|
await this.assetRepository.remove(asset);
|
2024-05-20 18:09:10 -04:00
|
|
|
if (!asset.libraryId) {
|
2024-04-16 20:04:59 -07:00
|
|
|
await this.userRepository.updateUsage(asset.ownerId, -(asset.exifInfo?.fileSizeInByte || 0));
|
|
|
|
|
}
|
2024-03-22 18:24:02 -04:00
|
|
|
this.eventRepository.clientSend(ClientEvent.ASSET_DELETE, asset.ownerId, id);
|
2023-10-06 07:01:14 +00:00
|
|
|
|
2024-06-27 15:41:49 -04:00
|
|
|
// delete the motion if it is not used by another asset
|
2023-10-06 07:01:14 +00:00
|
|
|
if (asset.livePhotoVideoId) {
|
2024-06-27 15:41:49 -04:00
|
|
|
const count = await this.assetRepository.getLivePhotoCount(asset.livePhotoVideoId);
|
|
|
|
|
if (count === 0) {
|
|
|
|
|
await this.jobRepository.queue({
|
|
|
|
|
name: JobName.ASSET_DELETION,
|
|
|
|
|
data: { id: asset.livePhotoVideoId, deleteOnDisk },
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-10-06 07:01:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-19 20:03:33 -04:00
|
|
|
const { thumbnailFile, previewFile } = getAssetFiles(asset.files);
|
|
|
|
|
const files = [thumbnailFile?.path, previewFile?.path, asset.encodedVideoPath];
|
2024-06-10 13:04:34 -04:00
|
|
|
if (deleteOnDisk) {
|
2024-05-14 17:29:57 -04:00
|
|
|
files.push(asset.sidecarPath, asset.originalPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await this.jobRepository.queue({ name: JobName.DELETE_FILES, data: { files } });
|
2023-10-06 07:01:14 +00:00
|
|
|
|
2024-03-15 14:16:54 +01:00
|
|
|
return JobStatus.SUCCESS;
|
2023-10-06 07:01:14 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async deleteAll(auth: AuthDto, dto: AssetBulkDeleteDto): Promise<void> {
|
2023-10-06 07:01:14 +00:00
|
|
|
const { ids, force } = dto;
|
|
|
|
|
|
2024-08-20 07:49:56 -04:00
|
|
|
await requireAccess(this.access, { auth, permission: Permission.ASSET_DELETE, ids });
|
2023-10-06 07:01:14 +00:00
|
|
|
|
|
|
|
|
if (force) {
|
2024-06-10 13:04:34 -04:00
|
|
|
await this.jobRepository.queueAll(
|
|
|
|
|
ids.map((id) => ({
|
|
|
|
|
name: JobName.ASSET_DELETION,
|
|
|
|
|
data: { id, deleteOnDisk: true },
|
|
|
|
|
})),
|
|
|
|
|
);
|
2023-10-06 07:01:14 +00:00
|
|
|
} else {
|
|
|
|
|
await this.assetRepository.softDeleteAll(ids);
|
2024-03-22 18:24:02 -04:00
|
|
|
this.eventRepository.clientSend(ClientEvent.ASSET_TRASH, auth.user.id, ids);
|
2023-10-06 07:01:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-09 23:34:12 -05:00
|
|
|
async run(auth: AuthDto, dto: AssetJobsDto) {
|
2024-08-20 07:49:56 -04:00
|
|
|
await requireAccess(this.access, { auth, permission: Permission.ASSET_UPDATE, ids: dto.assetIds });
|
2023-08-18 10:31:48 -04:00
|
|
|
|
2024-01-01 15:45:42 -05:00
|
|
|
const jobs: JobItem[] = [];
|
|
|
|
|
|
2023-08-18 10:31:48 -04:00
|
|
|
for (const id of dto.assetIds) {
|
|
|
|
|
switch (dto.name) {
|
2024-02-02 04:18:00 +01:00
|
|
|
case AssetJobName.REFRESH_METADATA: {
|
2024-01-01 15:45:42 -05:00
|
|
|
jobs.push({ name: JobName.METADATA_EXTRACTION, data: { id } });
|
2023-08-18 10:31:48 -04:00
|
|
|
break;
|
2024-02-02 04:18:00 +01:00
|
|
|
}
|
2023-08-18 10:31:48 -04:00
|
|
|
|
2024-02-02 04:18:00 +01:00
|
|
|
case AssetJobName.REGENERATE_THUMBNAIL: {
|
2024-04-02 00:56:56 -04:00
|
|
|
jobs.push({ name: JobName.GENERATE_PREVIEW, data: { id } });
|
2023-08-18 10:31:48 -04:00
|
|
|
break;
|
2024-02-02 04:18:00 +01:00
|
|
|
}
|
2023-08-18 10:31:48 -04:00
|
|
|
|
2024-02-02 04:18:00 +01:00
|
|
|
case AssetJobName.TRANSCODE_VIDEO: {
|
2024-01-01 15:45:42 -05:00
|
|
|
jobs.push({ name: JobName.VIDEO_CONVERSION, data: { id } });
|
2023-08-18 10:31:48 -04:00
|
|
|
break;
|
2024-02-02 04:18:00 +01:00
|
|
|
}
|
2023-08-18 10:31:48 -04:00
|
|
|
}
|
|
|
|
|
}
|
2024-01-01 15:45:42 -05:00
|
|
|
|
|
|
|
|
await this.jobRepository.queueAll(jobs);
|
2023-08-18 10:31:48 -04:00
|
|
|
}
|
2023-11-30 04:52:28 +01:00
|
|
|
|
2024-09-11 16:26:29 -04:00
|
|
|
private async findOrFail(id: string) {
|
|
|
|
|
const asset = await this.assetRepository.getById(id);
|
|
|
|
|
if (!asset) {
|
|
|
|
|
throw new BadRequestException('Asset not found');
|
|
|
|
|
}
|
|
|
|
|
return asset;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-30 04:52:28 +01:00
|
|
|
private async updateMetadata(dto: ISidecarWriteJob) {
|
2024-08-09 19:45:52 +02:00
|
|
|
const { id, description, dateTimeOriginal, latitude, longitude, rating } = dto;
|
|
|
|
|
const writes = _.omitBy({ description, dateTimeOriginal, latitude, longitude, rating }, _.isUndefined);
|
2023-11-30 04:52:28 +01:00
|
|
|
if (Object.keys(writes).length > 0) {
|
|
|
|
|
await this.assetRepository.upsertExif({ assetId: id, ...writes });
|
|
|
|
|
await this.jobRepository.queue({ name: JobName.SIDECAR_WRITE, data: { id, ...writes } });
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-25 09:12:03 -05:00
|
|
|
}
|