[+] Un-shortlink
This commit is contained in:
+25
-23
@@ -1,4 +1,4 @@
|
|||||||
import { Elysia, t } from "elysia"
|
import { Elysia, redirect, t } from "elysia"
|
||||||
import ExifReader from "exifreader"
|
import ExifReader from "exifreader"
|
||||||
import { exists, mkdir } from "fs/promises"
|
import { exists, mkdir } from "fs/promises"
|
||||||
|
|
||||||
@@ -52,18 +52,10 @@ async function saveMetadata(data: PhotoMetadata[]): Promise<void> {
|
|||||||
* Extracts EXIF data from an uploaded file.
|
* Extracts EXIF data from an uploaded file.
|
||||||
*/
|
*/
|
||||||
async function getExifData(file: File): Promise<any> {
|
async function getExifData(file: File): Promise<any> {
|
||||||
try {
|
return ExifReader.load(await file.arrayBuffer(), {
|
||||||
const buffer = await file.arrayBuffer()
|
expanded: true,
|
||||||
// Set options to not parse maker notes or unknown tags for speed
|
includeUnknown: false,
|
||||||
const tags = ExifReader.load(buffer, {
|
})
|
||||||
expanded: true,
|
|
||||||
includeUnknown: false,
|
|
||||||
})
|
|
||||||
return tags
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error parsing EXIF for ${file.name}:`, e)
|
|
||||||
return { error: "Could not parse EXIF data." }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Elysia Server ---
|
// --- Elysia Server ---
|
||||||
@@ -80,8 +72,6 @@ function checkHeaderKey(headers: Record<string, string | undefined>, expectList:
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const app = new Elysia()
|
export const app = new Elysia()
|
||||||
.get("/", () => "Running!")
|
|
||||||
|
|
||||||
// Error handling: Return status code and message
|
// Error handling: Return status code and message
|
||||||
.onError(({ error, status }) => {
|
.onError(({ error, status }) => {
|
||||||
if (error instanceof HttpError) {
|
if (error instanceof HttpError) {
|
||||||
@@ -91,16 +81,17 @@ export const app = new Elysia()
|
|||||||
// else return status(500, { error: "Internal Server Error" })
|
// else return status(500, { error: "Internal Server Error" })
|
||||||
else throw error
|
else throw error
|
||||||
})
|
})
|
||||||
|
.get("/", ({ redirect }) => redirect("https://aza.moe/photo"))
|
||||||
|
|
||||||
.post("/upload", async ({ body, headers, status }) => {
|
.post("/upload", async ({ body, headers, status }) => {
|
||||||
const { id, owner_key, photo, edited_photo } = body
|
const { owner_key, photo, edited_photo } = body
|
||||||
checkHeaderKey(headers)
|
checkHeaderKey(headers)
|
||||||
|
|
||||||
// 2. Check for existing ID
|
// Generate an ID of 8 characters
|
||||||
const metadata = await getMetadata()
|
const id = Math.random().toString(36).substring(2, 10)
|
||||||
if (metadata.find((m) => m.id === id)) done(409, "This ID already exists")
|
let metadata = await getMetadata()
|
||||||
|
|
||||||
// 3. Process and save files
|
// Process and save files
|
||||||
// We use {id}-1 and {id}-2 as requested by "{id}-{number}"
|
// We use {id}-1 and {id}-2 as requested by "{id}-{number}"
|
||||||
const originalExt = photo.name.split(".").pop() || "jpg"
|
const originalExt = photo.name.split(".").pop() || "jpg"
|
||||||
const editedExt = edited_photo.name.split(".").pop() || "jpg"
|
const editedExt = edited_photo.name.split(".").pop() || "jpg"
|
||||||
@@ -119,8 +110,7 @@ export const app = new Elysia()
|
|||||||
|
|
||||||
// 4. Create new metadata entry
|
// 4. Create new metadata entry
|
||||||
const newEntry: PhotoMetadata = {
|
const newEntry: PhotoMetadata = {
|
||||||
id: id,
|
id, owner_key,
|
||||||
owner_key: owner_key,
|
|
||||||
upload_time: new Date().toISOString(),
|
upload_time: new Date().toISOString(),
|
||||||
original_photo: {
|
original_photo: {
|
||||||
filename: photo.name,
|
filename: photo.name,
|
||||||
@@ -142,7 +132,6 @@ export const app = new Elysia()
|
|||||||
}, {
|
}, {
|
||||||
// --- Validation Schema ---
|
// --- Validation Schema ---
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
id: t.String(),
|
|
||||||
owner_key: t.String(),
|
owner_key: t.String(),
|
||||||
photo: t.File({
|
photo: t.File({
|
||||||
type: ["image/jpeg", "image/png", "image/webp", "image/avif", "image/heic", "image/heif"],
|
type: ["image/jpeg", "image/png", "image/webp", "image/avif", "image/heic", "image/heif"],
|
||||||
@@ -217,6 +206,19 @@ export const app = new Elysia()
|
|||||||
body: t.Object({ id: t.String(), key: t.String(), field: t.String(), value: t.Any() })
|
body: t.Object({ id: t.String(), key: t.String(), field: t.String(), value: t.Any() })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Redirect for short links. ID can be either ID or owner_key
|
||||||
|
.get("/:id", async ({ params, redirect }) => {
|
||||||
|
const { id } = params
|
||||||
|
const metadata = await getMetadata()
|
||||||
|
|
||||||
|
const photo = metadata.find((p) => p.id === id) || metadata.find((p) => p.owner_key === id)
|
||||||
|
if (!photo || photo.hide === true) done(404, "Photo not found")
|
||||||
|
|
||||||
|
return redirect(`https://aza.moe/photo/${photo.id}`)
|
||||||
|
}, {
|
||||||
|
params: t.Object({ id: t.String() })
|
||||||
|
})
|
||||||
|
|
||||||
.listen(3000)
|
.listen(3000)
|
||||||
|
|
||||||
console.log(`🦊 Elysia server running at http://${app.server?.hostname}:${app.server?.port}`)
|
console.log(`🦊 Elysia server running at http://${app.server?.hostname}:${app.server?.port}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user