hlsrecord 3.3 KB

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