API de temporadas y episodios de TV

Lee una temporada con todos sus episodios en GET /3/tv/{series_id}/season/{season_number}, o un solo episodio un nivel más abajo. El JSON coincide con TMDB v3 con air_date, episode_number, runtime y still_path. Cada episodio trae crew y guest_stars, la temporada 0 reúne los especiales, y append_to_response añade credits, images y videos.

Actualizado el Ver en Markdown

Obtén una temporada

GET /3/tv/{series_id}/season/{season_number} devuelve una temporada y su array episodes completo en una sola respuesta. Los números de temporada empiezan en 1, y 0 se reserva para los especiales. Toma el id de la serie y los números de temporada del registro de series de TV.

El ejemplo lee la temporada 1 de Breaking Bad. El código imprime una línea por episodio.

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)
	}
}

Parámetros

  • series_idrutaobligatorio
    ID numérico de la serie de TV, por ejemplo 1396.
  • season_numberrutaobligatorio
    Número entero de temporada. 0 devuelve los especiales.
  • api_keyconsultauno de los dos
    Tu clave. Usa esta o el encabezado Authorization: Bearer.
  • languageconsulta
    Etiqueta TMDB como en-US o fr-FR. Se sirven 14 idiomas base. Por defecto en-US.
  • append_to_responseconsulta
    Valores a nivel de temporada: credits, external_ids, images, videos. Los demás nombres se ignoran.

Campos de la respuesta

CampoTipoNotas
id, season_numberenteroID de la temporada y su número dentro de la serie.
name, overviewtextoTexto localizado, vacío cuando no existe traducción.
air_datetexto o nullFecha del primer episodio, YYYY-MM-DD.
poster_pathtexto o nullSe añade a https://img.amodb.dev/t/p/{size}.
vote_averagenúmeroPuntuación agregada de los usuarios para la temporada.
episodesarrayTodos los episodios, con los campos de la sección siguiente.

Ejemplo de respuesta

GET /3/tv/1396/season/1?language=en-US. La temporada tiene 7 episodios, así que episodes se recortó a una entrada, y los arrays crew y guest_stars de esa entrada se omitieron:

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
}

Cada episodio de la respuesta de temporada también trae arrays crew y guest_stars, con la estructura de entrada descrita en créditos. runtime puede ser null en un episodio que aún no se ha emitido.

Obtén un episodio

GET /3/tv/{series_id}/season/{season_number}/episode/{episode_number} devuelve un episodio. La respuesta de temporada ya contiene todos los episodios con crew y guest_stars, así que usa este endpoint para actualizar un registro sin volver a cargar la temporada. Acepta language y append_to_response con credits, external_ids, images, translations y videos. Una solicitud como /3/tv/1396/season/1/episode/1?append_to_response=credits cuesta una sola solicitud.

CampoTipoNotas
identeroID del episodio.
show_identeroID de la serie. Aparece en la respuesta de temporada y en los punteros de la serie, no en la respuesta de un solo episodio.
season_number, episode_numberenteroPosición dentro de la serie. Úsalos para construir la ruta de la solicitud.
name, overviewtextoTexto localizado.
air_datetexto o nullSolo fecha, sin hora ni zona horaria. Null cuando no está programado.
episode_typetextostandard para episodios normales. Para detectar un final, compara episode_number con el episode_count de esa temporada en el registro de la serie.
runtimeentero o nullMinutos.
production_codetextoCódigo del estudio, a menudo vacío.
still_pathtexto o nullFotograma del episodio. Usa w300 u original de https://img.amodb.dev/t/p/{size}.
vote_average, vote_countnúmero, enteroPuntuación agregada de los usuarios.
crew, guest_starsarrayCréditos de este episodio, ver créditos.

Próximo y último episodio en el registro de la serie

El endpoint de series devuelve next_episode_to_air y last_episode_to_air. Cada uno es un resumen de episodio con los campos de arriba, más show_id y sin crew ni guest_stars. El próximo es null en las series terminadas y en las series en curso sin fecha confirmada. El ejemplo lee South Park, una serie en curso.

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');

Para una cuenta atrás, compara air_date con la fecha local del espectador. El valor no lleva hora del día, así que muestra una fecha y no una hora.

Subrecursos de temporada y episodio

Las rutas de temporada y episodio tienen sus propios subrecursos. Varios de ellos devuelven hoy datos vacíos.

Método y rutaDevuelve
GET /tv/{series_id}/season/{season_number}/creditsid, cast y crew de la temporada
GET /tv/{series_id}/season/{season_number}/imagesid y un array posters vacío
GET /tv/{series_id}/season/{season_number}/videosid y un array results vacío
GET /tv/{series_id}/season/{season_number}/external_idsid más tvdb_id, wikidata_id y otros ids, todos null
GET /tv/{series_id}/season/{season_number}/translationsid y un array translations vacío
GET .../episode/{episode_number}/creditsid, un cast vacío, crew y guest_stars
GET .../episode/{episode_number}/imagesid y un array stills con el fotograma del episodio
GET .../episode/{episode_number}/videosid y un array results vacío
GET .../episode/{episode_number}/external_idsid más imdb_id, tvdb_id y otros ids, todos null
GET .../episode/{episode_number}/translationsid y un array translations con nombre y sinopsis por idioma

Los créditos de temporada y episodio se explican en créditos, y los fotogramas en imágenes. amodb no ofrece las rutas changes de TMDB ni un endpoint para los episodios de un grupo de episodios.

Errores

HTTPstatus_codeCuándo
4017Falta la clave o es incorrecta.
40236El periodo del plan ha terminado.
40434La serie, la temporada o el episodio no existe, por ejemplo la temporada 0 en una serie sin especiales, o la ruta no se ofrece.
40537Llamaste a un método de escritura.
42925Superaste tus solicitudes por minuto. Espera los segundos indicados en Retry-After.

Consulta errores para ver el formato completo del cuerpo y límites de solicitudes para las ventanas.

Notas prácticas

  • Las temporadas y los episodios se guardan en caché 6 horas. Vuelve a leer la temporada actual una o dos veces al día mientras se emite la serie.
  • Una serie de 10 temporadas necesita 10 llamadas de temporada. En el plan de 20 solicitudes por minuto eso usa la mitad del cupo de un minuto, y una repetición dentro de las 6 horas se responde desde la caché perimetral.
  • Un episodio sin emitir puede tener air_date null, runtime null y overview vacío. Muestra un marcador de posición en lugar de fallar.
  • Los fotogramas son tomas panorámicas, no pósteres. Pide w300 en las listas y original solo cuando necesites una vista a tamaño completo.