-
Notifications
You must be signed in to change notification settings - Fork 6
/
server-express.js
134 lines (105 loc) · 3.9 KB
/
server-express.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
var rangeParser = require('range-parser')
var fs = require('fs')
const express = require('express')
// Import transcoder from files package to transcode torrents on-the-fly
const Transcoder = require('./transcoder');
function Server (btClient) {
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.sendFile('client.html', {root: __dirname })
})
app.get('/:torrentHash/:fileIndex', async function (req, res) {
const torrentHash = req.params.torrentHash;
const fileIndex = req.params.fileIndex;
var torrent = btClient.get(torrentHash)
if (!torrent || Number.isNaN(fileIndex) || fileIndex >= torrent.files.length) {
return res.sendStatus(404);
}
var file = torrent.files[fileIndex];
if(req.query && 'metadata' in req.query) {
console.log('querying metadata');
Transcoder.getMetadata(file.createReadStream()).then((metadata) => {
console.log('metadata', metadata);
return res.json(metadata);
}).catch(reason => {
console.log(reason);
return res.end();
});
return;
}
res.setHeader('Content-Type', 'video/mp4'); //mime.getType(file.name))
const fileNeedsTranscoding = await Transcoder.needsTranscoding(file.createReadStream());
/*
File needs transcoding, so we will use time ranges instead of bytes ranges.
*/
if(fileNeedsTranscoding) {
// Disable range-requests in bytes
res.setHeader('Accept-Ranges', 'none')
/*
File does not needs transcoding, so we can use byte-ranges.
*/
} else {
// Disable range-requests
res.setHeader('Accept-Ranges', 'bytes')
// `rangeParser` returns an array of ranges, or an error code (number) if
// there was an error parsing the range.
var range = rangeParser(file.length, req.headers.range || '')
if (Array.isArray(range)) {
res.statusCode = 206 // indicates that range-request was understood
// no support for multi-range request, just use the first range
range = range[0]
res.setHeader(
'Content-Range',
'bytes ' + range.start + '-' + range.end + '/' + file.length
)
res.setHeader('Content-Length', range.end - range.start + 1)
} else {
range = null
res.setHeader('Content-Length', file.length)
}
}
if (req.method === 'HEAD') {
return res.end()
}
if(fileNeedsTranscoding) {
const transcoder = new Transcoder();
const seekTime = req.query && req.query.time ? parseInt(req.query.time) : 0;
transcoder.transcode(file.createReadStream(), res, {
seek: seekTime,
onStart: async () => {
//pump(fs.createReadStream(tmpFile), res)
// Wait for transcoding to start and file to be writen a bit before streaming it
//await sleep(5000);
//const readStream = GrowingFile.open(tmpFile);
//const readStream = fs.createReadStream(tmpFile);
//readStream.pipe(res);
//pump(readStream, res)
/*readStream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
//readStream.pipe(res);
pump(readStream, res)
});
// This catches any errors that happen while creating the readable stream (usually invalid names)
readStream.on('error', function(err) {
console.log('Error', err);
res.end();
});*/
},
onProgress: (progress) => {
console.log('Transcode progress', progress);
},
onError: (e) => {
console.log('Transcode error, removing tmp file.');
fs.unlink(tmpFile);
}
}).catch((reason) => {
console.log('Transcoding error', reason);
});
} else {
file.createReadStream(range).pipe(res);
}
})
return app;
}
module.exports = Server