raspi-back/app/routes/files.js

218 lines
9.0 KiB
JavaScript

const fs = require("fs");
const route = require("express").Router()
const { exec } = require("child_process")
const { verifyToken } = require("../checkToken")
const { addRouteToScope, compareScopes, getRequiredScopes } = require("../scopes")
const { join } = require("path");
const { addScopeEntry, implicitAllowScopes, getExtSharePath } = require("../arangodb");
const { get } = require("https")
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, req.body.path)
},
filename: (req, file, cb) => {
cb(null, req.body.name)
}
})
const upload = multer({ storage })
addRouteToScope("/files/foldercontent", "files")
addRouteToScope("/files/text", "files")
addRouteToScope("/files/", "files")
addRouteToScope("/files/hls", "hls")
addRouteToScope("/files/hlscheck", "hls")
addRouteToScope("/files/hls", "files")
addRouteToScope("/files/hlscheck", "files")
addRouteToScope("/", "files")
//addRouteToScope("/files/upload", "upload")
addRouteToScope("/files/upload", "files")
route.post("/foldercontent", verifyToken, (req, res) => {
const { path } = req.body;
// console.log(req.tokendata)
implicitAllowScopes(path).then((implicitscopes) => {
if (implicitscopes.find((scope) => req.tokendata.scopes.includes(scope)) || compareScopes(path, req.tokendata.scopes)) {
fs.readdir(path, (err, files) => {
if (err) {
res.status(500).json(`can't get content of ${path}`)
} else {
const returnObj = { Files: [], Folders: [] }
Promise.all(files.map((file) => implicitAllowScopes(join(path, file)))).then((implicitscopes) => {
files.forEach((file, i) => {
try {
if (fs.statSync(join(path, file)).isDirectory() && (implicitscopes[i].find((scope) => req.tokendata.scopes.includes(scope)) || compareScopes(join(path, file), req.tokendata.scopes))) {
returnObj.Folders.push({ name: file, requiredScopes: getRequiredScopes(join(path, file)) })
} else if (compareScopes(join(path, file), req.tokendata.scopes)) {
returnObj.Files.push({ name: file, requiredScopes: getRequiredScopes(join(path, file)) })
}
} catch (e) {
}
})
res.json(returnObj)
})
}
})
} else {
res.status("403").json("you lack the required scopes to access this directory")
}
})
})
route.get("/text/:path", verifyToken, (req, res) => {
const route = req.params.path.replace(/%2f/gi, "/")
if (!compareScopes(route, req.tokendata.scopes)) {
res.status(403).json("you lack required scopes for this content")
} else {
res.sendFile(req.params.path.replace(/%2f/gi, "/"))
}
})
route.post("/scope", verifyToken, (req, res) => {
const { path, scope } = req.body;
// console.log(path, scope)
addScopeEntry({ scope, content: path }).then(() => {
addRouteToScope(path, scope)
res.end()
}, ({ error, message }) => {
res.status(error).json(message)
})
})
route.get("/video/:path", verifyToken, (req, res) => {
const route = req.params.path.replace(/%2f/gi, "/")
// console.log("getting video", req.tokendata.scopes, req.params.path)
if (req.tokendata.scopes.find((scope) => scope.replace(/%2f/g, "/").match(new RegExp(req.params.path))) || compareScopes(route, req.tokendata.scopes)) {
if (fs.existsSync(route)) {
const { size } = fs.statSync(route);
const { range } = req.headers;
if (range) {
const [start, end] = range.replace(/bytes=/, "").split("-").map((num) => parseInt(num, 10));
if (start >= size) {
res.statusCode = 416;
res.end();
return;
}
const chunksize = (end ? end : size - 1) - start + 1
const file = fs.createReadStream(route, { start, end: end ? end : size - 1 });
const head = {
"Content-Range": `bytes ${start}-${end ? end : size - 1}/${size}`,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
}
res.writeHead(206, head);
file.pipe(res)
} else {
const head = {
"Content-Length": size,
"Content-Type": "video/mp4"
}
res.writeHead(200, head);
fs.createReadStream(route).pipe(res);
}
} else {
res.status(404).json("not found")
}
}
})
route.get("/extshare/:id", (req, res) => {
getExtSharePath(req.params.id).then(({ path }) => {
if (path.endsWith(".mp4")) {
if (fs.existsSync(path)) {
const { size } = fs.statSync(path);
const { range } = req.headers;
if (range) {
const [start, end] = range.replace(/bytes=/, "").split("-").map((num) => parseInt(num, 10));
if (start >= size) {
res.statusCode = 416;
res.end();
return;
}
const chunksize = (end ? end : size - 1) - start + 1
const file = fs.createReadStream(route, { start, end: end ? end : size - 1 });
const head = {
"Content-Range": `bytes ${start}-${end ? end : size - 1}/${size}`,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
}
res.writeHead(206, head);
file.pipe(res)
} else {
const head = {
"Content-Length": size,
"Content-Type": "video/mp4"
}
res.writeHead(200, head);
fs.createReadStream(path).pipe(res);
}
} else {
res.status(404).json("not found")
}
} else {
res.sendFile(path)
}
}, () => {
res.status(404).json("not found")
})
})
route.post("/upload", verifyToken, upload.single("data"), (req, res) => {
//console.log(req.file)
// let prevprog = 0;
// res.writeHead(200, "ok", {"content-length":"100000"})
// const writeStream = fs.createWriteStream(path.join(req.body.path, req.body.name))
// const readStream = fs.createReadStream(req.file.path)
// const inter = setInterval(()=>{
// const curprog = Math.round((writeStream.bytesWritten+readStream.bytesRead)/req.file.size*50000)
// console.log(curprog, prevprog)
// if(curprog>prevprog){
// res.write(new Array(curprog-prevprog).fill("0").join(""))
// }
// prevprog=curprog
// }, 100)
// readStream.pipe(writeStream)
// writeStream.on("close", ()=>{
// clearInterval(inter)
// fs.unlink(req.file.path, ()=>{
// res.end()
// })
// // console.log(writeStream.bytesWritten)
// // fs.access(path.join(req.body.path, req.body.name), (err)=>{
// // console.log(err, path.join(req.body.path, req.body.name))
// // })
// })
res.end()
})
route.post("/hls", verifyToken, (req, res) => {
const { program, output, hls } = req.body;
if (program == undefined|| !output || !hls) {
res.status(406).json("missing hls, program or output fields")
} else {
exec(`ffmpeg -i ${hls} -map p:${program} -c copy -f segment -segment_list "${path.basename(output)}.list" "${path.basename(output)}%03d.ts"`, { cwd: path.dirname(output) }, (error) => {
if (error) {
res.status(500).json(error)
} else {
exec(`ffmpeg -f concat -safe 0 -i <(for f in "${path.dirname(output)}/${path.basename(output)}"*.ts; do echo "file '$f'"; done) -c copy "${output}"`, {shell:"/bin/bash"}, (error) => {
if (error) {
res.status(500).json(error)
} else {
res.end()
exec(`rm "${path.basename(output)}"*.ts "${path.basename(output)}.list"`, {cwd:path.dirname(output)}, (error)=>{
if(error){
console.log(error)
}
})
}
})
}
})
}
})
route.get("/hlscheck", verifyToken, (req, res) => {
get(req.query.url, (response)=>{
response.pipe(res)
})
})
module.exports = route