const fs = require('fs');
const cp = require('child_process');
const im = require('imagemagick');
const readline = require('readline');
const commandLineArgs = require('command-line-args');
const speakIndexName = 'whospeak.csv';
const charIndexName = 'chars.txt';

const fullWidth = 1920;
const fullHeight = 1080;
const outDir = 'clips';

const optionDefinitions = [
  { name: 'background', alias: 'b', type: String },
  { name: 'color', alias: 'c', type: String },
  { name: 'font', alias: 'f', type: String },
  { name: 'image', alias: 'i', type: String },
  { name: 'line', alias: 'l', type: Number },
  { name: 'play', alias: 'p', type: String },
];
const options = commandLineArgs(optionDefinitions);

if (
      !options.hasOwnProperty('font')
   || !options.hasOwnProperty('image')
   || !options.hasOwnProperty('line')
   || !options.hasOwnProperty('play')
   ) {
  // Can't do anything useful without input
  return;
}

var background = options.hasOwnProperty('background') ? options.background : 'lightgray';
var foreground = options.hasOwnProperty('color') ? options.color : 'black';
var fontFile = options.font;
var imageFile = options.image;
var lineNumber = options.line;
var playFile = options.play;
var imageBaseName = imageFile.split('/').pop();
var screenplay = fs.readFileSync(playFile).toString().split('\n');
var lines = screenplay.length;
var digits = lines.toString().length;
screenplay.unshift('');

var lineRead = screenplay[lineNumber];
var audioName = 'output/speech' + lineNumber + '.wav';
var proc = cp.spawnSync('/usr/bin/soxi', [ '-D', audioName ]);
var time = parseFloat(proc.stdout.toString().trim(), 10);
var width = 0;
var height = 0;
var rSwitch = Math.round(Math.random());

var speakIndex = fs.readFileSync(speakIndexName).toString().replace('|', ',').split('\n');
var charIndex = fs.readFileSync(charIndexName).toString().split('\n');

im.identify(imageFile, function (err, features) {
  if (err) throw err;
  var linelen = 100;
  var dir = 'Center';
  var geo = '+100+100';
  width = features.width;
  height = features.height;
  if (width > height) {
    var xScale = fullWidth / width;
    linelen = Math.round((fullWidth - 200) / 24 - 1);
    if (rSwitch == 1) {
      dir = 'South';
      geo = '+100+100';
    } else {
      dir = 'North';
      geo = '+100+' + (height * xScale + 50);
    }
  } else {
    var yScale = fullHeight / height;
    linelen = Math.round((fullWidth - width * yScale - 200) / 24 - 1);
    if (rSwitch == 1) {
      dir = 'East';
      geo = '+100+100';
    } else {
      dir = 'West';
      geo = '+' + (100 + Math.round(width * yScale)) + '+100';
    }
  }
  var words = lineRead.replace(/_/g, '').split(' ');
  var chars = 0;
  lineRead = '';
  for (var i = 0; i < words.length; i++) {
    var wd = words[i];
    chars += wd.length + 1;
    if (chars > linelen) {
      chars = 0;
      lineRead += '\n';
    }
    lineRead += wd + ' ';
  }
  im.convert([
      imageFile,
      '-resize', fullWidth + 'x' + fullHeight,
      '-gravity', dir,
      '-background', background,
      '-opaque', foreground,
      '-extent', fullWidth + 'x' + fullHeight,
      'resized_' + imageBaseName
    ], function (err, output) {
    if (err) {
      console.log(err);
    }
    im.convert([
      'resized_' + imageBaseName,
      '-fill', foreground,
      '-font', fontFile,
      '-pointsize', 48,
      '-annotate', geo,
      lineRead,
      'text_' + imageBaseName
      ], function (err, output) {
      var videoName = outDir + '/video' + lineNumber + '.mp4';
      fs.unlink('resized_' + imageBaseName);
      cp.spawnSync('/usr/bin/ffmpeg', [
        '-framerate', '1/' + time,
        '-i', 'text_' + imageBaseName,
        '-c:v', 'libx264',
        '-r', '30',
        videoName
      ]);
      fs.unlink('text_' + imageBaseName);
      console.log(videoName);
      console.log(audioName);
      cp.spawnSync('/usr/bin/ffmpeg', [
        '-i', videoName,
        '-i', audioName,
        outDir + '/video' + ('00000' + lineNumber).slice(-digits) + '.mp4'
      ]);
      fs.unlink(videoName);
    });
  });
});

@@ -594,24 +594,74 @@
 : Number %7D,%0A
+  %7B name: 'novoice', alias: 'n', type: Boolean %7D,%0A
   %7B name: 'p
@@ -1258,16 +1258,91 @@
 s.play;%0A
+var novoice = options.hasOwnProperty('novoice') ? options.novoice : false;%0A
 var imag
@@ -3624,34 +3624,61 @@
  '/video' + 
-lineNumber
+('00000' + lineNumber).slice(-digits)
  + '.mp4';%0A 
@@ -3962,62 +3962,26 @@
     
-console.log(videoName);%0A      console.log(audioName);%0A
+if (!novoice) %7B%0A  
     
@@ -4020,24 +4020,26 @@
 , %5B%0A        
+ 
+ 
 '-i', videoN
@@ -4039,24 +4039,26 @@
  videoName,%0A
+  
         '-i'
@@ -4066,24 +4066,26 @@
  audioName,%0A
+  
         outD
@@ -4083,37 +4083,36 @@
      outDir + '/
-video
+clip
 ' + ('00000' + l
@@ -4148,28 +4148,32 @@
 .mp4'%0A      
+  
 %5D);%0A
+  
       fs.unl
@@ -4184,24 +4184,32 @@
 videoName);%0A
+      %7D%0A
     %7D);%0A  %7D)

Rename files for convenience and allow for visual-only collections