1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2024-11-03 21:04:03 +08:00

Smaller performance tweeks to thumbnail reading

#437
This commit is contained in:
Patrik J. Braun 2022-06-27 23:46:17 +02:00
parent c06620a795
commit 849ebbec9e
4 changed files with 58 additions and 43 deletions

View File

@ -1,23 +1,23 @@
import * as path from 'path';
import * as fs from 'fs';
import { NextFunction, Request, Response } from 'express';
import { ErrorCodes, ErrorDTO } from '../../../common/entities/Error';
import { ContentWrapper } from '../../../common/entities/ConentWrapper';
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../../common/entities/Error';
import {ContentWrapper} from '../../../common/entities/ConentWrapper';
import {
ParentDirectoryDTO,
SubDirectoryDTO,
} from '../../../common/entities/DirectoryDTO';
import { ProjectPath } from '../../ProjectPath';
import { Config } from '../../../common/config/private/Config';
import { ThumbnailSourceType } from '../../model/threading/PhotoWorker';
import { MediaDTO } from '../../../common/entities/MediaDTO';
import { PhotoProcessing } from '../../model/fileprocessing/PhotoProcessing';
import { PersonWithSampleRegion } from '../../../common/entities/PersonDTO';
import { ServerTime } from '../ServerTimingMWs';
import {ProjectPath} from '../../ProjectPath';
import {Config} from '../../../common/config/private/Config';
import {ThumbnailSourceType} from '../../model/threading/PhotoWorker';
import {MediaDTO} from '../../../common/entities/MediaDTO';
import {PhotoProcessing} from '../../model/fileprocessing/PhotoProcessing';
import {PersonWithSampleRegion} from '../../../common/entities/PersonDTO';
import {ServerTime} from '../ServerTimingMWs';
export class ThumbnailGeneratorMWs {
private static ThumbnailMap: { [key: number]: number } =
Config.Client.Media.Thumbnail.generateThumbnailMap();
private static ThumbnailMapEntries =
Config.Client.Media.Thumbnail.generateThumbnailMapEntries();
@ServerTime('2.th', 'Thumbnail decoration')
public static async addThumbnailInformation(
@ -34,6 +34,10 @@ export class ThumbnailGeneratorMWs {
if (cw.notModified === true) {
return next();
}
// regenerate in case the list change since startup
ThumbnailGeneratorMWs.ThumbnailMapEntries =
Config.Client.Media.Thumbnail.generateThumbnailMapEntries();
if (cw.directory) {
ThumbnailGeneratorMWs.addThInfoTODir(cw.directory);
}
@ -209,8 +213,6 @@ export class ThumbnailGeneratorMWs {
private static addThInfoTODir(
directory: ParentDirectoryDTO | SubDirectoryDTO
): void {
ThumbnailGeneratorMWs.ThumbnailMap =
Config.Client.Media.Thumbnail.generateThumbnailMap();
if (typeof directory.media !== 'undefined') {
ThumbnailGeneratorMWs.addThInfoToPhotos(directory.media);
}
@ -220,8 +222,8 @@ export class ThumbnailGeneratorMWs {
}
private static addThInfoToPhotos(photos: MediaDTO[]): void {
for (const item of photos) {
this.addThInfoToAPhoto(item);
for (let i = 0; i < photos.length; ++i) {
this.addThInfoToAPhoto(photos[i]);
}
}
@ -232,19 +234,18 @@ export class ThumbnailGeneratorMWs {
photo.directory.name,
photo.name
);
for (const _s of Object.keys(ThumbnailGeneratorMWs.ThumbnailMap)) {
const size = parseInt(_s)
for (let i = 0; i < ThumbnailGeneratorMWs.ThumbnailMapEntries.length; ++i) {
const entry = ThumbnailGeneratorMWs.ThumbnailMapEntries[i];
const thPath = PhotoProcessing.generateConvertedPath(
fullMediaPath,
size
entry.size
);
if (fs.existsSync(thPath) !== true) {
if (typeof photo.missingThumbnails === 'undefined') {
photo.missingThumbnails = 0;
}
// this is a bitwise operation
photo.missingThumbnails +=
ThumbnailGeneratorMWs.ThumbnailMap[size];
photo.missingThumbnails += entry.bit;
}
}
}

View File

@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/no-inferrable-types */
import 'reflect-metadata';
import { SortingMethods } from '../../entities/SortingMethods';
import { UserRoles } from '../../entities/UserDTO';
import { ConfigProperty, SubConfigClass } from 'typeconfig/common';
import { IPrivateConfig } from '../private/PrivateConfig';
import {SortingMethods} from '../../entities/SortingMethods';
import {UserRoles} from '../../entities/UserDTO';
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
import {IPrivateConfig} from '../private/PrivateConfig';
export enum MapProviders {
OpenStreetMap = 1,
@ -15,11 +15,11 @@ export enum MapProviders {
export class AutoCompleteConfig {
@ConfigProperty()
enabled: boolean = true;
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
targetItemsPerCategory: number = 5;
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
maxItems: number = 30;
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
cacheTimeout: number = 1000 * 60 * 60;
}
@ -27,11 +27,11 @@ export class AutoCompleteConfig {
export class ClientSearchConfig {
@ConfigProperty()
enabled: boolean = true;
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
searchCacheTimeout: number = 1000 * 60 * 60;
@ConfigProperty()
AutoComplete: AutoCompleteConfig = new AutoCompleteConfig();
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
maxMediaResult: number = 10000;
@ConfigProperty({
description: 'Search returns also with directories, not just media',
@ -42,7 +42,7 @@ export class ClientSearchConfig {
'Search also returns with metafiles from directories that contain a media file of the matched search result',
})
listMetafiles: boolean = true;
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
maxDirectoryResult: number = 200;
}
@ -62,7 +62,7 @@ export class ClientSharingConfig {
@SubConfigClass()
export class ClientRandomPhotoConfig {
@ConfigProperty({ description: 'Enables random link generation.' })
@ConfigProperty({description: 'Enables random link generation.'})
enabled: boolean = true;
}
@ -92,23 +92,23 @@ export class ClientMapConfig {
maxPreviewMarkers: number = 50;
@ConfigProperty()
useImageMarkers: boolean = true;
@ConfigProperty({ type: MapProviders })
@ConfigProperty({type: MapProviders})
mapProvider: MapProviders = MapProviders.OpenStreetMap;
@ConfigProperty()
mapboxAccessToken: string = '';
@ConfigProperty({ arrayType: MapLayers })
@ConfigProperty({arrayType: MapLayers})
customLayers: MapLayers[] = [new MapLayers()];
}
@SubConfigClass()
export class ClientThumbnailConfig {
@ConfigProperty({ type: 'unsignedInt', max: 100 })
@ConfigProperty({type: 'unsignedInt', max: 100})
iconSize: number = 45;
@ConfigProperty({ type: 'unsignedInt' })
@ConfigProperty({type: 'unsignedInt'})
personThumbnailSize: number = 200;
@ConfigProperty({ arrayType: 'unsignedInt' })
@ConfigProperty({arrayType: 'unsignedInt'})
thumbnailSizes: number[] = [240, 480];
@ConfigProperty({ volatile: true })
@ConfigProperty({volatile: true})
concurrentThumbnailGenerations: number = 1;
/**
@ -121,6 +121,13 @@ export class ClientThumbnailConfig {
});
return m;
}
/**
* Generates a map for bitwise operation from icon and normal thumbnails
*/
generateThumbnailMapEntries(): { size: number, bit: number }[] {
return Object.entries(this.generateThumbnailMap()).map(v => ({size: parseInt(v[0]), bit: v[1]}));
}
}
@SubConfigClass()
@ -137,7 +144,7 @@ export class ClientOtherConfig {
enableCache: boolean = true;
@ConfigProperty()
enableOnScrollRendering: boolean = true;
@ConfigProperty({ type: SortingMethods })
@ConfigProperty({type: SortingMethods})
defaultPhotoSortingMethod: SortingMethods = SortingMethods.ascDate;
@ConfigProperty({
description:
@ -227,9 +234,9 @@ export class ClientFacesConfig {
enabled: boolean = true;
@ConfigProperty()
keywordsToPersons: boolean = true;
@ConfigProperty({ type: UserRoles })
@ConfigProperty({type: UserRoles})
writeAccessMinRole: UserRoles = UserRoles.Admin;
@ConfigProperty({ type: UserRoles })
@ConfigProperty({type: UserRoles})
readAccessMinRole: UserRoles = UserRoles.User;
}
@ -255,9 +262,9 @@ export class ClientConfig {
Other: ClientOtherConfig = new ClientOtherConfig();
@ConfigProperty()
authenticationRequired: boolean = true;
@ConfigProperty({ type: UserRoles })
@ConfigProperty({type: UserRoles})
unAuthenticatedUserRole: UserRoles = UserRoles.Admin;
@ConfigProperty({ arrayType: 'string', volatile: true })
@ConfigProperty({arrayType: 'string', volatile: true})
languages: string[] | undefined;
@ConfigProperty()
Media: ClientMediaConfig = new ClientMediaConfig();

View File

@ -164,6 +164,10 @@ export class ContentWrapper {
}
}
if (m.missingThumbnails === 0) {
delete m.missingThumbnails;
}
if (MediaDTOUtils.isPhoto(m)) {
delete (m as VideoDTO).metadata.bitRate;
delete (m as VideoDTO).metadata.duration;

View File

@ -34,6 +34,9 @@ describe('ContentWrapper', () => {
delete (m as PhotoDTO).metadata.faces;
delete (m as PhotoDTO).metadata.positionData;
}
if (m.missingThumbnails === 0) {
delete m.missingThumbnails;
}
}
for (let i = 0; i < content.metaFile.length; ++i) {
delete content.metaFile[i].id;