refactor(validation): abstract MIME type validation in validateAudioFile; check supported extensions in fileService; enhance docs and error logging

This commit is contained in:
xtrullor73
2024-05-27 15:20:12 -07:00
parent f8f6ae688e
commit f63bab30f0
4 changed files with 64 additions and 20 deletions

2
package-lock.json generated
View File

@@ -13,6 +13,7 @@
"dotenv": "^16.4.5",
"ffmetadata": "^1.7.0",
"fpcalc": "^1.3.0",
"mime-types": "^2.1.35",
"qs": "^6.12.1"
},
"bin": {
@@ -2080,6 +2081,7 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},

View File

@@ -11,6 +11,7 @@
"dotenv": "^16.4.5",
"ffmetadata": "^1.7.0",
"fpcalc": "^1.3.0",
"mime-types": "^2.1.35",
"qs": "^6.12.1"
},
"devDependencies": {

View File

@@ -1,20 +1,46 @@
import validateAudioFile from '../utils/validateAudioFiles.js';
import path from 'path';
/**
* Processes an array of file paths and returns an array containing only valid audio file paths.
* Processes an array of file paths and returns an array containing only valid and supported audio file paths.
*
* @param {string[]} filePaths - The array of file paths to process.
* @returns {Promise<string[]>} A promise that resolves to an array of valid audio file paths.
* @returns {Promise<string[]>} A promise that resolves to an array of valid and supported audio file paths.
* @throws {TypeError} - If the input is not an array of file paths (strings).
*/
export default async function validateAudioFiles(filePaths) {
// Validate input type
if (!(filePaths instanceof Array)) {
// Validate input type to ensure it is an array
if (!Array.isArray(filePaths)) {
throw new TypeError('Input must be an array of file paths (strings).');
}
/**
* Set of supported audio file extensions for this project.
* Currently, the project only supports .mp3 files.
*/
const supportedAudioExtensions = new Set(['.mp3']);
// Create a Promise for each file to validate it as an audio file
const validationPromises = filePaths.map((filePath) => validateAudioFile(filePath));
const validationPromises = filePaths.map(async (filePath) => {
// Validate the file as a generic audio file
const validFilePath = await validateAudioFile(filePath);
// If the file is a valid audio file, check if its extension is supported
if (validFilePath) {
const fileExtension = path.extname(validFilePath).toLowerCase();
if (supportedAudioExtensions.has(fileExtension)) {
// Return the file path if the extension is supported
return validFilePath;
} else {
console.error(`File ${path.basename(validFilePath)} is an audio file but ${fileExtension} format is not yet supported and so is ignored.`);
}
}
return null; // Return null if file is not valid or not supported
});
// Wait for all the validation promises to resolve
const validationResults = await Promise.all(validationPromises);
// Filter out any non-audio file paths (represented as null from validateAudioFile) and return resulting array
return validationResults.filter((result) => result.type !== null);
// Filter out any non-audio or unsupported file paths (represented as null) and return the resulting array
return validationResults.filter((filePath) => filePath !== null);
}

View File

@@ -1,34 +1,49 @@
import fs from 'fs/promises';
import path from 'path';
import mime from 'mime-types';
/**
* Validates whether a given file path points to a supported audio file.
* Logs an error for each file that is not an audio file or not a file at all and ignores it.
* Validates whether a given file path points to an audio file by checking its MIME type.
* Logs an error if the path is not a file or if the file is not a recognized audio type.
*
* @param {string} filePath - The absolute path to the file to validate.
* @returns {Promise<string|null>} - The file path if it is a supported audio file, otherwise null.
* @returns {Promise<string|null>} - The file path if it is a recognized audio file, otherwise null.
*/
export default async function validateAudioFile(filePath) {
try {
// Ensure that the path points to a file
const stats = await fs.lstat(filePath);
if (!stats.isFile()) {
console.error(`The path ${filePath} is not an audio file and is ignored.`);
console.error(`The path ${filePath} is not a file and is ignored.`);
return null; // Stop further checks and return null
}
// List of supported audio file extensions
const audioExtensions = ['.mp3', '.wav', '.aac', '.flac', '.ogg', '.aiff', '.m4a'];
// MIME type checking
const mimeType = mime.lookup(filePath);
console.log(`MIME type of ${filePath} is ${mimeType}`); // Log the MIME type
// Check if the file extension is in the list of supported audio formats
const fileExtension = path.extname(filePath).toLowerCase();
if (!audioExtensions.includes(fileExtension)) {
console.error(`File ${path.basename(filePath)} is not an audio file and is ignored.`);
return null; // Not an audio file, return null
// Set of recognized audio MIME types
const validAudioMimeTypes = new Set([
'audio/mpeg', // .mp3
'audio/wav', // .wav
'audio/x-wav', // .wav
'audio/flac', // .flac
'audio/x-flac', // .flac
'audio/ogg', // .ogg
'audio/aac', // .aac
'audio/aiff', // .aiff
'audio/x-aiff', // .aiff
'audio/x-m4a', // .m4a
]);
// Perform the MIME type validation
if (!validAudioMimeTypes.has(mimeType)) {
console.error(`File ${filePath} is not an audio file and is ignored.`);
return null; // Not a recognized audio file type, return null
}
return filePath; // The file is a supported audio file
return filePath; // The file is a recognized audio file
} catch (e) {
console.error(`Error validating file ${filePath}: ${e}`);
return null; // Return null on error to maintain a consistent return type
}
}