Files
pozor/app/api/github-photos/route.ts
T
2026-06-05 03:02:41 +03:00

117 lines
2.8 KiB
TypeScript

import { NextResponse } from "next/server";
import { boardConfig } from "../../../board.config";
type GithubContent = {
name: string;
path: string;
type: "file" | "dir";
download_url: string | null;
html_url: string;
};
type ShamePhoto = {
name: string;
path: string;
url: string;
htmlUrl: string;
};
const imageExtensionPattern = /\.(avif|gif|jpe?g|png|webp)$/i;
function parseRepo(value: string | null) {
const clean = value?.trim().replace(/^https:\/\/github\.com\//, "") ?? "";
const [owner, repo] = clean.split("/");
if (!owner || !repo) {
return null;
}
return {
owner,
repo: repo.replace(/\.git$/, "")
};
}
async function fetchDirectory(owner: string, repo: string, path: string, branch?: string) {
const encodedPath = path
.split("/")
.filter(Boolean)
.map((part) => encodeURIComponent(part))
.join("/");
const url = new URL(`https://api.github.com/repos/${owner}/${repo}/contents/${encodedPath}`);
if (branch) {
url.searchParams.set("ref", branch);
}
const response = await fetch(url, {
headers: {
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28"
},
next: { revalidate: 60 }
});
if (!response.ok) {
return {
ok: false as const,
status: response.status,
message: response.status === 404 ? "Repository or folder was not found." : "GitHub did not return the photo list."
};
}
const content = (await response.json()) as GithubContent[] | GithubContent;
const items = Array.isArray(content) ? content : [content];
return {
ok: true as const,
items
};
}
export async function GET() {
const branch = boardConfig.branch || undefined;
const path = boardConfig.photosPath;
const parsedRepo = parseRepo(boardConfig.repo);
if (!parsedRepo) {
return NextResponse.json({
photos: [],
repo: null,
path,
message: "Set a GitHub repository to load the board."
});
}
const directory = await fetchDirectory(parsedRepo.owner, parsedRepo.repo, path, branch);
if (!directory.ok) {
return NextResponse.json(
{
photos: [],
repo: `${parsedRepo.owner}/${parsedRepo.repo}`,
path,
message: directory.message
},
{ status: directory.status }
);
}
const photos: ShamePhoto[] = directory.items
.filter((item) => item.type === "file" && item.download_url && imageExtensionPattern.test(item.name))
.map((item) => ({
name: item.name.replace(imageExtensionPattern, ""),
path: item.path,
url: item.download_url as string,
htmlUrl: item.html_url
}));
return NextResponse.json({
photos,
repo: `${parsedRepo.owner}/${parsedRepo.repo}`,
path,
branch: branch ?? null,
message: photos.length ? null : "No image files were found in that GitHub folder."
});
}