var express = require('express'); var YoutubeMp3Downloader = require("youtube-mp3-downloader"); var fs = require('fs'); var path = require('path'); var urlParse = require("body-parser"); var id3 = require('node-id3'); var router = express.Router(); router.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); var YD = new YoutubeMp3Downloader({ "ffmpegPath": path.join(__dirname + "/../bin/ffmpeg"), "outputPath": path.join(__dirname + "/../music"), "youtubeVideoQuality": "highest", "queueParallelism": 1, "progressTimeout": 2000 }); const rootdir = path.join(__dirname, '/../'); /* GET home page. */ router.get('/', (_req, res, _next) => { res.render('index', { title: 'Express' }); }); // Download route to download youtube video's router.get('/download', (req, res, _next) => { YD.download(req.query.url); YD.on('finished', (err, data) => { if (err) { res.json({ result: err }); } else { res.json({ result: data }); } }); }); function dbGet(type, id) { let db = { song: require(rootdir + 'database/songs.json'), album: require(rootdir + "database/albums.json"), artist: require(rootdir + "database/artists.json") }; let result; if (id === 'all') { result = db[type]; } else { id = parseInt(id); db[type].forEach(element => { if (id == element.id) { result = element; } }); } return result; } router.get('/get/:type/:id', (req, res, _next) => { // Get variables from url const type = req.params.type; const id = req.params.id; // Check if all info is requested if (id === 'all') { res.json({ result: dbGet(type, id) }); } else { // Split arguments and reset result const arg = id.split(","); resultArray = []; // TODO // OK, for some reason this script works absolutely fine when run the fist time, // However, if you run any other get url or refresh the page it will either throw a circulation error or return a bunch of null values // I have no idea what is causing this but i am absolutely fucking done with it right now // If you read this and you know how to fix it, please change it // For each array in argument, make object in resultArray for (let index = 0; index < arg.length; index++) { resultArray[index] = dbGet(type, arg[index]); // Add song info if id is given if (typeof resultArray[index].song !== 'undefined') { for (let song = 0; song < resultArray[index].song.length; song++) { resultArray[index].song[song] = dbGet('song', resultArray[index].song[song]); } } // Add artist info if id is given if (typeof resultArray[index].artist !== 'undefined') { for (let artist = 0; artist < resultArray[index].artist.length; artist++) { resultArray[index].artist[artist] = dbGet('artist', resultArray[index].artist[artist]); } } // Add album info if id is given if (typeof resultArray[index].album !== 'undefined') { for (let album = 0; album < resultArray[index].album.length; album++) { resultArray[index].album[album] = dbGet('album', resultArray[index].album[album]); } } } // Print result res.json({ result: resultArray }); } }); // Play route to stream track router.get('/play/:track', (req, res, _next) => { var key = req.params.track; var music = rootdir + "music/" + key + ".mp3"; var stat = fs.statSync(music); range = req.headers.range; var readStream; if (range !== undefined) { var parts = range.replace(/bytes=/, "").split("-"); var partial_start = parts[0]; var partial_end = parts[1]; if ( (isNaN(partial_start) && partial_start.length > 1) || (isNaN(partial_end) && partial_end.length > 1) ) { return res.sendStatus(500); //ERR_INCOMPLETE_CHUNKED_ENCODING } var start = parseInt(partial_start, 10); var end = partial_end ? parseInt(partial_end, 10) : stat.size - 1; var content_length = end - start + 1; res.status(206).header({ "Content-Type": "audio/mpeg", "Content-Length": content_length, "Content-Range": "bytes " + start + "-" + end + "/" + stat.size }); readStream = fs.createReadStream(music, { start: start, end: end }); } else { res.header({ "Content-Type": "audio/mpeg", "Content-Length": stat.size }); readStream = fs.createReadStream(music); } readStream.pipe(res); }); // Image route to get album image router.get('/image/:path', (req, res, _next) => { const path = '/music/' + req.params.path res.sendFile(path, { root: rootdir }); }); // Search route to search for a query in the db router.get('/search/:query', (req, res, _next) => { const query = req.params.query; let result = []; fs.readdir(rootdir + 'database/', (err, files) => { files.forEach(file => { const content = require(rootdir + 'database/' + file); content.forEach(element => { if (element.name.match(query)) { element.foundIn = file; result.push(element); } }); }); res.json({result: result}); }); }); router.use(urlParse.urlencoded({extended : true})); // Analyse route to scan .mp3 ID3 tags router.get('/analyse/*', (req, res, _next) => { let file = '/' + req.params[0]; if (fs.existsSync(file)) { var result = id3.read(file); if (result.image.imageBuffer) { result.image.base64 = result.image.imageBuffer.toString('base64'); } } else { var result = `File ${file} not found`; } res.json({ result: result }); }); module.exports = router;