import cacheManager from '../../lib/cache'; import ExternalAPI from '../externalapi'; import { TmdbCollection, TmdbExternalIdResponse, TmdbMovieDetails, TmdbPersonCombinedCredits, TmdbPersonDetail, TmdbSearchMovieResponse, TmdbSearchMultiResponse, TmdbSearchTvResponse, TmdbSeasonWithEpisodes, TmdbTvDetails, TmdbUpcomingMoviesResponse, } from './interfaces'; interface SearchOptions { query: string; page?: number; includeAdult?: boolean; language?: string; } interface DiscoverMovieOptions { page?: number; includeAdult?: boolean; language?: string; sortBy?: | 'popularity.asc' | 'popularity.desc' | 'release_date.asc' | 'release_date.desc' | 'revenue.asc' | 'revenue.desc' | 'primary_release_date.asc' | 'primary_release_date.desc' | 'original_title.asc' | 'original_title.desc' | 'vote_average.asc' | 'vote_average.desc' | 'vote_count.asc' | 'vote_count.desc'; } interface DiscoverTvOptions { page?: number; language?: string; sortBy?: | 'popularity.asc' | 'popularity.desc' | 'vote_average.asc' | 'vote_average.desc' | 'vote_count.asc' | 'vote_count.desc' | 'first_air_date.asc' | 'first_air_date.desc'; } class TheMovieDb extends ExternalAPI { constructor() { super( 'https://api.themoviedb.org/3', { api_key: 'db55323b8d3e4154498498a75642b381', }, { nodeCache: cacheManager.getCache('tmdb').data, } ); } public searchMulti = async ({ query, page = 1, includeAdult = false, language = 'en', }: SearchOptions): Promise => { try { const data = await this.get('/search/multi', { params: { query, page, include_adult: includeAdult, language }, }); return data; } catch (e) { return { page: 1, results: [], total_pages: 1, total_results: 0, }; } }; public getPerson = async ({ personId, language = 'en', }: { personId: number; language?: string; }): Promise => { try { const data = await this.get(`/person/${personId}`, { params: { language }, }); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch person details: ${e.message}`); } }; public getPersonCombinedCredits = async ({ personId, language = 'en', }: { personId: number; language?: string; }): Promise => { try { const data = await this.get( `/person/${personId}/combined_credits`, { params: { language }, } ); return data; } catch (e) { throw new Error( `[TMDB] Failed to fetch person combined credits: ${e.message}` ); } }; public getMovie = async ({ movieId, language = 'en', }: { movieId: number; language?: string; }): Promise => { try { const data = await this.get( `/movie/${movieId}`, { params: { language, append_to_response: 'credits,external_ids,videos', }, }, 900 ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch movie details: ${e.message}`); } }; public getTvShow = async ({ tvId, language = 'en', }: { tvId: number; language?: string; }): Promise => { try { const data = await this.get( `/tv/${tvId}`, { params: { language, append_to_response: 'aggregate_credits,credits,external_ids,keywords,videos', }, }, 900 ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch tv show details: ${e.message}`); } }; public getTvSeason = async ({ tvId, seasonNumber, language, }: { tvId: number; seasonNumber: number; language?: string; }): Promise => { try { const data = await this.get( `/tv/${tvId}/season/${seasonNumber}`, { params: { language, append_to_response: 'external_ids', }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch tv show details: ${e.message}`); } }; public async getMovieRecommendations({ movieId, page = 1, language = 'en', }: { movieId: number; page?: number; language?: string; }): Promise { try { const data = await this.get( `/movie/${movieId}/recommendations`, { params: { page, language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch discover movies: ${e.message}`); } } public async getMovieSimilar({ movieId, page = 1, language = 'en', }: { movieId: number; page?: number; language?: string; }): Promise { try { const data = await this.get( `/movie/${movieId}/similar`, { params: { page, language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch discover movies: ${e.message}`); } } public async getMoviesByKeyword({ keywordId, page = 1, language = 'en', }: { keywordId: number; page?: number; language?: string; }): Promise { try { const data = await this.get( `/keyword/${keywordId}/movies`, { params: { page, language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch movies by keyword: ${e.message}`); } } public async getTvRecommendations({ tvId, page = 1, language = 'en', }: { tvId: number; page?: number; language?: string; }): Promise { try { const data = await this.get( `/tv/${tvId}/recommendations`, { params: { page, language, }, } ); return data; } catch (e) { throw new Error( `[TMDB] Failed to fetch tv recommendations: ${e.message}` ); } } public async getTvSimilar({ tvId, page = 1, language = 'en', }: { tvId: number; page?: number; language?: string; }): Promise { try { const data = await this.get(`/tv/${tvId}/similar`, { params: { page, language, }, }); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch tv similar: ${e.message}`); } } public getDiscoverMovies = async ({ sortBy = 'popularity.desc', page = 1, includeAdult = false, language = 'en', }: DiscoverMovieOptions = {}): Promise => { try { const data = await this.get('/discover/movie', { params: { sort_by: sortBy, page, include_adult: includeAdult, language, }, }); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch discover movies: ${e.message}`); } }; public getDiscoverTv = async ({ sortBy = 'popularity.desc', page = 1, language = 'en', }: DiscoverTvOptions = {}): Promise => { try { const data = await this.get('/discover/tv', { params: { sort_by: sortBy, page, language, }, }); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch discover tv: ${e.message}`); } }; public getUpcomingMovies = async ({ page = 1, language = 'en', }: { page: number; language: string; }): Promise => { try { const data = await this.get( '/movie/upcoming', { params: { page, language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch upcoming movies: ${e.message}`); } }; public getAllTrending = async ({ page = 1, timeWindow = 'day', language = 'en', }: { page?: number; timeWindow?: 'day' | 'week'; language?: string; } = {}): Promise => { try { const data = await this.get( `/trending/all/${timeWindow}`, { params: { page, language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch all trending: ${e.message}`); } }; public getMovieTrending = async ({ page = 1, timeWindow = 'day', }: { page?: number; timeWindow?: 'day' | 'week'; } = {}): Promise => { try { const data = await this.get( `/trending/movie/${timeWindow}`, { params: { page, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch all trending: ${e.message}`); } }; public getTvTrending = async ({ page = 1, timeWindow = 'day', }: { page?: number; timeWindow?: 'day' | 'week'; } = {}): Promise => { try { const data = await this.get( `/trending/tv/${timeWindow}`, { params: { page, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch all trending: ${e.message}`); } }; public async getByExternalId({ externalId, type, language = 'en', }: | { externalId: string; type: 'imdb'; language?: string; } | { externalId: number; type: 'tvdb'; language?: string; }): Promise { try { const data = await this.get( `/find/${externalId}`, { params: { external_source: type === 'imdb' ? 'imdb_id' : 'tvdb_id', language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to find by external ID: ${e.message}`); } } public async getMovieByImdbId({ imdbId, language = 'en', }: { imdbId: string; language?: string; }): Promise { try { const extResponse = await this.getByExternalId({ externalId: imdbId, type: 'imdb', }); if (extResponse.movie_results[0]) { const movie = await this.getMovie({ movieId: extResponse.movie_results[0].id, language, }); return movie; } throw new Error( '[TMDB] Failed to find a title with the provided IMDB id' ); } catch (e) { throw new Error( `[TMDB] Failed to get movie by external imdb ID: ${e.message}` ); } } public async getShowByTvdbId({ tvdbId, language = 'en', }: { tvdbId: number; language?: string; }): Promise { try { const extResponse = await this.getByExternalId({ externalId: tvdbId, type: 'tvdb', }); if (extResponse.tv_results[0]) { const tvshow = await this.getTvShow({ tvId: extResponse.tv_results[0].id, language, }); return tvshow; } throw new Error( `[TMDB] Failed to find a TV show with the provided TVDB ID: ${tvdbId}` ); } catch (e) { throw new Error( `[TMDB] Failed to get TV show using the external TVDB ID: ${e.message}` ); } } public async getCollection({ collectionId, language = 'en', }: { collectionId: number; language?: string; }): Promise { try { const data = await this.get( `/collection/${collectionId}`, { params: { language, }, } ); return data; } catch (e) { throw new Error(`[TMDB] Failed to fetch collection: ${e.message}`); } } } export default TheMovieDb;