# 图片 API 与图片主机

> 图片接口以文件路径的形式列出作品的海报、背景图、标志、人物照片和剧照。随后从 img.amodb.dev 按固定尺寸加载每个文件，无需密钥，边缘缓存 30 天。路径和 JSON 与 TMDB v3 一致，换基础 URL 后现有图片代码即可使用。

## 接口

`GET /3/movie/{movie_id}/images`

```bash
curl "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null" \
  -H "Authorization: Bearer $AMODB_KEY"
```

响应:

```json
{
  "id": 550,
  "backdrops": [
    {
      "aspect_ratio": 1.778,
      "height": 1440,
      "iso_639_1": null,
      "file_path": "/c6OLXfKAk5BKeR6broC8pYiCquX.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2560
    },
    {
      "aspect_ratio": 1.778,
      "height": 1080,
      "iso_639_1": "en",
      "file_path": "/b9HyPoxwxjxkWEUL5ErZdhApQe2.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1920
    },
    {
      "aspect_ratio": 1.778,
      "height": 2160,
      "iso_639_1": "en",
      "file_path": "/ewMhHVyXQKMAviVWM7InPjZqpSr.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 3840
    }
  ],
  "logos": [
    {
      "aspect_ratio": 4.638,
      "height": 389,
      "iso_639_1": "en",
      "file_path": "/7Uqhv24pGJs4Ns31NoOPWFJGWNG.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1804
    },
    {
      "aspect_ratio": 0.848,
      "height": 1295,
      "iso_639_1": "en",
      "file_path": "/4XkF0Rf7gvSfea8fYLFbU5tmuJw.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1098
    },
    {
      "aspect_ratio": 1.457,
      "height": 1299,
      "iso_639_1": "en",
      "file_path": "/lm0VCzO1ZFhyx81k5Fzkex4u6C8.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1893
    }
  ],
  "posters": [
    {
      "aspect_ratio": 0.667,
      "height": 3000,
      "iso_639_1": "en",
      "file_path": "/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2000
    },
    {
      "aspect_ratio": 0,
      "height": 0,
      "iso_639_1": null,
      "file_path": "/qkrH7rjYKU4KOwwIl6wF6H3ISvm.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 0
    },
    {
      "aspect_ratio": 0,
      "height": 0,
      "iso_639_1": null,
      "file_path": "/efBb4gjjKneUoBVgfFOUu2OwihS.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 0
    }
  ]
}
```

## 获取电影的图片

`GET /3/movie/{movie_id}/images` 以三个数组列出一部电影所有已知的图片：`backdrops`、`logos` 和 `posters`。每一项有 `file_path`、像素尺寸和语言标记。JSON 里不含文件本身，你要在第二步从图片主机加载它。

示例请求英文和无文字图片，选出第一张英文海报，然后以 500 像素宽度获取该文件。

```bash
curl -s "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null" \
  -H "Authorization: Bearer $AMODB_KEY"

curl -s -o poster.jpg -w "%{http_code}\n" \
  "https://img.amodb.dev/t/p/w500/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg"
```

```js
const url = 'https://api.amodb.dev/3/movie/550/images?include_image_language=en,null';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { posters } = await res.json();
if (posters.length === 0) throw new Error('no posters');
const poster = posters.find((p) => p.iso_639_1 === 'en') ?? posters[0];
const posterUrl = `https://img.amodb.dev/t/p/w500${poster.file_path}`;
const img = await fetch(posterUrl);
console.log(img.status, img.headers.get('content-type'), posterUrl);
```

```python
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/550/images",
    params={"include_image_language": "en,null"},
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
posters = r.json()["posters"]
if not posters:
    raise SystemExit("no posters")
poster = next((p for p in posters if p["iso_639_1"] == "en"), posters[0])
poster_url = "https://img.amodb.dev/t/p/w500" + poster["file_path"]
img = requests.get(poster_url, timeout=10)
print(img.status_code, img.headers.get("content-type"), poster_url)
```

```php
<?php
$url = 'https://api.amodb.dev/3/movie/550/images?include_image_language=en,null';
$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");
}
$posters = json_decode($body, true)['posters'];
if (!$posters) {
    throw new RuntimeException('no posters');
}
$poster = $posters[0];
foreach ($posters as $p) {
    if ($p['iso_639_1'] === 'en') {
        $poster = $p;
        break;
    }
}
$posterUrl = 'https://img.amodb.dev/t/p/w500' . $poster['file_path'];
$img = curl_init($posterUrl);
curl_setopt_array($img, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10]);
curl_exec($img);
echo curl_getinfo($img, CURLINFO_HTTP_CODE), ' ', curl_getinfo($img, CURLINFO_CONTENT_TYPE), ' ', $posterUrl, PHP_EOL;
curl_close($img);
```

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

type Images struct {
	Posters []struct {
		FilePath string `json:"file_path"`
		Language string `json:"iso_639_1"`
	} `json:"posters"`
}

func main() {
	url := "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null"
	req, _ := http.NewRequest("GET", url, 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 images Images
	if err := json.NewDecoder(res.Body).Decode(&images); err != nil || len(images.Posters) == 0 {
		panic("no posters")
	}
	poster := images.Posters[0]
	for _, p := range images.Posters {
		if p.Language == "en" {
			poster = p
			break
		}
	}
	posterURL := "https://img.amodb.dev/t/p/w500" + poster.FilePath
	img, err := client.Get(posterURL)
	if err != nil {
		panic(err)
	}
	defer img.Body.Close()
	fmt.Println(img.StatusCode, img.Header.Get("Content-Type"), posterURL)
}
```

### 参数

| 参数                       | 位置 | 必填  | 说明                                                                      |
| ------------------------ | -- | --- | ----------------------------------------------------------------------- |
| `movie_id`               | 路径 | 是   | 数字形式的电影 ID，例如 `550`。                                                    |
| `api_key`                | 查询 | 二选一 | 你的密钥。使用它，或使用 `Authorization: Bearer` 请求头。                               |
| `include_image_language` | 查询 | 否   | 用逗号分隔的 ISO 639-1 代码。加上 `null` 可包含无文字图片，例如 `en,null`。只返回列出的语言。不传则返回所有语言。 |
| `language`               | 查询 | 否   | 此接口接受但会忽略它。请用 `include_image_language` 选择语言。                            |

### 响应字段

| 字段                            | 类型             | 说明                                                         |
| ----------------------------- | -------------- | ---------------------------------------------------------- |
| `id`                          | integer        | 电影 ID。                                                     |
| `backdrops`、`logos`、`posters` | array          | 每种图片一个数组，键按此顺序排列。每个都可能为空。                                  |
| `file_path`                   | string         | 以斜杠开头。把它追加到图片主机的某个尺寸后面。海报和背景图是 `.jpg`，标志是 `.png` 或 `.svg`。 |
| `width`、`height`              | integer        | 原始文件的像素尺寸。尺寸未知时为 `0`。                                      |
| `aspect_ratio`                | number         | 宽度除以高度。海报约为 0.667，背景图约为 1.778。尺寸未知时为 `0`。                  |
| `iso_639_1`                   | string 或 null  | 图片上文字的语言。`null` 表示没有文字。                                    |
| `vote_average`、`vote_count`   | number、integer | 电影和剧集的图片始终为 `0`，所以无法用来给图片排名。请保持 API 返回的顺序。                 |

### 示例响应

每个数组显示两项。

```json
{
  "id": 550,
  "backdrops": [
    {
      "aspect_ratio": 1.778,
      "height": 1440,
      "iso_639_1": null,
      "file_path": "/c6OLXfKAk5BKeR6broC8pYiCquX.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2560
    },
    {
      "aspect_ratio": 1.778,
      "height": 1080,
      "iso_639_1": "en",
      "file_path": "/b9HyPoxwxjxkWEUL5ErZdhApQe2.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1920
    }
  ],
  "logos": [
    {
      "aspect_ratio": 4.638,
      "height": 389,
      "iso_639_1": "en",
      "file_path": "/7Uqhv24pGJs4Ns31NoOPWFJGWNG.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1804
    },
    {
      "aspect_ratio": 0.848,
      "height": 1295,
      "iso_639_1": "en",
      "file_path": "/4XkF0Rf7gvSfea8fYLFbU5tmuJw.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1098
    }
  ],
  "posters": [
    {
      "aspect_ratio": 0.667,
      "height": 3000,
      "iso_639_1": "en",
      "file_path": "/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2000
    },
    {
      "aspect_ratio": 0,
      "height": 0,
      "iso_639_1": null,
      "file_path": "/qkrH7rjYKU4KOwwIl6wF6H3ISvm.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 0
    }
  ]
}
```

第二张海报展示了尺寸未知的条目。文件仍然可以加载。

## 构建图片 URL

把三部分拼在一起：`https://img.amodb.dev/t/p/`、一个尺寸段和 `file_path`。路径本身已经以斜杠开头，所以 `https://img.amodb.dev/t/p/w500` 加上 `/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg` 就是一个完整的 URL。

尺寸是 `w` 加像素宽度、`h` 加像素高度，或表示存储文件的 `original`。主机提供十种尺寸：`w92`、`w154`、`w185`、`w300`、`w342`、`w500`、`w780`、`w1280`、`h632` 和 `original`。其他任何尺寸，例如 `w400`，都返回 404。`/3/configuration` 列出每种图片类型适用的尺寸。

| 类型   | 配置字段             | 尺寸                                                  |
| ---- | ---------------- | --------------------------------------------------- |
| 海报   | `poster_sizes`   | `w92`、`w154`、`w185`、`w342`、`w500`、`w780`、`original` |
| 背景图  | `backdrop_sizes` | `w300`、`w780`、`w1280`、`original`                    |
| 标志   | `logo_sizes`     | `w92`、`w154`、`w185`、`w300`、`w500`、`original`        |
| 人物照片 | `profile_sizes`  | `w185`、`h632`、`original`                            |
| 剧照   | `still_sizes`    | `w92`、`w185`、`w300`、`original`                      |

主机不检查类型，所以海报也能以 `w1280` 加载。请使用该类型所列的尺寸，这样你的代码才与配置以及任何 TMDB 客户端一致。

图片主机无需密钥，边缘节点把每个文件缓存 30 天。因为不发送密钥，加载图片不消耗你每分钟的请求数。响应带有 `Access-Control-Allow-Origin: *`，所以浏览器可以从任何页面加载它们。未知的尺寸或未知的文件会返回 404 和一个 JSON 响应体。

## 用 srcset 实现响应式图片

选择仍能覆盖显示宽度乘以屏幕密度的最小尺寸。一张显示为 171 个 CSS 像素宽的海报，在 2x 屏幕上需要 `w342`。下面的辅助函数根据保存的路径构建 `srcset`。

```js
const WIDTHS = [185, 342, 500, 780];

function posterSrcset(filePath) {
  return WIDTHS.map((w) => `https://img.amodb.dev/t/p/w${w}${filePath} ${w}w`).join(', ');
}

const path = '/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg';
console.log(`<img src="https://img.amodb.dev/t/p/w342${path}" srcset="${posterSrcset(path)}" sizes="(max-width: 600px) 50vw, 342px" alt="Fight Club poster">`);
```

## 其他图片接口

下面所有路径都使用基础地址 `https://api.amodb.dev/3`，并返回第二列所列的数组。

| 方法和路径                                                                        | 返回的数组                               | 参数                       |
| ---------------------------------------------------------------------------- | ----------------------------------- | ------------------------ |
| `GET /tv/{series_id}/images`                                                 | `backdrops`、`logos`、`posters`       | `include_image_language` |
| `GET /tv/{series_id}/season/{season_number}/images`                          | `posters`，始终为空                      | 无                        |
| `GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/images` | `stills`，一项，`width` 和 `height` 设为 0 | 无                        |
| `GET /person/{person_id}/images`                                             | `profiles`                          | 无                        |

对于电影和剧集，你也可以在详情调用上加 `append_to_response=images`。`include_image_language` 在那里同样有效。追加的数据块没有自己的 `id`。

人物照片是 `vote_average` 带有真实评分的唯一地方。季或集响应的 `id` 是该季或该集的 ID。父级记录见[人物](https://amodb.dev/zh/people/)和[电视剧](https://amodb.dev/zh/tv-series/)。

amodb 不提供合集、公司和电视网的图片路径。它们的记录本身已包含一个 `poster_path`、`backdrop_path` 或 `logo_path`，见[系列合集](https://amodb.dev/zh/collections/)和[公司与电视网](https://amodb.dev/zh/companies-networks/)。

## 配置接口

`GET /3/configuration` 返回一个 `images` 块，其中 `secure_base_url` 设为 `https://img.amodb.dev/t/p/`，`base_url` 是纯 http 形式，还有尺寸列表 `backdrop_sizes`、`logo_sizes`、`poster_sizes`、`profile_sizes` 和 `still_sizes`。启动时读取一次，使用安全形式，并据此构建 URL，而不是把尺寸写死。边缘节点缓存它 24 小时。

## 错误

| HTTP | status_code | 何时出现                            |
| ---- | ----------- | ------------------------------- |
| 401  | 7           | JSON 调用的密钥缺失或错误。                |
| 402  | 36          | 套餐周期已结束。                        |
| 404  | 34          | 没有该 ID 的人物、季或集，或图片主机上的尺寸或文件未知。  |
| 405  | 37          | 你对图片路径使用了写入方法。                  |
| 429  | 25          | 你超过了每分钟请求数。请等待 `Retry-After` 秒。 |

不存在的电影或剧集 ID 在这里不算错误：图片路径返回 200 和空数组，而详情路径返回 404。完整列表见[错误](https://amodb.dev/zh/errors/)。图片文件请求是普通的 HTTP 加载，所以请检查响应的状态码，而不是解析 JSON 响应体。

## 实用说明

- 在数据库中保存 `file_path`，在渲染时构建 URL。这样新增尺寸或更换主机只需改一处代码。
- 把 `include_image_language` 设为你的显示语言加 `null`，例如 `ru,null`，这样带外语文字的海报就不会出现。
- 空数组是正常的 200。请回退到[电影详情](https://amodb.dev/zh/movies/)记录上的 `poster_path`。
- 全宽主视觉背景图用 `w1280`，卡片用 `w780`。`original` 是完整分辨率的存储文件，比 `w780` 大得多。
- 边缘副本保存 30 天且是共享的，所以一个客户端请求过的文件会从缓存提供给下一个客户端。

## 常见问题

### 图片请求需要 API 密钥吗？

不需要。img.amodb.dev/t/p/{size}/{file} 上的文件是公开的，可以直接用于 img 标签和 CSS。只有列出文件路径的 JSON 接口才需要你的密钥。

### 可以请求哪些图片尺寸？

w92、w154、w185、w300、w342、w500、w780、w1280、h632 和 original。其他任何尺寸都返回 404。/3/configuration 列出了每种图片类型适用的尺寸，本页的尺寸表也重复了这些内容。

### 如何只获取某一种语言的海报？

用逗号分隔的列表传入 include_image_language，例如 en,null。值 null 会加入无文字图片。只返回列出的语言。language 参数不会过滤图片。

### 为什么文件路径以斜杠开头？

TMDB 风格的路径包含开头的斜杠，这样可以直接追加到尺寸段后面。请只保存路径本身，渲染时再构建完整 URL。

## 相关页面

- [电影详情 API](https://amodb.dev/zh/movies/): 路径和 JSON 与 TMDB v3 相同的电影详情 API：按 ID 取电影，用 append_to_response 加入演职员和评分，支持 14 种语言。
- [电视剧 API](https://amodb.dev/zh/tv-series/): 路径和 JSON 与 TMDB v3 相同的电视剧 API。按 ID 获取剧集的季、电视网和下一集，以及内容分级和观看平台。
- [人物详情 API](https://amodb.dev/zh/people/): 路径和 JSON 与 TMDB v3 相同的人物详情 API。按 ID 获取演员或幕后人员，含传记、作品列表、外部 ID 和热门列表。
- [系列合集 API](https://amodb.dev/zh/collections/): 采用 TMDB v3 路径的系列合集 API：按 ID 获取系列及全部成员影片，读取电影的 belongs_to_collection，并按名称搜索合集。
- [电影海报 API 与图片 CDN](https://amodb.dev/zh/movie-poster-api/): 无需密钥的电影海报 API 与图片主机。可选 w92 到 original 的尺寸，生成 srcset，并按语言选图。
- [快速开始](https://amodb.dev/zh/quickstart/): 发出第一次 amodb 调用：获取密钥，用 curl、JavaScript、Python、PHP 或 Go 请求电影详情，再加载海报。

更新于: 2026-10-18. Source: https://amodb.dev/zh/images-api/
