diff --git a/Dockerfile b/Dockerfile
index 6d8225a..f720809 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -53,7 +53,8 @@ RUN apk --no-cache add \
poppler-utils \
gcompat \
libva-utils \
- py3-numpy
+ py3-numpy \
+ zip
RUN apk --no-cache add calibre --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/
diff --git a/public/results.js b/public/results.js
index 7659edb..a3b6db3 100644
--- a/public/results.js
+++ b/public/results.js
@@ -13,6 +13,33 @@ window.downloadAll = function () {
}, index * 100);
});
};
+
+window.downloadZip = function () {
+ const jobId = window.location.pathname.split("/").pop();
+ const userId = document.querySelector("meta[name='user-id']").content;
+
+ fetch(`${webroot}/zip/${userId}/${jobId}`, {
+ method: "GET",
+ })
+ .then((res) => {
+ if (res.ok) {
+ return res.blob();
+ }
+
+ return Promise.reject(new Error("Failed to download zip"));
+ })
+ .then((blob) => {
+ const url = window.URL.createObjectURL(blob);
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = `convertx-${userId}-${jobId}.zip`;
+ document.body.appendChild(a);
+ a.click();
+ a.remove();
+ })
+ .catch((err) => console.log(err));
+};
+
const jobId = window.location.pathname.split("/").pop();
const main = document.querySelector("main");
let progressElem = document.querySelector("progress");
diff --git a/src/components/base.tsx b/src/components/base.tsx
index 9f3db2e..748c4a1 100644
--- a/src/components/base.tsx
+++ b/src/components/base.tsx
@@ -4,16 +4,19 @@ export const BaseHtml = ({
children,
title = "ConvertX",
webroot = "",
+ userId = "",
}: {
children: JSX.Element;
title?: string;
webroot?: string;
+ userId?: string;
}) => (
+
{title}
{
+ return new Promise((resolve, reject) => {
+ const absoluteInputPath = path.resolve(inputPath);
+ const absoluteOutputPath = path.resolve(outputPath);
+
+ const allTargets = getAllTargets();
+ const supportedExtensions = new Set();
+
+ Object.values(allTargets).forEach((extensions) => {
+ extensions.forEach((ext) => supportedExtensions.add(ext));
+ });
+
+ fs.readdir(absoluteInputPath, { withFileTypes: true }, (err, entries) => {
+ if (err) {
+ return reject(err);
+ }
+
+ const files = entries
+ .filter((entry) => entry.isFile())
+ .filter((entry) => entry.name !== path.basename(outputPath))
+ .map((entry) => entry.name)
+ .filter((filename) => {
+ // We don't want to zip files with unsafe characters
+ if (!/^[a-zA-Z0-9._-]+\.[a-zA-Z0-9]+$/.test(filename)) {
+ return false;
+ }
+
+ const extension = path.extname(filename).substring(1).toLowerCase();
+ return supportedExtensions.has(extension);
+ });
+
+ if (files.length === 0) {
+ return reject(new Error("No files to zip"));
+ }
+
+ execFile(
+ "zip",
+ ["-j", absoluteOutputPath, ...files],
+ { cwd: absoluteInputPath },
+ (error, stdout, stderr) => {
+ if (error) {
+ reject(error);
+ }
+
+ if (stdout) {
+ console.log(`stdout: ${stdout}`);
+ }
+
+ if (stderr) {
+ console.error(`stderr: ${stderr}`);
+ }
+
+ resolve("Done");
+ },
+ );
+ });
+ });
+};
diff --git a/src/index.tsx b/src/index.tsx
index 1041320..fb9a408 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -20,6 +20,7 @@ import {
normalizeOutputFiletype,
} from "./helpers/normalizeFiletype";
import "./helpers/printVersions";
+import { zip } from "./helpers/zip";
mkdir("./data", { recursive: true }).catch(console.error);
const db = new Database("./data/mydb.sqlite", { create: true });
@@ -563,7 +564,7 @@ const app = new Elysia({
console.log("jobId set to:", id);
return (
-
+
<>
job.num_files > 0);
return (
-
+
<>
+
<>
Results
-