hlsrecord 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/env node
  2. /* eslint-disable no-process-exit */
  3. "use strict";
  4. // record a live hls-stream storing an on-demand ready version
  5. var fs = require('fs'),
  6. path = require('path');
  7. var nopt;
  8. try {
  9. nopt = require('noptify/node_modules/nopt');
  10. } catch (e) {
  11. nopt = require('nopt');
  12. }
  13. var HlsSegmentReader = require('hls-segment-reader');
  14. var recorder = require('../lib/recorder');
  15. function DateValue(){}
  16. nopt.typeDefs[DateValue] = { type: DateValue, validate: function (data, key, val) {
  17. var date;
  18. if (val === 'now') val = '+0';
  19. if (val.length && (val[0] === '+' || val[0] === '-')) {
  20. date = new Date(Math.round(new Date().getTime() / 1000 + parseInt(val, 10)) * 1000);
  21. } else if (parseInt(val, 10) == val) {
  22. date = new Date(parseInt(val, 10) * 1000);
  23. } else {
  24. date = new Date(val);
  25. }
  26. if (!date) return false;
  27. data[key] = date;
  28. }};
  29. function HexValue(){}
  30. nopt.typeDefs[HexValue] = { type: HexValue, validate: function (data, key, val) {
  31. data[key] = new Buffer(val, 'hex');
  32. }};
  33. var hlsrecord = require('noptify')(process.argv, { program: 'hlsrecord <url>' });
  34. hlsrecord.version(require('../package').version)
  35. .option('collect', '-C', 'Collect output segments to a single file', Boolean)
  36. .option('output', '-o', 'Output directory', path)
  37. .option('create-dir', '-c', 'Explicitly create output dir', Boolean)
  38. .option('begin-date', '-b', 'Start recording at', DateValue)
  39. .option('end-date', '-e', 'Stop recording at', DateValue)
  40. .option('start-offset', '-s', 'Playback start time offset in seconds', Number)
  41. .option('create-dir', '-c', 'Explicitly create output dir', Boolean)
  42. .option('extension', 'Preserve specified vendor extension', Array)
  43. .option('segment-extension', 'Preserve specified vendor segment extension', Array)
  44. .option('user-agent', '-a', 'HTTP User-Agent', String)
  45. .option('decrypt', 'Attempt to decrypt segments', Boolean)
  46. .option('cookie', 'Add cookie header to key requests', String)
  47. .option('key', 'Use oob hex encoded key to decrypt segments', HexValue)
  48. // .option('-f, --full', 'record all variants')
  49. .parse(process.argv);
  50. var options = hlsrecord.nopt;
  51. var src = options.argv.remain[0];
  52. if (!src) {
  53. hlsrecord.help();
  54. process.exit(-1);
  55. }
  56. var outDir = options.output || 'stream';
  57. if (options['create-dir'])
  58. fs.mkdirSync(outDir);
  59. if (options['begin-date'])
  60. console.log('fetching from:', options['begin-date']);
  61. if (options['end-date'])
  62. console.log('fetching until:', options['end-date']);
  63. var extensions = {};
  64. (options.extension || []).forEach(function(ext) {
  65. extensions[ext] = false;
  66. });
  67. (options['segment-extension'] || []).forEach(function(ext) {
  68. extensions[ext] = true;
  69. });
  70. var readerOptions = {
  71. withData: true,
  72. fullStream: !options['begin-date'],
  73. startDate: options['begin-date'],
  74. stopDate: options['end-date'],
  75. maxStallTime: 5 * 60 * 1000,
  76. extensions: extensions,
  77. highWaterMark: 0,
  78. };
  79. function createReader(src) {
  80. var r = new HlsSegmentReader(src, readerOptions);
  81. r.on('error', function(err) {
  82. console.error('reader error', err);
  83. });
  84. return r;
  85. }
  86. var decrypt = null;
  87. if (options.decrypt) {
  88. decrypt = {
  89. cookie: options.cookie,
  90. key: options.key
  91. };
  92. }
  93. var rdr = createReader(src);
  94. recorder(rdr, outDir, { subreader:createReader, startOffset: options['start-offset'], collect: options.collect, decrypt: decrypt }).start();