merge.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. 'use strict';
  2. import childProcess = require('child_process');
  3. import fs = require('fs');
  4. import os = require('os');
  5. import path = require('path');
  6. import subtitle from '../subtitle/index';
  7. /**
  8. * Merges the subtitle and video files into a Matroska Multimedia Container.
  9. */
  10. export default function(config: IConfig, isSubtitled: boolean, rtmpInputPath: string, filePath: string,
  11. streamMode: string, verbose: boolean, done: (err: Error) => void)
  12. {
  13. const subtitlePath = filePath + '.' + (subtitle.formats[config.format] ? config.format : 'ass');
  14. let videoPath = filePath;
  15. let cp;
  16. if (streamMode === 'RTMP')
  17. {
  18. videoPath += path.extname(rtmpInputPath);
  19. }
  20. else
  21. {
  22. videoPath += '.mp4';
  23. }
  24. cp = childProcess.exec(command() + ' ' +
  25. '-o "' + filePath + '.mkv" ' +
  26. '"' + videoPath + '" ' +
  27. (isSubtitled ? '"' + subtitlePath + '"' : ''), {
  28. maxBuffer: Infinity,
  29. }, (err) =>
  30. {
  31. if (err)
  32. {
  33. return done(err);
  34. }
  35. unlink(videoPath, subtitlePath, (errin) =>
  36. {
  37. if (errin)
  38. {
  39. unlinkTimeout(videoPath, subtitlePath, 5000);
  40. }
  41. done(null);
  42. });
  43. });
  44. if (verbose === true)
  45. {
  46. cp.stdin.pipe(process.stdin);
  47. cp.stdout.pipe(process.stdout);
  48. cp.stderr.pipe(process.stderr);
  49. }
  50. }
  51. /**
  52. * Determines the command for the operating system.
  53. */
  54. function command(): string
  55. {
  56. if (os.platform() !== 'win32')
  57. {
  58. return 'mkvmerge';
  59. }
  60. return '"' + path.join(__dirname, '../../bin/mkvmerge.exe') + '"';
  61. }
  62. /**
  63. * Unlinks the video and subtitle.
  64. * @private
  65. */
  66. function unlink(videoPath: string, subtitlePath: string, done: (err: Error) => void)
  67. {
  68. fs.unlink(videoPath, (err) =>
  69. {
  70. if (err)
  71. {
  72. return done(err);
  73. }
  74. fs.unlink(subtitlePath, done);
  75. });
  76. }
  77. /**
  78. * Attempts to unlink the video and subtitle with a timeout between each try.
  79. */
  80. function unlinkTimeout(videoPath: string, subtitlePath: string, timeout: number)
  81. {
  82. setTimeout(() =>
  83. {
  84. unlink(videoPath, subtitlePath, (err) =>
  85. {
  86. if (err)
  87. {
  88. unlinkTimeout(videoPath, subtitlePath, timeout);
  89. }
  90. });
  91. }, timeout);
  92. }