@ -177,15 +177,18 @@ IU.process = function () {
if ( image . ext == '.mov' )
image . ext = '.mp4' ;
if ( IMAGE _EXTS . indexOf ( image . ext ) < 0
&& ( ! config . VIDEO || config . VIDEO _EXTS . indexOf ( image . ext ) < 0 ) )
&& ( ! config . VIDEO || config . VIDEO _EXTS . indexOf ( image . ext ) < 0 )
&& ( ! config . VIDEO || config . AUDIO _EXTS . indexOf ( image . ext ) < 0 ) )
return this . failure ( Muggle ( 'Invalid image format.' ) ) ;
image . imgnm = filename . substr ( 0 , 256 ) ;
this . status ( 'Verifying...' ) ;
if ( config . VIDEO _EXTS . indexOf ( image . ext ) >= 0 )
video _still ( image . path , image . ext , this . verify _video . bind ( this ) ) ;
video _still ( image . path , image . ext , this . verify _video . bind ( this ) ) ;
else if ( config . AUDIO _EXTS . indexOf ( image . ext ) >= 0 )
audio _still ( image . path , this . verify _audio . bind ( this ) ) ;
else if ( image . ext == '.jpg' && jpegtranBin && jheadBin )
jobs . schedule ( new AutoRotateJob ( image . path ) , this . verify _image . bind ( this ) ) ;
jobs . schedule ( new AutoRotateJob ( image . path ) , this . verify _image . bind ( this ) ) ;
else
this . verify _image ( ) ;
} ;
@ -210,6 +213,166 @@ AutoRotateJob.prototype.perform_job = function () {
} ) ;
} ;
function AudioStillJob ( src ) {
jobs . Job . call ( this ) ;
this . src = src ;
}
util . inherits ( AudioStillJob , jobs . Job ) ;
AudioStillJob . prototype . describe _job = function ( ) {
return "FFmpeg audio still of " + this . src ;
} ;
AudioStillJob . prototype . perform _job = function ( ) {
var self = this ;
self . get _info ( ) ;
}
AudioStillJob . prototype . get _info = function ( ) {
var self = this ;
var audioData = { } ;
child _process . execFile ( ffprobeBin , [ this . src ] ,
function ( err , stdout , stderr ) {
var type = stderr . match ( /Input #0, (.*),/ ) ;
if ( type )
audioData . type = type [ 1 ] ;
var title = stderr . match ( /title\s+: (.*)/i ) ;
if ( title )
audioData . title = title [ 1 ] ;
var artist = stderr . match ( /artist\s+: (.*)/i ) ;
if ( artist )
audioData . artist = artist [ 1 ] ;
var l = stderr . match ( /Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2})/ ) ;
if ( l ) {
var h = ( l [ 1 ] != '00' ? l [ 1 ] + 'h' : '' ) ;
var m = ( l [ 2 ] != '00' ? l [ 2 ] + 'm' : '' ) ;
var s = ( l [ 3 ] != '00' ? l [ 3 ] + 's' : '' ) ;
audioData . total = parseFloat ( parseFloat ( l [ 1 ] ) * 3600 +
parseFloat ( l [ 2 ] ) * 60 + parseFloat ( l [ 3 ] ) + '.' + parseFloat ( l [ 4 ] ) ) ;
audioData . length = h + m + s ;
}
self . short _test ( audioData ) ;
} ) ;
}
AudioStillJob . prototype . short _test = function ( audioData ) {
var self = this ;
var dest = index . media _path ( 'tmp' , 'still_' + etc . random _id ( ) ) ;
if ( audioData . total <= 10 ) {
if ( ! config . AUDIOFILE _IMAGE ) {
var msg = "Failure serverside." ;
var prob = "Missing AUDIOFILE_IMAGE." ;
winston . warn ( prob ) ;
fs . unlink ( dest , function ( err ) {
self . finish _job ( Muggle ( msg , prob ) ) ;
} ) ;
return ;
}
fs . readFile ( config . AUDIOFILE _IMAGE , function ( errRead , img ) {
if ( errRead ) {
var msg = "Failure serverside." ;
var prob = "Error reading AUDIOFILE_IMAGE" ;
winston . warn ( prob ) ;
fs . unlink ( dest , function ( err ) {
self . finish _job ( Muggle ( msg , prob ) ) ;
} ) ;
return ;
}
fs . writeFile ( dest , img , function ( errWrite ) {
if ( errWrite ) {
var msg = "Failure serverside." ;
var prob = "Error copying AUDIOFILE_IMAGE" ;
winston . warn ( prob ) ;
fs . unlink ( dest , function ( err ) {
self . finish _job ( Muggle ( msg , prob ) ) ;
} ) ;
return ;
}
self . finish _job ( null , {
still _path : dest ,
duration : audioData . length ,
audiotype : audioData . type ,
title : audioData . title ,
artist : audioData . artist ,
} ) ;
} ) ;
} ) ;
} else {
self . encode _thumb ( audioData , dest ) ;
}
}
AudioStillJob . prototype . encode _thumb = function ( audioData , dest ) {
var self = this ;
var args = [ '-hide_banner' , '-loglevel' , 'info' ,
'-f' , 'lavfi' , '-ss' , ( Math . floor ( audioData . total / 2 ) <= 10 ?
Math . floor ( audioData . total - audioData . total / 10 ) : Math . floor ( audioData . total / 2 ) ) ,
'-i' , 'amovie=' + this . src + ', asplit [a][out1];[a] showspectrum=mode=separate:color=intensity:slide=1:scale=cbrt [out0]' ,
'-f' , 'image2' , '-vframes' , '1' , '-vcodec' , 'png' ,
'-y' , dest ] ;
var opts = { env : { AV _LOG _FORCE _NOCOLOR : '1' } } ;
child _process . execFile ( ffmpegBin , args , opts ,
function ( err , stdout , stderr ) {
var lines = stderr ? stderr . split ( '\n' ) : [ ] ;
var first = lines [ 0 ] ;
if ( err ) {
var msg ;
if ( /no such file or directory/i . test ( first ) )
msg = "Audio went missing." ;
else if ( /invalid data found when/i . test ( first ) )
msg = "Invalid audio file." ;
else if ( /^ffmpeg version/i . test ( first ) )
msg = "Server's ffmpeg is too old." ;
else {
msg = "Unknown audio reading error." ;
winston . warn ( "Unknown ffmpeg output: " + first ) ;
}
fs . unlink ( dest , function ( err ) {
self . finish _job ( Muggle ( msg , stderr ) ) ;
} ) ;
return ;
}
self . finish _job ( null , {
still _path : dest ,
duration : audioData . length ,
audiotype : audioData . type ,
title : audioData . title ,
artist : audioData . artist ,
} ) ;
} ) ;
} ;
function audio _still ( src , cb ) {
jobs . schedule ( new AudioStillJob ( src ) , cb ) ;
}
IU . verify _audio = function ( err , info ) {
if ( err )
return this . failure ( err ) ;
var self = this ;
this . db . track _temporary ( info . still _path , function ( err ) {
if ( err )
winston . warn ( "Tracking error: " + err ) ;
// pretend it's a PNG for the next steps
var image = self . image ;
image . video _path = image . path ;
image . path = info . still _path ;
image . ext = '.png' ;
if ( info . duration )
image . duration = info . duration ;
if ( info . audiotype )
image . audiofile = info . audiotype ;
if ( info . title )
image . title = info . title ;
if ( info . artist )
image . artist = info . artist ;
self . verify _image ( ) ;
} ) ;
} ;
function StillJob ( src , ext ) {
jobs . Job . call ( this ) ;
this . src = src ;
@ -305,6 +468,10 @@ function video_still(src, ext, cb) {
jobs . schedule ( new StillJob ( src , ext ) , cb ) ;
}
function audio _thumb ( src , ext , cb ) {
jobs . schedule ( new AudioJob ( src , ext ) , cb ) ;
}
IU . verify _video = function ( err , info ) {
if ( err )
return this . failure ( err ) ;
@ -474,8 +641,8 @@ IU.got_nails = function () {
var image = this . image ;
if ( image . video _path ) {
// stop pretending this is just a still image
image . path = image . video _path ;
image . ext = '.' + image . video ;
image . path = image . video _path ;
image . ext = image . audiofile ? '.' + image . audiofile : '.' + image . video ;
delete image . video _path ;
}
@ -532,9 +699,10 @@ var identifyBin, convertBin;
which ( 'identify' , function ( err , bin ) { if ( err ) throw err ; identifyBin = bin ; } ) ;
which ( 'convert' , function ( err , bin ) { if ( err ) throw err ; convertBin = bin ; } ) ;
var ffmpegBin ;
var ffmpegBin , ffprobeBin ;
if ( config . VIDEO ) {
which ( 'ffmpeg' , function ( err , bin ) { if ( err ) throw err ; ffmpegBin = bin ; } ) ;
which ( 'ffprobe' , function ( err , bin ) { if ( err ) throw err ; ffprobeBin = bin ; } ) ;
}
/* optional JPEG auto-rotation */