move
All checks were successful
continuous-integration/drone Build is passing

This commit is contained in:
Artem Anufrij
2023-02-08 12:30:56 +01:00
commit cff48aaada
44 changed files with 12200 additions and 0 deletions

88
router/activitypub.js Normal file
View File

@@ -0,0 +1,88 @@
const express = require("express");
const router = new express.Router();
const database = require("../services/database");
const server = require("../server");
const config = server.config;
router.route("/:user")
.get((req, res) => {
database.userByName(req.params.user.toLowerCase(), user => {
if (user == undefined) {
return req.status(404).end();
}
let id = "https://" + config.domain + "/users/" + user.name;
let inbox = "https://" + config.domain + "/users/" + user.name + "/inbox";
let outbox = "https://" + config.domain + "/users/" + user.name + "/outbox";
let followers = "https://" + config.domain + "/users/" + user.name + "/followers";
let following = "https://" + config.domain + "/users/" + user.name + "/followinig";
let liked = "https://" + config.domain + "/users/" + user.name + "/liked";
let response = {
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": id,
"name": "Artem",
"preferredUsername": user.name,
"summary": "cajon player and e-bass junkie",
"inbox": inbox,
"outbox": outbox,
"followers": followers,
"following": following,
"liked": liked
}
res.json(response).end();
});
});
router.route("/:user/inbox")
.get((req, res) => {
console.log(req);
res.end();
})
.post((req, res) => {
console.log(req);
res.end();
});
router.route("/:user/outbox")
.get((req, res) => {
})
.post((req, res) => {
console.log(req);
res.end();
});
router.route("/:user/followers")
.get((req, res) => {
console.log(req);
res.end();
})
.post((req, res) => {
console.log(req);
res.end();
});
router.route("/:user/following")
.get((req, res) => {
console.log(req);
res.end();
})
.post((req, res) => {
console.log(req);
res.end();
});
router.route("/:user/liked")
.get((req, res) => {
console.log(req);
res.end();
})
.post((req, res) => {
console.log(req);
res.end();
});
module.exports = router;

119
router/album.js Normal file
View File

@@ -0,0 +1,119 @@
console.log("router/album INIT");
const express = require("express");
const database = require("../services/database");
const server = require("../server");
const passport = server.passport;
const checkGuest = server.checkGuest;
const resize_image_for_album = require("../services/cover/resizer").resize_image_for_album
const router = new express.Router();
router.route("/favourites")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
database.albums.favourites(req.user._id, result => {
res.json(result).end();
});
})
router.route("/page/:page")
.get(checkGuest, (req, res) => {
process.stdout.write("router/album GET albums page " + req.params.page + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.albums.collection(req.params.page, filter, result => {
process.stdout.write("router/album GET albums page " + req.params.page + " DB result\n");
res.json(result);
});
});
router.route("/newest/:count")
.get(checkGuest, (req, res) => {
process.stdout.write("router/album GET newest " + req.params.count + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.albums.newest(parseInt(req.params.count), filter, result => {
process.stdout.write("router/album GET newest " + req.params.count + " DB result\n");
res.json(result);
});
});
router.route("/:id")
.get(checkGuest, (req, res) => {
process.stdout.write("router/album GET album by id " + req.params.id + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.albums.byId(req.params.id, filter, result => {
process.stdout.write("router/album GET album by id " + req.params.id + " DB result\n");
res.json(result);
});
})
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.user.roles.indexOf("admin") >= 0 || req.user.roles.indexOf("moderator") >= 0) {
database.albums.update(req.body);
}
res.end();
});
router.route("/filter/:term")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("router/album GET filter by term " + req.params.term + "\n");
database.albums.filter(req.params.term, result => {
process.stdout.write("router/album GET filter by term " + req.params.term + " DB result\n");
res.json(result);
});
})
router.route("/:id/cover")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.files) {
if (req.files.file) {
resize_image_for_album(req.files.file.data, (result) => {
database.albums.updateCovers({ _id: req.params.id }, result);
res.json(result);
});
}
}
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
database.albums.updateCovers({ _id: req.params.id }, {});
res.end();
});
router.route("/:id/move")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
let source = {};
let target = {};
database.albums.byId(req.body.source, undefined, (result) => {
if (result != undefined && (req.user.roles.indexOf("admin") > -1) || result.owner_id == req.user._id) {
source = result;
database.albums.byId(req.body.target, undefined, (result) => {
if (result && (req.user.roles.indexOf("admin") > -1 || result.owner_id == req.user._id)) {
target = result;
for (let i = 0; i < source.tracks.length; i++) {
let track = source.tracks[i]
track.album_id = target._id
database.tracks.moveTo(track);
}
database.albums.delete(source, () => {
res.status(200).end();
});
} else {
res.status(403).end();
}
});
} else {
res.status(403).end();
}
});
});
module.exports = router;

102
router/artist.js Normal file
View File

@@ -0,0 +1,102 @@
console.log("router/artist INIT");
const express = require("express");
console.log("router/artist REQUIRE database");
const database = require("../services/database");
const server = require("../server");
const passport = server.passport;
const checkGuest = server.checkGuest;
const resize_image_for_artist = require("../services/cover/resizer").resize_image_for_artist
const router = new express.Router();
router.route("/favourites")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
database.artists.favourites(req.user._id, result => {
res.json(result).end();
});
})
router
.route("/page/:page")
.get(checkGuest, (req, res) => {
process.stdout.write("router/artist GET artists page " + req.params.page + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.artists.collection(req.params.page, filter, result => {
process.stdout.write("router/artist GET artists page " + req.params.page + " DB result\n");
res.json(result);
});
});
router
.route("/:id")
.get(checkGuest, (req, res) => {
process.stdout.write("router/artist GET by id " + req.params.id + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.artists.byId(req.params.id, filter, result => {
process.stdout.write("router/artist GET by id " + req.params.id + " DB result\n");
res.json(result);
});
});
router.route("/filter/:term")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("router/artist GET filter by term " + req.params.term + "\n");
database.artists.filter(req.params.term, result => {
process.stdout.write("router/artist GET filter by term " + req.params.term + " DB result\n");
res.json(result);
});
})
router.route("/:id/cover")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.files) {
if (req.files.file) {
resize_image_for_artist(req.files.file.data, (result) => {
database.artists.updateCovers({ _id: req.params.id }, result);
res.json(result);
});
}
}
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
database.artists.updateCovers({ _id: req.params.id }, {});
res.end();
});
router.route("/:id/move")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
let source = {};
let target = {};
database.artists.byId(req.body.source, undefined, (result) => {
if (result && req.user.roles.indexOf("admin") > -1) {
source = result;
database.artists.byId(req.body.target, undefined, (result) => {
if (result && req.user.roles.indexOf("admin") > -1) {
target = result;
for (let i = 0; i < source.albums.length; i++) {
let album = source.albums[i];
album.artist_id = target._id;
album.artist_name = target.name;
database.albums.moveTo(album);
}
database.artists.delete(source, () => {
res.status(200).end();
});
} else {
res.status(403).end();
}
});
} else {
res.status(403).end();
}
});
});
module.exports = router;

118
router/box.js Normal file
View File

@@ -0,0 +1,118 @@
console.log("router/box INIT");
const express = require("express");
const database = require("../services/database");
const server = require("../server");
const passport = server.passport;
const checkGuest = server.checkGuest;
const resize_image_for_box = require("../services/cover/resizer").resize_image_for_box
const router = new express.Router();
router.route("/favourites")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
database.boxes.favourites(req.user._id, result => {
res.json(result).end();
});
})
router
.route("/page/:page")
.get(checkGuest, (req, res) => {
process.stdout.write("router/box GET boxes page " + req.params.page + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.boxes.collection(req.params.page, filter, result => {
process.stdout.write("router/box GET boxes page " + req.params.page + " DB result\n");
res.json(result);
});
});
router
.route("/newest/:count")
.get(checkGuest, (req, res) => {
process.stdout.write("router/box GET newest " + req.params.count + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.boxes.newest(parseInt(req.params.count), filter, result => {
process.stdout.write("router/box GET newest " + req.params.count + " DB result\n");
res.json(result);
});
});
router
.route("/:id")
.get(checkGuest, (req, res) => {
process.stdout.write("router/box GET by id " + req.params.id + "\n");
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.boxes.byId(req.params.id, filter, result => {
process.stdout.write("router/box GET by id " + req.params.id + " DB result\n");
res.json(result).end();
});
}).put(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.user.roles.indexOf("admin") >= 0 || req.user.roles.indexOf("moderator") >= 0) {
database.boxes.update(req.body);
}
res.end();
});
router.route("/filter/:term")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("router/boxes GET filter by term " + req.params.term + "\n");
database.boxes.filter(req.params.term, result => {
process.stdout.write("router/boxes GET filter by term " + req.params.term + " DB result\n");
res.json(result);
});
})
router.route("/:id/cover")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.files) {
if (req.files.file) {
resize_image_for_box(req.files.file.data, (result) => {
database.boxes.updateCovers({ _id: req.params.id }, result);
res.json(result);
});
}
}
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
database.boxes.updateCovers({ _id: req.params.id }, {});
res.end();
});
router.route("/:id/move")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
let source = {};
let target = {};
database.boxes.byId(req.body.source, undefined, (result) => {
if (result && (req.user.roles.indexOf("admin") > -1 || result.owner_id == req.user._id)) {
source = result;
database.boxes.byId(req.body.target, undefined, (result) => {
if (result && (req.user.roles.indexOf("admin") > -1 || result.owner_id == req.user._id)) {
target = result;
for (let i = 0; i < source.videos.length; i++) {
let video = source.videos[i]
video.box_id = target._id
database.videos.moveTo(video);
}
database.boxes.delete(source, () => {
res.status(200).end();
});
} else {
res.status(403).end();
}
});
} else {
res.status(403).end();
}
});
});
module.exports = router;

16
router/index.js Normal file
View File

@@ -0,0 +1,16 @@
exports.albumRouter = require("./album");
exports.artistRouter = require("./artist");
exports.trackRouter = require("./track");
exports.radioRouter = require("./radio")
exports.boxRouter = require("./box");
exports.videoRouter = require("./video");
exports.scanRouter = require("./scan");
exports.userRouter = require("./user");
exports.loginRouter = require("./login");
exports.infoRouter = require("./info");
exports.systemRouter = require("./system")
exports.statusRouter = require("./status");
exports.settingsRouter = require("./settings");
exports.searchRouter = require("./search");
// exports.activitypubRouter = require("./activitypub");
// exports.wellknownRouter = require("./well-known");

33
router/info.js Normal file
View File

@@ -0,0 +1,33 @@
console.log("router/info INIT");
var express = require("express");
var router = new express.Router();
var database = require("../services/database");
let info = {}
info.stats = {}
router
.route("")
.get((req, res) => {
database.artist_count((q, c) => {
info.stats.artists = c;
database.album_count((q, c) => {
info.stats.albums = c;
database.track_count((q, c) => {
info.stats.tracks = c;
database.box_count((q, c) => {
info.stats.boxes = c;
database.video_count((q, c) => {
info.stats.videos = c;
database.users_count((q, c) => {
info.stats.users = c;
res.json(info);
});
});
});
});
});
});
});
module.exports = router;

59
router/login.js Normal file
View File

@@ -0,0 +1,59 @@
console.log("router/login INIT");
var express = require("express");
var router = new express.Router();
var bcrypt = require("bcryptjs");
var database = require("../services/database");
var jwt = require("jsonwebtoken");
var server = require("../server");
var passport = server.passport;
var secret = server.secret;
router
.route("/login")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
let user = req.user;
database.historyList(user._id, history => {
user.history = history;
database.users.favourites(user._id, favourites => {
user.favourites = favourites;
res.status(200).json(req.user);
});
});
})
.post((req, res) => {
database.userByName(req.body.username, user => {
if (!user) {
process.stdout.write("no user in DB\n");
return res.status(401).send({
success: false,
msg: "Authentication failed. Wrong user."
});
}
bcrypt.compare(req.body.password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
var token = jwt.sign(user, secret);
user.token = "JWT " + token;
process.stdout.write("pass ok\n");
database.updateUserAccess(req.body.username);
database.historyList(user._id, history => {
user.history = history;
database.users.favourites(user._id, favourites => {
user.favourites = favourites;
res.status(200).json(user);
});
});
} else {
process.stdout.write("pass fail\n");
res.status(401).send({
success: false,
msg: "Authentication failed. Wrong password."
});
}
});
});
});
module.exports = router;

71
router/radio.js Normal file
View File

@@ -0,0 +1,71 @@
console.log("router/radio INIT");
const express = require("express");
console.log("router/radio REQUIRE END");
const database = require("../services/database");
const server = require("../server");
const passport = server.passport;
const checkGuest = server.checkGuest;
const resize_image_for_radio = require("../services/cover/resizer").resize_image_for_radio;
console.log("router/radio CREATE instances");
var router = new express.Router();
console.log("router/radio READY");
router
.route("")
.get(checkGuest, (req, res) => {
database.radios.collection(result => {
res.json(result);
});
})
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("add radio\n");
if (
req.body.name == "" ||
!req.body.url ||
!req.body.url.startsWith("http")
) {
return res.end();
}
let newRadio = {
name: req.body.name,
url: req.body.url
};
database.radios.add(newRadio, () => {
res.end();
});
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("delete radio\n");
database.radios.delete(req.query.id, () => {
database.radios.collection(result => {
res.json(result);
});
});
});
router
.route("/:id/cover")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("update radio cover\n");
if (req.files) {
database.radios.byId(req.params.id, radio => {
if (radio) {
if (req.files.file) {
resize_image_for_radio(req.files.file.data, (result) => {
radio.cover32 = result.cover32;
radio.cover64 = result.cover64;
radio.cover128 = result.cover128;
database.radios.update(radio);
res.json(radio).end();
});
}
}
});
}
});
module.exports = router;

48
router/scan.js Normal file
View File

@@ -0,0 +1,48 @@
console.log("router/scan INIT");
var express = require("express");
var file_scanner = require("../services/files_scanner");
var cover_excluder = require("../services/cover_excluder");
console.log("router/scan LOAD server settings");
var server = require("../server");
var status = server.status;
var config = server.config;
var passport = server.passport;
var router = new express.Router();
console.log("router/scan SET routers");
router
.route("/music")
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (!status.scanning_music) {
status.scanning_music = true;
process.stdout.write("music scann started…\n");
res.send("music scann started…");
file_scanner.scann_local_music_files(config.music_folder);
setTimeout(() => {
file_scanner.scann_local_music_files(config.upload_folder);
}, 1000);
} else {
res.send("please wait. server is scanning for music files…");
}
});
router
.route("/video")
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (!status.scanning_video) {
status.scanning_video = true;
process.stdout.write("video scann started…\n");
res.send("video scann started…");
file_scanner.scann_local_video_files(config.video_folder);
setTimeout(() => {
file_scanner.scann_local_video_files(config.upload_folder);
}, 1000);
} else {
res.send("please wait. server is scanning for video files…");
}
});
console.log("router/scan EXPORT routers");
module.exports = router;

17
router/search.js Normal file
View File

@@ -0,0 +1,17 @@
console.log("router/search INIT");
var express = require("express");
var server = require("../server");
var database = require("../services/database");
var passport = server.passport;
var router = new express.Router();
router
.route("/:term")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
database.search(req.params.term.toLowerCase(), result => {
res.json(result).end();
});
});
module.exports = router;

26
router/settings.js Normal file
View File

@@ -0,0 +1,26 @@
console.log("router/settings INIT");
var express = require("express");
var database = require("../services/database");
var router = new express.Router();
var server = require("../server");
router.route("/").get((req, res) => {
database.system.allows((result) => {
console.log(result);
res.json(result)
});
});
router.route("/lists").get((req, res) => {
let lists = {
audio_quality: server.lists.audio_quality,
video_lang: server.lists.lang,
video_quality: server.lists.video_quality,
visibility: server.lists.visibility,
user_role: server.lists.user_role
}
res.json(lists);
});
module.exports = router;

18
router/status.js Normal file
View File

@@ -0,0 +1,18 @@
console.log("router/status INIT");
var express = require("express");
var router = new express.Router();
var server = require("../server");
var status = server.status;
var tag_excluder = require("../services/tag_excluder");
router.route("").get((req, res) => {
status.scann_buffer = tag_excluder.get_buffer_size();
status.parsing_music_data = tag_excluder.parsing_music_data();
status.parsing_video_data = tag_excluder.parsing_video_data();
status.parsing_cover = tag_excluder.parsing_cover();
res.json(status);
});
module.exports = router;

97
router/system.js Normal file
View File

@@ -0,0 +1,97 @@
console.log("router/system INIT");
const express = require("express");
const router = new express.Router();
const database = require("../services/database");
const redis = require("../services/redis")
const jwt = require("jsonwebtoken");
const server = require("../server");
const secret = server.secret;
const passport = server.passport;
const config = server.config
router
.route("")
.get((req, res) => {
database.system.allows((result) => {
res.json(result).end();
})
})
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.user.roles.indexOf("admin") > -1) {
database.system.setAllows(req.body, () => {
res.status(200).end();
})
} else {
res.status(403).end();
}
});
router
.route("/domains")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.user.roles.indexOf("admin") > -1) {
let domains = {
const: config.allowed_domains,
dynamic: []
}
database.system.domains((result) => {
result.forEach(domain => {
domains.dynamic.push(domain);
});
res.json(domains).end();
});
} else {
res.status(403).end();
}
})
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.user.roles.indexOf("admin") > -1) {
database.system.setDomains(req.body, () => {
res.status(200).end();
});
}
})
router
.route("/setup")
.get((req, res) => {
database.users.collection(users => {
if (users && users.length > 0) {
res.status(204).end();
} else {
res.status(200).end();
}
});
})
.post((req, res) => {
process.stdout.write("add admin user\n");
database.users.collection(users => {
if (users && users.length > 0) {
res.status(403).end();
} else {
let newUser = {
name: req.body.username,
password: req.body.password,
roles: ["admin"]
};
database.addUser(newUser, result => {
var token = jwt.sign(result, secret);
result.token = "JWT " + token;
result.history = [];
res.json(result).end();
});
}
});
});
router
.route("/reset/redis")
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.user.roles.indexOf("admin") > -1) {
redis.flushAll();
}
});
module.exports = router;

222
router/track.js Normal file
View File

@@ -0,0 +1,222 @@
console.log("router/track INIT");
const express = require("express");
const fs = require("fs");
const meta_data = require("music-metadata");
const database = require("../services/database");
const node_id3 = require("node-id3");
const Lame = require("node-lame").Lame;
const Fdkaac = require("node-fdkaac").Fdkaac;
const notifier = require("../services/notifier");
const server = require("../server");
const passport = server.passport;
const config = server.config;
const checkGuest = server.checkGuest;
const router = new express.Router();
const audio_cache_dir = config.cache_folder + "/audio_cache/";
const resizer = require("../services/cover/resizer");
if (!fs.existsSync(audio_cache_dir)) {
fs.mkdirSync(audio_cache_dir);
}
server.lists.audio_quality.forEach(bmp => {
let dir = audio_cache_dir + bmp;
if (!fs.existsSync(dir)) {
fs.mkdir(dir, () => { });
}
});
router.route("")
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.files) {
let track = JSON.parse(req.body.track);
let url_user = config.upload_folder + "/" + req.user._id;
let folder = Math.floor(Date.now() / 1000 / 60);
let url_folder = url_user + "/" + folder
let file = url_folder + "/" + req.files.file.name;
req.files.file.mv(file).then(() => {
meta_data
.parseFile(file, { duration: true })
.then(meta => {
let item = {
path: file,
artist: track.artist,
album: track.album,
title: track.title,
duration: meta.format.duration,
bitrate: meta.format.bitrate,
mime: req.files.file.mimetype,
year: track.year,
track: track.track,
disk: meta.common.disk,
genre: track.genre || meta.common.genre,
owner: req.user
};
if (meta.common.picture && meta.common.picture.length > 0) {
resizer.resize_image_for_album(meta.common.picture[0].data, (covers) => {
item.covers = covers;
notifier.emit("metadata_excluded", item);
res.status(200).end();
});
} else {
notifier.emit("metadata_excluded", item);
res.status(200).end();
}
})
.catch(err => {
process.stdout.write(file);
console.log(err);
});
});
} else {
res.end();
}
});
router
.route("/most_listened")
.get(checkGuest, (req, res) => {
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.tracks.mostListened(filter, (result) => {
res.json(result);
});
});
router
.route("/:id/stream")
.get((req, res) => {
database.tracks.byId(req.params.id, result => {
process.stdout.write("audio stream: " + result.title);
if (!fs.existsSync(config.music_folder + result.path)) {
return res.end();
}
stream(req, res, config.music_folder + result.path, result.mime);
});
});
router
.route("/:id/stream/:rate")
.get((req, res) => {
if (!server.lists.audio_quality.includes(req.params.rate)) {
res.end();
}
let music = audio_cache_dir + req.params.rate + "/" + req.params.id + ".mp3";
if (fs.existsSync(music)) {
stream(req, res, music, "audio/mpeg");
} else {
convert(req.params.id, req.params.rate).then((file) => {
if (file) {
stream(req, res, file.path, file.mime);
} else {
res.end();
}
});
}
});
router.route("/:id/convert/:rate")
.put((req, res) => {
let music = audio_cache_dir + req.params.rate + "/" + req.params.id + ".mp3";
if (!fs.existsSync(music)) {
convert(req.params.id, req.params.rate);
}
res.end();
});
function stream(req, res, music, mime) {
process.stdout.write("audio stream: " + music + "\n");
let stat = fs.statSync(music);
if (req.headers.range) {
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : stat.size - 1;
var chunksize = end - start + 1;
var readStream = fs.createReadStream(music, { start: start, end: end });
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + stat.size,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": mime
});
readStream.pipe(res);
} else {
res.writeHead(200, {
"Content-Length": stat.size,
"Content-Type": mime
});
fs.createReadStream(music).pipe(res);
}
}
function convert(id, rate) {
return new Promise((resolve) => {
database.tracks.byId(id, result => {
let full_path = config.music_folder + result.path;
let cache_path = audio_cache_dir + rate + "/" + id + ".mp3";
if (!fs.existsSync(full_path)) {
full_path = config.upload_folder + result.path;
if (!fs.existsSync(full_path)) {
resolve();
}
}
if (result.mime == "audio/mpeg" && result.bitrate / 1000 <= rate) {
process.stdout.write("stream non converted file: " + result.titel + "\n");
resolve({ path: full_path, mime: result.mime });
return;
}
process.stdout.write("audio convert: " + result.title + " (" + result.mime + ")\n");
if (result.mime.includes("mp4")) {
process.stdout.write("audio decode: " + result.title + " (" + result.mime + ")\n");
const decoder = new Fdkaac({ output: "buffer" }).setFile(full_path);
decoder
.decode()
.then(() => {
const buffer = decoder.getBuffer();
const lame_encoder = new Lame({
output: cache_path,
bitrate: rate
}).setBuffer(buffer);
lame_encoder
.encode()
.then(() => {
node_id3.removeTags(cache_path);
resolve({ path: cache_path, mime: "audio/mpeg" });
})
.catch(err => {
process.stdout.write(err);
});
})
.catch(err => {
process.stdout.write(err);
});
} else {
const lame_encoder = new Lame({ output: cache_path, bitrate: rate }).setFile(full_path);
lame_encoder
.encode()
.then(() => {
node_id3.removeTags(cache_path);
resolve({ path: cache_path, mime: "audio/mpeg" });
})
.catch(err => {
process.stdout.write(err);
process.stdout.write("stream original");
resolve({ path: full_path, mime: result.mime });
});
}
});
});
}
module.exports = router;

172
router/user.js Normal file
View File

@@ -0,0 +1,172 @@
console.log("router/user INIT");
var express = require("express");
var database = require("../services/database");
var bcrypt = require("bcryptjs");
var router = new express.Router();
var server = require("../server");
var passport = server.passport;
router
.route("")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
database.users.collection(result => {
res.json(result).end();
});
})
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("add user\n");
if (
req.user.roles.includes("admin") ||
req.user.roles.includes("moderator")
) {
let newUser = {
name: req.body.name,
password: req.body.password
};
database.addUser(newUser, () => {
res.end();
});
} else {
res.status(401).end();
}
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("delete user\n");
if (req.user.roles.includes("admin") || req.user._id == req.query.id) {
database.userById(req.query.id, (user) => {
if (user.roles.includes("admin")) {
res.status(403).end();
} else {
database.deleteUser(req.query.id, () => {
database.users.collection(result => {
res.json(result).end();
});
});
}
});
} else {
res.status(401).end();
}
})
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("update user\n");
if (req.user.roles.includes("admin")) {
if (req.body.newPassword) {
database.updateUserPassword(req.body.name, req.body.newPassword);
} else {
database.updateUserRole(req.body, () => {
res.status(202).end();
});
}
res.end();
} else {
res.status(401).end();
}
});
router
.route("/:name/exists")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
if (
req.user.roles.includes("admin") ||
req.user.roles.includes("moderator")
) {
database.userByName(req.params.name, user => {
res.json({ exists: user != null }).end();
});
} else {
res.status(401).end();
}
});
router
.route("/update")
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (!req.user) {
return res.status(401).end();
}
if (!req.body.oldPassword) {
database.updateUserConfig(req.user, req.body);
process.stdout.write("config changed\n");
}
if (req.body.oldPassword && req.user.password) {
bcrypt.compare(req.body.oldPassword, req.user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
database.updateUserPassword(req.user.name, req.body.newPassword);
process.stdout.write("password changed\n");
res.status(202);
} else {
process.stdout.write("no match\n");
res.status(422);
}
res.end();
});
} else {
res.end();
}
});
router
.route("/favourites")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
process.stdout.write("router/user GET favourites\n");
database.user.favourites(id, result => {
res.json(result).end();
});
})
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
let item = req.body;
item.userId = req.user._id;
process.stdout.write("router/user POST favourites\n");
database.users.insertFavourite(item, () => {
res.status(200).end();
})
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
let item = {};
item.itemId = req.query.itemId;
item.userId = req.user._id;
process.stdout.write("router/user DELETE favourites " + req.query.itemId + "\n");
database.users.deleteFavourite(item, () => {
res.status(200).end();
});
});
router
.route("/history")
.get(passport.authenticate("jwt", { session: false }), (req, res) => {
database.historyList(req.user._id, result => {
res.json(result).end();
});
})
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
let item = req.body;
item.userId = req.user._id;
database.updateHistory(item, () => {
database.historyList(req.user._id, result => {
res.json(result).end();
});
});
})
.delete(passport.authenticate("jwt", { session: false }), (req, res) => {
database.clearHistory(req.user._id, () => {
process.stdout.write("history cleared for '" + req.user.name + "'\n");
res.status(200).end();
});
});
router
.route("/settings")
.put(passport.authenticate("jwt", { session: false }), (req, res) => {
req.user.player.repeat = req.body.repeat;
req.user.player.shuffle = req.body.shuffle;
database.updateUserSettings(req.user, () => {
res.status(202).end();
});
});
module.exports = router;

209
router/video.js Normal file
View File

@@ -0,0 +1,209 @@
console.log("router/video INIT");
const express = require("express");
const fs = require("fs");
const ffmpeg = require("fluent-ffmpeg");
const database = require("../services/database");
const notifier = require("../services/notifier");
const server = require("../server");
const passport = server.passport;
const config = server.config;
const router = new express.Router();
const video_cache_dir = config.cache_folder + "/video_cache/";
const checkGuest = server.checkGuest;
const resize_image_for_box = require("../services/cover/resizer").resize_image_for_box
if (!fs.existsSync(video_cache_dir)) {
fs.mkdirSync(video_cache_dir);
}
router.route("")
.post(passport.authenticate("jwt", { session: false }), (req, res) => {
if (req.files) {
let file = undefined;
let cover = undefined;
if (Array.isArray(req.files.file)) {
file = req.files.file[0];
cover = req.files.file[1];
} else {
file = req.files.file;
}
let box = JSON.parse(req.body.box);
let url_user = config.upload_folder + "/" + req.user._id;
let folder = Math.floor(Date.now() / 1000 / 60);
let url_folder = url_user + "/" + folder
let file_path = url_folder + "/" + file.name;
let item = {
path: file_path.replace(config.upload_folder, ""),
box: box.title,
box_path: url_folder,
title: req.body.title,
mime: file.mimetype,
year: box.year,
owner: req.user
};
//SAVE VIDEO FILE
function saveVideoFile() {
file.mv(file_path).then(() => {
notifier.emit("pathdata_excluded", item);
res.status(200).end();
});
}
if (cover) {
resize_image_for_box(cover.data, (result) => {
item.cover32 = result.cover32;
item.cover64 = result.cover64;
item.cover128 = result.cover128;
item.cover256 = result.cover256;
saveVideoFile();
});
} else {
saveVideoFile();
}
}
});
router.route("/most_viewed")
.get(checkGuest, (req, res) => {
let filter = undefined;
if (req.user._id == -1) {
filter = ['global'];
}
database.videos.mostViewed(filter, (result) => {
res.json(result);
});
});
router.route("/:id/stream")
.get((req, res) => {
database.videos.byId(req.params.id, result => {
process.stdout.write("video stream: " + result.title + "\n");
let full_path = config.video_folder + result.path;
if (!fs.existsSync(full_path)) {
full_path = config.upload_folder + result.path;
if (!fs.existsSync(full_path)) {
return res.end();
}
}
stream(req, res, full_path, result.mime);
});
});
router.route("/:id/stream/:rate/:audioIndex")
.get((req, res) => {
if (!server.lists.video_quality.includes(req.params.rate)) {
req.end();
}
let video = getFileName(req);
if (fs.existsSync(video)) {
stream(req, res, video, "video/mpeg");
} else {
convert(req, res, video, () => {
stream(req, res, video, "video/mp4");
});
}
});
router.route("/:id/convert/:rate/:audioIndex")
.get((req, res) => {
if (!server.lists.video_quality.includes(req.params.rate)) {
req.end();
}
let video = getFileName(req);
if (!fs.existsSync(video)) {
convert(req, res, video);
}
res.end();
});
function convert(req, res, video, callback = null) {
database.videos.byId(req.params.id, result => {
process.stdout.write("video stream: " + result.title + "\n");
let full_path = config.video_folder + result.path;
if (!fs.existsSync(full_path)) {
full_path = config.upload_folder + result.path;
if (!fs.existsSync(full_path)) {
return res.end();
}
}
ffmpeg(full_path)
.audioBitrate(128)
.audioChannels(2)
.videoCodec("libvpx")
.size("?x" + req.params.rate)
.videoBitrate(req.params.rate * 2)
.outputOptions([
"-cpu-used " + server.config.cpu_cores,
"-map 0:v:0",
"-map 0:a:" + req.params.audioIndex
])
.output(video)
.on("start", commandLine => {
process.stdout.write(
"Spawned Ffmpeg with command: " + commandLine + "\n"
);
if (callback) {
let interval = setInterval(() => {
if (fs.existsSync(video) && fs.statSync(video).size > 3000000) {
clearInterval(interval);
callback();
}
}, 4000);
}
})
.on("error", e => {
process.stdout.write(e);
})
.run();
});
}
function stream(req, res, video, mime) {
process.stdout.write("video stream: " + video + "\n");
let stat = fs.statSync(video);
if (req.headers.range) {
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : stat.size - 1;
var chunksize = end - start + 1;
var readStream = fs.createReadStream(video, { start: start, end: end });
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + stat.size,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": mime
});
readStream.pipe(res);
} else {
res.writeHead(200, {
"Content-Length": stat.size,
"Content-Type": mime
});
fs.createReadStream(video).pipe(res);
}
}
function getFileName(req) {
return (
video_cache_dir +
req.params.id +
"-" +
req.params.rate +
"-" +
req.params.audioIndex +
".webm"
);
}
module.exports = router;

49
router/well-known.js Normal file
View File

@@ -0,0 +1,49 @@
const express = require("express");
const router = new express.Router();
const server = require("../server");
const config = server.config;
const database = require("../services/database");
router.route("/webfinger")
.get((req, res) => {
if (!req.query.resource) {
return res.status(400).end();
}
let resource = req.query.resource.toLowerCase();
let name = resource.replace("acct:", "").replace("@" + config.domain, "").toLowerCase();
if (name.length == 0) {
return res.status(400).end();
}
database.userByName(name, (user) => {
if (user == undefined) {
return res.status(404).end();
}
let response = {
"subject": resource,
"aliases": [
"https://" + config.domain + "/#/users/" + user.name
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://" + config.domain + "/#/users/" + user.name
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://" + config.domain + "/users/" + user.name
}
]
}
res.json(response).end();
});
});
module.exports = router;