mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 06:15:39 -04:00
Introduce a local disk cache for TMDB images served through a proxy API route (/api/images/[...path]), eliminating direct client-side CDN dependencies. Images are cached by category (posters, backdrops, stills, logos) and served with immutable cache headers. Move all tmdbImageUrl() calls from client components to API routes and server components so clients receive ready-to-use URLs. This removes the need to expose TMDB_IMAGE_BASE_URL and IMAGE_CACHE_ENABLED via next.config.ts env block. The landing page is split into a server wrapper (app/page.tsx) and client component (components/landing-page.tsx). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import { type NextRequest, NextResponse } from "next/server";
|
|
import { isTmdbConfigured } from "@/lib/config";
|
|
import { searchMovies, searchMulti, searchTv } from "@/lib/tmdb/client";
|
|
import { tmdbImageUrl } from "@/lib/tmdb/image";
|
|
import type { TmdbSearchResponse } from "@/lib/tmdb/types";
|
|
|
|
export async function GET(req: NextRequest) {
|
|
if (!isTmdbConfigured()) {
|
|
return NextResponse.json(
|
|
{
|
|
error: "TMDB API key is not configured. Visit /setup for instructions.",
|
|
code: "TMDB_NOT_CONFIGURED",
|
|
},
|
|
{ status: 503 },
|
|
);
|
|
}
|
|
|
|
const query = req.nextUrl.searchParams.get("query");
|
|
const type = req.nextUrl.searchParams.get("type");
|
|
|
|
if (!query)
|
|
return NextResponse.json(
|
|
{ error: "query parameter is required" },
|
|
{ status: 400 },
|
|
);
|
|
|
|
let results: TmdbSearchResponse;
|
|
if (type === "movie") {
|
|
results = await searchMovies(query);
|
|
} else if (type === "tv") {
|
|
results = await searchTv(query);
|
|
} else {
|
|
results = await searchMulti(query);
|
|
}
|
|
|
|
// Filter out person results from multi search
|
|
const filtered = results.results.filter(
|
|
(r) => r.media_type !== "person" || type,
|
|
);
|
|
|
|
return NextResponse.json({
|
|
results: filtered.map((r) => ({
|
|
tmdbId: r.id,
|
|
type: r.media_type ?? type,
|
|
title: r.title ?? r.name,
|
|
overview: r.overview,
|
|
releaseDate: r.release_date ?? r.first_air_date,
|
|
posterPath: tmdbImageUrl(r.poster_path, "w500"),
|
|
popularity: r.popularity,
|
|
voteAverage: r.vote_average,
|
|
})),
|
|
});
|
|
}
|