我目前正在做一个下载torrent的项目,在下载的同时,将其流式传输到html5视频播放器中。由于项目的限制,我不能使用peerflix或webtorrent。我目前使用的是torrent-stream模块。我的代码是node.js和pug。具体如下:
server.js
var uri = 'magnet:?xt=urn:btih:11a2ac68a11634e980f265cb1433c599d017a759';
var engine = torrentStream(uri);
let engineGo = function () {
return new Promise(function (resolve, reject) {
var engine = torrentStream(uri);
engine.on('ready', function() {
engine.files.forEach(function(file) {
if (file.name.substr(file.name.length - 3) == 'mkv' || file.name.substr(file.name.length - 3) == 'mp4') {
console.log('filename:', file.name);
var stream = file.createReadStream();
var writable = fs.createWriteStream(file.name);
stream.pipe(writable);
engine.on('download', function () {
console.log(file.name);
console.log(engine.swarm.downloaded / file.length * 100 + "%");
resolve(file);
});
}
});
});
});
}
app.get('*', function (req, res) {
if (req.url != "/Guardians.of.the.Galaxy.2014.1080p.BluRay.x264.YIFY.mp4") {
var rpath = __dirname + '/views/index.pug';
fs.readFile(rpath, 'utf8', function (err, str) {
var fn = pug.compile(str, { filename: rpath, pretty: true});
res.writeHead(200, { "Content-Type": "text/html" });
res.write(fn());
res.end();
});
} else {
engineGo().then(function (result) {
var filer = path.resolve(__dirname,result.name);
fs.stat(filer, function(err, stats) {
if (err) {
if (err.code === 'ENOENT') {
// 404 Error if file not found
return res.sendStatus(404);
}
res.end(err);
}
var range = req.headers.range;
if (!range) {
// 416 Wrong range
return res.sendStatus(416);
}
var positions = range.replace(/bytes=/, "").split("-");
var start = parseInt(positions[0], 10);
var total = stats.size;
var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
var chunksize = (end - start) + 1;
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges": "bytes",
'Connection': 'keep-alive',
"Content-Length": chunksize,
"Content-Type": "video/mp4"
});
var stream = fs.createReadStream(filer, { start: start, end: end })
.on("open", function() {
stream.pipe(res);
}).on("data", function (data) {
console.log(data);
}).on("error", function(err) {
res.end(err);
});
});
});
}
});
index.pug
doctype
html
title
|Welcome
body
video(id='video' src="http://localhost:8888/Guardians.of.the.Galaxy.2014.1080p.BluRay.x264.YIFY.mp4" type="video/mp4" controls)
在那一刻,这开始起作用了。一旦我加载了页面,promise就会执行并开始下载torrent。一旦来自torrent的第一位数据通过.on上的流(“打开”)发送出去,视频就会开始播放。播放器显示,随着更多的信息被下载,更多的信息被添加到视频中,但它永远不会播放超过发送的初始数据。有没有什么方法可以告诉玩家更多的数据即将到来,而不是在读取完发送的初始数据块后立即中断?任何建议都是有帮助的,并提前感谢你!
发布于 2016-11-24 00:47:35
你可以试试这个:
const path = require('path');
const parseRange = require('range-parser');
const engine = torrentStream('magnet:?xt=urn:btih:11a2ac68a11634e980f265cb1433c599d017a759');
const getTorrentFile = new Promise(function (resolve, reject) {
engine.on('ready', function() {
engine.files.forEach(function (file, idx) {
const ext = path.extname(file.name).slice(1);
if (ext === 'mkv' || ext === 'mp4') {
file.ext = ext;
resolve(file);
}
});
});
});
app.use('*', function (req, res) {
if (req.url != '/Guardians.of.the.Galaxy.2014.1080p.BluRay.x264.YIFY.mp4') {
res.setHeader('Content-Type', 'text/html');
if (req.method !== 'GET') return res.end();
var rpath = __dirname + '/views/index.pug';
fs.readFile(rpath, 'utf8', function (err, str) {
var fn = pug.compile(str, { filename: rpath, pretty: true});
res.end(fn());
});
} else {
res.setHeader('Accept-Ranges', 'bytes');
getTorrentFile.then(function (file) {
res.setHeader('Content-Length', file.length);
res.setHeader('Content-Type', `video/${file.ext}`);
const ranges = parseRange(file.length, req.headers.range, { combine: true });
if (ranges === -1) {
// 416 Requested Range Not Satisfiable
res.statusCode = 416;
return res.end();
} else if (ranges === -2 || ranges.type !== 'bytes' || ranges.length > 1) {
// 200 OK requested range malformed or multiple ranges requested, stream entire video
if (req.method !== 'GET') return res.end();
return file.createReadStream().pipe(res);
} else {
// 206 Partial Content valid range requested
const range = ranges[0];
res.statusCode = 206;
res.setHeader('Content-Length', 1 + range.end - range.start);
res.setHeader('Content-Range', `bytes ${range.start}-${range.end}/${file.length}`);
if (req.method !== 'GET') return res.end();
return file.createReadStream(range).pipe(res);
}
}).catch(function (e) {
console.error(e);
res.end(e);
});
}
});
我使用range-parser
来获取请求的字节范围,因为它经过了彻底的测试,可以处理奇怪的边缘情况。当服务器启动时,我也会立即启动torrent下载。这是因为浏览器经常会对同一个音频/视频文件发出多个请求,只是字节范围不同,所以在每个请求上启动一个新的torrent流并不是很有效。
https://stackoverflow.com/questions/40765376
复制相似问题