API obrazów i host obrazów
Endpointy obrazów wypisują plakaty, tła, loga, profile i kadry tytułu jako ścieżki plików. Każdy plik ładujesz potem z img.amodb.dev w stałym rozmiarze, bez klucza i z cache na edge przez 30 dni. Ścieżki i JSON odpowiadają TMDB v3, więc istniejący kod do obrazów działa po zmianie bazowego URL.
Pobieranie obrazów filmu
GET / wypisuje wszystkie znane obrazy jednego filmu jako trzy tablice: backdrops, logos i posters. Każda pozycja ma file_path, rozmiar w pikselach i tag języka. Samego pliku w JSON nie ma. Ładujesz go z hosta obrazów w drugim kroku.
Przykład prosi o obrazy angielskie i bez tekstu, wybiera pierwszy angielski plakat, a potem pobiera ten plik o szerokości 500 pikseli.
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)
}Parametry
movie_idpathwymaganyNumeryczne ID filmu, na przykład550.api_keyqueryjeden z dwóchTwój klucz. Użyj go albo nagłówkaAuthorization: Bearer.include_image_languagequeryKody ISO 639-1 oddzielone przecinkami. Dodajnull, aby uwzględnić obrazy bez tekstu, na przykładen,null. Wracają tylko wymienione języki. Bez niego dostajesz każdy język.languagequeryPrzyjmowany, ale ignorowany w tym endpoincie. Do wyboru języków użyjinclude_image_language.
Pola odpowiedzi
| Pole | Typ | Uwagi |
|---|---|---|
id | integer | ID filmu. |
backdrops, logos, posters | array | Jedna tablica na rodzaj obrazu, w tej kolejności kluczy. Każda może być pusta. |
file_path | string | Zaczyna się od ukośnika. Dołącz go do rozmiaru na hoście obrazów. Plakaty i tła to .jpg, loga to .png lub .svg. |
width, height | integer | Rozmiar oryginalnego pliku w pikselach. 0, gdy rozmiar nie jest znany. |
aspect_ratio | number | Szerokość podzielona przez wysokość. Plakaty mają około 0.667, tła około 1.778. 0, gdy rozmiar nie jest znany. |
iso_639_1 | string lub null | Język tekstu na obrazie. null oznacza brak tekstu. |
vote_average, vote_count | number, integer | Zawsze 0 dla obrazów filmów i seriali, więc nie da się nimi porządkować obrazów. Zachowaj kolejność zwracaną przez API. |
Przykładowa odpowiedź
Pokazano po dwie pozycje w każdej tablicy.
{
"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
}
]
}Drugi plakat pokazuje pozycję, której rozmiar nie jest znany. Plik mimo to się ładuje.
Budowanie URL obrazu
Połącz trzy części: https:/, segment rozmiaru i file_path. Ścieżka już zaczyna się od ukośnika, więc https:/ plus / to kompletny URL.
Rozmiar to w plus szerokość w pikselach, h plus wysokość w pikselach albo original dla zapisanego pliku. Host obsługuje dziesięć rozmiarów: w92, w154, w185, w300, w342, w500, w780, w1280, h632 i original. Każdy inny rozmiar, na przykład w400, odpowiada 404. /3/configuration wymienia rozmiary pasujące do każdego rodzaju obrazu.
| Rodzaj | Pole konfiguracji | Rozmiary |
|---|---|---|
| Plakat | poster_sizes | w92, w154, w185, w342, w500, w780, original |
| Tło | backdrop_sizes | w300, w780, w1280, original |
| Logo | logo_sizes | w92, w154, w185, w300, w500, original |
| Profil | profile_sizes | w185, h632, original |
| Kadr | still_sizes | w92, w185, w300, original |
Host nie sprawdza rodzaju, więc plakat ładuje się też w w1280. Trzymaj się rozmiarów wymienionych dla danego rodzaju, aby twój kod zgadzał się z konfiguracją i każdym klientem TMDB.
Host obrazów nie wymaga klucza, a edge trzyma każdy plik przez 30 dni. Ponieważ klucz nie jest wysyłany, ładowanie obrazów nie zużywa twoich żądań na minutę. Odpowiedzi niosą Access-Control-Allow-Origin: *, więc przeglądarka może je ładować z dowolnej strony. Nieznany rozmiar lub nieznany plik odpowiada 404 z treścią JSON.
Responsywne obrazy ze srcset
Wybierz najmniejszy rozmiar, który nadal pokrywa wyświetlaną szerokość razy gęstość ekranu. Plakat wyświetlany na szerokość 171 pikseli CSS potrzebuje w342 na ekranie 2x. Ta funkcja pomocnicza buduje srcset z zapisanej ścieżki.
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">`);Inne endpointy obrazów
Wszystkie poniższe ścieżki używają bazy https:/ i zwracają tablice wymienione w drugiej kolumnie.
| Metoda i ścieżka | Zwracane tablice | Parametry |
|---|---|---|
GET / | backdrops, logos, posters | include_image_language |
GET / | posters, zawsze pusta | brak |
GET / | stills, jedna pozycja z width i height ustawionymi na 0 | brak |
GET / | profiles | brak |
W filmach i serialach możesz też dodać append_ do wywołania szczegółów. include_image_language działa tam również. Dołączony blok nie ma własnego id.
Profile osób to jedyne miejsce, w którym vote_average niesie prawdziwą ocenę. id w odpowiedzi sezonu lub odcinka to ID sezonu lub odcinka. Rekordy nadrzędne opisują strony osoby i seriale.
amodb nie udostępnia ścieżek images dla kolekcji, firm i sieci. Ich rekordy zawierają już jedno poster_path, backdrop_path lub logo_path, opisane na stronach kolekcje i firmy i sieci telewizyjne.
Endpoint konfiguracji
GET /3/configuration zwraca blok images z secure_base_url ustawionym na https:/, base_url (zwykła forma http) oraz listami rozmiarów backdrop_sizes, logo_sizes, poster_sizes, profile_sizes i still_sizes. Odczytaj go raz przy starcie, użyj formy bezpiecznej i buduj z niego URL-e zamiast wpisywać rozmiary na stałe. Edge trzyma go w cache przez 24 godziny.
Błędy
| HTTP | status_code | Kiedy |
|---|---|---|
| 401 | 7 | Brakuje klucza lub jest błędny w wywołaniu JSON. |
| 402 | 36 | Okres planu dobiegł końca. |
| 404 | 34 | Brak osoby, sezonu lub odcinka o tym ID albo nieznany rozmiar lub plik na hoście obrazów. |
| 405 | 37 | Użyto metody zapisu na ścieżce images. |
| 429 | 25 | Przekroczono limit żądań na minutę. Poczekaj tyle sekund, ile podaje Retry-After. |
Nieistniejące ID filmu lub serialu nie jest tu błędem: ścieżka images odpowiada 200 z pustymi tablicami, podczas gdy ścieżka szczegółów odpowiada 404. Pełną listę zobacz w błędy. Żądania plików obrazów to zwykłe ładowanie HTTP, więc sprawdzaj kod statusu odpowiedzi zamiast parsować treść JSON.
Praktyczne uwagi
- Zapisuj
file_pathw bazie danych i buduj URL przy renderowaniu. Nowy rozmiar lub host kosztuje wtedy jedną zmianę kodu. - Przekaż
include_image_languagez językiem wyświetlania plusnull, na przykładru,null, by nie pojawiały się plakaty z obcym tekstem. - Pusta tablica to zwykłe 200. Użyj zapasowego
poster_pathz rekordu szczegółów filmu. - Użyj
w1280dla teł hero na całą szerokość iw780dla kart.originalto zapisany plik w pełnej rozdzielczości i jest dużo większy niżw780. - Kopie na edge żyją 30 dni i są współdzielone, więc plik zażądany przez jednego klienta jest serwowany z cache następnemu.