API de vídeos y tráilers
Los endpoints de vídeos listan los tráilers, teasers, clips y reportajes asociados a una película o serie. Cada entrada trae el servidor, una clave de vídeo, un tipo, una marca oficial, un tamaño y una fecha de publicación. Las rutas de temporada y episodio existen pero no devuelven vídeos. Filtra por idioma y tipo en tu código.
Obtén los vídeos de una película
GET / devuelve los registros de vídeo asociados a una película. Un registro son solo metadatos: un nombre, el servidor que sirve el vídeo, la clave del vídeo en ese servidor, un tipo y unas pocas marcas. amodb no devuelve archivos de vídeo.
El ejemplo imprime el primer tráiler oficial en inglés y, si no existe, cualquier tráiler en inglés.
curl -s "https://api.amodb.dev/3/movie/550/videos" \
-H "Authorization: Bearer $AMODB_KEY"const url = 'https://api.amodb.dev/3/movie/550/videos';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { results } = await res.json();
const trailers = results.filter((v) => v.type === 'Trailer' && v.iso_639_1 === 'en');
const pick = trailers.find((v) => v.official) ?? trailers[0];
console.log(pick ? `${pick.name} (${pick.site}, key ${pick.key})` : 'no trailer');import os
import requests
r = requests.get(
"https://api.amodb.dev/3/movie/550/videos",
headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
timeout=10,
)
r.raise_for_status()
trailers = [v for v in r.json()["results"] if v["type"] == "Trailer" and v["iso_639_1"] == "en"]
official = [v for v in trailers if v["official"]]
pick = (official or trailers or [None])[0]
print(f"{pick['name']} ({pick['site']}, key {pick['key']})" if pick else "no trailer")<?php
$url = 'https://api.amodb.dev/3/movie/550/videos';
$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");
}
$trailers = array_values(array_filter(
json_decode($body, true)['results'],
fn($v) => $v['type'] === 'Trailer' && $v['iso_639_1'] === 'en'
));
$official = array_values(array_filter($trailers, fn($v) => $v['official']));
$pick = $official[0] ?? $trailers[0] ?? null;
echo $pick ? "{$pick['name']} ({$pick['site']}, key {$pick['key']})" : 'no trailer', PHP_EOL;package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type Videos struct {
Results []struct {
Name string `json:"name"`
Key string `json:"key"`
Site string `json:"site"`
Type string `json:"type"`
Language string `json:"iso_639_1"`
Official bool `json:"official"`
} `json:"results"`
}
func main() {
url := "https://api.amodb.dev/3/movie/550/videos"
req, _ := http.NewRequest("GET", url, 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 v Videos
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
panic(err)
}
for _, r := range v.Results {
if r.Type == "Trailer" && r.Language == "en" && r.Official {
fmt.Printf("%s (%s, key %s)\n", r.Name, r.Site, r.Key)
return
}
}
fmt.Println("no official trailer")
}Parámetros
movie_idrutaobligatorioID numérico de la película, por ejemplo550.api_keyconsultauno de los dosTu clave. Usa esta o el encabezadoAuthorization: Bearer.language,include_video_languageconsultaSe aceptan pero se ignoran. La respuesta siempre contiene todos los vídeos del título. Filtra poriso_639_1en tu código.
Campos de la respuesta
| Campo | Tipo | Notas |
|---|---|---|
id | entero | El ID de la película. |
results | array | Registros de vídeo, sin ordenar por tipo ni por fecha. Vacío cuando no se conoce ninguno. |
results[].iso_639_1, results[].iso_3166_1 | texto | Idioma y país del vídeo, por ejemplo en y US. |
results[].name | texto | Título del vídeo, por ejemplo #TBT Trailer. |
results[].key | texto | ID del vídeo en ese servidor. |
results[].site | texto | Nombre del servidor de vídeo. Hoy siempre YouTube. |
results[].size | entero | Resolución vertical. Hoy siempre 1080. |
results[].type | texto | Trailer, Teaser, Clip, Featurette, Behind the Scenes, Bloopers, Opening Credits o Recap. |
results[].official | booleano | True cuando lo publicó el estudio o el titular de los derechos. |
results[].published_at | texto | Marca de tiempo ISO 8601, con o sin milisegundos. |
results[].id | texto | ID del registro de vídeo. Igual a key. |
Ejemplo de respuesta
Se muestran tres de los 19 registros de la película 550.
{
"id": 550,
"results": [
{
"iso_639_1": "en",
"iso_3166_1": "US",
"name": "Theatrical Trailer (HD Fan Remaster)",
"key": "6JnN1DmbqoU",
"site": "YouTube",
"size": 1080,
"type": "Trailer",
"official": false,
"published_at": "2015-02-26T03:19:25Z",
"id": "6JnN1DmbqoU"
},
{
"iso_639_1": "en",
"iso_3166_1": "US",
"name": "#TBT Trailer",
"key": "BdJKm16Co6M",
"site": "YouTube",
"size": 1080,
"type": "Trailer",
"official": true,
"published_at": "2014-10-02T19:20:22Z",
"id": "BdJKm16Co6M"
},
{
"iso_639_1": "en",
"iso_3166_1": "US",
"name": "Mark Kermode introduces Fight Club | Film4 Interview",
"key": "tiWCNtGDGEY",
"site": "YouTube",
"size": 1080,
"type": "Featurette",
"official": true,
"published_at": "2015-05-08T15:59:05Z",
"id": "tiWCNtGDGEY"
}
]
}Tipos de vídeo
El campo type te dice qué es un vídeo. Compáralo de forma exacta, con las mayúsculas indicadas.
| Tipo | Para qué usarlo |
|---|---|
Trailer | La promoción principal. Muéstralo en una página de detalle. |
Teaser | Un anuncio corto que llega antes del tráiler. |
Clip | Una escena tomada de la película o del episodio terminado. |
Featurette | Una pieza breve sobre cómo se hizo el título. |
Behind the Scenes | Imágenes del rodaje y entrevistas. |
Bloopers | Tomas falsas y recopilaciones de gags. |
Opening Credits | La secuencia de títulos de una serie. |
Recap | Un resumen de episodios anteriores. |
Con el tiempo pueden aparecer otros valores, así que trata un type desconocido como un extra genérico y no falles por él.
Elige el vídeo adecuado
Usa el mismo orden para todos los títulos. Prueba tus idiomas en orden. Dentro de un idioma, primero van los tráilers oficiales, luego cualquier tráiler, después los teasers y por último los clips. Dentro de un grupo ordena por published_at: el orden ascendente da el primer tráiler y el descendente da el más reciente.
function pickVideo(results, langs = ['en']) {
const order = ['Trailer', 'Teaser', 'Clip'];
for (const lang of langs) {
for (const type of order) {
const group = results
.filter((v) => v.iso_639_1 === lang && v.type === type)
.sort((a, b) => Number(b.official) - Number(a.official) || Date.parse(a.published_at) - Date.parse(b.published_at));
if (group.length > 0) return group[0];
}
}
return null;
}
// Russian first, English as the fallback.
// const video = pickVideo(results, ['ru', 'en']);Idiomas
language y include_video_language no cambian la respuesta, así que una sola llamada te da todos los vídeos del título. Cada registro trae iso_639_1 e iso_3166_1. La película 550 tiene vídeos etiquetados como fr, en, es, pt, it, cs, pl y ru. Filtra por iso_639_1 en tu código como se muestra arriba, y luego indica al usuario en qué idioma va a escuchar el vídeo. Un título puede no tener ningún vídeo en el idioma que quieres, así que conserva un respaldo en inglés o en cualquier idioma. Los 14 idiomas que se sirven están en idiomas.
Otros endpoints de vídeo
Las rutas siguientes devuelven la misma estructura de id y results.
| Método y ruta | Devuelve |
|---|---|
GET / | Vídeos de una serie. |
GET / | Siempre un array results vacío. |
GET / | Siempre un array results vacío. |
También puedes añadir append_ a una llamada de detalles de película o serie. El bloque añadido contiene results y no id. Las páginas de series y temporadas se describen en series de TV y temporadas y episodios.
Errores
| HTTP | status_code | Cuándo |
|---|---|---|
| 401 | 7 | Falta la clave o es incorrecta. |
| 402 | 36 | El periodo del plan ha terminado. |
| 404 | 34 | No existe la temporada o el episodio con ese id, o el id no es un número. |
| 405 | 37 | Usaste un método de escritura en una ruta de vídeos. |
| 429 | 25 | Superaste tus solicitudes por minuto. Espera los segundos indicados en Retry-After. |
Un id de película o serie que no existe no es un error aquí: la ruta de vídeos responde 200 con "results": [], igual que un título conocido sin vídeos. La ruta de detalles responde 404 ante un id desconocido. Más información en errores y límites de solicitudes.
Notas prácticas
- Guarda con el título el
sitey lakeyelegidos, no una dirección completa, para poder cambiar el reproductor más adelante. - Las listas de vídeos siguen la caché de detalles de 6 horas en la caché perimetral. Una caché de cliente de unas pocas horas encaja con ella.
sizees 1080 en todos los registros hoy, así que no te dice qué clip es ligero. Deja que el reproductor elija la calidad.- No des por hecho que existe un tráiler. Oculta el botón de reproducir cuando tu función de selección devuelva null.
- El orden de
resultsno significa nada. Ordena en tu código. - Para los archivos de póster y de imagen de fondo, consulta imágenes. Para la vista del caso de uso, consulta la API de tráilers de películas.