|
|
@@ -1,17 +1,14 @@
|
|
|
'use strict';
|
|
|
|
|
|
-const Fs = require('fs');
|
|
|
const Path = require('path');
|
|
|
const Url = require('url');
|
|
|
|
|
|
const Mime = require('mime-types');
|
|
|
const StreamEach = require('stream-each');
|
|
|
-const Oncemore = require('oncemore');
|
|
|
const M3U8Parse = require('m3u8parse');
|
|
|
-const Mkdirp = require('mkdirp');
|
|
|
-const writeFileAtomic = require('write-file-atomic');
|
|
|
const debug = require('debug')('hls:recorder');
|
|
|
|
|
|
+const HlsUploader = require('./hls-uploader');
|
|
|
const SegmentDecrypt = require('./segment-decrypt');
|
|
|
|
|
|
|
|
|
@@ -41,15 +38,13 @@ function HlsStreamRecorder(reader, dst, options) {
|
|
|
this.mapSeq = 0;
|
|
|
this.nextMap = null;
|
|
|
|
|
|
- this.writing = null; // tracks writing state
|
|
|
+ this.uploader = null;
|
|
|
+ this.segmentHead = 0;
|
|
|
}
|
|
|
|
|
|
HlsStreamRecorder.prototype.start = function() {
|
|
|
|
|
|
- // TODO: make async?
|
|
|
- if (!Fs.existsSync(this.dst)) {
|
|
|
- Mkdirp.sync(this.dst);
|
|
|
- }
|
|
|
+ this.uploader = new HlsUploader(this.dst, { collect: this.collect });
|
|
|
|
|
|
StreamEach(this.reader, this.process.bind(this));
|
|
|
|
|
|
@@ -207,7 +202,7 @@ HlsStreamRecorder.prototype.processInfo = function (segmentInfo, callback) {
|
|
|
|
|
|
// handle byterange
|
|
|
if (this.collect) {
|
|
|
- map.quotedString('byterange', `${bytesWritten}@${this.writing.bytes - bytesWritten}`);
|
|
|
+ map.quotedString('byterange', `${bytesWritten}@${this.uploader.segmentBytes - bytesWritten}`);
|
|
|
}
|
|
|
|
|
|
this.nextMap = map;
|
|
|
@@ -258,13 +253,13 @@ HlsStreamRecorder.prototype.processSegment = function (segmentInfo, callback) {
|
|
|
|
|
|
// handle byterange
|
|
|
if (this.collect) {
|
|
|
- const isContigious = this.writing.segmentHead > 0 && ((this.writing.segmentHead + bytesWritten) === this.writing.bytes);
|
|
|
+ const isContigious = this.segmentHead > 0 && ((this.segmentHead + bytesWritten) === this.uploader.segmentBytes);
|
|
|
segment.byterange = {
|
|
|
length: bytesWritten,
|
|
|
- offset: isContigious ? null : this.writing.bytes - bytesWritten
|
|
|
+ offset: isContigious ? null : this.uploader.segmentBytes - bytesWritten
|
|
|
}
|
|
|
|
|
|
- this.writing.segmentHead = this.writing.bytes;
|
|
|
+ this.segmentHead = this.uploader.segmentBytes;
|
|
|
}
|
|
|
|
|
|
// update index
|
|
|
@@ -278,28 +273,7 @@ HlsStreamRecorder.prototype.processSegment = function (segmentInfo, callback) {
|
|
|
|
|
|
HlsStreamRecorder.prototype.writeStream = function (stream, name, callback) {
|
|
|
|
|
|
- if (!this.writing || !this.collect) {
|
|
|
- this.writing = {
|
|
|
- bytes: 0,
|
|
|
- segmentHead: 0
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- stream.pipe(Fs.createWriteStream(Path.join(this.dst, name), { flags: this.writing.bytes === 0 ? 'w' : 'a' }));
|
|
|
-
|
|
|
- let bytesWritten = 0;
|
|
|
- if (this.collect) {
|
|
|
- stream.on('data', (chunk) => {
|
|
|
-
|
|
|
- bytesWritten += +chunk.length;
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- Oncemore(stream).once('end', 'error', (err) => {
|
|
|
-
|
|
|
- this.writing.bytes += bytesWritten;
|
|
|
- return callback(err, bytesWritten);
|
|
|
- });
|
|
|
+ this.uploader.pushSegment(stream, name).then((written) => callback(null, written), callback);
|
|
|
};
|
|
|
|
|
|
HlsStreamRecorder.prototype.variantName = function(info, index) {
|
|
|
@@ -329,19 +303,7 @@ HlsStreamRecorder.prototype.segmentName = function(seqNo, isInit) {
|
|
|
|
|
|
HlsStreamRecorder.prototype.flushIndex = function(cb) {
|
|
|
|
|
|
- let appendString, indexString = this.index.toString().trim();
|
|
|
- if (this.lastIndexString && indexString.lastIndexOf(this.lastIndexString, 0) === 0) {
|
|
|
- let lastLength = this.lastIndexString.length;
|
|
|
- appendString = indexString.substr(lastLength);
|
|
|
- }
|
|
|
- this.lastIndexString = indexString;
|
|
|
-
|
|
|
- if (appendString) {
|
|
|
- Fs.appendFile(Path.join(this.dst, 'index.m3u8'), appendString, cb);
|
|
|
- }
|
|
|
- else {
|
|
|
- writeFileAtomic(Path.join(this.dst, 'index.m3u8'), indexString, cb);
|
|
|
- }
|
|
|
+ this.uploader.flushIndex(this.index).then(() => cb(), cb);
|
|
|
};
|
|
|
|
|
|
HlsStreamRecorder.prototype.recorderForUrl = function(remoteUrl) {
|