# Саундтреки

> GET /3/movie/{movie_id}/soundtracks і GET /3/tv/{tv_id}/soundtracks повертають альбом саундтреку назви у списку results. Кожен альбом має джерело, назву, виконавця, дату релізу, посилання та список tracks з диском, номером, назвою, виконавцем і тривалістю кожного треку. Додайте append_to_response=soundtracks, щоб злити його з деталями фільму чи серіалу.

## Ендпоінт

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

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

Відповідь:

```json
{
  "id": 155,
  "results": [
    {
      "source": "musicbrainz",
      "album": "The Dark Knight",
      "artist": "Hans Zimmer & James Newton Howard",
      "released": "2008-07-15",
      "url": "https://musicbrainz.org/release/814b2f7b-c27c-451e-abac-a316d2e6cea9",
      "track_count": 14,
      "tracks": [
        {
          "disc": 1,
          "number": 1,
          "title": "Why So Serious?",
          "artist": "Hans Zimmer",
          "duration_ms": 554000
        },
        {
          "disc": 1,
          "number": 2,
          "title": "I'm Not a Hero",
          "artist": "Hans Zimmer",
          "duration_ms": 395000
        },
        {
          "disc": 1,
          "number": 3,
          "title": "Harvey Two-Face",
          "artist": "James Newton Howard",
          "duration_ms": 377000
        }
      ]
    }
  ]
}
```

## Отримання саундтреку фільму

`GET /3/movie/{movie_id}/soundtracks` повертає альбом саундтреку одного фільму. Відповідь містить `id` фільму та масив `results`. Кожен елемент це альбом з його даними та списком `tracks`.

Приклад завантажує The Dark Knight (id 155) і виводить альбом та по одному рядку на трек.

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

```js
const res = await fetch('https://api.amodb.dev/3/movie/155/soundtracks', {
  headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` },
});
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { results } = await res.json();
if (results.length === 0) console.log('no soundtrack album known');
for (const album of results) {
  console.log(`${album.album} by ${album.artist} (${album.track_count} tracks)`);
  for (const t of album.tracks) {
    console.log(`${t.number}. ${t.title} by ${t.artist}`);
  }
}
```

```python
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/155/soundtracks",
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
results = r.json()["results"]
if not results:
    print("no soundtrack album known")
for album in results:
    print(f"{album['album']} by {album['artist']} ({album['track_count']} tracks)")
    for t in album["tracks"]:
        print(f"{t['number']}. {t['title']} by {t['artist']}")
```

```php
<?php
$ch = curl_init('https://api.amodb.dev/3/movie/155/soundtracks');
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");
}
$results = json_decode($body, true)['results'];
if (!$results) {
    echo 'no soundtrack album known', PHP_EOL;
}
foreach ($results as $album) {
    echo $album['album'], ' by ', $album['artist'] ?? 'unknown', ' (', $album['track_count'], ' tracks)', PHP_EOL;
    foreach ($album['tracks'] as $t) {
        echo $t['number'], '. ', $t['title'], ' by ', $t['artist'], PHP_EOL;
    }
}
```

```go
package main

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

type Track struct {
	Disc       int    `json:"disc"`
	Number     int    `json:"number"`
	Title      string `json:"title"`
	Artist     string `json:"artist"`
	DurationMs int    `json:"duration_ms"`
}

type Album struct {
	Source     string  `json:"source"`
	Album      string  `json:"album"`
	Artist     string  `json:"artist"`
	Released   string  `json:"released"`
	URL        string  `json:"url"`
	TrackCount int     `json:"track_count"`
	Tracks     []Track `json:"tracks"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/movie/155/soundtracks", 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 {
		Results []Album `json:"results"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		panic(err)
	}
	if len(body.Results) == 0 {
		fmt.Println("no soundtrack album known")
	}
	for _, a := range body.Results {
		fmt.Printf("%s by %s (%d tracks)\n", a.Album, a.Artist, a.TrackCount)
		for _, t := range a.Tracks {
			fmt.Printf("%d. %s by %s\n", t.Number, t.Title, t.Artist)
		}
	}
}
```

### Параметри

| Параметр   | Де    | Обов'язковий | Опис                                                                 |
| ---------- | ----- | ------------ | -------------------------------------------------------------------- |
| `movie_id` | шлях  | так          | Числовий id фільму, наприклад `155`.                                 |
| `api_key`  | query | один із двох | Ваш ключ. Використовуйте його або заголовок `Authorization: Bearer`. |

### Поля відповіді

| Поле                             | Тип            | Примітки                                                                   |
| -------------------------------- | -------------- | -------------------------------------------------------------------------- |
| `id`                             | ціле число     | ID фільму. Відсутній, коли ви використовуєте `append_to_response`.         |
| `results`                        | масив          | Альбоми. Порожній, коли альбом невідомий. Наразі містить щонайбільше один. |
| `results[].source`               | рядок          | Звідки альбом: `musicbrainz` або `deezer`.                                 |
| `results[].album`                | рядок          | Назва альбому.                                                             |
| `results[].artist`               | рядок або null | Виконавець альбому, наприклад `Hans Zimmer & James Newton Howard`.         |
| `results[].released`             | рядок або null | Дата релізу у форматі `YYYY-MM-DD`.                                        |
| `results[].url`                  | рядок або null | Посилання на сторінку альбому в джерелі.                                   |
| `results[].track_count`          | ціле число     | Кількість треків в альбомі.                                                |
| `results[].tracks`               | масив          | Треки в порядку альбому.                                                   |
| `results[].tracks[].disc`        | ціле число     | Номер диска, починаючи з 1.                                                |
| `results[].tracks[].number`      | ціле число     | Номер треку на диску.                                                      |
| `results[].tracks[].title`       | рядок          | Назва треку.                                                               |
| `results[].tracks[].artist`      | рядок          | Виконавець треку.                                                          |
| `results[].tracks[].duration_ms` | ціле число     | Тривалість у мілісекундах.                                                 |

Читайте потрібні ключі за іменем і пропускайте решту.

### Приклад відповіді

```json
{
  "id": 155,
  "results": [
    {
      "source": "musicbrainz",
      "album": "The Dark Knight",
      "artist": "Hans Zimmer & James Newton Howard",
      "released": "2008-07-15",
      "url": "https://musicbrainz.org/release/814b2f7b-c27c-451e-abac-a316d2e6cea9",
      "track_count": 14,
      "tracks": [
        { "disc": 1, "number": 1, "title": "Why So Serious?", "artist": "Hans Zimmer", "duration_ms": 554000 },
        { "disc": 1, "number": 2, "title": "I'm Not a Hero", "artist": "Hans Zimmer", "duration_ms": 395000 },
        { "disc": 1, "number": 3, "title": "Harvey Two-Face", "artist": "James Newton Howard", "duration_ms": 377000 }
      ]
    }
  ]
}
```

Список треків скорочено до 3 із 14. Назва без відомого альбому, як-от Fight Club (id 550), повертає порожній список:

```json
{
  "id": 550,
  "results": []
}
```

## Отримання саундтреку серіалу

`GET /3/tv/{tv_id}/soundtracks` повертає ту саму структуру для серіалу. Передайте id серіалу, наприклад `1396`. Для Breaking Bad альбом невідомий, тож його масив `results` порожній.

| Метод і шлях                        | Повертає                                     | Параметри                              |
| ----------------------------------- | -------------------------------------------- | -------------------------------------- |
| `GET /movie/{movie_id}/soundtracks` | `id` і `results`                             | `movie_id`                             |
| `GET /tv/{tv_id}/soundtracks`       | `id` і `results`                             | `tv_id`                                |
| `append_to_response=soundtracks`    | Той самий `results` під ключем `soundtracks` | Додається до деталей фільму чи серіалу |

Щоб отримати альбом під час завантаження сторінки фільму, додайте його до деталей:

```bash
curl -sf "https://api.amodb.dev/3/movie/155?append_to_response=credits,soundtracks" \
  -H "Authorization: Bearer $AMODB_KEY"
```

Доданий блок міститься під ключем `soundtracks` запису. Він містить `results` і не має власного `id`. Це лічиться як один запит.

## Список музики з фільму

Сортуйте за `disc` і `number`, показуйте назву та виконавця й ховайте блок, коли `results` порожній. Функції нижче повертають текстові рядки, які можна вставити в елемент списку.

```js
function clock(ms) {
  const s = Math.round(ms / 1000);
  return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}`;
}

function musicLines(results) {
  const album = results[0];
  if (!album) return [];
  return [...album.tracks]
    .sort((a, b) => a.disc - b.disc || a.number - b.number)
    .map((t) => `${t.title} by ${t.artist} (${clock(t.duration_ms)})`);
}
```

Кілька ідей для інтерфейсу, що не потребують додаткових даних:

| Ідея                 | Як                                                                                             |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| Нумерований список   | Використовуйте `number` як номер у списку й групуйте за `disc`, коли дисків кілька.            |
| Посилання на альбом  | Зробіть назву альбому посиланням на `url`, коли він не null.                                   |
| Загальна тривалість  | Додайте `duration_ms` усіх треків.                                                             |
| Поєднання з настроєм | Покажіть список поруч із [індикаторами настрою](https://amodb.dev/uk/moods/) тієї самої назви. |

## Помилки

Кожна помилка повертає `success` зі значенням false і числовий `status_code`, як це робить TMDB.

| HTTP | status_code | Коли                                                                                            |
| ---- | ----------- | ----------------------------------------------------------------------------------------------- |
| 401  | 7           | Ключ відсутній або хибний.                                                                      |
| 402  | 36          | Термін дії тарифу закінчився.                                                                   |
| 429  | 25          | Перевищено ліміт запитів на хвилину. Зачекайте стільки секунд, скільки вказано в `Retry-After`. |

Ендпоінт саундтреків не відповідає 404 для невідомого id. Він відповідає 200 з порожнім масивом `results`. Якщо блок додано до деталей, невідомий id дає 404 від виклику деталей. Усі коди дивіться в розділі [помилки](https://amodb.dev/uk/errors/), а заголовки в розділі [ліміти запитів](https://amodb.dev/uk/rate-limits/).

## Практичні нотатки

- Як і інші дані деталей, саундтреки кешуються на edge на 6 годин. Коротший кеш на клієнті нічого не дає.
- Використовуйте `append_to_response=soundtracks` на сторінці деталей, яку ви вже завантажуєте. Це заощаджує один запит із ваших 20, 40 або 120 запитів на хвилину.
- Не вимагайте, щоб альбом існував. Ховайте музичний блок, коли `results` порожній.
- Одні альбоми походять із MusicBrainz, інші з Deezer. Фільм 27205 (Inception) має альбом із Deezer. Структура однакова, тож перевіряйте `source` лише тоді, коли показуєте його.
- Назви треків і виконавців це прості рядки, які можуть містити будь-які символи. Зберігайте їх як UTF-8 і екрануйте під час вставки в HTML.
- Про трейлер тієї самої назви дивіться розділ [відео та трейлери](https://amodb.dev/uk/videos-trailers/).

## Запитання й відповіді

### Що містить один запис саундтреку?

Один об'єкт альбому. У ньому є джерело, назва альбому, виконавець, дата релізу, посилання та track_count. Масив tracks перелічує кожен трек з disc, number, title, artist і duration_ms. Відповідь також містить id назви.

### Чи отримаю я аудіофайли або посилання на стримінг?

Аудіо немає. Поле url веде на сторінку альбому в MusicBrainz або Deezer і може бути null. Щоб користувачі могли послухати, знайдіть альбом у музичному сервісі, яким ви вже користуєтеся, і відкривайте його зі свого інтерфейсу.

### Чи є саундтрек для кожної назви?

Ні. Для багатьох назв, зокрема Fight Club, альбом невідомий, і відповідь це порожній масив results. Наразі в назви щонайбільше один альбом. Проєктуйте музичний блок так, щоб він сам ховався, коли показувати нічого.

### Чи можна отримати саундтреки для серіалу?

Так. Викличте GET /3/tv/{tv_id}/soundtracks з id серіалу. Відповідь має ту саму структуру, що й ендпоінт фільмів, тож один парсер обслуговує обидва.

## Пов'язані сторінки

- [API деталей фільму](https://amodb.dev/uk/movies/): API деталей фільму з тими самими шляхами та JSON, що в TMDB v3. Отримайте фільм за id, додайте акторів, рейтинги й настрої через append_to_response, 14 мовами.
- [API серіалів](https://amodb.dev/uk/tv-series/): API серіалів з тими самими шляхами та JSON, що в TMDB v3. Отримайте серіал за id із сезонами, телемережами й наступною серією, плюс вікові рейтинги.
- [Індикатори настрою](https://amodb.dev/uk/moods/): API настроїв фільмів з індикаторами від 0 до 10. Читайте настрої фільму чи серіалу, додавайте їх через append_to_response=moods і будуйте бейджі та фільтри.
- [API відео та трейлерів](https://amodb.dev/uk/videos-trailers/): API відео фільмів зі шляхами TMDB v3: список трейлерів, тизерів, кліпів і фічерет для фільму чи серіалу з фільтрацією за типом і мовою у вашому коді.
- [Рейтинги фільмів і серіалів](https://amodb.dev/uk/ratings/): API рейтингів фільмів повертає оцінки IMDb, Kinopoisk, Metacritic, Rotten Tomatoes і TMDB для фільму чи серіалу одним викликом, з null для невідомих джерел.
- [Швидкий старт](https://amodb.dev/uk/quickstart/): Перший виклик amodb: отримайте ключ, запросіть деталі фільму в curl, JavaScript, Python, PHP чи Go і завантажте постер з img.amodb.dev. Менш ніж за 2 хвилини.

Оновлено: 2026-10-18. Source: https://amodb.dev/uk/soundtracks/
