2016-11-23 10 views
2

私は現在トレントをダウンロードし、ダウンロードしている間にそれをhtml5ビデオプレーヤーにストリームするプロジェクトに取り組んでいます。私のプロジェクトの制約によって、私はpeerflixやwebtorrentを使用できません。私は現在、トレントストリームモジュールを使用しています。私のコードはnode.jsとpugにあります。以下のようになります:node.jsを使用して現在html5プレーヤーにビデオをダウンロードする方法はありますか?

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) 

これが動作を開始します現時点では。ページをロードすると、約束が実行され、トレントのダウンロードが開始されます。トレントからの最初のビットのデータが.on( 'open')ストリームに送られると、ビデオが再生を開始します。プレーヤーは、より多くの情報がダウンロードされるにつれて、より多くの情報がビデオに追加されていることを示していますが、送信された最初のデータを超えて再生することはありません。プレーヤーに、より多くのデータが来ていることを伝え、送信された最初のチャンクを読み終えたら2番目を切り捨てないようにする方法がありますか?アドバイスは有益であり、事前に感謝します!

+0

@Aks - torrent-stream –

+0

@Aksこれは私がtorrent-streamを使用している理由です。それはダウンロードとして順番にトレントを入れます – pbie42

+0

ええ、私の悪い!これを知らなかった。ここで役に立たないので私の前のコメントを削除した。私は今までにあなたを助けることができないことを申し訳なく思っています。あなたの質問をアップして、それは面白いと私はいくつかの時間で試してみます – Aks

答えて

1

あなたはこれを試してみることができます:それは徹底的にテストされ、奇数エッジケースを処理していますので、私は要求されたバイト範囲を取得するためにrange-parserを使用してい

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); 
    }); 
    } 
}); 

。また、サーバーの起動時にすぐにトレントダウンロードを開始します。これは、ブラウザが異なるバイト範囲の同じオーディオ/ビデオファイルに対して複数の要求を行うことが多いため、そのファイルに対する各要求時に新しいトレントストリームを開始することはあまり効率的ではないからです。

関連する問題