grab-url 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/download.cjs.js +3 -0
- package/dist/download.cjs.js.map +1 -0
- package/dist/download.d.ts +1 -0
- package/dist/download.es.js +3715 -0
- package/dist/download.es.js.map +1 -0
- package/dist/grab-api.cjs.js +1 -1
- package/dist/grab-api.cjs.js.map +1 -1
- package/dist/grab-api.d.ts +64 -55
- package/dist/grab-api.es.js +87 -223
- package/dist/grab-api.es.js.map +1 -1
- package/dist/grab-api.umd.js +2 -0
- package/dist/grab-api.umd.js.map +1 -0
- package/dist/icons.cjs.js +1 -1
- package/dist/icons.cjs.js.map +1 -1
- package/dist/icons.d.ts +0 -0
- package/dist/icons.es.js +3 -3
- package/dist/icons.es.js.map +1 -1
- package/dist/log.cjs.js +2 -0
- package/dist/log.cjs.js.map +1 -0
- package/dist/log.d.ts +123 -0
- package/dist/log.es.js +299 -0
- package/dist/log.es.js.map +1 -0
- package/package.json +17 -13
- package/readme.md +7 -7
- package/src/grab-api.ts +114 -72
- package/src/grab-url.js +15 -81
- package/src/icons/cli/spinners.js +818 -0
- package/src/icons/svg/index.ts +0 -0
- package/src/icons/svg/loading-bouncy-ball.svg +0 -0
- package/src/icons/svg/loading-double-ring.svg +0 -0
- package/src/icons/svg/loading-eclipse.svg +0 -0
- package/src/icons/svg/loading-ellipsis.svg +0 -0
- package/src/icons/svg/loading-floating-search.svg +0 -0
- package/src/icons/svg/loading-gears.svg +0 -0
- package/src/icons/svg/loading-infinity.svg +0 -0
- package/src/icons/svg/loading-orbital.svg +0 -0
- package/src/icons/svg/loading-pacman.svg +0 -0
- package/src/icons/svg/loading-pulse-bars.svg +0 -0
- package/src/icons/svg/loading-red-blue-ball.svg +0 -0
- package/src/icons/svg/loading-reload-arrow.svg +0 -0
- package/src/icons/svg/loading-ring.svg +0 -0
- package/src/icons/svg/loading-ripple.svg +0 -0
- package/src/icons/svg/loading-spinner-oval.svg +0 -0
- package/src/icons/svg/loading-spinner.svg +0 -0
- package/src/icons/svg/loading-square-blocks.svg +0 -0
- package/src/{log.ts → log-json.ts} +128 -129
- package/src/icons/cli/spinners.json +0 -1074
|
@@ -0,0 +1,3715 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { pipeline } from "stream/promises";
|
|
5
|
+
import { Readable } from "stream";
|
|
6
|
+
import require$$0 from "readline";
|
|
7
|
+
import grab from "./grab-api.es.js";
|
|
8
|
+
import { pathToFileURL } from "url";
|
|
9
|
+
import require$$4 from "events";
|
|
10
|
+
import { log } from "./log.es.js";
|
|
11
|
+
const spinners = {
|
|
12
|
+
dots: [
|
|
13
|
+
"⠋",
|
|
14
|
+
"⠙",
|
|
15
|
+
"⠹",
|
|
16
|
+
"⠸",
|
|
17
|
+
"⠼",
|
|
18
|
+
"⠴",
|
|
19
|
+
"⠦",
|
|
20
|
+
"⠧",
|
|
21
|
+
"⠇",
|
|
22
|
+
"⠏"
|
|
23
|
+
],
|
|
24
|
+
dots2: [
|
|
25
|
+
"⣾",
|
|
26
|
+
"⣽",
|
|
27
|
+
"⣻",
|
|
28
|
+
"⢿",
|
|
29
|
+
"⡿",
|
|
30
|
+
"⣟",
|
|
31
|
+
"⣯",
|
|
32
|
+
"⣷"
|
|
33
|
+
],
|
|
34
|
+
dots3: [
|
|
35
|
+
"⠋",
|
|
36
|
+
"⠙",
|
|
37
|
+
"⠚",
|
|
38
|
+
"⠞",
|
|
39
|
+
"⠖",
|
|
40
|
+
"⠦",
|
|
41
|
+
"⠴",
|
|
42
|
+
"⠲",
|
|
43
|
+
"⠳",
|
|
44
|
+
"⠓"
|
|
45
|
+
],
|
|
46
|
+
dots4: [
|
|
47
|
+
"⠄",
|
|
48
|
+
"⠆",
|
|
49
|
+
"⠇",
|
|
50
|
+
"⠋",
|
|
51
|
+
"⠙",
|
|
52
|
+
"⠸",
|
|
53
|
+
"⠰",
|
|
54
|
+
"⠠",
|
|
55
|
+
"⠰",
|
|
56
|
+
"⠸",
|
|
57
|
+
"⠙",
|
|
58
|
+
"⠋",
|
|
59
|
+
"⠇",
|
|
60
|
+
"⠆"
|
|
61
|
+
],
|
|
62
|
+
dots5: [
|
|
63
|
+
"⠋",
|
|
64
|
+
"⠙",
|
|
65
|
+
"⠚",
|
|
66
|
+
"⠒",
|
|
67
|
+
"⠂",
|
|
68
|
+
"⠂",
|
|
69
|
+
"⠒",
|
|
70
|
+
"⠲",
|
|
71
|
+
"⠴",
|
|
72
|
+
"⠦",
|
|
73
|
+
"⠖",
|
|
74
|
+
"⠒",
|
|
75
|
+
"⠐",
|
|
76
|
+
"⠐",
|
|
77
|
+
"⠒",
|
|
78
|
+
"⠓",
|
|
79
|
+
"⠋"
|
|
80
|
+
],
|
|
81
|
+
dots6: [
|
|
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
|
+
dots7: [
|
|
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
|
+
dots8: [
|
|
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
|
+
dots9: [
|
|
165
|
+
"⢹",
|
|
166
|
+
"⢺",
|
|
167
|
+
"⢼",
|
|
168
|
+
"⣸",
|
|
169
|
+
"⣇",
|
|
170
|
+
"⡧",
|
|
171
|
+
"⡗",
|
|
172
|
+
"⡏"
|
|
173
|
+
],
|
|
174
|
+
dots10: [
|
|
175
|
+
"⢄",
|
|
176
|
+
"⢂",
|
|
177
|
+
"⢁",
|
|
178
|
+
"⡁",
|
|
179
|
+
"⡈",
|
|
180
|
+
"⡐",
|
|
181
|
+
"⡠"
|
|
182
|
+
],
|
|
183
|
+
dots11: [
|
|
184
|
+
"⠁",
|
|
185
|
+
"⠂",
|
|
186
|
+
"⠄",
|
|
187
|
+
"⡀",
|
|
188
|
+
"⢀",
|
|
189
|
+
"⠠",
|
|
190
|
+
"⠐",
|
|
191
|
+
"⠈"
|
|
192
|
+
],
|
|
193
|
+
dots12: [
|
|
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
|
+
"⠅⡘",
|
|
222
|
+
"⢃⠨",
|
|
223
|
+
"⡃⢐",
|
|
224
|
+
"⠍⡐",
|
|
225
|
+
"⢋⠠",
|
|
226
|
+
"⡋⢀",
|
|
227
|
+
"⠍⡁",
|
|
228
|
+
"⢋⠁",
|
|
229
|
+
"⡋⠁",
|
|
230
|
+
"⠍⠉",
|
|
231
|
+
"⠋⠉",
|
|
232
|
+
"⠋⠉",
|
|
233
|
+
"⠉⠙",
|
|
234
|
+
"⠉⠙",
|
|
235
|
+
"⠉⠩",
|
|
236
|
+
"⠈⢙",
|
|
237
|
+
"⠈⡙",
|
|
238
|
+
"⠈⠩",
|
|
239
|
+
"⠀⢙",
|
|
240
|
+
"⠀⡙",
|
|
241
|
+
"⠀⠩",
|
|
242
|
+
"⠀⢘",
|
|
243
|
+
"⠀⡘",
|
|
244
|
+
"⠀⠨",
|
|
245
|
+
"⠀⢐",
|
|
246
|
+
"⠀⡐",
|
|
247
|
+
"⠀⠠",
|
|
248
|
+
"⠀⢀",
|
|
249
|
+
"⠀⡀"
|
|
250
|
+
],
|
|
251
|
+
dots13: [
|
|
252
|
+
"⣼",
|
|
253
|
+
"⣹",
|
|
254
|
+
"⢻",
|
|
255
|
+
"⠿",
|
|
256
|
+
"⡟",
|
|
257
|
+
"⣏",
|
|
258
|
+
"⣧",
|
|
259
|
+
"⣶"
|
|
260
|
+
],
|
|
261
|
+
dots14: [
|
|
262
|
+
"⠉⠉",
|
|
263
|
+
"⠈⠙",
|
|
264
|
+
"⠀⠹",
|
|
265
|
+
"⠀⢸",
|
|
266
|
+
"⠀⣰",
|
|
267
|
+
"⢀⣠",
|
|
268
|
+
"⣀⣀",
|
|
269
|
+
"⣄⡀",
|
|
270
|
+
"⣆⠀",
|
|
271
|
+
"⡇⠀",
|
|
272
|
+
"⠏⠀",
|
|
273
|
+
"⠋⠁"
|
|
274
|
+
],
|
|
275
|
+
dotsCircle: [
|
|
276
|
+
"⢎ ",
|
|
277
|
+
"⠎⠁",
|
|
278
|
+
"⠊⠑",
|
|
279
|
+
"⠈⠱",
|
|
280
|
+
" ⡱",
|
|
281
|
+
"⢀⡰",
|
|
282
|
+
"⢄⡠",
|
|
283
|
+
"⢆⡀"
|
|
284
|
+
],
|
|
285
|
+
sand: [
|
|
286
|
+
"⠁",
|
|
287
|
+
"⠂",
|
|
288
|
+
"⠄",
|
|
289
|
+
"⡀",
|
|
290
|
+
"⡈",
|
|
291
|
+
"⡐",
|
|
292
|
+
"⡠",
|
|
293
|
+
"⣀",
|
|
294
|
+
"⣁",
|
|
295
|
+
"⣂",
|
|
296
|
+
"⣄",
|
|
297
|
+
"⣌",
|
|
298
|
+
"⣔",
|
|
299
|
+
"⣤",
|
|
300
|
+
"⣥",
|
|
301
|
+
"⣦",
|
|
302
|
+
"⣮",
|
|
303
|
+
"⣶",
|
|
304
|
+
"⣷",
|
|
305
|
+
"⣿",
|
|
306
|
+
"⡿",
|
|
307
|
+
"⠿",
|
|
308
|
+
"⢟",
|
|
309
|
+
"⠟",
|
|
310
|
+
"⡛",
|
|
311
|
+
"⠛",
|
|
312
|
+
"⠫",
|
|
313
|
+
"⢋",
|
|
314
|
+
"⠋",
|
|
315
|
+
"⠍",
|
|
316
|
+
"⡉",
|
|
317
|
+
"⠉",
|
|
318
|
+
"⠑",
|
|
319
|
+
"⠡",
|
|
320
|
+
"⢁"
|
|
321
|
+
],
|
|
322
|
+
line: [
|
|
323
|
+
"-",
|
|
324
|
+
"\\",
|
|
325
|
+
"|",
|
|
326
|
+
"/"
|
|
327
|
+
],
|
|
328
|
+
line2: [
|
|
329
|
+
"⠂",
|
|
330
|
+
"-",
|
|
331
|
+
"–",
|
|
332
|
+
"—",
|
|
333
|
+
"–",
|
|
334
|
+
"-"
|
|
335
|
+
],
|
|
336
|
+
pipe: [
|
|
337
|
+
"┤",
|
|
338
|
+
"┘",
|
|
339
|
+
"┴",
|
|
340
|
+
"└",
|
|
341
|
+
"├",
|
|
342
|
+
"┌",
|
|
343
|
+
"┬",
|
|
344
|
+
"┐"
|
|
345
|
+
],
|
|
346
|
+
simpleDots: [
|
|
347
|
+
". ",
|
|
348
|
+
".. ",
|
|
349
|
+
"...",
|
|
350
|
+
" "
|
|
351
|
+
],
|
|
352
|
+
simpleDotsScrolling: [
|
|
353
|
+
". ",
|
|
354
|
+
".. ",
|
|
355
|
+
"...",
|
|
356
|
+
" ..",
|
|
357
|
+
" .",
|
|
358
|
+
" "
|
|
359
|
+
],
|
|
360
|
+
star: [
|
|
361
|
+
"✶",
|
|
362
|
+
"✸",
|
|
363
|
+
"✹",
|
|
364
|
+
"✺",
|
|
365
|
+
"✹",
|
|
366
|
+
"✷"
|
|
367
|
+
],
|
|
368
|
+
star2: [
|
|
369
|
+
"+",
|
|
370
|
+
"x",
|
|
371
|
+
"*"
|
|
372
|
+
],
|
|
373
|
+
flip: [
|
|
374
|
+
"_",
|
|
375
|
+
"_",
|
|
376
|
+
"_",
|
|
377
|
+
"-",
|
|
378
|
+
"`",
|
|
379
|
+
"`",
|
|
380
|
+
"'",
|
|
381
|
+
"´",
|
|
382
|
+
"-",
|
|
383
|
+
"_",
|
|
384
|
+
"_",
|
|
385
|
+
"_"
|
|
386
|
+
],
|
|
387
|
+
hamburger: [
|
|
388
|
+
"☱",
|
|
389
|
+
"☲",
|
|
390
|
+
"☴"
|
|
391
|
+
],
|
|
392
|
+
growVertical: [
|
|
393
|
+
"▁",
|
|
394
|
+
"▃",
|
|
395
|
+
"▄",
|
|
396
|
+
"▅",
|
|
397
|
+
"▆",
|
|
398
|
+
"▇",
|
|
399
|
+
"▆",
|
|
400
|
+
"▅",
|
|
401
|
+
"▄",
|
|
402
|
+
"▃"
|
|
403
|
+
],
|
|
404
|
+
growHorizontal: [
|
|
405
|
+
"▏",
|
|
406
|
+
"▎",
|
|
407
|
+
"▍",
|
|
408
|
+
"▌",
|
|
409
|
+
"▋",
|
|
410
|
+
"▊",
|
|
411
|
+
"▉",
|
|
412
|
+
"▊",
|
|
413
|
+
"▋",
|
|
414
|
+
"▌",
|
|
415
|
+
"▍",
|
|
416
|
+
"▎"
|
|
417
|
+
],
|
|
418
|
+
balloon: [
|
|
419
|
+
" ",
|
|
420
|
+
".",
|
|
421
|
+
"o",
|
|
422
|
+
"O",
|
|
423
|
+
"@",
|
|
424
|
+
"*",
|
|
425
|
+
" "
|
|
426
|
+
],
|
|
427
|
+
balloon2: [
|
|
428
|
+
".",
|
|
429
|
+
"o",
|
|
430
|
+
"O",
|
|
431
|
+
"°",
|
|
432
|
+
"O",
|
|
433
|
+
"o",
|
|
434
|
+
"."
|
|
435
|
+
],
|
|
436
|
+
noise: [
|
|
437
|
+
"▓",
|
|
438
|
+
"▒",
|
|
439
|
+
"░"
|
|
440
|
+
],
|
|
441
|
+
bounce: [
|
|
442
|
+
"⠁",
|
|
443
|
+
"⠂",
|
|
444
|
+
"⠄",
|
|
445
|
+
"⠂"
|
|
446
|
+
],
|
|
447
|
+
boxBounce: [
|
|
448
|
+
"▖",
|
|
449
|
+
"▘",
|
|
450
|
+
"▝",
|
|
451
|
+
"▗"
|
|
452
|
+
],
|
|
453
|
+
boxBounce2: [
|
|
454
|
+
"▌",
|
|
455
|
+
"▀",
|
|
456
|
+
"▐",
|
|
457
|
+
"▄"
|
|
458
|
+
],
|
|
459
|
+
triangle: [
|
|
460
|
+
"◢",
|
|
461
|
+
"◣",
|
|
462
|
+
"◤",
|
|
463
|
+
"◥"
|
|
464
|
+
],
|
|
465
|
+
binary: [
|
|
466
|
+
"010010",
|
|
467
|
+
"001100",
|
|
468
|
+
"100101",
|
|
469
|
+
"111010",
|
|
470
|
+
"111101",
|
|
471
|
+
"010111",
|
|
472
|
+
"101011",
|
|
473
|
+
"111000",
|
|
474
|
+
"110011",
|
|
475
|
+
"110101"
|
|
476
|
+
],
|
|
477
|
+
arc: [
|
|
478
|
+
"◜",
|
|
479
|
+
"◠",
|
|
480
|
+
"◝",
|
|
481
|
+
"◞",
|
|
482
|
+
"◡",
|
|
483
|
+
"◟"
|
|
484
|
+
],
|
|
485
|
+
circle: [
|
|
486
|
+
"◡",
|
|
487
|
+
"⊙",
|
|
488
|
+
"◠"
|
|
489
|
+
],
|
|
490
|
+
squareCorners: [
|
|
491
|
+
"◰",
|
|
492
|
+
"◳",
|
|
493
|
+
"◲",
|
|
494
|
+
"◱"
|
|
495
|
+
],
|
|
496
|
+
circleQuarters: [
|
|
497
|
+
"◴",
|
|
498
|
+
"◷",
|
|
499
|
+
"◶",
|
|
500
|
+
"◵"
|
|
501
|
+
],
|
|
502
|
+
circleHalves: [
|
|
503
|
+
"◐",
|
|
504
|
+
"◓",
|
|
505
|
+
"◑",
|
|
506
|
+
"◒"
|
|
507
|
+
],
|
|
508
|
+
squish: [
|
|
509
|
+
"╫",
|
|
510
|
+
"╪"
|
|
511
|
+
],
|
|
512
|
+
toggle: [
|
|
513
|
+
"⊶",
|
|
514
|
+
"⊷"
|
|
515
|
+
],
|
|
516
|
+
toggle2: [
|
|
517
|
+
"▫",
|
|
518
|
+
"▪"
|
|
519
|
+
],
|
|
520
|
+
toggle3: [
|
|
521
|
+
"□",
|
|
522
|
+
"■"
|
|
523
|
+
],
|
|
524
|
+
toggle4: [
|
|
525
|
+
"■",
|
|
526
|
+
"□",
|
|
527
|
+
"▪",
|
|
528
|
+
"▫"
|
|
529
|
+
],
|
|
530
|
+
toggle5: [
|
|
531
|
+
"▮",
|
|
532
|
+
"▯"
|
|
533
|
+
],
|
|
534
|
+
toggle6: [
|
|
535
|
+
"ဝ",
|
|
536
|
+
"၀"
|
|
537
|
+
],
|
|
538
|
+
toggle7: [
|
|
539
|
+
"⦾",
|
|
540
|
+
"⦿"
|
|
541
|
+
],
|
|
542
|
+
toggle8: [
|
|
543
|
+
"◍",
|
|
544
|
+
"◌"
|
|
545
|
+
],
|
|
546
|
+
toggle9: [
|
|
547
|
+
"◉",
|
|
548
|
+
"◎"
|
|
549
|
+
],
|
|
550
|
+
toggle10: [
|
|
551
|
+
"㊂",
|
|
552
|
+
"㊀",
|
|
553
|
+
"㊁"
|
|
554
|
+
],
|
|
555
|
+
toggle11: [
|
|
556
|
+
"⧇",
|
|
557
|
+
"⧆"
|
|
558
|
+
],
|
|
559
|
+
toggle12: [
|
|
560
|
+
"☗",
|
|
561
|
+
"☖"
|
|
562
|
+
],
|
|
563
|
+
toggle13: [
|
|
564
|
+
"=",
|
|
565
|
+
"*",
|
|
566
|
+
"-"
|
|
567
|
+
],
|
|
568
|
+
arrow: [
|
|
569
|
+
"←",
|
|
570
|
+
"↖",
|
|
571
|
+
"↑",
|
|
572
|
+
"↗",
|
|
573
|
+
"→",
|
|
574
|
+
"↘",
|
|
575
|
+
"↓",
|
|
576
|
+
"↙"
|
|
577
|
+
],
|
|
578
|
+
arrow2: [
|
|
579
|
+
"⬆️ ",
|
|
580
|
+
"↗️ ",
|
|
581
|
+
"➡️ ",
|
|
582
|
+
"↘️ ",
|
|
583
|
+
"⬇️ ",
|
|
584
|
+
"↙️ ",
|
|
585
|
+
"⬅️ ",
|
|
586
|
+
"↖️ "
|
|
587
|
+
],
|
|
588
|
+
arrow3: [
|
|
589
|
+
"▹▹▹▹▹",
|
|
590
|
+
"▸▹▹▹▹",
|
|
591
|
+
"▹▸▹▹▹",
|
|
592
|
+
"▹▹▸▹▹",
|
|
593
|
+
"▹▹▹▸▹",
|
|
594
|
+
"▹▹▹▹▸"
|
|
595
|
+
],
|
|
596
|
+
bouncingBar: [
|
|
597
|
+
"[ ]",
|
|
598
|
+
"[= ]",
|
|
599
|
+
"[== ]",
|
|
600
|
+
"[=== ]",
|
|
601
|
+
"[====]",
|
|
602
|
+
"[ ===]",
|
|
603
|
+
"[ ==]",
|
|
604
|
+
"[ =]",
|
|
605
|
+
"[ ]",
|
|
606
|
+
"[ =]",
|
|
607
|
+
"[ ==]",
|
|
608
|
+
"[ ===]",
|
|
609
|
+
"[====]",
|
|
610
|
+
"[=== ]",
|
|
611
|
+
"[== ]",
|
|
612
|
+
"[= ]"
|
|
613
|
+
],
|
|
614
|
+
bouncingBall: [
|
|
615
|
+
"( ● )",
|
|
616
|
+
"( ● )",
|
|
617
|
+
"( ● )",
|
|
618
|
+
"( ● )",
|
|
619
|
+
"( ●)",
|
|
620
|
+
"( ● )",
|
|
621
|
+
"( ● )",
|
|
622
|
+
"( ● )",
|
|
623
|
+
"( ● )",
|
|
624
|
+
"(● )"
|
|
625
|
+
],
|
|
626
|
+
smiley: [
|
|
627
|
+
"😄 ",
|
|
628
|
+
"😝 "
|
|
629
|
+
],
|
|
630
|
+
monkey: [
|
|
631
|
+
"🙈 ",
|
|
632
|
+
"🙈 ",
|
|
633
|
+
"🙉 ",
|
|
634
|
+
"🙊 "
|
|
635
|
+
],
|
|
636
|
+
hearts: [
|
|
637
|
+
"💛 ",
|
|
638
|
+
"💙 ",
|
|
639
|
+
"💜 ",
|
|
640
|
+
"💚 ",
|
|
641
|
+
"❤️ "
|
|
642
|
+
],
|
|
643
|
+
clock: [
|
|
644
|
+
"🕛 ",
|
|
645
|
+
"🕐 ",
|
|
646
|
+
"🕑 ",
|
|
647
|
+
"🕒 ",
|
|
648
|
+
"🕓 ",
|
|
649
|
+
"🕔 ",
|
|
650
|
+
"🕕 ",
|
|
651
|
+
"🕖 ",
|
|
652
|
+
"🕗 ",
|
|
653
|
+
"🕘 ",
|
|
654
|
+
"🕙 ",
|
|
655
|
+
"🕚 "
|
|
656
|
+
],
|
|
657
|
+
earth: [
|
|
658
|
+
"🌍 ",
|
|
659
|
+
"🌎 ",
|
|
660
|
+
"🌏 "
|
|
661
|
+
],
|
|
662
|
+
moon: [
|
|
663
|
+
"🌑 ",
|
|
664
|
+
"🌒 ",
|
|
665
|
+
"🌓 ",
|
|
666
|
+
"🌔 ",
|
|
667
|
+
"🌕 ",
|
|
668
|
+
"🌖 ",
|
|
669
|
+
"🌗 ",
|
|
670
|
+
"🌘 "
|
|
671
|
+
],
|
|
672
|
+
runner: [
|
|
673
|
+
"🚶 ",
|
|
674
|
+
"🏃 "
|
|
675
|
+
],
|
|
676
|
+
dqpb: [
|
|
677
|
+
"d",
|
|
678
|
+
"q",
|
|
679
|
+
"p",
|
|
680
|
+
"b"
|
|
681
|
+
],
|
|
682
|
+
weather: [
|
|
683
|
+
"☀️ ",
|
|
684
|
+
"☀️ ",
|
|
685
|
+
"☀️ ",
|
|
686
|
+
"🌤 ",
|
|
687
|
+
"⛅️ ",
|
|
688
|
+
"🌥 ",
|
|
689
|
+
"☁️ ",
|
|
690
|
+
"🌧 ",
|
|
691
|
+
"🌨 ",
|
|
692
|
+
"🌧 ",
|
|
693
|
+
"🌨 ",
|
|
694
|
+
"🌧 ",
|
|
695
|
+
"🌨 ",
|
|
696
|
+
"⛈ ",
|
|
697
|
+
"🌨 ",
|
|
698
|
+
"🌧 ",
|
|
699
|
+
"🌨 ",
|
|
700
|
+
"☁️ ",
|
|
701
|
+
"🌥 ",
|
|
702
|
+
"⛅️ ",
|
|
703
|
+
"🌤 ",
|
|
704
|
+
"☀️ ",
|
|
705
|
+
"☀️ "
|
|
706
|
+
],
|
|
707
|
+
christmas: [
|
|
708
|
+
"🌲",
|
|
709
|
+
"🎄"
|
|
710
|
+
],
|
|
711
|
+
grenade: [
|
|
712
|
+
"، ",
|
|
713
|
+
"′ ",
|
|
714
|
+
" ´ ",
|
|
715
|
+
" ‾ ",
|
|
716
|
+
" ⸌",
|
|
717
|
+
" ⸊",
|
|
718
|
+
" |",
|
|
719
|
+
" ⁎",
|
|
720
|
+
" ⁕",
|
|
721
|
+
" ෴ ",
|
|
722
|
+
" ⁓",
|
|
723
|
+
" ",
|
|
724
|
+
" ",
|
|
725
|
+
" "
|
|
726
|
+
],
|
|
727
|
+
point: [
|
|
728
|
+
"∙∙∙",
|
|
729
|
+
"●∙∙",
|
|
730
|
+
"∙●∙",
|
|
731
|
+
"∙∙●",
|
|
732
|
+
"∙∙∙"
|
|
733
|
+
],
|
|
734
|
+
layer: [
|
|
735
|
+
"-",
|
|
736
|
+
"=",
|
|
737
|
+
"≡"
|
|
738
|
+
],
|
|
739
|
+
betaWave: [
|
|
740
|
+
"ρββββββ",
|
|
741
|
+
"βρβββββ",
|
|
742
|
+
"ββρββββ",
|
|
743
|
+
"βββρβββ",
|
|
744
|
+
"ββββρββ",
|
|
745
|
+
"βββββρβ",
|
|
746
|
+
"ββββββρ"
|
|
747
|
+
],
|
|
748
|
+
fingerDance: [
|
|
749
|
+
"🤘 ",
|
|
750
|
+
"🤟 ",
|
|
751
|
+
"🖖 ",
|
|
752
|
+
"✋ ",
|
|
753
|
+
"🤚 ",
|
|
754
|
+
"👆 "
|
|
755
|
+
],
|
|
756
|
+
mindblown: [
|
|
757
|
+
"😐 ",
|
|
758
|
+
"😐 ",
|
|
759
|
+
"😮 ",
|
|
760
|
+
"😮 ",
|
|
761
|
+
"😦 ",
|
|
762
|
+
"😦 ",
|
|
763
|
+
"😧 ",
|
|
764
|
+
"😧 ",
|
|
765
|
+
"🤯 ",
|
|
766
|
+
"💥 ",
|
|
767
|
+
"✨ ",
|
|
768
|
+
" ",
|
|
769
|
+
" ",
|
|
770
|
+
" "
|
|
771
|
+
],
|
|
772
|
+
speaker: [
|
|
773
|
+
"🔈 ",
|
|
774
|
+
"🔉 ",
|
|
775
|
+
"🔊 ",
|
|
776
|
+
"🔉 "
|
|
777
|
+
],
|
|
778
|
+
orangePulse: [
|
|
779
|
+
"🔸 ",
|
|
780
|
+
"🔶 ",
|
|
781
|
+
"🟠 ",
|
|
782
|
+
"🟠 ",
|
|
783
|
+
"🔶 "
|
|
784
|
+
],
|
|
785
|
+
bluePulse: [
|
|
786
|
+
"🔹 ",
|
|
787
|
+
"🔷 ",
|
|
788
|
+
"🔵 ",
|
|
789
|
+
"🔵 ",
|
|
790
|
+
"🔷 "
|
|
791
|
+
],
|
|
792
|
+
orangeBluePulse: [
|
|
793
|
+
"🔸 ",
|
|
794
|
+
"🔶 ",
|
|
795
|
+
"🟠 ",
|
|
796
|
+
"🟠 ",
|
|
797
|
+
"🔶 ",
|
|
798
|
+
"🔹 ",
|
|
799
|
+
"🔷 ",
|
|
800
|
+
"🔵 ",
|
|
801
|
+
"🔵 ",
|
|
802
|
+
"🔷 "
|
|
803
|
+
],
|
|
804
|
+
timeTravel: [
|
|
805
|
+
"🕛 ",
|
|
806
|
+
"🕚 ",
|
|
807
|
+
"🕙 ",
|
|
808
|
+
"🕘 ",
|
|
809
|
+
"🕗 ",
|
|
810
|
+
"🕖 ",
|
|
811
|
+
"🕕 ",
|
|
812
|
+
"🕔 ",
|
|
813
|
+
"🕓 ",
|
|
814
|
+
"🕒 ",
|
|
815
|
+
"🕑 ",
|
|
816
|
+
"🕐 "
|
|
817
|
+
],
|
|
818
|
+
aesthetic: [
|
|
819
|
+
"▰▱▱▱▱▱▱",
|
|
820
|
+
"▰▰▱▱▱▱▱",
|
|
821
|
+
"▰▰▰▱▱▱▱",
|
|
822
|
+
"▰▰▰▰▱▱▱",
|
|
823
|
+
"▰▰▰▰▰▱▱",
|
|
824
|
+
"▰▰▰▰▰▰▱",
|
|
825
|
+
"▰▰▰▰▰▰▰",
|
|
826
|
+
"▰▱▱▱▱▱▱"
|
|
827
|
+
]
|
|
828
|
+
};
|
|
829
|
+
function getDefaultExportFromCjs(x) {
|
|
830
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
831
|
+
}
|
|
832
|
+
var eta;
|
|
833
|
+
var hasRequiredEta;
|
|
834
|
+
function requireEta() {
|
|
835
|
+
if (hasRequiredEta) return eta;
|
|
836
|
+
hasRequiredEta = 1;
|
|
837
|
+
class ETA {
|
|
838
|
+
constructor(length, initTime, initValue) {
|
|
839
|
+
this.etaBufferLength = length || 100;
|
|
840
|
+
this.valueBuffer = [initValue];
|
|
841
|
+
this.timeBuffer = [initTime];
|
|
842
|
+
this.eta = "0";
|
|
843
|
+
}
|
|
844
|
+
// add new values to calculation buffer
|
|
845
|
+
update(time, value, total) {
|
|
846
|
+
this.valueBuffer.push(value);
|
|
847
|
+
this.timeBuffer.push(time);
|
|
848
|
+
this.calculate(total - value);
|
|
849
|
+
}
|
|
850
|
+
// fetch estimated time
|
|
851
|
+
getTime() {
|
|
852
|
+
return this.eta;
|
|
853
|
+
}
|
|
854
|
+
// eta calculation - request number of remaining events
|
|
855
|
+
calculate(remaining) {
|
|
856
|
+
const currentBufferSize = this.valueBuffer.length;
|
|
857
|
+
const buffer = Math.min(this.etaBufferLength, currentBufferSize);
|
|
858
|
+
const v_diff = this.valueBuffer[currentBufferSize - 1] - this.valueBuffer[currentBufferSize - buffer];
|
|
859
|
+
const t_diff = this.timeBuffer[currentBufferSize - 1] - this.timeBuffer[currentBufferSize - buffer];
|
|
860
|
+
const vt_rate = v_diff / t_diff;
|
|
861
|
+
this.valueBuffer = this.valueBuffer.slice(-this.etaBufferLength);
|
|
862
|
+
this.timeBuffer = this.timeBuffer.slice(-this.etaBufferLength);
|
|
863
|
+
const eta2 = Math.ceil(remaining / vt_rate / 1e3);
|
|
864
|
+
if (isNaN(eta2)) {
|
|
865
|
+
this.eta = "NULL";
|
|
866
|
+
} else if (!isFinite(eta2)) {
|
|
867
|
+
this.eta = "INF";
|
|
868
|
+
} else if (eta2 > 1e7) {
|
|
869
|
+
this.eta = "INF";
|
|
870
|
+
} else if (eta2 < 0) {
|
|
871
|
+
this.eta = 0;
|
|
872
|
+
} else {
|
|
873
|
+
this.eta = eta2;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
eta = ETA;
|
|
878
|
+
return eta;
|
|
879
|
+
}
|
|
880
|
+
var terminal;
|
|
881
|
+
var hasRequiredTerminal;
|
|
882
|
+
function requireTerminal() {
|
|
883
|
+
if (hasRequiredTerminal) return terminal;
|
|
884
|
+
hasRequiredTerminal = 1;
|
|
885
|
+
const _readline = require$$0;
|
|
886
|
+
class Terminal {
|
|
887
|
+
constructor(outputStream) {
|
|
888
|
+
this.stream = outputStream;
|
|
889
|
+
this.linewrap = true;
|
|
890
|
+
this.dy = 0;
|
|
891
|
+
}
|
|
892
|
+
// save cursor position + settings
|
|
893
|
+
cursorSave() {
|
|
894
|
+
if (!this.stream.isTTY) {
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
this.stream.write("\x1B7");
|
|
898
|
+
}
|
|
899
|
+
// restore last cursor position + settings
|
|
900
|
+
cursorRestore() {
|
|
901
|
+
if (!this.stream.isTTY) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
this.stream.write("\x1B8");
|
|
905
|
+
}
|
|
906
|
+
// show/hide cursor
|
|
907
|
+
cursor(enabled) {
|
|
908
|
+
if (!this.stream.isTTY) {
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
if (enabled) {
|
|
912
|
+
this.stream.write("\x1B[?25h");
|
|
913
|
+
} else {
|
|
914
|
+
this.stream.write("\x1B[?25l");
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
// change cursor positionn
|
|
918
|
+
cursorTo(x = null, y = null) {
|
|
919
|
+
if (!this.stream.isTTY) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
_readline.cursorTo(this.stream, x, y);
|
|
923
|
+
}
|
|
924
|
+
// change relative cursor position
|
|
925
|
+
cursorRelative(dx = null, dy = null) {
|
|
926
|
+
if (!this.stream.isTTY) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
this.dy = this.dy + dy;
|
|
930
|
+
_readline.moveCursor(this.stream, dx, dy);
|
|
931
|
+
}
|
|
932
|
+
// relative reset
|
|
933
|
+
cursorRelativeReset() {
|
|
934
|
+
if (!this.stream.isTTY) {
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
_readline.moveCursor(this.stream, 0, -this.dy);
|
|
938
|
+
_readline.cursorTo(this.stream, 0, null);
|
|
939
|
+
this.dy = 0;
|
|
940
|
+
}
|
|
941
|
+
// clear to the right from cursor
|
|
942
|
+
clearRight() {
|
|
943
|
+
if (!this.stream.isTTY) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
_readline.clearLine(this.stream, 1);
|
|
947
|
+
}
|
|
948
|
+
// clear the full line
|
|
949
|
+
clearLine() {
|
|
950
|
+
if (!this.stream.isTTY) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
_readline.clearLine(this.stream, 0);
|
|
954
|
+
}
|
|
955
|
+
// clear everyting beyond the current line
|
|
956
|
+
clearBottom() {
|
|
957
|
+
if (!this.stream.isTTY) {
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
_readline.clearScreenDown(this.stream);
|
|
961
|
+
}
|
|
962
|
+
// add new line; increment counter
|
|
963
|
+
newline() {
|
|
964
|
+
this.stream.write("\n");
|
|
965
|
+
this.dy++;
|
|
966
|
+
}
|
|
967
|
+
// write content to output stream
|
|
968
|
+
// @TODO use string-width to strip length
|
|
969
|
+
write(s, rawWrite = false) {
|
|
970
|
+
if (this.linewrap === true && rawWrite === false) {
|
|
971
|
+
this.stream.write(s.substr(0, this.getWidth()));
|
|
972
|
+
} else {
|
|
973
|
+
this.stream.write(s);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// control line wrapping
|
|
977
|
+
lineWrapping(enabled) {
|
|
978
|
+
if (!this.stream.isTTY) {
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
this.linewrap = enabled;
|
|
982
|
+
if (enabled) {
|
|
983
|
+
this.stream.write("\x1B[?7h");
|
|
984
|
+
} else {
|
|
985
|
+
this.stream.write("\x1B[?7l");
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
// tty environment ?
|
|
989
|
+
isTTY() {
|
|
990
|
+
return this.stream.isTTY === true;
|
|
991
|
+
}
|
|
992
|
+
// get terminal width
|
|
993
|
+
getWidth() {
|
|
994
|
+
return this.stream.columns || (this.stream.isTTY ? 80 : 200);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
terminal = Terminal;
|
|
998
|
+
return terminal;
|
|
999
|
+
}
|
|
1000
|
+
var stringWidth = { exports: {} };
|
|
1001
|
+
var ansiRegex;
|
|
1002
|
+
var hasRequiredAnsiRegex;
|
|
1003
|
+
function requireAnsiRegex() {
|
|
1004
|
+
if (hasRequiredAnsiRegex) return ansiRegex;
|
|
1005
|
+
hasRequiredAnsiRegex = 1;
|
|
1006
|
+
ansiRegex = ({ onlyFirst = false } = {}) => {
|
|
1007
|
+
const pattern = [
|
|
1008
|
+
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
|
1009
|
+
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"
|
|
1010
|
+
].join("|");
|
|
1011
|
+
return new RegExp(pattern, onlyFirst ? void 0 : "g");
|
|
1012
|
+
};
|
|
1013
|
+
return ansiRegex;
|
|
1014
|
+
}
|
|
1015
|
+
var stripAnsi;
|
|
1016
|
+
var hasRequiredStripAnsi;
|
|
1017
|
+
function requireStripAnsi() {
|
|
1018
|
+
if (hasRequiredStripAnsi) return stripAnsi;
|
|
1019
|
+
hasRequiredStripAnsi = 1;
|
|
1020
|
+
const ansiRegex2 = requireAnsiRegex();
|
|
1021
|
+
stripAnsi = (string) => typeof string === "string" ? string.replace(ansiRegex2(), "") : string;
|
|
1022
|
+
return stripAnsi;
|
|
1023
|
+
}
|
|
1024
|
+
var isFullwidthCodePoint = { exports: {} };
|
|
1025
|
+
var hasRequiredIsFullwidthCodePoint;
|
|
1026
|
+
function requireIsFullwidthCodePoint() {
|
|
1027
|
+
if (hasRequiredIsFullwidthCodePoint) return isFullwidthCodePoint.exports;
|
|
1028
|
+
hasRequiredIsFullwidthCodePoint = 1;
|
|
1029
|
+
const isFullwidthCodePoint$1 = (codePoint) => {
|
|
1030
|
+
if (Number.isNaN(codePoint)) {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
if (codePoint >= 4352 && (codePoint <= 4447 || // Hangul Jamo
|
|
1034
|
+
codePoint === 9001 || // LEFT-POINTING ANGLE BRACKET
|
|
1035
|
+
codePoint === 9002 || // RIGHT-POINTING ANGLE BRACKET
|
|
1036
|
+
// CJK Radicals Supplement .. Enclosed CJK Letters and Months
|
|
1037
|
+
11904 <= codePoint && codePoint <= 12871 && codePoint !== 12351 || // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
|
|
1038
|
+
12880 <= codePoint && codePoint <= 19903 || // CJK Unified Ideographs .. Yi Radicals
|
|
1039
|
+
19968 <= codePoint && codePoint <= 42182 || // Hangul Jamo Extended-A
|
|
1040
|
+
43360 <= codePoint && codePoint <= 43388 || // Hangul Syllables
|
|
1041
|
+
44032 <= codePoint && codePoint <= 55203 || // CJK Compatibility Ideographs
|
|
1042
|
+
63744 <= codePoint && codePoint <= 64255 || // Vertical Forms
|
|
1043
|
+
65040 <= codePoint && codePoint <= 65049 || // CJK Compatibility Forms .. Small Form Variants
|
|
1044
|
+
65072 <= codePoint && codePoint <= 65131 || // Halfwidth and Fullwidth Forms
|
|
1045
|
+
65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510 || // Kana Supplement
|
|
1046
|
+
110592 <= codePoint && codePoint <= 110593 || // Enclosed Ideographic Supplement
|
|
1047
|
+
127488 <= codePoint && codePoint <= 127569 || // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
|
|
1048
|
+
131072 <= codePoint && codePoint <= 262141)) {
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
return false;
|
|
1052
|
+
};
|
|
1053
|
+
isFullwidthCodePoint.exports = isFullwidthCodePoint$1;
|
|
1054
|
+
isFullwidthCodePoint.exports.default = isFullwidthCodePoint$1;
|
|
1055
|
+
return isFullwidthCodePoint.exports;
|
|
1056
|
+
}
|
|
1057
|
+
var emojiRegex;
|
|
1058
|
+
var hasRequiredEmojiRegex;
|
|
1059
|
+
function requireEmojiRegex() {
|
|
1060
|
+
if (hasRequiredEmojiRegex) return emojiRegex;
|
|
1061
|
+
hasRequiredEmojiRegex = 1;
|
|
1062
|
+
emojiRegex = function() {
|
|
1063
|
+
return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
|
|
1064
|
+
};
|
|
1065
|
+
return emojiRegex;
|
|
1066
|
+
}
|
|
1067
|
+
var hasRequiredStringWidth;
|
|
1068
|
+
function requireStringWidth() {
|
|
1069
|
+
if (hasRequiredStringWidth) return stringWidth.exports;
|
|
1070
|
+
hasRequiredStringWidth = 1;
|
|
1071
|
+
const stripAnsi2 = requireStripAnsi();
|
|
1072
|
+
const isFullwidthCodePoint2 = requireIsFullwidthCodePoint();
|
|
1073
|
+
const emojiRegex2 = requireEmojiRegex();
|
|
1074
|
+
const stringWidth$1 = (string) => {
|
|
1075
|
+
if (typeof string !== "string" || string.length === 0) {
|
|
1076
|
+
return 0;
|
|
1077
|
+
}
|
|
1078
|
+
string = stripAnsi2(string);
|
|
1079
|
+
if (string.length === 0) {
|
|
1080
|
+
return 0;
|
|
1081
|
+
}
|
|
1082
|
+
string = string.replace(emojiRegex2(), " ");
|
|
1083
|
+
let width = 0;
|
|
1084
|
+
for (let i = 0; i < string.length; i++) {
|
|
1085
|
+
const code = string.codePointAt(i);
|
|
1086
|
+
if (code <= 31 || code >= 127 && code <= 159) {
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (code >= 768 && code <= 879) {
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
if (code > 65535) {
|
|
1093
|
+
i++;
|
|
1094
|
+
}
|
|
1095
|
+
width += isFullwidthCodePoint2(code) ? 2 : 1;
|
|
1096
|
+
}
|
|
1097
|
+
return width;
|
|
1098
|
+
};
|
|
1099
|
+
stringWidth.exports = stringWidth$1;
|
|
1100
|
+
stringWidth.exports.default = stringWidth$1;
|
|
1101
|
+
return stringWidth.exports;
|
|
1102
|
+
}
|
|
1103
|
+
var formatValue;
|
|
1104
|
+
var hasRequiredFormatValue;
|
|
1105
|
+
function requireFormatValue() {
|
|
1106
|
+
if (hasRequiredFormatValue) return formatValue;
|
|
1107
|
+
hasRequiredFormatValue = 1;
|
|
1108
|
+
formatValue = function formatValue2(v, options2, type) {
|
|
1109
|
+
if (options2.autopadding !== true) {
|
|
1110
|
+
return v;
|
|
1111
|
+
}
|
|
1112
|
+
function autopadding(value, length) {
|
|
1113
|
+
return (options2.autopaddingChar + value).slice(-3);
|
|
1114
|
+
}
|
|
1115
|
+
switch (type) {
|
|
1116
|
+
case "percentage":
|
|
1117
|
+
return autopadding(v);
|
|
1118
|
+
default:
|
|
1119
|
+
return v;
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
return formatValue;
|
|
1123
|
+
}
|
|
1124
|
+
var formatBar;
|
|
1125
|
+
var hasRequiredFormatBar;
|
|
1126
|
+
function requireFormatBar() {
|
|
1127
|
+
if (hasRequiredFormatBar) return formatBar;
|
|
1128
|
+
hasRequiredFormatBar = 1;
|
|
1129
|
+
formatBar = function formatBar2(progress, options2) {
|
|
1130
|
+
const completeSize = Math.round(progress * options2.barsize);
|
|
1131
|
+
const incompleteSize = options2.barsize - completeSize;
|
|
1132
|
+
return options2.barCompleteString.substr(0, completeSize) + options2.barGlue + options2.barIncompleteString.substr(0, incompleteSize);
|
|
1133
|
+
};
|
|
1134
|
+
return formatBar;
|
|
1135
|
+
}
|
|
1136
|
+
var formatTime;
|
|
1137
|
+
var hasRequiredFormatTime;
|
|
1138
|
+
function requireFormatTime() {
|
|
1139
|
+
if (hasRequiredFormatTime) return formatTime;
|
|
1140
|
+
hasRequiredFormatTime = 1;
|
|
1141
|
+
formatTime = function formatTime2(t, options2, roundToMultipleOf) {
|
|
1142
|
+
function round(input) {
|
|
1143
|
+
if (roundToMultipleOf) {
|
|
1144
|
+
return roundToMultipleOf * Math.round(input / roundToMultipleOf);
|
|
1145
|
+
} else {
|
|
1146
|
+
return input;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
function autopadding(v) {
|
|
1150
|
+
return (options2.autopaddingChar + v).slice(-2);
|
|
1151
|
+
}
|
|
1152
|
+
if (t > 3600) {
|
|
1153
|
+
return autopadding(Math.floor(t / 3600)) + "h" + autopadding(round(t % 3600 / 60)) + "m";
|
|
1154
|
+
} else if (t > 60) {
|
|
1155
|
+
return autopadding(Math.floor(t / 60)) + "m" + autopadding(round(t % 60)) + "s";
|
|
1156
|
+
} else if (t > 10) {
|
|
1157
|
+
return autopadding(round(t)) + "s";
|
|
1158
|
+
} else {
|
|
1159
|
+
return autopadding(t) + "s";
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
return formatTime;
|
|
1163
|
+
}
|
|
1164
|
+
var formatter;
|
|
1165
|
+
var hasRequiredFormatter;
|
|
1166
|
+
function requireFormatter() {
|
|
1167
|
+
if (hasRequiredFormatter) return formatter;
|
|
1168
|
+
hasRequiredFormatter = 1;
|
|
1169
|
+
const _stringWidth = requireStringWidth();
|
|
1170
|
+
const _defaultFormatValue = requireFormatValue();
|
|
1171
|
+
const _defaultFormatBar = requireFormatBar();
|
|
1172
|
+
const _defaultFormatTime = requireFormatTime();
|
|
1173
|
+
formatter = function defaultFormatter(options2, params, payload) {
|
|
1174
|
+
let s = options2.format;
|
|
1175
|
+
const formatTime2 = options2.formatTime || _defaultFormatTime;
|
|
1176
|
+
const formatValue2 = options2.formatValue || _defaultFormatValue;
|
|
1177
|
+
const formatBar2 = options2.formatBar || _defaultFormatBar;
|
|
1178
|
+
const percentage = Math.floor(params.progress * 100) + "";
|
|
1179
|
+
const stopTime = params.stopTime || Date.now();
|
|
1180
|
+
const elapsedTime = Math.round((stopTime - params.startTime) / 1e3);
|
|
1181
|
+
const context = Object.assign({}, payload, {
|
|
1182
|
+
bar: formatBar2(params.progress, options2),
|
|
1183
|
+
percentage: formatValue2(percentage, options2, "percentage"),
|
|
1184
|
+
total: formatValue2(params.total, options2, "total"),
|
|
1185
|
+
value: formatValue2(params.value, options2, "value"),
|
|
1186
|
+
eta: formatValue2(params.eta, options2, "eta"),
|
|
1187
|
+
eta_formatted: formatTime2(params.eta, options2, 5),
|
|
1188
|
+
duration: formatValue2(elapsedTime, options2, "duration"),
|
|
1189
|
+
duration_formatted: formatTime2(elapsedTime, options2, 1)
|
|
1190
|
+
});
|
|
1191
|
+
s = s.replace(/\{(\w+)\}/g, function(match, key) {
|
|
1192
|
+
if (typeof context[key] !== "undefined") {
|
|
1193
|
+
return context[key];
|
|
1194
|
+
}
|
|
1195
|
+
return match;
|
|
1196
|
+
});
|
|
1197
|
+
const fullMargin = Math.max(0, params.maxWidth - _stringWidth(s) - 2);
|
|
1198
|
+
const halfMargin = Math.floor(fullMargin / 2);
|
|
1199
|
+
switch (options2.align) {
|
|
1200
|
+
// fill start-of-line with whitespaces
|
|
1201
|
+
case "right":
|
|
1202
|
+
s = fullMargin > 0 ? " ".repeat(fullMargin) + s : s;
|
|
1203
|
+
break;
|
|
1204
|
+
// distribute whitespaces to left+right
|
|
1205
|
+
case "center":
|
|
1206
|
+
s = halfMargin > 0 ? " ".repeat(halfMargin) + s : s;
|
|
1207
|
+
break;
|
|
1208
|
+
}
|
|
1209
|
+
return s;
|
|
1210
|
+
};
|
|
1211
|
+
return formatter;
|
|
1212
|
+
}
|
|
1213
|
+
var options;
|
|
1214
|
+
var hasRequiredOptions;
|
|
1215
|
+
function requireOptions() {
|
|
1216
|
+
if (hasRequiredOptions) return options;
|
|
1217
|
+
hasRequiredOptions = 1;
|
|
1218
|
+
function mergeOption(v, defaultValue) {
|
|
1219
|
+
if (typeof v === "undefined" || v === null) {
|
|
1220
|
+
return defaultValue;
|
|
1221
|
+
} else {
|
|
1222
|
+
return v;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
options = {
|
|
1226
|
+
// set global options
|
|
1227
|
+
parse: function parse(rawOptions, preset) {
|
|
1228
|
+
const options2 = {};
|
|
1229
|
+
const opt = Object.assign({}, preset, rawOptions);
|
|
1230
|
+
options2.throttleTime = 1e3 / mergeOption(opt.fps, 10);
|
|
1231
|
+
options2.stream = mergeOption(opt.stream, process.stderr);
|
|
1232
|
+
options2.terminal = mergeOption(opt.terminal, null);
|
|
1233
|
+
options2.clearOnComplete = mergeOption(opt.clearOnComplete, false);
|
|
1234
|
+
options2.stopOnComplete = mergeOption(opt.stopOnComplete, false);
|
|
1235
|
+
options2.barsize = mergeOption(opt.barsize, 40);
|
|
1236
|
+
options2.align = mergeOption(opt.align, "left");
|
|
1237
|
+
options2.hideCursor = mergeOption(opt.hideCursor, false);
|
|
1238
|
+
options2.linewrap = mergeOption(opt.linewrap, false);
|
|
1239
|
+
options2.barGlue = mergeOption(opt.barGlue, "");
|
|
1240
|
+
options2.barCompleteChar = mergeOption(opt.barCompleteChar, "=");
|
|
1241
|
+
options2.barIncompleteChar = mergeOption(opt.barIncompleteChar, "-");
|
|
1242
|
+
options2.format = mergeOption(opt.format, "progress [{bar}] {percentage}% | ETA: {eta}s | {value}/{total}");
|
|
1243
|
+
options2.formatTime = mergeOption(opt.formatTime, null);
|
|
1244
|
+
options2.formatValue = mergeOption(opt.formatValue, null);
|
|
1245
|
+
options2.formatBar = mergeOption(opt.formatBar, null);
|
|
1246
|
+
options2.etaBufferLength = mergeOption(opt.etaBuffer, 10);
|
|
1247
|
+
options2.etaAsynchronousUpdate = mergeOption(opt.etaAsynchronousUpdate, false);
|
|
1248
|
+
options2.progressCalculationRelative = mergeOption(opt.progressCalculationRelative, false);
|
|
1249
|
+
options2.synchronousUpdate = mergeOption(opt.synchronousUpdate, true);
|
|
1250
|
+
options2.noTTYOutput = mergeOption(opt.noTTYOutput, false);
|
|
1251
|
+
options2.notTTYSchedule = mergeOption(opt.notTTYSchedule, 2e3);
|
|
1252
|
+
options2.emptyOnZero = mergeOption(opt.emptyOnZero, false);
|
|
1253
|
+
options2.forceRedraw = mergeOption(opt.forceRedraw, false);
|
|
1254
|
+
options2.autopadding = mergeOption(opt.autopadding, false);
|
|
1255
|
+
options2.gracefulExit = mergeOption(opt.gracefulExit, false);
|
|
1256
|
+
return options2;
|
|
1257
|
+
},
|
|
1258
|
+
// derived options: instance specific, has to be created for every bar element
|
|
1259
|
+
assignDerivedOptions: function assignDerivedOptions(options2) {
|
|
1260
|
+
options2.barCompleteString = options2.barCompleteChar.repeat(options2.barsize + 1);
|
|
1261
|
+
options2.barIncompleteString = options2.barIncompleteChar.repeat(options2.barsize + 1);
|
|
1262
|
+
options2.autopaddingChar = options2.autopadding ? mergeOption(options2.autopaddingChar, " ") : "";
|
|
1263
|
+
return options2;
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
return options;
|
|
1267
|
+
}
|
|
1268
|
+
var genericBar;
|
|
1269
|
+
var hasRequiredGenericBar;
|
|
1270
|
+
function requireGenericBar() {
|
|
1271
|
+
if (hasRequiredGenericBar) return genericBar;
|
|
1272
|
+
hasRequiredGenericBar = 1;
|
|
1273
|
+
const _ETA = requireEta();
|
|
1274
|
+
const _Terminal = requireTerminal();
|
|
1275
|
+
const _formatter = requireFormatter();
|
|
1276
|
+
const _options = requireOptions();
|
|
1277
|
+
const _EventEmitter = require$$4;
|
|
1278
|
+
genericBar = class GenericBar extends _EventEmitter {
|
|
1279
|
+
constructor(options2) {
|
|
1280
|
+
super();
|
|
1281
|
+
this.options = _options.assignDerivedOptions(options2);
|
|
1282
|
+
this.terminal = this.options.terminal ? this.options.terminal : new _Terminal(this.options.stream);
|
|
1283
|
+
this.value = 0;
|
|
1284
|
+
this.startValue = 0;
|
|
1285
|
+
this.total = 100;
|
|
1286
|
+
this.lastDrawnString = null;
|
|
1287
|
+
this.startTime = null;
|
|
1288
|
+
this.stopTime = null;
|
|
1289
|
+
this.lastRedraw = Date.now();
|
|
1290
|
+
this.eta = new _ETA(this.options.etaBufferLength, 0, 0);
|
|
1291
|
+
this.payload = {};
|
|
1292
|
+
this.isActive = false;
|
|
1293
|
+
this.formatter = typeof this.options.format === "function" ? this.options.format : _formatter;
|
|
1294
|
+
}
|
|
1295
|
+
// internal render function
|
|
1296
|
+
render(forceRendering = false) {
|
|
1297
|
+
const params = {
|
|
1298
|
+
progress: this.getProgress(),
|
|
1299
|
+
eta: this.eta.getTime(),
|
|
1300
|
+
startTime: this.startTime,
|
|
1301
|
+
stopTime: this.stopTime,
|
|
1302
|
+
total: this.total,
|
|
1303
|
+
value: this.value,
|
|
1304
|
+
maxWidth: this.terminal.getWidth()
|
|
1305
|
+
};
|
|
1306
|
+
if (this.options.etaAsynchronousUpdate) {
|
|
1307
|
+
this.updateETA();
|
|
1308
|
+
}
|
|
1309
|
+
const s = this.formatter(this.options, params, this.payload);
|
|
1310
|
+
const forceRedraw = forceRendering || this.options.forceRedraw || this.options.noTTYOutput && !this.terminal.isTTY();
|
|
1311
|
+
if (forceRedraw || this.lastDrawnString != s) {
|
|
1312
|
+
this.emit("redraw-pre");
|
|
1313
|
+
this.terminal.cursorTo(0, null);
|
|
1314
|
+
this.terminal.write(s);
|
|
1315
|
+
this.terminal.clearRight();
|
|
1316
|
+
this.lastDrawnString = s;
|
|
1317
|
+
this.lastRedraw = Date.now();
|
|
1318
|
+
this.emit("redraw-post");
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
// start the progress bar
|
|
1322
|
+
start(total, startValue, payload) {
|
|
1323
|
+
this.value = startValue || 0;
|
|
1324
|
+
this.total = typeof total !== "undefined" && total >= 0 ? total : 100;
|
|
1325
|
+
this.startValue = startValue || 0;
|
|
1326
|
+
this.payload = payload || {};
|
|
1327
|
+
this.startTime = Date.now();
|
|
1328
|
+
this.stopTime = null;
|
|
1329
|
+
this.lastDrawnString = "";
|
|
1330
|
+
this.eta = new _ETA(this.options.etaBufferLength, this.startTime, this.value);
|
|
1331
|
+
this.isActive = true;
|
|
1332
|
+
this.emit("start", total, startValue);
|
|
1333
|
+
}
|
|
1334
|
+
// stop the bar
|
|
1335
|
+
stop() {
|
|
1336
|
+
this.isActive = false;
|
|
1337
|
+
this.stopTime = Date.now();
|
|
1338
|
+
this.emit("stop", this.total, this.value);
|
|
1339
|
+
}
|
|
1340
|
+
// update the bar value
|
|
1341
|
+
// update(value, payload)
|
|
1342
|
+
// update(payload)
|
|
1343
|
+
update(arg0, arg1 = {}) {
|
|
1344
|
+
if (typeof arg0 === "number") {
|
|
1345
|
+
this.value = arg0;
|
|
1346
|
+
this.eta.update(Date.now(), arg0, this.total);
|
|
1347
|
+
}
|
|
1348
|
+
const payloadData = (typeof arg0 === "object" ? arg0 : arg1) || {};
|
|
1349
|
+
this.emit("update", this.total, this.value);
|
|
1350
|
+
for (const key in payloadData) {
|
|
1351
|
+
this.payload[key] = payloadData[key];
|
|
1352
|
+
}
|
|
1353
|
+
if (this.value >= this.getTotal() && this.options.stopOnComplete) {
|
|
1354
|
+
this.stop();
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
// calculate the actual progress value
|
|
1358
|
+
getProgress() {
|
|
1359
|
+
let progress = this.value / this.total;
|
|
1360
|
+
if (this.options.progressCalculationRelative) {
|
|
1361
|
+
progress = (this.value - this.startValue) / (this.total - this.startValue);
|
|
1362
|
+
}
|
|
1363
|
+
if (isNaN(progress)) {
|
|
1364
|
+
progress = this.options && this.options.emptyOnZero ? 0 : 1;
|
|
1365
|
+
}
|
|
1366
|
+
progress = Math.min(Math.max(progress, 0), 1);
|
|
1367
|
+
return progress;
|
|
1368
|
+
}
|
|
1369
|
+
// update the bar value
|
|
1370
|
+
// increment(delta, payload)
|
|
1371
|
+
// increment(payload)
|
|
1372
|
+
increment(arg0 = 1, arg1 = {}) {
|
|
1373
|
+
if (typeof arg0 === "object") {
|
|
1374
|
+
this.update(this.value + 1, arg0);
|
|
1375
|
+
} else {
|
|
1376
|
+
this.update(this.value + arg0, arg1);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
// get the total (limit) value
|
|
1380
|
+
getTotal() {
|
|
1381
|
+
return this.total;
|
|
1382
|
+
}
|
|
1383
|
+
// set the total (limit) value
|
|
1384
|
+
setTotal(total) {
|
|
1385
|
+
if (typeof total !== "undefined" && total >= 0) {
|
|
1386
|
+
this.total = total;
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
// force eta calculation update (long running processes)
|
|
1390
|
+
updateETA() {
|
|
1391
|
+
this.eta.update(Date.now(), this.value, this.total);
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1394
|
+
return genericBar;
|
|
1395
|
+
}
|
|
1396
|
+
var singleBar;
|
|
1397
|
+
var hasRequiredSingleBar;
|
|
1398
|
+
function requireSingleBar() {
|
|
1399
|
+
if (hasRequiredSingleBar) return singleBar;
|
|
1400
|
+
hasRequiredSingleBar = 1;
|
|
1401
|
+
const _GenericBar = requireGenericBar();
|
|
1402
|
+
const _options = requireOptions();
|
|
1403
|
+
singleBar = class SingleBar extends _GenericBar {
|
|
1404
|
+
constructor(options2, preset) {
|
|
1405
|
+
super(_options.parse(options2, preset));
|
|
1406
|
+
this.timer = null;
|
|
1407
|
+
if (this.options.noTTYOutput && this.terminal.isTTY() === false) {
|
|
1408
|
+
this.options.synchronousUpdate = false;
|
|
1409
|
+
}
|
|
1410
|
+
this.schedulingRate = this.terminal.isTTY() ? this.options.throttleTime : this.options.notTTYSchedule;
|
|
1411
|
+
this.sigintCallback = null;
|
|
1412
|
+
}
|
|
1413
|
+
// internal render function
|
|
1414
|
+
render() {
|
|
1415
|
+
if (this.timer) {
|
|
1416
|
+
clearTimeout(this.timer);
|
|
1417
|
+
this.timer = null;
|
|
1418
|
+
}
|
|
1419
|
+
super.render();
|
|
1420
|
+
if (this.options.noTTYOutput && this.terminal.isTTY() === false) {
|
|
1421
|
+
this.terminal.newline();
|
|
1422
|
+
}
|
|
1423
|
+
this.timer = setTimeout(this.render.bind(this), this.schedulingRate);
|
|
1424
|
+
}
|
|
1425
|
+
update(current, payload) {
|
|
1426
|
+
if (!this.timer) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
super.update(current, payload);
|
|
1430
|
+
if (this.options.synchronousUpdate && this.lastRedraw + this.options.throttleTime * 2 < Date.now()) {
|
|
1431
|
+
this.render();
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
// start the progress bar
|
|
1435
|
+
start(total, startValue, payload) {
|
|
1436
|
+
if (this.options.noTTYOutput === false && this.terminal.isTTY() === false) {
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
if (this.sigintCallback === null && this.options.gracefulExit) {
|
|
1440
|
+
this.sigintCallback = this.stop.bind(this);
|
|
1441
|
+
process.once("SIGINT", this.sigintCallback);
|
|
1442
|
+
process.once("SIGTERM", this.sigintCallback);
|
|
1443
|
+
}
|
|
1444
|
+
this.terminal.cursorSave();
|
|
1445
|
+
if (this.options.hideCursor === true) {
|
|
1446
|
+
this.terminal.cursor(false);
|
|
1447
|
+
}
|
|
1448
|
+
if (this.options.linewrap === false) {
|
|
1449
|
+
this.terminal.lineWrapping(false);
|
|
1450
|
+
}
|
|
1451
|
+
super.start(total, startValue, payload);
|
|
1452
|
+
this.render();
|
|
1453
|
+
}
|
|
1454
|
+
// stop the bar
|
|
1455
|
+
stop() {
|
|
1456
|
+
if (!this.timer) {
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
if (this.sigintCallback) {
|
|
1460
|
+
process.removeListener("SIGINT", this.sigintCallback);
|
|
1461
|
+
process.removeListener("SIGTERM", this.sigintCallback);
|
|
1462
|
+
this.sigintCallback = null;
|
|
1463
|
+
}
|
|
1464
|
+
this.render();
|
|
1465
|
+
super.stop();
|
|
1466
|
+
clearTimeout(this.timer);
|
|
1467
|
+
this.timer = null;
|
|
1468
|
+
if (this.options.hideCursor === true) {
|
|
1469
|
+
this.terminal.cursor(true);
|
|
1470
|
+
}
|
|
1471
|
+
if (this.options.linewrap === false) {
|
|
1472
|
+
this.terminal.lineWrapping(true);
|
|
1473
|
+
}
|
|
1474
|
+
this.terminal.cursorRestore();
|
|
1475
|
+
if (this.options.clearOnComplete) {
|
|
1476
|
+
this.terminal.cursorTo(0, null);
|
|
1477
|
+
this.terminal.clearLine();
|
|
1478
|
+
} else {
|
|
1479
|
+
this.terminal.newline();
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
return singleBar;
|
|
1484
|
+
}
|
|
1485
|
+
var multiBar;
|
|
1486
|
+
var hasRequiredMultiBar;
|
|
1487
|
+
function requireMultiBar() {
|
|
1488
|
+
if (hasRequiredMultiBar) return multiBar;
|
|
1489
|
+
hasRequiredMultiBar = 1;
|
|
1490
|
+
const _Terminal = requireTerminal();
|
|
1491
|
+
const _BarElement = requireGenericBar();
|
|
1492
|
+
const _options = requireOptions();
|
|
1493
|
+
const _EventEmitter = require$$4;
|
|
1494
|
+
multiBar = class MultiBar extends _EventEmitter {
|
|
1495
|
+
constructor(options2, preset) {
|
|
1496
|
+
super();
|
|
1497
|
+
this.bars = [];
|
|
1498
|
+
this.options = _options.parse(options2, preset);
|
|
1499
|
+
this.options.synchronousUpdate = false;
|
|
1500
|
+
this.terminal = this.options.terminal ? this.options.terminal : new _Terminal(this.options.stream);
|
|
1501
|
+
this.timer = null;
|
|
1502
|
+
this.isActive = false;
|
|
1503
|
+
this.schedulingRate = this.terminal.isTTY() ? this.options.throttleTime : this.options.notTTYSchedule;
|
|
1504
|
+
this.loggingBuffer = [];
|
|
1505
|
+
this.sigintCallback = null;
|
|
1506
|
+
}
|
|
1507
|
+
// add a new bar to the stack
|
|
1508
|
+
create(total, startValue, payload, barOptions = {}) {
|
|
1509
|
+
const bar = new _BarElement(Object.assign(
|
|
1510
|
+
{},
|
|
1511
|
+
// global options
|
|
1512
|
+
this.options,
|
|
1513
|
+
// terminal instance
|
|
1514
|
+
{
|
|
1515
|
+
terminal: this.terminal
|
|
1516
|
+
},
|
|
1517
|
+
// overrides
|
|
1518
|
+
barOptions
|
|
1519
|
+
));
|
|
1520
|
+
this.bars.push(bar);
|
|
1521
|
+
if (this.options.noTTYOutput === false && this.terminal.isTTY() === false) {
|
|
1522
|
+
return bar;
|
|
1523
|
+
}
|
|
1524
|
+
if (this.sigintCallback === null && this.options.gracefulExit) {
|
|
1525
|
+
this.sigintCallback = this.stop.bind(this);
|
|
1526
|
+
process.once("SIGINT", this.sigintCallback);
|
|
1527
|
+
process.once("SIGTERM", this.sigintCallback);
|
|
1528
|
+
}
|
|
1529
|
+
if (!this.isActive) {
|
|
1530
|
+
if (this.options.hideCursor === true) {
|
|
1531
|
+
this.terminal.cursor(false);
|
|
1532
|
+
}
|
|
1533
|
+
if (this.options.linewrap === false) {
|
|
1534
|
+
this.terminal.lineWrapping(false);
|
|
1535
|
+
}
|
|
1536
|
+
this.timer = setTimeout(this.update.bind(this), this.schedulingRate);
|
|
1537
|
+
}
|
|
1538
|
+
this.isActive = true;
|
|
1539
|
+
bar.start(total, startValue, payload);
|
|
1540
|
+
this.emit("start");
|
|
1541
|
+
return bar;
|
|
1542
|
+
}
|
|
1543
|
+
// remove a bar from the stack
|
|
1544
|
+
remove(bar) {
|
|
1545
|
+
const index = this.bars.indexOf(bar);
|
|
1546
|
+
if (index < 0) {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
this.bars.splice(index, 1);
|
|
1550
|
+
this.update();
|
|
1551
|
+
this.terminal.newline();
|
|
1552
|
+
this.terminal.clearBottom();
|
|
1553
|
+
return true;
|
|
1554
|
+
}
|
|
1555
|
+
// internal update routine
|
|
1556
|
+
update() {
|
|
1557
|
+
if (this.timer) {
|
|
1558
|
+
clearTimeout(this.timer);
|
|
1559
|
+
this.timer = null;
|
|
1560
|
+
}
|
|
1561
|
+
this.emit("update-pre");
|
|
1562
|
+
this.terminal.cursorRelativeReset();
|
|
1563
|
+
this.emit("redraw-pre");
|
|
1564
|
+
if (this.loggingBuffer.length > 0) {
|
|
1565
|
+
this.terminal.clearLine();
|
|
1566
|
+
while (this.loggingBuffer.length > 0) {
|
|
1567
|
+
this.terminal.write(this.loggingBuffer.shift(), true);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
for (let i = 0; i < this.bars.length; i++) {
|
|
1571
|
+
if (i > 0) {
|
|
1572
|
+
this.terminal.newline();
|
|
1573
|
+
}
|
|
1574
|
+
this.bars[i].render();
|
|
1575
|
+
}
|
|
1576
|
+
this.emit("redraw-post");
|
|
1577
|
+
if (this.options.noTTYOutput && this.terminal.isTTY() === false) {
|
|
1578
|
+
this.terminal.newline();
|
|
1579
|
+
this.terminal.newline();
|
|
1580
|
+
}
|
|
1581
|
+
this.timer = setTimeout(this.update.bind(this), this.schedulingRate);
|
|
1582
|
+
this.emit("update-post");
|
|
1583
|
+
if (this.options.stopOnComplete && !this.bars.find((bar) => bar.isActive)) {
|
|
1584
|
+
this.stop();
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
stop() {
|
|
1588
|
+
clearTimeout(this.timer);
|
|
1589
|
+
this.timer = null;
|
|
1590
|
+
if (this.sigintCallback) {
|
|
1591
|
+
process.removeListener("SIGINT", this.sigintCallback);
|
|
1592
|
+
process.removeListener("SIGTERM", this.sigintCallback);
|
|
1593
|
+
this.sigintCallback = null;
|
|
1594
|
+
}
|
|
1595
|
+
this.isActive = false;
|
|
1596
|
+
if (this.options.hideCursor === true) {
|
|
1597
|
+
this.terminal.cursor(true);
|
|
1598
|
+
}
|
|
1599
|
+
if (this.options.linewrap === false) {
|
|
1600
|
+
this.terminal.lineWrapping(true);
|
|
1601
|
+
}
|
|
1602
|
+
this.terminal.cursorRelativeReset();
|
|
1603
|
+
this.emit("stop-pre-clear");
|
|
1604
|
+
if (this.options.clearOnComplete) {
|
|
1605
|
+
this.terminal.clearBottom();
|
|
1606
|
+
} else {
|
|
1607
|
+
for (let i = 0; i < this.bars.length; i++) {
|
|
1608
|
+
if (i > 0) {
|
|
1609
|
+
this.terminal.newline();
|
|
1610
|
+
}
|
|
1611
|
+
this.bars[i].render();
|
|
1612
|
+
this.bars[i].stop();
|
|
1613
|
+
}
|
|
1614
|
+
this.terminal.newline();
|
|
1615
|
+
}
|
|
1616
|
+
this.emit("stop");
|
|
1617
|
+
}
|
|
1618
|
+
log(s) {
|
|
1619
|
+
this.loggingBuffer.push(s);
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
return multiBar;
|
|
1623
|
+
}
|
|
1624
|
+
var legacy;
|
|
1625
|
+
var hasRequiredLegacy;
|
|
1626
|
+
function requireLegacy() {
|
|
1627
|
+
if (hasRequiredLegacy) return legacy;
|
|
1628
|
+
hasRequiredLegacy = 1;
|
|
1629
|
+
legacy = {
|
|
1630
|
+
format: "progress [{bar}] {percentage}% | ETA: {eta}s | {value}/{total}",
|
|
1631
|
+
barCompleteChar: "=",
|
|
1632
|
+
barIncompleteChar: "-"
|
|
1633
|
+
};
|
|
1634
|
+
return legacy;
|
|
1635
|
+
}
|
|
1636
|
+
var shadesClassic;
|
|
1637
|
+
var hasRequiredShadesClassic;
|
|
1638
|
+
function requireShadesClassic() {
|
|
1639
|
+
if (hasRequiredShadesClassic) return shadesClassic;
|
|
1640
|
+
hasRequiredShadesClassic = 1;
|
|
1641
|
+
shadesClassic = {
|
|
1642
|
+
format: " {bar} {percentage}% | ETA: {eta}s | {value}/{total}",
|
|
1643
|
+
barCompleteChar: "█",
|
|
1644
|
+
barIncompleteChar: "░"
|
|
1645
|
+
};
|
|
1646
|
+
return shadesClassic;
|
|
1647
|
+
}
|
|
1648
|
+
var shadesGrey;
|
|
1649
|
+
var hasRequiredShadesGrey;
|
|
1650
|
+
function requireShadesGrey() {
|
|
1651
|
+
if (hasRequiredShadesGrey) return shadesGrey;
|
|
1652
|
+
hasRequiredShadesGrey = 1;
|
|
1653
|
+
shadesGrey = {
|
|
1654
|
+
format: " \x1B[90m{bar}\x1B[0m {percentage}% | ETA: {eta}s | {value}/{total}",
|
|
1655
|
+
barCompleteChar: "█",
|
|
1656
|
+
barIncompleteChar: "░"
|
|
1657
|
+
};
|
|
1658
|
+
return shadesGrey;
|
|
1659
|
+
}
|
|
1660
|
+
var rect;
|
|
1661
|
+
var hasRequiredRect;
|
|
1662
|
+
function requireRect() {
|
|
1663
|
+
if (hasRequiredRect) return rect;
|
|
1664
|
+
hasRequiredRect = 1;
|
|
1665
|
+
rect = {
|
|
1666
|
+
format: " {bar}■ {percentage}% | ETA: {eta}s | {value}/{total}",
|
|
1667
|
+
barCompleteChar: "■",
|
|
1668
|
+
barIncompleteChar: " "
|
|
1669
|
+
};
|
|
1670
|
+
return rect;
|
|
1671
|
+
}
|
|
1672
|
+
var presets;
|
|
1673
|
+
var hasRequiredPresets;
|
|
1674
|
+
function requirePresets() {
|
|
1675
|
+
if (hasRequiredPresets) return presets;
|
|
1676
|
+
hasRequiredPresets = 1;
|
|
1677
|
+
const _legacy = requireLegacy();
|
|
1678
|
+
const _shades_classic = requireShadesClassic();
|
|
1679
|
+
const _shades_grey = requireShadesGrey();
|
|
1680
|
+
const _rect = requireRect();
|
|
1681
|
+
presets = {
|
|
1682
|
+
legacy: _legacy,
|
|
1683
|
+
shades_classic: _shades_classic,
|
|
1684
|
+
shades_grey: _shades_grey,
|
|
1685
|
+
rect: _rect
|
|
1686
|
+
};
|
|
1687
|
+
return presets;
|
|
1688
|
+
}
|
|
1689
|
+
var cliProgress$1;
|
|
1690
|
+
var hasRequiredCliProgress;
|
|
1691
|
+
function requireCliProgress() {
|
|
1692
|
+
if (hasRequiredCliProgress) return cliProgress$1;
|
|
1693
|
+
hasRequiredCliProgress = 1;
|
|
1694
|
+
const _SingleBar = requireSingleBar();
|
|
1695
|
+
const _MultiBar = requireMultiBar();
|
|
1696
|
+
const _Presets = requirePresets();
|
|
1697
|
+
const _Formatter = requireFormatter();
|
|
1698
|
+
const _defaultFormatValue = requireFormatValue();
|
|
1699
|
+
const _defaultFormatBar = requireFormatBar();
|
|
1700
|
+
const _defaultFormatTime = requireFormatTime();
|
|
1701
|
+
cliProgress$1 = {
|
|
1702
|
+
Bar: _SingleBar,
|
|
1703
|
+
SingleBar: _SingleBar,
|
|
1704
|
+
MultiBar: _MultiBar,
|
|
1705
|
+
Presets: _Presets,
|
|
1706
|
+
Format: {
|
|
1707
|
+
Formatter: _Formatter,
|
|
1708
|
+
BarFormat: _defaultFormatBar,
|
|
1709
|
+
ValueFormat: _defaultFormatValue,
|
|
1710
|
+
TimeFormat: _defaultFormatTime
|
|
1711
|
+
}
|
|
1712
|
+
};
|
|
1713
|
+
return cliProgress$1;
|
|
1714
|
+
}
|
|
1715
|
+
var cliProgressExports = requireCliProgress();
|
|
1716
|
+
const cliProgress = /* @__PURE__ */ getDefaultExportFromCjs(cliProgressExports);
|
|
1717
|
+
const ANSI_BACKGROUND_OFFSET = 10;
|
|
1718
|
+
const wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
1719
|
+
const wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
1720
|
+
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
1721
|
+
const styles$1 = {
|
|
1722
|
+
modifier: {
|
|
1723
|
+
reset: [0, 0],
|
|
1724
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
1725
|
+
bold: [1, 22],
|
|
1726
|
+
dim: [2, 22],
|
|
1727
|
+
italic: [3, 23],
|
|
1728
|
+
underline: [4, 24],
|
|
1729
|
+
overline: [53, 55],
|
|
1730
|
+
inverse: [7, 27],
|
|
1731
|
+
hidden: [8, 28],
|
|
1732
|
+
strikethrough: [9, 29]
|
|
1733
|
+
},
|
|
1734
|
+
color: {
|
|
1735
|
+
black: [30, 39],
|
|
1736
|
+
red: [31, 39],
|
|
1737
|
+
green: [32, 39],
|
|
1738
|
+
yellow: [33, 39],
|
|
1739
|
+
blue: [34, 39],
|
|
1740
|
+
magenta: [35, 39],
|
|
1741
|
+
cyan: [36, 39],
|
|
1742
|
+
white: [37, 39],
|
|
1743
|
+
// Bright color
|
|
1744
|
+
blackBright: [90, 39],
|
|
1745
|
+
gray: [90, 39],
|
|
1746
|
+
// Alias of `blackBright`
|
|
1747
|
+
grey: [90, 39],
|
|
1748
|
+
// Alias of `blackBright`
|
|
1749
|
+
redBright: [91, 39],
|
|
1750
|
+
greenBright: [92, 39],
|
|
1751
|
+
yellowBright: [93, 39],
|
|
1752
|
+
blueBright: [94, 39],
|
|
1753
|
+
magentaBright: [95, 39],
|
|
1754
|
+
cyanBright: [96, 39],
|
|
1755
|
+
whiteBright: [97, 39]
|
|
1756
|
+
},
|
|
1757
|
+
bgColor: {
|
|
1758
|
+
bgBlack: [40, 49],
|
|
1759
|
+
bgRed: [41, 49],
|
|
1760
|
+
bgGreen: [42, 49],
|
|
1761
|
+
bgYellow: [43, 49],
|
|
1762
|
+
bgBlue: [44, 49],
|
|
1763
|
+
bgMagenta: [45, 49],
|
|
1764
|
+
bgCyan: [46, 49],
|
|
1765
|
+
bgWhite: [47, 49],
|
|
1766
|
+
// Bright color
|
|
1767
|
+
bgBlackBright: [100, 49],
|
|
1768
|
+
bgGray: [100, 49],
|
|
1769
|
+
// Alias of `bgBlackBright`
|
|
1770
|
+
bgGrey: [100, 49],
|
|
1771
|
+
// Alias of `bgBlackBright`
|
|
1772
|
+
bgRedBright: [101, 49],
|
|
1773
|
+
bgGreenBright: [102, 49],
|
|
1774
|
+
bgYellowBright: [103, 49],
|
|
1775
|
+
bgBlueBright: [104, 49],
|
|
1776
|
+
bgMagentaBright: [105, 49],
|
|
1777
|
+
bgCyanBright: [106, 49],
|
|
1778
|
+
bgWhiteBright: [107, 49]
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
Object.keys(styles$1.modifier);
|
|
1782
|
+
const foregroundColorNames = Object.keys(styles$1.color);
|
|
1783
|
+
const backgroundColorNames = Object.keys(styles$1.bgColor);
|
|
1784
|
+
[...foregroundColorNames, ...backgroundColorNames];
|
|
1785
|
+
function assembleStyles() {
|
|
1786
|
+
const codes = /* @__PURE__ */ new Map();
|
|
1787
|
+
for (const [groupName, group] of Object.entries(styles$1)) {
|
|
1788
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
1789
|
+
styles$1[styleName] = {
|
|
1790
|
+
open: `\x1B[${style[0]}m`,
|
|
1791
|
+
close: `\x1B[${style[1]}m`
|
|
1792
|
+
};
|
|
1793
|
+
group[styleName] = styles$1[styleName];
|
|
1794
|
+
codes.set(style[0], style[1]);
|
|
1795
|
+
}
|
|
1796
|
+
Object.defineProperty(styles$1, groupName, {
|
|
1797
|
+
value: group,
|
|
1798
|
+
enumerable: false
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
Object.defineProperty(styles$1, "codes", {
|
|
1802
|
+
value: codes,
|
|
1803
|
+
enumerable: false
|
|
1804
|
+
});
|
|
1805
|
+
styles$1.color.close = "\x1B[39m";
|
|
1806
|
+
styles$1.bgColor.close = "\x1B[49m";
|
|
1807
|
+
styles$1.color.ansi = wrapAnsi16();
|
|
1808
|
+
styles$1.color.ansi256 = wrapAnsi256();
|
|
1809
|
+
styles$1.color.ansi16m = wrapAnsi16m();
|
|
1810
|
+
styles$1.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
1811
|
+
styles$1.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
1812
|
+
styles$1.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
1813
|
+
Object.defineProperties(styles$1, {
|
|
1814
|
+
rgbToAnsi256: {
|
|
1815
|
+
value(red, green, blue) {
|
|
1816
|
+
if (red === green && green === blue) {
|
|
1817
|
+
if (red < 8) {
|
|
1818
|
+
return 16;
|
|
1819
|
+
}
|
|
1820
|
+
if (red > 248) {
|
|
1821
|
+
return 231;
|
|
1822
|
+
}
|
|
1823
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
1824
|
+
}
|
|
1825
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
1826
|
+
},
|
|
1827
|
+
enumerable: false
|
|
1828
|
+
},
|
|
1829
|
+
hexToRgb: {
|
|
1830
|
+
value(hex) {
|
|
1831
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
1832
|
+
if (!matches) {
|
|
1833
|
+
return [0, 0, 0];
|
|
1834
|
+
}
|
|
1835
|
+
let [colorString] = matches;
|
|
1836
|
+
if (colorString.length === 3) {
|
|
1837
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
1838
|
+
}
|
|
1839
|
+
const integer = Number.parseInt(colorString, 16);
|
|
1840
|
+
return [
|
|
1841
|
+
/* eslint-disable no-bitwise */
|
|
1842
|
+
integer >> 16 & 255,
|
|
1843
|
+
integer >> 8 & 255,
|
|
1844
|
+
integer & 255
|
|
1845
|
+
/* eslint-enable no-bitwise */
|
|
1846
|
+
];
|
|
1847
|
+
},
|
|
1848
|
+
enumerable: false
|
|
1849
|
+
},
|
|
1850
|
+
hexToAnsi256: {
|
|
1851
|
+
value: (hex) => styles$1.rgbToAnsi256(...styles$1.hexToRgb(hex)),
|
|
1852
|
+
enumerable: false
|
|
1853
|
+
},
|
|
1854
|
+
ansi256ToAnsi: {
|
|
1855
|
+
value(code) {
|
|
1856
|
+
if (code < 8) {
|
|
1857
|
+
return 30 + code;
|
|
1858
|
+
}
|
|
1859
|
+
if (code < 16) {
|
|
1860
|
+
return 90 + (code - 8);
|
|
1861
|
+
}
|
|
1862
|
+
let red;
|
|
1863
|
+
let green;
|
|
1864
|
+
let blue;
|
|
1865
|
+
if (code >= 232) {
|
|
1866
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
1867
|
+
green = red;
|
|
1868
|
+
blue = red;
|
|
1869
|
+
} else {
|
|
1870
|
+
code -= 16;
|
|
1871
|
+
const remainder = code % 36;
|
|
1872
|
+
red = Math.floor(code / 36) / 5;
|
|
1873
|
+
green = Math.floor(remainder / 6) / 5;
|
|
1874
|
+
blue = remainder % 6 / 5;
|
|
1875
|
+
}
|
|
1876
|
+
const value = Math.max(red, green, blue) * 2;
|
|
1877
|
+
if (value === 0) {
|
|
1878
|
+
return 30;
|
|
1879
|
+
}
|
|
1880
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
1881
|
+
if (value === 2) {
|
|
1882
|
+
result += 60;
|
|
1883
|
+
}
|
|
1884
|
+
return result;
|
|
1885
|
+
},
|
|
1886
|
+
enumerable: false
|
|
1887
|
+
},
|
|
1888
|
+
rgbToAnsi: {
|
|
1889
|
+
value: (red, green, blue) => styles$1.ansi256ToAnsi(styles$1.rgbToAnsi256(red, green, blue)),
|
|
1890
|
+
enumerable: false
|
|
1891
|
+
},
|
|
1892
|
+
hexToAnsi: {
|
|
1893
|
+
value: (hex) => styles$1.ansi256ToAnsi(styles$1.hexToAnsi256(hex)),
|
|
1894
|
+
enumerable: false
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
return styles$1;
|
|
1898
|
+
}
|
|
1899
|
+
const ansiStyles = assembleStyles();
|
|
1900
|
+
const level = (() => {
|
|
1901
|
+
if (!("navigator" in globalThis)) {
|
|
1902
|
+
return 0;
|
|
1903
|
+
}
|
|
1904
|
+
if (globalThis.navigator.userAgentData) {
|
|
1905
|
+
const brand = navigator.userAgentData.brands.find(({ brand: brand2 }) => brand2 === "Chromium");
|
|
1906
|
+
if (brand && brand.version > 93) {
|
|
1907
|
+
return 3;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
if (/\b(Chrome|Chromium)\//.test(globalThis.navigator.userAgent)) {
|
|
1911
|
+
return 1;
|
|
1912
|
+
}
|
|
1913
|
+
return 0;
|
|
1914
|
+
})();
|
|
1915
|
+
const colorSupport = level !== 0 && {
|
|
1916
|
+
level
|
|
1917
|
+
};
|
|
1918
|
+
const supportsColor = {
|
|
1919
|
+
stdout: colorSupport,
|
|
1920
|
+
stderr: colorSupport
|
|
1921
|
+
};
|
|
1922
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
1923
|
+
let index = string.indexOf(substring);
|
|
1924
|
+
if (index === -1) {
|
|
1925
|
+
return string;
|
|
1926
|
+
}
|
|
1927
|
+
const substringLength = substring.length;
|
|
1928
|
+
let endIndex = 0;
|
|
1929
|
+
let returnValue = "";
|
|
1930
|
+
do {
|
|
1931
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
1932
|
+
endIndex = index + substringLength;
|
|
1933
|
+
index = string.indexOf(substring, endIndex);
|
|
1934
|
+
} while (index !== -1);
|
|
1935
|
+
returnValue += string.slice(endIndex);
|
|
1936
|
+
return returnValue;
|
|
1937
|
+
}
|
|
1938
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
1939
|
+
let endIndex = 0;
|
|
1940
|
+
let returnValue = "";
|
|
1941
|
+
do {
|
|
1942
|
+
const gotCR = string[index - 1] === "\r";
|
|
1943
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
1944
|
+
endIndex = index + 1;
|
|
1945
|
+
index = string.indexOf("\n", endIndex);
|
|
1946
|
+
} while (index !== -1);
|
|
1947
|
+
returnValue += string.slice(endIndex);
|
|
1948
|
+
return returnValue;
|
|
1949
|
+
}
|
|
1950
|
+
const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
|
|
1951
|
+
const GENERATOR = Symbol("GENERATOR");
|
|
1952
|
+
const STYLER = Symbol("STYLER");
|
|
1953
|
+
const IS_EMPTY = Symbol("IS_EMPTY");
|
|
1954
|
+
const levelMapping = [
|
|
1955
|
+
"ansi",
|
|
1956
|
+
"ansi",
|
|
1957
|
+
"ansi256",
|
|
1958
|
+
"ansi16m"
|
|
1959
|
+
];
|
|
1960
|
+
const styles = /* @__PURE__ */ Object.create(null);
|
|
1961
|
+
const applyOptions = (object, options2 = {}) => {
|
|
1962
|
+
if (options2.level && !(Number.isInteger(options2.level) && options2.level >= 0 && options2.level <= 3)) {
|
|
1963
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
1964
|
+
}
|
|
1965
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
1966
|
+
object.level = options2.level === void 0 ? colorLevel : options2.level;
|
|
1967
|
+
};
|
|
1968
|
+
const chalkFactory = (options2) => {
|
|
1969
|
+
const chalk2 = (...strings) => strings.join(" ");
|
|
1970
|
+
applyOptions(chalk2, options2);
|
|
1971
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
1972
|
+
return chalk2;
|
|
1973
|
+
};
|
|
1974
|
+
function createChalk(options2) {
|
|
1975
|
+
return chalkFactory(options2);
|
|
1976
|
+
}
|
|
1977
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
1978
|
+
for (const [styleName, style] of Object.entries(ansiStyles)) {
|
|
1979
|
+
styles[styleName] = {
|
|
1980
|
+
get() {
|
|
1981
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
1982
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
1983
|
+
return builder;
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
styles.visible = {
|
|
1988
|
+
get() {
|
|
1989
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
1990
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
1991
|
+
return builder;
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
const getModelAnsi = (model, level2, type, ...arguments_) => {
|
|
1995
|
+
if (model === "rgb") {
|
|
1996
|
+
if (level2 === "ansi16m") {
|
|
1997
|
+
return ansiStyles[type].ansi16m(...arguments_);
|
|
1998
|
+
}
|
|
1999
|
+
if (level2 === "ansi256") {
|
|
2000
|
+
return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
|
|
2001
|
+
}
|
|
2002
|
+
return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
|
|
2003
|
+
}
|
|
2004
|
+
if (model === "hex") {
|
|
2005
|
+
return getModelAnsi("rgb", level2, type, ...ansiStyles.hexToRgb(...arguments_));
|
|
2006
|
+
}
|
|
2007
|
+
return ansiStyles[type][model](...arguments_);
|
|
2008
|
+
};
|
|
2009
|
+
const usedModels = ["rgb", "hex", "ansi256"];
|
|
2010
|
+
for (const model of usedModels) {
|
|
2011
|
+
styles[model] = {
|
|
2012
|
+
get() {
|
|
2013
|
+
const { level: level2 } = this;
|
|
2014
|
+
return function(...arguments_) {
|
|
2015
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level2], "color", ...arguments_), ansiStyles.color.close, this[STYLER]);
|
|
2016
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
2021
|
+
styles[bgModel] = {
|
|
2022
|
+
get() {
|
|
2023
|
+
const { level: level2 } = this;
|
|
2024
|
+
return function(...arguments_) {
|
|
2025
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level2], "bgColor", ...arguments_), ansiStyles.bgColor.close, this[STYLER]);
|
|
2026
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
2031
|
+
const proto = Object.defineProperties(() => {
|
|
2032
|
+
}, {
|
|
2033
|
+
...styles,
|
|
2034
|
+
level: {
|
|
2035
|
+
enumerable: true,
|
|
2036
|
+
get() {
|
|
2037
|
+
return this[GENERATOR].level;
|
|
2038
|
+
},
|
|
2039
|
+
set(level2) {
|
|
2040
|
+
this[GENERATOR].level = level2;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
const createStyler = (open, close, parent) => {
|
|
2045
|
+
let openAll;
|
|
2046
|
+
let closeAll;
|
|
2047
|
+
if (parent === void 0) {
|
|
2048
|
+
openAll = open;
|
|
2049
|
+
closeAll = close;
|
|
2050
|
+
} else {
|
|
2051
|
+
openAll = parent.openAll + open;
|
|
2052
|
+
closeAll = close + parent.closeAll;
|
|
2053
|
+
}
|
|
2054
|
+
return {
|
|
2055
|
+
open,
|
|
2056
|
+
close,
|
|
2057
|
+
openAll,
|
|
2058
|
+
closeAll,
|
|
2059
|
+
parent
|
|
2060
|
+
};
|
|
2061
|
+
};
|
|
2062
|
+
const createBuilder = (self, _styler, _isEmpty) => {
|
|
2063
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
2064
|
+
Object.setPrototypeOf(builder, proto);
|
|
2065
|
+
builder[GENERATOR] = self;
|
|
2066
|
+
builder[STYLER] = _styler;
|
|
2067
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
2068
|
+
return builder;
|
|
2069
|
+
};
|
|
2070
|
+
const applyStyle = (self, string) => {
|
|
2071
|
+
if (self.level <= 0 || !string) {
|
|
2072
|
+
return self[IS_EMPTY] ? "" : string;
|
|
2073
|
+
}
|
|
2074
|
+
let styler = self[STYLER];
|
|
2075
|
+
if (styler === void 0) {
|
|
2076
|
+
return string;
|
|
2077
|
+
}
|
|
2078
|
+
const { openAll, closeAll } = styler;
|
|
2079
|
+
if (string.includes("\x1B")) {
|
|
2080
|
+
while (styler !== void 0) {
|
|
2081
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
2082
|
+
styler = styler.parent;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
const lfIndex = string.indexOf("\n");
|
|
2086
|
+
if (lfIndex !== -1) {
|
|
2087
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
2088
|
+
}
|
|
2089
|
+
return openAll + string + closeAll;
|
|
2090
|
+
};
|
|
2091
|
+
Object.defineProperties(createChalk.prototype, styles);
|
|
2092
|
+
const chalk = createChalk();
|
|
2093
|
+
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
2094
|
+
dirname(import.meta.url);
|
|
2095
|
+
class ArgParser {
|
|
2096
|
+
constructor() {
|
|
2097
|
+
this.commands = {};
|
|
2098
|
+
this.options = {};
|
|
2099
|
+
this.examples = [];
|
|
2100
|
+
this.helpText = "";
|
|
2101
|
+
this.versionText = "1.0.0";
|
|
2102
|
+
}
|
|
2103
|
+
usage(text) {
|
|
2104
|
+
this.helpText = text;
|
|
2105
|
+
return this;
|
|
2106
|
+
}
|
|
2107
|
+
command(pattern, desc, handler) {
|
|
2108
|
+
const match = pattern.match(/\$0 <(\w+)>/);
|
|
2109
|
+
if (match) this.commands[match[1]] = { desc, handler, required: true };
|
|
2110
|
+
return this;
|
|
2111
|
+
}
|
|
2112
|
+
option(name, opts = {}) {
|
|
2113
|
+
this.options[name] = opts;
|
|
2114
|
+
return this;
|
|
2115
|
+
}
|
|
2116
|
+
example(cmd, desc) {
|
|
2117
|
+
this.examples.push({ cmd, desc });
|
|
2118
|
+
return this;
|
|
2119
|
+
}
|
|
2120
|
+
help() {
|
|
2121
|
+
return this;
|
|
2122
|
+
}
|
|
2123
|
+
alias(short, long) {
|
|
2124
|
+
if (this.options[long]) this.options[long].alias = short;
|
|
2125
|
+
return this;
|
|
2126
|
+
}
|
|
2127
|
+
version(v) {
|
|
2128
|
+
if (v) this.versionText = v;
|
|
2129
|
+
return this;
|
|
2130
|
+
}
|
|
2131
|
+
strict() {
|
|
2132
|
+
return this;
|
|
2133
|
+
}
|
|
2134
|
+
parseSync() {
|
|
2135
|
+
const args = process.argv.slice(2);
|
|
2136
|
+
const result = {};
|
|
2137
|
+
const positional = [];
|
|
2138
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
2139
|
+
this.showHelp();
|
|
2140
|
+
process.exit(0);
|
|
2141
|
+
}
|
|
2142
|
+
if (args.includes("--version")) {
|
|
2143
|
+
console.log(this.versionText);
|
|
2144
|
+
process.exit(0);
|
|
2145
|
+
}
|
|
2146
|
+
for (let i = 0; i < args.length; i++) {
|
|
2147
|
+
const arg = args[i];
|
|
2148
|
+
if (arg.startsWith("--")) {
|
|
2149
|
+
const [key, value] = arg.split("=");
|
|
2150
|
+
const optName = key.slice(2);
|
|
2151
|
+
if (value !== void 0) {
|
|
2152
|
+
result[optName] = this.coerceValue(optName, value);
|
|
2153
|
+
} else if (this.options[optName]?.type === "boolean") {
|
|
2154
|
+
result[optName] = true;
|
|
2155
|
+
} else {
|
|
2156
|
+
const nextArg = args[i + 1];
|
|
2157
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
2158
|
+
result[optName] = this.coerceValue(optName, nextArg);
|
|
2159
|
+
i++;
|
|
2160
|
+
} else {
|
|
2161
|
+
result[optName] = true;
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
} else if (arg.startsWith("-") && arg.length === 2) {
|
|
2165
|
+
const shortFlag = arg[1];
|
|
2166
|
+
const longName = this.findLongName(shortFlag);
|
|
2167
|
+
if (longName) {
|
|
2168
|
+
if (this.options[longName]?.type === "boolean") {
|
|
2169
|
+
result[longName] = true;
|
|
2170
|
+
} else {
|
|
2171
|
+
const nextArg = args[i + 1];
|
|
2172
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
2173
|
+
result[longName] = this.coerceValue(longName, nextArg);
|
|
2174
|
+
i++;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
} else {
|
|
2179
|
+
positional.push(arg);
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
if (positional.length > 0) result.urls = positional;
|
|
2183
|
+
Object.keys(this.options).forEach((key) => {
|
|
2184
|
+
if (result[key] === void 0 && this.options[key].default !== void 0) {
|
|
2185
|
+
result[key] = this.options[key].default;
|
|
2186
|
+
}
|
|
2187
|
+
});
|
|
2188
|
+
if ((!result.urls || result.urls.length === 0) && this.commands.url?.required) {
|
|
2189
|
+
console.error("Error: Missing required argument: url");
|
|
2190
|
+
this.showHelp();
|
|
2191
|
+
process.exit(1);
|
|
2192
|
+
}
|
|
2193
|
+
return result;
|
|
2194
|
+
}
|
|
2195
|
+
coerceValue(optName, value) {
|
|
2196
|
+
const opt = this.options[optName];
|
|
2197
|
+
if (!opt) return value;
|
|
2198
|
+
if (opt.coerce) return opt.coerce(value);
|
|
2199
|
+
switch (opt.type) {
|
|
2200
|
+
case "number":
|
|
2201
|
+
return Number(value);
|
|
2202
|
+
case "boolean":
|
|
2203
|
+
return value === "true" || value === "1";
|
|
2204
|
+
default:
|
|
2205
|
+
return value;
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
findLongName(shortFlag) {
|
|
2209
|
+
return Object.keys(this.options).find((key) => this.options[key].alias === shortFlag);
|
|
2210
|
+
}
|
|
2211
|
+
showHelp() {
|
|
2212
|
+
console.log(this.helpText || "Usage: grab <url> [options]");
|
|
2213
|
+
console.log("\nPositional arguments:");
|
|
2214
|
+
Object.keys(this.commands).forEach((cmd) => {
|
|
2215
|
+
console.log(` ${cmd.padEnd(20)} ${this.commands[cmd].desc}`);
|
|
2216
|
+
});
|
|
2217
|
+
console.log("\nOptions:");
|
|
2218
|
+
Object.keys(this.options).forEach((key) => {
|
|
2219
|
+
const opt = this.options[key];
|
|
2220
|
+
const flags = opt.alias ? `-${opt.alias}, --${key}` : `--${key}`;
|
|
2221
|
+
console.log(` ${flags.padEnd(20)} ${opt.describe || ""}`);
|
|
2222
|
+
});
|
|
2223
|
+
if (this.examples.length > 0) {
|
|
2224
|
+
console.log("\nExamples:");
|
|
2225
|
+
this.examples.forEach((ex) => {
|
|
2226
|
+
console.log(` ${ex.cmd}`);
|
|
2227
|
+
console.log(` ${ex.desc}`);
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
function isFileUrl(url) {
|
|
2233
|
+
return /\.[a-zA-Z0-9]{1,5}(?:\.[a-zA-Z0-9]{1,5})*$/.test(url.split("?")[0]);
|
|
2234
|
+
}
|
|
2235
|
+
class ColorFileDownloader {
|
|
2236
|
+
constructor() {
|
|
2237
|
+
this.progressBar = null;
|
|
2238
|
+
this.multiBar = null;
|
|
2239
|
+
this.loadingSpinner = null;
|
|
2240
|
+
this.abortController = null;
|
|
2241
|
+
this.COL_FILENAME = 25;
|
|
2242
|
+
this.COL_SPINNER = 2;
|
|
2243
|
+
this.COL_BAR = 15;
|
|
2244
|
+
this.COL_PERCENT = 4;
|
|
2245
|
+
this.COL_DOWNLOADED = 16;
|
|
2246
|
+
this.COL_TOTAL = 10;
|
|
2247
|
+
this.COL_SPEED = 10;
|
|
2248
|
+
this.COL_ETA = 10;
|
|
2249
|
+
this.colors = {
|
|
2250
|
+
primary: chalk.cyan,
|
|
2251
|
+
success: chalk.green,
|
|
2252
|
+
warning: chalk.yellow,
|
|
2253
|
+
error: chalk.red,
|
|
2254
|
+
info: chalk.blue,
|
|
2255
|
+
purple: chalk.magenta,
|
|
2256
|
+
pink: chalk.magentaBright,
|
|
2257
|
+
yellow: chalk.yellowBright,
|
|
2258
|
+
cyan: chalk.cyanBright,
|
|
2259
|
+
green: chalk.green,
|
|
2260
|
+
gradient: [
|
|
2261
|
+
chalk.blue,
|
|
2262
|
+
chalk.magenta,
|
|
2263
|
+
chalk.cyan,
|
|
2264
|
+
chalk.green,
|
|
2265
|
+
chalk.yellow,
|
|
2266
|
+
chalk.red
|
|
2267
|
+
]
|
|
2268
|
+
};
|
|
2269
|
+
this.barColors = [
|
|
2270
|
+
"\x1B[32m",
|
|
2271
|
+
// green
|
|
2272
|
+
"\x1B[33m",
|
|
2273
|
+
// yellow
|
|
2274
|
+
"\x1B[34m",
|
|
2275
|
+
// blue
|
|
2276
|
+
"\x1B[35m",
|
|
2277
|
+
// magenta
|
|
2278
|
+
"\x1B[36m",
|
|
2279
|
+
// cyan
|
|
2280
|
+
"\x1B[91m",
|
|
2281
|
+
// bright red
|
|
2282
|
+
"\x1B[92m",
|
|
2283
|
+
// bright green
|
|
2284
|
+
"\x1B[93m",
|
|
2285
|
+
// bright yellow
|
|
2286
|
+
"\x1B[94m",
|
|
2287
|
+
// bright blue
|
|
2288
|
+
"\x1B[95m",
|
|
2289
|
+
// bright magenta
|
|
2290
|
+
"\x1B[96m"
|
|
2291
|
+
// bright cyan
|
|
2292
|
+
];
|
|
2293
|
+
this.barGlueColors = [
|
|
2294
|
+
"\x1B[31m",
|
|
2295
|
+
// red
|
|
2296
|
+
"\x1B[33m",
|
|
2297
|
+
// yellow
|
|
2298
|
+
"\x1B[35m",
|
|
2299
|
+
// magenta
|
|
2300
|
+
"\x1B[37m",
|
|
2301
|
+
// white
|
|
2302
|
+
"\x1B[90m",
|
|
2303
|
+
// gray
|
|
2304
|
+
"\x1B[93m",
|
|
2305
|
+
// bright yellow
|
|
2306
|
+
"\x1B[97m"
|
|
2307
|
+
// bright white
|
|
2308
|
+
];
|
|
2309
|
+
this.spinnerTypes = Object.keys(spinners.default || spinners);
|
|
2310
|
+
this.stateDir = this.getStateDirectory();
|
|
2311
|
+
this.ensureStateDirectoryExists();
|
|
2312
|
+
this.isPaused = false;
|
|
2313
|
+
this.pauseCallback = null;
|
|
2314
|
+
this.resumeCallback = null;
|
|
2315
|
+
this.abortControllers = [];
|
|
2316
|
+
this.keyboardListener = null;
|
|
2317
|
+
this.isAddingUrl = false;
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Get state directory from environment variable or use default
|
|
2321
|
+
* @returns {string} State directory path
|
|
2322
|
+
*/
|
|
2323
|
+
getStateDirectory() {
|
|
2324
|
+
return process.env.GRAB_DOWNLOAD_STATE_DIR || path.join(process.cwd(), ".grab-downloads");
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Ensure state directory exists
|
|
2328
|
+
*/
|
|
2329
|
+
ensureStateDirectoryExists() {
|
|
2330
|
+
try {
|
|
2331
|
+
if (!fs.existsSync(this.stateDir)) {
|
|
2332
|
+
fs.mkdirSync(this.stateDir, { recursive: true });
|
|
2333
|
+
}
|
|
2334
|
+
} catch (error) {
|
|
2335
|
+
console.log(this.colors.warning("⚠️ Could not create state directory, using current directory"));
|
|
2336
|
+
this.stateDir = process.cwd();
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
/**
|
|
2340
|
+
* Get state file path for a given output path
|
|
2341
|
+
* @param {string} outputPath - The output file path
|
|
2342
|
+
* @returns {string} State file path
|
|
2343
|
+
*/
|
|
2344
|
+
getStateFilePath(outputPath) {
|
|
2345
|
+
const stateFileName = path.basename(outputPath) + ".download-state";
|
|
2346
|
+
return path.join(this.stateDir, stateFileName);
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Clean up state file
|
|
2350
|
+
* @param {string} stateFilePath - Path to state file
|
|
2351
|
+
*/
|
|
2352
|
+
cleanupStateFile(stateFilePath) {
|
|
2353
|
+
try {
|
|
2354
|
+
if (fs.existsSync(stateFilePath)) {
|
|
2355
|
+
fs.unlinkSync(stateFilePath);
|
|
2356
|
+
}
|
|
2357
|
+
} catch (error) {
|
|
2358
|
+
console.log(this.colors.warning("⚠️ Could not clean up state file"));
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Print aligned header row for progress bars
|
|
2363
|
+
*/
|
|
2364
|
+
printHeaderRow() {
|
|
2365
|
+
console.log(
|
|
2366
|
+
this.colors.success("📈 %".padEnd(this.COL_PERCENT)) + this.colors.yellow("📁 Files".padEnd(this.COL_FILENAME)) + this.colors.cyan("🔄".padEnd(this.COL_SPINNER)) + " " + this.colors.green("📊 Progress".padEnd(this.COL_BAR + 1)) + this.colors.info("📥 Downloaded".padEnd(this.COL_DOWNLOADED)) + this.colors.info("📦 Total".padEnd(this.COL_TOTAL)) + this.colors.purple("⚡ Speed".padEnd(this.COL_SPEED)) + this.colors.pink("⏱️ ETA".padEnd(this.COL_ETA))
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
/**
|
|
2370
|
+
* Get random ora spinner type (for ora spinners)
|
|
2371
|
+
* @returns {string} Random ora spinner name
|
|
2372
|
+
*/
|
|
2373
|
+
getRandomOraSpinner() {
|
|
2374
|
+
return this.spinnerTypes[Math.floor(Math.random() * this.spinnerTypes.length)];
|
|
2375
|
+
}
|
|
2376
|
+
/**
|
|
2377
|
+
* Get random bar color
|
|
2378
|
+
* @returns {string} ANSI color code
|
|
2379
|
+
*/
|
|
2380
|
+
getRandomBarColor() {
|
|
2381
|
+
return this.barColors[Math.floor(Math.random() * this.barColors.length)];
|
|
2382
|
+
}
|
|
2383
|
+
/**
|
|
2384
|
+
* Get random bar glue color
|
|
2385
|
+
* @returns {string} ANSI color code
|
|
2386
|
+
*/
|
|
2387
|
+
getRandomBarGlueColor() {
|
|
2388
|
+
return this.barGlueColors[Math.floor(Math.random() * this.barGlueColors.length)];
|
|
2389
|
+
}
|
|
2390
|
+
/**
|
|
2391
|
+
* Get random spinner type
|
|
2392
|
+
*/
|
|
2393
|
+
getRandomSpinner() {
|
|
2394
|
+
return this.spinnerTypes[Math.floor(Math.random() * this.spinnerTypes.length)];
|
|
2395
|
+
}
|
|
2396
|
+
/**
|
|
2397
|
+
* Get spinner frames for a given spinner type
|
|
2398
|
+
* @param {string} spinnerType - The spinner type name
|
|
2399
|
+
* @returns {array} Array of spinner frame characters
|
|
2400
|
+
*/
|
|
2401
|
+
getSpinnerFrames(spinnerType) {
|
|
2402
|
+
const spinnerData = spinners.default || spinners;
|
|
2403
|
+
const spinner = spinnerData[spinnerType];
|
|
2404
|
+
if (spinner && spinner.frames) {
|
|
2405
|
+
return spinner.frames;
|
|
2406
|
+
}
|
|
2407
|
+
return spinnerData.dots?.frames || ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
2408
|
+
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Get the visual width of a spinner frame (accounting for multi-char emojis)
|
|
2411
|
+
* @param {string} frame - The spinner frame
|
|
2412
|
+
* @returns {number} Visual width
|
|
2413
|
+
*/
|
|
2414
|
+
getSpinnerWidth(frame) {
|
|
2415
|
+
let width = 0;
|
|
2416
|
+
for (const char of frame) {
|
|
2417
|
+
const code = char.codePointAt(0);
|
|
2418
|
+
if (code >= 126976 && code <= 128767 || // Miscellaneous Symbols and Pictographs
|
|
2419
|
+
code >= 127744 && code <= 128511 || // Miscellaneous Symbols
|
|
2420
|
+
code >= 128512 && code <= 128591 || // Emoticons
|
|
2421
|
+
code >= 128640 && code <= 128767 || // Transport and Map
|
|
2422
|
+
code >= 128768 && code <= 128895 || // Alchemical Symbols
|
|
2423
|
+
code >= 128896 && code <= 129023 || // Geometric Shapes Extended
|
|
2424
|
+
code >= 129024 && code <= 129279 || // Supplemental Arrows-C
|
|
2425
|
+
code >= 9728 && code <= 9983 || // Miscellaneous Symbols
|
|
2426
|
+
code >= 9984 && code <= 10175) {
|
|
2427
|
+
width += 2;
|
|
2428
|
+
} else {
|
|
2429
|
+
width += 1;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
return width;
|
|
2433
|
+
}
|
|
2434
|
+
/**
|
|
2435
|
+
* Calculate dynamic bar size based on spinner width and terminal width
|
|
2436
|
+
* @param {string} spinnerFrame - Current spinner frame
|
|
2437
|
+
* @param {number} baseBarSize - Base bar size
|
|
2438
|
+
* @returns {number} Adjusted bar size
|
|
2439
|
+
*/
|
|
2440
|
+
calculateBarSize(spinnerFrame, baseBarSize = 20) {
|
|
2441
|
+
const terminalWidth = process.stdout.columns || 120;
|
|
2442
|
+
const spinnerWidth = this.getSpinnerWidth(spinnerFrame);
|
|
2443
|
+
const otherElementsWidth = 59;
|
|
2444
|
+
const filenameWidth = 20;
|
|
2445
|
+
const availableWidth = terminalWidth - otherElementsWidth - filenameWidth - spinnerWidth;
|
|
2446
|
+
const adjustedBarSize = Math.max(10, Math.min(baseBarSize, availableWidth));
|
|
2447
|
+
return adjustedBarSize;
|
|
2448
|
+
}
|
|
2449
|
+
/**
|
|
2450
|
+
* Check if server supports resumable downloads
|
|
2451
|
+
* @param {string} url - The URL to check
|
|
2452
|
+
* @returns {Object} - Server support info and headers
|
|
2453
|
+
*/
|
|
2454
|
+
async checkServerSupport(url) {
|
|
2455
|
+
try {
|
|
2456
|
+
const response = await fetch(url, {
|
|
2457
|
+
method: "HEAD",
|
|
2458
|
+
signal: this.abortController?.signal
|
|
2459
|
+
});
|
|
2460
|
+
if (!response.ok) {
|
|
2461
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
2462
|
+
}
|
|
2463
|
+
const acceptRanges = response.headers.get("accept-ranges");
|
|
2464
|
+
const contentLength = response.headers.get("content-length");
|
|
2465
|
+
const lastModified = response.headers.get("last-modified");
|
|
2466
|
+
const etag = response.headers.get("etag");
|
|
2467
|
+
return {
|
|
2468
|
+
supportsResume: acceptRanges === "bytes",
|
|
2469
|
+
totalSize: contentLength ? parseInt(contentLength, 10) : 0,
|
|
2470
|
+
lastModified,
|
|
2471
|
+
etag,
|
|
2472
|
+
headers: response.headers
|
|
2473
|
+
};
|
|
2474
|
+
} catch (error) {
|
|
2475
|
+
console.log(this.colors.warning("⚠️ Could not check server resume support, proceeding with regular download"));
|
|
2476
|
+
return {
|
|
2477
|
+
supportsResume: false,
|
|
2478
|
+
totalSize: 0,
|
|
2479
|
+
lastModified: null,
|
|
2480
|
+
etag: null,
|
|
2481
|
+
headers: null
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Load download state from file
|
|
2487
|
+
* @param {string} stateFilePath - Path to state file
|
|
2488
|
+
* @returns {Object} - Download state
|
|
2489
|
+
*/
|
|
2490
|
+
loadDownloadState(stateFilePath) {
|
|
2491
|
+
try {
|
|
2492
|
+
if (fs.existsSync(stateFilePath)) {
|
|
2493
|
+
const stateData = fs.readFileSync(stateFilePath, "utf8");
|
|
2494
|
+
return JSON.parse(stateData);
|
|
2495
|
+
}
|
|
2496
|
+
} catch (error) {
|
|
2497
|
+
console.log(this.colors.warning("⚠️ Could not load download state, starting fresh"));
|
|
2498
|
+
}
|
|
2499
|
+
return null;
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Save download state to file
|
|
2503
|
+
* @param {string} stateFilePath - Path to state file
|
|
2504
|
+
* @param {Object} state - Download state
|
|
2505
|
+
*/
|
|
2506
|
+
saveDownloadState(stateFilePath, state) {
|
|
2507
|
+
try {
|
|
2508
|
+
fs.writeFileSync(stateFilePath, JSON.stringify(state, null, 2));
|
|
2509
|
+
} catch (error) {
|
|
2510
|
+
console.log(this.colors.warning("⚠️ Could not save download state"));
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
/**
|
|
2514
|
+
* Get partial file size
|
|
2515
|
+
* @param {string} filePath - Path to partial file
|
|
2516
|
+
* @returns {number} - Size of partial file
|
|
2517
|
+
*/
|
|
2518
|
+
getPartialFileSize(filePath) {
|
|
2519
|
+
try {
|
|
2520
|
+
if (fs.existsSync(filePath)) {
|
|
2521
|
+
const stats = fs.statSync(filePath);
|
|
2522
|
+
return stats.size;
|
|
2523
|
+
}
|
|
2524
|
+
} catch (error) {
|
|
2525
|
+
console.log(this.colors.warning("⚠️ Could not read partial file size"));
|
|
2526
|
+
}
|
|
2527
|
+
return 0;
|
|
2528
|
+
}
|
|
2529
|
+
/**
|
|
2530
|
+
* Get random gradient color
|
|
2531
|
+
*/
|
|
2532
|
+
getRandomColor() {
|
|
2533
|
+
return this.colors.gradient[Math.floor(Math.random() * this.colors.gradient.length)];
|
|
2534
|
+
}
|
|
2535
|
+
/**
|
|
2536
|
+
* Format bytes into human readable format with proper MB/GB units using 1024 base
|
|
2537
|
+
* @param {number} bytes - Number of bytes
|
|
2538
|
+
* @param {number} decimals - Number of decimal places
|
|
2539
|
+
* @returns {string} Formatted string
|
|
2540
|
+
*/
|
|
2541
|
+
formatBytes(bytes, decimals = 2) {
|
|
2542
|
+
if (bytes === 0) return this.colors.info("0 B");
|
|
2543
|
+
const k = 1024;
|
|
2544
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
2545
|
+
const sizes = [
|
|
2546
|
+
{ unit: "B", color: this.colors.info },
|
|
2547
|
+
{ unit: "KB", color: this.colors.cyan },
|
|
2548
|
+
{ unit: "MB", color: this.colors.yellow },
|
|
2549
|
+
{ unit: "GB", color: this.colors.purple },
|
|
2550
|
+
{ unit: "TB", color: this.colors.pink },
|
|
2551
|
+
{ unit: "PB", color: this.colors.primary }
|
|
2552
|
+
];
|
|
2553
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
2554
|
+
const value = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
|
|
2555
|
+
const size = sizes[i] || sizes[sizes.length - 1];
|
|
2556
|
+
return size.color.bold(`${value} ${size.unit}`);
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* Format bytes for progress display (without colors for progress bar)
|
|
2560
|
+
* @param {number} bytes - Number of bytes
|
|
2561
|
+
* @param {number} decimals - Number of decimal places
|
|
2562
|
+
* @returns {string} Formatted string without colors
|
|
2563
|
+
*/
|
|
2564
|
+
formatBytesPlain(bytes, decimals = 1) {
|
|
2565
|
+
if (bytes === 0) return "0 B";
|
|
2566
|
+
const k = 1024;
|
|
2567
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
2568
|
+
const sizes = ["B", "KB", "MB", "GB", "TB", "PB"];
|
|
2569
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
2570
|
+
const value = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
|
|
2571
|
+
return `${value} ${sizes[i] || sizes[sizes.length - 1]}`;
|
|
2572
|
+
}
|
|
2573
|
+
/**
|
|
2574
|
+
* Format bytes for progress display (compact version for tight layouts)
|
|
2575
|
+
* @param {number} bytes - Number of bytes
|
|
2576
|
+
* @returns {string} Formatted string in compact format
|
|
2577
|
+
*/
|
|
2578
|
+
formatBytesCompact(bytes) {
|
|
2579
|
+
if (bytes === 0) return "0B";
|
|
2580
|
+
const k = 1024;
|
|
2581
|
+
const kb = bytes / k;
|
|
2582
|
+
if (kb < 100) {
|
|
2583
|
+
const value2 = Math.round(kb);
|
|
2584
|
+
return `${value2}KB`;
|
|
2585
|
+
}
|
|
2586
|
+
const mb = bytes / (k * k);
|
|
2587
|
+
const value = mb.toFixed(1);
|
|
2588
|
+
return `${value}`;
|
|
2589
|
+
}
|
|
2590
|
+
/**
|
|
2591
|
+
* Truncate filename for display
|
|
2592
|
+
* @param {string} filename - Original filename
|
|
2593
|
+
* @param {number} maxLength - Maximum length
|
|
2594
|
+
* @returns {string} Truncated filename
|
|
2595
|
+
*/
|
|
2596
|
+
truncateFilename(filename, maxLength = 25) {
|
|
2597
|
+
if (filename.length <= maxLength) return filename.padEnd(maxLength);
|
|
2598
|
+
const extension = path.extname(filename);
|
|
2599
|
+
const baseName = path.basename(filename, extension);
|
|
2600
|
+
if (baseName.length <= 3) {
|
|
2601
|
+
return filename.padEnd(maxLength);
|
|
2602
|
+
}
|
|
2603
|
+
const firstPart = Math.ceil((maxLength - extension.length - 3) / 2);
|
|
2604
|
+
const lastPart = Math.floor((maxLength - extension.length - 3) / 2);
|
|
2605
|
+
const truncatedBase = baseName.substring(0, firstPart) + "..." + baseName.substring(baseName.length - lastPart);
|
|
2606
|
+
return `${truncatedBase}${extension}`.padEnd(maxLength);
|
|
2607
|
+
}
|
|
2608
|
+
/**
|
|
2609
|
+
* Format ETA time in hours:minutes:seconds format
|
|
2610
|
+
* @param {number} seconds - ETA in seconds
|
|
2611
|
+
* @returns {string} Formatted ETA string (padded to consistent width)
|
|
2612
|
+
*/
|
|
2613
|
+
formatETA(seconds) {
|
|
2614
|
+
if (!seconds || seconds === Infinity || seconds < 0) return " -- ";
|
|
2615
|
+
const hours = Math.floor(seconds / 3600);
|
|
2616
|
+
const mins = Math.floor(seconds % 3600 / 60);
|
|
2617
|
+
const secs = Math.round(seconds % 60);
|
|
2618
|
+
return `${hours}:${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`.padEnd(this.COL_ETA);
|
|
2619
|
+
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Format progress for master bar showing sum of all downloads
|
|
2622
|
+
* @param {number} totalDownloaded - Total downloaded bytes across all files
|
|
2623
|
+
* @param {number} totalSize - Total size bytes across all files
|
|
2624
|
+
* @returns {string} Formatted progress string showing sums in MB
|
|
2625
|
+
*/
|
|
2626
|
+
formatMasterProgress(totalDownloaded, totalSize) {
|
|
2627
|
+
const k = 1024;
|
|
2628
|
+
const totalDownloadedMB = totalDownloaded / (k * k);
|
|
2629
|
+
const totalSizeMB = totalSize / (k * k);
|
|
2630
|
+
if (totalSizeMB >= 1024) {
|
|
2631
|
+
const totalDownloadedGB = totalDownloadedMB / 1024;
|
|
2632
|
+
return `${totalDownloadedGB.toFixed(1)}GB`.padEnd(this.COL_DOWNLOADED);
|
|
2633
|
+
}
|
|
2634
|
+
return `${totalDownloadedMB.toFixed(1)}MB`.padEnd(this.COL_DOWNLOADED);
|
|
2635
|
+
}
|
|
2636
|
+
/**
|
|
2637
|
+
* Format progress display with consistent width
|
|
2638
|
+
* @param {number} downloaded - Downloaded bytes
|
|
2639
|
+
* @param {number} total - Total bytes
|
|
2640
|
+
* @returns {string} Formatted progress string
|
|
2641
|
+
*/
|
|
2642
|
+
formatProgress(downloaded, total) {
|
|
2643
|
+
const downloadedStr = this.formatBytesCompact(downloaded);
|
|
2644
|
+
return downloadedStr.padEnd(this.COL_DOWNLOADED);
|
|
2645
|
+
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Format downloaded bytes for display
|
|
2648
|
+
* @param {number} downloaded - Downloaded bytes
|
|
2649
|
+
* @returns {string} Formatted downloaded string
|
|
2650
|
+
*/
|
|
2651
|
+
formatDownloaded(downloaded) {
|
|
2652
|
+
return this.formatBytesCompact(downloaded).padEnd(this.COL_DOWNLOADED);
|
|
2653
|
+
}
|
|
2654
|
+
/**
|
|
2655
|
+
* Format total bytes for display (separate column)
|
|
2656
|
+
* @param {number} total - Total bytes
|
|
2657
|
+
* @returns {string} Formatted total string
|
|
2658
|
+
*/
|
|
2659
|
+
formatTotalDisplay(total) {
|
|
2660
|
+
if (total === 0) return "0MB".padEnd(this.COL_TOTAL);
|
|
2661
|
+
const k = 1024;
|
|
2662
|
+
const mb = total / (k * k);
|
|
2663
|
+
if (mb >= 1024) {
|
|
2664
|
+
const gb = mb / 1024;
|
|
2665
|
+
return `${gb.toFixed(1)}GB`.padEnd(this.COL_TOTAL);
|
|
2666
|
+
}
|
|
2667
|
+
if (mb < 1) {
|
|
2668
|
+
return `${mb.toFixed(2)}MB`.padEnd(this.COL_TOTAL);
|
|
2669
|
+
}
|
|
2670
|
+
return `${mb.toFixed(1)}MB`.padEnd(this.COL_TOTAL);
|
|
2671
|
+
}
|
|
2672
|
+
/**
|
|
2673
|
+
* Format total bytes for display (MB/GB format)
|
|
2674
|
+
* @param {number} total - Total bytes
|
|
2675
|
+
* @returns {string} Formatted total string
|
|
2676
|
+
*/
|
|
2677
|
+
formatTotal(total) {
|
|
2678
|
+
if (total === 0) return "0MB".padEnd(this.COL_TOTAL);
|
|
2679
|
+
const k = 1024;
|
|
2680
|
+
const mb = total / (k * k);
|
|
2681
|
+
if (mb >= 1024) {
|
|
2682
|
+
const gb = mb / 1024;
|
|
2683
|
+
return `${gb.toFixed(1)}GB`.padEnd(this.COL_TOTAL);
|
|
2684
|
+
}
|
|
2685
|
+
if (mb < 1) {
|
|
2686
|
+
return `${mb.toFixed(2)}MB`.padEnd(this.COL_TOTAL);
|
|
2687
|
+
}
|
|
2688
|
+
return `${mb.toFixed(1)}MB`.padEnd(this.COL_TOTAL);
|
|
2689
|
+
}
|
|
2690
|
+
/**
|
|
2691
|
+
* Format speed display with consistent width
|
|
2692
|
+
* @param {string} speed - Speed string
|
|
2693
|
+
* @returns {string} Formatted speed string
|
|
2694
|
+
*/
|
|
2695
|
+
formatSpeed(speed) {
|
|
2696
|
+
return speed.padEnd(this.COL_SPEED);
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Format speed for display (MB/s without "MB" text unless below 100KB/s)
|
|
2700
|
+
* @param {number} bytesPerSecond - Speed in bytes per second
|
|
2701
|
+
* @returns {string} Formatted speed string
|
|
2702
|
+
*/
|
|
2703
|
+
formatSpeedDisplay(bytesPerSecond) {
|
|
2704
|
+
if (bytesPerSecond === 0) return "0B";
|
|
2705
|
+
const k = 1024;
|
|
2706
|
+
const kbPerSecond = bytesPerSecond / k;
|
|
2707
|
+
if (kbPerSecond < 100) {
|
|
2708
|
+
const formattedValue2 = Math.round(kbPerSecond);
|
|
2709
|
+
return `${formattedValue2}KB`;
|
|
2710
|
+
}
|
|
2711
|
+
const mbPerSecond = bytesPerSecond / (k * k);
|
|
2712
|
+
const formattedValue = mbPerSecond.toFixed(1);
|
|
2713
|
+
return `${formattedValue}`;
|
|
2714
|
+
}
|
|
2715
|
+
/**
|
|
2716
|
+
* Format speed for total display (MB/s without "MB" text unless below 100KB/s)
|
|
2717
|
+
* @param {number} bytesPerSecond - Speed in bytes per second
|
|
2718
|
+
* @returns {string} Formatted speed string
|
|
2719
|
+
*/
|
|
2720
|
+
formatTotalSpeed(bytesPerSecond) {
|
|
2721
|
+
return this.formatSpeedDisplay(bytesPerSecond).padEnd(this.COL_SPEED);
|
|
2722
|
+
}
|
|
2723
|
+
/**
|
|
2724
|
+
* Download multiple files with multibar progress tracking
|
|
2725
|
+
* @param {Array} downloads - Array of {url, outputPath, filename} objects
|
|
2726
|
+
*/
|
|
2727
|
+
async downloadMultipleFiles(downloads) {
|
|
2728
|
+
try {
|
|
2729
|
+
this.setupGlobalKeyboardListener();
|
|
2730
|
+
const masterBarColor = this.getRandomBarColor();
|
|
2731
|
+
const masterBarGlue = this.getRandomBarGlueColor();
|
|
2732
|
+
this.multiBar = new cliProgress.MultiBar({
|
|
2733
|
+
format: this.colors.success("{percentage}%") + " " + this.colors.yellow("{filename}") + " " + this.colors.cyan("{spinner}") + " " + masterBarColor + "{bar}\x1B[0m " + this.colors.info("{downloadedDisplay}") + " " + this.colors.info("{totalDisplay}") + " " + this.colors.purple("{speed}") + " " + this.colors.pink("{etaFormatted}"),
|
|
2734
|
+
hideCursor: true,
|
|
2735
|
+
clearOnComplete: false,
|
|
2736
|
+
stopOnComplete: true,
|
|
2737
|
+
autopadding: false,
|
|
2738
|
+
barCompleteChar: "█",
|
|
2739
|
+
barIncompleteChar: "░",
|
|
2740
|
+
barGlue: masterBarGlue,
|
|
2741
|
+
barsize: this.COL_BAR
|
|
2742
|
+
});
|
|
2743
|
+
let totalDownloaded = 0;
|
|
2744
|
+
let totalSize = 0;
|
|
2745
|
+
let individualSpeeds = new Array(downloads.length).fill(0);
|
|
2746
|
+
let individualSizes = new Array(downloads.length).fill(0);
|
|
2747
|
+
let individualDownloaded = new Array(downloads.length).fill(0);
|
|
2748
|
+
let individualStartTimes = new Array(downloads.length).fill(Date.now());
|
|
2749
|
+
let lastSpeedUpdate = Date.now();
|
|
2750
|
+
let lastIndividualDownloaded = new Array(downloads.length).fill(0);
|
|
2751
|
+
let lastTotalUpdate = Date.now();
|
|
2752
|
+
let lastTotalDownloaded = 0;
|
|
2753
|
+
const totalSizeFromDownloads = downloads.reduce((sum, download) => {
|
|
2754
|
+
const estimatedSize = download.estimatedSize || 1024 * 1024 * 100;
|
|
2755
|
+
return sum + estimatedSize;
|
|
2756
|
+
}, 0);
|
|
2757
|
+
totalSize = totalSizeFromDownloads;
|
|
2758
|
+
let actualTotalSize = 0;
|
|
2759
|
+
const speedUpdateInterval = setInterval(() => {
|
|
2760
|
+
const now = Date.now();
|
|
2761
|
+
const timeSinceLastUpdate = (now - lastSpeedUpdate) / 1e3;
|
|
2762
|
+
for (let i = 0; i < downloads.length; i++) {
|
|
2763
|
+
if (timeSinceLastUpdate > 0) {
|
|
2764
|
+
const incrementalDownloaded = individualDownloaded[i] - lastIndividualDownloaded[i];
|
|
2765
|
+
individualSpeeds[i] = incrementalDownloaded / timeSinceLastUpdate;
|
|
2766
|
+
if (fileBars[i] && fileBars[i].bar) {
|
|
2767
|
+
const speed = this.formatSpeed(this.formatSpeedDisplay(individualSpeeds[i]));
|
|
2768
|
+
const eta2 = individualSizes[i] > 0 ? this.formatETA((individualSizes[i] - individualDownloaded[i]) / individualSpeeds[i]) : this.formatETA(0);
|
|
2769
|
+
fileBars[i].bar.update(individualDownloaded[i], {
|
|
2770
|
+
speed,
|
|
2771
|
+
progress: this.formatProgress(individualDownloaded[i], individualSizes[i]),
|
|
2772
|
+
downloadedDisplay: this.formatBytesCompact(individualDownloaded[i]),
|
|
2773
|
+
totalDisplay: this.formatTotalDisplay(individualSizes[i]),
|
|
2774
|
+
etaFormatted: eta2
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
lastSpeedUpdate = now;
|
|
2780
|
+
lastIndividualDownloaded = [...individualDownloaded];
|
|
2781
|
+
const totalSpeedBps = individualSpeeds.reduce((sum, speed) => sum + speed, 0);
|
|
2782
|
+
const totalDownloadedFromFiles = individualDownloaded.reduce((sum, downloaded) => sum + downloaded, 0);
|
|
2783
|
+
const timeElapsed = (now - individualStartTimes[0]) / 1e3;
|
|
2784
|
+
const totalEta = totalSize > 0 && totalSpeedBps > 0 ? this.formatETA((totalSize - totalDownloadedFromFiles) / totalSpeedBps) : this.formatETA(0);
|
|
2785
|
+
const totalPercentage = totalSize > 0 ? Math.round(totalDownloadedFromFiles / totalSize * 100) : 0;
|
|
2786
|
+
const discoveredTotalSize = individualSizes.reduce((sum, size) => sum + size, 0);
|
|
2787
|
+
const displayTotalSize = discoveredTotalSize > 0 ? discoveredTotalSize : totalSize;
|
|
2788
|
+
masterBar.update(totalDownloadedFromFiles, {
|
|
2789
|
+
speed: this.formatTotalSpeed(totalSpeedBps),
|
|
2790
|
+
progress: this.formatMasterProgress(totalDownloadedFromFiles, displayTotalSize),
|
|
2791
|
+
downloadedDisplay: this.formatBytesCompact(totalDownloadedFromFiles),
|
|
2792
|
+
totalDisplay: this.formatTotalDisplay(displayTotalSize),
|
|
2793
|
+
etaFormatted: this.formatETA(timeElapsed),
|
|
2794
|
+
// Show time elapsed instead of ETA
|
|
2795
|
+
percentage: displayTotalSize > 0 ? Math.round(totalDownloadedFromFiles / displayTotalSize * 100) : 0
|
|
2796
|
+
});
|
|
2797
|
+
}, 1e3);
|
|
2798
|
+
const masterSpinnerWidth = this.getSpinnerWidth("⬇️");
|
|
2799
|
+
const masterMaxFilenameLength = this.COL_FILENAME - masterSpinnerWidth;
|
|
2800
|
+
const masterBarSize = this.calculateBarSize("⬇️", this.COL_BAR);
|
|
2801
|
+
const masterBar = this.multiBar.create(totalSize, 0, {
|
|
2802
|
+
filename: "Total".padEnd(masterMaxFilenameLength),
|
|
2803
|
+
spinner: "⬇️",
|
|
2804
|
+
speed: "0B".padEnd(this.COL_SPEED),
|
|
2805
|
+
progress: this.formatMasterProgress(0, totalSize),
|
|
2806
|
+
downloadedDisplay: this.formatBytesCompact(0),
|
|
2807
|
+
totalDisplay: this.formatTotalDisplay(totalSize),
|
|
2808
|
+
etaFormatted: this.formatETA(0),
|
|
2809
|
+
percentage: " 0".padStart(this.COL_PERCENT - 1)
|
|
2810
|
+
}, {
|
|
2811
|
+
format: this.colors.success("{percentage}%") + " " + this.colors.yellow.bold("{filename}") + " " + this.colors.success("{spinner}") + " \x1B[92m{bar}\x1B[0m " + this.colors.info("{downloadedDisplay}") + " " + this.colors.info("{totalDisplay}") + " " + this.colors.purple("{speed}") + " " + this.colors.pink("{etaFormatted}"),
|
|
2812
|
+
barCompleteChar: "▶",
|
|
2813
|
+
barIncompleteChar: "▷",
|
|
2814
|
+
barGlue: "\x1B[33m",
|
|
2815
|
+
barsize: masterBarSize
|
|
2816
|
+
});
|
|
2817
|
+
const fileBars = downloads.map((download, index) => {
|
|
2818
|
+
const spinnerType = this.getRandomSpinner();
|
|
2819
|
+
const spinnerFrames = this.getSpinnerFrames(spinnerType);
|
|
2820
|
+
const spinnerWidth = this.getSpinnerWidth(spinnerFrames[0]);
|
|
2821
|
+
const maxFilenameLength = this.COL_FILENAME - spinnerWidth;
|
|
2822
|
+
const truncatedName = this.truncateFilename(download.filename, maxFilenameLength);
|
|
2823
|
+
const fileBarColor = this.getRandomBarColor();
|
|
2824
|
+
const fileBarGlue = this.getRandomBarGlueColor();
|
|
2825
|
+
const barSize = this.calculateBarSize(spinnerFrames[0], this.COL_BAR);
|
|
2826
|
+
return {
|
|
2827
|
+
bar: this.multiBar.create(100, 0, {
|
|
2828
|
+
filename: truncatedName,
|
|
2829
|
+
spinner: spinnerFrames[0],
|
|
2830
|
+
speed: this.formatSpeed("0B"),
|
|
2831
|
+
progress: this.formatProgress(0, 0),
|
|
2832
|
+
downloadedDisplay: this.formatBytesCompact(0),
|
|
2833
|
+
totalDisplay: this.formatTotalDisplay(0),
|
|
2834
|
+
etaFormatted: this.formatETA(0),
|
|
2835
|
+
percentage: " 0".padStart(3)
|
|
2836
|
+
}, {
|
|
2837
|
+
format: this.colors.yellow("{filename}") + " " + this.colors.cyan("{spinner}") + " " + fileBarColor + "{bar}\x1B[0m " + this.colors.success("{percentage}%") + " " + this.colors.info("{downloadedDisplay}") + " " + this.colors.info("{totalDisplay}") + " " + this.colors.purple("{speed}") + " " + this.colors.pink("{etaFormatted}"),
|
|
2838
|
+
barCompleteChar: "█",
|
|
2839
|
+
barIncompleteChar: "░",
|
|
2840
|
+
barGlue: fileBarGlue,
|
|
2841
|
+
barsize: barSize
|
|
2842
|
+
}),
|
|
2843
|
+
spinnerFrames,
|
|
2844
|
+
spinnerIndex: 0,
|
|
2845
|
+
lastSpinnerUpdate: Date.now(),
|
|
2846
|
+
lastFrameUpdate: Date.now(),
|
|
2847
|
+
download: { ...download, index }
|
|
2848
|
+
};
|
|
2849
|
+
});
|
|
2850
|
+
const downloadPromises = fileBars.map(async (fileBar, index) => {
|
|
2851
|
+
try {
|
|
2852
|
+
await this.downloadSingleFileWithBar(fileBar, masterBar, downloads.length, {
|
|
2853
|
+
totalDownloaded,
|
|
2854
|
+
totalSize,
|
|
2855
|
+
individualSpeeds,
|
|
2856
|
+
individualSizes,
|
|
2857
|
+
individualDownloaded,
|
|
2858
|
+
individualStartTimes,
|
|
2859
|
+
lastTotalUpdate,
|
|
2860
|
+
lastTotalDownloaded,
|
|
2861
|
+
actualTotalSize
|
|
2862
|
+
});
|
|
2863
|
+
return { success: true, index, filename: fileBar.download.filename };
|
|
2864
|
+
} catch (error) {
|
|
2865
|
+
return { success: false, index, filename: fileBar.download.filename, error };
|
|
2866
|
+
}
|
|
2867
|
+
});
|
|
2868
|
+
const results = await Promise.allSettled(downloadPromises);
|
|
2869
|
+
clearInterval(speedUpdateInterval);
|
|
2870
|
+
this.multiBar.stop();
|
|
2871
|
+
const successful = results.filter((r) => r.status === "fulfilled" && r.value.success).length;
|
|
2872
|
+
const failed = results.length - successful;
|
|
2873
|
+
if (failed > 0) {
|
|
2874
|
+
console.log(this.colors.error(`❌ Failed: ${failed}/${downloads.length}`));
|
|
2875
|
+
results.forEach((result, index) => {
|
|
2876
|
+
if (result.status === "rejected" || !result.value.success) {
|
|
2877
|
+
const filename = downloads[index].filename;
|
|
2878
|
+
const error = result.reason || result.value?.error || "Unknown error";
|
|
2879
|
+
console.log(this.colors.error(` • ${filename}: ${error.message || error}`));
|
|
2880
|
+
}
|
|
2881
|
+
});
|
|
2882
|
+
}
|
|
2883
|
+
const celebrationEmojis = ["🥳", "🎊", "🎈", "🌟", "💯", "🚀", "✨", "🔥"];
|
|
2884
|
+
const randomEmoji = celebrationEmojis[Math.floor(Math.random() * celebrationEmojis.length)];
|
|
2885
|
+
console.log(this.colors.green(`${randomEmoji} Success: ${successful}/${downloads.length}`));
|
|
2886
|
+
this.clearAbortControllers();
|
|
2887
|
+
let pausedMessageShown = false;
|
|
2888
|
+
this.setPauseCallback(() => {
|
|
2889
|
+
if (!pausedMessageShown) {
|
|
2890
|
+
this.multiBar.stop();
|
|
2891
|
+
console.log(this.colors.warning("⏸️ Paused. Press p to resume, a to add URL."));
|
|
2892
|
+
pausedMessageShown = true;
|
|
2893
|
+
}
|
|
2894
|
+
});
|
|
2895
|
+
this.setResumeCallback(() => {
|
|
2896
|
+
if (pausedMessageShown) {
|
|
2897
|
+
console.log(this.colors.success("▶️ Resumed. Press p to pause, a to add URL."));
|
|
2898
|
+
pausedMessageShown = false;
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
} catch (error) {
|
|
2902
|
+
if (this.multiBar) {
|
|
2903
|
+
this.multiBar.stop();
|
|
2904
|
+
}
|
|
2905
|
+
console.error(this.colors.error.bold("💥 Batch download failed: ") + this.colors.warning(error.message));
|
|
2906
|
+
throw error;
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
/**
|
|
2910
|
+
* Download a single file with multibar integration and resume capability
|
|
2911
|
+
* @param {Object} fileBar - File bar object with progress bar and spinner info
|
|
2912
|
+
* @param {Object} masterBar - Master progress bar
|
|
2913
|
+
* @param {number} totalFiles - Total number of files being downloaded
|
|
2914
|
+
* @param {Object} totalTracking - Object to track total progress
|
|
2915
|
+
*/
|
|
2916
|
+
async downloadSingleFileWithBar(fileBar, masterBar, totalFiles, totalTracking) {
|
|
2917
|
+
const { bar, spinnerFrames, download } = fileBar;
|
|
2918
|
+
const { url, outputPath, filename } = download;
|
|
2919
|
+
const stateFilePath = this.getStateFilePath(outputPath);
|
|
2920
|
+
const tempFilePath = outputPath + ".tmp";
|
|
2921
|
+
try {
|
|
2922
|
+
const abortController = new AbortController();
|
|
2923
|
+
this.setAbortController(abortController);
|
|
2924
|
+
const serverInfo = await this.checkServerSupport(url);
|
|
2925
|
+
const previousState = this.loadDownloadState(stateFilePath);
|
|
2926
|
+
const partialSize = this.getPartialFileSize(tempFilePath);
|
|
2927
|
+
let startByte = 0;
|
|
2928
|
+
let resuming = false;
|
|
2929
|
+
if (serverInfo.supportsResume && partialSize > 0 && previousState) {
|
|
2930
|
+
const fileUnchanged = (!serverInfo.lastModified || serverInfo.lastModified === previousState.lastModified) && (!serverInfo.etag || serverInfo.etag === previousState.etag) && serverInfo.totalSize === previousState.totalSize;
|
|
2931
|
+
if (fileUnchanged && partialSize < serverInfo.totalSize) {
|
|
2932
|
+
startByte = partialSize;
|
|
2933
|
+
resuming = true;
|
|
2934
|
+
} else {
|
|
2935
|
+
if (fs.existsSync(tempFilePath)) {
|
|
2936
|
+
fs.unlinkSync(tempFilePath);
|
|
2937
|
+
}
|
|
2938
|
+
this.cleanupStateFile(stateFilePath);
|
|
2939
|
+
}
|
|
2940
|
+
} else if (partialSize > 0) {
|
|
2941
|
+
if (fs.existsSync(tempFilePath)) {
|
|
2942
|
+
fs.unlinkSync(tempFilePath);
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
const headers = {};
|
|
2946
|
+
if (resuming && startByte > 0) {
|
|
2947
|
+
headers["Range"] = `bytes=${startByte}-`;
|
|
2948
|
+
}
|
|
2949
|
+
const response = await fetch(url, {
|
|
2950
|
+
headers,
|
|
2951
|
+
signal: abortController.signal
|
|
2952
|
+
});
|
|
2953
|
+
if (!response.ok) {
|
|
2954
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
2955
|
+
}
|
|
2956
|
+
const contentLength = response.headers.get("content-length");
|
|
2957
|
+
const totalSize = resuming ? serverInfo.totalSize : contentLength ? parseInt(contentLength, 10) : 0;
|
|
2958
|
+
const downloadState = {
|
|
2959
|
+
url,
|
|
2960
|
+
outputPath,
|
|
2961
|
+
totalSize,
|
|
2962
|
+
startByte,
|
|
2963
|
+
lastModified: serverInfo.lastModified,
|
|
2964
|
+
etag: serverInfo.etag,
|
|
2965
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2966
|
+
};
|
|
2967
|
+
this.saveDownloadState(stateFilePath, downloadState);
|
|
2968
|
+
bar.setTotal(totalSize || 100);
|
|
2969
|
+
bar.update(startByte, {
|
|
2970
|
+
progress: this.formatProgress(startByte, totalSize),
|
|
2971
|
+
downloadedDisplay: this.formatBytesCompact(startByte),
|
|
2972
|
+
totalDisplay: this.formatTotalDisplay(totalSize)
|
|
2973
|
+
});
|
|
2974
|
+
const writeStream = fs.createWriteStream(tempFilePath, {
|
|
2975
|
+
flags: resuming ? "a" : "w"
|
|
2976
|
+
});
|
|
2977
|
+
let downloaded = startByte;
|
|
2978
|
+
let lastTime = Date.now();
|
|
2979
|
+
let lastDownloaded = downloaded;
|
|
2980
|
+
const progressStream = new Readable({
|
|
2981
|
+
read() {
|
|
2982
|
+
}
|
|
2983
|
+
});
|
|
2984
|
+
const reader = response.body.getReader();
|
|
2985
|
+
const processChunk = async () => {
|
|
2986
|
+
try {
|
|
2987
|
+
while (true) {
|
|
2988
|
+
while (this.isPaused) {
|
|
2989
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2990
|
+
}
|
|
2991
|
+
const { done, value } = await reader.read();
|
|
2992
|
+
if (done) {
|
|
2993
|
+
progressStream.push(null);
|
|
2994
|
+
break;
|
|
2995
|
+
}
|
|
2996
|
+
downloaded += value.length;
|
|
2997
|
+
const now = Date.now();
|
|
2998
|
+
const timeDiff = (now - lastTime) / 1e3;
|
|
2999
|
+
if (now - fileBar.lastFrameUpdate >= 150) {
|
|
3000
|
+
fileBar.spinnerIndex = (fileBar.spinnerIndex + 1) % spinnerFrames.length;
|
|
3001
|
+
fileBar.lastFrameUpdate = now;
|
|
3002
|
+
const currentSpinner = spinnerFrames[fileBar.spinnerIndex];
|
|
3003
|
+
const newBarSize = this.calculateBarSize(currentSpinner, this.COL_BAR);
|
|
3004
|
+
bar.options.barsize = newBarSize;
|
|
3005
|
+
}
|
|
3006
|
+
if (now - fileBar.lastSpinnerUpdate >= 45e3) {
|
|
3007
|
+
const newSpinnerType = this.getRandomSpinner();
|
|
3008
|
+
fileBar.spinnerFrames = this.getSpinnerFrames(newSpinnerType);
|
|
3009
|
+
fileBar.spinnerIndex = 0;
|
|
3010
|
+
fileBar.lastSpinnerUpdate = now;
|
|
3011
|
+
}
|
|
3012
|
+
if (timeDiff >= 0.3) {
|
|
3013
|
+
bar.update(downloaded, {
|
|
3014
|
+
spinner: spinnerFrames[fileBar.spinnerIndex],
|
|
3015
|
+
progress: this.formatProgress(downloaded, totalSize),
|
|
3016
|
+
downloadedDisplay: this.formatBytesCompact(downloaded),
|
|
3017
|
+
totalDisplay: this.formatTotalDisplay(totalSize)
|
|
3018
|
+
});
|
|
3019
|
+
if (totalTracking) {
|
|
3020
|
+
const bytesDiff = downloaded - lastDownloaded;
|
|
3021
|
+
totalTracking.totalDownloaded += bytesDiff;
|
|
3022
|
+
const fileIndex = fileBar.download.index || 0;
|
|
3023
|
+
totalTracking.individualDownloaded[fileIndex] = downloaded;
|
|
3024
|
+
totalTracking.individualSizes[fileIndex] = totalSize;
|
|
3025
|
+
totalTracking.totalSize = totalTracking.individualSizes.reduce((sum, size) => sum + size, 0);
|
|
3026
|
+
if (totalTracking.actualTotalSize !== void 0) {
|
|
3027
|
+
totalTracking.actualTotalSize = totalTracking.totalSize;
|
|
3028
|
+
}
|
|
3029
|
+
if (totalSize > 0 && totalTracking.individualSizes[fileIndex] === totalSize) {
|
|
3030
|
+
masterBar.setTotal(totalTracking.totalSize);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
lastTime = now;
|
|
3034
|
+
lastDownloaded = downloaded;
|
|
3035
|
+
} else {
|
|
3036
|
+
bar.update(downloaded, {
|
|
3037
|
+
spinner: spinnerFrames[fileBar.spinnerIndex],
|
|
3038
|
+
progress: this.formatProgress(downloaded, totalSize),
|
|
3039
|
+
downloadedDisplay: this.formatBytesCompact(downloaded),
|
|
3040
|
+
totalDisplay: this.formatTotalDisplay(totalSize)
|
|
3041
|
+
});
|
|
3042
|
+
}
|
|
3043
|
+
progressStream.push(Buffer.from(value));
|
|
3044
|
+
}
|
|
3045
|
+
} catch (error) {
|
|
3046
|
+
progressStream.destroy(error);
|
|
3047
|
+
}
|
|
3048
|
+
};
|
|
3049
|
+
processChunk();
|
|
3050
|
+
await pipeline(progressStream, writeStream);
|
|
3051
|
+
if (fs.existsSync(outputPath)) {
|
|
3052
|
+
fs.unlinkSync(outputPath);
|
|
3053
|
+
}
|
|
3054
|
+
fs.renameSync(tempFilePath, outputPath);
|
|
3055
|
+
this.cleanupStateFile(stateFilePath);
|
|
3056
|
+
const currentCompleted = masterBar.value + 1;
|
|
3057
|
+
const finalTotalSize = totalTracking.actualTotalSize || totalTracking.totalSize;
|
|
3058
|
+
const discoveredTotalSize = totalTracking.individualSizes.reduce((sum, size) => sum + size, 0);
|
|
3059
|
+
const displayTotalSize = discoveredTotalSize > 0 ? discoveredTotalSize : finalTotalSize;
|
|
3060
|
+
masterBar.update(totalTracking.totalDownloaded, {
|
|
3061
|
+
progress: this.formatMasterProgress(totalTracking.totalDownloaded, displayTotalSize),
|
|
3062
|
+
downloadedDisplay: this.formatBytesCompact(totalTracking.totalDownloaded),
|
|
3063
|
+
totalDisplay: this.formatTotalDisplay(displayTotalSize),
|
|
3064
|
+
etaFormatted: this.formatETA((Date.now() - (totalTracking.individualStartTimes?.[0] || Date.now())) / 1e3)
|
|
3065
|
+
// Show time elapsed
|
|
3066
|
+
});
|
|
3067
|
+
} catch (error) {
|
|
3068
|
+
bar.update(bar.total, {
|
|
3069
|
+
spinner: "❌",
|
|
3070
|
+
speed: this.formatSpeed("FAILED"),
|
|
3071
|
+
downloadedDisplay: this.formatBytesCompact(0),
|
|
3072
|
+
totalDisplay: this.formatTotalDisplay(0)
|
|
3073
|
+
});
|
|
3074
|
+
console.log(this.colors.info(`💾 Partial download saved for ${filename}. Restart to resume.`));
|
|
3075
|
+
throw error;
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
/**
|
|
3079
|
+
* Download a file with colorful progress tracking and resume capability
|
|
3080
|
+
* @param {string} url - The URL to download
|
|
3081
|
+
* @param {string} outputPath - The local path to save the file
|
|
3082
|
+
*/
|
|
3083
|
+
async downloadFile(url, outputPath) {
|
|
3084
|
+
const stateFilePath = this.getStateFilePath(outputPath);
|
|
3085
|
+
const tempFilePath = outputPath + ".tmp";
|
|
3086
|
+
try {
|
|
3087
|
+
this.abortController = new AbortController();
|
|
3088
|
+
const randomOraSpinner = this.getRandomOraSpinner();
|
|
3089
|
+
this.loadingSpinner = ora({
|
|
3090
|
+
text: this.colors.primary("🌐 Checking server capabilities..."),
|
|
3091
|
+
spinner: randomOraSpinner,
|
|
3092
|
+
color: "cyan"
|
|
3093
|
+
}).start();
|
|
3094
|
+
const serverInfo = await this.checkServerSupport(url);
|
|
3095
|
+
const previousState = this.loadDownloadState(stateFilePath);
|
|
3096
|
+
const partialSize = this.getPartialFileSize(tempFilePath);
|
|
3097
|
+
let startByte = 0;
|
|
3098
|
+
let resuming = false;
|
|
3099
|
+
if (serverInfo.supportsResume && partialSize > 0 && previousState) {
|
|
3100
|
+
const fileUnchanged = (!serverInfo.lastModified || serverInfo.lastModified === previousState.lastModified) && (!serverInfo.etag || serverInfo.etag === previousState.etag) && serverInfo.totalSize === previousState.totalSize;
|
|
3101
|
+
if (fileUnchanged && partialSize < serverInfo.totalSize) {
|
|
3102
|
+
startByte = partialSize;
|
|
3103
|
+
resuming = true;
|
|
3104
|
+
this.loadingSpinner.succeed(this.colors.success(`✅ Found partial download: ${this.formatBytes(partialSize)} of ${this.formatTotal(serverInfo.totalSize)}`));
|
|
3105
|
+
console.log(this.colors.info(`🔄 Resuming download from ${this.formatBytes(startByte)}`));
|
|
3106
|
+
} else {
|
|
3107
|
+
this.loadingSpinner.warn(this.colors.warning("⚠️ File changed on server, starting fresh download"));
|
|
3108
|
+
if (fs.existsSync(tempFilePath)) {
|
|
3109
|
+
fs.unlinkSync(tempFilePath);
|
|
3110
|
+
}
|
|
3111
|
+
this.cleanupStateFile(stateFilePath);
|
|
3112
|
+
}
|
|
3113
|
+
} else {
|
|
3114
|
+
this.loadingSpinner.stop();
|
|
3115
|
+
if (partialSize > 0) {
|
|
3116
|
+
console.log(this.colors.warning("⚠️ Server does not support resumable downloads, starting fresh"));
|
|
3117
|
+
if (fs.existsSync(tempFilePath)) {
|
|
3118
|
+
fs.unlinkSync(tempFilePath);
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
const headers = {};
|
|
3123
|
+
if (resuming && startByte > 0) {
|
|
3124
|
+
headers["Range"] = `bytes=${startByte}-`;
|
|
3125
|
+
}
|
|
3126
|
+
const response = await fetch(url, {
|
|
3127
|
+
headers,
|
|
3128
|
+
signal: this.abortController.signal
|
|
3129
|
+
});
|
|
3130
|
+
if (!response.ok) {
|
|
3131
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
3132
|
+
}
|
|
3133
|
+
const contentLength = response.headers.get("content-length");
|
|
3134
|
+
const totalSize = resuming ? serverInfo.totalSize : contentLength ? parseInt(contentLength, 10) : 0;
|
|
3135
|
+
const remainingSize = contentLength ? parseInt(contentLength, 10) : 0;
|
|
3136
|
+
if (!resuming) {
|
|
3137
|
+
if (totalSize === 0) {
|
|
3138
|
+
console.log(this.colors.warning("⚠️ Warning: Content-Length not provided, progress will be estimated"));
|
|
3139
|
+
} else {
|
|
3140
|
+
console.log(this.colors.info(`📦 File size: ${this.formatTotal(totalSize)}`));
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
const downloadState = {
|
|
3144
|
+
url,
|
|
3145
|
+
outputPath,
|
|
3146
|
+
totalSize,
|
|
3147
|
+
startByte,
|
|
3148
|
+
lastModified: serverInfo.lastModified,
|
|
3149
|
+
etag: serverInfo.etag,
|
|
3150
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3151
|
+
};
|
|
3152
|
+
this.saveDownloadState(stateFilePath, downloadState);
|
|
3153
|
+
const singleBarColor = this.getRandomBarColor();
|
|
3154
|
+
const singleBarGlue = this.getRandomBarGlueColor();
|
|
3155
|
+
let currentSpinnerType = this.getRandomSpinner();
|
|
3156
|
+
let spinnerFrames = this.getSpinnerFrames(currentSpinnerType);
|
|
3157
|
+
let spinnerFrameIndex = 0;
|
|
3158
|
+
const initialBarSize = this.calculateBarSize(spinnerFrames[0], this.COL_BAR);
|
|
3159
|
+
console.log(
|
|
3160
|
+
this.colors.success("📈 %".padEnd(this.COL_PERCENT)) + this.colors.cyan("🔄".padEnd(this.COL_SPINNER)) + " " + this.colors.green("📊 Progress".padEnd(this.COL_BAR + 1)) + this.colors.info("📥 Downloaded".padEnd(this.COL_DOWNLOADED)) + this.colors.info("📦 Total".padEnd(this.COL_TOTAL)) + this.colors.purple("⚡ Speed".padEnd(this.COL_SPEED)) + this.colors.pink("⏱️ ETA".padEnd(this.COL_ETA))
|
|
3161
|
+
);
|
|
3162
|
+
const keyboardRl = this.setupSingleFileKeyboardListeners(url, outputPath);
|
|
3163
|
+
this.progressBar = new cliProgress.SingleBar({
|
|
3164
|
+
format: this.colors.success("{percentage}%") + " " + this.colors.cyan("{spinner}") + " " + singleBarColor + "{bar}\x1B[0m " + this.colors.info("{downloadedDisplay}") + " " + this.colors.info("{totalDisplay}") + " " + this.colors.purple("{speed}") + " " + this.colors.pink("{etaFormatted}"),
|
|
3165
|
+
barCompleteChar: "█",
|
|
3166
|
+
barIncompleteChar: "░",
|
|
3167
|
+
barGlue: singleBarGlue,
|
|
3168
|
+
hideCursor: true,
|
|
3169
|
+
barsize: initialBarSize,
|
|
3170
|
+
stopOnComplete: true,
|
|
3171
|
+
clearOnComplete: false
|
|
3172
|
+
});
|
|
3173
|
+
this.progressBar.start(totalSize || 100, startByte, {
|
|
3174
|
+
speed: this.formatSpeed("0B/s"),
|
|
3175
|
+
etaFormatted: this.formatETA(0),
|
|
3176
|
+
spinner: spinnerFrames[0],
|
|
3177
|
+
progress: this.formatProgress(startByte, totalSize),
|
|
3178
|
+
downloadedDisplay: this.formatBytesCompact(startByte),
|
|
3179
|
+
totalDisplay: this.formatTotalDisplay(totalSize)
|
|
3180
|
+
});
|
|
3181
|
+
const writeStream = fs.createWriteStream(tempFilePath, {
|
|
3182
|
+
flags: resuming ? "a" : "w"
|
|
3183
|
+
});
|
|
3184
|
+
let downloaded = startByte;
|
|
3185
|
+
let sessionDownloaded = 0;
|
|
3186
|
+
let lastTime = Date.now();
|
|
3187
|
+
let lastDownloaded = downloaded;
|
|
3188
|
+
let lastSpinnerUpdate = Date.now();
|
|
3189
|
+
let lastSpinnerFrameUpdate = Date.now();
|
|
3190
|
+
const progressStream = new Readable({
|
|
3191
|
+
read() {
|
|
3192
|
+
}
|
|
3193
|
+
// No-op, we'll push data manually
|
|
3194
|
+
});
|
|
3195
|
+
const reader = response.body.getReader();
|
|
3196
|
+
const processChunk = async () => {
|
|
3197
|
+
try {
|
|
3198
|
+
while (true) {
|
|
3199
|
+
while (this.isPaused) {
|
|
3200
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3201
|
+
}
|
|
3202
|
+
const { done, value } = await reader.read();
|
|
3203
|
+
if (done) {
|
|
3204
|
+
progressStream.push(null);
|
|
3205
|
+
break;
|
|
3206
|
+
}
|
|
3207
|
+
sessionDownloaded += value.length;
|
|
3208
|
+
downloaded += value.length;
|
|
3209
|
+
const now = Date.now();
|
|
3210
|
+
const timeDiff = (now - lastTime) / 1e3;
|
|
3211
|
+
if (now - lastSpinnerUpdate >= 45e3) {
|
|
3212
|
+
currentSpinnerType = this.getRandomSpinner();
|
|
3213
|
+
spinnerFrames = this.getSpinnerFrames(currentSpinnerType);
|
|
3214
|
+
spinnerFrameIndex = 0;
|
|
3215
|
+
lastSpinnerUpdate = now;
|
|
3216
|
+
}
|
|
3217
|
+
if (now - lastSpinnerFrameUpdate >= 120) {
|
|
3218
|
+
spinnerFrameIndex = (spinnerFrameIndex + 1) % spinnerFrames.length;
|
|
3219
|
+
lastSpinnerFrameUpdate = now;
|
|
3220
|
+
const currentSpinner = spinnerFrames[spinnerFrameIndex];
|
|
3221
|
+
const newBarSize = this.calculateBarSize(currentSpinner, this.COL_BAR);
|
|
3222
|
+
this.progressBar.options.barsize = newBarSize;
|
|
3223
|
+
}
|
|
3224
|
+
if (timeDiff >= 0.3) {
|
|
3225
|
+
const bytesDiff = downloaded - lastDownloaded;
|
|
3226
|
+
const speedBps = bytesDiff / timeDiff;
|
|
3227
|
+
const speed = this.formatSpeed(this.formatSpeedDisplay(speedBps));
|
|
3228
|
+
const eta2 = totalSize > 0 ? this.formatETA((totalSize - downloaded) / speedBps) : this.formatETA(0);
|
|
3229
|
+
this.progressBar.update(downloaded, {
|
|
3230
|
+
speed,
|
|
3231
|
+
etaFormatted: eta2,
|
|
3232
|
+
spinner: spinnerFrames[spinnerFrameIndex],
|
|
3233
|
+
progress: this.formatProgress(downloaded, totalSize),
|
|
3234
|
+
downloadedDisplay: this.formatBytesCompact(downloaded),
|
|
3235
|
+
totalDisplay: this.formatTotalDisplay(totalSize)
|
|
3236
|
+
});
|
|
3237
|
+
lastTime = now;
|
|
3238
|
+
lastDownloaded = downloaded;
|
|
3239
|
+
} else {
|
|
3240
|
+
this.progressBar.update(downloaded, {
|
|
3241
|
+
spinner: spinnerFrames[spinnerFrameIndex],
|
|
3242
|
+
progress: this.formatProgress(downloaded, totalSize),
|
|
3243
|
+
downloadedDisplay: this.formatBytesCompact(downloaded),
|
|
3244
|
+
totalDisplay: this.formatTotalDisplay(totalSize)
|
|
3245
|
+
});
|
|
3246
|
+
}
|
|
3247
|
+
progressStream.push(Buffer.from(value));
|
|
3248
|
+
}
|
|
3249
|
+
} catch (error) {
|
|
3250
|
+
progressStream.destroy(error);
|
|
3251
|
+
}
|
|
3252
|
+
};
|
|
3253
|
+
processChunk();
|
|
3254
|
+
await pipeline(progressStream, writeStream);
|
|
3255
|
+
this.progressBar.stop();
|
|
3256
|
+
if (fs.existsSync(outputPath)) {
|
|
3257
|
+
fs.unlinkSync(outputPath);
|
|
3258
|
+
}
|
|
3259
|
+
fs.renameSync(tempFilePath, outputPath);
|
|
3260
|
+
this.cleanupStateFile(stateFilePath);
|
|
3261
|
+
console.log(this.colors.success("✅ Download completed!"));
|
|
3262
|
+
console.log(this.colors.primary("📁 File saved to: ") + chalk.underline(outputPath));
|
|
3263
|
+
console.log(this.colors.purple("📊 Total size: ") + this.formatBytes(downloaded));
|
|
3264
|
+
if (resuming) {
|
|
3265
|
+
console.log(this.colors.info("🔄 Resumed from: ") + this.formatBytes(startByte));
|
|
3266
|
+
console.log(this.colors.info("📥 Downloaded this session: ") + this.formatBytes(sessionDownloaded));
|
|
3267
|
+
}
|
|
3268
|
+
const celebrationEmojis = ["🥳", "🎊", "🎈", "🌟", "💯", "🚀", "✨", "🔥"];
|
|
3269
|
+
const randomEmoji = celebrationEmojis[Math.floor(Math.random() * celebrationEmojis.length)];
|
|
3270
|
+
console.log(this.colors.success(`${randomEmoji} Successfully downloaded! ${randomEmoji}`));
|
|
3271
|
+
} catch (error) {
|
|
3272
|
+
if (this.loadingSpinner && this.loadingSpinner.isSpinning) {
|
|
3273
|
+
this.loadingSpinner.fail(this.colors.error("❌ Connection failed"));
|
|
3274
|
+
}
|
|
3275
|
+
if (this.progressBar) {
|
|
3276
|
+
this.progressBar.stop();
|
|
3277
|
+
}
|
|
3278
|
+
console.error(this.colors.error.bold("💥 Download failed: ") + this.colors.warning(error.message));
|
|
3279
|
+
if (error.name === "AbortError") {
|
|
3280
|
+
console.log(this.colors.info("💾 Download state saved. You can resume later by running the same command."));
|
|
3281
|
+
} else {
|
|
3282
|
+
console.log(this.colors.info("💾 Partial download saved. Restart to resume from where it left off."));
|
|
3283
|
+
}
|
|
3284
|
+
throw error;
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
/**
|
|
3288
|
+
* Clean up resources
|
|
3289
|
+
*/
|
|
3290
|
+
cleanup() {
|
|
3291
|
+
if (this.loadingSpinner && this.loadingSpinner.isSpinning) {
|
|
3292
|
+
this.loadingSpinner.stop();
|
|
3293
|
+
}
|
|
3294
|
+
if (this.progressBar) {
|
|
3295
|
+
this.progressBar.stop();
|
|
3296
|
+
}
|
|
3297
|
+
if (this.multiBar) {
|
|
3298
|
+
this.multiBar.stop();
|
|
3299
|
+
}
|
|
3300
|
+
if (this.abortController) {
|
|
3301
|
+
this.abortController.abort();
|
|
3302
|
+
}
|
|
3303
|
+
if (this.keyboardListener) {
|
|
3304
|
+
try {
|
|
3305
|
+
this.keyboardListener.kill();
|
|
3306
|
+
} catch (error) {
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
if (process.stdin.isTTY) {
|
|
3310
|
+
process.stdin.setRawMode(false);
|
|
3311
|
+
process.stdin.pause();
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
/**
|
|
3315
|
+
* Set up global keyboard listener for pause/resume and add URL functionality
|
|
3316
|
+
*/
|
|
3317
|
+
setupGlobalKeyboardListener() {
|
|
3318
|
+
this.setupFallbackKeyboardListener();
|
|
3319
|
+
}
|
|
3320
|
+
/**
|
|
3321
|
+
* Handle global key press events
|
|
3322
|
+
* @param {string} keyName - The name of the pressed key
|
|
3323
|
+
*/
|
|
3324
|
+
async handleGlobalKeyPress(keyName) {
|
|
3325
|
+
if (keyName === "P") {
|
|
3326
|
+
console.log(this.colors.info("P key pressed - toggling pause/resume"));
|
|
3327
|
+
if (!this.isPaused) {
|
|
3328
|
+
this.pauseAll();
|
|
3329
|
+
} else {
|
|
3330
|
+
this.resumeAll();
|
|
3331
|
+
}
|
|
3332
|
+
} else if (keyName === "A" && !this.isAddingUrl) {
|
|
3333
|
+
console.log(this.colors.info("A key pressed - adding URL"));
|
|
3334
|
+
await this.promptForNewUrl();
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
/**
|
|
3338
|
+
* Prompt user for a new URL to download
|
|
3339
|
+
*/
|
|
3340
|
+
async promptForNewUrl() {
|
|
3341
|
+
this.isAddingUrl = true;
|
|
3342
|
+
try {
|
|
3343
|
+
console.log(this.colors.cyan("\n📥 Enter URL to add (or press Enter to cancel):"));
|
|
3344
|
+
const rl = require$$0.createInterface({
|
|
3345
|
+
input: process.stdin,
|
|
3346
|
+
output: process.stdout
|
|
3347
|
+
});
|
|
3348
|
+
const newUrl = await new Promise((resolve) => {
|
|
3349
|
+
rl.question("", (answer) => {
|
|
3350
|
+
rl.close();
|
|
3351
|
+
resolve(answer.trim());
|
|
3352
|
+
});
|
|
3353
|
+
});
|
|
3354
|
+
if (newUrl && this.isValidUrl(newUrl)) {
|
|
3355
|
+
console.log(this.colors.success(`✅ Adding URL: ${newUrl}`));
|
|
3356
|
+
const newFilename = this.generateFilename(newUrl);
|
|
3357
|
+
const newOutputPath = path.isAbsolute(newFilename) ? newFilename : path.join(process.cwd(), newFilename);
|
|
3358
|
+
const outputDir = path.dirname(newOutputPath);
|
|
3359
|
+
try {
|
|
3360
|
+
if (!fs.existsSync(outputDir)) {
|
|
3361
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
3362
|
+
}
|
|
3363
|
+
} catch (error) {
|
|
3364
|
+
console.error(this.colors.red.bold("❌ Could not create output directory: ") + error.message);
|
|
3365
|
+
return;
|
|
3366
|
+
}
|
|
3367
|
+
if (this.multiBar) {
|
|
3368
|
+
await this.addToMultipleDownloads(newUrl, newOutputPath, newFilename);
|
|
3369
|
+
} else {
|
|
3370
|
+
this.downloadFile(newUrl, newOutputPath).catch((error) => {
|
|
3371
|
+
console.error(this.colors.error(`❌ Failed to download ${newFilename}: ${error.message}`));
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
console.log(this.colors.success("🚀 New download started!"));
|
|
3375
|
+
} else if (newUrl) {
|
|
3376
|
+
console.log(this.colors.red("❌ Invalid URL provided."));
|
|
3377
|
+
} else {
|
|
3378
|
+
console.log(this.colors.yellow("⚠️ No URL provided, cancelling."));
|
|
3379
|
+
}
|
|
3380
|
+
} catch (error) {
|
|
3381
|
+
console.error(this.colors.red("❌ Error adding URL: ") + error.message);
|
|
3382
|
+
} finally {
|
|
3383
|
+
this.isAddingUrl = false;
|
|
3384
|
+
if (this.isPaused) {
|
|
3385
|
+
console.log(this.colors.warning("⏸️ Still paused. Press p to resume, a to add URL."));
|
|
3386
|
+
} else {
|
|
3387
|
+
console.log(this.colors.success("▶️ Downloads active. Press p to pause, a to add URL."));
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
/**
|
|
3392
|
+
* Add a new download to the multiple downloads queue
|
|
3393
|
+
* @param {string} url - The URL to download
|
|
3394
|
+
* @param {string} outputPath - The output path
|
|
3395
|
+
* @param {string} filename - The filename
|
|
3396
|
+
*/
|
|
3397
|
+
async addToMultipleDownloads(url, outputPath, filename) {
|
|
3398
|
+
const spinnerType = this.getRandomSpinner();
|
|
3399
|
+
const spinnerFrames = this.getSpinnerFrames(spinnerType);
|
|
3400
|
+
const spinnerWidth = this.getSpinnerWidth(spinnerFrames[0]);
|
|
3401
|
+
const maxFilenameLength = this.COL_FILENAME - spinnerWidth;
|
|
3402
|
+
const truncatedName = this.truncateFilename(filename, maxFilenameLength);
|
|
3403
|
+
const fileBarColor = this.getRandomBarColor();
|
|
3404
|
+
const fileBarGlue = this.getRandomBarGlueColor();
|
|
3405
|
+
const barSize = this.calculateBarSize(spinnerFrames[0], this.COL_BAR);
|
|
3406
|
+
const newDownload = {
|
|
3407
|
+
url,
|
|
3408
|
+
outputPath,
|
|
3409
|
+
filename
|
|
3410
|
+
};
|
|
3411
|
+
const newFileBar = {
|
|
3412
|
+
bar: this.multiBar.create(100, 0, {
|
|
3413
|
+
filename: truncatedName,
|
|
3414
|
+
spinner: spinnerFrames[0],
|
|
3415
|
+
speed: this.formatSpeed("0B"),
|
|
3416
|
+
progress: this.formatProgress(0, 0),
|
|
3417
|
+
downloadedDisplay: this.formatBytesCompact(0),
|
|
3418
|
+
totalDisplay: this.formatTotalDisplay(0),
|
|
3419
|
+
etaFormatted: this.formatETA(0),
|
|
3420
|
+
percentage: " 0".padStart(3)
|
|
3421
|
+
}, {
|
|
3422
|
+
format: this.colors.yellow("{filename}") + " " + this.colors.cyan("{spinner}") + " " + fileBarColor + "{bar}\x1B[0m " + this.colors.success("{percentage}%") + " " + this.colors.info("{downloadedDisplay}") + " " + this.colors.info("{totalDisplay}") + " " + this.colors.purple("{speed}") + " " + this.colors.pink("{etaFormatted}"),
|
|
3423
|
+
barCompleteChar: "█",
|
|
3424
|
+
barIncompleteChar: "░",
|
|
3425
|
+
barGlue: fileBarGlue,
|
|
3426
|
+
barsize: barSize
|
|
3427
|
+
}),
|
|
3428
|
+
spinnerFrames,
|
|
3429
|
+
spinnerIndex: 0,
|
|
3430
|
+
lastSpinnerUpdate: Date.now(),
|
|
3431
|
+
lastFrameUpdate: Date.now(),
|
|
3432
|
+
download: { ...newDownload, index: this.getCurrentDownloadCount() }
|
|
3433
|
+
};
|
|
3434
|
+
this.downloadSingleFileWithBar(newFileBar, this.getMasterBar(), this.getCurrentDownloadCount() + 1, {
|
|
3435
|
+
totalDownloaded: 0,
|
|
3436
|
+
totalSize: 0,
|
|
3437
|
+
individualSpeeds: [],
|
|
3438
|
+
individualSizes: [],
|
|
3439
|
+
individualDownloaded: [],
|
|
3440
|
+
individualStartTimes: [],
|
|
3441
|
+
lastTotalUpdate: Date.now(),
|
|
3442
|
+
lastTotalDownloaded: 0,
|
|
3443
|
+
actualTotalSize: 0
|
|
3444
|
+
}).catch((error) => {
|
|
3445
|
+
console.error(this.colors.error(`❌ Failed to download ${newDownload.filename}: ${error.message}`));
|
|
3446
|
+
});
|
|
3447
|
+
}
|
|
3448
|
+
/**
|
|
3449
|
+
* Get current download count (for multiple downloads)
|
|
3450
|
+
* @returns {number} Current number of downloads
|
|
3451
|
+
*/
|
|
3452
|
+
getCurrentDownloadCount() {
|
|
3453
|
+
return 1;
|
|
3454
|
+
}
|
|
3455
|
+
/**
|
|
3456
|
+
* Get master bar (for multiple downloads)
|
|
3457
|
+
* @returns {Object} Master progress bar
|
|
3458
|
+
*/
|
|
3459
|
+
getMasterBar() {
|
|
3460
|
+
return null;
|
|
3461
|
+
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Set up fallback keyboard listener using readline
|
|
3464
|
+
*/
|
|
3465
|
+
setupFallbackKeyboardListener() {
|
|
3466
|
+
if (process.stdin.isTTY) {
|
|
3467
|
+
process.stdin.setRawMode(true);
|
|
3468
|
+
process.stdin.resume();
|
|
3469
|
+
process.stdin.setEncoding("utf8");
|
|
3470
|
+
const handleKeypress = async (str) => {
|
|
3471
|
+
if (str === "") {
|
|
3472
|
+
console.log(this.colors.yellow.bold("\n🛑 Download cancelled by user"));
|
|
3473
|
+
process.exit(0);
|
|
3474
|
+
}
|
|
3475
|
+
if (str.toLowerCase() === "p") {
|
|
3476
|
+
console.log(this.colors.info("P key pressed - toggling pause/resume"));
|
|
3477
|
+
if (!this.isPaused) {
|
|
3478
|
+
this.pauseAll();
|
|
3479
|
+
} else {
|
|
3480
|
+
this.resumeAll();
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
if (str.toLowerCase() === "a" && !this.isAddingUrl) {
|
|
3484
|
+
console.log(this.colors.info("A key pressed - adding URL"));
|
|
3485
|
+
await this.promptForNewUrl();
|
|
3486
|
+
}
|
|
3487
|
+
};
|
|
3488
|
+
process.stdin.on("data", handleKeypress);
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
/**
|
|
3492
|
+
* Set up keyboard listeners for single file download (legacy method)
|
|
3493
|
+
* @param {string} url - The URL being downloaded
|
|
3494
|
+
* @param {string} outputPath - The output path
|
|
3495
|
+
*/
|
|
3496
|
+
setupSingleFileKeyboardListeners(url, outputPath) {
|
|
3497
|
+
this.setupGlobalKeyboardListener();
|
|
3498
|
+
return null;
|
|
3499
|
+
}
|
|
3500
|
+
/**
|
|
3501
|
+
* Validate URL format
|
|
3502
|
+
* @param {string} url - URL to validate
|
|
3503
|
+
* @returns {boolean} - Whether URL is valid
|
|
3504
|
+
*/
|
|
3505
|
+
isValidUrl(url) {
|
|
3506
|
+
try {
|
|
3507
|
+
new URL(url);
|
|
3508
|
+
return true;
|
|
3509
|
+
} catch {
|
|
3510
|
+
return false;
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
/**
|
|
3514
|
+
* Get file extension from URL
|
|
3515
|
+
* @param {string} url - URL to extract extension from
|
|
3516
|
+
* @returns {string} - File extension or empty string
|
|
3517
|
+
*/
|
|
3518
|
+
getFileExtension(url) {
|
|
3519
|
+
try {
|
|
3520
|
+
const pathname = new URL(url).pathname;
|
|
3521
|
+
return path.extname(pathname).toLowerCase();
|
|
3522
|
+
} catch {
|
|
3523
|
+
return "";
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
/**
|
|
3527
|
+
* Generate filename from URL
|
|
3528
|
+
* @param {string} url - Download URL
|
|
3529
|
+
* @returns {string} - Generated filename
|
|
3530
|
+
*/
|
|
3531
|
+
generateFilename(url) {
|
|
3532
|
+
try {
|
|
3533
|
+
const filename = path.basename(new URL(url).pathname);
|
|
3534
|
+
return filename || "downloaded-file";
|
|
3535
|
+
} catch (error) {
|
|
3536
|
+
return "downloaded-file";
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
setPauseCallback(cb) {
|
|
3540
|
+
this.pauseCallback = cb;
|
|
3541
|
+
}
|
|
3542
|
+
setResumeCallback(cb) {
|
|
3543
|
+
this.resumeCallback = cb;
|
|
3544
|
+
}
|
|
3545
|
+
setAbortController(controller) {
|
|
3546
|
+
this.abortControllers.push(controller);
|
|
3547
|
+
}
|
|
3548
|
+
clearAbortControllers() {
|
|
3549
|
+
this.abortControllers = [];
|
|
3550
|
+
}
|
|
3551
|
+
pauseAll() {
|
|
3552
|
+
this.isPaused = true;
|
|
3553
|
+
console.log(this.colors.warning("⏸️ Pausing all downloads..."));
|
|
3554
|
+
if (this.pauseCallback) this.pauseCallback();
|
|
3555
|
+
}
|
|
3556
|
+
resumeAll() {
|
|
3557
|
+
this.isPaused = false;
|
|
3558
|
+
console.log(this.colors.success("▶️ Resuming all downloads..."));
|
|
3559
|
+
if (this.resumeCallback) this.resumeCallback();
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
const __isMain = typeof import.meta.main === "boolean" && import.meta.main || (() => {
|
|
3563
|
+
try {
|
|
3564
|
+
const scriptArg = process.argv[1] ? path.resolve(process.argv[1]) : "";
|
|
3565
|
+
if (!scriptArg) return false;
|
|
3566
|
+
const href = pathToFileURL(scriptArg).href;
|
|
3567
|
+
return import.meta.url === href;
|
|
3568
|
+
} catch {
|
|
3569
|
+
return false;
|
|
3570
|
+
}
|
|
3571
|
+
})();
|
|
3572
|
+
if (__isMain) {
|
|
3573
|
+
const argv = new ArgParser().usage("Usage: grab-url <url...> [options]").command("$0 <url>", "Fetch data or download files; pass one or more URLs").option("no-save", {
|
|
3574
|
+
type: "boolean",
|
|
3575
|
+
default: false,
|
|
3576
|
+
describe: "Don't save output to file, just print to console"
|
|
3577
|
+
}).option("output", {
|
|
3578
|
+
alias: "o",
|
|
3579
|
+
type: "string",
|
|
3580
|
+
describe: "Output filename (default: output.json)",
|
|
3581
|
+
default: null
|
|
3582
|
+
}).option("params", {
|
|
3583
|
+
alias: "p",
|
|
3584
|
+
type: "string",
|
|
3585
|
+
describe: `JSON string of query parameters (e.g., '{"key":"value"}')`,
|
|
3586
|
+
coerce: (arg) => {
|
|
3587
|
+
if (!arg) return {};
|
|
3588
|
+
try {
|
|
3589
|
+
return JSON.parse(arg);
|
|
3590
|
+
} catch (e) {
|
|
3591
|
+
throw new Error(`Invalid JSON in params: ${arg}`);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
}).help().alias("h", "help").example("grab-url https://api.example.com/data", "Fetch JSON/text from an API and save to output.json").example("grab-url https://example.com/file1.zip https://example.com/file2.zip", "Download multiple files concurrently").example("grab-url https://example.com/file.iso -o ubuntu.iso", "Save the first URL to a custom filename").version("1.0.0").strict().parseSync();
|
|
3595
|
+
const urls = argv.urls || [];
|
|
3596
|
+
const params = argv.params || {};
|
|
3597
|
+
const outputFile = argv.output;
|
|
3598
|
+
const noSave = argv["no-save"];
|
|
3599
|
+
const anyFileUrl = urls.some(isFileUrl);
|
|
3600
|
+
const isDownloadMode = urls.length > 1 || anyFileUrl;
|
|
3601
|
+
(async () => {
|
|
3602
|
+
if (isDownloadMode) {
|
|
3603
|
+
const downloader = new ColorFileDownloader();
|
|
3604
|
+
const downloads = urls.map((url, i) => {
|
|
3605
|
+
let filename = null;
|
|
3606
|
+
if (i === 0 && outputFile) filename = outputFile;
|
|
3607
|
+
return { url, outputPath: filename };
|
|
3608
|
+
});
|
|
3609
|
+
const downloadObjects = downloads.map((download, index) => {
|
|
3610
|
+
let actualUrl = download.url;
|
|
3611
|
+
let filename = download.outputPath;
|
|
3612
|
+
if (!filename) filename = downloader.generateFilename(actualUrl);
|
|
3613
|
+
const outputPath = path.isAbsolute(filename) ? filename : path.join(process.cwd(), filename);
|
|
3614
|
+
const outputDir = path.dirname(outputPath);
|
|
3615
|
+
try {
|
|
3616
|
+
if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
|
|
3617
|
+
} catch (error) {
|
|
3618
|
+
console.error(chalk.red.bold("❌ Could not create output directory: ") + error.message);
|
|
3619
|
+
process.exit(1);
|
|
3620
|
+
}
|
|
3621
|
+
return {
|
|
3622
|
+
url: actualUrl,
|
|
3623
|
+
outputPath,
|
|
3624
|
+
filename: path.basename(filename)
|
|
3625
|
+
};
|
|
3626
|
+
});
|
|
3627
|
+
try {
|
|
3628
|
+
await downloader.downloadMultipleFiles(downloadObjects);
|
|
3629
|
+
const statsTable = new Table({
|
|
3630
|
+
head: ["Filename", "Size", "Created"],
|
|
3631
|
+
colWidths: [32, 14, 25],
|
|
3632
|
+
colAligns: ["left", "right", "left"],
|
|
3633
|
+
style: { "padding-left": 1, "padding-right": 1, head: [], border: [] }
|
|
3634
|
+
});
|
|
3635
|
+
downloadObjects.forEach((downloadObj) => {
|
|
3636
|
+
try {
|
|
3637
|
+
const stats = fs.statSync(downloadObj.outputPath);
|
|
3638
|
+
statsTable.push([
|
|
3639
|
+
downloadObj.filename,
|
|
3640
|
+
downloader.formatBytes(stats.size),
|
|
3641
|
+
stats.birthtime.toLocaleString()
|
|
3642
|
+
]);
|
|
3643
|
+
} catch (error) {
|
|
3644
|
+
statsTable.push([
|
|
3645
|
+
downloadObj.filename,
|
|
3646
|
+
"Error",
|
|
3647
|
+
"Could not read"
|
|
3648
|
+
]);
|
|
3649
|
+
}
|
|
3650
|
+
});
|
|
3651
|
+
console.log(chalk.cyan.bold("\nFile Details:"));
|
|
3652
|
+
console.log(statsTable.toString());
|
|
3653
|
+
} catch (error) {
|
|
3654
|
+
console.error(chalk.red.bold("Failed to download files: ") + chalk.yellow(error.message));
|
|
3655
|
+
process.exit(1);
|
|
3656
|
+
}
|
|
3657
|
+
downloader.cleanup();
|
|
3658
|
+
} else {
|
|
3659
|
+
const url = urls[0];
|
|
3660
|
+
const startTime = process.hrtime();
|
|
3661
|
+
try {
|
|
3662
|
+
const res = await grab(url, params);
|
|
3663
|
+
if (res.error) log(`
|
|
3664
|
+
|
|
3665
|
+
Status: ❌ ${res.error}`);
|
|
3666
|
+
let filePath = null;
|
|
3667
|
+
let outputData;
|
|
3668
|
+
let isTextData = false;
|
|
3669
|
+
if (typeof res.data === "string") {
|
|
3670
|
+
outputData = res.data;
|
|
3671
|
+
isTextData = true;
|
|
3672
|
+
} else if (Buffer.isBuffer(res.data) || res.data instanceof Uint8Array) {
|
|
3673
|
+
outputData = res.data;
|
|
3674
|
+
isTextData = false;
|
|
3675
|
+
} else if (res.data instanceof Blob) {
|
|
3676
|
+
const arrayBuffer = await res.data.arrayBuffer();
|
|
3677
|
+
outputData = Buffer.from(arrayBuffer);
|
|
3678
|
+
isTextData = false;
|
|
3679
|
+
} else if (res.data && typeof res.data === "object") {
|
|
3680
|
+
outputData = JSON.stringify(res.data, null, 2);
|
|
3681
|
+
isTextData = true;
|
|
3682
|
+
} else {
|
|
3683
|
+
outputData = String(res.data);
|
|
3684
|
+
isTextData = true;
|
|
3685
|
+
}
|
|
3686
|
+
if (!noSave) {
|
|
3687
|
+
const urlPath = new URL(url).pathname;
|
|
3688
|
+
const urlExt = path.extname(urlPath);
|
|
3689
|
+
const defaultExt = isTextData ? ".json" : urlExt || ".bin";
|
|
3690
|
+
filePath = outputFile ? path.resolve(outputFile) : path.resolve(process.cwd(), `output${defaultExt}`);
|
|
3691
|
+
if (isTextData) fs.writeFileSync(filePath, outputData, "utf8");
|
|
3692
|
+
else fs.writeFileSync(filePath, outputData);
|
|
3693
|
+
const [seconds, nanoseconds] = process.hrtime(startTime);
|
|
3694
|
+
const elapsedMs = (seconds + nanoseconds / 1e9).toFixed(2);
|
|
3695
|
+
const stats = fs.statSync(filePath);
|
|
3696
|
+
const fileSizeMB = (stats.size / (1024 * 1024)).toFixed(1);
|
|
3697
|
+
log(`⏱️ ${elapsedMs}s 📦 ${fileSizeMB}MB ✅ Saved to: ${filePath}`);
|
|
3698
|
+
} else {
|
|
3699
|
+
if (isTextData) {
|
|
3700
|
+
log(outputData);
|
|
3701
|
+
} else {
|
|
3702
|
+
log(`Binary data received (${outputData.length} bytes). Use --output to save to file.`);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
} catch (error) {
|
|
3706
|
+
log(`Error: ${error.message}`, { color: "red" });
|
|
3707
|
+
process.exit(1);
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
})();
|
|
3711
|
+
}
|
|
3712
|
+
export {
|
|
3713
|
+
ColorFileDownloader
|
|
3714
|
+
};
|
|
3715
|
+
//# sourceMappingURL=download.es.js.map
|