import fs from 'fs'; import https from 'https'; import chalk from 'chalk'; let songCount = 1; const AUTHTOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiJGYmd3dndBT1JCTjlibVJmRUxLcHciLCJleHAiOjE2ODE5ODg5MTUuMzU2LCJpYXQiOjE2ODE5ODgwMTV9.hCs0U5Iv5bgaU9oYi9kmSl0A_gt3V9svL0NiCEvtZFr4DXiNQwkt30fUtwOofMmHUnoEKiRt8ER-K8n5vsXKc23gvvcKaYEzY1kipwlAkK_JiYslE1FXDGXBBN1VrunACWLY5sWyRt1og6WP20BaoD0gIvBr0iazN323mlpU_Ls4yOrid2J_veXAwmCkW_26Q2NbhJeEV2rlwnV95CtxmogYHkoDrDz65UncU5AUvl4ae96il9IN7MSI0DvFl3NutVnD3B2wPaNHNAIoMC1_nLwWl5Q5GMbgC2AW3B1U0pozg78ePFVWq-mKYY8IbgjESNKWg1gRF5oknsFq8shxjw"; 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=FbgwvwAORBN9bmRfELKpw&token=1Uah43y3X33F7ERFwx-_P` 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); }