Usage
The central object is the TheTVDBClient client which needs the
api_key supplied by the TheTVDB. It can be initialised with a
cache (optionally), and if no cache is passed a dummy cache object
will be created.
Cache
It is advisable to use a cache that will persist during a server restart, so that the token will not have to be regenerated.
Security warning
Please be advised that the token will be stored in the default cache in plaintext, so if there are any security considerations they should be taken care into account when choosing the cache.
Configuration
You can provide credentials in any of these ways (checked in this order):
- Direct constructor argument — pass
api_key(and optionallypin) toTheTVDBClient. - Environment variables — set
TVDB_API_KEY_V4and/orTVDB_PIN_V4. - Config file — create
the_tvdb.yamlin$XDG_CONFIG_HOMEwith aclientsection:
client:
api_key: your-api-key
pin: your-pin # optional
Security warning
Passing secrets in env vars is insecure, as some operating systems
allow non-root users to see process environment variables via ps.
It is advised to use the config file option and set restrictive
permissions on it (e.g. chmod 600 the_tvdb.yaml).
The TVDB API Client
Refreshing cache
All methods use the cached value when present.
Pass refresh_cache=True to any of them to fetch fresh data.
get
def get(path: str) -> dict[str, object]
Low-level method that performs an authenticated GET request to the TVDB API and returns the raw JSON response. Use the higher-level methods below unless you need an endpoint not yet wrapped by this client.
data = client.get("series/81189")
get_series_by_id
def get_series_by_id(tvdb_id: int, *, refresh_cache: bool = False) -> Series
Fetches a TV series by its TVDB id and returns a parsed Series object.
series = client.get_series_by_id(81189)
print(series.name) # "Breaking Bad"
print(series.status.name) # "Ended"
print(series.first_aired) # datetime.date(2008, 1, 20)
get_raw_series_by_id
def get_raw_series_by_id(tvdb_id: int, *, refresh_cache: bool = False) -> SeriesRawData
Same as get_series_by_id but returns the raw API dict instead of a Series
dataclass. Useful when you need fields not yet exposed by the data model.
raw = client.get_raw_series_by_id(81189)
print(raw["name"]) # "Breaking Bad"
get_episodes_by_series
def get_episodes_by_series(
tvdb_id: int,
season_type: str = "default",
*,
refresh_cache: bool = False,
) -> list[Episode]
Fetches all episodes for a TV series and returns a list of parsed Episode
objects. Handles pagination automatically.
episodes = client.get_episodes_by_series(81189)
for ep in episodes:
print(ep.season_number, ep.number, ep.name)
The season_type parameter controls the ordering used by TVDB:
| Value | Description |
|---|---|
"default" |
The series' default ordering (usually official) |
"official" |
Broadcast / official season ordering |
"dvd" |
DVD release ordering |
"absolute" |
Absolute (continuous) episode numbering |
"alternate" |
Alternate ordering defined by the community |
"regional" |
Region-specific ordering |
get_raw_episodes_by_series
def get_raw_episodes_by_series(
tvdb_id: int,
season_type: str = "default",
page: int = 0,
*,
refresh_cache: bool = False,
) -> CleanedEpisodeData
Same as get_episodes_by_series but returns raw dicts and exposes the page
parameter for manual pagination. Each page contains up to 500 episodes.
page = client.get_raw_episodes_by_series(81189, page=0)
print(page["has_next_page"]) # False for most series
Data Models
Series
| Field | Type | Description |
|---|---|---|
id |
int |
TVDB series id |
name |
str |
Primary title |
slug |
str |
URL-friendly identifier |
image |
URL \| None |
Poster image URL |
name_translations |
list[str] |
Language codes with a translated title |
overview_translations |
list[str] |
Language codes with a translated overview |
aliases |
list[Alias] |
Alternative titles |
first_aired |
date \| None |
Date the series first aired |
last_aired |
date \| None |
Date the series last aired |
next_aired |
date \| None |
Date of the next episode |
score |
float |
Community rating score |
status |
Status |
Current airing status |
original_country |
str |
Country of origin |
original_language |
str |
Original language |
default_season_type |
int |
Default season ordering id |
is_order_randomized |
bool |
Whether episode order is randomised |
last_updated |
datetime \| None |
Last metadata update timestamp |
average_runtime |
int |
Average episode runtime in minutes |
overview |
str |
Plot summary |
Episode
| Field | Type | Description |
|---|---|---|
id |
int |
TVDB episode id |
series_id |
int |
TVDB id of the parent series |
name |
str |
Episode title |
aired |
date \| None |
Air date |
runtime |
int |
Runtime in minutes |
name_translations |
list[str] |
Language codes with a translated title |
overview |
str |
Episode synopsis |
overview_translations |
list[str] |
Language codes with a translated overview |
image |
URL \| None |
Episode still image URL |
image_type |
int |
Image type code |
is_movie |
int |
Non-zero if this is a movie entry |
number |
int |
Episode number within its season |
season_number |
int |
Season number |
last_updated |
datetime \| None |
Last metadata update timestamp |
finale_type |
str |
Finale classification (e.g. "season", "series") |
Status
| Field | Type | Description |
|---|---|---|
id |
int |
Status id |
name |
str |
Human-readable status (e.g. "Ended", "Continuing") |
record_type |
str |
Record type this status applies to |
keep_updated |
bool |
Whether TVDB continues updating this record |
Alias
| Field | Type | Description |
|---|---|---|
language |
str |
BCP 47 language code |
name |
str |
Alternative title in that language |