-
Notifications
You must be signed in to change notification settings - Fork 78
/
cli.js
executable file
·221 lines (196 loc) · 6.44 KB
/
cli.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/usr/bin/env node
var minimist = require('minimist')
var fs = require('fs')
var log = require('single-line-log').stdout
var bytes = require('pretty-bytes')
var pkg = require('./package.json')
var torrent = require('./')
var createTorrent = require('create-torrent')
var parseTorrent = require('parse-torrent')
var concat = require('concat-stream')
var humanSize = require('human-format')
var prettySeconds = require('pretty-seconds')
var argv = minimist(process.argv.slice(2), {
alias: { outfile: 'o' }
})
if (argv.version) {
console.log(pkg.version)
process.exit(0)
}
if (argv.help || argv._.length === 0) {
console.log(fs.readFileSync(__dirname + '/usage.txt', 'utf-8'))
process.exit(0)
}
if (argv.quiet) log = function () {}
var source = argv._.shift()
var infile
if (source === 'create') {
var dir = argv._.shift()
var outfile = argv.outfile
if (outfile === '-') outfile = null
if (outfile && fs.existsSync(outfile)) {
console.error('refusing to overwrite existing torrent file')
process.exit(1)
}
var opts = {}
if (argv.tracker) {
if (typeof argv.tracker === 'string') opts.announceList = [[argv.tracker]]
else opts.announceList = argv.tracker.map(function (t) { return [t] })
}
opts.urlList = argv.urlList
createTorrent(dir, opts, function (err, torrent) {
if (err) {
console.error(err.stack)
process.exit(1)
} else if (outfile) {
fs.writeFile(outfile, torrent, function (err) {
if (err) {
console.error(err.stack)
process.exit(1)
}
})
} else {
process.stdout.write(torrent)
}
})
} else if (source === 'info') {
infile = argv._.shift()
getInfo(infile, function (parsed) {
delete parsed.infoBuffer
delete parsed.info.pieces
console.log(JSON.stringify(toString(parsed), null, 2))
function toString (obj) {
if (Array.isArray(obj)) {
return obj.map(toString)
} else if (Buffer.isBuffer(obj)) {
return obj.toString('utf8')
} else if (typeof obj === 'object') {
return Object.keys(obj).reduce(function (acc, key) {
acc[key] = toString(obj[key])
return acc
}, {})
}
else return obj
}
})
} else if (source === 'ls' || source === 'list') {
infile = argv._.shift()
getInfo(infile, function (parsed) {
parsed.files.forEach(function (file) {
var prefix = ''
if (argv.s && argv.h) {
prefix = humanSize(file.length).replace(/(\d)B$/, '$1 B')
prefix = Array(10 - prefix.length).join(' ') + prefix + ' '
} else if (argv.s) {
prefix = String(file.length)
prefix = Array(10 - prefix.length).join(' ') + prefix + ' '
}
console.log(prefix + file.path)
})
})
} else if (source === 'seed') {
infile = argv._.shift()
var filename = infile
if (!argv.path) argv.path = process.cwd()
getSource(infile, function (body) {
var dl = torrent(body, argv)
dl.on('ready', function () {
var seeding = dl.torrent.pieces.every(function (piece, i) {
return dl.bitfield.get(i)
})
if (!seeding) {
console.error('Missing files!')
process.exit(1)
} else {
console.log('Verified files successfully!')
}
function status () {
log(
'Seeding ' + filename + '\n' +
'Connected to ' + dl.swarm.wires.reduce(notChoked, 0) + '/' + dl.swarm.wires.length + ' peers\n' +
'Uploaded ' + bytes(dl.swarm.uploaded) + ' (' + bytes(dl.swarm.uploadSpeed()) + ')\n'
)
}
setInterval(status, 1000)
status()
})
dl.listen(0)
})
} else {
if (!argv.path) argv.path = process.cwd()
getSource(source, function (body) {
var dl = torrent(body, argv)
dl.on('ready', function () {
if (argv.peer) {
console.log('connecting to peer', argv.peer)
dl.connect(argv.peer)
}
var fileCount = dl.files.length
var timeStart = (new Date()).getTime()
console.log(fileCount.toString(), (fileCount === 1 ? 'file' : 'files'), 'in torrent')
console.log(dl.files.map(function (f) { return f.name.trim() }).join('\n'))
var status = function () {
var down = bytes(dl.swarm.downloaded)
var downSpeed = bytes(dl.swarm.downloadSpeed()) + '/s'
var up = bytes(dl.swarm.uploaded)
var upSpeed = bytes(dl.swarm.uploadSpeed()) + '/s'
var torrentSize = dl.torrent.length
var bytesRemaining = torrentSize - dl.swarm.downloaded
var percentage = ((dl.swarm.downloaded / dl.torrent.length) * 100).toPrecision(4)
var progressBar = ''
var bars = ~~((percentage) / 5)
// (TimeTaken / bytesDownloaded) * bytesLeft=timeLeft
if (dl.swarm.downloaded > 0) {
if (dl.swarm.downloadSpeed() > 0) {
var seconds = 1000
var timeNow = (new Date()).getTime()
var timeElapsed = timeNow - timeStart
var timeRemaining = (((timeElapsed / dl.swarm.downloaded) * bytesRemaining) / seconds).toPrecision(6)
timeRemaining = 'Estimated ' + prettySeconds(~~timeRemaining) + ' remaining'
} else {
timeRemaining = 'Unknown time remaining'
}
} else {
timeRemaining = 'Calculating'
}
if (percentage > 100) { percentage = 100 }
for (var i = 0; i < bars; i++) {
progressBar = progressBar + '='
}
progressBar = progressBar + Array(20 + 1 - progressBar.length).join(' ')
log(
'Connected to ' + dl.swarm.wires.reduce(notChoked, 0) + '/' + dl.swarm.wires.length + ' peers\n' +
'Downloaded ' + down + ' (' + downSpeed + ')\n' +
'Uploaded ' + up + ' (' + upSpeed + ')\n' +
'Torrent Size ' + bytes(torrentSize) + '\n\n' +
'Complete: ' + percentage + '%\n' +
'[' + progressBar + ']\n' +
'0% 25 50 75 100%\n\n' + timeRemaining + '\n'
)
}
setInterval(status, 500)
status()
})
})
}
function notChoked (result, wire) {
return result + (wire.peerChoking ? 0 : 1)
}
function getSource (infile, cb) {
if (/^magnet:/.test(infile)) return cb(infile)
var instream = !infile || infile === '-'
? process.stdin
: fs.createReadStream(infile)
instream.pipe(concat(cb))
}
function getInfo (infile, cb) {
getSource(infile, function (body) {
try {
var parsed = parseTorrent(body)
} catch (err) {
console.error(err.stack)
process.exit(1)
}
cb(parsed)
})
}