Побудуйте власну базу фільмів через API

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

Що ви отримуєте:

  • Шість пов'язаних типів сутностей зі стабільними числовими id.
  • Сторінки discover для першого завантаження: до 20 результатів на сторінці, 500 сторінок на запит.
  • Вікна дат виходу в discover, щоб розбити перше завантаження та показувати нові прем'єри.
  • Пошук за зовнішніми id для imdb_id, tvdb_id, wikidata_id і kinopoisk_id.

Які дані ви отримуєте

Це модель даних. Кожен рядок це одна таблиця в реляційній копії.

СутністьЯк читатиКлючЗв'язки
ФільмGET /3/movie/{movie_id}id, imdb_idgenres[].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}idparts[], список фільмів
Ключове словоGET /3/keyword/{keyword_id}idФільми через /3/keyword/{keyword_id}/movies або with_keywords
ЖанрGET /3/genre/movie/listidgenres[].id у фільмах

Зв'язки «багато до багатьох» потребують таблиць зв'язку: movie_genre, movie_company, movie_keyword і movie_credit. Використовуйте credit_id зі сторінки акторський склад і знімальна група як ключ останньої. Списки полів на сторінках фільми, персони і колекції.

Почніть за 3 кроки

  1. Порівняйте три ліміти запитів на сторінці ціни. Більший ліміт скорочує перше завантаження, більше нічого не змінюється.
  2. Створіть ключ у кабінеті акаунта й тримайте його в змінній середовища.
  3. Викличте /3/discover/movie для однодобового вікна дат виходу, а потім отримайте кожен id зі списку.

Приклад запиту

Скрипт на PHP виводить фільми, що вийшли вчора й сьогодні, через discover і додає або оновлює кожен запис у таблиці SQLite. Він робить паузу 3 секунди між запитами деталей, щоб лишатися в межах 20 запитів на хвилину, повторює 429 після Retry-After і видаляє рядки, id яких тепер повертає 404.

bashphp
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
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 годинСтрічки змін немає. Оновлюйте тайтли, які відкривають користувачі, а решту рідше.
Зіставлення власних idGET /3/find/{external_id}Один id на запит, джерело вибирається через external_source.
Ліниве заповненняGET /3/movie/{movie_id}, коли користувач відкриває тайтлЗберігайте відповідь із міткою часу.

Вікно сторінок це головне архітектурне рішення. Коли total_pages у відповіді більше за 500, вікно містить понад 10,000 рядків, тож діліть його навпіл, доки воно не вміститься. Для недавнього року потрібні місяці, а один день прем'єр це кілька сотень тайтлів. Зберігайте завершений відрізок, щоб перерваний запуск міг продовжитися. Правила зіставлення для поєднання на сторінці пошук за зовнішнім ID.

Планування синхронізації

Кожен рядок, який ви оновлюєте, коштує один запит деталей. Тариф з 20 запитами на хвилину дає 1,200 викликів на годину, 40 дає 2,400, а 120 дає 7,200. Сторінка discover перелічує 20 id за один запит. Запускайте оновлення в непіковий час, якщо ваш застосунок ділить ключ, бо ліміт діє на ключ, а не на скрипт. Заголовки, що показують залишок у вікні, описано на сторінці ліміти запитів.

Кешування у два шари

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

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

Порівняння

МожливістьСкрапінг сторінок власноручСтатичні файли датасетівamodb
СвіжістьНастільки свіжа, як ваш останній обхідНастільки свіжа, як останній опублікований файлДеталі кешуються на 6 годин, повторний запит за віком
Інкрементальні оновленняПовторний обхід і порівнянняЗавантаження нового файлуDiscover із вікном дат виходу, без стрічки змін
Id між сутностямиURL сторінокВизначає видавецьЧислові id, imdb_id і /3/find
Що ви запускаєтеКраулери й сховищеСховище та завдання імпортуСховище та скрипт синхронізації
Ліміт запитівВизначають сайти, які ви обходитеНе застосовується20, 40 або 120 запитів на хвилину, рахуються на ключ
Мови на записТе, що пропонує кожна сторінкаЗалежить від файлів14, вибираються через language

Ціни

Перше завантаження найвитратніше, і воно обмежене вашим лімітом запитів на хвилину. Оберіть 20, 40 або 120 на хвилину на сторінці ціни. Платіть за 1, 3, 6, 12 або 24 місяці зі знижками 0, 10, 20, 30 або 40 відсотків. Нічого не поновлюється автоматично, безкоштовного тарифу немає, і кожен тариф читає ті самі дані.