huge update (pls dont break)

This commit is contained in:
2025-12-06 04:07:19 +01:00
parent b76a113c4d
commit e54214a92b
10 changed files with 401 additions and 277 deletions
-113
View File
@@ -1,113 +0,0 @@
import { type NextRequest, NextResponse } from "next/server";
import { subjects } from "@/utils/subjects";
export async function GET(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
const vizsgatargy = searchParams.get("vizsgatargy");
const ev = searchParams.get("ev");
const idoszak = searchParams.get("idoszak");
const szint = searchParams.get("szint");
if (!vizsgatargy && !ev && !idoszak && !szint) {
const currentYear = new Date().getFullYear();
return NextResponse.json({
parameters: {
vizsgatargy: {
type: "string",
required: true,
values: subjects.map((s) => ({
value: s.value,
label: s.label,
})),
},
ev: {
type: "integer",
required: true,
values: `2013 - ${currentYear}`,
},
idoszak: {
type: "string",
required: true,
values: ["tavasz", "osz"],
},
szint: {
type: "string",
required: true,
values: ["kozep", "emelt"],
},
},
example:
"/api/erettsegi?vizsgatargy=mat&ev=2023&idoszak=tavasz&szint=kozep",
});
}
if (!vizsgatargy || !ev || !idoszak || !szint) {
const missingParams = [
!vizsgatargy && "vizsgatargy",
!ev && "ev",
!idoszak && "idoszak",
!szint && "szint",
].filter(Boolean);
return NextResponse.json(
{ error: `Hiányzó paraméterek: ${missingParams.join(", ")}` },
{ status: 400 },
);
}
if (parseInt(ev, 10) <= 2012) {
return NextResponse.json({ error: "Érvénytelen év" }, { status: 400 });
}
const validSubjects = subjects.map((subject) => subject.value);
if (!validSubjects.includes(vizsgatargy)) {
return NextResponse.json(
{ error: "Érvénytelen vizsgatárgy" },
{ status: 400 },
);
}
const honap = idoszak === "osz" ? "okt" : "maj";
const prefix = szint === "emelt" ? `e_${vizsgatargy}` : `k_${vizsgatargy}`;
const protocol =
req.headers.get("x-forwarded-proto") === "https" ? "https" : "http";
const host = req.headers.get("host");
const baseUrl = `https://dload-oktatas.educatio.hu/erettsegi/feladatok_${ev}${idoszak}_${szint}/`;
const proxiedUrl = `${protocol}://${host}/api/proxy?link=${encodeURI(
baseUrl,
)}`;
const shortev = ev.slice(-2);
const feladat = "fl";
const utmutato = "ut";
const forras = "for";
const megoldas = "meg";
const urls = {
flPdfUrl: `${proxiedUrl}${prefix}_${shortev}${honap}_${feladat}.pdf`,
utPdfUrl: `${proxiedUrl}${prefix}_${shortev}${honap}_${utmutato}.pdf`,
flZipUrl: ["inf", "infoism", "digkult"].includes(vizsgatargy)
? `${baseUrl}${prefix}${forras}_${shortev}${honap}_${feladat}.zip`
: undefined,
utZipUrl: ["inf", "infoism", "digkult"].includes(vizsgatargy)
? `${baseUrl}${prefix}${megoldas}_${shortev}${honap}_${utmutato}.zip`
: undefined,
flMp3Url: ["angol", "nemet"].includes(vizsgatargy)
? `${baseUrl}${prefix}_${shortev}${honap}_${feladat}.mp3`
: undefined,
};
return NextResponse.json(urls, {
status: 200,
headers: { "Cache-Control": "s-maxage=31536000" },
});
} catch (e: unknown) {
console.error("An unexpected error occurred in the API route:", e);
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 },
);
}
}
-68
View File
@@ -1,68 +0,0 @@
import { type NextRequest, NextResponse } from "next/server";
export async function GET(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
const link = searchParams.get("link");
if (!link) {
return NextResponse.json({
parameters: {
link: {
type: "string",
required: true,
},
},
example: `/api/proxy?link=https://dload-oktatas.educatio.hu/erettsegi/feladatok_2023tavasz_kozep/k_mat_23maj_fl.pdf`,
});
}
let url: URL;
try {
url = new URL(link);
} catch {
return NextResponse.json(
{ error: "Érvénytelen link formátum" },
{ status: 400 },
);
}
if (url.hostname !== "dload-oktatas.educatio.hu") {
return NextResponse.json({ error: "Érvénytelen link" }, { status: 400 });
}
const externalResponse = await fetch(link, {
method: "GET",
});
if (!externalResponse.ok) {
return NextResponse.json(
{ error: "Hiba történt a külső forrás lekérése során." },
{ status: externalResponse.status },
);
}
const headers = new Headers(externalResponse.headers);
headers.set("Cache-Control", "s-maxage=31536000, stale-while-revalidate");
const contentType = externalResponse.headers.get("content-type");
if (contentType === "application/pdf") {
const filename = url.pathname.split("/").pop() ?? "document.pdf";
headers.set("Content-Disposition", `inline; filename="${filename}"`);
}
return new NextResponse(externalResponse.body, {
status: 200,
headers,
});
} catch (e: unknown) {
console.error("Proxy Error:", e);
const errorMessage =
e instanceof Error ? e.message : "An unexpected internal error occurred";
return NextResponse.json(
{ error: "Internal Server Error", message: errorMessage },
{ status: 500 },
);
}
}
-61
View File
@@ -1,61 +0,0 @@
import { type NextRequest, NextResponse } from "next/server";
const ALLOWED_HOSTS = [
"localhost:3000",
"erettsegi.albert.lol",
"dload-oktatas.educatio.hu",
];
export async function GET(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
let link = searchParams.get("link");
if (!link) {
return NextResponse.json({
parameters: {
link: {
type: "string",
required: true,
allowed_hosts: ALLOWED_HOSTS,
},
},
example: `/api/validate?link=https://dload-oktatas.educatio.hu/erettsegi/feladatok_2023tavasz_kozep/k_mat_23maj_fl.pdf`,
});
}
let url: URL;
try {
url = new URL(link);
} catch {
return NextResponse.json(
{ error: "Érvénytelen link formátum" },
{ status: 400 },
);
}
if (url.pathname === "/api/proxy" && url.searchParams.has("link")) {
const realTarget = url.searchParams.get("link");
if (realTarget) {
try {
const realUrl = new URL(realTarget);
link = realTarget;
url = realUrl;
} catch {}
}
}
if (!ALLOWED_HOSTS.includes(url.host)) {
return NextResponse.json({ error: "Érvénytelen link" }, { status: 400 });
}
const response = await fetch(link, {
method: "HEAD",
});
return NextResponse.json({ status: response.status }, { status: 200 });
} catch (error) {
console.error("Validation Error:", error);
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
}
+76
View File
@@ -0,0 +1,76 @@
import { type NextRequest, NextResponse } from "next/server";
import { parseSegments } from "@/utils/edu";
import { subjects } from "@/utils/subjects";
const LABELS = {
periods: { tavasz: "Tavasz", osz: "Ősz" } as Record<string, string>,
levels: { kozep: "Közép", emelt: "Emelt" } as Record<string, string>,
};
export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ slug: string[] }> },
) {
try {
const { slug } = await params;
const query = parseSegments(slug);
const { subject, year, period, level } = query;
const isComplete = subject && year && period && level;
if (isComplete) {
const protocol =
req.headers.get("x-forwarded-proto") === "https" ? "https" : "http";
const host = req.headers.get("host");
const proxyBase = `${protocol}://${host}/proxy/${subject.slug}/${year}/${period}/${level}`;
const makeLink = (type: string) => `${proxyBase}/${type}`;
return NextResponse.json({
found: true,
meta: {
subject: subject.label,
year,
period: LABELS.periods[period] ?? period,
level: LABELS.levels[level] ?? level,
},
links: {
flPdfUrl: makeLink("feladat"),
utPdfUrl: makeLink("utmutato"),
flZipUrl: ["inf", "infoism", "digkult"].includes(subject.value)
? makeLink("forras")
: undefined,
utZipUrl: ["inf", "infoism", "digkult"].includes(subject.value)
? makeLink("megoldas")
: undefined,
flMp3Url: ["angol", "nemet"].includes(subject.value)
? makeLink("hang")
: undefined,
},
});
}
const suggestions = {
found: false,
message: "Missing parameters",
currentSelection: {
subject: subject?.label || null,
year: year || null,
period: period ? (LABELS.periods[period] ?? period) : null,
level: level ? (LABELS.levels[level] ?? level) : null,
},
options: {
subjects: !subject ? subjects.map((s) => s.slug) : undefined,
years: !year ? "2013 - 2024" : undefined,
periods: !period ? Object.values(LABELS.periods) : undefined,
levels: !level ? Object.values(LABELS.levels) : undefined,
},
};
return NextResponse.json(suggestions);
} catch (e) {
console.error(e);
return NextResponse.json({ error: "Server Error" }, { status: 500 });
}
}
+55
View File
@@ -0,0 +1,55 @@
import { type NextRequest, NextResponse } from "next/server";
import { parseSegments, getExternalUrl, type ResourceSlug } from "@/utils/edu";
export async function GET(
_req: NextRequest,
{ params }: { params: Promise<{ slug: string[] }> },
) {
try {
const { slug } = await params;
const { subject, year, period, level, resourceType } = parseSegments(slug);
if (!subject || !year || !period || !level || !resourceType) {
return NextResponse.json(
{ error: "Invalid download link. Missing parameters." },
{ status: 400 },
);
}
const targetUrl = getExternalUrl(
subject.value,
year,
period,
level,
resourceType as ResourceSlug,
);
if (!targetUrl) {
return NextResponse.json(
{ error: "This file type does not exist for this subject." },
{ status: 404 },
);
}
const externalResponse = await fetch(targetUrl, { method: "GET" });
if (!externalResponse.ok) {
return NextResponse.json(
{ error: "File not found on external server." },
{ status: 404 },
);
}
const headers = new Headers(externalResponse.headers);
headers.set("Cache-Control", "s-maxage=31536000, stale-while-revalidate");
const filename = targetUrl.split("/").pop() ?? "erettsegi_file";
headers.set("Content-Disposition", `inline; filename="${filename}"`);
return new NextResponse(externalResponse.body, { status: 200, headers });
} catch (e) {
console.error("Proxy Error", e);
return NextResponse.json({ error: "Internal Error" }, { status: 500 });
}
}
+30
View File
@@ -0,0 +1,30 @@
import { type NextRequest, NextResponse } from "next/server";
import { parseSegments, getExternalUrl, type ResourceSlug } from "@/utils/edu";
export async function GET(
_req: NextRequest,
{ params }: { params: Promise<{ slug: string[] }> },
) {
try {
const { slug } = await params;
const { subject, year, period, level, resourceType } = parseSegments(slug);
if (!subject || !year || !period || !level || !resourceType) {
return NextResponse.json({ status: 400 });
}
const targetUrl = getExternalUrl(
subject.value,
year,
period,
level,
resourceType as ResourceSlug,
);
if (!targetUrl) return NextResponse.json({ status: 404 });
const res = await fetch(targetUrl, { method: "HEAD" });
return NextResponse.json({ status: res.status });
} catch {
return NextResponse.json({ status: 500 });
}
}