brainfm-extractor/main.js
2023-05-09 18:24:10 +02:00

158 lines
3.9 KiB
JavaScript

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);
}