电视剧季与单集 API
用 GET /3/tv/{series_id}/season/{season_number} 读取一季及其全部单集,再深一层读取单集。JSON 与 TMDB v3 一致,每集带 crew 和 guest_stars,第 0 季存放特别篇。
获取一季
GET / 在一个响应中返回一季及其完整的 episodes 数组。季号从 1 开始,0 保留给特别篇。剧集 ID 和季号取自电视剧记录。
示例读取《绝命毒师》第 1 季。代码为每一集打印一行。
curl -sSf "https://api.amodb.dev/3/tv/1396/season/1?language=en-US" \
-H "Authorization: Bearer $AMODB_KEY"const url = 'https://api.amodb.dev/3/tv/1396/season/1?language=en-US';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const season = await res.json();
for (const ep of season.episodes) {
console.log(String(ep.episode_number).padStart(2, '0'), ep.name, ep.air_date, `${ep.runtime ?? '?'} min`);
}import os
import requests
r = requests.get(
"https://api.amodb.dev/3/tv/1396/season/1",
params={"language": "en-US"},
headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
timeout=10,
)
r.raise_for_status()
season = r.json()
for ep in season["episodes"]:
print(f"{ep['episode_number']:02d}", ep["name"], ep["air_date"], ep["runtime"] or "?")<?php
$url = 'https://api.amodb.dev/3/tv/1396/season/1?language=en-US';
$ch = curl_init($url);
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");
}
$season = json_decode($body, true);
foreach ($season['episodes'] as $ep) {
printf("%02d %s %s\n", $ep['episode_number'], $ep['name'], $ep['air_date']);
}package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type Season struct {
Name string `json:"name"`
Episodes []struct {
EpisodeNumber int `json:"episode_number"`
Name string `json:"name"`
AirDate string `json:"air_date"`
Runtime int `json:"runtime"`
} `json:"episodes"`
}
func main() {
req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/tv/1396/season/1?language=en-US", 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 s Season
if err := json.NewDecoder(res.Body).Decode(&s); err != nil {
panic(err)
}
for _, e := range s.Episodes {
fmt.Printf("%02d %s %s %d min\n", e.EpisodeNumber, e.Name, e.AirDate, e.Runtime)
}
}参数
series_id路径必填数字形式的电视剧 ID,例如1396。season_number路径必填整数季号。0返回特别篇。api_key查询二选一你的密钥。使用它,或使用Authorization: Bearer请求头。language查询en-US或fr-FR这样的 TMDB 标签。提供 14 种基础语言。默认en-US。append_to_response查询季一级的取值:credits、external_ids、images、videos。其他名称会被忽略。
响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
id、season_number | integer | 季 ID 及其在剧中的季号。 |
name、overview | string | 本地化文本,没有译文时为空。 |
air_date | string 或 null | 第一集的日期,YYYY-MM-DD。 |
poster_path | string 或 null | 拼接到 https:/。 |
vote_average | number | 这一季的汇总用户评分。 |
episodes | array | 每一集,字段见下一节。 |
示例响应
GET /。这一季有 7 集,所以 episodes 缩减为一条,该条目的 crew 和 guest_stars 数组也被省略:
{
"air_date": "2008-01-20",
"episodes": [
{
"air_date": "2008-01-20",
"episode_number": 1,
"episode_type": "standard",
"id": 62085,
"name": "Pilot",
"overview": "When an unassuming high school chemistry teacher discovers he has a rare form of lung cancer, he decides to...",
"production_code": "",
"runtime": 59,
"season_number": 1,
"show_id": 1396,
"still_path": "/ydlY3iPfeOAvu8gVqrxPoMvzNCn.jpg",
"vote_average": 0,
"vote_count": 0
}
],
"name": "Season 1",
"overview": "High school chemistry teacher Walter White's life is suddenly transformed by a dire medical diagnosis. Stre...",
"id": 3572,
"poster_path": "/91EIXdWxmp2mHNRsSuDW3WyDJLj.jpg",
"season_number": 1,
"vote_average": 0
}季响应中的每一集还带有 crew 和 guest_stars 数组,条目结构见演职员。未播出单集的 runtime 可能为 null。
获取单集
GET / 返回一集。季响应已经包含所有带 crew 和 guest_stars 的单集,所以当你想在不重新加载整季的情况下刷新一条记录时,使用此接口。它接受 language 和 append_to_response,取值可为 credits、external_ids、images、translations 和 videos。像 / 这样的请求只算一次请求。
| 字段 | 类型 | 说明 |
|---|---|---|
id | integer | 单集 ID。 |
show_id | integer | 电视剧 ID。出现在季响应和电视剧的指针字段中,不在单集响应里。 |
season_number、episode_number | integer | 在剧中的位置。用它们构建请求路径。 |
name、overview | string | 本地化文本。 |
air_date | string 或 null | 仅日期,没有时间或时区。未排期时为 null。 |
episode_type | string | 普通单集为 standard。要识别季终集,请把 episode_number 与电视剧记录中该季的 episode_count 比较。 |
runtime | integer 或 null | 分钟。 |
production_code | string | 制片厂编码,通常为空。 |
still_path | string 或 null | 单集剧照。使用 https:/ 中的 w300 或 original。 |
vote_average、vote_count | number、integer | 汇总用户评分。 |
crew、guest_stars | array | 这一集的演职员,见演职员。 |
电视剧记录上的下一集和上一集
电视剧接口返回 next_episode_to_air 和 last_episode_to_air。每个都是单集摘要,字段同上,另外多了 show_id,少了 crew 和 guest_stars。已完结的剧和没有确认日期的在播剧,下一集为 null。示例读取在播剧《南方公园》。
const headers = { Authorization: `Bearer ${process.env.AMODB_KEY}` };
const res = await fetch('https://api.amodb.dev/3/tv/2190', { headers });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const next = (await res.json()).next_episode_to_air;
console.log(next ? `Next: S${next.season_number}E${next.episode_number} on ${next.air_date}` : 'No upcoming episode');做倒计时时,把 air_date 与访客的本地日期比较。该值不含具体时刻,所以请显示日期,而不是时钟时间。
季和单集的子资源
季和单集路径有自己的子资源。其中好几个目前返回空数据。
| 方法和路径 | 返回内容 |
|---|---|
GET / | 这一季的 id、cast 和 crew |
GET / | id 和空的 posters 数组 |
GET / | id 和空的 results 数组 |
GET / | id 加上 tvdb_id、wikidata_id 等 ID,全部为 null |
GET / | id 和空的 translations 数组 |
GET .../ | id、空的 cast、crew 和 guest_stars |
GET .../ | id 和带有该单集剧照的 stills 数组 |
GET .../ | id 和空的 results 数组 |
GET .../ | id 加上 imdb_id、tvdb_id 等 ID,全部为 null |
GET .../ | id 和 translations 数组,每种语言有名称和简介 |
季和单集的演职员见演职员,剧照见图片。amodb 不提供 TMDB 的 changes 路径,也不提供返回某个单集分组中各集的接口。
错误
| HTTP | status_code | 何时出现 |
|---|---|---|
| 401 | 7 | 密钥缺失或错误。 |
| 402 | 36 | 套餐周期已结束。 |
| 404 | 34 | 电视剧、季或单集不存在,例如没有特别篇的剧请求第 0 季,或该路径不提供。 |
| 405 | 37 | 你调用了写入方法。 |
| 429 | 25 | 超过每分钟请求数。请等待 Retry-After 秒。 |
实用说明
- 季和单集缓存 6 小时。剧集播出期间,每天重新读取当前季一两次即可。
- 一部 10 季的剧需要 10 次季调用。在每分钟 20 个请求的套餐上,这会用掉一分钟额度的一半,而 6 小时内重复运行时会由边缘缓存响应。
- 未播出的单集可能
air_date为 null、runtime为 null、overview为空。请渲染占位内容,不要报错。 - 剧照是宽画幅,不是海报。列表中请求
w300,只有需要全尺寸查看时才用original。