Постеры фильмов с хоста изображений без ключа

URL постера выглядит так: https://img.amodb.dev/t/p/{size}/{file}. Файловая часть: строка poster_path из ответа любого фильма, поиска или списка, и она начинается со слеша. Часть с размером это название размера, например w342. Изображениям ключ не нужен, поэтому браузеры и приложения могут грузить их напрямую. JSON, который сообщает имя файла, по-прежнему требует ключ, а amodb является независимым API, использующим протокол TMDB v3, поэтому существующий код для изображений продолжает работать после смены хоста.

Что вы получаете:

  • Постеры, фоны (backdrop), логотипы, фото профилей и кадры серий на одном хосте.
  • Десять названий размеров, от w92 до original.
  • Списки постеров по каждому тайтлу, с языком, шириной и высотой у каждого элемента.
  • Edge-кэш изображений на 30 дней.

Какие данные вы получаете

ИзображениеОткуда берется имя файлаТипичные размеры
Постер фильмаposter_path в /3/movie/{movie_id} и в спискахw92, w154, w185, w342, w500, w780, original
Фон (backdrop)backdrop_pathw300, w780, w1280, original
Фото человекаprofile_path в /3/person/{person_id}w185, h632, original
Логотип компании или телесетиlogo_pathw92, w154, w185, w300, w500, original
Кадр серииstill_pathw92, w185, w300, original
Все постеры одного тайтлаGET /3/movie/{movie_id}/imagesМассив posters

poster_path есть и у сериалов, сезонов и коллекций. Точные списки размеров один раз при запуске читайте из блока images в GET /3/configuration, а не зашивайте в код. Справочник по изображениям находится на странице API изображений.

Начало работы в 3 шага

  1. Выберите тариф на странице цены. Он задает лимит вызовов JSON: 20, 40 или 120 запросов в минуту.
  2. Создайте ключ в личном кабинете.
  3. Прочитайте poster_path из вызова данных или списка, затем подставьте его после хоста изображений и названия размера.

Пример запроса

Программа на Go перечисляет постеры The Matrix (id фильма 603) на английском и без текста, выбирает самый широкий, выводит готовый srcset и сохраняет файл w342. Ключ передается только в вызове JSON.

bashgo
# the JSON call needs the key
curl -s "https://api.amodb.dev/3/movie/603/images?include_image_language=en,null" \
  -H "Authorization: Bearer $AMODB_KEY"

# the image call does not
curl -s -o poster.jpg "https://img.amodb.dev/t/p/w342/aOIuZAjPaRIE6CMzbazvcHuHXDc.jpg"
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

const imgBase = "https://img.amodb.dev/t/p/"

type poster struct {
	FilePath string  `json:"file_path"`
	Lang     *string `json:"iso_639_1"`
	Width    int     `json:"width"`
}

type images struct {
	Posters []poster `json:"posters"`
}

func srcset(file string) string {
	var parts []string
	for _, w := range []int{185, 342, 500, 780} {
		parts = append(parts, fmt.Sprintf("%sw%d%s %dw", imgBase, w, file, w))
	}
	return strings.Join(parts, ", ")
}

func main() {
	client := &http.Client{Timeout: 10 * time.Second}

	url := "https://api.amodb.dev/3/movie/603/images?include_image_language=en,null"
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic(res.Status)
	}

	var imgs images
	if err := json.NewDecoder(res.Body).Decode(&imgs); err != nil {
		panic(err)
	}
	if len(imgs.Posters) == 0 {
		fmt.Println("no posters")
		return
	}

	best := imgs.Posters[0]
	for _, p := range imgs.Posters {
		if p.Width > best.Width {
			best = p
		}
	}
	lang := "none"
	if best.Lang != nil {
		lang = *best.Lang
	}
	fmt.Println("best poster:", best.FilePath, "language:", lang, "width:", best.Width)
	fmt.Println("srcset:", srcset(best.FilePath))

	// Image requests carry no key.
	pic, err := client.Get(imgBase + "w342" + best.FilePath)
	if err != nil {
		panic(err)
	}
	defer pic.Body.Close()
	if pic.StatusCode != http.StatusOK {
		panic(pic.Status)
	}
	out, err := os.Create("poster.jpg")
	if err != nil {
		panic(err)
	}
	defer out.Close()
	io.Copy(out, pic.Body)
}

Сокращенный ответ images для include_image_language=en,null: 3 из 145 постеров, английский, самый широкий английский и без текста. В ответе есть также backdrops и logos, здесь они опущены.

JSON
{
  "id": 603,
  "posters": [
    {
      "aspect_ratio": 0.667,
      "height": 2250,
      "iso_639_1": "en",
      "file_path": "/dXNAPwY7VrqMAo51EKhhCJfaGb5.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1500
    },
    {
      "aspect_ratio": 0.667,
      "height": 3000,
      "iso_639_1": "en",
      "file_path": "/aOIuZAjPaRIE6CMzbazvcHuHXDc.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2000
    },
    {
      "aspect_ratio": 0.701,
      "height": 1426,
      "iso_639_1": null,
      "file_path": "/iLWzJxatuwwMT76dtMuwh3FEp2X.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1000
    }
  ]
}

Выбор размера

Число в размере w задает ширину изображения в пикселях, а h632 задает высоту. Малые размеры экономят трафик, большие сохраняют детали на экранах с высокой плотностью.

РазмерТипичное применение
w92Подсказки поиска и мелкие строки списков
w154, w185Плотные списки и карточки
w342Плитки сетки на телефонах
w500Страница с подробностями
w780Большие экраны и дисплеи 2x
originalАрхив или печать, файл без масштабирования

Дайте браузеру несколько ширин и позвольте ему выбрать. Программа на Go выше выводит srcset с вариантами 185w, 342w, 500w и 780w. Сочетайте его с атрибутом sizes, подходящим вашей верстке, например sizes="(max-width: 600px) 45vw, 185px" на элементе img.

Языки постеров

У каждого элемента posters есть значение iso_639_1: код языка или null для изображений без текста. Параметр include_image_language принимает список кодов через запятую.

ЗначениеЧто возвращает
enПостеры с пометкой английский
en,nullАнглийские постеры и постеры без текста
nullТолько постеры без текста

Хороший порядок запасных вариантов: постер на языке пользователя, затем без текста, затем английский. Внутри каждой группы сортируйте по width и при равенстве оставляйте первый. vote_average и vote_count равны 0 у изображений фильмов и сериалов, поэтому ничего не ранжируют. Языки постеров описывают текст, напечатанный на изображении, поэтому не совпадают с 14 языками интерфейса. Проверяйте iso_639_1 в полученном ответе, потому что набор зависит от тайтла.

Хранение и кэширование постеров

  • Сохраняйте poster_path, а не полный URL. Из него позже можно собрать любой размер.
  • Edge-кэш хранит изображения 30 дней. Данные хранятся в кэше 6 часов, поэтому после этого срока снова читайте poster_path, чтобы узнать, изменился ли он.
  • Держите ключ на своем сервере. Браузеру отправляйте только URL изображений.
  • Если poster_path равен null, показывайте заглушку вместо сломанного изображения.

Сравнение

ВозможностьПарсинг страниц ради изображенийСвои копии на своем хостингеХост изображений amodb
Нужен ли ключНет, действуют условия каждого сайтаНетДля изображений ключ не нужен
Варианты размеровЛюбой размер, который отдает страницаВы создаете и храните каждый самиФиксированные названия размеров в URL, от w92 до original
Поиск файлаРазбор HTMLВаша собственная базаposter_path в каждом ответе
Языки изображенийСтраница за страницейЧто вы собралиinclude_image_language на эндпоинтах изображений
Хранилище и трафикВаши, плюс источникаВашиБраузер загружает с img.amodb.dev
КэшВашВаш30 дней в edge-кэше

Цены

Загрузка изображений идет без ключа. Тариф ограничивает только вызовы JSON, которые дают имена файлов, а ответы со списками уже включают poster_path для каждого элемента, поэтому один вызов списка наполняет всю сетку. Выберите 20, 40 или 120 запросов в минуту на странице цены. Доступ оплачивается заранее на 1, 3, 6, 12 или 24 месяца со скидкой 0, 10, 20, 30 и 40 процентов, сам он не продлевается, бесплатного тарифа нет.