# Саўндтрэкі

> GET /3/movie/{movie_id}/soundtracks і GET /3/tv/{tv_id}/soundtracks вяртаюць альбом саўндтрэка назвы ў спісе results. Кожны альбом мае source, назву, выканаўцу, дату выхаду, спасылку і спіс tracks з disc, number, title, artist і працягласцю. Дадайце 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`  | запыт | адзін з двух | Ваш ключ. Выкарыстоўвайце яго або загаловак `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/be/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/be/errors/), а загалоўкі на старонцы [ліміты запытаў](https://amodb.dev/be/rate-limits/).

## Практычныя заўвагі

- Як і іншыя даныя дэталяў, саўндтрэкі кэшуюцца на edge на 6 гадзін. Карацейшы кліенцкі кэш нічога не дае.
- Выкарыстоўвайце `append_to_response=soundtracks` на старонцы дэталяў, якую вы ўжо загружаеце. Гэта эканоміць адзін з вашых 20, 40 або 120 запытаў у хвіліну.
- Не патрабуйце, каб альбом існаваў. Хавайце блок з музыкай, калі `results` пусты.
- Некаторыя альбомы паходзяць з MusicBrainz, а іншыя з Deezer. У фільма 27205 (Inception) альбом з Deezer. Форма аднолькавая, таму правярайце `source`, толькі калі вы яго паказваеце.
- Назвы трэкаў і выканаўцаў гэта простыя радкі, і ў іх можа быць любы сімвал. Захоўвайце іх у UTF-8 і экрануйце, калі змяшчаеце ў HTML.
- Трэйлер той жа назвы гл. на старонцы [відэа і трэйлеры](https://amodb.dev/be/videos-trailers/).

## Пытанні і адказы

### Што змяшчае адзін запіс саўндтрэка?

Адзін аб’ект альбома. У ім ёсць source, назва альбома, выканаўца, дата выхаду, спасылка і 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/be/movies/): API дэталяў фільма з тымі ж шляхамі і JSON, што ў TMDB v3. Адзін фільм па id, а акцёры, рэйтынгі і настрой праз append_to_response, на 14 мовах.
- [API серыялаў](https://amodb.dev/be/tv-series/): API серыялаў з тымі ж шляхамі і JSON, што ў TMDB v3. Серыял па id з сезонамі, тэлеканаламі і наступным эпізодам, плюс узроставыя рэйтынгі і сэрвісы прагляду.
- [Індыкатары настрою](https://amodb.dev/be/moods/): API настрою з індыкатарамі ад 0 да 10 для кожнай назвы. Дадавайце настрой фільма ці серыяла праз append_to_response=moods і будуйце значкі або фільтры.
- [API відэа і трэйлераў](https://amodb.dev/be/videos-trailers/): API відэа з шляхамі TMDB v3: спіс трэйлераў, тызераў, кліпаў і фічарэтаў для фільма або серыяла, а потым фільтр па тыпе і мове ў вашым кодзе.
- [Рэйтынгі фільмаў і серыялаў](https://amodb.dev/be/ratings/): API рэйтынгаў фільмаў вяртае ацэнкі IMDb, Kinopoisk, Metacritic, Rotten Tomatoes і TMDB для назвы адным выклікам, з null для крыніцы, якая невядомая.
- [Хуткі старт](https://amodb.dev/be/quickstart/): Першы выклік да amodb: атрымайце ключ, запытайце дэталі фільма ў curl, JavaScript, Python, PHP або Go і загрузіце постэр з img.amodb.dev. Менш за 2 хвіліны.

Абноўлена: 2026-10-18. Source: https://amodb.dev/be/soundtracks/
