# Саундтреки

> 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/ru/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/ru/errors/), заголовки на странице [лимиты запросов](https://amodb.dev/ru/rate-limits/).

## Практические заметки

- Как и остальные детальные данные, саундтреки кэшируются на CDN на 6 часов. Более короткий клиентский кэш ничего не даст.
- Используйте `append_to_response=soundtracks` на странице деталей, которую вы и так загружаете. Это экономит один запрос из ваших 20, 40 или 120 запросов в минуту.
- Не требуйте, чтобы альбом существовал. Скрывайте музыкальный блок, когда `results` пуст.
- Одни альбомы приходят из MusicBrainz, другие из Deezer. У фильма 27205 (Inception) альбом из Deezer. Структура одинакова, поэтому проверяйте `source`, только если показываете его.
- Названия треков и исполнителей это обычные строки, и в них может быть любой символ. Храните их в UTF-8 и экранируйте при вставке в HTML.
- Трейлер того же названия смотрите в разделе [видео и трейлеры](https://amodb.dev/ru/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/ru/movies/): API деталей фильма с теми же путями и JSON, что в TMDB v3. Получите фильм по ID, добавьте актеров, рейтинги и настроения через append_to_response, на 14 языках.
- [API сериалов](https://amodb.dev/ru/tv-series/): API сериалов с теми же путями и JSON, что в TMDB v3. Сериал по id с сезонами, телесетями и следующей серией, а также возрастные рейтинги и сервисы просмотра.
- [Шкалы настроения](https://amodb.dev/ru/moods/): API настроений фильмов: шкалы от 0 до 10 для каждого тайтла. Читайте настроения фильма или сериала, добавляйте через append_to_response=moods, стройте бейджи.
- [API видео и трейлеров](https://amodb.dev/ru/videos-trailers/): API видео фильмов с путями TMDB v3: список трейлеров, тизеров, клипов и фичереток фильма или сериала, фильтрация по типу и языку в вашем коде.
- [Рейтинги фильмов и сериалов](https://amodb.dev/ru/ratings/): API рейтингов фильмов: оценки IMDb, Kinopoisk, Metacritic, Rotten Tomatoes и TMDB для тайтла одним запросом, с null для источника, о котором нет данных.
- [Быстрый старт](https://amodb.dev/ru/quickstart/): Первый вызов amodb: получите ключ, запросите детали фильма через curl, JavaScript, Python, PHP или Go и загрузите постер с img.amodb.dev. Меньше 2 минут.

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