From cd124f916ef8cb5f771256ed565a5d6ee4ebdf62 Mon Sep 17 00:00:00 2001 From: Reimar Date: Mon, 12 Feb 2024 19:09:23 +0100 Subject: [PATCH] Listen for file changes and update progress continuously --- index.js | 108 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/index.js b/index.js index eb20f47..954b832 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,9 @@ import levenshtein from "js-levenshtein"; import cookieParser from "cookie-parser"; import { fileURLToPath } from "url"; import sqlite3 from "sqlite3"; +import fs from "fs/promises"; + +const PORT = 8000; let sessions = []; let videoQueue = []; @@ -59,6 +62,35 @@ function dirname() { return path.dirname(fileURLToPath(import.meta.url)); } +function authorized() { + return async (req, res, next) => { + const token = (() => { + if (req.cookies && "token" in req.cookies) { + return req.cookies["token"]; + } else if ("token" in req.query) { + return req.query["token"]; + } else if (req.method === "post" && "token" in req.body) { + return req.body["token"]; + } else { + return null; + } + })(); + if (token === null) { + return res.status(400).json({ ok: false, error: "unauthorized" }); + } + const session = sessions.find(session => session.token === token); + if (session === undefined) { + return res.status(400).json({ ok: false, error: "unauthorized" }); + } + const user = await dbGet("SELECT * FROM users WHERE id = ?", session.userId); + if (user === undefined) { + throw new Error("error: session with invalid userId"); + } + req.user = user; + next(); + } +} + const app = express(); app.use(cors()); app.use(express.json()); @@ -142,35 +174,6 @@ app.get("/api/search", async (req, res) => { return res.status(200).json({ ok: true, videos, total }); }); -function authorized() { - return async (req, res, next) => { - const token = (() => { - if (req.cookies && "token" in req.cookies) { - return req.cookies["token"]; - } else if ("token" in req.query) { - return req.query["token"]; - } else if (req.method === "post" && "token" in req.body) { - return req.body["token"]; - } else { - return null; - } - })(); - if (token === null) { - return res.status(400).json({ ok: false, error: "unauthorized" }); - } - const session = sessions.find(session => session.token === token); - if (session === undefined) { - return res.status(400).json({ ok: false, error: "unauthorized" }); - } - const user = await dbGet("SELECT * FROM users WHERE id = ?", session.userId); - if (user === undefined) { - throw new Error("error: session with invalid userId"); - } - req.user = user; - next(); - } -} - app.get("/api/logout", authorized(), (req, res) => { sessions = sessions.filter(session => session.userId !== req.user.id); return res.status(200).json({ ok: true }); @@ -198,7 +201,7 @@ app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 * return res.status(400).json({ ok: false, error: "invalid video file" }); } - const duration = parseFloat(durationResult.data.match(/duration=([.\d]+)/)[1]); + const duration = parseFloat(durationResult.data.match(/duration=([.\d]+)/)[1]) * 1_000_000;; const queueItem = { videoId: id, @@ -210,7 +213,8 @@ app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 * videoQueue.push(queueItem); - const uploadProcess = childProcess.spawn("ffmpeg", ["-i", tempPath, "-b:v", "1M", "-b:a", "192k", "-loglevel", "error", newPath]); + const progressPath = path.join(dirname(), "tmp", "progress", `${id}.txt`) + const uploadProcess = childProcess.spawn("ffmpeg", ["-i", tempPath, "-b:v", "1M", "-b:a", "192k", "-progress", progressPath, "-loglevel", "error", newPath]); const thumbnailProcess = childProcess.spawn("ffmpeg", ["-i", tempPath, "-ss", "00:00:01.000", "-vframes", "1", "-loglevel", "error", thumbnailPath]); uploadProcess.stderr.on("data", data => queueItem.errors.push(data.toString())); @@ -263,6 +267,42 @@ app.use((err, req, res, next) => { res.status(500).json({ ok: false, error: "server error" }) }); -app.listen(8000, () => { - console.log("app at http://localhost:8000/"); -}) +async function main() { + (async () => { + const progressPath = path.join(dirname(), "tmp", "progress"); + + await fs.mkdir(progressPath, { recursive: true }); + + const watch = fs.watch(progressPath, { recursive: true }); + + for await (const event of watch) { + const videoId = event.filename.replace(".txt", ""); + const queueItem = videoQueue.find(item => item.videoId === videoId); + + if (!queueItem) { + continue; + } + + fs.readFile(path.join(progressPath, event.filename), "utf-8") + .then(string => { + const index = string.lastIndexOf("out_time_ms="); + if (index === -1) return; + + const length = parseInt(string.slice(index).match(/out_time_ms=(\d+)/)[1]); + + for (const i in videoQueue) { + if (videoQueue[i].videoId !== videoId) continue; + + videoQueue[i].progress = length; + } + }); + } + })(); + + app.listen(PORT, () => { + console.log("app at http://localhost:8000/"); + }); +} + +main(); +