import { mkdir } from "node:fs/promises"; import { Elysia, t } from "elysia"; import sanitize from "sanitize-filename"; import { outputDir, uploadsDir } from ".."; import { mainConverter } from "../converters/main"; import { WEBROOT } from "../helpers/env"; import db from "../db/db"; import { normalizeFiletype, normalizeOutputFiletype, } from "../helpers/normalizeFiletype"; import { userService } from "./user"; import { Jobs } from "../db/types"; export const convert = new Elysia().use(userService).post( "/convert", async ({ body, redirect, jwt, cookie: { auth, jobId } }) => { if (!auth?.value) { return redirect(`${WEBROOT}/login`, 302); } const user = await jwt.verify(auth.value); if (!user) { return redirect(`${WEBROOT}/login`, 302); } if (!jobId?.value) { return redirect(`${WEBROOT}/`, 302); } const existingJob = db .query("SELECT * FROM jobs WHERE id = ? AND user_id = ?") .as(Jobs) .get(jobId.value, user.id); if (!existingJob) { return redirect(`${WEBROOT}/`, 302); } const userUploadsDir = `${uploadsDir}${user.id}/${jobId.value}/`; const userOutputDir = `${outputDir}${user.id}/${jobId.value}/`; // create the output directory try { await mkdir(userOutputDir, { recursive: true }); } catch (error) { console.error( `Failed to create the output directory: ${userOutputDir}.`, error, ); } const convertTo = normalizeFiletype(body.convert_to.split(",")[0] ?? ""); const converterName = body.convert_to.split(",")[1]; const fileNames = JSON.parse(body.file_names) as string[]; for (let i = 0; i < fileNames.length; i++) { fileNames[i] = sanitize(fileNames[i] || ""); } if (!Array.isArray(fileNames) || fileNames.length === 0) { return redirect(`${WEBROOT}/`, 302); } db.query( "UPDATE jobs SET num_files = ?1, status = 'pending' WHERE id = ?2", ).run(fileNames.length, jobId.value); const query = db.query( "INSERT INTO file_names (job_id, file_name, output_file_name, status) VALUES (?1, ?2, ?3, ?4)", ); // Start the conversion process in the background Promise.all( fileNames.map(async (fileName) => { const filePath = `${userUploadsDir}${fileName}`; const fileTypeOrig = fileName.split(".").pop() ?? ""; const fileType = normalizeFiletype(fileTypeOrig); const newFileExt = normalizeOutputFiletype(convertTo); const newFileName = fileName.replace( new RegExp(`${fileTypeOrig}(?!.*${fileTypeOrig})`), newFileExt, ); const targetPath = `${userOutputDir}${newFileName}`; const result = await mainConverter( filePath, fileType, convertTo, targetPath, {}, converterName, ); if (jobId.value) { query.run(jobId.value, fileName, newFileName, result); } }), ) .then(() => { // All conversions are done, update the job status to 'completed' if (jobId.value) { db.query("UPDATE jobs SET status = 'completed' WHERE id = ?1").run( jobId.value, ); } // delete all uploaded files in userUploadsDir // rmSync(userUploadsDir, { recursive: true, force: true }); }) .catch((error) => { console.error("Error in conversion process:", error); }); // Redirect the client immediately return redirect(`${WEBROOT}/results/${jobId.value}`, 302); }, { body: t.Object({ convert_to: t.String(), file_names: t.String(), }), }, );