first commit
This commit is contained in:
commit
b5772e476b
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
songs/
|
||||||
|
json-data/
|
||||||
|
node_modules/
|
25
downloadSong.js
Normal file
25
downloadSong.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import https from 'https';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
async function downloadSong(downloadLink, folder, filename, songCount) {
|
||||||
|
console.log(`Downloading song #${songCount} ...`)
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
https.get(downloadLink, (response) => {
|
||||||
|
response.pipe(fs.createWriteStream(`${folder}/${filename}.mp3`))
|
||||||
|
.on('finish', () => {
|
||||||
|
console.log(`${songCount} songs downloaded successfully`);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.on('error', (error) => {
|
||||||
|
console.error('Error downloading song:', error);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('message', async (message) => {
|
||||||
|
const { downloadLink, folder, filename, songCount } = message;
|
||||||
|
await downloadSong(downloadLink, folder, filename, songCount);
|
||||||
|
process.send(`Song #${songCount} downloaded successfully`);
|
||||||
|
});
|
2
genres.http
Normal file
2
genres.http
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
GET https://api.brain.fm/v2/mental-states/6042a1bad80ae028b821e958/genres/
|
||||||
|
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiJGYmd3dndBT1JCTjlibVJmRUxLcHciLCJleHAiOjE2ODE5ODg5MTUuMzU2LCJpYXQiOjE2ODE5ODgwMTV9.hCs0U5Iv5bgaU9oYi9kmSl0A_gt3V9svL0NiCEvtZFr4DXiNQwkt30fUtwOofMmHUnoEKiRt8ER-K8n5vsXKc23gvvcKaYEzY1kipwlAkK_JiYslE1FXDGXBBN1VrunACWLY5sWyRt1og6WP20BaoD0gIvBr0iazN323mlpU_Ls4yOrid2J_veXAwmCkW_26Q2NbhJeEV2rlwnV95CtxmogYHkoDrDz65UncU5AUvl4ae96il9IN7MSI0DvFl3NutVnD3B2wPaNHNAIoMC1_nLwWl5Q5GMbgC2AW3B1U0pozg78ePFVWq-mKYY8IbgjESNKWg1gRF5oknsFq8shxjw
|
147
main.js
Normal file
147
main.js
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
27
package-lock.json
generated
Normal file
27
package-lock.json
generated
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "brainfm-extract",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "brainfm-extract",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "brainfm-extract",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "main.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^5.2.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user