API obrázků a hostitel obrázků

Endpointy obrázků vypisují plakáty, pozadí, loga, profily a záběry titulu jako cesty k souborům. Každý soubor pak načtete z img.amodb.dev v pevné velikosti, bez klíče a s cache na edge na 30 dní. Cesty a JSON odpovídají TMDB v3, takže stávající kód pro obrázky funguje po změně základní URL.

Aktualizováno Zobrazit jako Markdown

Získání obrázků filmu

GET /3/movie/{movie_id}/images vypíše všechny známé obrázky jednoho filmu jako tři pole: backdrops, logos a posters. Každá položka má file_path, rozměry v pixelech a jazykový tag. Samotný soubor v JSON není. Načtete jej z hostitele obrázků druhým krokem.

Příklad si vyžádá anglické obrázky a obrázky bez textu, vybere první anglický plakát a pak načte tento soubor o šířce 500 pixelů.

bashjspyphpgo
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_idpathpovinný
    Číselné ID filmu, například 550.
  • api_keyqueryjeden ze dvou
    Váš klíč. Použijte jej, nebo hlavičku Authorization: Bearer.
  • include_image_languagequery
    Kódy ISO 639-1 oddělené čárkou. Přidejte null, aby se zahrnuly obrázky bez textu, například en,null. Vrátí se jen uvedené jazyky. Bez něj dostanete všechny jazyky.
  • languagequery
    Na tomto endpointu se přijímá, ale ignoruje. Jazyky vybírejte přes include_image_language.

Pole odpovědi

PoleTypPoznámky
idintegerID filmu.
backdrops, logos, postersarrayJedno pole na druh obrázku, v tomto pořadí klíčů. Každé může být prázdné.
file_pathstringZačíná lomítkem. Připojte jej k velikosti na hostiteli obrázků. Plakáty a pozadí jsou .jpg, loga .png nebo .svg.
width, heightintegerRozměr původního souboru v pixelech. 0, když rozměr není znám.
aspect_rationumberŠířka dělená výškou. Plakáty jsou kolem 0.667, pozadí kolem 1.778. 0, když rozměr není znám.
iso_639_1string nebo nullJazyk textu na obrázku. null znamená bez textu.
vote_average, vote_countnumber, integerU obrázků filmů a seriálů vždy 0, takže jimi nelze obrázky řadit. Ponechte pořadí, které API vrací.

Příklad odpovědi

Zobrazeny jsou dvě položky v každém poli.

JSON
{
  "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
    }
  ]
}

Druhý plakát ukazuje položku, jejíž rozměr není znám. Soubor se přesto načte.

Sestavení URL obrázku

Spojte tři části: https://img.amodb.dev/t/p/, segment velikosti a file_path. Cesta už začíná lomítkem, takže https://img.amodb.dev/t/p/w500 plus /jSziioSwPVrOy9Yow3XhWIBDjq1.jpg je úplná URL.

Velikost je w plus šířka v pixelech, h plus výška v pixelech, nebo original pro uložený soubor. Hostitel obsluhuje deset velikostí: w92, w154, w185, w300, w342, w500, w780, w1280, h632 a original. Jakákoli jiná velikost, například w400, odpoví 404. /3/configuration uvádí velikosti, které se hodí pro každý druh obrázku.

DruhPole konfiguraceVelikosti
Plakátposter_sizesw92, w154, w185, w342, w500, w780, original
Pozadíbackdrop_sizesw300, w780, w1280, original
Logologo_sizesw92, w154, w185, w300, w500, original
Profilprofile_sizesw185, h632, original
Záběrstill_sizesw92, w185, w300, original

Hostitel druh nekontroluje, takže se plakát načte i ve velikosti w1280. Držte se velikostí uvedených pro daný druh, aby váš kód odpovídal konfiguraci a jakémukoli klientovi TMDB.

Hostitel obrázků klíč nepotřebuje a edge uchovává každý soubor 30 dní. Protože se neposílá klíč, načítání obrázků nespotřebovává vaše požadavky za minutu. Odpovědi nesou Access-Control-Allow-Origin: *, takže je prohlížeč může načíst z libovolné stránky. Neznámá velikost nebo neznámý soubor odpoví 404 s tělem JSON.

Responzivní obrázky se srcset

Vyberte nejmenší velikost, která stále pokryje zobrazenou šířku krát hustotu obrazovky. Plakát zobrazený o šířce 171 pixelů CSS potřebuje na obrazovce 2x w342. Tato pomocná funkce sestaví srcset z uložené cesty.

JavaScript
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">`);

Další endpointy obrázků

Všechny cesty níže používají základ https://api.amodb.dev/3 a vracejí pole uvedená ve druhém sloupci.

Metoda a cestaVrácená poleParametry
GET /tv/{series_id}/imagesbackdrops, logos, postersinclude_image_language
GET /tv/{series_id}/season/{season_number}/imagesposters, vždy prázdnéžádné
GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/imagesstills, jedna položka s width a height nastavenými na 0žádné
GET /person/{person_id}/imagesprofilesžádné

U filmů a seriálů můžete také přidat append_to_response=images k volání detailů. include_image_language funguje i tam. Přidaný blok nemá vlastní id.

Profily osob jsou jediné místo, kde vote_average nese skutečné skóre. id v odpovědi sezóny nebo epizody je ID sezóny nebo epizody. Nadřazené záznamy viz osoby a seriály.

amodb nenabízí cesty images pro kolekce, společnosti a sítě. Jejich záznamy už obsahují jedno poster_path, backdrop_path nebo logo_path, popsané na stránkách kolekce a společnosti a televizní sítě.

Endpoint konfigurace

GET /3/configuration vrací blok images s secure_base_url nastaveným na https://img.amodb.dev/t/p/, base_url (prostá forma http) a seznamy velikostí backdrop_sizes, logo_sizes, poster_sizes, profile_sizes a still_sizes. Přečtěte jej jednou při startu, použijte zabezpečenou formu a URL z něj sestavujte místo pevného zadání velikostí. Edge jej cachuje 24 hodin.

Chyby

HTTPstatus_codeKdy
4017Klíč chybí nebo je nesprávný při volání JSON.
40236Platnost tarifu skončila.
40434Osoba, sezóna nebo epizoda s tímto ID neexistuje, nebo neznámá velikost či soubor na hostiteli obrázků.
40537Použili jste metodu pro zápis na cestě images.
42925Překročili jste počet požadavků za minutu. Počkejte tolik sekund, kolik říká Retry-After.

ID filmu nebo seriálu, které neexistuje, zde není chyba: cesta images odpoví 200 s prázdnými poli, zatímco cesta detailů odpoví 404. Úplný seznam viz chyby. Požadavky na soubory obrázků jsou prosté načtení HTTP, kontrolujte proto stavový kód odpovědi místo parsování těla JSON.

Praktické poznámky

  • Ukládejte file_path do databáze a URL sestavujte při vykreslování. Nová velikost nebo hostitel pak stojí jednu změnu kódu.
  • Předejte include_image_language s jazykem zobrazení plus null, například ru,null, aby se neobjevovaly plakáty s cizím textem.
  • Prázdné pole je běžné 200. Použijte záložní poster_path ze záznamu detailu filmu.
  • Pro hero pozadí přes celou šířku použijte w1280 a pro karty w780. original je uložený soubor v plném rozlišení a je mnohem větší než w780.
  • Kopie na edge žijí 30 dní a jsou sdílené, takže soubor, který vyžádal jeden klient, se dalšímu obslouží z cache.