---
title: "播放与分发"
description: "获取播放地址和完整播放列表，选择合适的凭据，并了解按需频道的启动与回收方式。"
---

> Documentation Index
> Fetch the complete documentation index at: https://kiln.wbxdocs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 播放与分发

频道配置完成后，还需要确定两件事：播放器该访问哪个地址，以及该使用哪类凭据。下面列出所有播放入口及其行为。

## 播放地址

每条频道对外只有一个入口，其余地址都由播放列表生成，不需要手工拼：

- `/v1/play/{id}/index.m3u8`：播放入口。HLS 频道返回改写后的上游播放列表，DASH 频道返回重封装产出的主播放列表。
- `/v1/play/{id}/live/{file}`：Kiln 本地产出的媒体播放列表、分片、初始化段与字幕，DASH 重封装路径使用。
- `/v1/play/{id}/u/{upstream}`：HLS 频道的同源回源代理。`{upstream}` 是编码后的上游地址，附带 `?sig=` 签名，且目标主机必须在允许范围内，两者任一不满足直接拒绝。

DASH 频道每次重启会换一个发布代，播放地址上带 `?g=`。媒体播放列表请求会被 307 重定向到当前代，请求已经消失的旧代返回 410 并带上 `Retry-After: 1`，播放器自己换代即可，不需要手动刷新。

分片与初始化段带长缓存头，播放列表一律 `no-store`。

## 鉴权

播放路由默认要求凭据，由 `security.play_require_auth` 控制。两种传法完全等价，查询参数优先：

```bash
curl -s "http://127.0.0.1:8080/v1/play/hls-demo/index.m3u8?token=$TOKEN"
curl -s http://127.0.0.1:8080/v1/play/hls-demo/index.m3u8 -H "authorization: Bearer $TOKEN"
```

查询参数是为了兼容播放器。多数 IPTV 客户端不会在分片请求中携带自定义请求头，因此播放列表里的地址统一通过 `?token=` 传递凭据。

带频道范围的非管理员会话只能播放范围内的频道，越界返回 403。

> **调试开关**
>
> `KILN_PLAY_OPEN=1` 会关闭播放鉴权，`KILN_PLAY_OPEN=0` 强制打开，环境变量优先于配置文件。只在本地排查时使用，任何对外可达的部署都不要开。

## 完整播放列表

`GET /v1/playlist.m3u` 返回当前全部启用频道的 M3U，只接受登录会话。管理员 API 令牌访问它会被拒绝，因为这条路由不在令牌允许访问的路由表中。

行为要点：

- 请求所用的凭据会被原样拼进每条播放地址的 `?token=`，所以这份播放列表的有效期就是会话令牌的有效期。
- 带频道范围的会话只会拿到范围内的频道。
- 节目单启用时，`#EXTM3U` 行上会带 `x-tvg-url`，指向 Kiln 自己的 EPG 地址。
- 停用的频道不会出现在结果里。

需要一份不随会话过期、可以长期交给播放器的播放列表时，用下面的播放密钥。

## 路径式播放密钥

播放密钥把凭据放进 URL 路径而不是查询参数，因此可以整条链接分发，也便于在日志里按前缀区分来源。

- `/p/{token}/playlist.m3u`：该密钥可见范围内的播放列表。
- `/p/{token}/play/{id}/index.m3u8`：播放入口。
- `/p/{token}/play/{id}/live/{file}`：本地产出的媒体资源。
- `/p/{token}/play/{id}/u/{upstream}`：同源回源代理。

这套地址下的播放列表不再附加 `?token=`，所有条目都落在 `/p/` 前缀内。

### 创建与管理

在管理控制台的「播放访问控制」里创建和维护，也可以走 `/v1/admin/access-tokens` 系列接口。

- **只展示一次**：明文只在创建时返回一次，服务端仅保存 SHA-256 摘要和前 10 位前缀，丢失只能重新创建。
- **可限定频道范围**：默认覆盖全部频道，也可以指定一个频道子集。范围外的频道返回 403，并且不会出现在该密钥的播放列表里。
- **可设有效期**：到期后自动失效。
- **随时撤销**：撤销或停用后立即拒绝，不需要重启。
- **可追溯**：每次取用都记一条播放访问日志。

### 播放访问日志

每次取用都会写入密钥前缀、频道、状态码、来源 IP 与请求路径，鉴权失败的请求同样记录。日志里的路径经过脱敏，只保留密钥前缀，完整密钥不会落盘到日志。

日志按天数保留，默认 30 天，可在设置里调整。控制台提供按密钥与频道的筛选，用来回答「这条链接被谁在什么时候用过」。

## 按需频道的冷启动与回收

从观众视角看，一条 `on_demand` 频道的完整生命周期是这样的：

1. **第一个观众触发启动**

   请求 `index.m3u8` 时如果没有正在运行的会话，Kiln 才开始拉上游。同一频道并发到达的首批请求只会触发一次启动，其余请求等待同一个结果，不会把上游打成多份连接。
2. **等待首份播放列表**

   HLS 频道拿到会话后立刻回源取播放列表。DASH 频道需要等打包器产出第一份播放列表，尚未就绪时返回 502 并附 `playlist not ready`，播放器重试即可。想消掉这段等待，用管理控制台的「立即启动」提前预热，或把频道设为启动时预热。
3. **播放期间持续续期**

   此后每次取播放列表或分片都会刷新会话的活跃时间。只要有人在看，会话就不会被回收。
4. **无人观看后回收**

   回收协程每 5 秒扫一次，`on_demand` 频道的活跃时间超过 `idle_timeout_sec`（默认 90 秒）就停掉会话、断开上游并清理工作目录。下一个观众到来时重新走一遍启动流程。

关闭 `on_demand` 而打开 `autostart` 的频道不参与回收，会一直挂着上游连接，代价是常驻内存与带宽。频繁被观看的频道适合这样配，其余保持按需即可。

配置了 `max_viewers` 的频道还多一层观众租约：入口请求会被 307 重定向补上一枚签名过的 `viewer=` 参数，租约在 1 分钟内没有续期就失效，超出上限的新观众收到 429。

## 播放列表改写

HLS 频道的上游播放列表在返回给播放器之前会被改写：相对地址解析成绝对地址，需要经由 Kiln 回源的条目改指向 `/v1/play/{id}/u/...` 并附签名。是否改写由出站策略 `playlist_policy` 决定，默认 `rewrite`；配置了 `max_viewers` 的频道无条件改写，否则观众数无从统计。策略取值与按域名的路由规则见 [出站代理](/guide/proxy/)。

Source: https://kiln.wbxdocs.com/guide/playback/index.mdx
