@ -241,139 +241,110 @@ ${res.locals.numFiles > 0 ? req.files.file.map(f => f.name+'|'+(f.phash || '')).
} ;
} ;
//type and subtype
//type and subtype
const [ type , subtype ] = processedFile . mimetype . split ( '/' ) ;
let [ type , subtype ] = processedFile . mimetype . split ( '/' ) ;
let imageData ;
let firstFrameOnly = true ;
if ( type === 'image' ) {
processedFile . thumbextension = thumbExtension ;
///detect images with opacity for PNG thumbnails, set thumbextension before increment
try {
imageData = await imageIdentify ( req . files . file [ i ] . tempFilePath , null , true ) ;
} catch ( e ) {
await deleteTempFiles ( req ) . catch ( e => console . error ) ;
return dynamicResponse ( req , res , 400 , 'message' , {
'title' : 'Bad request' ,
'message' : ` The server failed to process " ${ req . files . file [ i ] . name } ". Possible unsupported or corrupt file. ` ,
'redirect' : redirect
} ) ;
}
if ( imageData [ 'Channel Statistics' ] && imageData [ 'Channel Statistics' ] [ 'Opacity' ] ) { //does this depend on GM version or anything?
const opacityMaximum = imageData [ 'Channel Statistics' ] [ 'Opacity' ] [ 'Maximum' ] ;
if ( opacityMaximum !== '0.00 (0.0000)' ) {
processedFile . thumbextension = '.png' ;
}
}
processedFile . geometry = imageData . size ;
processedFile . geometryString = imageData . Geometry ;
const lteThumbSize = ( processedFile . geometry . height <= thumbSize
&& processedFile . geometry . width <= thumbSize ) ;
processedFile . hasThumb = ! ( mimeTypes . allowed ( file . mimetype , { image : true } )
&& subtype !== 'png'
&& lteThumbSize ) ;
if ( processedFile . hasThumb //if it needs thumbnailing
&& ( ! lteThumbSize //and its big enough
&& file . mimetype === 'image/gif' //and its a gif
&& ( imageData [ 'Delay' ] != null || imageData [ 'Iterations' ] != null ) //and its not a static gif (naive check)
&& animatedGifThumbnails === true ) ) { //and animated thumbnails for gifs are enabled
firstFrameOnly = false ;
processedFile . thumbextension = '.gif' ;
}
} else if ( type === 'audio' ) {
if ( audioThumbnails ) {
// waveform has a transparent background, so force png
processedFile . thumbextension = '.png' ;
}
} else {
processedFile . thumbextension = thumbExtension ;
}
//increment file count
await Files . increment ( processedFile ) ;
req . files . file [ i ] . inced = true ;
//check if already exists
//check if already exists
const existsFull = await pathExists ( ` ${ uploadDirectory } /file/ ${ processedFile . filename } ` ) ;
const existsFull = await pathExists ( ` ${ uploadDirectory } /file/ ${ processedFile . filename } ` ) ;
processedFile . sizeString = formatSize ( processedFile . size )
processedFile . sizeString = formatSize ( processedFile . size )
const saveFull = async ( ) => {
if ( ! existsFull ) {
await Files . increment ( processedFile ) ;
req . files . file [ i ] . inced = true ;
await moveUpload ( file , processedFile . filename , 'file' ) ;
}
}
if ( mimeTypes . other . has ( processedFile . mimetype ) ) {
if ( mimeTypes . other . has ( processedFile . mimetype ) ) {
//"other" mimes from config, overrides main type to avoid codec issues in browser or ffmpeg for unsupported filetypes
//"other" mimes from config, overrides main type to avoid codec issues in browser or ffmpeg for unsupported filetypes
processedFile . hasThumb = false ;
processedFile . hasThumb = false ;
processedFile . attachment = true ;
processedFile . attachment = true ;
if ( ! existsFull ) {
await saveFull ( ) ;
await moveUpload ( file , processedFile . filename , 'file' ) ;
}
} else {
} else {
const existsThumb = await pathExists ( ` ${ uploadDirectory } /file/thumb- ${ processedFile . hash } ${ processedFile . thumbextension } ` ) ;
const existsThumb = await pathExists ( ` ${ uploadDirectory } /file/thumb- ${ processedFile . hash } ${ processedFile . thumbextension } ` ) ;
switch ( type ) {
switch ( type ) {
case 'image' : {
case 'image' : {
if ( ! existsFull ) {
processedFile . thumbextension = thumbExtension ;
await moveUpload ( file , processedFile . filename , 'file' ) ;
///detect images with opacity for PNG thumbnails, set thumbextension before increment
}
let imageData ;
if ( ! existsThumb ) {
try {
await imageThumbnail ( processedFile , firstFrameOnly ) ;
imageData = await imageIdentify ( req . files . file [ i ] . tempFilePath , null , true ) ;
}
} catch ( e ) {
processedFile = fixGifs ( processedFile ) ;
break ;
}
case 'video' : {
//video metadata
const videoData = await ffprobe ( req . files . file [ i ] . tempFilePath , null , true ) ;
videoData . streams = videoData . streams . filter ( stream => stream . width != null ) ; //filter to only video streams or something with a resolution
if ( videoData . streams . length <= 0 ) {
//corrupt, or audio only?
await deleteTempFiles ( req ) . catch ( e => console . error ) ;
await deleteTempFiles ( req ) . catch ( e => console . error ) ;
return dynamicResponse ( req , res , 400 , 'message' , {
return dynamicResponse ( req , res , 400 , 'message' , {
'title' : 'Bad request' ,
'title' : 'Bad request' ,
'message' : 'Audio only video file not supported' ,
'message' : ` The server failed to process " ${ req . files . file [ i ] . name } ". Possible unsupported or corrupt file. ` ,
'redirect' : redirect
'redirect' : redirect
} ) ;
} ) ;
}
}
processedFile . duration = videoData . format . duration ;
if ( imageData [ 'Channel Statistics' ] && imageData [ 'Channel Statistics' ] [ 'Opacity' ] ) {
processedFile . durationString = timeUtils . durationString ( videoData . format . duration * 1000 ) ;
//does this depend on GM version or anything?
processedFile . geometry = { width : videoData . streams [ 0 ] . coded _width , height : videoData . streams [ 0 ] . coded _height } ;
const opacityMaximum = imageData [ 'Channel Statistics' ] [ 'Opacity' ] [ 'Maximum' ] ;
processedFile . geometryString = ` ${ processedFile . geometry . width } x ${ processedFile . geometry . height } `
if ( opacityMaximum !== '0.00 (0.0000)' ) {
processedFile . hasThumb = true ;
processedFile . thumbextension = '.png' ;
if ( ! existsFull ) {
}
await moveUpload ( file , processedFile . filename , 'file' ) ;
}
processedFile . geometry = imageData . size ;
processedFile . geometryString = imageData . Geometry ;
const lteThumbSize = ( processedFile . geometry . height <= thumbSize
&& processedFile . geometry . width <= thumbSize ) ;
processedFile . hasThumb = ! ( mimeTypes . allowed ( file . mimetype , { image : true } )
&& subtype !== 'png'
&& lteThumbSize ) ;
let firstFrameOnly = true ;
if ( processedFile . hasThumb //if it needs thumbnailing
&& ( ! lteThumbSize //and its big enough
&& file . mimetype === 'image/gif' //and its a gif
&& ( imageData [ 'Delay' ] != null || imageData [ 'Iterations' ] != null ) //and its not a static gif (naive check)
&& animatedGifThumbnails === true ) ) { //and animated thumbnails for gifs are enabled
firstFrameOnly = false ;
processedFile . thumbextension = '.gif' ;
}
}
await saveFull ( ) ;
if ( ! existsThumb ) {
if ( ! existsThumb ) {
const numFrames = videoData . streams [ 0 ] . nb _frames ;
await imageThumbnail ( processedFile , firstFrameOnly ) ;
if ( numFrames === 'N/A' && subtype === 'webm' ) {
await videoThumbnail ( processedFile , processedFile . geometry , videoThumbPercentage + '%' ) ;
let videoThumbStat = null ;
try {
videoThumbStat = await fsStat ( ` ${ uploadDirectory } /file/thumb- ${ processedFile . hash } ${ processedFile . thumbextension } ` ) ;
} catch ( err ) { /*ENOENT, the thumb failed to create. No need to handle this.*/ }
if ( ! videoThumbStat || videoThumbStat . size === 0 ) {
await videoThumbnail ( processedFile , processedFile . geometry , 0 ) ;
}
} else {
await videoThumbnail ( processedFile , processedFile . geometry , ( ( numFrames === 'N/A' || numFrames <= 1 ) ? 0 : videoThumbPercentage + '%' ) ) ;
}
}
}
processedFile = fixGifs ( processedFile ) ;
break ;
break ;
}
}
case 'audio' : {
case 'audio' :
//audio metadata
case 'video' :
const audioData = await ffprobe ( req . files . file [ i ] . tempFilePath , null , true ) ;
//video metadata
processedFile . duration = audioData . format . duration ;
const audioVideoData = await ffprobe ( req . files . file [ i ] . tempFilePath , null , true ) ;
processedFile . durationString = timeUtils . durationString ( audioData . format . duration * 1000 ) ;
processedFile . duration = audioVideoData . format . duration ;
processedFile . hasThumb = audioThumbnails ;
processedFile . durationString = timeUtils . durationString ( audioVideoData . format . duration * 1000 ) ;
if ( ! existsFull ) {
const videoStreams = audioVideoData . streams . filter ( stream => stream . width != null ) ; //filter to only video streams or something with a resolution
await moveUpload ( file , processedFile . filename , 'file' ) ;
if ( videoStreams . length > 0 ) {
}
processedFile . thumbextension = thumbExtension ;
if ( audioThumbnails ) {
processedFile . geometry = { width : videoStreams [ 0 ] . coded _width , height : videoStreams [ 0 ] . coded _height } ;
// audio thumbnail is always thumbSize x thumbSize
processedFile . geometryString = ` ${ processedFile . geometry . width } x ${ processedFile . geometry . height } `
processedFile . geometry = {
processedFile . hasThumb = true ;
thumbwidth : thumbSize , thumbheight : thumbSize ,
await saveFull ( ) ;
} ;
if ( ! existsThumb ) {
const numFrames = videoStreams [ 0 ] . nb _frames ;
if ( numFrames === 'N/A' && subtype === 'webm' ) {
await videoThumbnail ( processedFile , processedFile . geometry , videoThumbPercentage + '%' ) ;
let videoThumbStat = null ;
try {
videoThumbStat = await fsStat ( ` ${ uploadDirectory } /file/thumb- ${ processedFile . hash } ${ processedFile . thumbextension } ` ) ;
} catch ( err ) { /*ENOENT, the thumb failed to create. No need to handle this.*/ }
if ( ! videoThumbStat || videoThumbStat . size === 0 ) {
await videoThumbnail ( processedFile , processedFile . geometry , 0 ) ;
}
} else {
await videoThumbnail ( processedFile , processedFile . geometry , ( ( numFrames === 'N/A' || numFrames <= 1 ) ? 0 : videoThumbPercentage + '%' ) ) ;
}
}
} else {
//audio file, or video with only audio streams
type = 'audio' ;
processedFile . mimetype = ` audio/ ${ subtype } ` ;
processedFile . thumbextension = '.png' ;
processedFile . hasThumb = audioThumbnails ;
processedFile . geometry = { thumbwidth : thumbSize , thumbheight : thumbSize } ;
await saveFull ( ) ;
if ( ! existsThumb ) {
if ( ! existsThumb ) {
await audioThumbnail ( processedFile ) ;
await audioThumbnail ( processedFile ) ;
}
}
}
}
break ;
break ;
}
default :
default :
throw new Error ( ` invalid file mime type: ${ processedFile } ` ) ;
throw new Error ( ` invalid file mime type: ${ processedFile } ` ) ;
}
}