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