From 8c083ed59b9581486c348ee078da6097588bfdc0 Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Mon, 11 Sep 2023 13:19:51 +0200 Subject: [PATCH] Implement youngest and oldest photo date for directories --- src/backend/model/database/IndexingManager.ts | 4 ++++ .../database/enitites/DirectoryEntity.ts | 18 ++++++++++++++ .../model/threading/DiskMangerWorker.ts | 24 ++++++++++++------- src/common/DataStructureVersion.ts | 2 +- src/common/entities/DirectoryDTO.ts | 9 ++++--- src/common/entities/FileDTO.ts | 2 +- test/TestHelper.ts | 8 +++++-- .../unit/model/sql/PreviewManager.spec.ts | 2 ++ .../unit/model/sql/SearchManager.spec.ts | 2 ++ 9 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/backend/model/database/IndexingManager.ts b/src/backend/model/database/IndexingManager.ts index 497c1d88..051b2980 100644 --- a/src/backend/model/database/IndexingManager.ts +++ b/src/backend/model/database/IndexingManager.ts @@ -208,6 +208,8 @@ export class IndexingManager { currentDir.lastModified = scannedDirectory.lastModified; currentDir.lastScanned = scannedDirectory.lastScanned; currentDir.mediaCount = scannedDirectory.mediaCount; + currentDir.youngestMedia = scannedDirectory.youngestMedia; + currentDir.oldestMedia = scannedDirectory.oldestMedia; await directoryRepository.save(currentDir); return currentDir.id; } else { @@ -216,6 +218,8 @@ export class IndexingManager { mediaCount: scannedDirectory.mediaCount, lastModified: scannedDirectory.lastModified, lastScanned: scannedDirectory.lastScanned, + youngestMedia: scannedDirectory.youngestMedia, + oldestMedia: scannedDirectory.oldestMedia, name: scannedDirectory.name, path: scannedDirectory.path, } as DirectoryEntity) diff --git a/src/backend/model/database/enitites/DirectoryEntity.ts b/src/backend/model/database/enitites/DirectoryEntity.ts index dab733d2..3df67e58 100644 --- a/src/backend/model/database/enitites/DirectoryEntity.ts +++ b/src/backend/model/database/enitites/DirectoryEntity.ts @@ -64,6 +64,24 @@ export class DirectoryEntity @Column('mediumint', { unsigned: true }) mediaCount: number; + @Column('bigint', { + nullable: true, + transformer: { + from: (v) => parseInt(v, 10), + to: (v) => v, + }, + }) + oldestMedia: number; + + @Column('bigint', { + nullable: true, + transformer: { + from: (v) => parseInt(v, 10), + to: (v) => v, + }, + }) + youngestMedia: number; + @Index() @ManyToOne((type) => DirectoryEntity, (directory) => directory.directories, { onDelete: 'CASCADE', diff --git a/src/backend/model/threading/DiskMangerWorker.ts b/src/backend/model/threading/DiskMangerWorker.ts index eecd811f..477031c1 100644 --- a/src/backend/model/threading/DiskMangerWorker.ts +++ b/src/backend/model/threading/DiskMangerWorker.ts @@ -1,9 +1,6 @@ import {promises as fsp, Stats} from 'fs'; import * as path from 'path'; -import { - ParentDirectoryDTO, - SubDirectoryDTO, -} from '../../../common/entities/DirectoryDTO'; +import {ParentDirectoryDTO, SubDirectoryDTO,} from '../../../common/entities/DirectoryDTO'; import {PhotoDTO} from '../../../common/entities/PhotoDTO'; import {ProjectPath} from '../../ProjectPath'; import {Config} from '../../../common/config/private/Config'; @@ -120,15 +117,17 @@ export class DiskMangerWorker { name: directoryName, path: directoryParent, lastModified: this.calcLastModified(stat), - lastScanned: Date.now(), directories: [], - isPartial: false, + isPartial: settings.coverOnly === true, mediaCount: 0, cover: null, validCover: false, media: [], metaFile: [], }; + if (!settings.coverOnly) { + directory.lastScanned = Date.now(); + } // nothing to scan, we are here for the empty dir if ( @@ -164,9 +163,6 @@ export class DiskMangerWorker { } )) as SubDirectoryDTO; - d.lastScanned = 0; // it was not a fully scanned - d.isPartial = true; - directory.directories.push(d); } else if (PhotoProcessing.isPhoto(fullFilePath)) { if (settings.noPhoto === true) { @@ -239,6 +235,16 @@ export class DiskMangerWorker { } directory.mediaCount = directory.media.length; + if (!directory.isPartial) { + directory.youngestMedia = Number.MAX_SAFE_INTEGER; + directory.oldestMedia = Number.MIN_SAFE_INTEGER; + + directory.media.forEach((m) => { + directory.youngestMedia = Math.min(m.metadata.creationDate, directory.youngestMedia); + directory.oldestMedia = Math.max(m.metadata.creationDate, directory.oldestMedia); + } + ); + } return directory; } diff --git a/src/common/DataStructureVersion.ts b/src/common/DataStructureVersion.ts index 9c01a7a5..e55817a2 100644 --- a/src/common/DataStructureVersion.ts +++ b/src/common/DataStructureVersion.ts @@ -1,4 +1,4 @@ /** * This version indicates that the sql/entities/*Entity.ts files got changed and the db needs to be recreated */ -export const DataStructureVersion = 32; +export const DataStructureVersion = 33; diff --git a/src/common/entities/DirectoryDTO.ts b/src/common/entities/DirectoryDTO.ts index 3f8eedb0..164126d9 100644 --- a/src/common/entities/DirectoryDTO.ts +++ b/src/common/entities/DirectoryDTO.ts @@ -16,11 +16,12 @@ export interface DirectoryBaseDTO name: string; path: string; lastModified: number; - lastScanned: number; + lastScanned?: number; isPartial?: boolean; parent: DirectoryBaseDTO; mediaCount: number; - + youngestMedia?: number; + oldestMedia?: number; directories?: DirectoryBaseDTO[]; media?: S[]; metaFile?: FileDTO[]; @@ -34,10 +35,12 @@ export interface ParentDirectoryDTO name: string; path: string; lastModified: number; - lastScanned: number; + lastScanned?: number; isPartial?: boolean; parent: ParentDirectoryDTO; mediaCount: number; + youngestMedia?: number; + oldestMedia?: number; directories: SubDirectoryDTO[]; media: S[]; metaFile: FileDTO[]; diff --git a/src/common/entities/FileDTO.ts b/src/common/entities/FileDTO.ts index 1dc7af68..63d08848 100644 --- a/src/common/entities/FileDTO.ts +++ b/src/common/entities/FileDTO.ts @@ -1,4 +1,4 @@ -import { DirectoryPathDTO } from './DirectoryDTO'; +import {DirectoryPathDTO} from './DirectoryDTO'; export interface FileDTO { id: number; diff --git a/test/TestHelper.ts b/test/TestHelper.ts index 6b1fd0d2..0e3353f7 100644 --- a/test/TestHelper.ts +++ b/test/TestHelper.ts @@ -10,12 +10,12 @@ import {VideoEntity, VideoMetadataEntity} from '../src/backend/model/database/en import {MediaDimension, MediaDTO} from '../src/common/entities/MediaDTO'; import { CameraMetadata, + CoverPhotoDTO, FaceRegion, GPSMetadata, PhotoDTO, PhotoMetadata, - PositionMetaData, - CoverPhotoDTO + PositionMetaData } from '../src/common/entities/PhotoDTO'; import {DirectoryBaseDTO, DirectoryPathDTO} from '../src/common/entities/DirectoryDTO'; import {FileDTO} from '../src/common/entities/FileDTO'; @@ -31,6 +31,8 @@ export class TestHelper { dir.name = name; dir.path = DiskMangerWorker.pathFromParent({path: '', name: '.'}); dir.mediaCount = 0; + dir.youngestMedia = 10; + dir.oldestMedia = 1000; dir.directories = []; dir.metaFile = []; dir.media = []; @@ -272,6 +274,8 @@ export class TestHelper { name: DiskMangerWorker.dirName(forceStr || Math.random().toString(36).substring(7)), path: DiskMangerWorker.pathFromParent({path: '', name: '.'}), mediaCount: 0, + youngestMedia: 10, + oldestMedia: 1000, directories: [], metaFile: [], cover: null, diff --git a/test/backend/unit/model/sql/PreviewManager.spec.ts b/test/backend/unit/model/sql/PreviewManager.spec.ts index b1752e8f..1ed3be43 100644 --- a/test/backend/unit/model/sql/PreviewManager.spec.ts +++ b/test/backend/unit/model/sql/PreviewManager.spec.ts @@ -147,6 +147,8 @@ describe('CoverManager', (sqlHelper: DBTestHelper) => { delete (ret.directory as DirectoryBaseDTO).lastScanned; delete (ret.directory as DirectoryBaseDTO).lastModified; delete (ret.directory as DirectoryBaseDTO).mediaCount; + delete (ret.directory as DirectoryBaseDTO).youngestMedia; + delete (ret.directory as DirectoryBaseDTO).oldestMedia; delete (ret as PhotoDTO).metadata; tmpDir.directories = tmpD; tmpDir.media = tmpM; diff --git a/test/backend/unit/model/sql/SearchManager.spec.ts b/test/backend/unit/model/sql/SearchManager.spec.ts index 0fa56729..63935fe7 100644 --- a/test/backend/unit/model/sql/SearchManager.spec.ts +++ b/test/backend/unit/model/sql/SearchManager.spec.ts @@ -229,6 +229,8 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => { delete (ret.directory as DirectoryBaseDTO).lastScanned; delete (ret.directory as DirectoryBaseDTO).lastModified; delete (ret.directory as DirectoryBaseDTO).mediaCount; + delete (ret.directory as DirectoryBaseDTO).youngestMedia; + delete (ret.directory as DirectoryBaseDTO).oldestMedia; if ((ret as PhotoDTO).metadata && ((ret as PhotoDTO).metadata as PhotoMetadata).faces && !((ret as PhotoDTO).metadata as PhotoMetadata).faces.length) { delete ((ret as PhotoDTO).metadata as PhotoMetadata).faces;