按范围和预算选择
TVmaze 只提供电视剧。它是可免费使用的公开 API,按 IP 地址设置速率限制,数据遵循署名许可,详情请查阅其文档。amodb 是付费的,涵盖电视剧、电影和人物。如果你的应用是电视剧追踪器,而免费数据源能满足需求,那么 TVmaze 是不错的起点。如果你还要展示电影、演员页面或多语言海报,一个 amodb 密钥就能取代多个数据源。
不同范围对你的应用意味着什么
| 你的应用展示 | TVmaze | amodb |
|---|---|---|
| 电视剧页面 | 支持 | GET /3/tv/{series_id} |
| 剧集列表 | 支持 | GET / |
| 电影页面 | 没有电影 | GET / |
| 演员页面 | 请查阅其文档 | GET / 和合并的演职员记录 |
| 今日播出的剧集 | 请查阅其文档 | GET /3/tv/airing_today |
| 翻译后的简介 | 请查阅其文档 | language 参数,14 种语言 |
| 多个网站的评分 | 请查阅其文档 | /ratings 扩展 |
电影这一行决定了大多数情况。如果你没有电影页面,额外的范围对你就没有价值。
迁移前要检查的缺口
季和集接口遵循 TMDB 的结构,其中少数部分返回为空。请测试用到它们的页面。
- 单集演员。 在单集上,
cast是空数组。guest_stars和crew有内容,主要演员在剧集的/credits调用中。 - 季的附加内容。 季的
images、videos和translations为空,因此季海报来自季记录,而不是图片列表。 - 外部 ID。 季和集的
external_ids全为 null。请按season_number和episode_number把剧集映射到你自己的记录。 - 创作者。 大多数剧集的
created_by为空。 - 没有变更动态。 amodb 没有列出自某个日期以来有变化的剧集的接口。
功能对比
| 功能 | TVmaze | amodb |
|---|---|---|
| 定价模式 | 可免费使用的公开 API | 预付,每次购买 1 至 24 个月 |
| 免费额度 | 有,整个公开 API | 无,也没有试用 |
| 认证方式 | 请查阅其文档 | api_key 或 Bearer 请求头 |
| 响应格式 | JSON,请查阅其文档 | TMDB v3 格式的 JSON |
| 语言 | 请查阅其文档 | 14 种界面语言 |
| 电影 | 无 | 支持 |
| 电视剧 | 支持,唯一的定位 | 支持 |
| 人物 | 请查阅其文档 | 支持 |
| 图片 | 请查阅其文档 | img.amodb.dev,十种尺寸标识 |
| 评分 | 请查阅其文档 | 已知时提供五个来源 |
| 速率限制 | 按 IP 地址,具体数字请查阅其文档 | 每个密钥每分钟 20、40 或 120 次 |
| 商业使用 | 数据遵循署名许可,请查阅其文档 | 付费套餐,见定价 |
| 兼容性 | 自有 API | TMDB v3 读取接口和 OMDb |
amodb 的不同之处
- 限制跟着密钥走。 你所有的服务器共用一个计数器,窗口为 60 秒滑动窗口,响应带有
X-RateLimit-Remaining。请求从哪个地址发出并不影响计数。 - 电影、电视剧和人物集中在一处。 一个客户端、一种错误格式和一组响应头就能覆盖整个应用。
- 语言。 片名和简介可以用 14 种语言中的任意一种返回,
original_name保留原生标题。 - 成熟的协议。 为 TMDB v3 读取编写的库,换一个新的基础 URL 就能使用。剧集接口见电视剧 API页面。
TVmaze 更适合的场景
- 没有预算。 它可免费使用,学生项目或周末做的追剧工具无需付费。amodb 没有免费额度,也没有试用。
- 只做电视剧,保持简单。 如果你的数据模型里只有剧集和单集,聚焦电视剧的 API 更贴合。
- 它自己的约定。 已经围绕 TVmaze 模型构建的应用,留在原地可以省事。
如果继续使用它,请遵守其署名许可。具体措辞请查阅其文档。
迁移到 amodb
从一个映射任务开始。读取你保存的 TVmaze 记录所列出的外部 ID(字段名请查阅其文档),并通过 /3/find 解析。下面的程序把一个 IMDb ID 映射到一部剧集,并打印下一集的日期。
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type findResult struct {
TVResults []struct {
ID int `json:"id"`
Name string `json:"name"`
} `json:"tv_results"`
}
type episode struct {
AirDate string `json:"air_date"`
SeasonNumber int `json:"season_number"`
EpisodeNumber int `json:"episode_number"`
}
type series struct {
Name string `json:"name"`
Status string `json:"status"`
NextEpisode *episode `json:"next_episode_to_air"`
}
var client = &http.Client{Timeout: 10 * time.Second}
func get(path string, out any) error {
req, err := http.NewRequest(http.MethodGet, "https://api.amodb.dev/3"+path, nil)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
res, err := client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return fmt.Errorf("amodb returned %s", res.Status)
}
return json.NewDecoder(res.Body).Decode(out)
}
func main() {
var found findResult
if err := get("/find/tt0903747?external_source=imdb_id", &found); err != nil {
fmt.Println(err)
return
}
if len(found.TVResults) == 0 {
fmt.Println("no match")
return
}
var s series
if err := get(fmt.Sprintf("/tv/%d", found.TVResults[0].ID), &s); err != nil {
fmt.Println(err)
return
}
fmt.Println(s.Name, s.Status)
if s.NextEpisode != nil {
fmt.Println("next episode:", s.NextEpisode.AirDate)
}
}NextEpisode 的指针类型用来处理已完结剧集返回的 null。运行一次映射,把 amodb ID 与你的每条记录一起保存,之后改为调用 /3/tv/{id}。429 响应会带有 Retry-After,其他 ID 来源见按外部 ID 查找页面。
估算夜间同步的规模
假设你每晚刷新 300 部剧。由于一次剧集调用返回一部剧,这就是 300 个请求。每分钟 20 个请求时任务需要 15 分钟,40 个时需要 7.5 分钟,120 个时需要 2.5 分钟。请在每次调用中加上 append_,让演职员和评分在同一个请求中返回,而不是每部剧再多花两次请求。读取 X-RateLimit-Remaining,降到零时暂停,然后在 X-RateLimit-Reset 秒之后继续。
定价
amodb 采用预付方式,从不自动续费。可选择 1、3、6、12 或 24 个月,以及每分钟 20、40 或 120 个请求的套餐。较长的周期便宜 10、20、30 或 40%,每个套餐都包含全部数据。具体金额见定价。