Побудуйте власну базу фільмів через 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 / | id, imdb_id | genres[].id, production_, belongs_ |
| Персона | GET / | id, imdb_id | Фільми через / |
| Компанія | GET / | id | Фільми через with_companies у discover. parent_company завжди null, а description порожній |
| Колекція | GET / | id | parts[], список фільмів |
| Ключове слово | GET / | id | Фільми через / або with_keywords |
| Жанр | GET / | id | genres[].id у фільмах |
Зв'язки «багато до багатьох» потребують таблиць зв'язку: movie_genre, movie_company, movie_keyword і movie_credit. Використовуйте credit_id зі сторінки акторський склад і знімальна група як ключ останньої. Списки полів на сторінках фільми, персони і колекції.
Почніть за 3 кроки
- Порівняйте три ліміти запитів на сторінці ціни. Більший ліміт скорочує перше завантаження, більше нічого не змінюється.
- Створіть ключ у кабінеті акаунта й тримайте його в змінній середовища.
- Викличте
/3/discover/movieдля однодобового вікна дат виходу, а потім отримайте кожен id зі списку.
Приклад запиту
Скрипт на PHP виводить фільми, що вийшли вчора й сьогодні, через discover і додає або оновлює кожен запис у таблиці SQLite. Він робить паузу 3 секунди між запитами деталей, щоб лишатися в межах 20 запитів на хвилину, повторює 429 після Retry-After і видаляє рядки, id яких тепер повертає 404.
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}.
{
"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_ і .lte, щоб піти далі. |
| Нові прем'єри | GET /3/discover/movie з primary_, встановленим на час останнього запуску, і GET /3/movie/upcoming | Кеш 30 хвилин. |
| Оновлення рядків | GET / для рядків старших за 6 годин | Стрічки змін немає. Оновлюйте тайтли, які відкривають користувачі, а решту рідше. |
| Зіставлення власних id | GET / | Один id на запит, джерело вибирається через external_source. |
| Ліниве заповнення | GET /, коли користувач відкриває тайтл | Зберігайте відповідь із міткою часу. |
Вікно сторінок це головне архітектурне рішення. Коли 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 відсотків. Нічого не поновлюється автоматично, безкоштовного тарифу немає, і кожен тариф читає ті самі дані.