mirror of
https://github.com/p-stream/p-stream.git
synced 2026-07-26 14:32:12 +00:00
Update personalRecommendations.ts
This commit is contained in:
parent
248da37056
commit
5b73ca114e
1 changed files with 115 additions and 10 deletions
|
|
@ -1,7 +1,9 @@
|
|||
import { getRelatedMedia } from "@/backend/metadata/tmdb";
|
||||
import { getMediaDetails, getRelatedMedia } from "@/backend/metadata/tmdb";
|
||||
import { TMDBContentTypes } from "@/backend/metadata/types/tmdb";
|
||||
import type {
|
||||
TMDBMovieData,
|
||||
TMDBMovieSearchResult,
|
||||
TMDBShowData,
|
||||
TMDBShowSearchResult,
|
||||
} from "@/backend/metadata/types/tmdb";
|
||||
import type { DiscoverMedia } from "@/pages/discover/types/discover";
|
||||
|
|
@ -73,9 +75,29 @@ function bookmarkToDiscoverMedia(b: BookmarkSource): DiscoverMedia {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches similar items from the fed-similar API
|
||||
*/
|
||||
async function fetchFedSimilarItems(
|
||||
tmdbId: string,
|
||||
isTVShow: boolean,
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
const endpoint = isTVShow
|
||||
? `https://fed-similar.up.railway.app/tv/${tmdbId}`
|
||||
: `https://fed-similar.up.railway.app/movie/${tmdbId}`;
|
||||
const response = await fetch(endpoint);
|
||||
if (!response.ok) return [];
|
||||
const items = await response.json();
|
||||
return Array.isArray(items) ? items : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches personal recommendations by:
|
||||
* 1. Getting related media for up to MAX_HISTORY_FOR_RELATED history items, MAX_CURRENT_FOR_RELATED progress items, and MAX_BOOKMARK_FOR_RELATED bookmark
|
||||
* 1. Getting related media from fed-similar API and TMDB for history, progress, and bookmark items
|
||||
* 2. Merging and deduping, excluding items already in history/progress/bookmarks
|
||||
* 3. Adding up to MAX_BOOKMARK_REMINDERS bookmarked items as "reminders"
|
||||
*/
|
||||
|
|
@ -123,21 +145,104 @@ export async function fetchPersonalRecommendations(
|
|||
}
|
||||
}
|
||||
|
||||
const relatedPromises = sourceIds.map((id) =>
|
||||
// Fetch from both fed-similar API and TMDB
|
||||
const fedSimilarPromises = sourceIds.map((id) =>
|
||||
fetchFedSimilarItems(id, isTVShow),
|
||||
);
|
||||
|
||||
const tmdbPromises = sourceIds.map((id) =>
|
||||
getRelatedMedia(id, type, RELATED_PER_ITEM_LIMIT),
|
||||
);
|
||||
|
||||
const relatedResults = await Promise.allSettled(relatedPromises);
|
||||
const [fedSimilarResults, tmdbResults] = await Promise.allSettled([
|
||||
Promise.all(fedSimilarPromises),
|
||||
Promise.all(tmdbPromises),
|
||||
]);
|
||||
|
||||
const merged: DiscoverMedia[] = [];
|
||||
const seenIds = new Set<number>([]);
|
||||
const seenFedSimilarIds = new Set<string>();
|
||||
|
||||
for (const result of relatedResults) {
|
||||
if (result.status !== "fulfilled" || !result.value) continue;
|
||||
for (const item of result.value) {
|
||||
const idStr = String(item.id);
|
||||
if (excludeIds.has(idStr) || seenIds.has(item.id)) continue;
|
||||
// Process fed-similar results first (higher priority)
|
||||
if (fedSimilarResults.status === "fulfilled") {
|
||||
for (const fedSimilarItems of fedSimilarResults.value) {
|
||||
for (const tmdbId of fedSimilarItems) {
|
||||
if (excludeIds.has(tmdbId) || seenFedSimilarIds.has(tmdbId)) {
|
||||
continue;
|
||||
}
|
||||
seenFedSimilarIds.add(tmdbId);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch full details for fed-similar items
|
||||
const fedSimilarDetailPromises = Array.from(seenFedSimilarIds)
|
||||
.slice(0, 20)
|
||||
.map((tmdbId) => getMediaDetails(tmdbId, type));
|
||||
|
||||
const fedSimilarDetails = await Promise.allSettled(
|
||||
fedSimilarDetailPromises,
|
||||
);
|
||||
|
||||
for (const result of fedSimilarDetails) {
|
||||
if (result.status !== "fulfilled" || !result.value) continue;
|
||||
const item = result.value as TMDBMovieData | TMDBShowData;
|
||||
if (seenIds.has(item.id)) continue;
|
||||
seenIds.add(item.id);
|
||||
merged.push(toDiscoverMedia(item, isTVShow));
|
||||
|
||||
let searchItem: TMDBMovieSearchResult | TMDBShowSearchResult;
|
||||
if (isTVShow) {
|
||||
const showItem = item as TMDBShowData;
|
||||
searchItem = {
|
||||
adult: showItem.adult ?? false,
|
||||
backdrop_path: showItem.backdrop_path ?? "",
|
||||
id: showItem.id,
|
||||
name: showItem.name,
|
||||
original_language: showItem.original_language ?? "",
|
||||
original_name: showItem.original_name ?? "",
|
||||
overview: showItem.overview ?? "",
|
||||
poster_path: showItem.poster_path ?? "",
|
||||
media_type: TMDBContentTypes.TV,
|
||||
genre_ids: showItem.genres?.map((g) => g.id) ?? [],
|
||||
popularity: showItem.popularity ?? 0,
|
||||
first_air_date: showItem.first_air_date ?? "",
|
||||
vote_average: showItem.vote_average,
|
||||
vote_count: showItem.vote_count,
|
||||
origin_country: showItem.origin_country ?? [],
|
||||
};
|
||||
} else {
|
||||
const movieItem = item as TMDBMovieData;
|
||||
searchItem = {
|
||||
adult: movieItem.adult ?? false,
|
||||
backdrop_path: movieItem.backdrop_path ?? "",
|
||||
id: movieItem.id,
|
||||
title: movieItem.title,
|
||||
original_language: movieItem.original_language ?? "",
|
||||
original_title: movieItem.original_title ?? "",
|
||||
overview: movieItem.overview ?? "",
|
||||
poster_path: movieItem.poster_path ?? "",
|
||||
media_type: TMDBContentTypes.MOVIE,
|
||||
genre_ids: movieItem.genres?.map((g) => g.id) ?? [],
|
||||
popularity: movieItem.popularity ?? 0,
|
||||
release_date: movieItem.release_date ?? "",
|
||||
video: movieItem.video ?? false,
|
||||
vote_average: movieItem.vote_average,
|
||||
vote_count: movieItem.vote_count,
|
||||
};
|
||||
}
|
||||
|
||||
merged.push(toDiscoverMedia(searchItem, isTVShow));
|
||||
}
|
||||
}
|
||||
|
||||
// Process TMDB results (lower priority)
|
||||
if (tmdbResults.status === "fulfilled") {
|
||||
for (const result of tmdbResults.value) {
|
||||
for (const item of result) {
|
||||
const idStr = String(item.id);
|
||||
if (excludeIds.has(idStr) || seenIds.has(item.id)) continue;
|
||||
seenIds.add(item.id);
|
||||
merged.push(toDiscoverMedia(item, isTVShow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue