# Catalog

> **TL;DR** — `GET /catalog` liệt kê mọi phim và tập mà tổ chức của bạn được stream ngay lúc này, kèm thứ tự hiển thị, quy tắc tập miễn phí và cờ sẵn sàng cho từng tập. Chỉ có metadata, không bao giờ có URL video. Lấy cả catalog một lần, hoặc theo trang bằng `limit` và `cursor`. Đây là danh sách phim duy nhất app của bạn cần; request xin vé đằng nào cũng kiểm tra lại mọi thứ.

## Catalog chứa gì
Một phim được liệt kê khi, tại thời điểm request:

- tổ chức của bạn có giấy phép streaming cho phim, và giấy phép đó đang hoạt động;
- hôm nay (UTC) nằm trong khung thời gian của giấy phép, tính theo ngày trọn vẹn, gồm cả ngày đầu và ngày cuối;
- phim đã được publish.

Với những phim đó, catalog liệt kê mọi tập đã publish, cộng một dòng placeholder cho mỗi tập dự kiến chưa publish. Phim còn đang sản xuất và bản dựng thô (review cut) không bao giờ xuất hiện và không phát được qua API. Response rỗng (`"films": []`) nghĩa là lúc này tổ chức của bạn không có giấy phép nào đang hoạt động.

## Cấu trúc response
Hai mảng phẳng, `films` và `episodes`; nối chúng theo `episodes[].film_id` = `films[].id`. Response còn mang `links` (`self`, `next`, `playback`, `config`). Mọi trường: [Lấy catalog được cấp phép](https://docs.wandura.ai/vi/v1/developers/reference/catalog).

## Trang
Không có `limit` hay `cursor` thì bạn nhận cả catalog trong một response. Có `limit` (1–200 phim) thì bạn nhận một trang phim kèm **mọi** tập của chúng, cộng `next_cursor` và `links.next`; gửi lại cursor nguyên văn cho tới khi nó là `null`. Các trang **không** phải một ảnh chụp nhất quán: luật đồng bộ an toàn nằm ở [Hành vi chuẩn của API · Pagination](https://docs.wandura.ai/vi/v1/developers/reference/behaviour#pagination), còn code nằm ở [Đồng bộ catalog](https://docs.wandura.ai/vi/v1/developers/guides/catalog-sync).

## Thứ tự
`films` được sắp theo `display_order`, nhỏ nhất trước, và giữ thứ tự đó qua các trang. Hiển thị phim đúng thứ tự này; Wandura chỉnh thứ tự, nên đừng giữ bảng thứ tự riêng. `episodes` được nhóm theo phim, rồi theo `episode_no`; hãy lấy thứ tự phim từ `films`.

## Tập miễn phí và tập trả phí
Tập có `episode_no` ≤ `free_until_episode` của phim là miễn phí; các tập còn lại là trả phí. `0` nghĩa là không có tập miễn phí; `null` nghĩa là chưa đặt số này, nên hãy coi mọi tập là trả phí. Giá trị khác nhau giữa các phim và có thể thay đổi: đọc lại ở mỗi lần đồng bộ.

## Tập dự kiến
`planned_episodes` là số tập phim sẽ có. Với mỗi tập chưa publish, catalog có một dòng placeholder để bạn hiển thị "sắp ra mắt":

| Trường | Giá trị |
|---|---|
| `id` | `null` |
| `status` | `"planned"` |
| `stream_ready` | `false` |
| `title`, `synopsis`, `duration_ms`, `poster_uri`, `poster_url` | `null` |

Không bao giờ gửi dòng placeholder tới `POST /playback`: nó không có ID. Khi `planned_episodes` là `null`, không có dòng placeholder nào.

## Trạng thái sẵn sàng: `stream_ready`
`true` nghĩa là lúc này có thể cấp vé cho tập. Làm mờ hoặc ẩn các tập có giá trị `false`. Cờ này là ảnh chụp tại lúc bạn tải catalog: request xin vé kiểm tra lại, và câu trả lời của nó mới có giá trị. Nhận `not_ready` cho một tập từng có `stream_ready: true` là bình thường, ví dụ ngay sau khi phim bị rút.

## Facet thể loại
| Trường | Giá trị (`null` = chưa phân loại; có thể có giá trị mới) |
|---|---|
| `audience` | `women`, `men`, `lgbtq` |
| `form` | `live_action`, `anime` |
| `setting` | `modern`, `city`, `fantasy`, `campus`, `palace` |

Phim còn có `genres` (nhãn văn bản tự do) và `language` (văn bản tự do: hiển thị, đừng parse).

## Văn bản và ảnh
- `synopsis_short` dùng cho thẻ, `synopsis_full` dùng cho trang chi tiết; độ dài khác nhau, hãy clamp. Cả hai đều có thể là `null`.
- `poster_url` (phim) có thể là `null` trong lúc ảnh đang được chuẩn bị: hiển thị ảnh placeholder.
- Với tập, dùng `poster_url` (URL `https` tải được, hoặc `null`, khi đó lui về poster của phim). `poster_uri` là tham chiếu nội bộ, không phải URL tải được.

Mỗi phim còn có `images`, ảnh của phim theo loại, mỗi phần tử `{ "kind", "url", "width", "height" }`:

| `kind` | Là gì | `width` / `height` |
|---|---|---|
| `poster_3_4` | Poster thẻ tỉ lệ 3:4 | pixel, đo từ chính file |
| `cover_9_16` | Ảnh bìa toàn màn hình 9:16, cùng ảnh với `poster_url` | tạm thời là `null` (chưa ghi kích thước) |

Loại Wandura chưa có thì không có mặt, nên mảng có thể rỗng; mảng không bao giờ chứa phần tử `null`. Mọi `url` là URL `https` tuyệt đối trên host của Wandura, tải thẳng được. Có thể có loại mới: bỏ qua loại bạn không biết. `poster_url` giữ nguyên như cũ.

## Độ mới
Một thay đổi phía Wandura (publish, rút phim, giấy phép bắt đầu hay kết thúc) xuất hiện trong catalog trong vòng 30 giây. Mọi mốc thời gian: [Hành vi chuẩn của API · Độ mới](https://docs.wandura.ai/vi/v1/developers/reference/behaviour#freshness). Đồng bộ mỗi 15–60 phút từ server của bạn; không bao giờ gọi catalog mỗi lần mở app.

## Liên quan
- [Đồng bộ catalog](https://docs.wandura.ai/vi/v1/developers/guides/catalog-sync)
- [Lấy catalog được cấp phép](https://docs.wandura.ai/vi/v1/developers/reference/catalog)
- [Khi quyền kết thúc](https://docs.wandura.ai/vi/v1/developers/production/rights-end)
