Comparing version 0.17.3 to 0.17.4
@@ -8,2 +8,5 @@ const axios = require('axios'); | ||
class Downloader { | ||
/** | ||
* Creates a new Downloader instance | ||
*/ | ||
constructor() { | ||
@@ -15,3 +18,3 @@ this.debug = false; | ||
/** | ||
* Set the debug mode for the downloader | ||
* Sets the debug mode for the downloader | ||
* @param {boolean} value - Whether to enable debug mode | ||
@@ -24,3 +27,3 @@ */ | ||
/** | ||
* Detect the file type based on its byte signature | ||
* Detects the file type based on its byte signature | ||
* @param {Buffer} buffer - The buffer containing the file data | ||
@@ -35,4 +38,12 @@ * @returns {string|null} The detected file extension or null if not recognized | ||
{ bytes: [0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50], ext: 'webp' }, | ||
{ bytes: [0x25, 0x50, 0x44, 0x46], ext: 'pdf' }, | ||
{ bytes: [0x50, 0x4B, 0x03, 0x04], ext: 'zip' }, | ||
{ bytes: [0x3C, 0x3F, 0x78, 0x6D, 0x6C], ext: 'svg' }, | ||
{ bytes: [0x42, 0x4D], ext: 'bmp' }, | ||
{ bytes: [0x49, 0x49, 0x2A, 0x00], ext: 'tiff' }, | ||
{ bytes: [0x4D, 0x4D, 0x00, 0x2A], ext: 'tiff' }, | ||
{ bytes: [0x66, 0x74, 0x79, 0x70], ext: 'mp4' }, | ||
{ bytes: [0x6D, 0x70, 0x34], ext: 'mp4' }, | ||
{ bytes: [0x52, 0x49, 0x46, 0x46], ext: 'avi' }, | ||
{ bytes: [0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x41], ext: 'm4a' }, | ||
{ bytes: [0x49, 0x44, 0x33], ext: 'mp3' }, | ||
{ bytes: [0xFF, 0xFB], ext: 'mp3' }, | ||
]; | ||
@@ -46,2 +57,8 @@ | ||
// Check if the file might be a text file | ||
const isText = buffer.every(byte => byte < 128); // ASCII check | ||
if (isText) { | ||
return 'txt'; | ||
} | ||
return null; | ||
@@ -51,3 +68,3 @@ } | ||
/** | ||
* Get file information from the given URL | ||
* Gets file information from the given URL | ||
* @param {string} fileUrl - The URL of the file to download | ||
@@ -76,4 +93,3 @@ * @returns {Promise<Object>} An object containing fileSize and filename | ||
let filename = ''; | ||
let extension = ''; | ||
let { filename, extension } = parseUrl(fileUrl); | ||
@@ -84,30 +100,11 @@ const contentDisposition = response.headers['content-disposition']; | ||
if (filenameMatch) { | ||
filename = filenameMatch[1]; | ||
const extMatch = filename.match(/\.([^.]+)$/); | ||
if (extMatch) { | ||
extension = extMatch[1]; | ||
const dispositionFilename = filenameMatch[1]; | ||
const dispositionExtMatch = dispositionFilename.match(/\.([^.]+)$/); | ||
if (dispositionExtMatch) { | ||
extension = dispositionExtMatch[1]; | ||
} | ||
filename = dispositionFilename.slice(0, -extension.length - 1); | ||
} | ||
} | ||
if (!filename) { | ||
const { filename: parsedFilename, searchParams } = parseUrl(fileUrl); | ||
if (parsedFilename.toLowerCase() === 'download.php' && searchParams.has('url')) { | ||
const encodedUrl = searchParams.get('url'); | ||
try { | ||
const decodedUrl = Buffer.from(encodedUrl, 'base64').toString('utf-8'); | ||
const { filename: decodedFilename } = parseUrl(decodedUrl); | ||
filename = decodedFilename; | ||
} catch (error) { | ||
log(colorize(COLORS.WARNING)(`Failed to decode URL parameter: ${error.message}`), this.debug); | ||
} | ||
} else { | ||
filename = parsedFilename; | ||
} | ||
const extMatch = filename.match(/\.([^.]+)$/); | ||
if (extMatch) { | ||
extension = extMatch[1]; | ||
} | ||
} | ||
if (!extension) { | ||
@@ -121,8 +118,18 @@ const contentType = response.headers['content-type']; | ||
'image/webp': 'webp', | ||
'application/pdf': 'pdf', | ||
'application/zip': 'zip', | ||
'image/svg+xml': 'svg', | ||
'image/bmp': 'bmp', | ||
'image/tiff': 'tiff', | ||
'video/mp4': 'mp4', | ||
'video/webm': 'webm', | ||
'video/x-msvideo': 'avi', | ||
'video/avi': 'avi', | ||
'audio/mp4': 'm4a', | ||
'audio/x-m4a': 'm4a', | ||
'audio/mpeg': 'mp3', | ||
'audio/ogg': 'ogg' | ||
'audio/mp3': 'mp3', | ||
'text/plain': 'txt', | ||
'text/html': 'html', | ||
'text/css': 'css', | ||
'text/javascript': 'js', | ||
'application/json': 'json', | ||
'application/xml': 'xml', | ||
}; | ||
@@ -137,5 +144,2 @@ extension = mimeToExt[contentType.split(';')[0]] || ''; | ||
responseType: 'arraybuffer', | ||
validateStatus: function (status) { | ||
return status < 500; | ||
}, | ||
maxContentLength: 1024 * 1024, | ||
@@ -147,13 +151,7 @@ timeout: 5000 | ||
if (!filename) { | ||
filename = 'downloaded_file'; | ||
} | ||
const fullFilename = `${filename}${extension ? `.${extension}` : ''}`; | ||
if (extension && !filename.endsWith(`.${extension}`)) { | ||
filename = `${filename}.${extension}`; | ||
} | ||
log(colorize(COLORS.INFO)(`File size: ${fileSize !== null ? colorize(COLORS.HIGHLIGHT)(formatBytes(fileSize)) : 'unknown'}`), this.debug); | ||
log(colorize(COLORS.INFO)(`File name: ${colorize(COLORS.HIGHLIGHT)(filename)}`), this.debug); | ||
return { fileSize, filename }; | ||
log(colorize(COLORS.INFO)(`File name: ${colorize(COLORS.HIGHLIGHT)(fullFilename)}`), this.debug); | ||
return { fileSize, filename: fullFilename }; | ||
} catch (error) { | ||
@@ -171,3 +169,3 @@ if (error.response) { | ||
/** | ||
* Get the temporary path for a chunk file | ||
* Gets the temporary path for a chunk file | ||
* @param {number} index - The index of the chunk | ||
@@ -181,3 +179,3 @@ * @returns {string} The temporary file path for the chunk | ||
/** | ||
* Download a chunk of the file | ||
* Downloads a chunk of the file | ||
* @param {string} fileUrl - The URL of the file to download | ||
@@ -239,3 +237,3 @@ * @param {number} start - The starting byte of the chunk | ||
/** | ||
* Download the entire file | ||
* Downloads the entire file | ||
* @param {string} fileUrl - The URL of the file to download | ||
@@ -341,2 +339,3 @@ * @param {string} output - The output file path | ||
const data = fs.readFileSync(chunkPath); | ||
writer.write(data); | ||
@@ -349,2 +348,3 @@ fs.unlinkSync(chunkPath); | ||
const averageSpeed = (fileSize / totalTime); | ||
log(colorize(COLORS.SUCCESS)(`File downloaded successfully to ${outputPath}`), this.debug, true); | ||
@@ -359,2 +359,2 @@ log(colorize(COLORS.INFO)(`Total time: ${colorize(COLORS.HIGHLIGHT)(formatTime(totalTime))}`), this.debug, true); | ||
module.exports = Downloader | ||
module.exports = Downloader; |
@@ -91,2 +91,3 @@ const chalk = require('chalk'); | ||
****/ | ||
function parseUrl(fileUrl) { | ||
@@ -125,17 +126,13 @@ try { | ||
let extension = '.mp4'; | ||
if (filename.includes('.')) { | ||
extension = filename.substring(filename.lastIndexOf('.')); | ||
filename = filename.substring(0, filename.lastIndexOf('.')); | ||
// Remove any existing extension from the filename | ||
const extensionMatch = filename.match(/\.([^.]+)$/); | ||
let extension = ''; | ||
if (extensionMatch) { | ||
extension = extensionMatch[1]; | ||
filename = filename.slice(0, -extension.length - 1); | ||
} | ||
if (!filename) { | ||
const randomString = Math.random().toString(36).substring(2, 8); | ||
filename = `downloaded_file_${randomString}${extension}`; | ||
} else { | ||
filename = `${filename}${extension}`; | ||
} | ||
return { | ||
filename, | ||
extension, | ||
searchParams, | ||
@@ -150,4 +147,7 @@ protocol: url.protocol.slice(0, -1), | ||
console.error(`Error parsing URL: ${error.message}`); | ||
const randomString = Math.random().toString(36).substring(2, 8); | ||
return { filename: `downloaded_file_${randomString}.mp4`, searchParams: new URLSearchParams() }; | ||
return { | ||
filename: `downloaded_file_${Math.random().toString(36).substring(2, 8)}`, | ||
extension: '', | ||
searchParams: new URLSearchParams() | ||
}; | ||
} | ||
@@ -154,0 +154,0 @@ } |
{ | ||
"name": "nexidyn", | ||
"version": "0.17.3", | ||
"version": "0.17.4", | ||
"description": "A fast multi-threaded downloader CLI tool", | ||
@@ -5,0 +5,0 @@ "main": "lib/main.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30067