发现 API
discover 在 GET /3/discover/movie 列出电影,在 GET /3/discover/tv 列出剧集,可按类型、演员、公司、关键词、日期、评分、时长、语言和流媒体平台筛选与排序。JSON 与 TMDB v3 一致,缓存 30 分钟。
发现电影
GET /3/discover/movie 返回一个分页的电影列表,这些电影匹配你发送的每个筛选条件,并按你选择的顺序排列。它是浏览页、“最佳”榜单和按维度推荐所用的接口,不需要 query 文本。如果你拿到的是用户输入的片名,请改用搜索。
示例列出至少有 1000 票的科幻电影(类型 ID 878),评分最高的在前。
curl -sSf --get "https://api.amodb.dev/3/discover/movie" \
--data-urlencode "with_genres=878" \
--data-urlencode "sort_by=vote_average.desc" \
--data-urlencode "vote_count.gte=1000" \
--data-urlencode "language=en-US" \
-H "Authorization: Bearer $AMODB_KEY"const params = new URLSearchParams({
with_genres: '878',
sort_by: 'vote_average.desc',
'vote_count.gte': '1000',
language: 'en-US',
});
const res = await fetch(`https://api.amodb.dev/3/discover/movie?${params}`, {
headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` },
});
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { results, total_pages } = await res.json();
console.log(`page 1 of ${total_pages}`);
for (const m of results.slice(0, 5)) console.log(m.vote_average, m.title, m.release_date);import os
import requests
r = requests.get(
"https://api.amodb.dev/3/discover/movie",
params={
"with_genres": 878,
"sort_by": "vote_average.desc",
"vote_count.gte": 1000,
"language": "en-US",
},
headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
timeout=10,
)
r.raise_for_status()
data = r.json()
print("page 1 of", data["total_pages"])
for m in data["results"][:5]:
print(m["vote_average"], m["title"], m["release_date"])<?php
$url = 'https://api.amodb.dev/3/discover/movie?' . http_build_query([
'with_genres' => 878,
'sort_by' => 'vote_average.desc',
'vote_count.gte' => 1000,
'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");
}
$data = json_decode($body, true);
foreach (array_slice($data['results'], 0, 5) as $m) {
echo $m['vote_average'], ' ', $m['title'], PHP_EOL;
}package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
)
type Page struct {
TotalPages int `json:"total_pages"`
Results []struct {
Title string `json:"title"`
ReleaseDate string `json:"release_date"`
VoteAverage float64 `json:"vote_average"`
} `json:"results"`
}
func main() {
q := url.Values{
"with_genres": {"878"},
"sort_by": {"vote_average.desc"},
"vote_count.gte": {"1000"},
"language": {"en-US"},
}
req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/discover/movie?"+q.Encode(), 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 p Page
if err := json.NewDecoder(res.Body).Decode(&p); err != nil {
panic(err)
}
fmt.Println("pages:", p.TotalPages)
for _, m := range p.Results {
fmt.Println(m.VoteAverage, m.Title, m.ReleaseDate)
}
}参数
| 参数 | 位置 | 必填 | 说明 |
|---|---|---|---|
api_key | 查询 | 二选一 | 你的密钥。使用它,或使用 Authorization: Bearer 请求头。 |
sort_by | 查询 | 否 | 字段和方向,例如 vote_average.desc。字段有:popularity、vote_average、vote_count、primary_release_date、revenue、title、original_title,每个后面加 .asc 或 .desc。title 和 original_title 都按原始标题排序。未知的值回退到 popularity.desc,这也是默认值。 |
with_genres | 查询 | 否 | 类型 ID。逗号表示 AND,竖线字符表示 OR。 |
without_genres | 查询 | 否 | 要排除的类型 ID。 |
with_cast、with_crew | 查询 | 否 | 人物 ID。用搜索查找。 |
with_people | 查询 | 否 | 以演员或幕后人员身份出现的人物 ID。 |
with_companies、without_companies | 查询 | 否 | 要求或排除的制作公司 ID。逗号和竖线的用法与 with_genres 相同。 |
with_keywords、without_keywords | 查询 | 否 | 要求或排除的关键词 ID。见关键词。 |
with_origin_country | 查询 | 否 | 大写的 2 位制作国家代码,例如 FR。 |
primary_release_year | 查询 | 否 | 首次上映日期的四位年份。 |
year | 查询 | 否 | 四位年份。匹配该年份内的任意上映日期,所以返回的作品比 primary_release_year 更多。 |
primary_、primary_ | 查询 | 否 | 首次上映日期的下限和上限,YYYY-MM-DD。 |
release_date.gte、release_date.lte | 查询 | 否 | 任意国家任意上映日期的下限和上限,YYYY-MM-DD。 |
region | 查询 | 否 | 大写的 2 位国家代码。把每条结果中的 release_date 替换为该国家的日期。它不会移除作品。 |
certification_country、certification | 查询 | 否 | 年龄分级筛选,例如 US 和 PG。没有国家时会忽略 certification。certification.gte 和 certification.lte 给出范围。 |
vote_average.gte、vote_average.lte | 查询 | 否 | 平均分的最小值和最大值,0 到 10。 |
vote_count.gte、vote_count.lte | 查询 | 否 | 投票数的最小值和最大值。 |
with_runtime.gte、with_runtime.lte | 查询 | 否 | 时长的最小值和最大值,单位为分钟。 |
with_original_language | 查询 | 否 | 原始语言,2 位代码,例如 fr 或 ko。 |
with_watch_providers | 查询 | 否 | 平台 ID。需要 watch_region,没有它则被忽略。ID 来自类型与查找列表。 |
watch_region | 查询 | 否 | 用于平台可用性的大写 2 位国家代码。 |
include_adult | 查询 | 否 | 接受但会被忽略。成人作品永远不会返回。 |
language | 查询 | 否 | en-US 或 pl-PL 这样的 TMDB 标签。提供 14 种基础语言。默认 en-US。 |
page | 查询 | 否 | 页码,1 到 500。默认 1。 |
响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
page、total_pages、total_results | integer | 这组筛选条件的分页信息。宽泛的筛选最多报告 1001 页和 20001 条结果,但只能读取第 1 到 500 页。 |
results | array | 最多 20 部电影。没有作品匹配全部筛选条件时为空。 |
id | integer | 用于电影详情的电影 ID。 |
title、original_title、overview | string | 本地化文本和原始标题。 |
original_language | string | 电影制作所用语言的两位代码。 |
release_date | string | YYYY-MM-DD。 |
genre_ids | array of integers | 只有 ID。用 /genre/movie/list 把它们映射为名称。 |
poster_path、backdrop_path | string 或 null | 拼接到 https:/。 |
vote_average、vote_count、popularity | number | 评分和排名数值。 |
adult、video | boolean | adult 始终为 false。 |
示例响应
{
"page": 1,
"results": [
{
"adult": false,
"backdrop_path": "/wLWvHcQz7N13DvSOTV7bHgwGXpT.jpg",
"genre_ids": [878, 12],
"id": 687163,
"original_language": "en",
"original_title": "Project Hail Mary",
"overview": "Science teacher Ryland Grace wakes up on a spaceship light years from home with no recollection of who he i...",
"popularity": 101.0341,
"poster_path": "/yihdXomYb5kTeSivtFndMy5iDmf.jpg",
"release_date": "2026-03-15",
"title": "Project Hail Mary",
"video": false,
"vote_average": 8.635,
"vote_count": 8354
},
{
"adult": false,
"backdrop_path": "/Ys8UIGWJpd2TMuQk8fU77W3mBz.jpg",
"genre_ids": [12, 18, 878],
"id": 157336,
"original_language": "en",
"original_title": "Interstellar",
"overview": "The adventures of a group of explorers who make use of a newly discovered wormhole to surpass the limitatio...",
"popularity": 74.3949,
"poster_path": "/yQvGrMoipbRoddT0ZR8tPoR7NfX.jpg",
"release_date": "2014-11-04",
"title": "Interstellar",
"video": false,
"vote_average": 8.491,
"vote_count": 41526
},
{
"adult": false,
"backdrop_path": "/tanwf7KOwQ6dxZzehKsXkffIJOd.jpg",
"genre_ids": [878, 28, 12],
"id": 969681,
"original_language": "en",
"original_title": "Spider-Man: Brand New Day",
"overview": "Fighting crime full-time as Spider-Man in a world that doesn't remember him...",
"popularity": 663.5004,
"poster_path": "/bjiS5ipwxb9JFy3XRRN4OAilSeX.jpg",
"release_date": "2026-07-29",
"title": "Spider-Man: Brand New Day",
"video": false,
"vote_average": 8.468,
"vote_count": 5684
}
],
"total_pages": 39,
"total_results": 772
}该响应取自示例请求的实时 API。它被缩减为第 1 页 20 条中的 3 条,较长的 overview 字符串也已缩短。
组合筛选条件
不同参数之间以 AND 组合。在同一个参数内,逗号表示 AND,竖线字符表示 OR。在原始 URL 中竖线写作 %7C,会对查询值编码的客户端会替你完成。
| 目标 | 请求 |
|---|---|
| 票数足够的最佳科幻片 | / |
| 动作或冒险 | / |
| 动作但不是动画 | / |
| 一位演员加一位导演 | / |
| 某一年的长片 | / |
| 某个日期窗口内的上映作品 | / |
| 某一种原始语言的电影 | / |
| 在某国流媒体平台上 | / |
| 美国 R 级 | / |
| 排除某个关键词 | / |
with_original_language 按作品制作时使用的语言筛选,它也接受 14 种提供的语言之外的代码,例如 ja 或 ko。返回文本的语言仍由 language 参数决定。在平台那一行中,8 是 Netflix。平台 ID 请从 /watch/providers/movie 读取。
发现电视剧
GET /3/discover/tv 使用相同的响应外壳和分页。条目包含 name、original_name、first_air_date、origin_country 和 genre_ids,类型 ID 来自 /genre/tv/list,其中包含合并后的电视类型 ID,例如科幻与奇幻的 10765。
| 参数 | 说明 |
|---|---|
first_air_date.gte、first_air_date.lte | 首播日期的下限和上限,YYYY-MM-DD。 |
first_air_date_year | 首播日期的四位年份。 |
air_date.gte、air_date.lte | 剧集有集数播出的日期的下限和上限,YYYY-MM-DD。 |
with_networks | 电视网 ID。在公司与电视网页查找。 |
with_status | 数字状态码:0 连载中,2 制作中,3 已完结,4 已取消。 |
with_type | 数字节目类型:0 纪录片,1 新闻,2 迷你剧,3 真人秀,4 剧本剧,5 脱口秀,6 视频。 |
sort_by | popularity、vote_average、vote_count、first_air_date、name 或 original_name,每个后面加 .asc 或 .desc。name 和 original_name 都按原始名称排序。 |
with_genres、without_genres、with_companies、with_keywords、without_keywords | 规则与电影相同。 |
vote_average.gte、vote_count.gte、with_runtime.gte、with_runtime.lte、with_original_language | 规则与电影相同。 |
with_watch_providers、watch_region、language、page | 规则与电影相同。 |
像 / 这样的请求,会列出 2025 年或更晚开播的剧情类剧集。结果的详细读取见电视剧。
错误
| HTTP | status_code | 何时出现 |
|---|---|---|
| 401 | 7 | 密钥缺失或错误。 |
| 402 | 36 | 套餐周期已结束。 |
| 405 | 37 | 你调用了写入方法。 |
| 429 | 25 | 超过每分钟请求数。请等待 Retry-After 秒。 |
| 500 | 11 | page 超出 1 到 500。 |
| 504 | 24 | 后端未能及时响应。请重试一次。 |
没有任何匹配的筛选组合不算错误。你会得到 HTTP 200,results 为空数组,total_results 为 0。见错误和速率限制。
实用说明
- 边缘节点把每组不同的筛选条件缓存 30 分钟,并在各密钥之间共享。缓存键使用排序后的查询,所以参数的顺序无关紧要。
- 每页 20 条,最后一页是 500,所以一组筛选条件最多取到 10,000 条。要更深入,请按日期窗口切分。宽泛的筛选会报告
total_results为 20001,这是上限而不是真实数量。 - 请始终把
sort_与by= vote_ average.desc vote_count.gte搭配使用。否则,只有几票的作品会挤满榜首。 - 筛选条件中的 ID 都是数字。人物 ID 从搜索获取,类型和平台 ID 从类型与查找列表获取。
- 想要现成的列表,例如热门或正在上映,请见热门趋势与列表。