Skip to content

Commit

Permalink
Add and enhance download options configuration (#9)
Browse files Browse the repository at this point in the history
This pull request enhances the YTMP3-JS library by adding configurable options for both the download and conversion processes. The new `DownloadOptions` typedef and resolver function ensure valid configurations, while the global configuration module provides a convenient way to manage CLI usage behavior. Additionally, improvements and fixes to existing functions ensure a more robust and user-friendly experience.

Note:
The global configuration module are still in development and some options might changes in the future.

Signed-off-by: Ryuu Mitsuki <dhefam31@gmail.com>
  • Loading branch information
mitsuki31 committed Jul 3, 2024
2 parents d2414ad + 2de438c commit cb0ae03
Show file tree
Hide file tree
Showing 5 changed files with 442 additions and 72 deletions.
174 changes: 174 additions & 0 deletions config/ytmp3-js.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* **YTMP3-JS Global Configuration Module**
*
* This module provides configuration options for the **YTMP3-JS** library,
* allowing you to customize the download and conversion process for YouTube
* videos to audio files when using the command-line interface (CLI).
*
* The configuration is divided into two main sections:
*
* - `downloadOptions`: Options related to the download process.
* - `audioConverterOptions`: Options related to the audio conversion process.
*
* ### Usage
*
* Modify the configuration options as needed before running the CLI commands
* to ensure the download and conversion processes behave as desired.
*
* > **NOTE**
* > This configuration is intended for non-programmatic use. For programmatic
* > configurations, consider directly using the library's API.
*
* Project: [ytmp3-js](https://github.com/mitsuki31/ytmp3-js)
*
* @module ytmp3-js_config
* @since 1.0.0
*/

'use strict';

const path = require('node:path');

module.exports = {
/**
* Options to configure the download process.
*
* @type {module:ytmp3~DownloadOptions}
* @namespace
*/
downloadOptions: {
/**
* The current working directory path.
*
* If this option is set to `null` or `undefined`, the path defaults to the
* current directory ('.'). When navigating to another directory, it will be
* set to that directory.
*
* @type {?string}
* @default '.'
*/
cwd: path.resolve(__dirname, '..'),
/**
* The output directory path for the downloaded files.
*
* This path is resolved relative to the `cwd` option. For example, if `cwd`
* is set to "directoryA" and `outDir` is set to "music", this option will
* resolve to "/path/to/directoryA/music".
*
* If this option is `null` or `undefined`, it defaults to the current directory.
*
* @type {?string}
* @default '.'
*/
outDir: 'download',
/**
* Whether to convert the downloaded audio files to a specific format.
*
* Set this to `false` if you want to keep the downloaded audio files in
* AAC (Advanced Audio Coding) format with a '.m4a' extension.
*
* To configure the audio converter options, refer to the `audioConverterOptions`
* field.
*
* @type {?boolean}
* @default true
*/
convertAudio: true,
/**
* Whether to suppress the output log messages during the download process.
*
* If this option is enabled, all informational and error messages, including
* the download progress bar, will be suppressed.
*
* @type {?boolean}
* @default false
*/
quiet: false
},
/**
* Options to configure the audio converter options.
*
* This field will be ignored if the `downloadOptions.convertAudio` option
* is set to `false`.
*
* <pre>
* ================================ [ WARNING ] ================================
* >>>> USER EXPERIENCED ONLY! <<<<
* All options in this field depend on the respective libraries included with
* the FFmpeg library installed on your system. It is possible that some codecs
* and encoders may not be included in your FFmpeg installation. Please check
* what codecs and encoders are supported before changing these options.
*
* If your system does not have the FFmpeg binaries and libraries installed,
* it is recommended to disable the `downloadOptions.convertAudio` option.
* The program will automatically detect the absence of FFmpeg and skip the
* audio conversion to avoid errors.
* ================================ ----------- ================================
* </pre>
*
* @type {module:audioconv~ConvertAudioOptions}
* @namespace
*/
audioConverterOptions: {
/**
* The output audio format to use.
*
* The output file's extension will be derived from this value.
* If unspecified or set to a nullable value, it defaults to 'mp3'.
*
* @type {?string}
* @default 'mp3'
*/
format: 'mp3',
/**
* The output audio codec to use.
*
* If unspecified or set to a nullable value, it will defaults to 'libmp3lame'
* (MP3 codec).
*
* @type {?string}
* @default 'libmp3lame'
*/
codec: 'libmp3lame',
/**
* The output audio bitrate in kbps, with an optional 'k' suffix.
*
* @type {?(number | string)}
* @default 128
*/
bitrate: 128,
/**
* The output audio sampling frequency in Hertz (Hz).
*
* @type {?number}
* @default 44100
*/
frequency: 44100,
/**
* The number of output audio channels.
*
* Set this option to 2 for stereo, or 1 for mono.
*
* @type {?number}
* @default 2
*/
channels: 2,
/**
* Whether to delete the original file after conversion.
*
* If you set this to `false`, the original or unconverted file will remain
* available in the output directory.
*
* @type {?boolean}
* @default true
*/
deleteOld: true,
/**
* Whether to suppress the conversion progress and error messages.
*
* @type {?boolean}
* @default false
*/
quiet: false
}
};
11 changes: 9 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const {
} = require('./lib/audioconv');
const { logger: log } = require('./lib/utils');
const ytmp3 = require('./lib/ytmp3');
const {
downloadOptions,
audioConverterOptions
} = require('./config/ytmp3-js.config');

const DEFAULT_BATCH_FILE = path.join(__dirname, 'downloads.txt');

Expand Down Expand Up @@ -83,15 +87,18 @@ module.exports = Object.freeze({
if (require.main === module) {
const input = getInput();

// Assign the `audioConverterOptions` to `downloadOptions`
Object.assign(downloadOptions, { converterOptions: audioConverterOptions });

if (input instanceof URL) {
log.info('URL input detected!');
ytmp3.singleDownload(input);
ytmp3.singleDownload(input, downloadOptions);
} else {
if (input !== DEFAULT_BATCH_FILE && !fs.existsSync(input)) {
log.error(`Batch file named \x1b[93m${input}\x1b[0m does not exist`);
log.error('Aborted');
process.exit(1);
}
ytmp3.batchDownload(input);
ytmp3.batchDownload(input, downloadOptions);
}
}
2 changes: 1 addition & 1 deletion jsdoc.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
recurseDepth: 2,
plugins: [ 'plugins/markdown' ],
source: {
include: [ 'lib' ],
include: [ 'lib', 'config' ],
exclude: [ 'docs', 'node_modules' ],
includePattern: /.+\.[tj]s(doc|x)?$/,
excludePattern: /(^|\/|\\)_/
Expand Down
31 changes: 21 additions & 10 deletions lib/audioconv.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const { logger: log } = require('./utils');
* @property {string} [codec='libmp3lame'] - The audio codec to use (e.g., `'libmp3lame'`).
* @property {number} [channels=2] - The number of audio channels (`2` for stereo).
* @property {boolean} [deleteOld=false] - Whether to delete the original file after conversion.
* @property {boolean} [quiet=false] - Whether to suppress the conversion progress and error message or not.
*
* @since 1.0.0
* @see {@link module:audioconv~defaultOptions defaultOptions}
Expand All @@ -65,6 +66,7 @@ const { logger: log } = require('./utils');
* @property {string} codec - The audio codec to use (e.g., `'libmp3lame'`).
* @property {number} channels - The number of audio channels (`2` for stereo).
* @property {boolean} deleteOld - Whether to delete the original file after conversion.
* @property {boolean} quiet - Whether to suppress the conversion progress and error message or not.
*
* @since 1.0.0
* @see {@link module:audioconv~defaultOptions defaultOptions}
Expand Down Expand Up @@ -92,7 +94,8 @@ const defaultOptions = Object.freeze({
frequency: 44100,
codec: 'libmp3lame',
channels: 2,
deleteOld: false
deleteOld: false,
quiet: false
});

/**
Expand Down Expand Up @@ -122,7 +125,10 @@ function resolveOptions(options) {
: defaultOptions.channels,
deleteOld: (typeof options?.deleteOld === 'boolean')
? options.deleteOld
: defaultOptions.deleteOld
: defaultOptions.deleteOld,
quiet: (typeof options?.quiet === 'boolean')
? options.quiet
: defaultOptions.quiet
};
}

Expand Down Expand Up @@ -212,6 +218,7 @@ async function convertAudio(inFile, options = defaultOptions) {
* @type {ResolvedConvertAudioOptions}
*/
options = resolveOptions(options);
const { quiet } = options; // Extract the 'quiet' field

// Check whether the given audio file is exist
if (!fs.existsSync(inFile)) {
Expand All @@ -238,13 +245,15 @@ async function convertAudio(inFile, options = defaultOptions) {
path.extname(outFile).replace('.', '')
];

log.info(`Processing audio for \x1b[93m${
quiet || log.info(`Processing audio for \x1b[93m${
noExtRegex.exec(ioBaseFile[0])[1]}\x1b[0m ...`);

// Check whether the `ffmpeg` binary is installed
if (!(await checkFfmpeg())) {
log.error('Cannot find `ffmpeg` on your system');
log.error('Audio conversion aborted');
if (!quiet) {
log.error('Cannot find `ffmpeg` on your system');
log.error('Audio conversion aborted');
}
throw new Error('Cannot find `ffmpeg` binary on your system');
}

Expand All @@ -260,17 +269,19 @@ async function convertAudio(inFile, options = defaultOptions) {

// Handlers
.on('error', (err) => {
process.stdout.write('\n');
log.error('Failed to convert the audio file');
console.error('Caused by:', err.message);
if (!quiet) {
process.stdout.write('\n');
log.error('Failed to convert the audio file');
console.error('Caused by:', err.message);
}
reject(err);
})
.on('progress', (info) => {
// Write the progress information to the console
process.stdout.write(createConversionProgress(info, extnames));
quiet || process.stdout.write(createConversionProgress(info, extnames));
})
.on('end', async () => {
process.stdout.write('\n');
quiet || process.stdout.write('\n');

// Remove the old audio file if `deleteOld` option is true
if (options.deleteOld) {
Expand Down
Loading

0 comments on commit cb0ae03

Please sign in to comment.