API des saisons et épisodes de séries TV

Lisez une saison avec tous ses épisodes sur GET /3/tv/{series_id}/season/{season_number}, ou un seul épisode un niveau plus bas. Le JSON suit TMDB v3 avec air_date, episode_number, runtime et still_path. Chaque épisode porte crew et guest_stars, la saison 0 contient les épisodes spéciaux, et append_to_response ajoute crédits, images et vidéos.

Mis à jour le Voir en Markdown

Obtenir une saison

GET /3/tv/{series_id}/season/{season_number} renvoie une saison et son tableau episodes complet en une seule réponse. Les numéros de saison commencent à 1, et 0 est réservé aux épisodes spéciaux. Prenez l'identifiant de la série et les numéros de saison dans la fiche séries TV.

L'exemple lit la saison 1 de Breaking Bad. Le code affiche une ligne par épisode.

bashjspyphpgo
curl -sSf "https://api.amodb.dev/3/tv/1396/season/1?language=en-US" \
  -H "Authorization: Bearer $AMODB_KEY"
const url = 'https://api.amodb.dev/3/tv/1396/season/1?language=en-US';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const season = await res.json();
for (const ep of season.episodes) {
  console.log(String(ep.episode_number).padStart(2, '0'), ep.name, ep.air_date, `${ep.runtime ?? '?'} min`);
}
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/tv/1396/season/1",
    params={"language": "en-US"},
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
season = r.json()
for ep in season["episodes"]:
    print(f"{ep['episode_number']:02d}", ep["name"], ep["air_date"], ep["runtime"] or "?")
<?php
$url = 'https://api.amodb.dev/3/tv/1396/season/1?language=en-US';
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
    throw new RuntimeException("amodb returned $status");
}
$season = json_decode($body, true);
foreach ($season['episodes'] as $ep) {
    printf("%02d %s %s\n", $ep['episode_number'], $ep['name'], $ep['air_date']);
}
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

type Season struct {
	Name     string `json:"name"`
	Episodes []struct {
		EpisodeNumber int    `json:"episode_number"`
		Name          string `json:"name"`
		AirDate       string `json:"air_date"`
		Runtime       int    `json:"runtime"`
	} `json:"episodes"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/tv/1396/season/1?language=en-US", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	client := &http.Client{Timeout: 10 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic(res.Status)
	}
	var s Season
	if err := json.NewDecoder(res.Body).Decode(&s); err != nil {
		panic(err)
	}
	for _, e := range s.Episodes {
		fmt.Printf("%02d %s %s %d min\n", e.EpisodeNumber, e.Name, e.AirDate, e.Runtime)
	}
}

Paramètres

  • series_idcheminobligatoire
    Identifiant numérique de la série, par exemple 1396.
  • season_numbercheminobligatoire
    Numéro de saison entier. 0 renvoie les épisodes spéciaux.
  • api_keyrequêtel'un des deux
    Votre clé. Utilisez-la ou l'en-tête Authorization: Bearer.
  • languagerequête
    Balise TMDB comme en-US ou fr-FR. 14 langues de base sont servies. Par défaut en-US.
  • append_to_responserequête
    Valeurs au niveau de la saison : credits, external_ids, images, videos. Les autres noms sont ignorés.

Champs de la réponse

ChampTypeRemarques
id, season_numberentierIdentifiant de la saison et son numéro dans la série.
name, overviewchaîneTexte localisé, vide quand il n'existe pas de traduction.
air_datechaîne ou nullDate du premier épisode, YYYY-MM-DD.
poster_pathchaîne ou nullÀ ajouter à https://img.amodb.dev/t/p/{size}.
vote_averagenombreNote agrégée des utilisateurs pour la saison.
episodestableauTous les épisodes, avec les champs listés dans la section suivante.

Exemple de réponse

GET /3/tv/1396/season/1?language=en-US. La saison compte 7 épisodes : episodes est donc réduit à une entrée, et les tableaux crew et guest_stars de cette entrée sont omis :

JSON
{
  "air_date": "2008-01-20",
  "episodes": [
    {
      "air_date": "2008-01-20",
      "episode_number": 1,
      "episode_type": "standard",
      "id": 62085,
      "name": "Pilot",
      "overview": "When an unassuming high school chemistry teacher discovers he has a rare form of lung cancer, he decides to...",
      "production_code": "",
      "runtime": 59,
      "season_number": 1,
      "show_id": 1396,
      "still_path": "/ydlY3iPfeOAvu8gVqrxPoMvzNCn.jpg",
      "vote_average": 0,
      "vote_count": 0
    }
  ],
  "name": "Season 1",
  "overview": "High school chemistry teacher Walter White's life is suddenly transformed by a dire medical diagnosis. Stre...",
  "id": 3572,
  "poster_path": "/91EIXdWxmp2mHNRsSuDW3WyDJLj.jpg",
  "season_number": 1,
  "vote_average": 0
}

Chaque épisode de la réponse de saison porte aussi des tableaux crew et guest_stars, avec la forme d'entrée décrite sur crédits. runtime peut être null pour un épisode pas encore diffusé.

Obtenir un épisode

GET /3/tv/{series_id}/season/{season_number}/episode/{episode_number} renvoie un épisode. La réponse de saison contient déjà tous les épisodes avec crew et guest_stars : utilisez donc ce point de terminaison pour actualiser une fiche sans recharger la saison. Il accepte language et append_to_response avec credits, external_ids, images, translations et videos. Une requête comme /3/tv/1396/season/1/episode/1?append_to_response=credits coûte une requête.

ChampTypeRemarques
identierIdentifiant de l'épisode.
show_identierIdentifiant de la série. Présent dans la réponse de saison et dans les pointeurs de série, pas dans la réponse d'un seul épisode.
season_number, episode_numberentierPosition dans la série. Utilisez-les pour construire le chemin de la requête.
name, overviewchaîneTexte localisé.
air_datechaîne ou nullDate seule, sans heure ni fuseau horaire. Null quand non programmé.
episode_typechaînestandard pour les épisodes normaux. Pour repérer un final, comparez episode_number avec l'episode_count de cette saison dans la fiche de la série.
runtimeentier ou nullMinutes.
production_codechaîneCode du studio, souvent vide.
still_pathchaîne ou nullImage de l'épisode. Utilisez w300 ou original depuis https://img.amodb.dev/t/p/{size}.
vote_average, vote_countnombre, entierNote agrégée des utilisateurs.
crew, guest_starstableauCrédits de cet épisode, voir crédits.

Prochain et dernier épisode dans la fiche de la série

Le point de terminaison de série renvoie next_episode_to_air et last_episode_to_air. Chacun est un résumé d'épisode avec les champs ci-dessus, plus show_id et sans crew ni guest_stars. Le prochain est null pour les séries terminées et pour les séries en cours sans date confirmée. L'exemple lit South Park, une série en cours.

JavaScript
const headers = { Authorization: `Bearer ${process.env.AMODB_KEY}` };
const res = await fetch('https://api.amodb.dev/3/tv/2190', { headers });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const next = (await res.json()).next_episode_to_air;
console.log(next ? `Next: S${next.season_number}E${next.episode_number} on ${next.air_date}` : 'No upcoming episode');

Pour un compte à rebours, comparez air_date avec la date locale du spectateur. La valeur ne porte pas d'heure : affichez donc une date et non une heure d'horloge.

Sous-ressources des saisons et des épisodes

Les chemins de saisons et d'épisodes ont leurs propres sous-ressources. Plusieurs renvoient aujourd'hui des données vides.

Méthode et cheminRenvoie
GET /tv/{series_id}/season/{season_number}/creditsid, cast et crew de la saison
GET /tv/{series_id}/season/{season_number}/imagesid et un tableau posters vide
GET /tv/{series_id}/season/{season_number}/videosid et un tableau results vide
GET /tv/{series_id}/season/{season_number}/external_idsid plus tvdb_id, wikidata_id et d'autres identifiants, tous nuls
GET /tv/{series_id}/season/{season_number}/translationsid et un tableau translations vide
GET .../episode/{episode_number}/creditsid, un cast vide, crew et guest_stars
GET .../episode/{episode_number}/imagesid et un tableau stills avec l'image de l'épisode
GET .../episode/{episode_number}/videosid et un tableau results vide
GET .../episode/{episode_number}/external_idsid plus imdb_id, tvdb_id et d'autres identifiants, tous nuls
GET .../episode/{episode_number}/translationsid et un tableau translations avec nom et résumé par langue

Les crédits de saisons et d'épisodes sont traités sur crédits, et les images sur images. amodb ne propose pas les chemins changes de TMDB ni de point de terminaison pour les épisodes d'un groupe d'épisodes.

Erreurs

HTTPstatus_codeQuand
4017La clé est absente ou fausse.
40236La période de l'offre est terminée.
40434La série, la saison ou l'épisode n'existe pas, par exemple la saison 0 d'une série sans épisodes spéciaux, ou le chemin n'est pas proposé.
40537Vous avez appelé une méthode d'écriture.
42925Au-dessus de vos requêtes par minute. Attendez les secondes de Retry-After.

Voir erreurs pour le format complet du corps et limites de débit pour les fenêtres.

Remarques pratiques

  • Les saisons et les épisodes sont mis en cache 6 heures. Relisez la saison en cours une ou deux fois par jour pendant la diffusion d'une série.
  • Une série de 10 saisons demande 10 appels de saison. Avec l'offre à 20 requêtes par minute, cela utilise la moitié du quota d'une minute, et une seconde exécution dans les 6 heures est servie depuis le cache de périphérie.
  • Un épisode non diffusé peut avoir un air_date null, un runtime null et un overview vide. Affichez une image de remplacement au lieu d'échouer.
  • Les images d'épisodes sont des plans larges, pas des affiches. Demandez w300 pour les listes et original seulement quand vous avez besoin d'une vue en taille réelle.