Add clickable watch links to streaming provider badges

Build a provider registry mapping TMDB provider IDs to search URL
templates. `generateProviderUrl()` resolves a URL for a given provider
and title name using URL-encoded search queries. `readAvailability()`
now accepts the title name and attaches `watchUrl` to each offer.

Provider badges with a resolved URL render as `<a>` links opening in a
new tab; tooltip copy switches from the provider name to "Watch on
{name}". Badges without a known URL remain non-interactive as before.
This commit is contained in:
2026-03-05 20:35:59 -05:00
parent 926ddfef34
commit cd4b2908d8
4 changed files with 145 additions and 5 deletions
+9 -3
View File
@@ -10,6 +10,7 @@ import {
titles,
} from "@/lib/db/schema";
import { createLogger } from "@/lib/logger";
import { generateProviderUrl } from "@/lib/providers";
import {
getMovieDetails,
getRecommendations,
@@ -715,7 +716,10 @@ async function ensureEnriched(
return false;
}
function readAvailability(titleId: string): AvailabilityOffer[] {
function readAvailability(
titleId: string,
titleName: string,
): AvailabilityOffer[] {
return db
.select()
.from(availabilityOffers)
@@ -726,6 +730,7 @@ function readAvailability(titleId: string): AvailabilityOffer[] {
providerName: a.providerName,
logoPath: tmdbImageUrl(a.logoPath, "w92"),
offerType: a.offerType,
watchUrl: generateProviderUrl(a.providerId, titleName),
}));
}
@@ -777,7 +782,7 @@ export async function getTitleWithChildren(id: string): Promise<{
const titleSeasons = needsTvHydration ? [] : (existingSeasons ?? []);
// Read enrichment data, then backfill anything missing
let availability = readAvailability(title.id);
let availability = readAvailability(title.id, title.title);
let cast = getCastForTitle(id);
if (title.lastFetchedAt) {
@@ -788,7 +793,8 @@ export async function getTitleWithChildren(id: string): Promise<{
if (enriched) {
// Re-read only what was missing
if (cast.length === 0) cast = getCastForTitle(id);
if (availability.length === 0) availability = readAvailability(title.id);
if (availability.length === 0)
availability = readAvailability(title.id, title.title);
title = db.select().from(titles).where(eq(titles.id, id)).get() ?? title;
}
}