create-torrent
Advanced tools
Comparing version 3.2.2 to 3.3.0
110
index.js
@@ -15,6 +15,7 @@ module.exports = createTorrent | ||
var stream = require('stream') | ||
var Transform = stream.Transform | ||
/** | ||
* Create a torrent. | ||
* @param {string|File|FileList|Blob|Buffer|Array.<File|Blob|Buffer>} input | ||
* @param {string|File|FileList|Blob|Buffer|Stream|Array.<File|Blob|Buffer|Steam>} input | ||
* @param {Object} opts | ||
@@ -44,3 +45,3 @@ * @param {string=} opts.name | ||
if (isBlob(input) || Buffer.isBuffer(input)) | ||
if (isBlob(input) || Buffer.isBuffer(input) || isReadable(input)) | ||
input = [ input ] | ||
@@ -50,11 +51,32 @@ | ||
opts.name = opts.name || input[0].name | ||
if (opts.name === undefined) | ||
throw new Error('Option \'name\' is required when input is not a file') | ||
// If there's just one file, allow the name to be set by `opts.name` | ||
if (input.length === 1 && !input[0].name) { | ||
input[0].name = opts.name | ||
} | ||
files = input.map(function (item) { | ||
if (!item) return | ||
if (!item.name) | ||
throw new Error('Missing requied `name` property on input') | ||
var file = { | ||
length: item.size || item.length, | ||
path: [ item.name || 'no-name' ] | ||
} | ||
if (isBlob(item)) file.getStream = getBlobStream(item) | ||
else if (Buffer.isBuffer(item)) file.getStream = getBufferStream(item) | ||
else throw new Error('Array must contain only File objects') | ||
if (isBlob(item)) { | ||
file.getStream = getBlobStream(item) | ||
file.length = item.size | ||
} else if (Buffer.isBuffer(item)) { | ||
file.getStream = getBufferStream(item) | ||
file.length = item.length | ||
} else if (isReadable(item)) { | ||
if (!opts.pieceLength) | ||
throw new Error('Must specify `pieceLength` option if input is Stream') | ||
file.getStream = getStreamStream(item, file) | ||
file.length = 0 | ||
} else { | ||
throw new Error('Array must contain only File|Blob|Buffer|Stream objects') | ||
} | ||
return file | ||
@@ -88,22 +110,2 @@ }) | ||
function getBlobStream(data) { | ||
return function() { | ||
return new FileReadStream(data) | ||
} | ||
} | ||
function getBufferStream(data) { | ||
return function() { | ||
var s = new stream.PassThrough() | ||
s.end(data) | ||
return s | ||
} | ||
} | ||
function getFSStream(data) { | ||
return function() { | ||
return fs.createReadStream(data) | ||
} | ||
} | ||
createTorrent.announceList = [ | ||
@@ -157,2 +159,3 @@ [ 'udp://tracker.publicbt.com:80' ], | ||
var pieces = '' // hex string | ||
var length = 0 | ||
@@ -166,6 +169,7 @@ var streams = files.map(function (file) { | ||
.on('data', function (chunk) { | ||
length += chunk.length | ||
pieces += sha1(chunk) | ||
}) | ||
.on('end', function () { | ||
cb(null, new Buffer(pieces, 'hex')) | ||
cb(null, new Buffer(pieces, 'hex'), length) | ||
}) | ||
@@ -208,11 +212,6 @@ .on('error', cb) | ||
var length = files.reduce(sumLength, 0) | ||
var pieceLength = opts.pieceLength || calcPieceLength(length) | ||
var pieceLength = opts.pieceLength || calcPieceLength(files.reduce(sumLength, 0)) | ||
torrent.info['piece length'] = pieceLength | ||
if (singleFile) { | ||
torrent.info.length = length | ||
} | ||
getPieceList(files, pieceLength, function (err, pieces) { | ||
getPieceList(files, pieceLength, function (err, pieces, torrentLength) { | ||
if (err) return cb(err) | ||
@@ -227,2 +226,4 @@ torrent.info.pieces = pieces | ||
torrent.info.files = files | ||
} else { | ||
torrent.info.length = torrentLength | ||
} | ||
@@ -252,1 +253,42 @@ | ||
} | ||
/** | ||
* Check if `obj` is a node Readable stream | ||
* @param {*} obj | ||
* @return {boolean} | ||
*/ | ||
function isReadable (obj) { | ||
return typeof obj === 'object' && typeof obj.pipe === 'function' | ||
} | ||
function getBlobStream (data) { | ||
return function () { | ||
return new FileReadStream(data) | ||
} | ||
} | ||
function getBufferStream (data) { | ||
return function () { | ||
var s = new stream.PassThrough() | ||
s.end(data) | ||
return s | ||
} | ||
} | ||
function getFSStream (data) { | ||
return function () { | ||
return fs.createReadStream(data) | ||
} | ||
} | ||
function getStreamStream (stream, file) { | ||
var counter = new Transform() | ||
counter._transform = function (buf, enc, done) { | ||
file.length += buf.length | ||
this.push(buf) | ||
done() | ||
} | ||
stream.pipe(counter) | ||
return counter | ||
} |
{ | ||
"name": "create-torrent", | ||
"description": "Create .torrent files", | ||
"version": "3.2.2", | ||
"version": "3.3.0", | ||
"author": "Feross Aboukhadijeh <feross@feross.org> (http://feross.org/)", | ||
@@ -29,4 +29,4 @@ "bin": { | ||
"brfs": "^1.1.2", | ||
"parse-torrent": "^1.1.0", | ||
"tape": "^2.5.0", | ||
"parse-torrent": "^2.1.2", | ||
"tape": "^3.0.3", | ||
"zuul": "^1.11.2" | ||
@@ -33,0 +33,0 @@ }, |
@@ -49,4 +49,5 @@ # create-torrent [![travis](https://img.shields.io/travis/feross/create-torrent.svg?style=flat)](https://travis-ci.org/feross/create-torrent) [![npm](https://img.shields.io/npm/v/create-torrent.svg?style=flat)](https://npmjs.org/package/create-torrent) [![gittip](https://img.shields.io/gittip/feross.svg?style=flat)](https://www.gittip.com/feross/) | ||
- Node [Buffer](http://nodejs.org/api/buffer.html) object (works in [the browser](https://www.npmjs.org/package/buffer)) | ||
- Node [stream.Readable](http://nodejs.org/api/stream.html) object (must attach a `name` property on it (or set `opt.name`), and set `opt.pieceLength`) | ||
Or, an **array of `File`, `Blob`, or `Buffer` objects**. | ||
Or, an **array of `File`, `Blob`, `Buffer`, or `Stream` objects**. | ||
@@ -53,0 +54,0 @@ `opts` is optional and allows you to set special settings on the produced .torrent file. |
var path = require('path') | ||
var fs = require('fs') | ||
var createTorrent = require('../') | ||
@@ -73,4 +74,17 @@ var crypto = require('crypto') | ||
test('create single file torrent from buffer', function (t) { | ||
t.plan(1) | ||
createTorrent(new Buffer('blah'), { name: 'blah.txt' }, function (err, torrent) { | ||
t.error(err) | ||
try { | ||
parseTorrent(torrent) | ||
} catch (err) { | ||
t.fail('failed to parse created torrent: ' + err.message) | ||
} | ||
}) | ||
}) | ||
test('create multi file torrent', function (t) { | ||
t.plan(16) | ||
t.plan(17) | ||
@@ -82,3 +96,3 @@ var numbersPath = __dirname + '/content/numbers' | ||
pieceLength: 32768, // force piece length to 32KB so info-hash will | ||
// match what transmission generataed, since we use | ||
// match what transmission generated, since we use | ||
// a different algo for picking piece length | ||
@@ -118,2 +132,3 @@ | ||
t.equal(parsedTorrent.length, 6) | ||
t.equal(parsedTorrent.info.pieces.length, 20) | ||
t.equal(parsedTorrent.pieceLength, 32768) | ||
@@ -136,3 +151,3 @@ | ||
pieceLength: 32768, // force piece length to 32KB so info-hash will | ||
// match what transmission generataed, since we use | ||
// match what transmission generated, since we use | ||
// a different algo for picking piece length | ||
@@ -191,1 +206,127 @@ | ||
}) | ||
test('create single file torrent from a stream', function (t) { | ||
t.plan(12) | ||
var leavesPath = __dirname + '/content/Leaves of Grass by Walt Whitman.epub' | ||
var stream = fs.createReadStream(leavesPath) | ||
stream.name = 'Leaves of Grass by Walt Whitman.epub' | ||
var startTime = Date.now() | ||
createTorrent(stream, { pieceLength: 16384 }, function (err, torrent) { | ||
t.error(err) | ||
var parsedTorrent = parseTorrent(torrent) | ||
t.equals(parsedTorrent.name, 'Leaves of Grass by Walt Whitman.epub') | ||
t.notOk(parsedTorrent.private) | ||
var createdTime = parsedTorrent.created / 1000 | ||
t.ok(createdTime >= startTime, 'created time is after start time') | ||
t.ok(createdTime <= Date.now(), 'created time is before now') | ||
t.deepEquals(parsedTorrent.announceList, [ | ||
['udp://tracker.publicbt.com:80'], | ||
['udp://tracker.openbittorrent.com:80'], | ||
['udp://tracker.webtorrent.io:80'], | ||
['wss://tracker.webtorrent.io'] | ||
]) | ||
t.equals(path.normalize(parsedTorrent.files[0].path), path.normalize('Leaves of Grass by Walt Whitman.epub')) | ||
t.equals(parsedTorrent.files[0].length, 362017) | ||
t.equal(parsedTorrent.length, 362017) | ||
t.equal(parsedTorrent.pieceLength, 16384) | ||
t.deepEquals(parsedTorrent.pieces, [ | ||
'1f9c3f59beec079715ec53324bde8569e4a0b4eb', | ||
'ec42307d4ce5557b5d3964c5ef55d354cf4a6ecc', | ||
'7bf1bcaf79d11fa5e0be06593c8faafc0c2ba2cf', | ||
'76d71c5b01526b23007f9e9929beafc5151e6511', | ||
'0931a1b44c21bf1e68b9138f90495e690dbc55f5', | ||
'72e4c2944cbacf26e6b3ae8a7229d88aafa05f61', | ||
'eaae6abf3f07cb6db9677cc6aded4dd3985e4586', | ||
'27567fa7639f065f71b18954304aca6366729e0b', | ||
'4773d77ae80caa96a524804dfe4b9bd3deaef999', | ||
'c9dd51027467519d5eb2561ae2cc01467de5f643', | ||
'0a60bcba24797692efa8770d23df0a830d91cb35', | ||
'b3407a88baa0590dc8c9aa6a120f274367dcd867', | ||
'e88e8338c572a06e3c801b29f519df532b3e76f6', | ||
'70cf6aee53107f3d39378483f69cf80fa568b1ea', | ||
'c53b506159e988d8bc16922d125d77d803d652c3', | ||
'ca3070c16eed9172ab506d20e522ea3f1ab674b3', | ||
'f923d76fe8f44ff32e372c3b376564c6fb5f0dbe', | ||
'52164f03629fd1322636babb2c014b7dae582da4', | ||
'1363965261e6ce12b43701f0a8c9ed1520a70eba', | ||
'004400a267765f6d3dd5c7beb5bd3c75f3df2a54', | ||
'560a61801147fa4ec7cf568e703acb04e5610a4d', | ||
'56dcc242d03293e9446cf5e457d8eb3d9588fd90', | ||
'c698de9b0dad92980906c026d8c1408fa08fe4ec' | ||
]) | ||
t.equals(sha1(parsedTorrent.infoBuffer), 'd2474e86c95b19b8bcfdb92bc12c9d44667cfa36') | ||
}) | ||
}) | ||
test('create multi file torrent with streams', function (t) { | ||
t.plan(17) | ||
var numbersPath = __dirname + '/content/numbers' | ||
var files = fs.readdirSync(numbersPath).map(function(file) { | ||
var stream = fs.createReadStream(numbersPath + '/' + file) | ||
stream.name = file | ||
return stream | ||
}) | ||
var startTime = Date.now() | ||
createTorrent(files, { | ||
pieceLength: 32768, // force piece length to 32KB so info-hash will | ||
// match what transmission generated, since we use | ||
// a different algo for picking piece length | ||
private: false, // also force `private: false` to match transmission | ||
name: 'numbers' | ||
}, function (err, torrent) { | ||
t.error(err) | ||
var parsedTorrent = parseTorrent(torrent) | ||
t.equals(parsedTorrent.name, 'numbers') | ||
t.notOk(parsedTorrent.private) | ||
var createdTime = parsedTorrent.created / 1000 | ||
t.ok(createdTime >= startTime, 'created time is after start time') | ||
t.ok(createdTime <= Date.now(), 'created time is before now') | ||
t.deepEquals(parsedTorrent.announceList, [ | ||
['udp://tracker.publicbt.com:80'], | ||
['udp://tracker.openbittorrent.com:80'], | ||
['udp://tracker.webtorrent.io:80'], | ||
['wss://tracker.webtorrent.io'] | ||
]) | ||
t.deepEquals(path.normalize(parsedTorrent.files[0].path), path.normalize('numbers/1.txt')) | ||
t.deepEquals(parsedTorrent.files[0].length, 1) | ||
t.deepEquals(path.normalize(parsedTorrent.files[1].path), path.normalize('numbers/2.txt')) | ||
t.deepEquals(parsedTorrent.files[1].length, 2) | ||
t.deepEquals(path.normalize(parsedTorrent.files[2].path), path.normalize('numbers/3.txt')) | ||
t.deepEquals(parsedTorrent.files[2].length, 3) | ||
t.equal(parsedTorrent.length, 6) | ||
t.equal(parsedTorrent.info.pieces.length, 20) | ||
t.equal(parsedTorrent.pieceLength, 32768) | ||
t.deepEquals(parsedTorrent.pieces, [ | ||
'1f74648e50a6a6708ec54ab327a163d5536b7ced' | ||
]) | ||
t.equals(sha1(parsedTorrent.infoBuffer), '80562f38656b385ea78959010e51a2cc9db41ea0') | ||
}) | ||
}) |
@@ -89,3 +89,3 @@ var createTorrent = require('../../') | ||
test('create multi file torrent', function (t) { | ||
t.plan(16) | ||
t.plan(17) | ||
@@ -95,3 +95,3 @@ var startTime = Date.now() | ||
pieceLength: 32768, // force piece length to 32KB so info-hash will | ||
// match what transmission generataed, since we use | ||
// match what transmission generated, since we use | ||
// a different algo for picking piece length | ||
@@ -132,2 +132,3 @@ | ||
t.equal(parsedTorrent.length, 6) | ||
t.equal(parsedTorrent.info.pieces.length, 20) | ||
t.equal(parsedTorrent.pieceLength, 32768) | ||
@@ -134,0 +135,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
430513
637
91
4