API de imagens e host de imagens
Os endpoints de imagens listam pôsteres, backdrops, logos, perfis e stills de um título como caminhos de arquivo. Você carrega cada arquivo de img.amodb.dev em um tamanho fixo, sem chave e com cache de borda de 30 dias. Caminhos e JSON seguem o TMDB v3, então o código de imagens existente funciona após trocar a URL base.
Obter as imagens de um filme
GET / lista todas as imagens conhecidas de um filme em três arrays: backdrops, logos e posters. Cada entrada tem um file_path, o tamanho em pixels e uma tag de idioma. O arquivo em si não vem no JSON. Você o carrega do host de imagens em uma segunda etapa.
O exemplo pede imagens em inglês e sem texto, escolhe o primeiro pôster em inglês e depois busca esse arquivo com 500 pixels de largura.
curl -s "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null" \
-H "Authorization: Bearer $AMODB_KEY"
curl -s -o poster.jpg -w "%{http_code}\n" \
"https://img.amodb.dev/t/p/w500/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg"const url = 'https://api.amodb.dev/3/movie/550/images?include_image_language=en,null';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { posters } = await res.json();
if (posters.length === 0) throw new Error('no posters');
const poster = posters.find((p) => p.iso_639_1 === 'en') ?? posters[0];
const posterUrl = `https://img.amodb.dev/t/p/w500${poster.file_path}`;
const img = await fetch(posterUrl);
console.log(img.status, img.headers.get('content-type'), posterUrl);import os
import requests
r = requests.get(
"https://api.amodb.dev/3/movie/550/images",
params={"include_image_language": "en,null"},
headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
timeout=10,
)
r.raise_for_status()
posters = r.json()["posters"]
if not posters:
raise SystemExit("no posters")
poster = next((p for p in posters if p["iso_639_1"] == "en"), posters[0])
poster_url = "https://img.amodb.dev/t/p/w500" + poster["file_path"]
img = requests.get(poster_url, timeout=10)
print(img.status_code, img.headers.get("content-type"), poster_url)<?php
$url = 'https://api.amodb.dev/3/movie/550/images?include_image_language=en,null';
$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");
}
$posters = json_decode($body, true)['posters'];
if (!$posters) {
throw new RuntimeException('no posters');
}
$poster = $posters[0];
foreach ($posters as $p) {
if ($p['iso_639_1'] === 'en') {
$poster = $p;
break;
}
}
$posterUrl = 'https://img.amodb.dev/t/p/w500' . $poster['file_path'];
$img = curl_init($posterUrl);
curl_setopt_array($img, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10]);
curl_exec($img);
echo curl_getinfo($img, CURLINFO_HTTP_CODE), ' ', curl_getinfo($img, CURLINFO_CONTENT_TYPE), ' ', $posterUrl, PHP_EOL;
curl_close($img);package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type Images struct {
Posters []struct {
FilePath string `json:"file_path"`
Language string `json:"iso_639_1"`
} `json:"posters"`
}
func main() {
url := "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null"
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 images Images
if err := json.NewDecoder(res.Body).Decode(&images); err != nil || len(images.Posters) == 0 {
panic("no posters")
}
poster := images.Posters[0]
for _, p := range images.Posters {
if p.Language == "en" {
poster = p
break
}
}
posterURL := "https://img.amodb.dev/t/p/w500" + poster.FilePath
img, err := client.Get(posterURL)
if err != nil {
panic(err)
}
defer img.Body.Close()
fmt.Println(img.StatusCode, img.Header.Get("Content-Type"), posterURL)
}Parâmetros
movie_idcaminhoobrigatórioId numérico do filme, por exemplo550.api_keyconsultaum dos doisSua chave. Use este parâmetro ou o headerAuthorization: Bearer.include_image_languageconsultaCódigos ISO 639-1 separados por vírgulas. Acrescentenullpara incluir imagens sem texto, por exemploen,null. Só os idiomas listados voltam. Sem ele, você recebe todos os idiomas.languageconsultaAceito, mas ignorado neste endpoint. Useinclude_image_languagepara escolher idiomas.
Campos da resposta
| Campo | Tipo | Observações |
|---|---|---|
id | inteiro | O id do filme. |
backdrops, logos, posters | array | Um array por tipo de imagem, nessa ordem de chaves. Cada um pode vir vazio. |
file_path | string | Começa com uma barra. Acrescente-o a um tamanho no host de imagens. Pôsteres e backdrops são .jpg, logos são .png ou .svg. |
width, height | inteiro | Tamanho em pixels do arquivo original. 0 quando o tamanho não é conhecido. |
aspect_ratio | número | Largura dividida pela altura. Pôsteres ficam perto de 0.667, backdrops perto de 1.778. 0 quando o tamanho não é conhecido. |
iso_639_1 | string ou null | Idioma do texto na imagem. null significa sem texto. |
vote_average, vote_count | número, inteiro | Sempre 0 em imagens de filmes e séries, então não servem para ordenar imagens. Mantenha a ordem que a API retorna. |
Exemplo de resposta
Duas entradas por array aparecem aqui.
{
"id": 550,
"backdrops": [
{
"aspect_ratio": 1.778,
"height": 1440,
"iso_639_1": null,
"file_path": "/c6OLXfKAk5BKeR6broC8pYiCquX.jpg",
"vote_average": 0,
"vote_count": 0,
"width": 2560
},
{
"aspect_ratio": 1.778,
"height": 1080,
"iso_639_1": "en",
"file_path": "/b9HyPoxwxjxkWEUL5ErZdhApQe2.jpg",
"vote_average": 0,
"vote_count": 0,
"width": 1920
}
],
"logos": [
{
"aspect_ratio": 4.638,
"height": 389,
"iso_639_1": "en",
"file_path": "/7Uqhv24pGJs4Ns31NoOPWFJGWNG.png",
"vote_average": 0,
"vote_count": 0,
"width": 1804
},
{
"aspect_ratio": 0.848,
"height": 1295,
"iso_639_1": "en",
"file_path": "/4XkF0Rf7gvSfea8fYLFbU5tmuJw.png",
"vote_average": 0,
"vote_count": 0,
"width": 1098
}
],
"posters": [
{
"aspect_ratio": 0.667,
"height": 3000,
"iso_639_1": "en",
"file_path": "/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg",
"vote_average": 0,
"vote_count": 0,
"width": 2000
},
{
"aspect_ratio": 0,
"height": 0,
"iso_639_1": null,
"file_path": "/qkrH7rjYKU4KOwwIl6wF6H3ISvm.jpg",
"vote_average": 0,
"vote_count": 0,
"width": 0
}
]
}O segundo pôster mostra uma entrada cujo tamanho não é conhecido. O arquivo carrega normalmente.
Montar a URL de uma imagem
Junte três partes: https:/, um segmento de tamanho e o file_path. O caminho já começa com uma barra, então https:/ mais / é uma URL completa.
Um tamanho é w mais uma largura em pixels, h mais uma altura em pixels, ou original para o arquivo armazenado. O host serve dez tamanhos: w92, w154, w185, w300, w342, w500, w780, w1280, h632 e original. Qualquer outro tamanho, como w400, responde 404. /3/configuration lista os tamanhos que servem para cada tipo de imagem.
| Tipo | Campo na configuração | Tamanhos |
|---|---|---|
| Pôster | poster_sizes | w92, w154, w185, w342, w500, w780, original |
| Backdrop | backdrop_sizes | w300, w780, w1280, original |
| Logo | logo_sizes | w92, w154, w185, w300, w500, original |
| Perfil | profile_sizes | w185, h632, original |
| Still (foto de cena) | still_sizes | w92, w185, w300, original |
O host não verifica o tipo, então um pôster também carrega em w1280. Fique nos tamanhos listados para o tipo, para que seu código corresponda à configuração e a qualquer cliente do TMDB.
O host de imagens não exige chave, e a borda guarda cada arquivo por 30 dias. Como nenhuma chave é enviada, o carregamento de imagens não consome o seu limite de requisições por minuto. As respostas trazem Access-Control-Allow-Origin: *, então um navegador pode carregá-las de qualquer página. Um tamanho desconhecido ou um arquivo desconhecido responde 404 com um corpo JSON.
Imagens responsivas com srcset
Escolha o menor tamanho que ainda cubra a largura exibida vezes a densidade da tela. Um pôster exibido com 171 pixels CSS de largura precisa de w342 em uma tela 2x. Esta função auxiliar monta um srcset a partir de um caminho guardado.
const WIDTHS = [185, 342, 500, 780];
function posterSrcset(filePath) {
return WIDTHS.map((w) => `https://img.amodb.dev/t/p/w${w}${filePath} ${w}w`).join(', ');
}
const path = '/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg';
console.log(`<img src="https://img.amodb.dev/t/p/w342${path}" srcset="${posterSrcset(path)}" sizes="(max-width: 600px) 50vw, 342px" alt="Fight Club poster">`);Outros endpoints de imagens
Todos os caminhos abaixo usam a base https:/ e retornam os arrays citados na segunda coluna.
| Método e caminho | Arrays retornados | Parâmetros |
|---|---|---|
GET / | backdrops, logos, posters | include_image_language |
GET / | posters, sempre vazio | nenhum |
GET / | stills, uma entrada com width e height definidos como 0 | nenhum |
GET / | profiles | nenhum |
Para filmes e séries, você também pode acrescentar append_ a uma chamada de detalhes. include_image_language funciona ali também. O bloco anexado não tem um id próprio.
Os perfis de pessoas são o único lugar em que vote_average traz uma nota real. O id da resposta de uma temporada ou de um episódio é o id da temporada ou do episódio. Veja pessoas e séries de TV para os registros principais.
O amodb não oferece caminhos de imagens para coleções, produtoras e emissoras. Os registros delas já têm um poster_path, backdrop_path ou logo_path, descritos em coleções e em produtoras e emissoras.
O endpoint de configuração
GET /3/configuration retorna um bloco images com secure_base_url definido como https:/, base_url (a forma http simples) e as listas de tamanhos backdrop_sizes, logo_sizes, poster_sizes, profile_sizes e still_sizes. Leia-o uma vez na inicialização, use a forma segura e monte as URLs a partir dele em vez de fixar os tamanhos no código. A borda o guarda em cache por 24 horas.
Erros
| HTTP | status_code | Quando |
|---|---|---|
| 401 | 7 | A chave está ausente ou incorreta em uma chamada JSON. |
| 402 | 36 | O período do plano terminou. |
| 404 | 34 | Nenhuma pessoa, temporada ou episódio com esse id, ou um tamanho ou arquivo desconhecido no host de imagens. |
| 405 | 37 | Você usou um método de escrita em um caminho de imagens. |
| 429 | 25 | Você passou do seu limite de requisições por minuto. Espere os segundos indicados em Retry-After. |
Um id de filme ou série que não existe não é um erro aqui: o caminho de imagens responde 200 com arrays vazios, enquanto o caminho de detalhes responde 404. Veja erros para a lista completa. As requisições de arquivos de imagem são cargas HTTP simples, então confira o código de status da resposta em vez de interpretar um corpo JSON.
Notas práticas
- Guarde o
file_pathno seu banco de dados e monte a URL na hora de renderizar. Assim, um novo tamanho ou host custa uma só mudança de código. - Passe
include_image_languagecom o seu idioma de exibição maisnull, por exemploru,null, para que pôsteres com texto em outros idiomas não apareçam. - Um array vazio é um 200 normal. Use como alternativa o
poster_pathdo registro de detalhes do filme. - Use
w1280para backdrops de destaque em largura total ew780para cards.originalé o arquivo armazenado em resolução máxima e é bem maior quew780. - As cópias na borda duram 30 dias e são compartilhadas, então um arquivo que um cliente pediu é servido do cache para o próximo.