# Phụ đề

> **TL;DR** — Mỗi vé liệt kê phụ đề của tập: mỗi ngôn ngữ một tệp WebVTT, theo thứ tự `lang`. Danh sách rỗng nghĩa là chưa có phụ đề, không phải lỗi. App native đưa URL cho Player SDK hoặc tự vẽ các cue; player web tải tệp về rồi thêm cue bằng `addTextTrack()`. URL phụ đề sống lâu hơn vé; khi một URL không còn dùng được, lấy URL hiện tại từ vé kế tiếp.

## Phụ đề lấy từ đâu
| Trường | Mô tả |
|---|---|
| `subtitles[].lang` | Mã ngôn ngữ như được giao, ví dụ `en`, `vi`, `pt-BR`. |
| `subtitles[].url` | Nơi tải tệp WebVTT. |
| `subtitles[].format` | Hiện là `webvtt`. Bỏ qua định dạng bạn không biết. |

- Phụ đề không nằm trong catalog; chúng đi kèm từng vé. Các ngôn ngữ có trong các phim của bạn được liệt kê ở `GET /config` (`subtitles.languages`).
- Phụ đề được gắn hoặc thay ở phía Wandura sẽ có trong vé trong vòng 5 phút.
- Tệp được thay sẽ có **URL mới**, và URL cũ ngừng hoạt động. Nếu một URL đã lưu bị hỏng, lấy URL hiện tại từ một vé mới.
- URL phụ đề là public và sống lâu: cache theo từng tập thì được, công bố ra ngoài thì không.
- Phụ đề không tải được không bao giờ được làm dừng playback.

## App native
Có hai cách, cả hai đều có trong hướng dẫn Player SDK trên cổng: đưa URL cho chế độ phụ đề ngoài của SDK, hoặc tải tệp `.vtt` về rồi tự vẽ các cue đè lên player. Ví dụ [iOS](https://docs.wandura.ai/vi/v1/developers/player-sdk/ios) và [Android](https://docs.wandura.ai/vi/v1/developers/player-sdk/android) truyền `ticket.subtitles` vào một lệnh `addSubtitles`.

## Player web
**Đừng** thêm thuộc tính `crossorigin` vào phần tử `<video>` chỉ để dùng `<track>`: nó thay đổi cách chính video được request và có thể làm video không phát được. Hãy tải tệp bằng `fetch` rồi tự thêm cue:

```ts
/** One text track per subtitle of a ticket. A file that fails is skipped: subtitles never block playback. */
export async function addSubtitles(video: HTMLVideoElement, subtitles: Subtitle[], show = 'en'): Promise<void> {
  for (const s of subtitles) {
    if (s.format !== 'webvtt') continue; // unknown format: skip it
    try {
      const res = await fetch(s.url);
      if (!res.ok) continue; // replaced since: the next ticket has the current URL
      const track = video.addTextTrack('subtitles', s.lang, s.lang);
      for (const c of parseVtt(await res.text())) track.addCue(new VTTCue(c.start, c.end, c.text));
      track.mode = s.lang === show ? 'showing' : 'hidden';
    } catch {
      // network error: play without this language
    }
  }
}
```

## Xong khi
- [ ] Phụ đề hiện ra, và đổi ngôn ngữ hoạt động.
- [ ] Tập không có phụ đề vẫn phát mà không báo lỗi.
- [ ] URL phụ đề trả `404` thì bị bỏ qua, và playback vẫn tiếp tục.

## Liên quan
- [Playback và vé](https://docs.wandura.ai/vi/v1/developers/concepts/playback#what-the-ticket-contains)
