Изградете собствена база данни за филми от 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_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 таблица с upsert. Спи 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 часаНяма поток changes. Обновявайте заглавията, които потребителите отварят, а останалите по-рядко.
Свързване на собствени idGET /3/find/{external_id}Едно id на извикване, източникът се избира с external_source.
Отложено попълванеGET /3/movie/{movie_id}, когато потребител отвори заглавиеЗаписвайте отговора с времеви печат.

Прозорецът на странициране е основното решение в проектирането. Когато 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 процента. Нищо не се подновява автоматично, няма безплатен план и всеки план чете същите данни.