j3lte/node-motion

View on GitHub
cli.js

Summary

Maintainability
B
4 hrs
Test Coverage
'use strict';
/*
 * node-motion
 * https://github.com/j3lte/node-motion
 *
 * Copyright (c) 2015 Jelte Lagendijk
 * Licensed under the MIT license.
 */
var chalk = require('chalk');
var optimist = require('optimist');
var updateNotifier = require('update-notifier');
var shell = require('shelljs');
var path = require('path');

var pkg = require('./package.json');

var MotionConfig = require('./config');
var MotionHandler = require('./motion');
var ViewServer = require('./server');

var motion, config;

var banner = [
  '',
  '                                                                                 ',
  '                       _                            _   _                        ',
  '       _ __   ___   __| | ___       _ __ ___   ___ | |_(_) ___  _ __             ',
  '      | \'_ \\ / _ \\ / _\` |/ _ \\_____| \'_ ` _ \\ / _ \\| __| |/ _ \\| \'_ \\            ',
  '      | | | | (_) | (_| |  __/_____| | | | | | (_) | |_| | (_) | | | |           ',
  '      |_| |_|\\___/ \\__,_|\\___|     |_| |_| |_|\\___/ \\__|_|\\___/|_| |_|           ',
  '                                                                                 ',
  '                                                                Version : ' + chalk.cyan(pkg.version),
  '                                                                By      : ' + chalk.cyan('@j3lte'),
  ''
].join('\n');

var argv = optimist
  .usage([
    '',
    ' ' + chalk.green('Node motion : Control motion with NodeJS'),
    '',
    ' Usage : ' + chalk.bold.cyan('node-motion [OPTIONS] [CONFIG-FILE]'),
    '',
    ' Configuration-file can either be a JSON or a .conf file',
    '',
    ' If you experience issues, report them here: ' + chalk.green('https://github.com/j3lte/node-motion/issues')
  ].join('\n'))
  .alias('n', 'no_webserver')
    .describe('n', 'Do not start a preview server')
    .boolean('n')
  .alias('v', 'videodevice')
    .describe('v', 'Videodevice (e.g. /dev/video0) (overridden by config-file)')
  .alias('c', 'control_port')
    .describe('c', 'Controlport for motion (overridden by config-file)')
    .default('c', 9000)
  .alias('s', 'webcam_port')
    .describe('s', 'Port for motion stream (overridden by config-file)')
    .default('s', 9001)
  .alias('b', 'motion_bin')
    .describe('b', 'Path to motion binary, in case it is not available in $PATH')
  .alias('p', 'preview_port')
    .describe('p', 'Port for hosting the preview server (http://localhost:<port>/')
    .default('p', 3000)
  .alias('d', 'debug')
      .describe('d', 'Verbose debug output')
      .boolean('d')
  .alias('h', 'help')
      .describe('h', 'Shows this help screen')
  .alias('u', 'update')
      .describe('u', 'Checks if there is an update for node-motion')
  .argv;

console.log(banner);

function runMotion(motionConfFile) {

  var viewServer;
  var useJSON = true;

  if (argv.motion_bin) {
    motion = new MotionHandler(argv.motion_bin);
  } else {
    motion = new MotionHandler();
  }

  if (motionConfFile && motionConfFile.type === '.json') {
    console.log('[NODE-MOTION] Using json: ' + motionConfFile.file);
    config = new MotionConfig(motionConfFile.file);
  } else if (motionConfFile && motionConfFile.type === '.conf') {
    console.log('[NODE-MOTION] Using conf : ' + motionConfFile.file);
    useJSON = false;
  } else {
    console.log('[NODE-MOTION] Generating temporary config file');
    var motionParams = {
      'control_port': argv.control_port, // This is used for controlling Motion
      'webcontrol_port': argv.control_port, // version 3_2_12_git20140228
      'webcam_port': argv.webcam_port, // This is used for the stream
      'stream_port': argv.webcam_port // version 3_2_12_git20140228
    };
    if (argv.videodevice) {
      motionParams.videodevice = argv.videodevice;
    }
    config = new MotionConfig({
      version: motion.version,
      params: motionParams
    });
  }

  if (!argv.no_webserver) {
    viewServer = new ViewServer(argv.preview_port);
  }

  if (useJSON) {
    config.on('info:configWritten', function (filename) {
      motion.setConfig(filename);
      motion.start();
      viewServer && viewServer.start();
    });
  } else {
    motion.setConfig(config.file);
    motion.start();
    viewServer && viewServer.start();
  }

  motion
    .on('info', function(msg) {
      argv.debug && console.log('[MOTION INFO]', msg);
    })
    .on('debug', function(msg) {
      argv.debug && console.log('[MOTION DEBUG]', msg);
    })
    .on('msg', function(msg) {
      //argv.debug && console.log('[MOTION MSG]', msg);
      if (msg.action === 'stream' && msg.value !== null && !argv.no_webserver) {
        viewServer.streamPort = msg.value;
        console.log('[NODE-MOTION] Preview started on http://localhost:' + argv.preview_port);
      }
    })
    .on('exit', function(msg) {
      console.log('[MOTION EXIT]', msg);
      config && config.deleteConfig();
    });
}

var platform = process.platform;

if (platform === 'linux') {
  if (process.arch === 'x64') {
    platform += '64';
  } else {
    platform += '32';
  }
} else {
  console.log(chalk.bold.red('Unexpected platform or architecture, node-motion only runs on Linux:'), process.platform, process.arch);
  process.exit(1);
}

if (argv.update) {
  console.log(chalk.cyan('\n Checking for an update'));
  updateNotifier({
    pkg: pkg,
    callback: function(err, update) {
      if (err) {
        console.log(chalk.red('\n Error checking the update : %s\n'), err);
      } else {
        if (update.latest !== update.current) {
          console.log(chalk.green(' Update available! Run ') + chalk.bold.cyan('npm update -g node-motion') + chalk.green(' to install version ') + chalk.bold.cyan(update.latest) + '\n');
        } else {
          console.log(chalk.green(' You are running the latest version :-)\n'));
        }
      }
      process.exit(0);
    }
  });
} else if (argv.help || argv._.length > 1) {
  console.log(optimist.help());
  process.exit(0);
} else if (argv._.length === 1) {
  var configFileName = argv._[0];
  if (!shell.test('-e', configFileName)) {
    console.log(chalk.red('\n\n Error, cannot find ' + configFileName));
    process.exit(1);
  } else {
    var filePath = path.resolve(configFileName);
    var ext = path.extname(configFileName);
    if (ext === '.json' || ext === '.conf') {
      runMotion({
        type: ext,
        file: filePath
      });
    } else {
      console.log(chalk.red('\n\n The file ' + configFileName + ' should either be a .json or a .conf file\n'));
      process.exit(1);
    }
  }
} else {
  runMotion();
}

process.on('SIGINT', function() {
  config && config.tmpFileName && config.deleteConfig();
  motion.motion && motion.stop();
  console.log('\n[NODE-MOTION] CTRL+C. exited.');
  return process.exit();
});