1329 lines
32 KiB
Markdown
1329 lines
32 KiB
Markdown
# TMDB-TS - Comprehensive Documentation
|
|
|
|
## Table of Contents
|
|
|
|
1. [Overview](#overview)
|
|
2. [Architecture](#architecture)
|
|
3. [Installation](#installation)
|
|
4. [Quick Start](#quick-start)
|
|
5. [Core Components](#core-components)
|
|
6. [API Endpoints](#api-endpoints)
|
|
7. [Type System](#type-system)
|
|
8. [Advanced Usage](#advanced-usage)
|
|
9. [Error Handling](#error-handling)
|
|
10. [Best Practices](#best-practices)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
**tmdb-ts** is a TypeScript library that provides a fully-typed wrapper around The Movie Database (TMDB) API v3. It simplifies interaction with the TMDB API by offering:
|
|
|
|
- **Type Safety**: Complete TypeScript type definitions for all API responses
|
|
- **Modern Authentication**: Uses JWT Bearer token authentication (no need for API keys in URLs)
|
|
- **Modular Design**: Organized endpoints for different resource types
|
|
- **Promise-based**: Modern async/await support
|
|
- **Zero Configuration**: Simple instantiation with access token
|
|
|
|
### Key Features
|
|
|
|
- ✅ Full TypeScript support with comprehensive type definitions
|
|
- ✅ All TMDB API v3 endpoints covered
|
|
- ✅ Automatic query parameter parsing
|
|
- ✅ Error handling with typed error responses
|
|
- ✅ Support for append_to_response functionality
|
|
- ✅ Cross-platform fetch implementation via cross-fetch
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
tmdb-ts/
|
|
├── src/
|
|
│ ├── api.ts # Core HTTP client
|
|
│ ├── tmdb.ts # Main TMDB class
|
|
│ ├── index.ts # Public exports
|
|
│ ├── common/
|
|
│ │ └── constants.ts # API base URLs and constants
|
|
│ ├── endpoints/ # Endpoint implementations
|
|
│ │ ├── base.ts # Base endpoint class
|
|
│ │ ├── movies.ts # Movie-related endpoints
|
|
│ │ ├── tv-shows.ts # TV show endpoints
|
|
│ │ ├── people.ts # People/cast endpoints
|
|
│ │ ├── search.ts # Search endpoints
|
|
│ │ ├── credits.ts # Credits endpoints
|
|
│ │ ├── genres.ts # Genre endpoints
|
|
│ │ ├── discover.ts # Discover endpoints
|
|
│ │ ├── trending.ts # Trending endpoints
|
|
│ │ ├── collections.ts # Collection endpoints
|
|
│ │ ├── companies.ts # Company endpoints
|
|
│ │ ├── networks.ts # Network endpoints
|
|
│ │ ├── keywords.ts # Keyword endpoints
|
|
│ │ ├── configuration.ts # Configuration endpoints
|
|
│ │ ├── certifications.ts# Certification endpoints
|
|
│ │ ├── changes.ts # Change tracking endpoints
|
|
│ │ ├── account.ts # Account endpoints
|
|
│ │ ├── review.ts # Review endpoints
|
|
│ │ ├── watch-providers.ts# Watch provider endpoints
|
|
│ │ ├── tv-seasons.ts # TV season endpoints
|
|
│ │ ├── tv-episode.ts # TV episode endpoints
|
|
│ │ └── find.ts # External ID lookup
|
|
│ ├── types/ # TypeScript type definitions
|
|
│ │ ├── index.ts # Main type exports
|
|
│ │ ├── options.ts # Query option types
|
|
│ │ ├── movies.ts # Movie-related types
|
|
│ │ ├── tv-shows.ts # TV show types
|
|
│ │ ├── people.ts # People/person types
|
|
│ │ ├── credits.ts # Credits types
|
|
│ │ ├── search.ts # Search result types
|
|
│ │ └── [other types] # Additional type definitions
|
|
│ └── utils/ # Utility functions
|
|
│ ├── parseOptions.ts # Query parameter parser
|
|
│ ├── getImagePath.ts # Image URL helper
|
|
│ └── index.ts # Utility exports
|
|
├── package.json
|
|
├── tsconfig.json
|
|
└── README.md
|
|
```
|
|
|
|
### Design Patterns
|
|
|
|
#### 1. **Lazy Instantiation Pattern**
|
|
```typescript
|
|
class TMDB {
|
|
get movies(): MoviesEndpoint {
|
|
return new MoviesEndpoint(this.accessToken);
|
|
}
|
|
}
|
|
```
|
|
Endpoints are instantiated on-demand via getter properties, keeping memory footprint low.
|
|
|
|
#### 2. **Base Endpoint Pattern**
|
|
```typescript
|
|
abstract class BaseEndpoint {
|
|
protected api: Api;
|
|
constructor(protected readonly accessToken: string) {
|
|
this.api = new Api(accessToken);
|
|
}
|
|
}
|
|
```
|
|
All endpoints extend a base class that provides HTTP client access.
|
|
|
|
#### 3. **Type-safe Append Pattern**
|
|
```typescript
|
|
type AppendToResponse<K, T extends AppendToResponseMovieKey[] | undefined>
|
|
```
|
|
Compile-time type safety for dynamic API response composition.
|
|
|
|
---
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
# Using npm
|
|
npm install tmdb-ts
|
|
|
|
# Using yarn
|
|
yarn add tmdb-ts
|
|
|
|
# Using pnpm
|
|
pnpm add tmdb-ts
|
|
|
|
# Using bun
|
|
bun add tmdb-ts
|
|
```
|
|
|
|
### Requirements
|
|
|
|
- Node.js >= 14.x
|
|
- TypeScript >= 4.5 (for type definitions)
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### 1. Get TMDB Access Token
|
|
|
|
1. Create an account at [themoviedb.org](https://www.themoviedb.org/)
|
|
2. Go to Settings → API
|
|
3. Generate an API Read Access Token (JWT)
|
|
|
|
### 2. Basic Usage
|
|
|
|
```typescript
|
|
import { TMDB } from 'tmdb-ts';
|
|
|
|
// Initialize the client
|
|
const tmdb = new TMDB('your_access_token_here');
|
|
|
|
// Search for movies
|
|
async function searchMovies() {
|
|
try {
|
|
const results = await tmdb.search.movies({
|
|
query: 'Inception'
|
|
});
|
|
console.log(results.results);
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
}
|
|
}
|
|
|
|
// Get movie details
|
|
async function getMovieDetails() {
|
|
const movie = await tmdb.movies.details(550); // Fight Club
|
|
console.log(movie.title, movie.overview);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Core Components
|
|
|
|
### 1. TMDB Class
|
|
|
|
The main entry point for all API interactions.
|
|
|
|
```typescript
|
|
class TMDB {
|
|
constructor(accessToken: string);
|
|
|
|
// Endpoint accessors (getters)
|
|
get movies(): MoviesEndpoint;
|
|
get tvShows(): TvShowsEndpoint;
|
|
get people(): PeopleEndpoint;
|
|
get search(): SearchEndpoint;
|
|
get credits(): CreditsEndpoint;
|
|
get discover(): DiscoverEndpoint;
|
|
get genres(): GenreEndpoint;
|
|
get trending(): TrendingEndpoint;
|
|
get collections(): CollectionsEndpoint;
|
|
get companies(): CompaniesEndpoint;
|
|
get networks(): NetworksEndpoint;
|
|
get keywords(): KeywordsEndpoint;
|
|
get configuration(): ConfigurationEndpoint;
|
|
get certifications(): CertificationEndpoint;
|
|
get changes(): ChangeEndpoint;
|
|
get account(): AccountEndpoint;
|
|
get review(): ReviewEndpoint;
|
|
get watchProviders(): WatchProvidersEndpoint;
|
|
get tvSeasons(): TvSeasonsEndpoint;
|
|
get tvEpisode(): TvEpisodesEndpoint;
|
|
get find(): FindEndpoint;
|
|
}
|
|
```
|
|
|
|
### 2. Api Class
|
|
|
|
Internal HTTP client handling all requests.
|
|
|
|
```typescript
|
|
class Api {
|
|
constructor(accessToken: string);
|
|
|
|
async get<T>(path: string, options?: Record<string, any>): Promise<T>;
|
|
}
|
|
```
|
|
|
|
**Features:**
|
|
- Automatically adds Bearer token authentication
|
|
- Converts options object to URL query parameters
|
|
- Returns typed responses
|
|
- Throws typed errors on failure
|
|
|
|
### 3. BaseEndpoint Class
|
|
|
|
Abstract base class for all endpoint implementations.
|
|
|
|
```typescript
|
|
abstract class BaseEndpoint {
|
|
protected api: Api;
|
|
constructor(protected readonly accessToken: string);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Movies Endpoint
|
|
|
|
Comprehensive movie-related operations.
|
|
|
|
#### Methods
|
|
|
|
```typescript
|
|
class MoviesEndpoint {
|
|
// Get detailed information about a movie
|
|
async details<T extends AppendToResponseMovieKey[]>(
|
|
id: number,
|
|
appendToResponse?: T,
|
|
language?: string
|
|
): Promise<AppendToResponse<MovieDetails, T, 'movie'>>;
|
|
|
|
// Get alternative titles for a movie
|
|
async alternativeTitles(id: number): Promise<AlternativeTitles>;
|
|
|
|
// Get the recent changes for a movie
|
|
async changes(id: number, options?: ChangeOption): Promise<Changes<MovieChangeValue>>;
|
|
|
|
// Get the cast and crew for a movie
|
|
async credits(id: number, options?: LanguageOption): Promise<Credits>;
|
|
|
|
// Get external IDs for a movie
|
|
async externalIds(id: number): Promise<ExternalIds>;
|
|
|
|
// Get images for a movie
|
|
async images(id: number, options?: MoviesImageSearchOptions): Promise<Images>;
|
|
|
|
// Get keywords for a movie
|
|
async keywords(id: number): Promise<Keywords>;
|
|
|
|
// Get lists that this movie belongs to
|
|
async lists(id: number, options?: LanguageOption & PageOption): Promise<MovieLists>;
|
|
|
|
// Get movie recommendations
|
|
async recommendations(id: number, options?: LanguageOption & PageOption): Promise<Recommendations>;
|
|
|
|
// Get release dates for a movie
|
|
async releaseDates(id: number): Promise<ReleaseDates>;
|
|
|
|
// Get user reviews for a movie
|
|
async reviews(id: number, options?: LanguageOption & PageOption): Promise<Reviews>;
|
|
|
|
// Get similar movies
|
|
async similar(id: number, options?: LanguageOption & PageOption): Promise<SimilarMovies>;
|
|
|
|
// Get translations for a movie
|
|
async translations(id: number): Promise<Translations>;
|
|
|
|
// Get videos (trailers, teasers) for a movie
|
|
async videos(id: number, options?: LanguageOption): Promise<Videos>;
|
|
|
|
// Get watch providers for a movie
|
|
async watchProviders(id: number): Promise<WatchProviders>;
|
|
|
|
// Get the latest movie
|
|
async latest(): Promise<LatestMovie>;
|
|
|
|
// Get movies now playing in theaters
|
|
async nowPlaying(options?: PageOption & LanguageOption & RegionOption): Promise<MoviesPlayingNow>;
|
|
|
|
// Get popular movies
|
|
async popular(options?: LanguageOption & PageOption): Promise<PopularMovies>;
|
|
|
|
// Get top rated movies
|
|
async topRated(options?: PageOption & LanguageOption & RegionOption): Promise<TopRatedMovies>;
|
|
|
|
// Get upcoming movies
|
|
async upcoming(options?: PageOption & LanguageOption & RegionOption): Promise<UpcomingMovies>;
|
|
}
|
|
```
|
|
|
|
#### Examples
|
|
|
|
```typescript
|
|
// Basic movie details
|
|
const movie = await tmdb.movies.details(550);
|
|
console.log(movie.title, movie.release_date);
|
|
|
|
// Movie details with additional data (append_to_response)
|
|
const movieWithExtras = await tmdb.movies.details(
|
|
550,
|
|
['credits', 'videos', 'images'],
|
|
'en-US'
|
|
);
|
|
console.log(movieWithExtras.credits.cast);
|
|
console.log(movieWithExtras.videos.results);
|
|
|
|
// Get movie credits
|
|
const credits = await tmdb.movies.credits(550);
|
|
console.log('Director:', credits.crew.find(c => c.job === 'Director')?.name);
|
|
|
|
// Search for similar movies
|
|
const similar = await tmdb.movies.similar(550, { page: 1 });
|
|
console.log('Similar movies:', similar.results.map(m => m.title));
|
|
|
|
// Get popular movies
|
|
const popular = await tmdb.movies.popular({ language: 'en-US', page: 1 });
|
|
```
|
|
|
|
### TV Shows Endpoint
|
|
|
|
TV series and episode management.
|
|
|
|
```typescript
|
|
class TvShowsEndpoint {
|
|
// Get TV show details
|
|
async details<T extends AppendToResponseTvKey[]>(
|
|
id: number,
|
|
appendToResponse?: T,
|
|
language?: string
|
|
): Promise<AppendToResponse<TvShowDetails, T, 'tvShow'>>;
|
|
|
|
// Get aggregate credits (all seasons)
|
|
async aggregateCredits(id: number, options?: LanguageOption): Promise<AggregateCredits>;
|
|
|
|
// Get alternative titles
|
|
async alternativeTitles(id: number): Promise<AlternativeTitles>;
|
|
|
|
// Get changes for a TV show
|
|
async changes(id: number, options?: ChangeOption): Promise<Changes<TvShowChangeValue>>;
|
|
|
|
// Get content ratings
|
|
async contentRatings(id: number): Promise<ContentRatings>;
|
|
|
|
// Get credits for a TV show
|
|
async credits(id: number, options?: LanguageOption): Promise<Credits>;
|
|
|
|
// Get episode groups
|
|
async episodeGroups(id: number): Promise<EpisodeGroups>;
|
|
|
|
// Get external IDs
|
|
async externalIds(id: number): Promise<ExternalIds>;
|
|
|
|
// Get images
|
|
async images(id: number, options?: LanguageOption): Promise<Images>;
|
|
|
|
// Get keywords
|
|
async keywords(id: number): Promise<Keywords>;
|
|
|
|
// Get recommendations
|
|
async recommendations(id: number, options?: LanguageOption & PageOption): Promise<Recommendations>;
|
|
|
|
// Get reviews
|
|
async reviews(id: number, options?: LanguageOption & PageOption): Promise<Reviews>;
|
|
|
|
// Get screened theatrically episodes
|
|
async screenedTheatrically(id: number): Promise<ScreenedTheatrically>;
|
|
|
|
// Get similar TV shows
|
|
async similar(id: number, options?: LanguageOption & PageOption): Promise<SimilarTvShows>;
|
|
|
|
// Get translations
|
|
async translations(id: number): Promise<Translations>;
|
|
|
|
// Get videos
|
|
async videos(id: number, options?: LanguageOption): Promise<Videos>;
|
|
|
|
// Get watch providers
|
|
async watchProviders(id: number): Promise<WatchProviders>;
|
|
|
|
// Get latest TV show
|
|
async latest(): Promise<TvShowDetails>;
|
|
|
|
// Get TV shows airing today
|
|
async airingToday(options?: PageOption & LanguageOption & TimezoneOption): Promise<TvShowsAiringToday>;
|
|
|
|
// Get TV shows on the air
|
|
async onTheAir(options?: PageOption & LanguageOption & TimezoneOption): Promise<TvShowsOnTheAir>;
|
|
|
|
// Get popular TV shows
|
|
async popular(options?: LanguageOption & PageOption): Promise<PopularTvShows>;
|
|
|
|
// Get top rated TV shows
|
|
async topRated(options?: LanguageOption & PageOption): Promise<TopRatedTvShows>;
|
|
}
|
|
```
|
|
|
|
### People Endpoint
|
|
|
|
Person/celebrity information and credits.
|
|
|
|
```typescript
|
|
class PeopleEndpoint {
|
|
// Get person details
|
|
async details<T extends AppendToResponsePersonKey[]>(
|
|
id: number,
|
|
appendToResponse?: T,
|
|
language?: string
|
|
): Promise<AppendToResponse<PersonDetails, T, 'person'>>;
|
|
|
|
// Get changes for a person
|
|
async changes(id: number, options?: ChangeOption): Promise<Changes<PersonChangeValue>>;
|
|
|
|
// Get movie credits for a person
|
|
async movieCredits(id: number, options?: LanguageOption): Promise<PersonMovieCredit>;
|
|
|
|
// Get TV show credits for a person
|
|
async tvShowCredits(id: number, options?: LanguageOption): Promise<PersonTvShowCredit>;
|
|
|
|
// Get combined movie and TV credits
|
|
async combinedCredits(id: number, options?: LanguageOption): Promise<PersonCombinedCredits>;
|
|
|
|
// Get external IDs for a person
|
|
async externalId(id: number): Promise<ExternalIds>;
|
|
|
|
// Get images for a person
|
|
async images(id: number): Promise<PeopleImages>;
|
|
|
|
// Get tagged images (deprecated)
|
|
async taggedImages(id: number, options?: PageOption): Promise<TaggedImages>;
|
|
|
|
// Get translations
|
|
async translation(id: number): Promise<PersonTranslations>;
|
|
|
|
// Get the latest person
|
|
async latest(): Promise<PersonDetails>;
|
|
|
|
// Get popular people
|
|
async popular(options?: LanguageOption & PageOption): Promise<PopularPeople>;
|
|
}
|
|
```
|
|
|
|
#### Examples
|
|
|
|
```typescript
|
|
// Get person details
|
|
const person = await tmdb.people.details(287); // Brad Pitt
|
|
console.log(person.name, person.biography);
|
|
|
|
// Get person with movie credits
|
|
const personWithCredits = await tmdb.people.details(
|
|
287,
|
|
['movie_credits', 'tv_credits']
|
|
);
|
|
console.log('Movies:', personWithCredits.movie_credits.cast);
|
|
|
|
// Get combined credits
|
|
const credits = await tmdb.people.combinedCredits(287);
|
|
console.log('All credits:', [...credits.cast, ...credits.crew]);
|
|
|
|
// Get popular people
|
|
const popularPeople = await tmdb.people.popular({ page: 1 });
|
|
```
|
|
|
|
### Search Endpoint
|
|
|
|
Search across all content types.
|
|
|
|
```typescript
|
|
class SearchEndpoint {
|
|
// Search for companies
|
|
async companies(options: { query: string } & PageOption): Promise<CompanySearchResponse>;
|
|
|
|
// Search for collections
|
|
async collections(options: { query: string } & PageOption & LanguageOption): Promise<CollectionSearchResponse>;
|
|
|
|
// Search for keywords
|
|
async keywords(options: { query: string } & PageOption): Promise<KeywordSearchResponse>;
|
|
|
|
// Search for movies
|
|
async movies(options: MovieSearchOptions): Promise<MovieSearchResponse>;
|
|
|
|
// Multi search (movies, TV shows, people)
|
|
async multi(options: { query: string } & PageOption & LanguageOption): Promise<MultiSearchResponse>;
|
|
|
|
// Search for people
|
|
async people(options: { query: string } & PageOption & LanguageOption): Promise<PeopleSearchResponse>;
|
|
|
|
// Search for TV shows
|
|
async tvShows(options: TvShowSearchOptions): Promise<TvShowSearchResponse>;
|
|
}
|
|
```
|
|
|
|
#### Examples
|
|
|
|
```typescript
|
|
// Search movies
|
|
const movies = await tmdb.search.movies({
|
|
query: 'Matrix',
|
|
year: 1999,
|
|
page: 1
|
|
});
|
|
|
|
// Multi-search (searches movies, TV, people)
|
|
const results = await tmdb.search.multi({
|
|
query: 'Tom Hanks'
|
|
});
|
|
|
|
// Search TV shows
|
|
const tvShows = await tmdb.search.tvShows({
|
|
query: 'Breaking Bad',
|
|
first_air_date_year: 2008
|
|
});
|
|
|
|
// Search people
|
|
const people = await tmdb.search.people({
|
|
query: 'Leonardo DiCaprio'
|
|
});
|
|
```
|
|
|
|
### Credits Endpoint
|
|
|
|
Individual credit information.
|
|
|
|
```typescript
|
|
class CreditsEndpoint {
|
|
// Get detailed information about a credit
|
|
async getById(id: string): Promise<CreditResponse>;
|
|
}
|
|
```
|
|
|
|
### Discover Endpoint
|
|
|
|
Discover movies and TV shows with filtering.
|
|
|
|
```typescript
|
|
class DiscoverEndpoint {
|
|
// Discover movies
|
|
async movies(options?: DiscoverMoviesOptions): Promise<DiscoverMoviesResponse>;
|
|
|
|
// Discover TV shows
|
|
async tvShows(options?: DiscoverTvShowsOptions): Promise<DiscoverTvShowsResponse>;
|
|
}
|
|
```
|
|
|
|
#### Examples
|
|
|
|
```typescript
|
|
// Discover movies with filters
|
|
const action = await tmdb.discover.movies({
|
|
with_genres: '28', // Action genre
|
|
'vote_average.gte': 7,
|
|
sort_by: 'popularity.desc',
|
|
page: 1
|
|
});
|
|
|
|
// Discover TV shows
|
|
const comedy = await tmdb.discover.tvShows({
|
|
with_genres: '35', // Comedy genre
|
|
'first_air_date.gte': '2020-01-01',
|
|
sort_by: 'vote_average.desc'
|
|
});
|
|
```
|
|
|
|
### Trending Endpoint
|
|
|
|
Get trending content.
|
|
|
|
```typescript
|
|
class TrendingEndpoint {
|
|
// Get trending content
|
|
async trending(
|
|
mediaType: 'all' | 'movie' | 'tv' | 'person',
|
|
timeWindow: 'day' | 'week',
|
|
options?: PageOption & LanguageOption
|
|
): Promise<TrendingResponse>;
|
|
}
|
|
```
|
|
|
|
### Configuration Endpoint
|
|
|
|
Get TMDB system configuration.
|
|
|
|
```typescript
|
|
class ConfigurationEndpoint {
|
|
// Get API configuration (image base URLs, etc.)
|
|
async getApiConfiguration(): Promise<Configuration>;
|
|
|
|
// Get list of countries
|
|
async getCountries(): Promise<Country[]>;
|
|
|
|
// Get list of jobs
|
|
async getJobs(): Promise<Job[]>;
|
|
|
|
// Get list of languages
|
|
async getLanguages(): Promise<Language[]>;
|
|
|
|
// Get list of primary translations
|
|
async getPrimaryTranslations(): Promise<string[]>;
|
|
|
|
// Get list of timezones
|
|
async getTimezones(): Promise<Timezone[]>;
|
|
}
|
|
```
|
|
|
|
### Other Endpoints
|
|
|
|
- **Collections**: Movie collection information
|
|
- **Companies**: Production company details
|
|
- **Networks**: TV network information
|
|
- **Keywords**: Keyword details
|
|
- **Genres**: Genre lists for movies and TV
|
|
- **Certifications**: Content rating certifications
|
|
- **Changes**: Track content changes
|
|
- **Account**: User account operations
|
|
- **Review**: Review details
|
|
- **Watch Providers**: Streaming availability
|
|
- **TV Seasons**: Season-specific information
|
|
- **TV Episodes**: Episode-specific information
|
|
- **Find**: Lookup by external IDs (IMDb, TVDb, etc.)
|
|
|
|
---
|
|
|
|
## Type System
|
|
|
|
### Core Types
|
|
|
|
#### Movie Types
|
|
|
|
```typescript
|
|
interface Movie {
|
|
id: number;
|
|
title: string;
|
|
original_title: string;
|
|
overview: string;
|
|
release_date: string;
|
|
poster_path: string;
|
|
backdrop_path: string;
|
|
genre_ids: number[];
|
|
adult: boolean;
|
|
original_language: string;
|
|
popularity: number;
|
|
vote_count: number;
|
|
vote_average: number;
|
|
video: boolean;
|
|
}
|
|
|
|
interface MovieDetails extends Omit<Movie, 'genre_ids'> {
|
|
belongs_to_collection?: BelongsToCollection;
|
|
budget: number;
|
|
genres: Genre[];
|
|
homepage: string;
|
|
imdb_id: string | null;
|
|
production_companies: ProductionCompany[];
|
|
production_countries: ProductionCountry[];
|
|
revenue: number;
|
|
runtime: number;
|
|
spoken_languages: SpokenLanguage[];
|
|
status: string;
|
|
tagline: string;
|
|
}
|
|
```
|
|
|
|
#### TV Show Types
|
|
|
|
```typescript
|
|
interface TV {
|
|
id: number;
|
|
name: string;
|
|
original_name: string;
|
|
overview: string;
|
|
first_air_date: string;
|
|
poster_path: string;
|
|
backdrop_path: string;
|
|
genre_ids: number[];
|
|
origin_country: string[];
|
|
adult: boolean;
|
|
original_language: string;
|
|
popularity: number;
|
|
vote_count: number;
|
|
vote_average: number;
|
|
}
|
|
|
|
interface TvShowDetails extends Omit<TV, 'genre_ids'> {
|
|
created_by: Creator[];
|
|
episode_run_time: number[];
|
|
genres: Genre[];
|
|
homepage: string;
|
|
in_production: boolean;
|
|
languages: string[];
|
|
last_air_date: string;
|
|
last_episode_to_air: Episode;
|
|
next_episode_to_air: Episode;
|
|
networks: Network[];
|
|
number_of_episodes: number;
|
|
number_of_seasons: number;
|
|
production_companies: ProductionCompany[];
|
|
production_countries: ProductionCountry[];
|
|
seasons: Season[];
|
|
spoken_languages: SpokenLanguage[];
|
|
status: string;
|
|
tagline: string;
|
|
type: string;
|
|
}
|
|
```
|
|
|
|
#### Person Types
|
|
|
|
```typescript
|
|
interface Person {
|
|
id: number;
|
|
name: string;
|
|
original_name: string;
|
|
profile_path: string;
|
|
adult: boolean;
|
|
known_for_department: string;
|
|
gender: number;
|
|
popularity: number;
|
|
known_for: KnownFor[];
|
|
}
|
|
|
|
interface PersonDetails {
|
|
id: number;
|
|
name: string;
|
|
biography: string;
|
|
birthday: string;
|
|
deathday: string;
|
|
place_of_birth: string;
|
|
profile_path: string;
|
|
adult: boolean;
|
|
known_for_department: string;
|
|
gender: number;
|
|
popularity: number;
|
|
also_known_as: string[];
|
|
imdb_id: string;
|
|
homepage: string;
|
|
}
|
|
```
|
|
|
|
#### Credits Types
|
|
|
|
```typescript
|
|
interface Cast {
|
|
adult: boolean;
|
|
gender: number;
|
|
id: number;
|
|
known_for_department: string;
|
|
name: string;
|
|
original_name: string;
|
|
popularity: number;
|
|
profile_path: string;
|
|
cast_id: number;
|
|
character: string;
|
|
credit_id: string;
|
|
order: number;
|
|
}
|
|
|
|
interface Crew {
|
|
adult: boolean;
|
|
gender: number;
|
|
id: number;
|
|
known_for_department: string;
|
|
name: string;
|
|
original_name: string;
|
|
popularity: number;
|
|
profile_path: string;
|
|
credit_id: string;
|
|
department: string;
|
|
job: string;
|
|
}
|
|
|
|
interface Credits {
|
|
id: number;
|
|
cast: Cast[];
|
|
crew: Crew[];
|
|
}
|
|
```
|
|
|
|
### Option Types
|
|
|
|
```typescript
|
|
// Language options
|
|
interface LanguageOption {
|
|
language?: AvailableLanguage; // e.g., 'en-US', 'fr-FR'
|
|
}
|
|
|
|
// Pagination
|
|
interface PageOption {
|
|
page?: number;
|
|
}
|
|
|
|
// Region filtering
|
|
interface RegionOption {
|
|
region?: string; // ISO 3166-1 code
|
|
}
|
|
|
|
// Date range for changes
|
|
interface ChangeOption extends PageOption {
|
|
start_date?: string; // YYYY-MM-DD
|
|
end_date?: string; // YYYY-MM-DD
|
|
}
|
|
|
|
// Timezone
|
|
interface TimezoneOption {
|
|
timezone?: string; // e.g., 'America/New_York'
|
|
}
|
|
```
|
|
|
|
### Append to Response
|
|
|
|
The `AppendToResponse` type enables type-safe dynamic response composition:
|
|
|
|
```typescript
|
|
type AppendToResponseMovieKey =
|
|
| 'images'
|
|
| 'videos'
|
|
| 'credits'
|
|
| 'recommendations'
|
|
| 'reviews'
|
|
| 'similar'
|
|
| 'lists'
|
|
| 'release_dates'
|
|
| 'alternative_titles'
|
|
| 'external_ids'
|
|
| 'translations'
|
|
| 'watch/providers'
|
|
| 'keywords';
|
|
|
|
// Usage
|
|
const movie = await tmdb.movies.details(550, ['credits', 'videos']);
|
|
// TypeScript knows movie.credits and movie.videos exist!
|
|
```
|
|
|
|
### Error Response
|
|
|
|
```typescript
|
|
interface ErrorResponse {
|
|
status_code: number;
|
|
status_message: string;
|
|
success: boolean;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Advanced Usage
|
|
|
|
### Append to Response
|
|
|
|
Reduce API calls by requesting multiple resources in one request:
|
|
|
|
```typescript
|
|
// Single request for movie with credits, videos, and images
|
|
const movie = await tmdb.movies.details(
|
|
550,
|
|
['credits', 'videos', 'images', 'recommendations']
|
|
);
|
|
|
|
// All data is available in the response
|
|
console.log(movie.title);
|
|
console.log(movie.credits.cast);
|
|
console.log(movie.videos.results);
|
|
console.log(movie.images.posters);
|
|
console.log(movie.recommendations.results);
|
|
```
|
|
|
|
### Pagination
|
|
|
|
```typescript
|
|
// Get multiple pages of results
|
|
async function getAllPopularMovies() {
|
|
const allMovies = [];
|
|
let page = 1;
|
|
let totalPages = 1;
|
|
|
|
do {
|
|
const response = await tmdb.movies.popular({ page });
|
|
allMovies.push(...response.results);
|
|
totalPages = response.total_pages;
|
|
page++;
|
|
} while (page <= totalPages && page <= 10); // Limit to 10 pages
|
|
|
|
return allMovies;
|
|
}
|
|
```
|
|
|
|
### Language Support
|
|
|
|
```typescript
|
|
// Get movie details in different languages
|
|
const movieEN = await tmdb.movies.details(550, undefined, 'en-US');
|
|
const movieFR = await tmdb.movies.details(550, undefined, 'fr-FR');
|
|
const movieES = await tmdb.movies.details(550, undefined, 'es-ES');
|
|
|
|
console.log(movieEN.title); // "Fight Club"
|
|
console.log(movieFR.title); // "Fight Club" (French title)
|
|
console.log(movieES.title); // "El club de la lucha"
|
|
```
|
|
|
|
### Image URLs
|
|
|
|
```typescript
|
|
import { getImagePath } from 'tmdb-ts';
|
|
|
|
// Get configuration first
|
|
const config = await tmdb.configuration.getApiConfiguration();
|
|
const baseUrl = config.images.secure_base_url;
|
|
|
|
// Helper function to build image URLs
|
|
function getFullImagePath(path: string, size: string = 'original'): string {
|
|
return `${baseUrl}${size}${path}`;
|
|
}
|
|
|
|
// Usage
|
|
const movie = await tmdb.movies.details(550);
|
|
const posterUrl = getFullImagePath(movie.poster_path, 'w500');
|
|
const backdropUrl = getFullImagePath(movie.backdrop_path, 'w1280');
|
|
```
|
|
|
|
### Discover with Complex Filters
|
|
|
|
```typescript
|
|
// Discover action movies from 2020 with high ratings
|
|
const movies = await tmdb.discover.movies({
|
|
with_genres: '28', // Action
|
|
'primary_release_date.gte': '2020-01-01',
|
|
'primary_release_date.lte': '2020-12-31',
|
|
'vote_average.gte': 7.0,
|
|
'vote_count.gte': 100,
|
|
sort_by: 'popularity.desc',
|
|
page: 1,
|
|
language: 'en-US'
|
|
});
|
|
```
|
|
|
|
### Search with Filters
|
|
|
|
```typescript
|
|
// Search movies with year filter
|
|
const movies = await tmdb.search.movies({
|
|
query: 'Star Wars',
|
|
year: 1977,
|
|
include_adult: false,
|
|
page: 1
|
|
});
|
|
|
|
// Search TV shows with first air date year
|
|
const tvShows = await tmdb.search.tvShows({
|
|
query: 'Friends',
|
|
first_air_date_year: 1994
|
|
});
|
|
```
|
|
|
|
### Find by External ID
|
|
|
|
```typescript
|
|
// Find movie/TV show by IMDb ID
|
|
const result = await tmdb.find.byId('tt0137523', { // Fight Club IMDb ID
|
|
external_source: 'imdb_id'
|
|
});
|
|
|
|
console.log(result.movie_results);
|
|
console.log(result.tv_results);
|
|
```
|
|
|
|
### Get Trending Content
|
|
|
|
```typescript
|
|
// Get trending movies today
|
|
const trendingToday = await tmdb.trending.trending('movie', 'day');
|
|
|
|
// Get trending TV shows this week
|
|
const trendingWeek = await tmdb.trending.trending('tv', 'week');
|
|
|
|
// Get all trending (movies, TV, people)
|
|
const trendingAll = await tmdb.trending.trending('all', 'week');
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Error Types
|
|
|
|
```typescript
|
|
interface ErrorResponse {
|
|
status_code: number;
|
|
status_message: string;
|
|
success: boolean;
|
|
}
|
|
```
|
|
|
|
### Handling Errors
|
|
|
|
```typescript
|
|
try {
|
|
const movie = await tmdb.movies.details(999999999);
|
|
} catch (error) {
|
|
const tmdbError = error as ErrorResponse;
|
|
|
|
console.error(`Error ${tmdbError.status_code}: ${tmdbError.status_message}`);
|
|
|
|
// Handle specific error codes
|
|
switch (tmdbError.status_code) {
|
|
case 7:
|
|
console.error('Invalid API key');
|
|
break;
|
|
case 34:
|
|
console.error('Resource not found');
|
|
break;
|
|
default:
|
|
console.error('Unknown error');
|
|
}
|
|
}
|
|
```
|
|
|
|
### Common Error Codes
|
|
|
|
| Code | Description |
|
|
|------|-------------|
|
|
| 7 | Invalid API key |
|
|
| 34 | The resource you requested could not be found |
|
|
| 404 | Not Found |
|
|
| 401 | Invalid credentials |
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### 1. Reuse TMDB Instance
|
|
|
|
```typescript
|
|
// ❌ Bad: Creating new instances
|
|
async function getMovie() {
|
|
const tmdb = new TMDB(token);
|
|
return await tmdb.movies.details(550);
|
|
}
|
|
|
|
// ✅ Good: Reuse instance
|
|
const tmdb = new TMDB(token);
|
|
|
|
async function getMovie() {
|
|
return await tmdb.movies.details(550);
|
|
}
|
|
```
|
|
|
|
### 2. Use Append to Response
|
|
|
|
```typescript
|
|
// ❌ Bad: Multiple requests
|
|
const movie = await tmdb.movies.details(550);
|
|
const credits = await tmdb.movies.credits(550);
|
|
const videos = await tmdb.movies.videos(550);
|
|
|
|
// ✅ Good: Single request
|
|
const movie = await tmdb.movies.details(550, ['credits', 'videos']);
|
|
console.log(movie.credits, movie.videos);
|
|
```
|
|
|
|
### 3. Handle Errors Gracefully
|
|
|
|
```typescript
|
|
async function safeMovieDetails(id: number) {
|
|
try {
|
|
return await tmdb.movies.details(id);
|
|
} catch (error) {
|
|
console.error('Failed to fetch movie:', error);
|
|
return null;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. Type Your Responses
|
|
|
|
```typescript
|
|
import type { MovieDetails, Credits } from 'tmdb-ts';
|
|
|
|
async function getMovieWithCredits(id: number): Promise<MovieDetails & { credits: Credits }> {
|
|
return await tmdb.movies.details(id, ['credits']);
|
|
}
|
|
```
|
|
|
|
### 5. Cache Configuration
|
|
|
|
```typescript
|
|
// Cache configuration to avoid repeated requests
|
|
let cachedConfig: Configuration | null = null;
|
|
|
|
async function getConfig(): Promise<Configuration> {
|
|
if (!cachedConfig) {
|
|
cachedConfig = await tmdb.configuration.getApiConfiguration();
|
|
}
|
|
return cachedConfig;
|
|
}
|
|
```
|
|
|
|
### 6. Environment Variables
|
|
|
|
```typescript
|
|
// Use environment variables for tokens
|
|
const tmdb = new TMDB(process.env.TMDB_ACCESS_TOKEN!);
|
|
```
|
|
|
|
### 7. Rate Limiting
|
|
|
|
```typescript
|
|
// Implement rate limiting for bulk operations
|
|
async function fetchMoviesWithDelay(ids: number[]) {
|
|
const movies = [];
|
|
|
|
for (const id of ids) {
|
|
movies.push(await tmdb.movies.details(id));
|
|
// Add delay to avoid rate limits
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
|
|
return movies;
|
|
}
|
|
```
|
|
|
|
### 8. Batch Operations
|
|
|
|
```typescript
|
|
// Process items in batches
|
|
async function fetchMoviesBatch(ids: number[], batchSize: number = 10) {
|
|
const results = [];
|
|
|
|
for (let i = 0; i < ids.length; i += batchSize) {
|
|
const batch = ids.slice(i, i + batchSize);
|
|
const batchResults = await Promise.all(
|
|
batch.map(id => tmdb.movies.details(id))
|
|
);
|
|
results.push(...batchResults);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Full Examples
|
|
|
|
### Movie Search Application
|
|
|
|
```typescript
|
|
import { TMDB } from 'tmdb-ts';
|
|
|
|
const tmdb = new TMDB(process.env.TMDB_ACCESS_TOKEN!);
|
|
|
|
interface MovieSearchResult {
|
|
id: number;
|
|
title: string;
|
|
year: number;
|
|
rating: number;
|
|
posterUrl: string;
|
|
}
|
|
|
|
async function searchMovies(query: string): Promise<MovieSearchResult[]> {
|
|
try {
|
|
// Get configuration for image URLs
|
|
const config = await tmdb.configuration.getApiConfiguration();
|
|
const baseUrl = config.images.secure_base_url;
|
|
|
|
// Search for movies
|
|
const response = await tmdb.search.movies({ query, page: 1 });
|
|
|
|
// Transform results
|
|
return response.results.map(movie => ({
|
|
id: movie.id,
|
|
title: movie.title,
|
|
year: new Date(movie.release_date).getFullYear(),
|
|
rating: movie.vote_average,
|
|
posterUrl: movie.poster_path
|
|
? `${baseUrl}w500${movie.poster_path}`
|
|
: ''
|
|
}));
|
|
} catch (error) {
|
|
console.error('Search failed:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
const results = await searchMovies('Inception');
|
|
console.log(results);
|
|
```
|
|
|
|
### TV Show Tracker
|
|
|
|
```typescript
|
|
async function getTvShowInfo(id: number) {
|
|
const show = await tmdb.tvShows.details(id, [
|
|
'credits',
|
|
'videos',
|
|
'recommendations'
|
|
]);
|
|
|
|
return {
|
|
title: show.name,
|
|
overview: show.overview,
|
|
seasons: show.number_of_seasons,
|
|
episodes: show.number_of_episodes,
|
|
status: show.status,
|
|
nextEpisode: show.next_episode_to_air,
|
|
cast: show.credits.cast.slice(0, 10),
|
|
trailer: show.videos.results.find(v => v.type === 'Trailer'),
|
|
similar: show.recommendations.results.slice(0, 5)
|
|
};
|
|
}
|
|
```
|
|
|
|
### Person Profile
|
|
|
|
```typescript
|
|
async function getPersonProfile(id: number) {
|
|
const person = await tmdb.people.details(id, [
|
|
'movie_credits',
|
|
'tv_credits',
|
|
'external_ids'
|
|
]);
|
|
|
|
// Get top-rated movies
|
|
const topMovies = person.movie_credits.cast
|
|
.sort((a, b) => b.vote_average - a.vote_average)
|
|
.slice(0, 10);
|
|
|
|
return {
|
|
name: person.name,
|
|
biography: person.biography,
|
|
birthday: person.birthday,
|
|
birthplace: person.place_of_birth,
|
|
knownFor: person.known_for_department,
|
|
topMovies: topMovies,
|
|
socialMedia: {
|
|
imdb: person.external_ids.imdb_id,
|
|
instagram: person.external_ids.instagram_id,
|
|
twitter: person.external_ids.twitter_id
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
### Recommendation Engine
|
|
|
|
```typescript
|
|
async function getMovieRecommendations(movieId: number, limit: number = 10) {
|
|
// Get similar movies
|
|
const similar = await tmdb.movies.similar(movieId, { page: 1 });
|
|
|
|
// Get recommendations
|
|
const recommendations = await tmdb.movies.recommendations(movieId, { page: 1 });
|
|
|
|
// Combine and deduplicate
|
|
const allMovies = [...similar.results, ...recommendations.results];
|
|
const uniqueMovies = Array.from(
|
|
new Map(allMovies.map(m => [m.id, m])).values()
|
|
);
|
|
|
|
// Sort by popularity and limit
|
|
return uniqueMovies
|
|
.sort((a, b) => b.popularity - a.popularity)
|
|
.slice(0, limit);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## API Reference Quick Links
|
|
|
|
- [TMDB API Documentation](https://developers.themoviedb.org/3)
|
|
- [TMDB Authentication](https://developers.themoviedb.org/3/authentication)
|
|
- [Image Configuration](https://developers.themoviedb.org/3/configuration/get-api-configuration)
|
|
- [Language Codes](https://developers.themoviedb.org/3/configuration/get-languages)
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
This library is a wrapper around the TMDB API. For issues or feature requests, please refer to the official repository.
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
MIT License - See LICENSE.md for details
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
For questions and support:
|
|
- GitHub Issues: [tmdb-ts issues](https://github.com/blakejoy/tmdb-ts/issues)
|
|
- TMDB Forums: [The Movie Database Forums](https://www.themoviedb.org/talk)
|
|
- TMDB API Docs: [TMDB API Documentation](https://developers.themoviedb.org/3)
|