# API базы даных фільмаў для вашага каталога

> Выкарыстоўвайце amodb як крыніцу для ўласнай базы даных фільмаў. Фільмы, людзі, кампаніі, калекцыі, ключавыя словы і жанры маюць лікавыя id, таму радкі чыста злучаюцца. Запоўніце базу праз discover па вокнах даты выхаду, абнаўляйце радкі па ўзросце і супастаўляйце ўласныя id праз find. JSON TMDB v3, ад 20 да 120 запытаў у хвіліну.

## Пабудуйце ўласную базу даных фільмаў з API

amodb гэта незалежнае API, якое працуе па пратаколе TMDB v3. Фільмы, людзі, кампаніі, калекцыі, ключавыя словы і жанры маюць лікавыя id і спасылаюцца адно на адно, таму з яго можна запоўніць табліцы SQL і трымаць іх актуальнымі. Запаўняйце табліцы праз discover па старонках, абнаўляйце іх па ўзросце і супастаўляйце свае ідэнтыфікатары праз `find`. У amodb няма стужкі changes, таму абнаўленне гэта звычайнае паўторнае чытанне радкоў, якія вы захоўваеце.

Што вы атрымліваеце:

- Шэсць звязаных тыпаў сутнасцей са стабільнымі лікавымі id.
- Старонкі discover для першай загрузкі: да 20 вынікаў на старонку, 500 старонак на запыт.
- Вокны дат выхаду ў discover, каб дзяліць першую загрузку і атрымліваць новыя рэлізы.
- Пошук па вонкавых id для `imdb_id`, `tvdb_id`, `wikidata_id` і `kinopoisk_id`.

## Якія даныя вы атрымліваеце

Гэта мадэль даных. Кожны радок гэта адна табліца ў рэляцыйнай копіі.

| Сутнасць       | Чытаць праз                         | Ключ            | Звязана з                                                                                         |
| -------------- | ----------------------------------- | --------------- | ------------------------------------------------------------------------------------------------- |
| Фільм          | `GET /3/movie/{movie_id}`           | `id`, `imdb_id` | `genres[].id`, `production_companies[].id`, `belongs_to_collection.id`                            |
| Персона        | `GET /3/person/{person_id}`         | `id`, `imdb_id` | Фільмамі праз `/3/movie/{movie_id}/credits`                                                       |
| Кампанія       | `GET /3/company/{company_id}`       | `id`            | Фільмамі праз `with_companies` у discover. `parent_company` заўсёды `null`, а `description` пусты |
| Калекцыя       | `GET /3/collection/{collection_id}` | `id`            | `parts[]`, спіс фільмаў                                                                           |
| Ключавое слова | `GET /3/keyword/{keyword_id}`       | `id`            | Фільмамі праз `/3/keyword/{keyword_id}/movies` або `with_keywords`                                |
| Жанр           | `GET /3/genre/movie/list`           | `id`            | `genres[].id` у фільмах                                                                           |

Сувязі «многія да многіх» патрабуюць злучальных табліц: `movie_genre`, `movie_company`, `movie_keyword` і `movie_credit`. Выкарыстоўвайце `credit_id` са старонкі [удзельнікі](https://amodb.dev/be/credits/) як ключ апошняй. Спісы палёў ёсць на старонках [фільмы](https://amodb.dev/be/movies/), [персоны](https://amodb.dev/be/people/) і [калекцыі](https://amodb.dev/be/collections/).

## Пачніце за 3 крокі

1. Параўнайце тры частаты запытаў на старонцы [цэны](https://amodb.dev/be/pricing/). Большая частата скарачае першую загрузку, больш нічога не мяняецца.
2. Стварыце ключ у асабістым кабінеце і трымайце яго ў зменнай асяроддзя.
3. Выклічце `/3/discover/movie` для аднадзённага акна дат выхаду, потым атрымайце кожны id са спісу.

## Прыклад запыту

Скрыпт на PHP пералічвае фільмы, што выйшлі ўчора і сёння, праз discover і дадае або абнаўляе кожны запіс у табліцы SQLite. Ён спіць 3 секунды паміж чытаннямі дэталяў, каб заставацца ніжэй за 20 запытаў у хвіліну, паўтарае 429 пасля `Retry-After` і выдаляе радкі, чый id цяпер вяртае 404.

```bash
curl -s "https://api.amodb.dev/3/discover/movie?primary_release_date.gte=2026-10-17&primary_release_date.lte=2026-10-18&sort_by=primary_release_date.asc&page=1" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```php
<?php
const BASE = 'https://api.amodb.dev/3';

function amodb(string $path, array $query = []): ?array
{
    $url = BASE . $path . '?' . http_build_query($query);
    for ($attempt = 0; $attempt < 3; $attempt++) {
        $retryAfter = 1;
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
            CURLOPT_HEADERFUNCTION => function ($handle, $line) use (&$retryAfter) {
                if (stripos($line, 'Retry-After:') === 0) {
                    $retryAfter = max(1, (int) trim(substr($line, 12)));
                }
                return strlen($line);
            },
        ]);
        $body = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($status === 429) {
            sleep($retryAfter);
            continue;
        }
        if ($status === 404) {
            return null;
        }
        if ($status !== 200) {
            throw new RuntimeException("amodb returned $status for $path");
        }
        return json_decode($body, true);
    }
    throw new RuntimeException("Still rate limited on $path");
}

$db = new PDO('sqlite:movies.sqlite');
$db->exec('CREATE TABLE IF NOT EXISTS movie (id INTEGER PRIMARY KEY, imdb_id TEXT, title TEXT, release_date TEXT, raw TEXT)');
$save = $db->prepare('INSERT OR REPLACE INTO movie (id, imdb_id, title, release_date, raw) VALUES (?, ?, ?, ?, ?)');
$drop = $db->prepare('DELETE FROM movie WHERE id = ?');

$from = date('Y-m-d', strtotime('-1 day'));
$to = date('Y-m-d');
$page = 1;
do {
    $list = amodb('/discover/movie', [
        'primary_release_date.gte' => $from,
        'primary_release_date.lte' => $to,
        'sort_by' => 'primary_release_date.asc',
        'page' => $page,
    ]);
    foreach ($list['results'] as $row) {
        $movie = amodb('/movie/' . $row['id'], ['language' => 'en-US']);
        if ($movie === null) {
            $drop->execute([$row['id']]);
            continue;
        }
        $save->execute([$movie['id'], $movie['imdb_id'] ?? null, $movie['title'], $movie['release_date'] ?? null, json_encode($movie)]);
        sleep(3);
    }
    $page++;
} while ($page <= min($list['total_pages'], 500));
```

Discover вяртае радкі спісу, а не поўныя запісы. Гэта 2 з 20 вынікаў на старонцы 1. Астатнія палі чытайце з `/3/movie/{id}`.

```json
{
  "page": 1,
  "results": [
    {
      "adult": false,
      "backdrop_path": "/siepLRGVjM8yLKppApkD3uSh8Y0.jpg",
      "genre_ids": [
        35
      ],
      "id": 1800227,
      "original_language": "en",
      "original_title": "Sly's Pack",
      "overview": "Nesmith, Gary, & Tony are smoking weed on the roof of a parking garage, but a...",
      "popularity": 0.0071,
      "poster_path": "/3HpIWZUI7jmpKZkfZNdchS2WsvN.jpg",
      "release_date": "2026-10-17",
      "title": "Sly's Pack",
      "video": false,
      "vote_average": 0,
      "vote_count": 0
    },
    {
      "adult": false,
      "backdrop_path": null,
      "genre_ids": [
        99
      ],
      "id": 1800168,
      "original_language": "en",
      "original_title": "The Good Life",
      "overview": "The Good LIfe is based on the best-selling book by Drs. Robert Waldinger and...",
      "popularity": 0.0143,
      "poster_path": null,
      "release_date": "2026-10-17",
      "title": "The Good Life",
      "video": false,
      "vote_average": 0,
      "vote_count": 0
    }
  ],
  "total_pages": 15,
  "total_results": 299
}
```

## Запаўненне і абнаўленне табліц

| Задача              | Выклік                                                                                                        | Абмежаванні                                                                                                                                |
| ------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Першая загрузка     | `GET /3/discover/movie` з `sort_by` і акном дат                                                               | `page` ад 1 да 500, да 20 вынікаў на старонку, то бок 10 000 на запыт. Каб выйсці за гэта, дзяліце па `primary_release_date.gte` і `.lte`. |
| Новыя рэлізы        | `GET /3/discover/movie` з `primary_release_date.gte`, роўным часу апошняга запуску, і `GET /3/movie/upcoming` | Кэшуецца 30 хвілін.                                                                                                                        |
| Абнаўленне радкоў   | `GET /3/movie/{movie_id}` для радкоў старэйшых за 6 гадзін                                                    | Стужкі changes няма. Абнаўляйце назвы, якія адкрываюць карыстальнікі, а астатнія радзей.                                                   |
| Злучэнне ўласных id | `GET /3/find/{external_id}`                                                                                   | Адзін id на выклік, крыніца вызначаецца праз `external_source`.                                                                            |
| Лянівае запаўненне  | `GET /3/movie/{movie_id}`, калі карыстальнік адкрывае назву                                                   | Захоўвайце адказ з часавой пазнакай.                                                                                                       |

Акно старонак гэта галоўнае рашэнне ў праектаванні. Калі `total_pages` у адказе вышэй за 500, акно змяшчае больш за 10 000 радкоў, таму дзеліце яго напалам, пакуль не памесціцца. Для апошняга года патрэбны месяцы, а адзін дзень рэлізаў гэта некалькі соцень назваў. Захоўвайце скончаны кавалак, каб запуск, што збоіў, мог працягнуцца. Правілы супастаўлення для злучэння гл. на старонцы [пошук па вонкавым ідэнтыфікатары](https://amodb.dev/be/find-by-external-id/).

## Ацэнка аб’ёму сінхранізацыі

Кожны абноўлены радок каштуе адно чытанне дэталяў. План на 20 запытаў у хвіліну дае 1200 выклікаў у гадзіну, 40 дае 2400, а 120 дае 7200. Старонка discover пералічвае 20 id за адзін выклік. Запускайце абнаўленне ў гадзіны меншай нагрузкі, калі ваша праграма дзеліць ключ, бо ліміт дзейнічае на ключ, а не на скрыпт. Загалоўкі, што паказваюць, колькі засталося ў акне, гл. на старонцы [ліміты запытаў](https://amodb.dev/be/rate-limits/).

## Кэшаванне ў два пласты

| Пласт        | Што трымае                           | TTL                                                                       |
| ------------ | ------------------------------------ | ------------------------------------------------------------------------- |
| Edge-кэш     | Дэталі і ўдзельнікі                  | 6 гадзін                                                                  |
| Edge-кэш     | Спісы discover, трэндаў і папулярных | 30 хвілін                                                                 |
| Edge-кэш     | Пошук                                | 10 хвілін                                                                 |
| Edge-кэш     | Канфігурацыя                         | 24 гадзіны                                                                |
| Edge-кэш     | Выявы                                | 30 дзён                                                                   |
| Вашы табліцы | Радкі, якія вы захоўваеце            | Пакуль правіла ўзросту не скажа паўтарыць запыт, але не раней за 6 гадзін |

Edge-кэш агульны для ключоў, але ліміт запытаў правяраецца да яго, таму трапленне ў кэш усё роўна расходуе адзін запыт з вашай хвіліны. Паўторнае чытанне радка часцей чым раз у 6 гадзін вяртае тую ж копію і марнуе квоту. Хай правіла ўзросту вырашае, калі абнаўляць.

## Параўнанне

| Магчымасць           | Уласны скрэйпінг старонак            | Статычныя файлы набораў даных                | amodb                                            |
| -------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------------------ |
| Свежасць             | Настолькі свежа, як апошні абыход    | Настолькі свежа, як апошні апублікаваны файл | Дэталі кэшуюцца 6 гадзін, абнаўляйце па ўзросце  |
| Паэтапныя абнаўленні | Паўторны абыход і параўнанне         | Спампаваць новы файл                         | Discover з акном даты выхаду, без стужкі changes |
| Id паміж сутнасцямі  | URL старонак                         | Вызначае выдавец                             | Лікавыя id, `imdb_id` і `/3/find`                |
| Што вы запускаеце    | Краўлеры і сховішча                  | Сховішча і задача імпарту                    | Сховішча і скрыпт сінхранізацыі                  |
| Ліміт запытаў        | Вызначаюць сайты, якія вы абыходзіце | Не ўжываецца                                 | 20, 40 або 120 запытаў у хвіліну, на ключ        |
| Мовы на запіс        | Тое, што прапануе кожная старонка    | Залежыць ад файлаў                           | 14, выбіраюцца праз `language`                   |

## Цэны

Першая загрузка самая дарагая, і яна абмежавана вашымі запытамі ў хвіліну. Абярыце 20, 40 або 120 у хвіліну на старонцы [цэны](https://amodb.dev/be/pricing/). Плаціце за 1, 3, 6, 12 або 24 месяцы са зніжкай 0, 10, 20, 30 або 40 працэнтаў. Нічога не прадаўжаецца аўтаматычна, бясплатнага тарыфа няма, і кожны план чытае тыя ж даныя.

## Пытанні і адказы

### Як падтрымліваць лакальную копію свежай?

У amodb няма стужкі changes, таму абнаўляйце па ўзросце. Дэталі кэшуюцца на edge на 6 гадзін, таму паўторна чытайце радок не раней. Новыя рэлізы бярыце праз discover з primary_release_date.gte, роўным часу вашага апошняга запуску.

### Як загрузіць першую копію?

Праходзьце /3/discover/movie са старонкамі ад 1 да 500 (да 20 вынікаў на старонку, то бок 10 000 на запыт) і дзяліце па вокнах primary_release_date, каб ісці далей. Толькі ў сакавіку 2025 каля 4400 назваў. Потым чытайце /3/movie/{id} для кожнага id, які вы захоўваеце.

### Колькі займае першая загрузка пры маім ліміце запытаў?

Пры 20 запытах у хвіліну можна зрабіць 1200 выклікаў у гадзіну, пры 40 гэта 2400, а пры 120 гэта 7200. Падзяліце колькасць патрэбных чытанняў дэталяў на гэтую лічбу, каб спланаваць запуск.

### Ці можна злучыць id amodb з id, якія я ўжо захоўваю?

Так. /3/find/{external_id} прымае imdb_id, tvdb_id, wikidata_id і kinopoisk_id і вяртае адпаведны запіс amodb. Запісы фільмаў таксама нясуць imdb_id, таму злучэнне працуе ў абодва бакі.

### Ці ёсць бясплатны тарыф для пабудовы базы даных?

Не. Доступ аплачваецца наперад на 1, 3, 6, 12 або 24 месяцы і не прадаўжаецца сам. Усе планы чытаюць тыя ж даныя, таму большы план толькі прыспешвае першую загрузку і абнаўленні.

## Звязаныя старонкі

- [API дэталяў фільма](https://amodb.dev/be/movies/): API дэталяў фільма з тымі ж шляхамі і JSON, што ў TMDB v3. Адзін фільм па id, а акцёры, рэйтынгі і настрой праз append_to_response, на 14 мовах.
- [API дэталяў персоны](https://amodb.dev/be/people/): API дэталяў персоны з тымі ж шляхамі і JSON, што ў TMDB v3. Акцёр ці член групы па id з біяграфіяй, фільмаграфіяй, вонкавымі id і спісам папулярных.
- [API калекцый](https://amodb.dev/be/collections/): API калекцый фільмаў з шляхамі TMDB v3: чытайце франшызу па id з усімі часткамі, belongs_to_collection у фільме і шукайце калекцыі па назве.
- [Кампаніі і тэлеканалы](https://amodb.dev/be/companies-networks/): Шукайце кінакампаніі і тэлеканалы па шляхах TMDB v3. Чытайце назву, краіну і лагатып па id, потым фільтруйце discover па id кампаніі або тэлеканала.
- [Пошук па вонкавым ідэнтыфікатары](https://amodb.dev/be/find-by-external-id/): Шукайце фільм, серыял або персону па IMDb, TVDB, Wikidata ці Kinopoisk id праз эндпоінт find TMDB і чытайце вонкавыя id і факты Wikidata для назвы.
- [Ліміты запытаў](https://amodb.dev/be/rate-limits/): amodb абмяжоўвае ключ па запытах у хвіліну ў слізгальным акне 60 секунд: 20, 40 або 120 па плане. Чытайце загалоўкі лімітаў і апрацоўвайце 429 праз Retry-After.

Абноўлена: 2026-10-18. Source: https://amodb.dev/be/movie-database-api/
