# Mierniki nastroju

> GET /3/movie/{movie_id}/moods i GET /3/tv/{tv_id}/moods zwracają źródło i listę results. Każdy wynik ma nazwę nastroju, na przykład fear lub humor, avg na skali od 0 do 10 oraz wartości, z których powstaje. Dodaj append_to_response=moods do wywołania szczegółów, by scalić mierniki bez drugiego żądania.

## Endpoint

`GET /3/movie/{movie_id}/moods`

```bash
curl "https://api.amodb.dev/3/movie/155/moods" \
  -H "Authorization: Bearer $AMODB_KEY"
```

Odpowiedź:

```json
{
  "id": 155,
  "source": "measured",
  "results": [
    {
      "name": "action",
      "avg": 3.9,
      "values": [
        3.6,
        3.4,
        4.2
      ]
    },
    {
      "name": "fear",
      "avg": 5.2,
      "values": [
        3.6,
        6,
        4.8
      ]
    },
    {
      "name": "humor",
      "avg": 0.9,
      "values": [
        2.4,
        1.8,
        0.4
      ]
    }
  ]
}
```

## Pobieranie mierników nastroju filmu

`GET /3/movie/{movie_id}/moods` zwraca mierniki nastroju jednego filmu. Miernik nastroju to nazwa i średnia na skali od 0 do 10. Odpowiedź niesie `id` filmu, `source` i tablicę `results`. Każdy wynik zawiera `name`, `avg` i `values`.

Przykład pobiera mierniki dla The Dark Knight (ID 155) i wypisuje je od najsilniejszego do najsłabszego.

```bash
curl -sf "https://api.amodb.dev/3/movie/155/moods" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```js
const res = await fetch('https://api.amodb.dev/3/movie/155/moods', {
  headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` },
});
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { source, results } = await res.json();
console.log('source:', source);
for (const m of [...results].sort((a, b) => b.avg - a.avg)) {
  console.log(m.name.padEnd(10), m.avg);
}
```

```python
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/155/moods",
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
data = r.json()
print("source:", data.get("source"))
for m in sorted(data["results"], key=lambda m: m["avg"], reverse=True):
    print(f"{m['name']:<10} {m['avg']}")
```

```php
<?php
$ch = curl_init('https://api.amodb.dev/3/movie/155/moods');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
    throw new RuntimeException("amodb returned $status");
}
$data = json_decode($body, true);
echo 'source: ', $data['source'] ?? 'none', PHP_EOL;
$results = $data['results'];
usort($results, fn ($a, $b) => $b['avg'] <=> $a['avg']);
foreach ($results as $m) {
    printf("%-10s %.1f\n", $m['name'], $m['avg']);
}
```

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"sort"
	"time"
)

type Mood struct {
	Name   string    `json:"name"`
	Avg    float64   `json:"avg"`
	Values []float64 `json:"values"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/movie/155/moods", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	client := &http.Client{Timeout: 10 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic(res.Status)
	}
	var body struct {
		Source  string `json:"source"`
		Results []Mood `json:"results"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		panic(err)
	}
	fmt.Println("source:", body.Source)
	sort.Slice(body.Results, func(i, j int) bool { return body.Results[i].Avg > body.Results[j].Avg })
	for _, m := range body.Results {
		fmt.Printf("%-10s %.1f\n", m.Name, m.Avg)
	}
}
```

### Parametry

| Parametr   | Gdzie | Wymagany      | Opis                                                       |
| ---------- | ----- | ------------- | ---------------------------------------------------------- |
| `movie_id` | path  | tak           | Numeryczne ID filmu, na przykład `155`.                    |
| `api_key`  | query | jeden z dwóch | Twój klucz. Użyj go albo nagłówka `Authorization: Bearer`. |

### Pola odpowiedzi

| Pole               | Typ              | Uwagi                                                                                                              |
| ------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| `id`               | integer          | ID filmu.                                                                                                          |
| `source`           | string lub null  | `measured` dla danych widzów, `estimated`, gdy wyliczone z gatunków, `null`, gdy tytuł nie ma danych.              |
| `results`          | array            | Mierniki nastroju posortowane według `name`. Puste, gdy nic nie wiadomo.                                           |
| `results[].name`   | string           | Krótkie słowo małymi literami, na przykład `fear`.                                                                 |
| `results[].avg`    | number           | Średnia na skali od 0 do 10. Jedno miejsce po przecinku dla zmierzonych tytułów, liczba całkowita dla szacowanych. |
| `results[].values` | array of numbers | Do 24 odczytów na tej samej skali od 0 do 10. Widziane zmierzone tytuły mają 6, szacowane 5.                       |

Dziś występują nazwy `action`, `fear`, `humor`, `pace`, `profanity`, `romance`, `sadness`, `sex` i `violence`. Nie każdy tytuł ma wszystkie dziewięć, więc renderuj nazwy z danych, a nie ze stałej listy.

### Przykładowa odpowiedź

```json
{
  "id": 155,
  "source": "measured",
  "results": [
    { "name": "action", "avg": 3.9, "values": [3.6, 3.4, 4.2, 4.2, 4.8, 3] },
    { "name": "fear", "avg": 5.2, "values": [3.6, 6, 4.8, 6.4, 6.4, 3.8] },
    { "name": "humor", "avg": 0.9, "values": [2.4, 1.8, 0.4, 0.4, 0, 0.5] }
  ]
}
```

Lista jest przycięta do 3 z 9 wyników.

### Tytuły zmierzone i szacowane

Fight Club (ID 550) nie ma jeszcze danych widzów, więc jego mierniki są wyliczone z gatunków. Każde `avg` jest liczbą całkowitą, a `values` ma 5 pozycji.

```json
{
  "id": 550,
  "source": "estimated",
  "results": [
    { "name": "action", "avg": 4, "values": [3, 4, 5, 4, 3] },
    { "name": "fear", "avg": 7, "values": [6, 7, 8, 7, 6] }
  ]
}
```

Sprawdź `source`, jeśli chcesz traktować mierniki szacowane inaczej niż zmierzone.

## Pobieranie mierników nastroju serialu

`GET /3/tv/{tv_id}/moods` ma ten sam kształt odpowiedzi, z ID serialu w `id`. Dla Breaking Bad użyj `1396`.

| Metoda i ścieżka              | Zwraca                           | Parametry                                |
| ----------------------------- | -------------------------------- | ---------------------------------------- |
| `GET /movie/{movie_id}/moods` | `id`, `source` i `results`       | `movie_id`                               |
| `GET /tv/{tv_id}/moods`       | `id`, `source` i `results`       | `tv_id`                                  |
| `append_to_response=moods`    | `source` i `results` pod `moods` | Dodawane do szczegółów filmu lub serialu |

```bash
curl -sf "https://api.amodb.dev/3/tv/1396?append_to_response=moods" -H "Authorization: Bearer $AMODB_KEY"
```

Gdy dołączasz `moods` do wywołania szczegółów, klucz `moods` leży na najwyższym poziomie rekordu obok `title` lub `name`. Zawiera `source` i `results` i nie ma własnego `id`. Kosztuje to jedno żądanie, podczas gdy dwa osobne wywołania kosztują dwa.

## Jak czytać skalę

Pole `avg` to intensywność od 0 do 10. Wyższa liczba oznacza, że nastrój jest silniejszy w tytule.

| Zakres   | Odczyt                          |
| -------- | ------------------------------- |
| 0 do 2.9 | Nastrój jest słaby lub go brak. |
| 3 do 5.9 | Nastrój jest obecny.            |
| 6 do 7.9 | Nastrój jest wyraźny.           |
| 8 do 10  | Nastrój definiuje tytuł.        |

Przedziały to sugestia dla twojego interfejsu, a nie pole w odpowiedzi. Tablica `values` zawiera odczyty stojące za średnią, na tej samej skali.

## Budowanie plakietek i filtrów

Nastroje pasują do trzech typowych wzorców interfejsu. Wybierz progi pasujące do twojego katalogu i dostrój je.

| Wzorzec        | Reguła                                                        | Uwagi                                                        |
| -------------- | ------------------------------------------------------------- | ------------------------------------------------------------ |
| Plakietka      | Pokaż do 3 nastrojów z `avg` 6 lub wyższym                    | Najpierw posortuj według `avg`.                              |
| Pasek miernika | Ustaw szerokość paska na `avg` razy 10 jako procent           | Skala to od 0 do 10.                                         |
| Chip filtra    | Dopasuj tytuły, w których wybrany nastrój wynosi 7 lub więcej | Pobierz mierniki dla każdego tytułu, potem filtruj lokalnie. |

```js
function topMoods(results, min = 6, limit = 3) {
  return results
    .filter((m) => m.avg >= min)
    .sort((a, b) => b.avg - a.avg)
    .slice(0, limit)
    .map((m) => m.name);
}

function matchesMood(results, name, min = 7) {
  return results.some((m) => m.name === name && m.avg >= min);
}
```

Pusta tablica `results` powinna się wyrenderować jako brak plakietek, a nie jako błąd.

## Błędy

Treść błędu ma `success`, `status_code` i `status_message`, czyli te same pola co w TMDB.

| HTTP | status_code | Kiedy                                                                               |
| ---- | ----------- | ----------------------------------------------------------------------------------- |
| 401  | 7           | Brakuje klucza lub jest błędny.                                                     |
| 402  | 36          | Okres planu dobiegł końca.                                                          |
| 429  | 25          | Przekroczono limit żądań na minutę. Poczekaj tyle sekund, ile podaje `Retry-After`. |

Endpoint nastrojów nie odpowiada 404 dla nieznanego ID. Odpowiada 200 z pustą tablicą `results`, a `source` ma wartość `null` albo go brak. Przy dołączeniu do szczegółów nieznane ID daje 404 z wywołania szczegółów. Pełna lista jest na stronie [błędy](https://amodb.dev/pl/errors/), a limity na stronie [limity żądań](https://amodb.dev/pl/rate-limits/).

## Praktyczne uwagi

- Jak inne dane szczegółów, mierniki nastroju są w cache na edge przez 6 godzin. Pobieranie ich częściej zwraca tę samą treść.
- Lista 20 tytułów wymaga 20 żądań o nastroje. Jeśli już wywołujesz szczegóły dla każdego tytułu, dołącz `moods` i oszczędź drugie wywołanie.
- Zanim porównasz tytuły, sprawdź `source`. Mierniki zmierzone i szacowane używają tej samej skali, ale nie tej samej precyzji.
- Jeśli filtrujesz często, zapisuj `name` i `avg` razem z ID tytułu we własnej bazie danych. Lokalny filtr jest lepszy niż żądanie na tytuł.
- Łącz mierniki z [ocenami](https://amodb.dev/pl/ratings/), by dostać wynik, i ze [ścieżkami dźwiękowymi](https://amodb.dev/pl/soundtracks/), by dostać muzykę z tego samego tytułu.

## Pytania i odpowiedzi

### Co oznacza wartość nastroju?

Pole avg to intensywność na skali od 0 do 10, z jednym miejscem po przecinku dla zmierzonych tytułów. Avg równe 7 dla fear oznacza, że tytuł jest straszny, a 0 oznacza brak tego nastroju. To nie procent ani ocena z recenzji.

### Czy lista nazw nastrojów jest stała?

Nie zakładaj tego. Dziś występują nazwy action, fear, humor, pace, profanity, romance, sadness, sex i violence, a tytuł może mieć ich mniej niż dziewięć. Renderuj ciągi nazw, które dostajesz, aby nowa też się pojawiła.

### Co oznaczają measured i estimated w source?

Measured oznacza, że mierniki pochodzą z danych widzów i mają miejsca po przecinku. Estimated oznacza, że są wyliczone z gatunków tytułu, więc avg jest liczbą całkowitą. Tytuł bez danych ma pustą tablicę results i source równe null.

### Jak filtrować listę tytułów według nastroju?

Pobierz mierniki dla każdego tytułu na liście, przez endpoint nastrojów albo przez append_to_response przy szczegółach, i zostaw tytuły, w których wybrany nastrój przekracza twój próg. Filtr działa w twoim kodzie.

### Czy seriale też mają nastroje?

Tak. Użyj GET /3/tv/{tv_id}/moods, na przykład z ID serialu 1396. Odpowiedź ma ten sam kształt co endpoint filmów.

## 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 serialu](https://amodb.dev/pl/tv-series/): API szczegółów serialu z tymi samymi ścieżkami i JSON co TMDB v3. Serial po ID z sezonami, sieciami, klasyfikacją wiekową i dostawcami streamingu.
- [Oceny filmów i seriali](https://amodb.dev/pl/ratings/): API ocen filmów zwraca wyniki z IMDb, Kinopoisk, Metacritic, Rotten Tomatoes i TMDB dla tytułu jednym wywołaniem, z null dla każdego nieznanego źródła.
- [Ścieżki dźwiękowe](https://amodb.dev/pl/soundtracks/): API ścieżek dźwiękowych filmów zwraca album soundtracku filmu lub serialu z listą utworów. Wywołaj endpoint albo dodaj append_to_response=soundtracks.
- [Discover API](https://amodb.dev/pl/discover/): Discover API z tymi samymi filtrami co TMDB v3. Wypisuj filmy i seriale według gatunku, obsady, firmy, słowa kluczowego, roku, oceny, czasu trwania i dostawcy.
- [Szybki start](https://amodb.dev/pl/quickstart/): Pierwsze wywołanie amodb: zdobądź klucz, pobierz szczegóły filmu w curl, JavaScript, Python, PHP lub Go, potem załaduj plakat z img.amodb.dev. Poniżej 2 minut.

Zaktualizowano: 2026-10-18. Source: https://amodb.dev/pl/moods/
