grab-url 0.9.138 β 0.9.140
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/package.json +1 -1
- package/src/grab-url-cli.js +37 -42
package/package.json
CHANGED
package/src/grab-url-cli.js
CHANGED
|
@@ -29,7 +29,7 @@ try {
|
|
|
29
29
|
spinners = JSON.parse(readFileSync(join(process.cwd(), 'src', 'spinners.json'), 'utf8'));
|
|
30
30
|
} catch (error3) {
|
|
31
31
|
// Fallback to default spinners if file not found
|
|
32
|
-
console.warn('
|
|
32
|
+
console.warn('Could not load spinners.json, using defaults');
|
|
33
33
|
spinners = {
|
|
34
34
|
dots: { frames: ['β ', 'β ', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ', 'β '] },
|
|
35
35
|
line: { frames: ['-', '\\', '|', '/'] },
|
|
@@ -141,7 +141,7 @@ ensureStateDirectoryExists() {
|
|
|
141
141
|
fs.mkdirSync(this.stateDir, { recursive: true });
|
|
142
142
|
}
|
|
143
143
|
} catch (error) {
|
|
144
|
-
console.log(this.colors.warning('
|
|
144
|
+
console.log(this.colors.warning('Could not create state directory, using current directory'));
|
|
145
145
|
this.stateDir = process.cwd();
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -166,7 +166,7 @@ cleanupStateFile(stateFilePath) {
|
|
|
166
166
|
fs.unlinkSync(stateFilePath);
|
|
167
167
|
}
|
|
168
168
|
} catch (error) {
|
|
169
|
-
console.log(this.colors.warning('
|
|
169
|
+
console.log(this.colors.warning('Could not clean up state file'));
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
@@ -313,7 +313,7 @@ async checkServerSupport(url) {
|
|
|
313
313
|
headers: response.headers
|
|
314
314
|
};
|
|
315
315
|
} catch (error) {
|
|
316
|
-
console.log(this.colors.warning('
|
|
316
|
+
console.log(this.colors.warning('Could not check server resume support, proceeding with regular download'));
|
|
317
317
|
return {
|
|
318
318
|
supportsResume: false,
|
|
319
319
|
totalSize: 0,
|
|
@@ -336,7 +336,7 @@ loadDownloadState(stateFilePath) {
|
|
|
336
336
|
return JSON.parse(stateData);
|
|
337
337
|
}
|
|
338
338
|
} catch (error) {
|
|
339
|
-
console.log(this.colors.warning('
|
|
339
|
+
console.log(this.colors.warning('Could not load download state, starting fresh'));
|
|
340
340
|
}
|
|
341
341
|
return null;
|
|
342
342
|
}
|
|
@@ -350,7 +350,7 @@ saveDownloadState(stateFilePath, state) {
|
|
|
350
350
|
try {
|
|
351
351
|
fs.writeFileSync(stateFilePath, JSON.stringify(state, null, 2));
|
|
352
352
|
} catch (error) {
|
|
353
|
-
console.log(this.colors.warning('
|
|
353
|
+
console.log(this.colors.warning('Could not save download state'));
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
|
|
@@ -366,7 +366,7 @@ getPartialFileSize(filePath) {
|
|
|
366
366
|
return stats.size;
|
|
367
367
|
}
|
|
368
368
|
} catch (error) {
|
|
369
|
-
console.log(this.colors.warning('
|
|
369
|
+
console.log(this.colors.warning('Could not read partial file size'));
|
|
370
370
|
}
|
|
371
371
|
return 0;
|
|
372
372
|
}
|
|
@@ -879,14 +879,14 @@ async downloadMultipleFiles(downloads) {
|
|
|
879
879
|
this.setPauseCallback(() => {
|
|
880
880
|
if (!pausedMessageShown) {
|
|
881
881
|
this.multiBar.stop();
|
|
882
|
-
console.log(this.colors.warning('
|
|
882
|
+
console.log(this.colors.warning('Paused. Press p to resume, a to add URL'));
|
|
883
883
|
pausedMessageShown = true;
|
|
884
884
|
}
|
|
885
885
|
});
|
|
886
886
|
|
|
887
887
|
this.setResumeCallback(() => {
|
|
888
888
|
if (pausedMessageShown) {
|
|
889
|
-
console.log(this.colors.success('
|
|
889
|
+
console.log(this.colors.success('Resumed. Press p to pause, a to add URL'));
|
|
890
890
|
pausedMessageShown = false;
|
|
891
891
|
}
|
|
892
892
|
});
|
|
@@ -1135,7 +1135,7 @@ async downloadSingleFileWithBar(fileBar, masterBar, totalFiles, totalTracking) {
|
|
|
1135
1135
|
});
|
|
1136
1136
|
|
|
1137
1137
|
// Don't clean up partial file on error - allow resume
|
|
1138
|
-
console.log(this.colors.info(
|
|
1138
|
+
console.log(this.colors.info(`Partial download saved for ${filename}. Restart to resume.`));
|
|
1139
1139
|
throw error;
|
|
1140
1140
|
}
|
|
1141
1141
|
}
|
|
@@ -1183,10 +1183,10 @@ async downloadFile(url, outputPath) {
|
|
|
1183
1183
|
if (fileUnchanged && partialSize < serverInfo.totalSize) {
|
|
1184
1184
|
startByte = partialSize;
|
|
1185
1185
|
resuming = true;
|
|
1186
|
-
this.loadingSpinner.succeed(this.colors.success(
|
|
1187
|
-
console.log(this.colors.info(
|
|
1186
|
+
this.loadingSpinner.succeed(this.colors.success(`Found partial download: ${this.formatBytes(partialSize)} of ${this.formatTotal(serverInfo.totalSize)}`));
|
|
1187
|
+
console.log(this.colors.info(`Resuming download from ${this.formatBytes(startByte)}`));
|
|
1188
1188
|
} else {
|
|
1189
|
-
this.loadingSpinner.warn(this.colors.warning('
|
|
1189
|
+
this.loadingSpinner.warn(this.colors.warning('File changed on server, starting fresh download'));
|
|
1190
1190
|
// Clean up partial file and state
|
|
1191
1191
|
if (fs.existsSync(tempFilePath)) {
|
|
1192
1192
|
fs.unlinkSync(tempFilePath);
|
|
@@ -1196,7 +1196,7 @@ async downloadFile(url, outputPath) {
|
|
|
1196
1196
|
} else {
|
|
1197
1197
|
this.loadingSpinner.stop();
|
|
1198
1198
|
if (partialSize > 0) {
|
|
1199
|
-
console.log(this.colors.warning('
|
|
1199
|
+
console.log(this.colors.warning('Server does not support resumable downloads, starting fresh'));
|
|
1200
1200
|
// Clean up partial file
|
|
1201
1201
|
if (fs.existsSync(tempFilePath)) {
|
|
1202
1202
|
fs.unlinkSync(tempFilePath);
|
|
@@ -1227,9 +1227,9 @@ async downloadFile(url, outputPath) {
|
|
|
1227
1227
|
|
|
1228
1228
|
if (!resuming) {
|
|
1229
1229
|
if (totalSize === 0) {
|
|
1230
|
-
console.log(this.colors.warning('
|
|
1230
|
+
console.log(this.colors.warning('Warning: Content-Length not provided, progress will be estimated'));
|
|
1231
1231
|
} else {
|
|
1232
|
-
console.log(this.colors.info(
|
|
1232
|
+
console.log(this.colors.info(`File size: ${this.formatTotal(totalSize)}`));
|
|
1233
1233
|
}
|
|
1234
1234
|
}
|
|
1235
1235
|
|
|
@@ -1416,36 +1416,31 @@ async downloadFile(url, outputPath) {
|
|
|
1416
1416
|
// Clean up state file
|
|
1417
1417
|
this.cleanupStateFile(stateFilePath);
|
|
1418
1418
|
|
|
1419
|
-
// Success
|
|
1420
|
-
console.log(this.colors.success('
|
|
1421
|
-
console.log(this.colors.primary('
|
|
1422
|
-
console.log(this.colors.purple('
|
|
1419
|
+
// Success message
|
|
1420
|
+
console.log(this.colors.success('Download completed!'));
|
|
1421
|
+
console.log(this.colors.primary('File saved to: ') + chalk.underline(outputPath));
|
|
1422
|
+
console.log(this.colors.purple('Total size: ') + this.formatBytes(downloaded));
|
|
1423
1423
|
|
|
1424
1424
|
if (resuming) {
|
|
1425
|
-
console.log(this.colors.info('
|
|
1426
|
-
console.log(this.colors.info('
|
|
1425
|
+
console.log(this.colors.info('Resumed from: ') + this.formatBytes(startByte));
|
|
1426
|
+
console.log(this.colors.info('Downloaded this session: ') + this.formatBytes(sessionDownloaded));
|
|
1427
1427
|
}
|
|
1428
|
-
|
|
1429
|
-
// Random success emoji
|
|
1430
|
-
const celebrationEmojis = ['π₯³', 'π', 'π', 'π', 'π―', 'π', 'β¨', 'π₯'];
|
|
1431
|
-
const randomEmoji = celebrationEmojis[Math.floor(Math.random() * celebrationEmojis.length)];
|
|
1432
|
-
console.log(this.colors.success(`${randomEmoji} Successfully downloaded! ${randomEmoji}`));
|
|
1433
1428
|
|
|
1434
1429
|
} catch (error) {
|
|
1435
1430
|
if (this.loadingSpinner && this.loadingSpinner.isSpinning) {
|
|
1436
|
-
this.loadingSpinner.fail(this.colors.error('
|
|
1431
|
+
this.loadingSpinner.fail(this.colors.error('Connection failed'));
|
|
1437
1432
|
}
|
|
1438
1433
|
if (this.progressBar) {
|
|
1439
1434
|
this.progressBar.stop();
|
|
1440
1435
|
}
|
|
1441
1436
|
|
|
1442
1437
|
// Don't clean up partial file on error - allow resume
|
|
1443
|
-
console.error(this.colors.error.bold('
|
|
1438
|
+
console.error(this.colors.error.bold('Download failed: ') + this.colors.warning(error.message));
|
|
1444
1439
|
|
|
1445
1440
|
if (error.name === 'AbortError') {
|
|
1446
|
-
console.log(this.colors.info('
|
|
1441
|
+
console.log(this.colors.info('Download state saved. You can resume later by running the same command.'));
|
|
1447
1442
|
} else {
|
|
1448
|
-
console.log(this.colors.info('
|
|
1443
|
+
console.log(this.colors.info('Partial download saved. Restart to resume from where it left off.'));
|
|
1449
1444
|
}
|
|
1450
1445
|
|
|
1451
1446
|
throw error;
|
|
@@ -1700,7 +1695,7 @@ setupFallbackKeyboardListener() {
|
|
|
1700
1695
|
};
|
|
1701
1696
|
|
|
1702
1697
|
process.stdin.on('data', handleKeypress);
|
|
1703
|
-
console.log(this.colors.info('
|
|
1698
|
+
console.log(this.colors.info('Keyboard active: p=pause/resume, a=add URL'));
|
|
1704
1699
|
}
|
|
1705
1700
|
}
|
|
1706
1701
|
|
|
@@ -1891,7 +1886,7 @@ for (let i = 0; i < urlIndices.length; i++) {
|
|
|
1891
1886
|
downloads.push({ url, outputPath });
|
|
1892
1887
|
}
|
|
1893
1888
|
|
|
1894
|
-
console.log(chalk.cyan.bold(
|
|
1889
|
+
console.log(chalk.cyan.bold(`Detected ${downloads.length} download(s):`));
|
|
1895
1890
|
downloads.forEach((download, index) => {
|
|
1896
1891
|
console.log(` ${index + 1}. ${chalk.yellow(download.url)} (URL)`);
|
|
1897
1892
|
});
|
|
@@ -1899,7 +1894,7 @@ console.log('');
|
|
|
1899
1894
|
|
|
1900
1895
|
// Handle multiple downloads
|
|
1901
1896
|
if (downloads.length > 1) {
|
|
1902
|
-
console.log(chalk.blue.bold(
|
|
1897
|
+
console.log(chalk.blue.bold(`Multiple downloads detected: ${downloads.length} files\n`));
|
|
1903
1898
|
|
|
1904
1899
|
// Prepare download objects
|
|
1905
1900
|
const downloadObjects = downloads.map((download, index) => {
|
|
@@ -1932,7 +1927,7 @@ if (downloads.length > 1) {
|
|
|
1932
1927
|
});
|
|
1933
1928
|
|
|
1934
1929
|
// Show download queue
|
|
1935
|
-
|
|
1930
|
+
console.log(chalk.cyan.bold('\nDownload Queue:'));
|
|
1936
1931
|
downloadObjects.forEach((downloadObj, index) => {
|
|
1937
1932
|
console.log(` ${chalk.yellow((index + 1).toString().padStart(2))}. ${chalk.green(downloadObj.filename)} ${chalk.gray('β')} ${downloadObj.outputPath}`);
|
|
1938
1933
|
});
|
|
@@ -1942,13 +1937,13 @@ if (downloads.length > 1) {
|
|
|
1942
1937
|
await downloader.downloadMultipleFiles(downloadObjects);
|
|
1943
1938
|
|
|
1944
1939
|
// Display individual file stats
|
|
1945
|
-
console.log(chalk.cyan.bold('\
|
|
1940
|
+
console.log(chalk.cyan.bold('\nFile Details:'));
|
|
1946
1941
|
downloadObjects.forEach((downloadObj) => {
|
|
1947
1942
|
displayFileStats(downloadObj.outputPath, downloader);
|
|
1948
1943
|
});
|
|
1949
1944
|
|
|
1950
1945
|
} catch (error) {
|
|
1951
|
-
console.error(chalk.red.bold('
|
|
1946
|
+
console.error(chalk.red.bold('Failed to download files: ') + chalk.yellow(error.message));
|
|
1952
1947
|
process.exit(1);
|
|
1953
1948
|
}
|
|
1954
1949
|
|
|
@@ -1975,26 +1970,26 @@ if (downloads.length > 1) {
|
|
|
1975
1970
|
|
|
1976
1971
|
// Check if file already exists
|
|
1977
1972
|
if (fs.existsSync(outputPath)) {
|
|
1978
|
-
console.log(chalk.yellow('
|
|
1973
|
+
console.log(chalk.yellow('File already exists: ') + outputPath);
|
|
1979
1974
|
console.log(chalk.gray(' Continuing will overwrite the existing file...'));
|
|
1980
1975
|
}
|
|
1981
1976
|
|
|
1982
|
-
console.log(chalk.green('\
|
|
1977
|
+
console.log(chalk.green('\nTarget: ') + chalk.bold(outputPath));
|
|
1983
1978
|
|
|
1984
1979
|
try {
|
|
1985
1980
|
await downloader.downloadFile(url, outputPath);
|
|
1986
1981
|
displayFileStats(outputPath, downloader);
|
|
1987
1982
|
|
|
1988
1983
|
} catch (error) {
|
|
1989
|
-
console.error(chalk.red.bold('
|
|
1984
|
+
console.error(chalk.red.bold('Failed to download file: ') + chalk.yellow(error.message));
|
|
1990
1985
|
|
|
1991
1986
|
// Clean up partial file if it exists
|
|
1992
1987
|
if (fs.existsSync(outputPath)) {
|
|
1993
1988
|
try {
|
|
1994
1989
|
fs.unlinkSync(outputPath);
|
|
1995
|
-
console.log(chalk.gray('
|
|
1990
|
+
console.log(chalk.gray('Cleaned up partial download'));
|
|
1996
1991
|
} catch (cleanupError) {
|
|
1997
|
-
|
|
1992
|
+
console.log(chalk.yellow('Could not clean up partial file: ') + cleanupError.message);
|
|
1998
1993
|
}
|
|
1999
1994
|
}
|
|
2000
1995
|
|