发现 API

discover 在 GET /3/discover/movie 列出电影,在 GET /3/discover/tv 列出剧集,可按类型、演员、公司、关键词、日期、评分、时长、语言和流媒体平台筛选与排序。JSON 与 TMDB v3 一致,缓存 30 分钟。

更新于 以 Markdown 查看

发现电影

GET /3/discover/movie 返回一个分页的电影列表,这些电影匹配你发送的每个筛选条件,并按你选择的顺序排列。它是浏览页、“最佳”榜单和按维度推荐所用的接口,不需要 query 文本。如果你拿到的是用户输入的片名,请改用搜索。

示例列出至少有 1000 票的科幻电影(类型 ID 878),评分最高的在前。

bashjspyphpgo
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_release_date.gte、primary_release_date.lte查询否首次上映日期的下限和上限,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_resultsinteger这组筛选条件的分页信息。宽泛的筛选最多报告 1001 页和 20001 条结果,但只能读取第 1 到 500 页。
resultsarray最多 20 部电影。没有作品匹配全部筛选条件时为空。
idinteger用于电影详情的电影 ID。
title、original_title、overviewstring本地化文本和原始标题。
original_languagestring电影制作所用语言的两位代码。
release_datestringYYYY-MM-DD。
genre_idsarray of integers只有 ID。用 /genre/movie/list 把它们映射为名称。
poster_path、backdrop_pathstring 或 null拼接到 https://img.amodb.dev/t/p/{size}。
vote_average、vote_count、popularitynumber评分和排名数值。
adult、videobooleanadult 始终为 false。

示例响应

JSON
{
  "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,会对查询值编码的客户端会替你完成。

目标请求
票数足够的最佳科幻片/discover/movie?with_genres=878&sort_by=vote_average.desc&vote_count.gte=1000
动作或冒险/discover/movie?with_genres=28%7C12
动作但不是动画/discover/movie?with_genres=28&without_genres=16
一位演员加一位导演/discover/movie?with_cast=6193&with_crew=525
某一年的长片/discover/movie?primary_release_year=2010&with_runtime.gte=150
某个日期窗口内的上映作品/discover/movie?primary_release_date.gte=2026-10-01&primary_release_date.lte=2026-10-31
某一种原始语言的电影/discover/movie?with_original_language=fr
在某国流媒体平台上/discover/movie?with_watch_providers=8&watch_region=US
美国 R 级/discover/movie?certification_country=US&certification=R
排除某个关键词/discover/movie?with_keywords=818&without_keywords=4565

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_bypopularity、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规则与电影相同。

像 /discover/tv?first_air_date.gte=2025-01-01&with_genres=18&vote_count.gte=100&sort_by=popularity.desc 这样的请求,会列出 2025 年或更晚开播的剧情类剧集。结果的详细读取见电视剧。

错误

HTTPstatus_code何时出现
4017密钥缺失或错误。
40236套餐周期已结束。
40537你调用了写入方法。
42925超过每分钟请求数。请等待 Retry-After 秒。
50011page 超出 1 到 500。
50424后端未能及时响应。请重试一次。

没有任何匹配的筛选组合不算错误。你会得到 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 从类型与查找列表获取。
  • 想要现成的列表,例如热门或正在上映,请见热门趋势与列表。