Skip to content

Commit

Permalink
Replace readyThumbnail filed with missingThumbnail bitmap.
Browse files Browse the repository at this point in the history
Expected to save 6% on the server result json size.

#437
  • Loading branch information
bpatrik committed Mar 26, 2022
1 parent 9b71674 commit 845c70f
Show file tree
Hide file tree
Showing 14 changed files with 54 additions and 59 deletions.
22 changes: 10 additions & 12 deletions src/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
}

}

}
Expand Down
6 changes: 0 additions & 6 deletions src/backend/model/database/sql/GalleryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}


Expand Down Expand Up @@ -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}));
Expand Down
7 changes: 0 additions & 7 deletions src/backend/model/database/sql/IndexingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
5 changes: 1 addition & 4 deletions src/backend/model/database/sql/enitites/MediaEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,5 @@ export abstract class MediaEntity implements MediaDTO {
@Column(type => MediaMetadataEntity)
metadata: MediaMetadataEntity;

readyThumbnails: number[] = [];

readyIcon = false;

missingThumbnails: number;
}
11 changes: 11 additions & 0 deletions src/common/config/public/ClientConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 1 addition & 3 deletions src/common/entities/MediaDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ export interface MediaDTO extends FileDTO {
name: string;
directory: DirectoryPathDTO;
metadata: MediaMetadata;
readyThumbnails: number[];
readyIcon: boolean;

missingThumbnails?: number;
}


Expand Down
2 changes: 1 addition & 1 deletion src/common/entities/PersonDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface PersonDTO {
id: number;
name: string;
count: number;
readyThumbnail?: boolean;
missingThumbnail?: boolean;
isFavourite: boolean;
}

Expand Down
5 changes: 1 addition & 4 deletions src/common/entities/PhotoDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ 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 {
id: number;
name: string;
directory: DirectoryPathDTO;
metadata: PhotoMetadata;
readyThumbnails: number[];
readyIcon: boolean;
missingThumbnails?: number;
}

export interface FaceRegionBox {
Expand Down
21 changes: 14 additions & 7 deletions src/frontend/app/ui/gallery/Media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}
}

Expand All @@ -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;
}
}
Expand All @@ -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 {
Expand Down
7 changes: 4 additions & 3 deletions src/frontend/app/ui/gallery/MediaIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 {
Expand Down
13 changes: 8 additions & 5 deletions src/frontend/app/ui/gallery/cache.gallery.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/app/ui/gallery/thumbnailManager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 1 addition & 3 deletions test/backend/unit/model/sql/SearchManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 1 addition & 3 deletions test/backend/unit/model/sql/TestHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down

0 comments on commit 845c70f

Please sign in to comment.