Изградете собствена база данни за филми от 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 / | 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 таблица с upsert. Спи 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 часа | Няма поток changes. Обновявайте заглавията, които потребителите отварят, а останалите по-рядко. |
| Свързване на собствени id | GET / | Едно id на извикване, източникът се избира с external_source. |
| Отложено попълване | GET /, когато потребител отвори заглавие | Записвайте отговора с времеви печат. |
Прозорецът на странициране е основното решение в проектирането. Когато total_pages в отговор е над 500, прозорецът съдържа над 10 000 реда, затова го режете на половини, докато се събере. За последна година ви трябват месеци, а един ден премиери са няколкостотин заглавия. Пазете приключената част, за да може срутило се изпълнение да продължи. Правилата за съпоставяне при свързването са на страницата търсене по външен идентификатор.
Оразмеряване на синхронизацията
Всеки ред, който обновявате, струва едно четене на детайли. План от 20 заявки в минута дава 1200 извиквания на час, 40 дава 2400, а 120 дава 7200. Една страница на discover изброява 20 id с едно извикване. Пускайте обновяването в часове с по-малко натоварване, ако приложението ви споделя ключа, защото лимитът е на ключ, а не на скрипт. Вижте лимити на заявките за заглавките, които показват какво остава в прозореца.
Кеширане на два слоя
| Слой | Какво държи | 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 в минута на страницата с цените. Плащате за 1, 3, 6, 12 или 24 месеца с отстъпка 0, 10, 20, 30 или 40 процента. Нищо не се подновява автоматично, няма безплатен план и всеки план чете същите данни.