diff --git a/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts b/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts index 027e37e..8d32dc3 100644 --- a/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts +++ b/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts @@ -11,10 +11,9 @@ import {Config} from '../../../common/config/private/Config'; import {ThumbnailProcessingLib} from '../../../common/config/private/IPrivateConfig'; import {ThumbnailTH} from '../../model/threading/ThreadPool'; import {RendererInput, ThumbnailSourceType, ThumbnailWorker} from '../../model/threading/ThumbnailWorker'; - import {MediaDTO} from '../../../common/entities/MediaDTO'; import {ITaskExecuter, TaskExecuter} from '../../model/threading/TaskExecuter'; -import {PhotoDTO} from '../../../common/entities/PhotoDTO'; +import {FaceRegion, PhotoDTO} from '../../../common/entities/PhotoDTO'; export class ThumbnailGeneratorMWs { @@ -87,17 +86,17 @@ export class ThumbnailGeneratorMWs { // load parameters const mediaPath = path.join(ProjectPath.ImageFolder, photo.directory.path, photo.directory.name, photo.name); const size: number = Config.Client.Thumbnail.personThumbnailSize; - const personName = photo.metadata.faces[0].name; // generate thumbnail path - const thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generatePersonThumbnailName(mediaPath, personName, size)); + const thPath = path.join(ProjectPath.ThumbnailFolder, + ThumbnailGeneratorMWs.generatePersonThumbnailName(mediaPath, photo.metadata.faces[0], size)); req.resultPipe = thPath; // check if thumbnail already exist if (fs.existsSync(thPath) === true) { - return next(); - } + return next(); + } // create thumbnail folder if not exist if (!fs.existsSync(ProjectPath.ThumbnailFolder)) { @@ -170,8 +169,9 @@ export class ThumbnailGeneratorMWs { return crypto.createHash('md5').update(mediaPath).digest('hex') + '_' + size + '.jpg'; } - public static generatePersonThumbnailName(mediaPath: string, personName: string, size: number): string { - return crypto.createHash('md5').update(mediaPath + '_' + personName).digest('hex') + '_' + size + '.jpg'; + public static generatePersonThumbnailName(mediaPath: string, faceRegion: FaceRegion, size: number): string { + return crypto.createHash('md5').update(mediaPath + '_' + faceRegion.name + '_' + faceRegion.box.x + '_' + faceRegion.box.y) + .digest('hex') + '_' + size + '.jpg'; } private static addThInfoTODir(directory: DirectoryDTO) { diff --git a/backend/model/threading/ThumbnailWorker.ts b/backend/model/threading/ThumbnailWorker.ts index 374164f..4279980 100644 --- a/backend/model/threading/ThumbnailWorker.ts +++ b/backend/model/threading/ThumbnailWorker.ts @@ -66,7 +66,7 @@ export class VideoRendererFactory { ffmpeg(input.mediaPath).ffprobe((err: any, data: FfprobeData) => { if (!!err || data === null) { - return reject(err.toString()); + return reject('[FFmpeg] ' + err.toString()); } /// console.log(data); let width = null; @@ -79,7 +79,7 @@ export class VideoRendererFactory { } } if (!width || !height) { - return reject('Can not read video dimension'); + return reject('[FFmpeg] Can not read video dimension'); } const ratio = height / width; const command: FfmpegCommand = ffmpeg(input.mediaPath); @@ -94,7 +94,7 @@ export class VideoRendererFactory { resolve(); }) .on('error', (e) => { - reject(e.toString() + ' executed: ' + executedCmd); + reject('[FFmpeg] ' + e.toString() + ' executed: ' + executedCmd); }) .outputOptions(['-qscale:v 4']); if (input.makeSquare === false) { @@ -168,7 +168,7 @@ export class ImageRendererFactory { await new Promise((resolve, reject) => { image.write(input.thPath, (err: Error | null) => { // save if (err) { - return reject(err); + return reject('[JimpThRenderer] ' + err.toString()); } resolve(); }); @@ -233,7 +233,7 @@ export class ImageRendererFactory { let image: State = gm(input.mediaPath); image.size((err, value: Dimensions) => { if (err) { - return reject(err); + return reject('[GMThRenderer] ' + err.toString()); } /** @@ -259,12 +259,12 @@ export class ImageRendererFactory { } image.write(input.thPath, (e) => { if (e) { - return reject(e); + return reject('[GMThRenderer] ' + e.toString()); } return resolve(); }); } catch (err) { - return reject(err); + return reject('[GMThRenderer] ' + err.toString()); } }); }); diff --git a/frontend/app/duplicates/duplicates.component.ts b/frontend/app/duplicates/duplicates.component.ts index 79c4b2d..8654f8f 100644 --- a/frontend/app/duplicates/duplicates.component.ts +++ b/frontend/app/duplicates/duplicates.component.ts @@ -95,6 +95,10 @@ export class DuplicateComponent implements OnDestroy { this.renderTimer = null; } + if (this.directoryGroups.length === 0) { + return; + } + if (this.renderedIndex.group === this.directoryGroups.length - 1 && this.renderedIndex.pairs >= this.directoryGroups[this.renderedIndex.group].duplicates.length) { diff --git a/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts b/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts index 43e56ed..2a1c3c6 100644 --- a/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts +++ b/frontend/app/gallery/grid/photo/photo.grid.gallery.component.ts @@ -62,7 +62,9 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, OnDestroy { const metadata = this.gridPhoto.media.metadata as PhotoMetadata; if ((metadata.keywords && metadata.keywords.length > 0) || (metadata.faces && metadata.faces.length > 0)) { - this.keywords = (metadata.faces || []).map(f => ({value: f.name, type: SearchTypes.person})) + const names: string[] = (metadata.faces || []).map(f => f.name); + this.keywords = names.filter((name, index) => names.indexOf(name) === index) + .map(n => ({value: n, type: SearchTypes.person})) .concat((metadata.keywords || []).map(k => ({value: k, type: SearchTypes.keyword}))); } diff --git a/frontend/app/gallery/share.service.ts b/frontend/app/gallery/share.service.ts index fd0bd19..525de4a 100644 --- a/frontend/app/gallery/share.service.ts +++ b/frontend/app/gallery/share.service.ts @@ -53,7 +53,6 @@ export class ShareService { public setUserObs(userOB: Observable) { userOB.subscribe((user) => { - console.log(user); if (user && !!user.usedSharingKey) { if (user.usedSharingKey !== this.sharingKey) { this.sharingKey = user.usedSharingKey;