diff --git a/src/backend/ProjectPath.ts b/src/backend/ProjectPath.ts index 6d22d79..84df68e 100644 --- a/src/backend/ProjectPath.ts +++ b/src/backend/ProjectPath.ts @@ -7,6 +7,7 @@ class ProjectPathClass { public ImageFolder: string; public ThumbnailFolder: string; public TranscodedFolder: string; + public FacesFolder: string; public FrontendFolder: string; constructor() { @@ -31,6 +32,7 @@ class ProjectPathClass { this.ImageFolder = this.getAbsolutePath(Config.Server.Media.folder); this.ThumbnailFolder = this.getAbsolutePath(Config.Server.Media.tempFolder); this.TranscodedFolder = path.join(this.ThumbnailFolder, 'tc'); + this.FacesFolder = path.join(this.ThumbnailFolder, 'f'); // create thumbnail folder if not exist if (!fs.existsSync(this.ThumbnailFolder)) { diff --git a/src/backend/middlewares/thumbnail/PhotoConverterMWs.ts b/src/backend/middlewares/thumbnail/PhotoConverterMWs.ts index 345b238..e2e514a 100644 --- a/src/backend/middlewares/thumbnail/PhotoConverterMWs.ts +++ b/src/backend/middlewares/thumbnail/PhotoConverterMWs.ts @@ -15,7 +15,7 @@ export class PhotoConverterMWs { } const fullMediaPath = req.resultPipe; - const convertedVideo = PhotoProcessing.generateConvertedFileName(fullMediaPath); + const convertedVideo = PhotoProcessing.generateConvertedFilePath(fullMediaPath); // check if transcoded video exist if (fs.existsSync(convertedVideo) === true) { diff --git a/src/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts b/src/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts index 5d5467e..472773c 100644 --- a/src/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts +++ b/src/backend/middlewares/thumbnail/ThumbnailGeneratorMWs.ts @@ -6,7 +6,7 @@ import {ContentWrapper} from '../../../common/entities/ConentWrapper'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; import {ProjectPath} from '../../ProjectPath'; import {Config} from '../../../common/config/private/Config'; -import {ThumbnailSourceType} from '../../model/threading/ThumbnailWorker'; +import {ThumbnailSourceType} from '../../model/threading/PhotoWorker'; import {MediaDTO} from '../../../common/entities/MediaDTO'; import {PersonWithPhoto} from '../PersonMWs'; import {PhotoProcessing} from '../../model/fileprocessing/PhotoProcessing'; @@ -56,8 +56,7 @@ export class ThumbnailGeneratorMWs { persons[i].samplePhoto.directory.name, persons[i].samplePhoto.name); // generate thumbnail path - const thPath = path.join(ProjectPath.ThumbnailFolder, - PhotoProcessing.generatePersonThumbnailName(mediaPath, persons[i].samplePhoto.metadata.faces[0], size)); + const thPath = PhotoProcessing.generatePersonThumbnailPath(mediaPath, persons[i].samplePhoto.metadata.faces[0], size); persons[i].readyThumbnail = fs.existsSync(thPath); } @@ -151,7 +150,7 @@ export class ThumbnailGeneratorMWs { const fullMediaPath = path.join(ProjectPath.ImageFolder, photos[i].directory.path, photos[i].directory.name, photos[i].name); for (let j = 0; j < Config.Client.Media.Thumbnail.thumbnailSizes.length; j++) { const size = Config.Client.Media.Thumbnail.thumbnailSizes[j]; - const thPath = path.join(thumbnailFolder, PhotoProcessing.generateThumbnailName(fullMediaPath, size)); + const thPath = PhotoProcessing.generateThumbnailPath(fullMediaPath, size); if (fs.existsSync(thPath) === true) { if (typeof photos[i].readyThumbnails === 'undefined') { photos[i].readyThumbnails = []; @@ -159,8 +158,7 @@ export class ThumbnailGeneratorMWs { photos[i].readyThumbnails.push(size); } } - const iconPath = path.join(thumbnailFolder, - PhotoProcessing.generateThumbnailName(fullMediaPath, Config.Client.Media.Thumbnail.iconSize)); + const iconPath = PhotoProcessing.generateThumbnailPath(fullMediaPath, Config.Client.Media.Thumbnail.iconSize); if (fs.existsSync(iconPath) === true) { photos[i].readyIcon = true; } diff --git a/src/backend/model/fileprocessing/PhotoProcessing.ts b/src/backend/model/fileprocessing/PhotoProcessing.ts index a09f789..e3e393b 100644 --- a/src/backend/model/fileprocessing/PhotoProcessing.ts +++ b/src/backend/model/fileprocessing/PhotoProcessing.ts @@ -5,7 +5,7 @@ import * as crypto from 'crypto'; import {ProjectPath} from '../../ProjectPath'; import {Config} from '../../../common/config/private/Config'; import {ThumbnailTH} from '../threading/ThreadPool'; -import {RendererInput, ThumbnailSourceType, ThumbnailWorker} from '../threading/ThumbnailWorker'; +import {PhotoWorker, RendererInput, ThumbnailSourceType} from '../threading/PhotoWorker'; import {ITaskExecuter, TaskExecuter} from '../threading/TaskExecuter'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; import {FaceRegion, PhotoDTO} from '../../../common/entities/PhotoDTO'; @@ -37,7 +37,7 @@ export class PhotoProcessing { this.taskQue = new ThumbnailTH(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations); } else { this.taskQue = new TaskExecuter(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations, - (input => ThumbnailWorker.render(input, Config.Server.Media.photoProcessingLibrary))); + (input => PhotoWorker.render(input, Config.Server.Media.photoProcessingLibrary))); } this.initDone = true; @@ -56,8 +56,7 @@ export class PhotoProcessing { const mediaPath = path.join(ProjectPath.ImageFolder, photo.directory.path, photo.directory.name, photo.name); const size: number = Config.Client.Media.Thumbnail.personThumbnailSize; // generate thumbnail path - const thPath = path.join(ProjectPath.ThumbnailFolder, - PhotoProcessing.generatePersonThumbnailName(mediaPath, photo.metadata.faces[0], size)); + const thPath = PhotoProcessing.generatePersonThumbnailPath(mediaPath, photo.metadata.faces[0], size); // check if thumbnail already exist @@ -95,17 +94,22 @@ export class PhotoProcessing { } - public static generateThumbnailName(mediaPath: string, size: number): string { - return crypto.createHash('md5').update(mediaPath).digest('hex') + '_' + size + '.jpg'; + public static generateThumbnailPath(mediaPath: string, size: number): string { + const extension = path.extname(mediaPath); + const file = path.basename(mediaPath, extension); + return path.join(ProjectPath.TranscodedFolder, + ProjectPath.getRelativePathToImages(path.dirname(mediaPath)), file + + '_' + size + '.jpg'); } - public static generatePersonThumbnailName(mediaPath: string, faceRegion: FaceRegion, size: number): string { - return crypto.createHash('md5').update(mediaPath + '_' + faceRegion.name + '_' + faceRegion.box.left + '_' + faceRegion.box.top) - .digest('hex') + '_' + size + '.jpg'; + public static generatePersonThumbnailPath(mediaPath: string, faceRegion: FaceRegion, size: number): string { + return path.join(ProjectPath.FacesFolder, + crypto.createHash('md5').update(mediaPath + '_' + faceRegion.name + '_' + faceRegion.box.left + '_' + faceRegion.box.top) + .digest('hex') + '_' + size + '.jpg'); } - public static generateConvertedFileName(photoPath: string): string { + public static generateConvertedFilePath(photoPath: string): string { const extension = path.extname(photoPath); const file = path.basename(photoPath, extension); const postfix = Config.Server.Media.Photo.Converting.resolution; @@ -117,7 +121,7 @@ export class PhotoProcessing { public static async convertPhoto(mediaPath: string, size: number) { // generate thumbnail path - const outPath = PhotoProcessing.generateConvertedFileName(mediaPath); + const outPath = PhotoProcessing.generateConvertedFilePath(mediaPath); // check if file already exist @@ -149,7 +153,7 @@ export class PhotoProcessing { sourceType: ThumbnailSourceType, makeSquare: boolean) { // generate thumbnail path - const outPath = path.join(ProjectPath.ThumbnailFolder, PhotoProcessing.generateThumbnailName(mediaPath, size)); + const outPath = PhotoProcessing.generateThumbnailPath(mediaPath, size); // check if thumbnail already exist diff --git a/src/backend/model/jobs/jobs/PhotoConvertingJob.ts b/src/backend/model/jobs/jobs/PhotoConvertingJob.ts index a3cc20a..772461d 100644 --- a/src/backend/model/jobs/jobs/PhotoConvertingJob.ts +++ b/src/backend/model/jobs/jobs/PhotoConvertingJob.ts @@ -31,7 +31,7 @@ export class PhotoConvertingJob extends FileJob { directory.media[i].directory.name, directory.media[i].name); - if (await existsPr(PhotoProcessing.generateConvertedFileName(photoPath)) === false) { + if (await existsPr(PhotoProcessing.generateConvertedFilePath(photoPath)) === false) { ret.push(photoPath); } } diff --git a/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts b/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts index edd2149..9a1fd2e 100644 --- a/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts +++ b/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts @@ -7,7 +7,7 @@ import * as util from 'util'; import {FileJob} from './FileJob'; import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO'; import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing'; -import {ThumbnailSourceType} from '../../threading/ThumbnailWorker'; +import {ThumbnailSourceType} from '../../threading/PhotoWorker'; import {MediaDTO} from '../../../../common/entities/MediaDTO'; const LOG_TAG = '[ThumbnailGenerationJob]'; diff --git a/src/backend/model/threading/ThumbnailWorker.ts b/src/backend/model/threading/PhotoWorker.ts similarity index 95% rename from src/backend/model/threading/ThumbnailWorker.ts rename to src/backend/model/threading/PhotoWorker.ts index a7911c6..3473082 100644 --- a/src/backend/model/threading/ThumbnailWorker.ts +++ b/src/backend/model/threading/PhotoWorker.ts @@ -5,7 +5,7 @@ import {FfmpegCommand, FfprobeData} from 'fluent-ffmpeg'; import {FFmpegFactory} from '../FFmpegFactory'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; -export class ThumbnailWorker { +export class PhotoWorker { private static imageRenderer: (input: RendererInput) => Promise = null; private static videoRenderer: (input: RendererInput) => Promise = null; @@ -19,19 +19,19 @@ export class ThumbnailWorker { } public static renderFromImage(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise { - if (ThumbnailWorker.rendererType !== renderer) { - ThumbnailWorker.imageRenderer = ImageRendererFactory.build(renderer); - ThumbnailWorker.rendererType = renderer; + if (PhotoWorker.rendererType !== renderer) { + PhotoWorker.imageRenderer = ImageRendererFactory.build(renderer); + PhotoWorker.rendererType = renderer; } - return ThumbnailWorker.imageRenderer(input); + return PhotoWorker.imageRenderer(input); } public static renderFromVideo(input: RendererInput): Promise { - if (ThumbnailWorker.videoRenderer === null) { - ThumbnailWorker.videoRenderer = VideoRendererFactory.build(); + if (PhotoWorker.videoRenderer === null) { + PhotoWorker.videoRenderer = VideoRendererFactory.build(); } - return ThumbnailWorker.videoRenderer(input); + return PhotoWorker.videoRenderer(input); } } diff --git a/src/backend/model/threading/ThreadPool.ts b/src/backend/model/threading/ThreadPool.ts index 9ac7774..1faac29 100644 --- a/src/backend/model/threading/ThreadPool.ts +++ b/src/backend/model/threading/ThreadPool.ts @@ -2,7 +2,7 @@ import * as cluster from 'cluster'; import {Logger} from '../../Logger'; import {DiskManagerTask, ThumbnailTask, WorkerMessage, WorkerTask, WorkerTaskTypes} from './Worker'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; -import {RendererInput} from './ThumbnailWorker'; +import {RendererInput} from './PhotoWorker'; import {Config} from '../../../common/config/private/Config'; import {TaskQue, TaskQueEntry} from './TaskQue'; import {ITaskExecuter} from './TaskExecuter'; diff --git a/src/backend/model/threading/Worker.ts b/src/backend/model/threading/Worker.ts index ba60a85..42dd48b 100644 --- a/src/backend/model/threading/Worker.ts +++ b/src/backend/model/threading/Worker.ts @@ -1,6 +1,6 @@ import {DiskMangerWorker} from './DiskMangerWorker'; import {Logger} from '../../Logger'; -import {RendererInput, ThumbnailWorker} from './ThumbnailWorker'; +import {RendererInput, PhotoWorker} from './PhotoWorker'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; import {Utils} from '../../../common/Utils'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; @@ -22,7 +22,7 @@ export class Worker { } break; case WorkerTaskTypes.thumbnail: - result = await ThumbnailWorker.render((task).input, (task).renderer); + result = await PhotoWorker.render((task).input, (task).renderer); break; default: throw new Error('Unknown worker task type'); diff --git a/src/backend/routes/GalleryRouter.ts b/src/backend/routes/GalleryRouter.ts index b893b93..962c32d 100644 --- a/src/backend/routes/GalleryRouter.ts +++ b/src/backend/routes/GalleryRouter.ts @@ -4,7 +4,7 @@ import {GalleryMWs} from '../middlewares/GalleryMWs'; import {RenderingMWs} from '../middlewares/RenderingMWs'; import {ThumbnailGeneratorMWs} from '../middlewares/thumbnail/ThumbnailGeneratorMWs'; import {UserRoles} from '../../common/entities/UserDTO'; -import {ThumbnailSourceType} from '../model/threading/ThumbnailWorker'; +import {ThumbnailSourceType} from '../model/threading/PhotoWorker'; import {VersionMWs} from '../middlewares/VersionMWs'; import {SupportedFormats} from '../../common/SupportedFormats'; import {PhotoConverterMWs} from '../middlewares/thumbnail/PhotoConverterMWs';