OpenByteDev/async-file-dl

View on GitHub
lib/index.ts

Summary

Maintainability
A
0 mins
Test Coverage
B
89%
import axios, { AxiosRequestConfig } from 'axios';
import filenamify = require('filenamify');
import fs = require('fs');
import path = require('path');
import { Readable } from 'stream';
import trim = require('trim-character');
const afs = fs.promises;

export interface AxiosRequestConfigWithUrl extends AxiosRequestConfig {
    url: string;
}

export let defaultConfig: AxiosRequestConfig = {
    method: 'get'
};

async function isDirectory(directory: string): Promise<boolean> {
    await afs.access(directory);
    const stat = await afs.lstat(directory);
    return stat.isDirectory();
}

function getFilename(file: string | null, url: string): string | null {
    if (typeof file !== 'string') {
        file = getFilenameFromUrl(url);
        if (file === null)
            return null;
    }
    return filenamify(file);
}

function getFilenameFromUrl(url: string): string | null {
    const pathname = new URL(url).pathname;
    if (typeof pathname !== 'undefined') {
        const basename = trim(path.basename(pathname).trim(), '/');
        if (basename !== '')
            return path.basename(pathname as string);
    }
    return null;
}

export async function download(
    url: string,
    directory?: string,
    file?: string | null): Promise<string>;
export async function download(
    config: AxiosRequestConfigWithUrl,
    directory?: string,
    file?: string | null): Promise<string>;
export async function download(
    urlOrConfig: string | AxiosRequestConfigWithUrl,
    directory: string= '.',
    file: string | null= null): Promise<string> {
    directory = path.resolve(directory);
    if (!(await isDirectory(directory)))
        throw new TypeError('Invalid directory specified');

    const config = {...defaultConfig,
                    ...(typeof urlOrConfig === 'string' ? { url: urlOrConfig } : urlOrConfig),
                    responseType: 'stream'};
    const url = (config.baseURL || '') + config.url;
    file = getFilename(file, url);
    if (file === null)
        throw new TypeError('Unable to get file');

    const response = await axios(config as any);

    const p = path.join(directory, file);

    const dataStream = response.data as Readable;
    const fileStream = fs.createWriteStream(p);
    dataStream.pipe(fileStream);

    return new Promise((resolve, reject) => {
        dataStream.on('end', () => resolve(p));
        dataStream.on('error', e => reject(e));
        fileStream.on('error', e => reject(e));
    }) as Promise<string>;
}