1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-01-04 03:49:28 +02:00

Replace readyThumbnail filed with missingThumbnail bitmap.

Expected to save 6% on the server result json size.

#437
This commit is contained in:
Patrik J. Braun 2022-03-26 11:55:15 +01:00
parent 9b71674ef7
commit 845c70f6c6
14 changed files with 54 additions and 59 deletions

View File

@ -14,6 +14,7 @@ import {ServerTime} from '../ServerTimingMWs';
export class ThumbnailGeneratorMWs {
private static ThumbnailMap: { [key: number]: number };
@ServerTime('2.th', 'Thumbnail decoration')
public static async addThumbnailInformation(req: Request, res: Response, next: NextFunction): Promise<any> {
@ -67,7 +68,7 @@ export class ThumbnailGeneratorMWs {
// generate thumbnail path
const thPath = PhotoProcessing.generatePersonThumbnailPath(mediaPath, item.sampleRegion, size);
item.readyThumbnail = fs.existsSync(thPath);
item.missingThumbnail = !fs.existsSync(thPath);
}
} catch (error) {
@ -148,6 +149,7 @@ 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);
}
@ -164,20 +166,16 @@ export class ThumbnailGeneratorMWs {
private static addThInfoToAPhoto(photo: MediaDTO): void {
const fullMediaPath = path.join(ProjectPath.ImageFolder, photo.directory.path, photo.directory.name, photo.name);
for (const size of Config.Client.Media.Thumbnail.thumbnailSizes) {
const thPath = PhotoProcessing.generateConvertedPath(fullMediaPath, size);
if (fs.existsSync(thPath) === true) {
if (typeof photo.readyThumbnails === 'undefined') {
photo.readyThumbnails = [];
for (const size of Object.keys(ThumbnailGeneratorMWs.ThumbnailMap)) {
const thPath = PhotoProcessing.generateConvertedPath(fullMediaPath, size as any);
if (fs.existsSync(thPath) !== true) {
if (typeof photo.missingThumbnails === 'undefined') {
photo.missingThumbnails = 0;
}
photo.readyThumbnails.push(size);
// this is a bitwise operation
photo.missingThumbnails += ThumbnailGeneratorMWs.ThumbnailMap[size as any];
}
}
const iconPath = PhotoProcessing.generateConvertedPath(fullMediaPath, Config.Client.Media.Thumbnail.iconSize);
if (fs.existsSync(iconPath) === true) {
photo.readyIcon = true;
}
}
}

View File

@ -229,10 +229,6 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
dir.media = [];
dir.isPartial = true;
if (dir.preview) {
dir.preview.readyThumbnails = [];
dir.preview.readyIcon = false;
}
}
@ -282,8 +278,6 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
.getMany();
for (const item of dir.media) {
item.directory = dir;
item.readyThumbnails = [];
item.readyIcon = false;
(item as PhotoDTO).metadata.faces = indexedFaces
.filter((fe): boolean => fe.media.id === item.id)
.map((f): { name: any; box: any } => ({box: f.box, name: f.person.name}));

View File

@ -61,13 +61,6 @@ export class IndexingManager implements IIndexingManager {
try {
const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName);
// returning with the result
if (scannedDirectory.preview) {
scannedDirectory.preview.readyThumbnails = [];
}
scannedDirectory.media.forEach((p): any[] => p.readyThumbnails = []);
const dirClone = Utils.shallowClone(scannedDirectory);
// filter server side only config from returning
dirClone.metaFile = dirClone.metaFile.filter(m => !ServerPG2ConfMap[m.name]);

View File

@ -167,8 +167,5 @@ export abstract class MediaEntity implements MediaDTO {
@Column(type => MediaMetadataEntity)
metadata: MediaMetadataEntity;
readyThumbnails: number[] = [];
readyIcon = false;
missingThumbnails: number;
}

View File

@ -103,6 +103,17 @@ export class ClientThumbnailConfig {
thumbnailSizes: number[] = [240, 480];
@ConfigProperty({volatile: true})
concurrentThumbnailGenerations: number = 1;
/**
* Generates a map for bitwise operation from icon and normal thumbnails
*/
generateThumbnailMap(): { [key: number]: number } {
const m: { [key: number]: number } = {};
[this.iconSize, ...this.thumbnailSizes.sort()].forEach((v, i) => {
m[v] = Math.pow(2, i + 1);
});
return m;
}
}
@SubConfigClass()

View File

@ -9,9 +9,7 @@ export interface MediaDTO extends FileDTO {
name: string;
directory: DirectoryPathDTO;
metadata: MediaMetadata;
readyThumbnails: number[];
readyIcon: boolean;
missingThumbnails?: number;
}

View File

@ -8,7 +8,7 @@ export interface PersonDTO {
id: number;
name: string;
count: number;
readyThumbnail?: boolean;
missingThumbnail?: boolean;
isFavourite: boolean;
}

View File

@ -5,8 +5,6 @@ import {MediaDimension, MediaDTO, MediaMetadata} from './MediaDTO';
export interface PreviewPhotoDTO extends MediaDTO {
name: string;
directory: DirectoryPathDTO;
readyThumbnails: number[];
readyIcon: boolean;
}
export interface PhotoDTO extends PreviewPhotoDTO, MediaDTO {
@ -14,8 +12,7 @@ export interface PhotoDTO extends PreviewPhotoDTO, MediaDTO {
name: string;
directory: DirectoryPathDTO;
metadata: PhotoMetadata;
readyThumbnails: number[];
readyIcon: boolean;
missingThumbnails?: number;
}
export interface FaceRegionBox {

View File

@ -14,9 +14,13 @@ export class Media extends MediaIcon {
thumbnailLoaded(): void {
console.log(this.media.name, this.media.missingThumbnails);
if (!this.isThumbnailAvailable()) {
this.media.readyThumbnails = this.media.readyThumbnails || [];
this.media.readyThumbnails.push(this.getThumbnailSize());
this.media.missingThumbnails = this.media.missingThumbnails || 0;
this.media.missingThumbnails -= MediaIcon.ThumbnailMap[this.getThumbnailSize()];
if (this.media.missingThumbnails < 0) {
throw new Error('missingThumbnails got below 0');
}
}
}
@ -31,10 +35,12 @@ export class Media extends MediaIcon {
this.replacementSizeCache = null;
const size = this.getThumbnailSize();
if (!!this.media.readyThumbnails) {
for (const item of this.media.readyThumbnails) {
if (item < size) {
this.replacementSizeCache = item;
if (!!this.media.missingThumbnails) {
for (const thSize of Config.Client.Media.Thumbnail.thumbnailSizes) {
// tslint:disable-next-line:no-bitwise
if ((this.media.missingThumbnails & MediaIcon.ThumbnailMap[thSize]) === 0 &&
thSize < size) {
this.replacementSizeCache = thSize;
break;
}
}
@ -48,7 +54,8 @@ export class Media extends MediaIcon {
}
isThumbnailAvailable(): boolean {
return this.media.readyThumbnails && this.media.readyThumbnails.indexOf(this.getThumbnailSize()) !== -1;
// tslint:disable-next-line:no-bitwise
return (this.media.missingThumbnails & MediaIcon.ThumbnailMap[this.getThumbnailSize()]) === 0;
}
getReplacementThumbnailPath(): string {

View File

@ -3,7 +3,7 @@ import {Config} from '../../../../common/config/public/Config';
import {MediaDTO} from '../../../../common/entities/MediaDTO';
export class MediaIcon {
protected static readonly ThumbnailMap = Config.Client.Media.Thumbnail.generateThumbnailMap();
protected replacementSizeCache: number | boolean = false;
@ -16,11 +16,12 @@ export class MediaIcon {
}
iconLoaded(): void {
this.media.readyIcon = true;
this.media.missingThumbnails -= MediaIcon.ThumbnailMap[Config.Client.Media.Thumbnail.iconSize];
}
isIconAvailable(): boolean {
return this.media.readyIcon;
// tslint:disable-next-line:no-bitwise
return (this.media.missingThumbnails & MediaIcon.ThumbnailMap[Config.Client.Media.Thumbnail.iconSize]) === 0;
}
getRelativePath(): string {

View File

@ -244,24 +244,27 @@ export class GalleryCacheService {
* @param media: MediaBaseDTO
*/
public mediaUpdated(media: MediaDTO): void {
if (Config.Client.Other.enableCache === false) {
return;
}
try {
const directoryName = Utils.concatUrls(media.directory.path, media.directory.name);
const value = localStorage.getItem(directoryName);
const directoryKey = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(media.directory.path, media.directory.name);
const value = localStorage.getItem(directoryKey);
if (value != null) {
const directory: ParentDirectoryDTO = JSON.parse(value);
directory.media.forEach((p) => {
if (p.name === media.name) {
// update data
p.metadata = media.metadata;
p.readyThumbnails = media.readyThumbnails;
if (media.missingThumbnails) {
p.missingThumbnails = media.missingThumbnails;
} else {
delete p.missingThumbnails;
}
// save changes
localStorage.setItem(directoryName, JSON.stringify(directory));
localStorage.setItem(directoryKey, JSON.stringify(directory));
return;
}
});

View File

@ -83,7 +83,7 @@ export class PersonThumbnail extends ThumbnailBase {
super(thumbnailService);
this.src = '';
this.error = false;
if (this.person.readyThumbnail) {
if (!this.person.missingThumbnail) {
this.src = Person.getThumbnailUrl(person);
this.available = true;
if (this.onLoad) {

View File

@ -1240,9 +1240,7 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
name: subDir.name,
path: subDir.path
},
name: pFaceLess.name,
readyIcon: false,
readyThumbnails: []
name: pFaceLess.name
} as any;
const query = {
text: subDir.name,

View File

@ -354,9 +354,7 @@ export class TestHelper {
id: null,
name: rndStr() + '.jpg',
directory: dir,
metadata: m,
readyThumbnails: [],
readyIcon: false
metadata: m
};
for (let i = 0; i < faces; i++) {