电视剧季与单集 API

用 GET /3/tv/{series_id}/season/{season_number} 读取一季及其全部单集,再深一层读取单集。JSON 与 TMDB v3 一致,每集带 crew 和 guest_stars,第 0 季存放特别篇。

更新于 以 Markdown 查看

获取一季

GET /3/tv/{series_id}/season/{season_number} 在一个响应中返回一季及其完整的 episodes 数组。季号从 1 开始,0 保留给特别篇。剧集 ID 和季号取自电视剧记录。

示例读取《绝命毒师》第 1 季。代码为每一集打印一行。

bashjspyphpgo
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_numberinteger季 ID 及其在剧中的季号。
name、overviewstring本地化文本,没有译文时为空。
air_datestring 或 null第一集的日期,YYYY-MM-DD。
poster_pathstring 或 null拼接到 https://img.amodb.dev/t/p/{size}。
vote_averagenumber这一季的汇总用户评分。
episodesarray每一集,字段见下一节。

示例响应

GET /3/tv/1396/season/1?language=en-US。这一季有 7 集,所以 episodes 缩减为一条,该条目的 crew 和 guest_stars 数组也被省略:

JSON
{
  "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 /3/tv/{series_id}/season/{season_number}/episode/{episode_number} 返回一集。季响应已经包含所有带 crew 和 guest_stars 的单集,所以当你想在不重新加载整季的情况下刷新一条记录时,使用此接口。它接受 language 和 append_to_response,取值可为 credits、external_ids、images、translations 和 videos。像 /3/tv/1396/season/1/episode/1?append_to_response=credits 这样的请求只算一次请求。

字段类型说明
idinteger单集 ID。
show_idinteger电视剧 ID。出现在季响应和电视剧的指针字段中,不在单集响应里。
season_number、episode_numberinteger在剧中的位置。用它们构建请求路径。
name、overviewstring本地化文本。
air_datestring 或 null仅日期,没有时间或时区。未排期时为 null。
episode_typestring普通单集为 standard。要识别季终集,请把 episode_number 与电视剧记录中该季的 episode_count 比较。
runtimeinteger 或 null分钟。
production_codestring制片厂编码,通常为空。
still_pathstring 或 null单集剧照。使用 https://img.amodb.dev/t/p/{size} 中的 w300 或 original。
vote_average、vote_countnumber、integer汇总用户评分。
crew、guest_starsarray这一集的演职员,见演职员。

电视剧记录上的下一集和上一集

电视剧接口返回 next_episode_to_air 和 last_episode_to_air。每个都是单集摘要,字段同上,另外多了 show_id,少了 crew 和 guest_stars。已完结的剧和没有确认日期的在播剧,下一集为 null。示例读取在播剧《南方公园》。

JavaScript
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 /tv/{series_id}/season/{season_number}/credits这一季的 id、cast 和 crew
GET /tv/{series_id}/season/{season_number}/imagesid 和空的 posters 数组
GET /tv/{series_id}/season/{season_number}/videosid 和空的 results 数组
GET /tv/{series_id}/season/{season_number}/external_idsid 加上 tvdb_id、wikidata_id 等 ID,全部为 null
GET /tv/{series_id}/season/{season_number}/translationsid 和空的 translations 数组
GET .../episode/{episode_number}/creditsid、空的 cast、crew 和 guest_stars
GET .../episode/{episode_number}/imagesid 和带有该单集剧照的 stills 数组
GET .../episode/{episode_number}/videosid 和空的 results 数组
GET .../episode/{episode_number}/external_idsid 加上 imdb_id、tvdb_id 等 ID,全部为 null
GET .../episode/{episode_number}/translationsid 和 translations 数组,每种语言有名称和简介

季和单集的演职员见演职员,剧照见图片。amodb 不提供 TMDB 的 changes 路径,也不提供返回某个单集分组中各集的接口。

错误

HTTPstatus_code何时出现
4017密钥缺失或错误。
40236套餐周期已结束。
40434电视剧、季或单集不存在,例如没有特别篇的剧请求第 0 季,或该路径不提供。
40537你调用了写入方法。
42925超过每分钟请求数。请等待 Retry-After 秒。

完整的响应体格式见错误,各窗口见速率限制。

实用说明

  • 季和单集缓存 6 小时。剧集播出期间,每天重新读取当前季一两次即可。
  • 一部 10 季的剧需要 10 次季调用。在每分钟 20 个请求的套餐上,这会用掉一分钟额度的一半,而 6 小时内重复运行时会由边缘缓存响应。
  • 未播出的单集可能 air_date 为 null、runtime 为 null、overview 为空。请渲染占位内容,不要报错。
  • 剧照是宽画幅,不是海报。列表中请求 w300,只有需要全尺寸查看时才用 original。