Files

106 lines
3.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/media.mjs — Openinary (media.ayris.tech) proxy, "mucomutfak" klasörüne kilitli
const BASE = () => process.env.OPENINARY_API_URL?.replace(/\/$/, "");
const KEY = () => process.env.OPENINARY_API_KEY;
export const MEDIA_ROOT = "mucomutfak";
export function mediaEnabled() {
return Boolean(BASE() && KEY());
}
function assertInsideRoot(p) {
const clean = String(p || "").replace(/^\/+|\/+$/g, "");
if (
clean !== MEDIA_ROOT &&
!clean.startsWith(`${MEDIA_ROOT}/`)
) {
throw Object.assign(new Error(`Yol '${MEDIA_ROOT}' klasörü içinde olmalı`), {
status: 400,
});
}
if (clean.includes("..")) {
throw Object.assign(new Error("Geçersiz yol"), { status: 400 });
}
return clean;
}
function deliveryUrl(path, transform = "") {
const t = transform ? `${transform}/` : "";
return `${BASE()}/t/${t}${path}`;
}
// Klasör içeriğini listele
export async function listMedia(path = MEDIA_ROOT) {
const clean = assertInsideRoot(path);
const res = await fetch(
`${BASE()}/api/storage?path=${encodeURIComponent(clean)}`,
{ headers: { Authorization: `Bearer ${KEY()}` } },
);
if (!res.ok) {
throw Object.assign(new Error(`Openinary listeleme hatası (${res.status})`), {
status: 502,
});
}
const data = await res.json();
const IMG_RE = /\.(webp|jpe?g|png|gif|svg|avif|heic|heif)$/i;
return {
path: clean,
folders: (data.folders || []).map((f) => ({ name: f.name, path: f.path })),
files: (data.files || [])
.filter((f) => IMG_RE.test(f.name))
.map((f) => ({
name: f.name,
path: f.path,
size: f.size,
mtime: f.mtime,
url: deliveryUrl(f.path),
thumb: deliveryUrl(f.path, "w_240,h_240,c_fill"),
})),
};
}
// Multipart isteği olduğu gibi Openinary'ye aktar (folder alanı client FormData'sında)
export async function proxyUpload(req) {
const res = await fetch(`${BASE()}/api/upload`, {
method: "POST",
headers: {
Authorization: `Bearer ${KEY()}`,
"content-type": req.headers["content-type"],
...(req.headers["content-length"]
? { "content-length": req.headers["content-length"] }
: {}),
},
body: req,
duplex: "half",
});
const body = await res.json().catch(() => ({}));
if (body?.files) {
for (const f of body.files) {
if (f.path) {
f.url = deliveryUrl(f.path);
f.thumb = deliveryUrl(f.path, "w_240,h_240,c_fill");
}
}
}
return { status: res.status, body };
}
export async function deleteMedia(path) {
const clean = assertInsideRoot(path);
if (clean === MEDIA_ROOT) {
throw Object.assign(new Error("Kök klasör silinemez"), { status: 400 });
}
const res = await fetch(
`${BASE()}/api/storage/${clean
.split("/")
.map(encodeURIComponent)
.join("/")}`,
{ method: "DELETE", headers: { Authorization: `Bearer ${KEY()}` } },
);
if (!res.ok) {
throw Object.assign(new Error(`Silme hatası (${res.status})`), {
status: 502,
});
}
return true;
}