mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
adding indexedOnly option to fileJobs
This commit is contained in:
parent
b3024986e6
commit
08e3937292
@ -63,10 +63,8 @@ export class JobManager implements IJobManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async onJobFinished(job: IJob<any>): Promise<void> {
|
async onJobFinished(job: IJob<any>): Promise<void> {
|
||||||
console.log('onFinished' + job.Name);
|
|
||||||
const sch = Config.Server.Jobs.scheduled.find(s => s.jobName === job.Name);
|
const sch = Config.Server.Jobs.scheduled.find(s => s.jobName === job.Name);
|
||||||
if (sch) {
|
if (sch) {
|
||||||
console.log('parent found' + sch.jobName);
|
|
||||||
const children = Config.Server.Jobs.scheduled.filter(s => s.trigger.type === JobTriggerType.after &&
|
const children = Config.Server.Jobs.scheduled.filter(s => s.trigger.type === JobTriggerType.after &&
|
||||||
(<AfterJobTrigger>s.trigger).afterScheduleName === sch.name);
|
(<AfterJobTrigger>s.trigger).afterScheduleName === sch.name);
|
||||||
for (let i = 0; i < children.length; ++i) {
|
for (let i = 0; i < children.length; ++i) {
|
||||||
|
@ -4,8 +4,15 @@ import {Job} from './Job';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {DiskManager} from '../../DiskManger';
|
import {DiskManager} from '../../DiskManger';
|
||||||
import {DiskMangerWorker} from '../../threading/DiskMangerWorker';
|
import {DiskMangerWorker} from '../../threading/DiskMangerWorker';
|
||||||
import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO';
|
|
||||||
import {Logger} from '../../../Logger';
|
import {Logger} from '../../../Logger';
|
||||||
|
import {Config} from '../../../../common/config/private/Config';
|
||||||
|
import {ServerConfig} from '../../../../common/config/private/IPrivateConfig';
|
||||||
|
import {FileDTO} from '../../../../common/entities/FileDTO';
|
||||||
|
import {SQLConnection} from '../../database/sql/SQLConnection';
|
||||||
|
import {MediaEntity} from '../../database/sql/enitites/MediaEntity';
|
||||||
|
import {PhotoEntity} from '../../database/sql/enitites/PhotoEntity';
|
||||||
|
import {VideoEntity} from '../../database/sql/enitites/VideoEntity';
|
||||||
|
import DatabaseType = ServerConfig.DatabaseType;
|
||||||
|
|
||||||
declare var global: NodeJS.Global;
|
declare var global: NodeJS.Global;
|
||||||
|
|
||||||
@ -13,14 +20,22 @@ declare var global: NodeJS.Global;
|
|||||||
const LOG_TAG = '[FileJob]';
|
const LOG_TAG = '[FileJob]';
|
||||||
|
|
||||||
|
|
||||||
export abstract class FileJob<T, S = void> extends Job<S> {
|
export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly: boolean }> extends Job<S> {
|
||||||
public readonly ConfigTemplate: ConfigTemplateEntry[] = null;
|
public readonly ConfigTemplate: ConfigTemplateEntry[] = [];
|
||||||
directoryQueue: string[] = [];
|
directoryQueue: string[] = [];
|
||||||
fileQueue: T[] = [];
|
fileQueue: FileDTO[] = [];
|
||||||
|
|
||||||
|
|
||||||
protected constructor(private scanFilter: DiskMangerWorker.DirectoryScanSettings) {
|
protected constructor(private scanFilter: DiskMangerWorker.DirectoryScanSettings) {
|
||||||
super();
|
super();
|
||||||
|
if (Config.Server.Database.type !== DatabaseType.memory) {
|
||||||
|
this.ConfigTemplate.push({
|
||||||
|
id: 'indexedOnly',
|
||||||
|
type: 'boolean',
|
||||||
|
name: 'Only indexed files',
|
||||||
|
defaultValue: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async init() {
|
protected async init() {
|
||||||
@ -29,9 +44,16 @@ export abstract class FileJob<T, S = void> extends Job<S> {
|
|||||||
this.directoryQueue.push('/');
|
this.directoryQueue.push('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract async processDirectory(directory: DirectoryDTO): Promise<T[]>;
|
protected async filterMediaFiles(files: FileDTO[]): Promise<FileDTO[]> {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract async processFile(file: T): Promise<void>;
|
|
||||||
|
protected async filterMetaFiles(files: FileDTO[]): Promise<FileDTO[]> {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract async processFile(file: FileDTO): Promise<void>;
|
||||||
|
|
||||||
protected async step(): Promise<JobProgressDTO> {
|
protected async step(): Promise<JobProgressDTO> {
|
||||||
if (this.directoryQueue.length === 0 && this.fileQueue.length === 0) {
|
if (this.directoryQueue.length === 0 && this.fileQueue.length === 0) {
|
||||||
@ -40,18 +62,19 @@ export abstract class FileJob<T, S = void> extends Job<S> {
|
|||||||
|
|
||||||
this.progress.time.current = Date.now();
|
this.progress.time.current = Date.now();
|
||||||
if (this.directoryQueue.length > 0) {
|
if (this.directoryQueue.length > 0) {
|
||||||
const directory = this.directoryQueue.shift();
|
|
||||||
this.progress.comment = 'scanning directory: ' + directory;
|
if (this.config.indexedOnly === true &&
|
||||||
const scanned = await DiskManager.scanDirectory(directory, this.scanFilter);
|
Config.Server.Database.type !== DatabaseType.memory) {
|
||||||
for (let i = 0; i < scanned.directories.length; i++) {
|
await this.loadAllMediaFilesFromDB();
|
||||||
this.directoryQueue.push(path.join(scanned.directories[i].path, scanned.directories[i].name));
|
this.directoryQueue = [];
|
||||||
|
} else {
|
||||||
|
await this.loadADirectoryFromDisk();
|
||||||
}
|
}
|
||||||
this.fileQueue.push(...await this.processDirectory(scanned));
|
|
||||||
} else if (this.fileQueue.length > 0) {
|
} else if (this.fileQueue.length > 0) {
|
||||||
const file = this.fileQueue.shift();
|
const file = this.fileQueue.shift();
|
||||||
this.progress.left = this.fileQueue.length;
|
this.progress.left = this.fileQueue.length;
|
||||||
this.progress.progress++;
|
this.progress.progress++;
|
||||||
this.progress.comment = 'processing: ' + file;
|
this.progress.comment = 'processing: ' + path.join(file.directory.path, file.directory.name, file.name);
|
||||||
try {
|
try {
|
||||||
await this.processFile(file);
|
await this.processFile(file);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -62,4 +85,43 @@ export abstract class FileJob<T, S = void> extends Job<S> {
|
|||||||
return this.progress;
|
return this.progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async loadADirectoryFromDisk() {
|
||||||
|
const directory = this.directoryQueue.shift();
|
||||||
|
this.progress.comment = 'scanning directory: ' + directory;
|
||||||
|
const scanned = await DiskManager.scanDirectory(directory, this.scanFilter);
|
||||||
|
for (let i = 0; i < scanned.directories.length; i++) {
|
||||||
|
this.directoryQueue.push(path.join(scanned.directories[i].path, scanned.directories[i].name));
|
||||||
|
}
|
||||||
|
if (this.scanFilter.noVideo !== true || this.scanFilter.noVideo !== true) {
|
||||||
|
this.fileQueue.push(...await this.filterMediaFiles(scanned.media));
|
||||||
|
}
|
||||||
|
if (this.scanFilter.noMetaFile !== true) {
|
||||||
|
this.fileQueue.push(...await this.filterMetaFiles(scanned.metaFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadAllMediaFilesFromDB() {
|
||||||
|
|
||||||
|
if (this.scanFilter.noVideo === true && this.scanFilter.noPhoto === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Logger.silly(LOG_TAG, 'Loading files from db');
|
||||||
|
|
||||||
|
const connection = await SQLConnection.getConnection();
|
||||||
|
|
||||||
|
let usedEntity = MediaEntity;
|
||||||
|
|
||||||
|
if (this.scanFilter.noVideo === true) {
|
||||||
|
usedEntity = PhotoEntity;
|
||||||
|
} else if (this.scanFilter.noPhoto === true) {
|
||||||
|
usedEntity = VideoEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await connection.getRepository(usedEntity).createQueryBuilder('media')
|
||||||
|
.select(['media.name', 'media.id'])
|
||||||
|
.leftJoinAndSelect('media.directory', 'directory')
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
this.fileQueue.push(...await this.filterMediaFiles(result));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,14 @@ import {Config} from '../../../../common/config/private/Config';
|
|||||||
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
||||||
import {ProjectPath} from '../../../ProjectPath';
|
import {ProjectPath} from '../../../ProjectPath';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as util from 'util';
|
|
||||||
import {FileJob} from './FileJob';
|
import {FileJob} from './FileJob';
|
||||||
import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO';
|
|
||||||
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
||||||
|
import {FileDTO} from '../../../../common/entities/FileDTO';
|
||||||
|
|
||||||
const LOG_TAG = '[PhotoConvertingJob]';
|
const LOG_TAG = '[PhotoConvertingJob]';
|
||||||
const existsPr = util.promisify(fs.exists);
|
|
||||||
|
|
||||||
|
|
||||||
export class PhotoConvertingJob extends FileJob<string> {
|
export class PhotoConvertingJob extends FileJob {
|
||||||
public readonly Name = DefaultsJobs[DefaultsJobs['Photo Converting']];
|
public readonly Name = DefaultsJobs[DefaultsJobs['Photo Converting']];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -23,23 +20,12 @@ export class PhotoConvertingJob extends FileJob<string> {
|
|||||||
return Config.Client.Media.Photo.Converting.enabled === true;
|
return Config.Client.Media.Photo.Converting.enabled === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async processDirectory(directory: DirectoryDTO): Promise<string[]> {
|
|
||||||
const ret = [];
|
|
||||||
for (let i = 0; i < directory.media.length; ++i) {
|
|
||||||
const photoPath = path.join(ProjectPath.ImageFolder,
|
|
||||||
directory.media[i].directory.path,
|
|
||||||
directory.media[i].directory.name,
|
|
||||||
directory.media[i].name);
|
|
||||||
|
|
||||||
if (await existsPr(PhotoProcessing.generateConvertedFilePath(photoPath)) === false) {
|
protected async processFile(file: FileDTO): Promise<void> {
|
||||||
ret.push(photoPath);
|
await PhotoProcessing.convertPhoto(path.join(ProjectPath.ImageFolder,
|
||||||
}
|
file.directory.path,
|
||||||
}
|
file.directory.name,
|
||||||
return ret;
|
file.name), Config.Server.Media.Photo.Converting.resolution);
|
||||||
}
|
|
||||||
|
|
||||||
protected async processFile(file: string): Promise<void> {
|
|
||||||
await PhotoProcessing.convertPhoto(file, Config.Server.Media.Photo.Converting.resolution);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
import {Config} from '../../../../common/config/private/Config';
|
import {Config} from '../../../../common/config/private/Config';
|
||||||
import {ConfigTemplateEntry, DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
||||||
import {ProjectPath} from '../../../ProjectPath';
|
import {ProjectPath} from '../../../ProjectPath';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {FileJob} from './FileJob';
|
import {FileJob} from './FileJob';
|
||||||
import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO';
|
|
||||||
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
||||||
import {ThumbnailSourceType} from '../../threading/PhotoWorker';
|
import {ThumbnailSourceType} from '../../threading/PhotoWorker';
|
||||||
import {MediaDTO} from '../../../../common/entities/MediaDTO';
|
import {MediaDTO} from '../../../../common/entities/MediaDTO';
|
||||||
|
import {FileDTO} from '../../../../common/entities/FileDTO';
|
||||||
|
|
||||||
const LOG_TAG = '[ThumbnailGenerationJob]';
|
const LOG_TAG = '[ThumbnailGenerationJob]';
|
||||||
|
|
||||||
|
|
||||||
export class ThumbnailGenerationJob extends FileJob<MediaDTO, { sizes: number[] }> {
|
export class ThumbnailGenerationJob extends FileJob<{ sizes: number[], indexedOnly: boolean }> {
|
||||||
public readonly Name = DefaultsJobs[DefaultsJobs['Thumbnail Generation']];
|
public readonly Name = DefaultsJobs[DefaultsJobs['Thumbnail Generation']];
|
||||||
public readonly ConfigTemplate: ConfigTemplateEntry[] = [{
|
|
||||||
id: 'sizes',
|
|
||||||
type: 'number-array',
|
|
||||||
name: 'Sizes to generate',
|
|
||||||
defaultValue: [Config.Client.Media.Thumbnail.thumbnailSizes[0]]
|
|
||||||
}];
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({noMetaFile: true});
|
super({noMetaFile: true});
|
||||||
|
this.ConfigTemplate.push({
|
||||||
|
id: 'sizes',
|
||||||
|
type: 'number-array',
|
||||||
|
name: 'Sizes to generate',
|
||||||
|
defaultValue: [Config.Client.Media.Thumbnail.thumbnailSizes[0]]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Supported(): boolean {
|
public get Supported(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
start(config: { sizes: number[] }, OnFinishCB: () => void): Promise<void> {
|
start(config: { sizes: number[], indexedOnly: boolean }, OnFinishCB: () => void): Promise<void> {
|
||||||
for (let i = 0; i < config.sizes.length; ++i) {
|
for (let i = 0; i < config.sizes.length; ++i) {
|
||||||
if (Config.Client.Media.Thumbnail.thumbnailSizes.indexOf(config.sizes[i]) === -1) {
|
if (Config.Client.Media.Thumbnail.thumbnailSizes.indexOf(config.sizes[i]) === -1) {
|
||||||
throw new Error('unknown thumbnails size: ' + config.sizes[i] + '. Add it to the possible thumbnail sizes.');
|
throw new Error('unknown thumbnails size: ' + config.sizes[i] + '. Add it to the possible thumbnail sizes.');
|
||||||
@ -38,11 +38,15 @@ export class ThumbnailGenerationJob extends FileJob<MediaDTO, { sizes: number[]
|
|||||||
return super.start(config, OnFinishCB);
|
return super.start(config, OnFinishCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async processDirectory(directory: DirectoryDTO): Promise<MediaDTO[]> {
|
protected async filterMediaFiles(files: FileDTO[]): Promise<FileDTO[]> {
|
||||||
return directory.media;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async processFile(media: MediaDTO): Promise<void> {
|
protected async filterMetaFiles(files: FileDTO[]): Promise<FileDTO[]> {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async processFile(media: FileDTO): Promise<void> {
|
||||||
|
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, media.directory.path, media.directory.name, media.name);
|
const mPath = path.join(ProjectPath.ImageFolder, media.directory.path, media.directory.name, media.name);
|
||||||
for (let i = 0; i < this.config.sizes.length; ++i) {
|
for (let i = 0; i < this.config.sizes.length; ++i) {
|
||||||
|
@ -2,17 +2,14 @@ import {Config} from '../../../../common/config/private/Config';
|
|||||||
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
||||||
import {ProjectPath} from '../../../ProjectPath';
|
import {ProjectPath} from '../../../ProjectPath';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as util from 'util';
|
|
||||||
import {FileJob} from './FileJob';
|
import {FileJob} from './FileJob';
|
||||||
import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO';
|
|
||||||
import {VideoProcessing} from '../../fileprocessing/VideoProcessing';
|
import {VideoProcessing} from '../../fileprocessing/VideoProcessing';
|
||||||
|
import {FileDTO} from '../../../../common/entities/FileDTO';
|
||||||
|
|
||||||
const LOG_TAG = '[VideoConvertingJob]';
|
const LOG_TAG = '[VideoConvertingJob]';
|
||||||
const existsPr = util.promisify(fs.exists);
|
|
||||||
|
|
||||||
|
|
||||||
export class VideoConvertingJob extends FileJob<string> {
|
export class VideoConvertingJob extends FileJob {
|
||||||
public readonly Name = DefaultsJobs[DefaultsJobs['Video Converting']];
|
public readonly Name = DefaultsJobs[DefaultsJobs['Video Converting']];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -23,23 +20,12 @@ export class VideoConvertingJob extends FileJob<string> {
|
|||||||
return Config.Client.Media.Video.enabled === true;
|
return Config.Client.Media.Video.enabled === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async processDirectory(directory: DirectoryDTO): Promise<string[]> {
|
|
||||||
const ret = [];
|
|
||||||
for (let i = 0; i < directory.media.length; ++i) {
|
|
||||||
const videoPath = path.join(ProjectPath.ImageFolder,
|
|
||||||
directory.media[i].directory.path,
|
|
||||||
directory.media[i].directory.name,
|
|
||||||
directory.media[i].name);
|
|
||||||
|
|
||||||
if (await existsPr(VideoProcessing.generateConvertedFilePath(videoPath)) === false) {
|
protected async processFile(file: FileDTO): Promise<void> {
|
||||||
ret.push(videoPath);
|
await VideoProcessing.convertVideo(path.join(ProjectPath.ImageFolder,
|
||||||
}
|
file.directory.path,
|
||||||
}
|
file.directory.name,
|
||||||
return ret;
|
file.name));
|
||||||
}
|
|
||||||
|
|
||||||
protected async processFile(file: string): Promise<void> {
|
|
||||||
await VideoProcessing.convertVideo(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ export class DiskMangerWorker {
|
|||||||
d.isPartial = true;
|
d.isPartial = true;
|
||||||
directory.directories.push(d);
|
directory.directories.push(d);
|
||||||
} else if (PhotoProcessing.isPhoto(fullFilePath)) {
|
} else if (PhotoProcessing.isPhoto(fullFilePath)) {
|
||||||
if (settings.noPhoto) {
|
if (settings.noPhoto === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
directory.media.push(<PhotoDTO>{
|
directory.media.push(<PhotoDTO>{
|
||||||
@ -139,7 +139,7 @@ export class DiskMangerWorker {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (VideoProcessing.isVideo(fullFilePath)) {
|
} else if (VideoProcessing.isVideo(fullFilePath)) {
|
||||||
if (Config.Client.Media.Video.enabled === false || settings.noVideo) {
|
if (Config.Client.Media.Video.enabled === false || settings.noVideo === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -153,7 +153,7 @@ export class DiskMangerWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (DiskMangerWorker.isMetaFile(fullFilePath)) {
|
} else if (DiskMangerWorker.isMetaFile(fullFilePath)) {
|
||||||
if (Config.Client.MetaFile.enabled === false || settings.noMetaFile) {
|
if (Config.Client.MetaFile.enabled === false || settings.noMetaFile === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,10 @@ export class PhotoWorker {
|
|||||||
if (input.type === ThumbnailSourceType.Photo) {
|
if (input.type === ThumbnailSourceType.Photo) {
|
||||||
return this.renderFromImage(input, renderer);
|
return this.renderFromImage(input, renderer);
|
||||||
}
|
}
|
||||||
return this.renderFromVideo(input);
|
if (input.type === ThumbnailSourceType.Video) {
|
||||||
|
return this.renderFromVideo(input);
|
||||||
|
}
|
||||||
|
throw new Error('Unsupported media type to render thumbnail:' + input.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static renderFromImage(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise<void> {
|
public static renderFromImage(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise<void> {
|
||||||
|
@ -51,11 +51,11 @@ export module MediaDTO {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isPhoto = (media: MediaDTO): boolean => {
|
export const isPhoto = (media: FileDTO): boolean => {
|
||||||
return !MediaDTO.isVideo(media);
|
return !MediaDTO.isVideo(media);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isVideo = (media: MediaDTO): boolean => {
|
export const isVideo = (media: FileDTO): boolean => {
|
||||||
const lower = media.name.toLowerCase();
|
const lower = media.name.toLowerCase();
|
||||||
for (const ext of SupportedFormats.WithDots.Videos) {
|
for (const ext of SupportedFormats.WithDots.Videos) {
|
||||||
if (lower.endsWith(ext)) {
|
if (lower.endsWith(ext)) {
|
||||||
@ -65,7 +65,7 @@ export module MediaDTO {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isVideoTranscodingNeeded = (media: MediaDTO): boolean => {
|
export const isVideoTranscodingNeeded = (media: FileDTO): boolean => {
|
||||||
const lower = media.name.toLowerCase();
|
const lower = media.name.toLowerCase();
|
||||||
for (const ext of SupportedFormats.WithDots.TranscodeNeed.Videos) {
|
for (const ext of SupportedFormats.WithDots.TranscodeNeed.Videos) {
|
||||||
if (lower.endsWith(ext)) {
|
if (lower.endsWith(ext)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user