# API bazy filmów do twojego własnego katalogu

> Używaj amodb jako źródła własnej bazy filmów. Filmy, osoby, firmy, kolekcje, słowa kluczowe i gatunki mają wspólne numeryczne ID, więc wiersze łączą się czysto. Zasil bazę paginacją discover w oknach dat premier, odświeżaj wiersze według wieku i dopasuj własne ID przez wyszukiwanie po zewnętrznym ID. JSON TMDB v3, od 20 do 120 żądań na minutę.

## Zbuduj własną bazę filmów z API

amodb to niezależne API, które mówi protokołem TMDB v3. Filmy, osoby, firmy, kolekcje, słowa kluczowe i gatunki mają numeryczne ID i wskazują na siebie nawzajem, więc możesz zasilać z nich tabele SQL i utrzymywać je w aktualnym stanie. Zasil tabele paginacją discover, odświeżaj je według wieku i dopasowuj własne identyfikatory przez `find`. amodb nie ma kanału zmian, więc odświeżenie to zwykłe ponowne pobranie wierszy, które zachowujesz.

Co dostajesz:

- Sześć powiązanych typów encji ze stałymi numerycznymi ID.
- Paginację discover do pierwszego ładowania: do 20 wyników na stronę, 500 stron na zapytanie.
- Okna dat premier w discover, którymi podzielisz pierwsze ładowanie i wypiszesz nowe premiery.
- Wyszukiwanie po zewnętrznych ID `imdb_id`, `tvdb_id`, `wikidata_id` i `kinopoisk_id`.

## Jakie dane dostajesz

To model danych. Każdy wiersz to jedna tabela w kopii relacyjnej.

| Encja          | Odczyt                              | Klucz           | Wskazuje na                                                                                              |
| -------------- | ----------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
| Film           | `GET /3/movie/{movie_id}`           | `id`, `imdb_id` | `genres[].id`, `production_companies[].id`, `belongs_to_collection.id`                                   |
| Osoba          | `GET /3/person/{person_id}`         | `id`, `imdb_id` | Filmy przez `/3/movie/{movie_id}/credits`                                                                |
| Firma          | `GET /3/company/{company_id}`       | `id`            | Filmy przez `with_companies` w discover. `parent_company` jest zawsze `null`, a `description` jest puste |
| Kolekcja       | `GET /3/collection/{collection_id}` | `id`            | `parts[]`, lista filmów                                                                                  |
| Słowo kluczowe | `GET /3/keyword/{keyword_id}`       | `id`            | Filmy przez `/3/keyword/{keyword_id}/movies` lub `with_keywords`                                         |
| Gatunek        | `GET /3/genre/movie/list`           | `id`            | `genres[].id` w filmach                                                                                  |

Powiązania wiele do wielu wymagają tabel łączących: `movie_genre`, `movie_company`, `movie_keyword` i `movie_credit`. Jako klucza ostatniej użyj `credit_id` ze strony [obsada i ekipa](https://amodb.dev/pl/credits/). Listy pól są na stronach [filmy](https://amodb.dev/pl/movies/), [osoby](https://amodb.dev/pl/people/) i [kolekcje](https://amodb.dev/pl/collections/).

## Start w 3 krokach

1. Porównaj trzy tempa żądań na stronie [cennik](https://amodb.dev/pl/pricing/). Wyższe tempo skraca pierwsze ładowanie, nic więcej się nie zmienia.
2. Utwórz klucz w panelu konta i trzymaj go w zmiennej środowiskowej.
3. Wywołaj `/3/discover/movie` dla jednodniowego okna dat premier, a potem pobierz każde ID z listy.

## Przykładowe żądanie

Skrypt w PHP wypisuje filmy wydane wczoraj i dziś przez discover i zapisuje (upsert) każdy rekord do tabeli SQLite. Między odczytami szczegółów czeka 3 sekundy, by zmieścić się w 20 żądaniach na minutę, ponawia 429 po `Retry-After` i usuwa wiersze, których ID zwraca teraz 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 zwraca wiersze listy, nie pełne rekordy. To 2 z 20 wyników na stronie 1. Pozostałe pola pobierz z `/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
}
```

## Wypełnianie i odświeżanie tabel

| Zadanie              | Wywołanie                                                                                                        | Limity                                                                                                                                     |
| -------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Pierwsze ładowanie   | `GET /3/discover/movie` z `sort_by` i oknem dat                                                                  | `page` od 1 do 500, do 20 wyników na stronę, czyli 10 000 na zapytanie. Aby pójść dalej, dziel według `primary_release_date.gte` i `.lte`. |
| Nowe premiery        | `GET /3/discover/movie` z `primary_release_date.gte` ustawionym na ostatni przebieg oraz `GET /3/movie/upcoming` | W cache przez 30 minut.                                                                                                                    |
| Odświeżanie wierszy  | `GET /3/movie/{movie_id}` dla wierszy starszych niż 6 godzin                                                     | Nie ma kanału zmian. Odświeżaj tytuły, które otwierają użytkownicy, a resztę rzadziej.                                                     |
| Łączenie własnych ID | `GET /3/find/{external_id}`                                                                                      | Jedno ID na wywołanie, źródło wybierane przez `external_source`.                                                                           |
| Leniwe wypełnianie   | `GET /3/movie/{movie_id}`, gdy użytkownik otwiera tytuł                                                          | Zapisz odpowiedź ze znacznikiem czasu.                                                                                                     |

Okno paginacji to główna decyzja projektowa. Gdy `total_pages` w odpowiedzi przekracza 500, okno zawiera ponad 10 000 wierszy, więc tnij je na pół, aż się zmieści. Ostatni rok wymaga miesięcy, a jeden dzień premier to kilkaset tytułów. Zapisuj ukończony wycinek, aby przerwany przebieg mógł wznowić pracę. Zasady dopasowania do łączenia opisuje strona [wyszukiwanie po zewnętrznym ID](https://amodb.dev/pl/find-by-external-id/).

## Wymiarowanie synchronizacji

Każdy odświeżany wiersz kosztuje jeden odczyt szczegółów. Plan z 20 żądaniami na minutę daje 1 200 wywołań na godzinę, 40 daje 2 400, a 120 daje 7 200. Strona discover wypisuje 20 ID za jedno wywołanie. Uruchamiaj odświeżanie poza godzinami szczytu, jeśli aplikacja dzieli klucz, bo limit dotyczy klucza, a nie skryptu. Nagłówki podające, ile zostało w oknie, opisują [limity żądań](https://amodb.dev/pl/rate-limits/).

## Cache w dwóch warstwach

| Warstwa       | Zawiera                            | TTL                                                                              |
| ------------- | ---------------------------------- | -------------------------------------------------------------------------------- |
| Cache na edge | Szczegóły i obsadę                 | 6 godzin                                                                         |
| Cache na edge | Listy discover, trending i popular | 30 minut                                                                         |
| Cache na edge | Wyszukiwanie                       | 10 minut                                                                         |
| Cache na edge | Konfigurację                       | 24 godziny                                                                       |
| Cache na edge | Obrazy                             | 30 dni                                                                           |
| Twoje tabele  | Wiersze, które zachowujesz         | Dopóki reguła wieku nie każe pobrać ponownie, nigdy wcześniej niż po 6 godzinach |

Cache na edge jest współdzielony między kluczami, ale limit żądań działa przed nim, więc trafienie w cache nadal zużywa jedno żądanie z twojej minuty. Ponowny odczyt wiersza częściej niż co 6 godzin zwraca tę samą kopię i marnuje limit. Decyzję o ponownym pobraniu zostaw regule wieku.

## Jak wypada w porównaniu

| Możliwość                | Własny scraping stron                | Statyczne pliki zbioru danych            | amodb                                                |
| ------------------------ | ------------------------------------ | ---------------------------------------- | ---------------------------------------------------- |
| Świeżość                 | Tak świeże jak ostatni crawl         | Tak świeże jak ostatni opublikowany plik | Szczegóły w cache 6 godzin, odświeżanie według wieku |
| Aktualizacje przyrostowe | Ponowny crawl i porównanie           | Pobranie nowego pliku                    | Discover z oknem dat premier, bez kanału zmian       |
| ID między encjami        | Adresy URL stron                     | Ustala wydawca                           | Numeryczne ID, `imdb_id` i `/3/find`                 |
| Co uruchamiasz           | Crawlery i magazyn danych            | Magazyn danych i zadanie importu         | Magazyn danych i skrypt synchronizacji               |
| Limit żądań              | Ustalają strony, które przeszukujesz | Nie dotyczy                              | 20, 40 lub 120 żądań na minutę, liczone na klucz     |
| Języki na rekord         | Co oferuje dana strona               | Zależy od plików                         | 14, wybierane przez `language`                       |

## Cennik

Kosztowne jest pierwsze ładowanie i ogranicza je liczba żądań na minutę. Wybierz 20, 40 lub 120 na minutę na stronie [cennik](https://amodb.dev/pl/pricing/). Płacisz za 1, 3, 6, 12 lub 24 miesiące ze zniżką 0, 10, 20, 30 lub 40 procent. Nic nie odnawia się automatycznie, nie ma darmowego planu, a każdy plan czyta te same dane.

## Pytania i odpowiedzi

### Jak utrzymać lokalną kopię w aktualnym stanie?

amodb nie ma kanału zmian, więc odświeżaj według wieku. Szczegóły są w cache na edge przez 6 godzin, więc nie pobieraj wiersza ponownie wcześniej. Nowe premiery wychwycisz przez discover z primary_release_date.gte ustawionym na ostatni przebieg.

### Jak załadować pierwszą kopię?

Przejdź /3/discover/movie ze stronami od 1 do 500 (do 20 wyników na stronę, czyli 10 000 na zapytanie) i dziel według okien primary_release_date, by pójść dalej. Sam marzec 2025 ma około 4 400 tytułów. Potem odczytaj /3/movie/{id} dla każdego ID, które zachowujesz.

### Ile trwa pierwsze ładowanie przy moim limicie żądań?

Przy 20 żądaniach na minutę możesz wykonać 1 200 wywołań na godzinę, przy 40 to 2 400, a przy 120 to 7 200. Podziel liczbę potrzebnych odczytów szczegółów przez tę wartość, aby zaplanować przebieg.

### Czy mogę połączyć ID z amodb z ID, które już przechowuję?

Tak. /3/find/{external_id} przyjmuje imdb_id, tvdb_id, wikidata_id i kinopoisk_id i zwraca pasujący rekord amodb. Rekordy filmów niosą też imdb_id, więc łączenie działa w obu kierunkach.

### Czy jest darmowy plan do budowy bazy danych?

Nie. Dostęp jest przedpłacony na 1, 3, 6, 12 lub 24 miesiące i nie odnawia się sam. Każdy plan czyta te same dane, więc większy plan tylko przyspiesza pierwsze ładowanie i odświeżanie.

## Powiązane strony

- [API szczegółów filmu](https://amodb.dev/pl/movies/): API szczegółów filmu z tymi samymi ścieżkami i JSON co TMDB v3. Pobierz film po ID, dołącz obsadę, oceny i nastroje przez append_to_response, 14 języków.
- [API szczegółów osoby](https://amodb.dev/pl/people/): API szczegółów osoby z tymi samymi ścieżkami i JSON co TMDB v3. Aktor lub ekipa po ID z biografią, filmografią, zewnętrznymi ID i listą popularnych osób.
- [API kolekcji](https://amodb.dev/pl/collections/): API kolekcji filmów ze ścieżkami TMDB v3: pobierz franczyzę po ID ze wszystkimi filmami, odczytaj belongs_to_collection w filmie i szukaj kolekcji po nazwie.
- [Firmy i sieci telewizyjne](https://amodb.dev/pl/companies-networks/): Firmy produkcyjne i sieci telewizyjne przez ścieżki TMDB v3. Odczytaj nazwę, kraj i logo po ID, a potem filtruj discover według ID firmy lub sieci.
- [Wyszukiwanie po zewnętrznym ID](https://amodb.dev/pl/find-by-external-id/): Znajdź film, serial lub osobę po ID z IMDb, TVDB, Wikidata lub Kinopoisk przez endpoint find z TMDB oraz odczytaj zewnętrzne ID i fakty z Wikidata o tytule.
- [Limity żądań](https://amodb.dev/pl/rate-limits/): amodb limituje klucz liczbą żądań na minutę w przesuwanym oknie 60 sekund: 20, 40 lub 120 zależnie od planu. Czytaj nagłówki limitu i obsłuż 429 z Retry-After.

Zaktualizowano: 2026-10-18. Source: https://amodb.dev/pl/movie-database-api/
