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:
parent
5ec9171ddf
commit
c3c94c1709
@ -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)) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]';
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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';
|
||||||
|
@ -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');
|
||||||
|
@ -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';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user