1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

replacing flat thumbnail path to shadow original folder hierarchy

preparing tmp folder clean-up task
This commit is contained in:
Patrik J. Braun 2019-12-24 12:44:38 +01:00
parent 5ec9171ddf
commit c3c94c1709
10 changed files with 37 additions and 33 deletions

View File

@ -7,6 +7,7 @@ class ProjectPathClass {
public ImageFolder: string; public ImageFolder: string;
public ThumbnailFolder: string; public ThumbnailFolder: string;
public TranscodedFolder: string; public TranscodedFolder: string;
public FacesFolder: string;
public FrontendFolder: string; public FrontendFolder: string;
constructor() { constructor() {
@ -31,6 +32,7 @@ class ProjectPathClass {
this.ImageFolder = this.getAbsolutePath(Config.Server.Media.folder); this.ImageFolder = this.getAbsolutePath(Config.Server.Media.folder);
this.ThumbnailFolder = this.getAbsolutePath(Config.Server.Media.tempFolder); this.ThumbnailFolder = this.getAbsolutePath(Config.Server.Media.tempFolder);
this.TranscodedFolder = path.join(this.ThumbnailFolder, 'tc'); this.TranscodedFolder = path.join(this.ThumbnailFolder, 'tc');
this.FacesFolder = path.join(this.ThumbnailFolder, 'f');
// create thumbnail folder if not exist // create thumbnail folder if not exist
if (!fs.existsSync(this.ThumbnailFolder)) { if (!fs.existsSync(this.ThumbnailFolder)) {

View File

@ -15,7 +15,7 @@ export class PhotoConverterMWs {
} }
const fullMediaPath = req.resultPipe; const fullMediaPath = req.resultPipe;
const convertedVideo = PhotoProcessing.generateConvertedFileName(fullMediaPath); const convertedVideo = PhotoProcessing.generateConvertedFilePath(fullMediaPath);
// check if transcoded video exist // check if transcoded video exist
if (fs.existsSync(convertedVideo) === true) { if (fs.existsSync(convertedVideo) === true) {

View File

@ -6,7 +6,7 @@ import {ContentWrapper} from '../../../common/entities/ConentWrapper';
import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
import {ProjectPath} from '../../ProjectPath'; import {ProjectPath} from '../../ProjectPath';
import {Config} from '../../../common/config/private/Config'; 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 {MediaDTO} from '../../../common/entities/MediaDTO';
import {PersonWithPhoto} from '../PersonMWs'; import {PersonWithPhoto} from '../PersonMWs';
import {PhotoProcessing} from '../../model/fileprocessing/PhotoProcessing'; import {PhotoProcessing} from '../../model/fileprocessing/PhotoProcessing';
@ -56,8 +56,7 @@ export class ThumbnailGeneratorMWs {
persons[i].samplePhoto.directory.name, persons[i].samplePhoto.name); persons[i].samplePhoto.directory.name, persons[i].samplePhoto.name);
// generate thumbnail path // generate thumbnail path
const thPath = path.join(ProjectPath.ThumbnailFolder, const thPath = PhotoProcessing.generatePersonThumbnailPath(mediaPath, persons[i].samplePhoto.metadata.faces[0], size);
PhotoProcessing.generatePersonThumbnailName(mediaPath, persons[i].samplePhoto.metadata.faces[0], size));
persons[i].readyThumbnail = fs.existsSync(thPath); 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); 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++) { for (let j = 0; j < Config.Client.Media.Thumbnail.thumbnailSizes.length; j++) {
const size = Config.Client.Media.Thumbnail.thumbnailSizes[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 (fs.existsSync(thPath) === true) {
if (typeof photos[i].readyThumbnails === 'undefined') { if (typeof photos[i].readyThumbnails === 'undefined') {
photos[i].readyThumbnails = []; photos[i].readyThumbnails = [];
@ -159,8 +158,7 @@ export class ThumbnailGeneratorMWs {
photos[i].readyThumbnails.push(size); photos[i].readyThumbnails.push(size);
} }
} }
const iconPath = path.join(thumbnailFolder, const iconPath = PhotoProcessing.generateThumbnailPath(fullMediaPath, Config.Client.Media.Thumbnail.iconSize);
PhotoProcessing.generateThumbnailName(fullMediaPath, Config.Client.Media.Thumbnail.iconSize));
if (fs.existsSync(iconPath) === true) { if (fs.existsSync(iconPath) === true) {
photos[i].readyIcon = true; photos[i].readyIcon = true;
} }

View File

@ -5,7 +5,7 @@ import * as crypto from 'crypto';
import {ProjectPath} from '../../ProjectPath'; import {ProjectPath} from '../../ProjectPath';
import {Config} from '../../../common/config/private/Config'; import {Config} from '../../../common/config/private/Config';
import {ThumbnailTH} from '../threading/ThreadPool'; 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 {ITaskExecuter, TaskExecuter} from '../threading/TaskExecuter';
import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig';
import {FaceRegion, PhotoDTO} from '../../../common/entities/PhotoDTO'; import {FaceRegion, PhotoDTO} from '../../../common/entities/PhotoDTO';
@ -37,7 +37,7 @@ export class PhotoProcessing {
this.taskQue = new ThumbnailTH(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations); this.taskQue = new ThumbnailTH(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations);
} else { } else {
this.taskQue = new TaskExecuter(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations, 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; 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 mediaPath = path.join(ProjectPath.ImageFolder, photo.directory.path, photo.directory.name, photo.name);
const size: number = Config.Client.Media.Thumbnail.personThumbnailSize; const size: number = Config.Client.Media.Thumbnail.personThumbnailSize;
// generate thumbnail path // generate thumbnail path
const thPath = path.join(ProjectPath.ThumbnailFolder, const thPath = PhotoProcessing.generatePersonThumbnailPath(mediaPath, photo.metadata.faces[0], size);
PhotoProcessing.generatePersonThumbnailName(mediaPath, photo.metadata.faces[0], size));
// check if thumbnail already exist // check if thumbnail already exist
@ -95,17 +94,22 @@ export class PhotoProcessing {
} }
public static generateThumbnailName(mediaPath: string, size: number): string { public static generateThumbnailPath(mediaPath: string, size: number): string {
return crypto.createHash('md5').update(mediaPath).digest('hex') + '_' + size + '.jpg'; 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 { public static generatePersonThumbnailPath(mediaPath: string, faceRegion: FaceRegion, size: number): string {
return crypto.createHash('md5').update(mediaPath + '_' + faceRegion.name + '_' + faceRegion.box.left + '_' + faceRegion.box.top) return path.join(ProjectPath.FacesFolder,
.digest('hex') + '_' + size + '.jpg'; 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 extension = path.extname(photoPath);
const file = path.basename(photoPath, extension); const file = path.basename(photoPath, extension);
const postfix = Config.Server.Media.Photo.Converting.resolution; const postfix = Config.Server.Media.Photo.Converting.resolution;
@ -117,7 +121,7 @@ export class PhotoProcessing {
public static async convertPhoto(mediaPath: string, size: number) { public static async convertPhoto(mediaPath: string, size: number) {
// generate thumbnail path // generate thumbnail path
const outPath = PhotoProcessing.generateConvertedFileName(mediaPath); const outPath = PhotoProcessing.generateConvertedFilePath(mediaPath);
// check if file already exist // check if file already exist
@ -149,7 +153,7 @@ export class PhotoProcessing {
sourceType: ThumbnailSourceType, sourceType: ThumbnailSourceType,
makeSquare: boolean) { makeSquare: boolean) {
// generate thumbnail path // generate thumbnail path
const outPath = path.join(ProjectPath.ThumbnailFolder, PhotoProcessing.generateThumbnailName(mediaPath, size)); const outPath = PhotoProcessing.generateThumbnailPath(mediaPath, size);
// check if thumbnail already exist // check if thumbnail already exist

View File

@ -31,7 +31,7 @@ export class PhotoConvertingJob extends FileJob<string> {
directory.media[i].directory.name, directory.media[i].directory.name,
directory.media[i].name); directory.media[i].name);
if (await existsPr(PhotoProcessing.generateConvertedFileName(photoPath)) === false) { if (await existsPr(PhotoProcessing.generateConvertedFilePath(photoPath)) === false) {
ret.push(photoPath); ret.push(photoPath);
} }
} }

View File

@ -7,7 +7,7 @@ import * as util from 'util';
import {FileJob} from './FileJob'; import {FileJob} from './FileJob';
import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO'; import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO';
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing'; import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
import {ThumbnailSourceType} from '../../threading/ThumbnailWorker'; import {ThumbnailSourceType} from '../../threading/PhotoWorker';
import {MediaDTO} from '../../../../common/entities/MediaDTO'; import {MediaDTO} from '../../../../common/entities/MediaDTO';
const LOG_TAG = '[ThumbnailGenerationJob]'; const LOG_TAG = '[ThumbnailGenerationJob]';

View File

@ -5,7 +5,7 @@ import {FfmpegCommand, FfprobeData} from 'fluent-ffmpeg';
import {FFmpegFactory} from '../FFmpegFactory'; import {FFmpegFactory} from '../FFmpegFactory';
import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig';
export class ThumbnailWorker { export class PhotoWorker {
private static imageRenderer: (input: RendererInput) => Promise<void> = null; private static imageRenderer: (input: RendererInput) => Promise<void> = null;
private static videoRenderer: (input: RendererInput) => Promise<void> = null; private static videoRenderer: (input: RendererInput) => Promise<void> = null;
@ -19,19 +19,19 @@ export class ThumbnailWorker {
} }
public static renderFromImage(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise<void> { public static renderFromImage(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise<void> {
if (ThumbnailWorker.rendererType !== renderer) { if (PhotoWorker.rendererType !== renderer) {
ThumbnailWorker.imageRenderer = ImageRendererFactory.build(renderer); PhotoWorker.imageRenderer = ImageRendererFactory.build(renderer);
ThumbnailWorker.rendererType = renderer; PhotoWorker.rendererType = renderer;
} }
return ThumbnailWorker.imageRenderer(input); return PhotoWorker.imageRenderer(input);
} }
public static renderFromVideo(input: RendererInput): Promise<void> { public static renderFromVideo(input: RendererInput): Promise<void> {
if (ThumbnailWorker.videoRenderer === null) { if (PhotoWorker.videoRenderer === null) {
ThumbnailWorker.videoRenderer = VideoRendererFactory.build(); PhotoWorker.videoRenderer = VideoRendererFactory.build();
} }
return ThumbnailWorker.videoRenderer(input); return PhotoWorker.videoRenderer(input);
} }
} }

View File

@ -2,7 +2,7 @@ import * as cluster from 'cluster';
import {Logger} from '../../Logger'; import {Logger} from '../../Logger';
import {DiskManagerTask, ThumbnailTask, WorkerMessage, WorkerTask, WorkerTaskTypes} from './Worker'; import {DiskManagerTask, ThumbnailTask, WorkerMessage, WorkerTask, WorkerTaskTypes} from './Worker';
import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
import {RendererInput} from './ThumbnailWorker'; import {RendererInput} from './PhotoWorker';
import {Config} from '../../../common/config/private/Config'; import {Config} from '../../../common/config/private/Config';
import {TaskQue, TaskQueEntry} from './TaskQue'; import {TaskQue, TaskQueEntry} from './TaskQue';
import {ITaskExecuter} from './TaskExecuter'; import {ITaskExecuter} from './TaskExecuter';

View File

@ -1,6 +1,6 @@
import {DiskMangerWorker} from './DiskMangerWorker'; import {DiskMangerWorker} from './DiskMangerWorker';
import {Logger} from '../../Logger'; import {Logger} from '../../Logger';
import {RendererInput, ThumbnailWorker} from './ThumbnailWorker'; import {RendererInput, PhotoWorker} from './PhotoWorker';
import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
import {Utils} from '../../../common/Utils'; import {Utils} from '../../../common/Utils';
import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig';
@ -22,7 +22,7 @@ export class Worker {
} }
break; break;
case WorkerTaskTypes.thumbnail: case WorkerTaskTypes.thumbnail:
result = await ThumbnailWorker.render((<ThumbnailTask>task).input, (<ThumbnailTask>task).renderer); result = await PhotoWorker.render((<ThumbnailTask>task).input, (<ThumbnailTask>task).renderer);
break; break;
default: default:
throw new Error('Unknown worker task type'); throw new Error('Unknown worker task type');

View File

@ -4,7 +4,7 @@ import {GalleryMWs} from '../middlewares/GalleryMWs';
import {RenderingMWs} from '../middlewares/RenderingMWs'; import {RenderingMWs} from '../middlewares/RenderingMWs';
import {ThumbnailGeneratorMWs} from '../middlewares/thumbnail/ThumbnailGeneratorMWs'; import {ThumbnailGeneratorMWs} from '../middlewares/thumbnail/ThumbnailGeneratorMWs';
import {UserRoles} from '../../common/entities/UserDTO'; import {UserRoles} from '../../common/entities/UserDTO';
import {ThumbnailSourceType} from '../model/threading/ThumbnailWorker'; import {ThumbnailSourceType} from '../model/threading/PhotoWorker';
import {VersionMWs} from '../middlewares/VersionMWs'; import {VersionMWs} from '../middlewares/VersionMWs';
import {SupportedFormats} from '../../common/SupportedFormats'; import {SupportedFormats} from '../../common/SupportedFormats';
import {PhotoConverterMWs} from '../middlewares/thumbnail/PhotoConverterMWs'; import {PhotoConverterMWs} from '../middlewares/thumbnail/PhotoConverterMWs';