scape tmdb data with languages

This commit is contained in:
Pas 2025-05-03 13:59:42 -06:00
parent 4d45dfd06e
commit 1205eebc2e
5 changed files with 83 additions and 23 deletions

View file

@ -1,7 +1,9 @@
import slugify from "slugify";
import { conf } from "@/setup/config";
import { useLanguageStore } from "@/stores/language";
import { usePreferencesStore } from "@/stores/preferences";
import { getTmdbLanguageCode } from "@/utils/language";
import { MediaItem } from "@/utils/mediaTypes";
import { getProxyUrls } from "@/utils/proxyUrls";
@ -176,12 +178,20 @@ export async function get<T>(url: string, params?: object): Promise<T> {
const proxyUrls = getProxyUrls();
const proxy = getNextProxy(proxyUrls);
const shouldProxyTmdb = usePreferencesStore.getState().proxyTmdb;
const userLanguage = useLanguageStore.getState().language;
const formattedLanguage = getTmdbLanguageCode(userLanguage);
if (!apiKey) throw new Error("TMDB API key not set");
// directly writing parameters, otherwise it will start the first parameter in the proxied request as "&" instead of "?" because it doesnt understand its proxied
const fullUrl = new URL(tmdbBaseUrl1 + url);
if (params) {
Object.entries(params).forEach(([key, value]) => {
const allParams = {
...params,
language: formattedLanguage,
};
if (allParams) {
Object.entries(allParams).forEach(([key, value]) => {
fullUrl.searchParams.append(key, String(value));
});
}
@ -205,18 +215,14 @@ export async function get<T>(url: string, params?: object): Promise<T> {
return await mwFetch<T>(encodeURI(url), {
headers: tmdbHeaders,
baseURL: tmdbBaseUrl1,
params: {
...params,
},
params: allParams,
signal: abortOnTimeout(5000),
});
} catch (err) {
return mwFetch<T>(encodeURI(url), {
headers: tmdbHeaders,
baseURL: tmdbBaseUrl2,
params: {
...params,
},
params: allParams,
signal: abortOnTimeout(30000),
});
}
@ -228,7 +234,6 @@ export async function multiSearch(
const data = await get<TMDBSearchResult>("search/multi", {
query,
include_adult: false,
language: "en-US",
page: 1,
});
// filter out results that aren't movies or shows

View file

@ -13,9 +13,11 @@ import { Dropdown } from "@/components/form/Dropdown";
import { Icon, Icons } from "@/components/Icon";
import { hasAired } from "@/components/player/utils/aired";
import { useBookmarkStore } from "@/stores/bookmarks";
import { useLanguageStore } from "@/stores/language";
import { useProgressStore } from "@/stores/progress";
import { shouldShowProgress } from "@/stores/progress/utils";
import { scrapeIMDb } from "@/utils/imdbScraper";
import { getTmdbLanguageCode } from "@/utils/language";
import { useModal } from "./Modal";
import { OverlayPortal } from "./OverlayDisplay";
@ -199,7 +201,17 @@ function DetailsContent({
setIsLoadingImdb(true);
try {
const imdbMetadata = await scrapeIMDb(data.imdbId);
// Get the user's selected language and format it properly
const userLanguage = useLanguageStore.getState().language;
const formattedLanguage = getTmdbLanguageCode(userLanguage);
// Pass the language to the scrapeIMDb function
const imdbMetadata = await scrapeIMDb(
data.imdbId,
undefined,
undefined,
formattedLanguage,
);
setImdbData(imdbMetadata);
} catch (error) {
console.error("Failed to fetch IMDb data:", error);

View file

@ -14,6 +14,8 @@ import {
} from "@/pages/discover/common";
import { conf } from "@/setup/config";
import { MediaItem } from "@/utils/mediaTypes";
import { useLanguageStore } from "@/stores/language";
import { getTmdbLanguageCode } from "@/utils/language";
import { CategoryButtons } from "./components/CategoryButtons";
import { LazyMediaCarousel } from "./components/LazyMediaCarousel";
@ -132,6 +134,9 @@ export function DiscoverContent() {
// );
const { t } = useTranslation();
const userLanguage = useLanguageStore.getState().language;
const formattedLanguage = getTmdbLanguageCode(userLanguage);
// Only load data for the active tab
const isMoviesTab = selectedCategory === "movies";
const isTVShowsTab = selectedCategory === "tvshows";
@ -145,7 +150,7 @@ export function DiscoverContent() {
try {
const data = await get<any>("/genre/tv/list", {
api_key: conf().TMDB_READ_API_KEY,
language: "en-US",
language: formattedLanguage,
});
// Fetch only the first 10 TV show genres
setTVGenres(data.genres.slice(0, 10));
@ -155,7 +160,7 @@ export function DiscoverContent() {
};
fetchTVGenres();
}, [isTVShowsTab]);
}, [isTVShowsTab, formattedLanguage]);
// Fetch Movie genres
useEffect(() => {
@ -165,7 +170,7 @@ export function DiscoverContent() {
try {
const data = await get<any>("/genre/movie/list", {
api_key: conf().TMDB_READ_API_KEY,
language: "en-US",
language: formattedLanguage,
});
// Fetch only the first 12 genres
@ -176,7 +181,7 @@ export function DiscoverContent() {
};
fetchGenres();
}, [isMoviesTab]);
}, [isMoviesTab, formattedLanguage]);
// Fetch Editor Picks Movies
useEffect(() => {
@ -187,7 +192,7 @@ export function DiscoverContent() {
const moviePromises = EDITOR_PICKS_MOVIES.map((item) =>
get<any>(`/movie/${item.id}`, {
api_key: conf().TMDB_READ_API_KEY,
language: "en-US",
language: formattedLanguage,
append_to_response: "videos,images",
}),
);
@ -202,7 +207,7 @@ export function DiscoverContent() {
};
fetchEditorPicksMovies();
}, [isEditorPicksTab]);
}, [isEditorPicksTab, formattedLanguage]);
// Fetch Editor Picks TV Shows
useEffect(() => {
@ -213,7 +218,7 @@ export function DiscoverContent() {
const tvShowPromises = EDITOR_PICKS_TV_SHOWS.map((item) =>
get<any>(`/tv/${item.id}`, {
api_key: conf().TMDB_READ_API_KEY,
language: "en-US",
language: formattedLanguage,
append_to_response: "videos,images",
}),
);
@ -228,7 +233,7 @@ export function DiscoverContent() {
};
fetchEditorPicksTVShows();
}, [isEditorPicksTab]);
}, [isEditorPicksTab, formattedLanguage]);
useEffect(() => {
let countdownInterval: NodeJS.Timeout;
@ -290,7 +295,7 @@ export function DiscoverContent() {
api_key: conf().TMDB_READ_API_KEY,
with_watch_providers: id,
watch_region: "US",
language: "en-US",
language: formattedLanguage,
});
setData(data.results);
} catch (error) {

View file

@ -1,6 +1,8 @@
import { useCallback, useEffect, useState } from "react";
import { get } from "@/backend/metadata/tmdb";
import { useLanguageStore } from "@/stores/language";
import { getTmdbLanguageCode } from "@/utils/language";
import { Category, Genre, Movie, TVShow } from "@/pages/discover/common";
import { conf } from "@/setup/config";
@ -19,6 +21,8 @@ export function useTMDBData(
[categoryName: string]: Movie[] | TVShow[];
}>({});
const [isLoading, setIsLoading] = useState(false);
const userLanguage = useLanguageStore.getState().language;
const formattedLanguage = getTmdbLanguageCode(userLanguage);
// Unified fetch function
const fetchMedia = useCallback(
@ -29,7 +33,7 @@ export function useTMDBData(
for (let page = 1; page <= 2; page += 1) {
const data = await get<any>(endpoint, {
api_key: conf().TMDB_READ_API_KEY,
language: "en-US",
language: formattedLanguage,
page: page.toString(),
...(isGenre ? { with_genres: key } : {}),
});
@ -51,7 +55,7 @@ export function useTMDBData(
return [];
}
},
[mediaType],
[mediaType, formattedLanguage],
);
// Fetch media for each genre
@ -104,6 +108,8 @@ export function useLazyTMDBData(
) {
const [media, setMedia] = useState<Movie[] | TVShow[]>([]);
const [isLoading, setIsLoading] = useState(false);
const userLanguage = useLanguageStore.getState().language;
const formattedLanguage = getTmdbLanguageCode(userLanguage);
const fetchMedia = useCallback(
async (endpoint: string, key: string, isGenre: boolean) => {
@ -113,7 +119,7 @@ export function useLazyTMDBData(
// Only fetch one page for better performance
const data = await get<any>(endpoint, {
api_key: conf().TMDB_READ_API_KEY,
language: "en-US",
language: formattedLanguage,
page: "1",
...(isGenre ? { with_genres: key } : {}),
});
@ -130,7 +136,7 @@ export function useLazyTMDBData(
return [];
}
},
[mediaType],
[mediaType, formattedLanguage],
);
useEffect(() => {

View file

@ -224,3 +224,35 @@ export function getLocaleInfo(locale: string): LocaleInfo | null {
nativeName: output.nativeName[0] ?? undefined,
};
}
/**
* Converts a language code to a TMDB-compatible format (ISO 639-1 with region)
* @param language The language code to convert
* @returns A TMDB-compatible language code (e.g., "en-US", "el-GR")
*/
export function getTmdbLanguageCode(language: string): string {
// Handle empty or undefined
if (!language) return "en-US";
// If it already has a region code (e.g., "en-US"), use it directly
if (language.includes("-")) return language;
// Handle special/custom languages by defaulting to English
if (language.length > 2 || Object.keys(extraLanguages).includes(language))
return "en-US";
// For standard language codes, find the appropriate region from the existing defaultLanguageCodes array
const defaultCode = defaultLanguageCodes.find((code) =>
code.startsWith(`${language}-`),
);
if (defaultCode) return defaultCode;
// If we can't find a good match, create a standard format like "fr-FR" from "fr"
if (language.length === 2) {
return `${language}-${language.toUpperCase()}`;
}
// Last resort fallback
return "en-US";
}