API delle immagini e host delle immagini

Gli endpoint delle immagini elencano locandine, sfondi, loghi, profili e fermi immagine di un titolo come percorsi di file. Poi carichi ogni file da img.amodb.dev in una dimensione fissa, senza chiave e con una cache edge di 30 giorni. Percorsi e JSON seguono TMDB v3, quindi il codice per le immagini esistente funziona dopo un cambio di URL di base.

Aggiornato il Vedi in Markdown

Ottenere le immagini di un film

GET /3/movie/{movie_id}/images elenca tutte le immagini note di un film come tre array: backdrops, logos e posters. Ogni voce ha un file_path, la sua dimensione in pixel e un tag di lingua. Il file stesso non è nel JSON. Lo carichi dall'host delle immagini in un secondo passaggio.

L'esempio chiede le immagini in inglese e senza testo, sceglie la prima locandina inglese e poi scarica quel file con 500 pixel di larghezza.

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)
}

Parametri

  • movie_idpercorsoobbligatorio
    ID numerico del film, per esempio 550.
  • api_keyqueryuno dei due
    La tua chiave. Usa questa o l'header Authorization: Bearer.
  • include_image_languagequery
    Codici ISO 639-1 separati da virgole. Aggiungi null per includere le immagini senza testo, per esempio en,null. Tornano solo le lingue elencate. Senza, ottieni ogni lingua.
  • languagequery
    Accettato ma ignorato su questo endpoint. Usa include_image_language per scegliere le lingue.

Campi della risposta

CampoTipoNote
idinteroL'ID del film.
backdrops, logos, postersarrayUn array per tipo di immagine, in quest'ordine di chiavi. Ognuno può essere vuoto.
file_pathstringaInizia con una barra. Da accodare a una dimensione sull'host delle immagini. Locandine e sfondi sono .jpg, i loghi sono .png o .svg.
width, heightinteroDimensione in pixel del file originale. 0 quando la dimensione non è nota.
aspect_rationumeroLarghezza divisa per altezza. Le locandine stanno vicino a 0.667, gli sfondi vicino a 1.778. 0 quando la dimensione non è nota.
iso_639_1stringa o nullLingua del testo sull'immagine. null significa nessun testo.
vote_average, vote_countnumero, interoSempre 0 per le immagini di film e serie, quindi non possono ordinare le immagini. Mantieni l'ordine restituito dall'API.

Risposta di esempio

Sono mostrate due voci per array.

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
    }
  ]
}

La seconda locandina mostra una voce la cui dimensione non è nota. Il file si carica comunque.

Costruire l'URL di un'immagine

Unisci tre parti: https://img.amodb.dev/t/p/, un segmento di dimensione e il file_path. Il percorso inizia già con una barra, quindi https://img.amodb.dev/t/p/w500 più /jSziioSwPVrOy9Yow3XhWIBDjq1.jpg è un URL completo.

Una dimensione è w più una larghezza in pixel, h più un'altezza in pixel, oppure original per il file salvato. L'host serve dieci dimensioni: w92, w154, w185, w300, w342, w500, w780, w1280, h632 e original. Qualsiasi altra dimensione, come w400, risponde 404. /3/configuration elenca le dimensioni adatte a ogni tipo di immagine.

TipoCampo di configurazioneDimensioni
Locandinaposter_sizesw92, w154, w185, w342, w500, w780, original
Sfondobackdrop_sizesw300, w780, w1280, original
Logologo_sizesw92, w154, w185, w300, w500, original
Profiloprofile_sizesw185, h632, original
Fermo immaginestill_sizesw92, w185, w300, original

L'host non controlla il tipo, quindi una locandina si carica anche a w1280. Resta sulle dimensioni elencate per il tipo, così il tuo codice corrisponde alla configurazione e a qualsiasi client TMDB.

L'host delle immagini non richiede chiave, e l'edge tiene ogni file per 30 giorni. Poiché non si invia alcuna chiave, i caricamenti delle immagini non usano le tue richieste al minuto. Le risposte portano Access-Control-Allow-Origin: *, quindi un browser può caricarle da qualsiasi pagina. Una dimensione sconosciuta o un file sconosciuto risponde 404 con un corpo JSON.

Immagini responsive con srcset

Scegli la dimensione più piccola che copra ancora la larghezza mostrata moltiplicata per la densità dello schermo. Una locandina mostrata a 171 pixel CSS di larghezza richiede w342 su uno schermo 2x. Questa funzione di aiuto costruisce un srcset da un percorso salvato.

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

Altri endpoint delle immagini

Tutti i percorsi qui sotto usano la base https://api.amodb.dev/3 e restituiscono gli array indicati nella seconda colonna.

Metodo e percorsoArray restituitiParametri
GET /tv/{series_id}/imagesbackdrops, logos, postersinclude_image_language
GET /tv/{series_id}/season/{season_number}/imagesposters, sempre vuotonessuno
GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/imagesstills, una voce con width e height a 0nessuno
GET /person/{person_id}/imagesprofilesnessuno

Per film e serie puoi anche aggiungere append_to_response=images a una chiamata di dettagli. Anche lì funziona include_image_language. Il blocco aggiunto non ha un id proprio.

I profili delle persone sono l'unico posto in cui vote_average porta un punteggio reale. L'id di una risposta di stagione o di episodio è l'ID della stagione o dell'episodio. Vedi persone e serie TV per le schede padre.

amodb non offre percorsi di immagini per collezioni, società ed emittenti. Le loro schede contengono già un poster_path, un backdrop_path o un logo_path, descritti nelle pagine collezioni e società ed emittenti.

L'endpoint di configurazione

GET /3/configuration restituisce un blocco images con secure_base_url impostato su https://img.amodb.dev/t/p/, base_url (la forma http semplice), e gli elenchi di dimensioni backdrop_sizes, logo_sizes, poster_sizes, profile_sizes e still_sizes. Leggilo una volta all'avvio, usa la forma sicura e costruisci gli URL da esso invece di scrivere le dimensioni nel codice. L'edge lo tiene in cache per 24 ore.

Errori

HTTPstatus_codeQuando
4017La chiave manca o è sbagliata su una chiamata JSON.
40236Il periodo del piano è terminato.
40434Nessuna persona, stagione o episodio con quell'ID, o una dimensione o un file sconosciuto sull'host delle immagini.
40537Hai usato un metodo di scrittura su un percorso di immagini.
42925Hai superato le richieste al minuto. Attendi i secondi di Retry-After.

Un ID di film o serie che non esiste qui non è un errore: il percorso delle immagini risponde 200 con array vuoti, mentre il percorso dei dettagli risponde 404. Vedi errori per l'elenco completo. Le richieste dei file immagine sono semplici caricamenti HTTP, quindi controlla il codice di stato della risposta invece di analizzare un corpo JSON.

Note pratiche

  • Salva file_path nel tuo database e costruisci l'URL al momento della visualizzazione. Una nuova dimensione o un nuovo host costa così una sola modifica al codice.
  • Passa include_image_language con la tua lingua di visualizzazione più null, per esempio ru,null, così non compaiono locandine con testo straniero.
  • Un array vuoto è un normale 200. Ripiega sul poster_path della scheda dei dettagli del film.
  • Usa w1280 per gli sfondi a tutta larghezza e w780 per le schede. original è il file salvato a piena risoluzione ed è molto più pesante di w780.
  • Le copie sull'edge durano 30 giorni e sono condivise, quindi un file richiesto da un client viene servito dalla cache al successivo.