2019-09-17 16:49:23 +02:00
|
|
|
var express = require('express');
|
2019-09-18 10:51:02 +02:00
|
|
|
var fs = require('fs');
|
2019-09-27 19:14:48 +02:00
|
|
|
var { getAudioDurationInSeconds } = require("get-audio-duration");
|
2019-09-18 10:51:02 +02:00
|
|
|
var path = require('path');
|
2019-09-19 23:28:19 +02:00
|
|
|
var urlParse = require("body-parser");
|
|
|
|
var id3 = require('node-id3');
|
2019-10-05 11:10:51 +02:00
|
|
|
var ytdl = require("ytdl-core");
|
|
|
|
var ffmpeg = require("fluent-ffmpeg");
|
2019-09-17 17:07:08 +02:00
|
|
|
|
2019-09-17 16:49:23 +02:00
|
|
|
var router = express.Router();
|
2019-09-20 23:04:06 +02:00
|
|
|
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");
|
2019-10-06 16:27:25 +02:00
|
|
|
res.header('Cache-Control', 'no-cache');
|
2019-09-20 23:04:06 +02:00
|
|
|
next();
|
|
|
|
});
|
2019-09-18 10:51:02 +02:00
|
|
|
const rootdir = path.join(__dirname, '/../');
|
2019-10-05 11:10:51 +02:00
|
|
|
ffmpeg.setFfmpegPath(rootdir + "bin/ffmpeg");
|
|
|
|
|
|
|
|
var downloadQueue = [];
|
2019-09-17 16:49:23 +02:00
|
|
|
|
|
|
|
/* GET home page. */
|
2019-09-18 10:51:02 +02:00
|
|
|
router.get('/', (_req, res, _next) => {
|
2019-09-17 16:49:23 +02:00
|
|
|
res.render('index', { title: 'Express' });
|
|
|
|
});
|
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
// Download route to download youtube video's
|
2019-10-05 11:10:51 +02:00
|
|
|
router.get('/download/:url', (req, res, _next) => {
|
|
|
|
ytdl.getInfo(req.params.url, (_err, info) => {
|
|
|
|
const index = downloadQueue.push({'progress': 0, 'info': info}) - 1;
|
|
|
|
let stream = ytdl(req.params.url, {
|
|
|
|
quality: "highestaudio"
|
|
|
|
//filter: 'audioonly',
|
|
|
|
});
|
|
|
|
|
|
|
|
ffmpeg(stream)
|
|
|
|
.audioBitrate(128)
|
|
|
|
.on("progress", p => {
|
|
|
|
if (downloadQueue[index]) downloadQueue[index].progress = p;
|
|
|
|
})
|
|
|
|
.save(`${rootdir}music/${info.title}.mp3`)
|
|
|
|
.on("end", () => {
|
|
|
|
downloadQueue.splice(index, 1);
|
|
|
|
res.json({ result: info });
|
|
|
|
});
|
2019-09-17 17:07:08 +02:00
|
|
|
});
|
2019-09-18 10:51:02 +02:00
|
|
|
});
|
|
|
|
|
2019-10-06 16:27:25 +02:00
|
|
|
router.get('/info/:id', (req, res, _next) => {
|
|
|
|
ytdl.getBasicInfo(req.params.id, (_err, info) => {
|
|
|
|
res.json({ result: info });
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2019-10-05 11:10:51 +02:00
|
|
|
router.get('/downloadqueue', (req, res, _next) => {
|
|
|
|
res.json({ result: downloadQueue });
|
|
|
|
})
|
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
function dbGet(type, id) {
|
2019-10-06 16:27:25 +02:00
|
|
|
JSON.parse(fs.readFileSync(rootdir + "database/albums.json").toString());
|
2019-09-20 23:04:06 +02:00
|
|
|
let db = {
|
2019-10-06 16:27:25 +02:00
|
|
|
song: JSON.parse(fs.readFileSync(rootdir + "database/songs.json").toString()),
|
|
|
|
album: JSON.parse(fs.readFileSync(rootdir + "database/albums.json").toString()),
|
|
|
|
artist: JSON.parse(fs.readFileSync(rootdir + "database/artists.json").toString())
|
2019-09-20 23:04:06 +02:00
|
|
|
};
|
|
|
|
let result;
|
|
|
|
|
|
|
|
if (id === 'all') {
|
|
|
|
result = db[type];
|
2019-09-26 22:04:41 +02:00
|
|
|
result.forEach(element => {
|
|
|
|
element.type = type;
|
|
|
|
});
|
2019-09-20 23:04:06 +02:00
|
|
|
} else {
|
|
|
|
id = parseInt(id);
|
|
|
|
db[type].forEach(element => {
|
|
|
|
if (id == element.id) {
|
|
|
|
result = element;
|
2019-09-26 22:04:41 +02:00
|
|
|
result.type = type;
|
2019-09-20 23:04:06 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-18 10:51:02 +02:00
|
|
|
router.get('/get/:type/:id', (req, res, _next) => {
|
2019-09-20 23:04:06 +02:00
|
|
|
// Get variables from url
|
2019-09-18 10:51:02 +02:00
|
|
|
const type = req.params.type;
|
|
|
|
const id = req.params.id;
|
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
// Check if all info is requested
|
2019-09-19 08:06:21 +02:00
|
|
|
if (id === 'all') {
|
2019-09-20 23:04:06 +02:00
|
|
|
res.json({ result: dbGet(type, id) });
|
2019-09-18 10:51:02 +02:00
|
|
|
} else {
|
2019-09-20 23:04:06 +02:00
|
|
|
// Split arguments and reset result
|
2019-09-19 08:06:21 +02:00
|
|
|
const arg = id.split(",");
|
2019-09-20 23:04:06 +02:00
|
|
|
resultArray = [];
|
|
|
|
|
|
|
|
// For each array in argument, make object in resultArray
|
|
|
|
for (let index = 0; index < arg.length; index++) {
|
|
|
|
resultArray[index] = dbGet(type, arg[index]);
|
2019-09-19 08:06:21 +02:00
|
|
|
}
|
2019-09-26 22:04:41 +02:00
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
// Print result
|
|
|
|
res.json({ result: resultArray });
|
2019-09-18 10:51:02 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
// Play route to stream track
|
2019-09-18 10:51:02 +02:00
|
|
|
router.get('/play/:track', (req, res, _next) => {
|
|
|
|
var key = req.params.track;
|
|
|
|
|
2019-09-27 19:14:48 +02:00
|
|
|
var music = rootdir + "music/" + key;
|
2019-09-18 10:51:02 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
// Image route to get album image
|
2019-09-18 10:51:02 +02:00
|
|
|
router.get('/image/:path', (req, res, _next) => {
|
|
|
|
const path = '/music/' + req.params.path
|
|
|
|
|
|
|
|
res.sendFile(path, { root: rootdir });
|
|
|
|
});
|
|
|
|
|
2019-09-20 23:04:06 +02:00
|
|
|
// Search route to search for a query in the db
|
2019-09-18 10:51:02 +02:00
|
|
|
router.get('/search/:query', (req, res, _next) => {
|
|
|
|
const query = req.params.query;
|
|
|
|
let result = [];
|
|
|
|
|
2019-09-19 08:06:21 +02:00
|
|
|
fs.readdir(rootdir + 'database/', (err, files) => {
|
2019-09-18 10:51:02 +02:00
|
|
|
files.forEach(file => {
|
|
|
|
|
2019-10-05 11:10:51 +02:00
|
|
|
if (file !== '.gitkeep') {
|
2019-09-18 10:51:02 +02:00
|
|
|
|
2019-10-05 11:10:51 +02:00
|
|
|
const content = require(rootdir + "database/" + file);
|
|
|
|
|
|
|
|
console.log(rootdir + "database/" + file);
|
|
|
|
|
|
|
|
content.forEach(element => {
|
|
|
|
if (element.name.match(query)) {
|
|
|
|
element.type = (file === 'songs.json' ? 'song' : (file === 'albums.json' ? 'album' : 'artist'));
|
|
|
|
result.push(element);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
2019-09-18 10:51:02 +02:00
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
res.json({result: result});
|
|
|
|
});
|
|
|
|
});
|
2019-09-17 17:07:08 +02:00
|
|
|
|
2019-09-26 22:04:41 +02:00
|
|
|
|
2019-09-19 23:28:19 +02:00
|
|
|
router.use(urlParse.urlencoded({extended : true}));
|
2019-09-20 23:04:06 +02:00
|
|
|
// Analyse route to scan .mp3 ID3 tags
|
2019-09-19 23:28:19 +02:00
|
|
|
router.get('/analyse/*', (req, res, _next) => {
|
2019-09-26 22:04:41 +02:00
|
|
|
let file = req.params[0];
|
2019-09-19 23:28:19 +02:00
|
|
|
if (fs.existsSync(file)) {
|
|
|
|
var result = id3.read(file);
|
2019-09-26 22:04:41 +02:00
|
|
|
if (typeof result.image.imageBuffer !== 'undefined') {
|
2019-09-20 23:04:06 +02:00
|
|
|
result.image.base64 = result.image.imageBuffer.toString('base64');
|
|
|
|
}
|
2019-09-19 23:28:19 +02:00
|
|
|
} else {
|
2019-09-20 23:04:06 +02:00
|
|
|
var result = `File ${file} not found`;
|
2019-09-19 23:28:19 +02:00
|
|
|
}
|
|
|
|
res.json({ result: result });
|
|
|
|
});
|
|
|
|
|
2019-09-27 19:14:48 +02:00
|
|
|
router.get('/duration/:file', (req, res, _next) => {
|
|
|
|
getAudioDurationInSeconds(__dirname + '/../music/' + req.params.file).then(duration => res.json({result: duration}));
|
|
|
|
})
|
|
|
|
|
2019-10-06 16:27:25 +02:00
|
|
|
router.get('/update/:database/:index/:field/:value', (req, res, _next) => {
|
|
|
|
const path = rootdir + "database/" + req.params.database + ".json";
|
|
|
|
const db = require(path);
|
|
|
|
db[req.params.index][req.params.field] = req.params.value;
|
|
|
|
fs.writeFileSync(path, JSON.stringify(db));
|
|
|
|
|
|
|
|
res.json({ result: true });
|
|
|
|
});
|
|
|
|
|
|
|
|
router.get('/insert/:database/', (req, res, _next) => {
|
|
|
|
const path = rootdir + "database/" + req.params.database + ".json";
|
|
|
|
const db = JSON.parse(fs.readFileSync(path).toString());
|
|
|
|
const index = db.push({}) - 1;
|
|
|
|
db[index].id = index;
|
|
|
|
fs.writeFileSync(path, JSON.stringify(db));
|
|
|
|
res.json({ result: db[index] });
|
|
|
|
});
|
|
|
|
|
2019-09-17 16:49:23 +02:00
|
|
|
module.exports = router;
|