Fix color extraction and image cache setup in development

Move `ensureImageDirs` outside the production-only block so the local
image cache directories are created in dev mode too. Update
`extractAndStoreColors` to download the poster if it isn't cached yet
instead of falling back to a direct TMDB CDN URL, keeping color
extraction consistent with the server-side image routing approach. Add
`/data` to `.gitignore` to avoid committing the local cache directory.
This commit is contained in:
2026-03-02 13:49:57 -05:00
parent 8eb1007612
commit 2f0fe02d26
6 changed files with 22 additions and 18 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
# SQLite database URL (Docker: file:/data/sqlite.db, local dev: file:sqlite.db)
DATABASE_URL=file:sqlite.db
DATABASE_URL=file:./data/sqlite.db
# TMDB API Read Access Token — get one at https://www.themoviedb.org/settings/api
TMDB_API_READ_ACCESS_TOKEN=your_tmdb_api_read_access_token_here
@@ -16,5 +16,5 @@ BETTER_AUTH_URL=http://localhost:3000
# Image caching — downloads TMDB images to local disk for faster serving
# Set to "false" to disable and use TMDB CDN directly (default: enabled)
IMAGE_CACHE_DIR=./data/images
# IMAGE_CACHE_ENABLED=false
# IMAGE_CACHE_DIR=/data/images
+1
View File
@@ -19,6 +19,7 @@
# production
/build
/data
# misc
.DS_Store
+1 -1
View File
@@ -5,6 +5,6 @@ export default defineConfig({
schema: "./lib/db/schema.ts",
out: "./drizzle",
dbCredentials: {
url: process.env.DATABASE_URL ?? "file:sqlite.db",
url: process.env.DATABASE_URL ?? "file:./data/sqlite.db",
},
});
+8 -8
View File
@@ -4,19 +4,19 @@ export async function onRequestError() {
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
// Ensure image cache directories exist (all environments)
const { ensureImageDirs, imageCacheEnabled } = await import(
"@/lib/services/image-cache"
);
if (imageCacheEnabled()) {
ensureImageDirs();
}
// Run database migrations on startup
if (process.env.NODE_ENV === "production") {
const { runMigrations } = await import("@/lib/db/migrate");
await runMigrations();
// Ensure image cache directories exist
const { ensureImageDirs, imageCacheEnabled } = await import(
"@/lib/services/image-cache"
);
if (imageCacheEnabled()) {
ensureImageDirs();
}
const { initJobs } = await import("@/lib/jobs/init");
initJobs();
+1 -1
View File
@@ -9,7 +9,7 @@ const globalForDb = globalThis as unknown as {
if (!globalForDb._client) {
globalForDb._client = createClient({
url: process.env.DATABASE_URL ?? "file:sqlite.db",
url: process.env.DATABASE_URL ?? "file:./data/sqlite.db",
});
globalForDb._client.execute("PRAGMA journal_mode = WAL");
globalForDb._client.execute("PRAGMA foreign_keys = ON");
+9 -6
View File
@@ -4,11 +4,11 @@ import { Vibrant } from "node-vibrant/node";
import { db } from "@/lib/db/client";
import { titles } from "@/lib/db/schema";
import {
downloadAndCacheImage,
getLocalImagePath,
imageCacheEnabled,
isImageCached,
} from "@/lib/services/image-cache";
import { tmdbImageUrl } from "@/lib/tmdb/image";
export interface ColorPalette {
vibrant: string | null;
@@ -25,15 +25,18 @@ export async function extractAndStoreColors(
): Promise<ColorPalette | null> {
if (!posterPath) return null;
// Prefer local file when image cache is active
// Use local cached image, downloading first if needed
let source: string;
const filename = path.basename(posterPath);
if (imageCacheEnabled() && isImageCached("posters", filename)) {
if (imageCacheEnabled()) {
if (!isImageCached("posters", filename)) {
await downloadAndCacheImage(posterPath, "posters");
}
source = getLocalImagePath("posters", filename);
} else {
const url = tmdbImageUrl(posterPath, "w300");
if (!url) return null;
source = url;
const baseUrl =
process.env.TMDB_IMAGE_BASE_URL || "https://image.tmdb.org/t/p";
source = `${baseUrl}/w300${posterPath}`;
}
try {