From 73923e269ae840c46199f8d15aa7d6c273c5ae71 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Tue, 4 Oct 2022 19:12:41 +1100 Subject: Video attachment support! --- src/cdn/routes/attachments.ts | 44 ++++++++++++++++++++++++++++++++++++++++--- src/cdn/util/FileStorage.ts | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cdn/routes/attachments.ts b/src/cdn/routes/attachments.ts index 2a1b6f09..9bd256aa 100644 --- a/src/cdn/routes/attachments.ts +++ b/src/cdn/routes/attachments.ts @@ -5,6 +5,9 @@ import FileType from "file-type"; import { HTTPError } from "lambert-server"; import { multer } from "../util/multer"; import imageSize from "image-size"; +import ffmpeg from "fluent-ffmpeg"; +import Path from "path"; +import { Duplex, Readable, Transform, Writable } from "stream"; const router = Router(); @@ -15,6 +18,14 @@ const SANITIZED_CONTENT_TYPE = [ "application/xhtml+xml", ]; +const probe = (file: string): Promise => new Promise((resolve, reject) => { + ffmpeg.setFfprobePath(process.env.FFPROBE_PATH as string); + ffmpeg.ffprobe(file, (err, data) => { + if (err) return reject(err); + return resolve(data); + }); +}); + router.post( "/:channel_id", multer.single("file"), @@ -44,6 +55,13 @@ router.post( height = dimensions.height; } } + else if (mimetype.includes("video") && process.env.FFPROBE_PATH) { + const root = process.env.STORAGE_LOCATION || "../"; // hmm, stolen from FileStorage + const out = await probe(Path.join(root, path)); + const stream = out.streams[0]; // hmm + width = stream.width; + height = stream.height; + } const file = { id, @@ -63,10 +81,10 @@ router.get( "/:channel_id/:id/:filename", async (req: Request, res: Response) => { const { channel_id, id, filename } = req.params; + const { format } = req.query; - const file = await storage.get( - `attachments/${channel_id}/${id}/${filename}`, - ); + const path = `attachments/${channel_id}/${id}/${filename}`; + let file = await storage.get(path); if (!file) throw new HTTPError("File not found"); const type = await FileType.fromBuffer(file); let content_type = type?.mime || "application/octet-stream"; @@ -75,6 +93,26 @@ router.get( content_type = "application/octet-stream"; } + // lol, super gross + if (content_type.includes("video") && format == "jpeg" && process.env.FFMPEG_PATH) { + const promise = (): Promise => new Promise((resolve, reject) => { + ffmpeg.setFfmpegPath(process.env.FFMPEG_PATH as string); + const out: any[] = []; + const cmd = ffmpeg(Readable.from(file as Buffer)) + .format("mjpeg") + .frames(1) + .on("end", () => resolve(Buffer.concat(out))) + .on("error", (err) => reject(err)) + const stream = cmd.pipe(); + stream.on("data", (data) => { + out.push(data) + }); + }); + const res = await promise(); + file = res; + content_type = "jpeg"; + } + res.set("Content-Type", content_type); res.set("Cache-Control", "public, max-age=31536000"); diff --git a/src/cdn/util/FileStorage.ts b/src/cdn/util/FileStorage.ts index 0e31a50e..9386663f 100644 --- a/src/cdn/util/FileStorage.ts +++ b/src/cdn/util/FileStorage.ts @@ -35,7 +35,7 @@ export class FileStorage implements Storage { async set(path: string, value: any) { path = getPath(path); - if (!fs.existsSync(dirname(path))) fs.mkdirSync(dirname(path)); + if (!fs.existsSync(dirname(path))) fs.mkdirSync(dirname(path), { recursive: true }); value = Readable.from(value); const cleaned_file = fs.createWriteStream(path); -- cgit 1.4.1