mirror of
https://github.com/C4illin/ConvertX.git
synced 2026-09-12 09:57:46 +02:00
Add converting from URL (#11)
This commit is contained in:
committed by
GitHub
parent
32d1ce6c28
commit
6a7ff645fe
@@ -1,4 +1,6 @@
|
||||
const webroot = document.querySelector("meta[name='webroot']").content;
|
||||
const urlInput = document.querySelector("#url-input");
|
||||
const urlSubmit = document.querySelector("#url-submit");
|
||||
const fileInput = document.querySelector('input[type="file"]');
|
||||
const dropZone = document.getElementById("dropzone");
|
||||
const convertButton = document.querySelector("input[type='submit']");
|
||||
@@ -33,6 +35,35 @@ dropZone.addEventListener("drop", (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
urlSubmit.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
handleUrl(urlInput.value);
|
||||
});
|
||||
|
||||
function handleUrl(url) {
|
||||
fetch(`${webroot}/url`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ url }),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const fileList = document.querySelector("#file-list");
|
||||
|
||||
const row = document.createElement("tr");
|
||||
row.innerHTML = `
|
||||
<td>${res.filename}</td>
|
||||
<td></td>
|
||||
<td>${(res.fileSizeBytes / 1024).toFixed(2)} kB</td>
|
||||
<td><a onclick="deleteRow(this)">Remove</a></td>
|
||||
`;
|
||||
|
||||
fileList.appendChild(row);
|
||||
fileNames.push(res.filename);
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
// Extracted handleFile function for reusability in drag-and-drop and file input
|
||||
function handleFile(file) {
|
||||
const fileList = document.querySelector("#file-list");
|
||||
|
||||
@@ -16,6 +16,7 @@ import { listConverters } from "./pages/listConverters";
|
||||
import { results } from "./pages/results";
|
||||
import { root } from "./pages/root";
|
||||
import { upload } from "./pages/upload";
|
||||
import { url } from "./pages/url";
|
||||
import { user } from "./pages/user";
|
||||
import { healthcheck } from "./pages/healthcheck";
|
||||
|
||||
@@ -41,6 +42,7 @@ const app = new Elysia({
|
||||
.use(user)
|
||||
.use(root)
|
||||
.use(upload)
|
||||
.use(url)
|
||||
.use(history)
|
||||
.use(convert)
|
||||
.use(download)
|
||||
|
||||
@@ -152,6 +152,20 @@ export const root = new Elysia().use(userService).get(
|
||||
class="absolute inset-0 size-full cursor-pointer opacity-0"
|
||||
/>
|
||||
</div>
|
||||
<label class="mt-4 flex flex-col gap-1 text-neutral-400">
|
||||
Or enter a URL
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
name="url"
|
||||
id="url-input"
|
||||
class="mr-2 flex-auto rounded-sm bg-neutral-800 p-3"
|
||||
placeholder="https://example.com/cat.jpg"
|
||||
/>
|
||||
<button id="url-submit" type="button" class="flex-initial btn-secondary">
|
||||
Add URL
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
</article>
|
||||
<form
|
||||
method="post"
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import { uploadsDir } from "..";
|
||||
import db from "../db/db";
|
||||
import { WEBROOT } from "../helpers/env";
|
||||
import { userService } from "./user";
|
||||
import sanitize from "sanitize-filename";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import mime from "mime";
|
||||
|
||||
const getFilename = (url: string, headers: Headers) => {
|
||||
const contentDisposition = headers.get("Content-Disposition");
|
||||
if (contentDisposition) {
|
||||
const match = /filename="([^"]+)"/.exec(contentDisposition);
|
||||
if (match && match[1]) {
|
||||
return sanitize(match[1]);
|
||||
}
|
||||
}
|
||||
const path = new URL(url).pathname;
|
||||
const lastPart = path.split("/").at(-1);
|
||||
const contentType = headers.get("content-type");
|
||||
const extension = contentType ? mime.getExtension(contentType) : null;
|
||||
if (!lastPart) {
|
||||
if (extension) {
|
||||
return `${randomUUID()}.${extension}`;
|
||||
}
|
||||
return randomUUID();
|
||||
}
|
||||
if (!lastPart.includes(".") && extension) {
|
||||
return `${sanitize(lastPart)}.${extension}`;
|
||||
}
|
||||
return sanitize(lastPart);
|
||||
};
|
||||
|
||||
export const url = new Elysia().use(userService).post(
|
||||
"/url",
|
||||
async ({ body, redirect, user, cookie: { jobId } }) => {
|
||||
if (!jobId?.value) {
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
|
||||
const existingJob = await db
|
||||
.query("SELECT * FROM jobs WHERE id = ? AND user_id = ?")
|
||||
.get(jobId.value, user.id);
|
||||
|
||||
if (!existingJob) {
|
||||
return redirect(`${WEBROOT}/`, 302);
|
||||
}
|
||||
|
||||
const userUploadsDir = `${uploadsDir}${user.id}/${jobId.value}/`;
|
||||
|
||||
const res = await fetch(body.url);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to download URL, received ${res.status}`);
|
||||
}
|
||||
const filename = getFilename(body.url, res.headers);
|
||||
const fileSizeBytes = await Bun.write(`${userUploadsDir}${filename}`, await res.blob());
|
||||
|
||||
return {
|
||||
message: "Files downloaded successfully.",
|
||||
filename,
|
||||
fileSizeBytes,
|
||||
};
|
||||
},
|
||||
{ body: t.Object({ url: t.String() }), auth: true },
|
||||
);
|
||||
Reference in New Issue
Block a user