API відео та трейлерів

Ендпоінти відео перелічують трейлери, тизери, кліпи й фічерети, прив'язані до фільму чи серіалу. Кожен запис дає назву хостингу, ключ відео, тип, прапорець офіційності, розмір і дату публікації. Шляхи сезонів і серій існують, але відео не повертають. Фільтруйте за мовою й типом у власному коді.

Оновлено Відкрити в Markdown

Отримання відео фільму

GET /3/movie/{movie_id}/videos повертає записи відео, прив'язані до одного фільму. Запис це лише метадані: назва, хостинг, що віддає відео, ключ відео на ньому, тип і кілька прапорців. amodb не повертає відеофайли.

Приклад виводить перший офіційний англійський трейлер, а за його відсутності будь-який англійський.

bashjspyphpgo
curl -s "https://api.amodb.dev/3/movie/550/videos" \
  -H "Authorization: Bearer $AMODB_KEY"
const url = 'https://api.amodb.dev/3/movie/550/videos';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { results } = await res.json();
const trailers = results.filter((v) => v.type === 'Trailer' && v.iso_639_1 === 'en');
const pick = trailers.find((v) => v.official) ?? trailers[0];
console.log(pick ? `${pick.name} (${pick.site}, key ${pick.key})` : 'no trailer');
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/550/videos",
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
trailers = [v for v in r.json()["results"] if v["type"] == "Trailer" and v["iso_639_1"] == "en"]
official = [v for v in trailers if v["official"]]
pick = (official or trailers or [None])[0]
print(f"{pick['name']} ({pick['site']}, key {pick['key']})" if pick else "no trailer")
<?php
$url = 'https://api.amodb.dev/3/movie/550/videos';
$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");
}
$trailers = array_values(array_filter(
    json_decode($body, true)['results'],
    fn($v) => $v['type'] === 'Trailer' && $v['iso_639_1'] === 'en'
));
$official = array_values(array_filter($trailers, fn($v) => $v['official']));
$pick = $official[0] ?? $trailers[0] ?? null;
echo $pick ? "{$pick['name']} ({$pick['site']}, key {$pick['key']})" : 'no trailer', PHP_EOL;
package main

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

type Videos struct {
	Results []struct {
		Name     string `json:"name"`
		Key      string `json:"key"`
		Site     string `json:"site"`
		Type     string `json:"type"`
		Language string `json:"iso_639_1"`
		Official bool   `json:"official"`
	} `json:"results"`
}

func main() {
	url := "https://api.amodb.dev/3/movie/550/videos"
	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 v Videos
	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
		panic(err)
	}
	for _, r := range v.Results {
		if r.Type == "Trailer" && r.Language == "en" && r.Official {
			fmt.Printf("%s (%s, key %s)\n", r.Name, r.Site, r.Key)
			return
		}
	}
	fmt.Println("no official trailer")
}

Параметри

  • movie_idшляхобов'язковий
    Числовий id фільму, наприклад 550.
  • api_keyqueryодин із двох
    Ваш ключ. Використовуйте його або заголовок Authorization: Bearer.
  • language, include_video_languagequery
    Приймаються, але ігноруються. Відповідь завжди містить усі відео назви. Фільтруйте за iso_639_1 у своєму коді.

Поля відповіді

ПолеТипПримітки
idціле числоID фільму.
resultsмасивЗаписи відео, не відсортовані за типом чи датою. Порожній, коли відео невідомі.
results[].iso_639_1, results[].iso_3166_1рядокМова й країна відео, наприклад en і US.
results[].nameрядокНазва відео, наприклад #TBT Trailer.
results[].keyрядокID відео на цьому хостингу.
results[].siteрядокНазва відеохостингу. Наразі завжди YouTube.
results[].sizeціле числоВертикальна роздільна здатність. Наразі завжди 1080.
results[].typeрядокTrailer, Teaser, Clip, Featurette, Behind the Scenes, Bloopers, Opening Credits або Recap.
results[].officialбулеве значенняTrue, коли відео опублікувала студія або правовласник.
results[].published_atрядокЧасова мітка ISO 8601 з мілісекундами або без них.
results[].idрядокID запису відео. Дорівнює key.

Приклад відповіді

Показано три з 19 записів фільму 550.

JSON
{
  "id": 550,
  "results": [
    {
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "name": "Theatrical Trailer (HD Fan Remaster)",
      "key": "6JnN1DmbqoU",
      "site": "YouTube",
      "size": 1080,
      "type": "Trailer",
      "official": false,
      "published_at": "2015-02-26T03:19:25Z",
      "id": "6JnN1DmbqoU"
    },
    {
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "name": "#TBT Trailer",
      "key": "BdJKm16Co6M",
      "site": "YouTube",
      "size": 1080,
      "type": "Trailer",
      "official": true,
      "published_at": "2014-10-02T19:20:22Z",
      "id": "BdJKm16Co6M"
    },
    {
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "name": "Mark Kermode introduces Fight Club | Film4 Interview",
      "key": "tiWCNtGDGEY",
      "site": "YouTube",
      "size": 1080,
      "type": "Featurette",
      "official": true,
      "published_at": "2015-05-08T15:59:05Z",
      "id": "tiWCNtGDGEY"
    }
  ]
}

Типи відео

Поле type вказує, що це за відео. Порівнюйте його точно, з великими літерами, як показано.

ТипДля чого використовувати
TrailerГоловний промо-ролик. Показуйте його на сторінці деталей.
TeaserКороткий анонс, що виходить перед трейлером.
ClipСцена з готового фільму чи серії.
FeaturetteКороткий матеріал про те, як створювали назву.
Behind the ScenesКадри зі знімального майданчика та інтерв'ю.
BloopersНевдалі дублі та добірки смішних моментів.
Opening CreditsЗаставка серіалу.
RecapПідсумок попередніх серій.

З часом можуть з'явитися інші значення, тож сприймайте невідомий type як загальний додатковий матеріал і не допускайте збою через нього.

Вибір потрібного відео

Використовуйте однаковий порядок для кожної назви. Перебирайте ваші мови по черзі. У межах однієї мови спершу йдуть офіційні трейлери, потім будь-який трейлер, потім тизери, потім кліпи. У межах групи сортуйте за published_at: за зростанням дає перший трейлер, за спаданням найновіший.

JavaScript
function pickVideo(results, langs = ['en']) {
  const order = ['Trailer', 'Teaser', 'Clip'];
  for (const lang of langs) {
    for (const type of order) {
      const group = results
        .filter((v) => v.iso_639_1 === lang && v.type === type)
        .sort((a, b) => Number(b.official) - Number(a.official) || Date.parse(a.published_at) - Date.parse(b.published_at));
      if (group.length > 0) return group[0];
    }
  }
  return null;
}

// Russian first, English as the fallback.
// const video = pickVideo(results, ['ru', 'en']);

Мови

language та include_video_language не змінюють відповідь, тож один виклик дає всі відео назви. Кожен запис містить iso_639_1 та iso_3166_1. Фільм 550 має відео з тегами fr, en, es, pt, it, cs, pl і ru. Фільтруйте за iso_639_1 у своєму коді, як показано вище, а потім покажіть користувачеві, якою мовою він зараз почує відео. У назви може не бути відео потрібною мовою, тому залиште запасний варіант: англійську або будь-яку мову. 14 обслуговуваних мов перелічено в розділі мови.

Інші ендпоінти відео

Шляхи нижче повертають ту саму структуру з id та results.

Метод і шляхПовертає
GET /tv/{series_id}/videosВідео серіалу.
GET /tv/{series_id}/season/{season_number}/videosЗавжди порожній масив results.
GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/videosЗавжди порожній масив results.

Також можна додати append_to_response=videos до виклику деталей фільму чи серіалу. Доданий блок містить results і не має id. Сторінки серіалів і сезонів описано в розділах серіали та сезони та серії.

Помилки

HTTPstatus_codeКоли
4017Ключ відсутній або хибний.
40236Термін дії тарифу закінчився.
40434Немає сезону чи серії з таким id або id не є числом.
40537Ви використали метод запису на шляху відео.
42925Ви перевищили ліміт запитів на хвилину. Зачекайте стільки секунд, скільки вказано в Retry-After.

Неіснуючий id фільму чи серіалу тут не помилка: шлях відео відповідає 200 із "results": [], так само як для відомої назви без відео. Шлях деталей відповідає 404 для невідомого id. Докладніше про помилки та ліміти запитів.

Практичні нотатки

  • Зберігайте обрані site і key разом із назвою, а не повну адресу, щоб пізніше можна було змінити плеєр.
  • Списки відео підпорядковуються кешу деталей: 6 годин на edge. Клієнтський кеш на кілька годин цьому відповідає.
  • size сьогодні дорівнює 1080 для кожного запису, тому за ним не можна визначити, який ролик легший. Дозвольте плеєру обирати якість.
  • Не покладайтеся на те, що трейлер існує. Ховайте кнопку відтворення, коли ваша функція вибору повертає null.
  • Порядок results не несе змісту. Сортуйте у своєму коді.
  • Файли постерів і фонів (backdrop) дивіться в розділі API зображень. Огляд сценарію використання дивіться в API трейлерів фільмів.