import fs from 'fs'; import https from 'https'; import chalk from 'chalk'; import load from 'dotenv'; load() let songCount = 1; const AUTHTOKEN = process.env.AUTHTOKEN; const TOKEN = process.env.TOKEN; const USERID = process.env.USERID; if(!AUTHTOKEN || !TOKEN || !USERID) { console.error('Please enter all the required information'); process.exit(1); } let genres = [ "Beach", "Chimes & Bowls", "Forest", "Nightsounds", "Rain", "Rainforest", "River", "Thunder", "Underwater", "Wind", "Acoustic", "Atmospheric", "Cinematic", "Classical", "Drone", "Electronic", "Grooves", "Lofi", "Piano", "Post Rock", ]; let mentalStateIDs = { focus: "6042a1bad80ae028b821e954", sleep: "6042a1bad80ae028b821e95c", relax: "6042a1bad80ae028b821e958" } class DownloadQueue { constructor(maxConcurrency) { this.queue = []; this.activeDownloads = 0; this.maxConcurrency = maxConcurrency; } enqueue(url, folder, filename) { this.queue.push({url, folder, filename}); this.processQueue(); } async processQueue() { if (this.activeDownloads < this.maxConcurrency && this.queue.length > 0) { const {url, folder, filename} = this.queue.shift(); this.activeDownloads++; await downloadSong(url, folder, filename); console.log(`${songCount} songs downloaded successfully \n${this.queue.length} remaining`) this.activeDownloads--; this.processQueue(); } } } const downloadQueue = new DownloadQueue(3) for(const genre of genres) { console.log(chalk.red(`Starting genre ${genre}`)) for(const mentalState of Object.keys(mentalStateIDs)) { console.log(chalk.yellow(`Starting mental state ${mentalState}`)) // // Phase 1 : Fetch all song data // let data = await fetch(`https://api.brain.fm/v2/genres/${genre}/tracks?mentalStateId=${mentalStateIDs[mentalState]}&version=3`, { headers: { authorization: `Bearer ${AUTHTOKEN}` } }); data = await data.json(); data = formatAudioData(data.result); if (checkIfJsonExists(`./json-data/${mentalState}/${genre}.json`)) continue; ensureDirectory(`./json-data/${mentalState}`); let file = fs.createWriteStream(`./json-data/${mentalState}/${genre}.json`); file.write(JSON.stringify(data)); file.close(); // // Phase 2 : Download songs to device // console.log(chalk.green(`Started downloading ${genre} ${mentalState}`)) for (const song of data) { let activity = song.serving.track.tags.find(tag => tag.type === "activity").value; let NEL = song.neuralEffectLevel; let level = (NEL > 0.66 ? "high" : NEL > 0.33 ? "medium" : "low"); let hasMultipleNELs = song.hasMultipleNELs; let folder = `./songs/${genre}/${mentalState}/${activity}/${hasMultipleNELs ? "mixed" : level}` let filename = `${song.name.replace(' ', '_')}`; let downloadLink = `https://audio.brain.fm/${song.url}?userId=${USERID}&token=${TOKEN}`; downloadQueue.enqueue(downloadLink, folder, filename); } } }; async function downloadSong(downloadLink, folder, filename) { return new Promise((resolve, reject) => { ensureDirectory(folder) https.get(downloadLink, (response) => { response.pipe(fs.createWriteStream(`${folder}/${filename}.mp3`)) .on('finish', () => { songCount++ resolve(); }) .on('error', (error) => { console.error('Error downloading song:', error); reject(error); }); }); }); } function formatAudioData(arr) { return arr.map(item => { delete item.serving.track.similarTracks; return item; }); } function ensureDirectory(directory) { if (!fs.existsSync(directory)) { fs.mkdirSync(directory, { recursive: true }); } } function checkIfJsonExists(mentalState, genre) { const filePath = `./json-data/${mentalState}/${genre}.json`; return fs.existsSync(filePath); }