I created a function to fetch mp3 files that are inside user's storage drives that takes an array of directories that needed to be searched. After receiving full list of music files in an array, I used that as an argument in another function that fetches it's metadata (using music metadata). So far my code is working perfectly when there are no files it returns empty array otherwise and array of objects containing their metadata. Here is My code :
const find = require('find') ;
const mm = require('music-metadata') ;
const directories = ["C:\\Users\\{UserNamehere}\\Music\\"] // you can add more directories
async function parseMetadata(files){
let metadata ;
data = files.map(async (file) => {
metadata = await mm.parseFile(file,{duration:true}) ;
m = metadata.common ;
return m ;
}) ;
const musicarray = await Promise.all(data) ;
return musicarray ;
}
function fetchNewSongs(dirs){
let res,musicfiles = [] ;
dirs.forEach((path)=>{
res = find.fileSync(/\.mp3/i,path) ;
musicfiles.push(...res) ;
});
if (musicfiles.length !== 0){
return parseMetadata(musicfiles) ;
}
else{
return Promise.resolve([]) ;
}
}
fetchNewSongs(directories).then( value => {
console.log(value)
})
Problem arises when any music file is corrupted or it's metadata cannot be fetched by music-metadata
causing the flow of parsing the metadata list to stop. I tried to rename a .txt
to .mp3
to reconstruct situation of a corrupted file. What I want is whenever parsing the metadata of a particular music file if an error occurs it just return empty array and then continue searching for other files. After the process is complete then removing those elements of array having empty objects.
I think you are missing a try/catch in your map function:
Mocked version:
const mm = {
parseFile(file) {
return Promise.reject("Bad format");
},
};
async function parseMetadata(files) {
let metadata = files.map(async (file) => {
try {
metadata = await mm.parseFile(file, { duration: true });
} catch (error) {
return [];
}
m = metadata.common;
return m;
});
return Promise.all(metadata);
}
async function fetchNewSongs(dirs = ["foo", "bar", "baz"]) {
return parseMetadata(dirs);
}
fetchNewSongs().then(console.log, console.error);
// output : [ [], [], [] ]
As an addition you might go for a for
loop and avoid having to filter your array afterward
const mm = {
parseFile(file) {
return Promise.reject("Bad format");
},
};
async function parseMetadata(files) {
const metadataCollection = [];
for (const file of files) {
try {
const metadata = await mm.parseFile(file, { duration: true });
metadataCollection.push(metadata);
} catch (error) {
console.warn(error);
}
}
return metadataCollection;
}
async function fetchNewSongs(dirs = ["foo", "bar", "baz"]) {
return parseMetadata(dirs);
}
fetchNewSongs().then(console.log, console.error);
// outputs:
// Bad format
// Bad format
// Bad format
// []