Create video queue and endpoint for showing it
This commit is contained in:
parent
8852a6f0c3
commit
a9b0c2a602
77
index.js
77
index.js
@ -10,6 +10,7 @@ import { fileURLToPath } from "url";
|
|||||||
import sqlite3 from "sqlite3";
|
import sqlite3 from "sqlite3";
|
||||||
|
|
||||||
let sessions = [];
|
let sessions = [];
|
||||||
|
let videoQueue = [];
|
||||||
|
|
||||||
const db = new sqlite3.Database("database.sqlite3");
|
const db = new sqlite3.Database("database.sqlite3");
|
||||||
|
|
||||||
@ -25,6 +26,22 @@ function dbRun(query, ...parameters) {
|
|||||||
return new Promise((resolve, reject) => db.run(query, parameters, (err, data) => err ? reject(err) : resolve(data)));
|
return new Promise((resolve, reject) => db.run(query, parameters, (err, data) => err ? reject(err) : resolve(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runCommand(cmd, args) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const process = childProcess.spawn(cmd, args);
|
||||||
|
|
||||||
|
let data = "";
|
||||||
|
let error = false;
|
||||||
|
process.stdout.on("data", chunk => data += chunk);
|
||||||
|
process.stderr.on("data", chunk => {
|
||||||
|
error = true;
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("close", () => resolve({ error, data }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function videoPath(id) {
|
function videoPath(id) {
|
||||||
return `videos/${id}.webm`;
|
return `videos/${id}.webm`;
|
||||||
}
|
}
|
||||||
@ -167,7 +184,7 @@ app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.files.video.mimetype !== "video/mp4") {
|
if (req.files.video.mimetype !== "video/mp4") {
|
||||||
return res.status(400).json({ ok: false, error: "bad mimetype" });
|
return res.status(415).json({ ok: false, error: "bad mimetype" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = req.user.id;
|
const userId = req.user.id;
|
||||||
@ -176,33 +193,51 @@ app.post("/api/upload-video", authorized(), fileUpload({ limits: { fileSize: 2 *
|
|||||||
const newPath = path.join(dirname(), videoPath(id));
|
const newPath = path.join(dirname(), videoPath(id));
|
||||||
const thumbnailPath = path.join(dirname(), "videos", `${id}.png`);
|
const thumbnailPath = path.join(dirname(), "videos", `${id}.png`);
|
||||||
|
|
||||||
console.log(newPath);
|
const durationResult = await runCommand("ffprobe", ["-i", tempPath, "-show_format", "-loglevel", "error"]);
|
||||||
|
if (durationResult.error) {
|
||||||
let exitCode = await new Promise(resolve => {
|
return res.status(400).json({ ok: false, error: "invalid video file" });
|
||||||
const process = childProcess.spawn("ffmpeg", ["-i", tempPath, "-b:v", "1M", "-b:a", "192k", newPath]);
|
|
||||||
process.stderr.on("data", (data) => console.error(data.toString()));
|
|
||||||
process.on("close", resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
throw new Error("ffmpeg failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exitCode = await new Promise(resolve => {
|
const duration = parseFloat(durationResult.data.match(/duration=([.\d]+)/)[1]);
|
||||||
const process = childProcess.spawn("ffmpeg", ["-i", tempPath, "-ss", "00:00:01.000", "-vframes", "1", thumbnailPath]);
|
|
||||||
process.stderr.on("data", (data) => console.error(data.toString()));
|
const queueItem = {
|
||||||
process.on("close", resolve);
|
videoId: id,
|
||||||
|
userId,
|
||||||
|
errors: [],
|
||||||
|
progress: 0,
|
||||||
|
duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
videoQueue.push(queueItem);
|
||||||
|
|
||||||
|
const uploadProcess = childProcess.spawn("ffmpeg", ["-i", tempPath, "-b:v", "1M", "-b:a", "192k", "-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()));
|
||||||
|
thumbnailProcess.stderr.on("data", data => queueItem.errors.push(data.toString()));
|
||||||
|
|
||||||
|
uploadProcess.on("close", () => {
|
||||||
|
if (queueItem.errors.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbRun("INSERT INTO videos (id, user_id, title) VALUES (?, ?, ?)", id, userId, title);
|
||||||
|
|
||||||
|
const index = videoQueue.indexOf(item => item.videoId === queueItem.videoId)
|
||||||
|
videoQueue.splice(index, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
throw new Error("thumbnail generation failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
await dbRun("INSERT INTO videos (id, user_id, title) VALUES (?, ?, ?)", id, userId, title);
|
|
||||||
|
|
||||||
return res.status(200).json({ ok: true });
|
return res.status(200).json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get("/api/video-queue", authorized(), (req, res) => {
|
||||||
|
const userId = req.user.id;
|
||||||
|
|
||||||
|
const videos = videoQueue.filter(item => item.userId === userId);
|
||||||
|
|
||||||
|
return res.status(200).json({ ok: true, videos });
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/api/video-info", async (req, res) => {
|
app.get("/api/video-info", async (req, res) => {
|
||||||
const id = req.query["id"];
|
const id = req.query["id"];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user