API de vídeos e trailers
Os endpoints de vídeos listam os trailers, teasers, clipes e featurettes ligados a um filme ou série. Cada entrada traz o nome do host, a chave do vídeo, o tipo, um sinalizador oficial, o tamanho e a data de publicação. Os caminhos de temporada e episódio não retornam vídeos. Filtre por idioma e tipo no seu próprio código.
Obter os vídeos de um filme
GET / retorna os registros de vídeo ligados a um filme. Um registro tem só metadados: um nome, o host que serve o vídeo, a chave do vídeo nesse host, um tipo e alguns sinalizadores. O amodb não retorna arquivos de vídeo.
O exemplo imprime o primeiro trailer oficial em inglês e, se não houver, qualquer trailer em 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_idcaminhoobrigatórioId numérico do filme, por exemplo550.api_keyconsultaum dos doisSua chave. Use este parâmetro ou o headerAuthorization: Bearer.language,include_video_languageconsultaAceitos, mas ignorados. A resposta sempre traz todos os vídeos do título. Filtre poriso_639_1no seu código.
Campos da resposta
| Campo | Tipo | Observações |
|---|---|---|
id | inteiro | O id do filme. |
results | array | Registros de vídeo, sem ordenação por tipo ou data. Vazio quando nenhum é conhecido. |
results[].iso_639_1, results[].iso_3166_1 | string | Idioma e país do vídeo, por exemplo en e US. |
results[].name | string | Título do vídeo, por exemplo #TBT Trailer. |
results[].key | string | Id do vídeo nesse host. |
results[].site | string | Nome do host do vídeo. Hoje é sempre YouTube. |
results[].size | inteiro | Resolução vertical. Hoje é sempre 1080. |
results[].type | string | Trailer, Teaser, Clip, Featurette, Behind the Scenes, Bloopers, Opening Credits ou Recap. |
results[].official | booleano | Verdadeiro quando o estúdio ou o detentor dos direitos o publicou. |
results[].published_at | string | Timestamp ISO 8601, com ou sem milissegundos. |
results[].id | string | Id do registro de vídeo. Igual a key. |
Exemplo de resposta
Três dos 19 registros do filme 550 são mostrados.
{
"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
O campo type diz o que um vídeo é. Compare exatamente, com as maiúsculas mostradas.
| Tipo | Para que serve |
|---|---|
Trailer | A promoção principal. Mostre este na página de detalhes. |
Teaser | Um anúncio curto que vem antes do trailer. |
Clip | Uma cena tirada do filme ou do episódio finalizado. |
Featurette | Um vídeo curto sobre como o título foi feito. |
Behind the Scenes | Imagens de set e entrevistas. |
Bloopers | Cenas cortadas e erros de gravação. |
Opening Credits | A abertura de uma série. |
Recap | Um resumo dos episódios anteriores. |
Outros valores podem aparecer com o tempo, então trate um type desconhecido como um extra genérico e não falhe por causa dele.
Escolher o vídeo certo
Use a mesma ordem para todo título. Tente seus idiomas em ordem. Dentro de um idioma, os trailers oficiais vêm primeiro, depois qualquer trailer, depois teasers, depois clipes. Dentro de um grupo, ordene por published_at: crescente dá o primeiro trailer, decrescente dá o mais recente.
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 e include_video_language não mudam a resposta, então uma chamada traz todos os vídeos do título. Cada registro tem iso_639_1 e iso_3166_1. O filme 550 tem vídeos marcados como fr, en, es, pt, it, cs, pl e ru. Filtre por iso_639_1 no seu código, como mostrado acima, e depois avise ao usuário em que idioma ele vai ouvir o vídeo. Um título pode não ter vídeo no idioma que você quer, então mantenha um fallback em inglês ou em qualquer idioma. Os 14 idiomas atendidos estão listados em idiomas.
Outros endpoints de vídeos
Os caminhos abaixo retornam o mesmo formato com id e results.
| Método e caminho | Retorna |
|---|---|
GET / | Vídeos de uma série. |
GET / | Sempre um array results vazio. |
GET / | Sempre um array results vazio. |
Você também pode usar append_ em uma chamada de detalhes de filme ou de série. O bloco acrescentado traz results e não tem id. As páginas de séries e de temporadas estão descritas em séries de TV e temporadas e episódios.
Erros
| HTTP | status_code | Quando |
|---|---|---|
| 401 | 7 | A chave está ausente ou incorreta. |
| 402 | 36 | O período do plano terminou. |
| 404 | 34 | Nenhuma temporada ou episódio com esse id, ou um id que não é um número. |
| 405 | 37 | Você usou um método de escrita em um caminho de vídeos. |
| 429 | 25 | Você passou do seu limite de requisições por minuto. Espere os segundos indicados em Retry-After. |
Um id de filme ou de série que não existe não é um erro aqui: o caminho de vídeos responde 200 com "results": [], igual a um título conhecido sem vídeos. O caminho de detalhes responde 404 para um id desconhecido. Mais em erros e limites de requisições.
Notas práticas
- Guarde o
sitee akeyescolhidos junto do título, não um endereço completo, para poder trocar o player depois. - As listas de vídeos seguem o cache de detalhes de 6 horas na borda. Um cache de cliente de poucas horas acompanha isso.
sizeé 1080 em todo registro hoje, então não diz qual clipe é mais leve. Deixe o player escolher a qualidade.- Não conte com a existência de um trailer. Esconda o botão de reproduzir quando sua função de escolha retornar null.
- A ordem de
resultsnão tem significado. Ordene no seu código. - Para arquivos de pôster e de imagem de fundo (backdrop), veja imagens. Para a visão do caso de uso, veja API de trailers de filmes.