Music API
开发者文档 / API v1
文档目录

Music API 接入文档#

版本:v1 · 更新:2026-10-20 · 基础地址:https://music.op.wiki

在线阅读 · OpenAPI JSON · Python 下载脚本

应用分流已于 2026-10-20 00:04:35(UTC+8)发布:页面、API、歌词、封面及生成中音频保持 https://music.op.wiki;仅 completed 普通音频和 ALAC packet 使用 https://music.zr.wiki(Cloudflare)。music.op.wiki 的入口方案为中国大陆走 AxisNow、海外走 Cloudflare,DNS 配置尚待迁移侧完成;应用配置保持不变,本次应用发布未修改 DNS/CDN。同源配置仍受支持;始终使用 API 实际返回的完整 URL,不自行换域名。

本接口提供音乐搜索、音频准备与下载、歌词、推荐和歌单解析。最常用的下载流程是:

搜索取得歌曲 ID → 创建播放任务 → 等待 completed → 下载 audio_url。

1. 下载一首歌#

1.1 搜索并确认歌曲#

下面示例使用 Apple Music;可替换平台及搜索词。

curl --fail-with-body --silent --show-error --get \
  'https://music.op.wiki/api/v1/search' \
  --data-urlencode 'platform=applemusic' \
  --data-urlencode 'q=晴天 周杰伦' \
  --data-urlencode 'limit=5'

返回数组,每项包含 id、song、singer、cover 和 platform。核对歌名、歌手及版本,把选中项的 id 作为下一步的 selected_id。不要把播放任务 ID 当作平台歌曲 ID。

1.2 创建任务#

将下面两处占位内容替换为上一步确认的歌曲 ID 和歌名:

curl --fail-with-body --silent --show-error \
  'https://music.op.wiki/api/v1/playbacks' \
  -H 'Content-Type: application/json' \
  --data '{
    "platform": "applemusic",
    "query": "替换为歌曲名",
    "selected_id": "替换为搜索结果的id",
    "quality": "hires",
    "include_cover": false
  }'

普通下载省略 streaming_mode。指定了 selected_id,query 仍然必须填写非空字符串。

响应结构示意:

{
  "playback": {
    "id": "applemusic--示例歌曲ID--hires",
    "status": "queued",
    "quality": "hires"
  },
  "status_url": "/api/v1/playbacks/applemusic--示例歌曲ID--hires",
  "audio_url": "/api/v1/playbacks/applemusic--示例歌曲ID--hires/audio?rev=example-native-revision",
  "cover_url": "/api/v1/playbacks/applemusic--示例歌曲ID--hires/cover",
  "lyrics_url": "/api/v1/playbacks/applemusic--示例歌曲ID--hires/lyrics"
}

这里省略了 playback 的其他字段。实际返回的 ID 和 rev 由服务器生成,直接使用响应中的 URL,不要照抄示例值。

  • 200:已经完成,可进入下载步骤。
  • 202:任务已接受或正在复用尚未完成的任务,需要继续查询。
  • 状态以 playback.status 为准。命中缓存可能直接得到 completed。

1.3 等待 completed#

以 API 基础地址解析响应的 status_url;状态请求始终留在 API 域。例如:

curl --fail-with-body --silent --show-error \
  'https://music.op.wiki/api/v1/playbacks/替换为实际任务ID'

查询接口直接返回任务对象,读取顶层 status,没有 playback 包装。

status 含义 下载客户端的处理
queued 已排队 等待后再查询
processing 准备音频中 等待后再查询
streaming 部分流式内容已可用,整首尚未完成 普通文件下载继续等待
completed 音频准备完成 下载 audio_url
failed 准备失败 停止轮询,显示 error

建议每 1–2 秒查询一次,并设置总等待时限,例如 10 分钟。这是客户端建议,不是服务端承诺的准备时长。不要为轮询重复 POST,也不要并行发送相同状态查询。

相同状态 URL 出现多次是正常轮询,不代表重复下载了歌曲。completed 后首次读取文件仍可能需要恢复缓存或生成兼容音频,下载请求的读取超时不宜过短。

1.4 保存文件#

仅在 completed 后,使用最新状态响应中的 audio_url。同源配置返回相对路径,须以 https://music.op.wiki 解析;双 CDN 配置返回 https://music.zr.wiki 的绝对媒体 URL。queued/processing/streaming 阶段的媒体地址仍为 API 域相对路径。不要沿用较早状态的旧地址,也不要自行替换域名或丢弃查询参数:

# 将最新 completed 响应的 audio_url 原样填入,保留查询参数。
AUDIO_PATH='替换为返回的audio_url'
AUDIO_URL="$(python3 -c 'import sys; from urllib.parse import urljoin; print(urljoin("https://music.op.wiki/", sys.argv[1]))' "$AUDIO_PATH")"
curl --fail --show-error --location \
  --connect-timeout 15 --max-time 900 \
  --remote-name --remote-header-name \
  "$AUDIO_URL"

这个响应是音频字节,不是 JSON。保存格式应以这次文件响应的 Content-Type 和 Content-Disposition 为准。

特别是 Apple Music 的 Lossless/Hi-Res:任务中的 format 可能是 m4a,而 audio_url 实际返回兼容的无损 audio/flac。不要硬改成 .mp3,也不要使用任务的 byte_size 校验兼容文件长度。应使用文件响应自身的 Content-Length(若有)。

audio_url 返回无损兼容文件,不提供“保证原始 ALAC 容器字节不变”的下载接口。source_url 是原平台来源链接,不是本服务下载地址。

1.5 用脚本自动完成#

下载本页附带的 download_song.py,仅依赖 Python 3 标准库:

# 用上一步的真实歌曲 ID 替换占位内容。
python3 download_song.py \
  --platform applemusic \
  --query '歌曲名 歌手' \
  --id '搜索结果中的id' \
  --quality hires

也可以只传某首歌的公开平台链接,由服务端解析:

python3 download_song.py \
  --platform applemusic \
  --query '替换为完整的Apple Music单曲链接' \
  --quality lossless

不传 --id 而只给搜索词时,平台会自行解析结果,不能保证就是你想要的版本;需要精确下载时先搜索并传 ID。省略 --output 会根据文件响应命名;可用 --output ./指定文件名.flac 自行指定正确扩展名。脚本不会覆盖已有文件,下载失败会清理自己创建的临时文件。

多首兼容 FLAC 的服务端文件名可能同为 browser-lossless.flac;下载第二首时请用 --output 指定不同文件名,或保存到不同目录。

--timeout 控制任务准备总时限,默认 600 秒;--read-timeout 控制音频响应的单次网络等待,默认 120 秒,首次生成兼容文件较慢时可调大,例如 --read-timeout 900。运行 python3 download_song.py --help 查看选项。脚本会串行查询状态、等待整首完成、流式写入文件,保留所选音质;不会一次把整首音频读入内存。

脚本默认以 https://music.op.wiki 解析相对地址,并已信任其返回的 https://music.zr.wiki 完成媒体地址;两种配置均无需修改下载器或额外传入 --media-base-url,脚本不会改写返回的 URL。API 轮询只访问 --base-url。自建服务若使用其他媒体域,显式传入 --base-url https://api.example.com --media-base-url https://media.example.com。所有请求不会携带 Cookie、Authorization 或浏览器会话。脚本使用明确的 MusicAPI-Downloader User-Agent;不需要伪装浏览器,也不要转发个人登录信息。

2. 通用约定#

项目 约定
基础地址 https://music.op.wiki
路径前缀 /api/v1;健康检查为 /health
请求 / 响应 JSON 使用 UTF-8;音频和封面接口返回二进制
认证 当前部署不要求 API Key 或调用者登录
请求头 JSON POST 需要 Content-Type: application/json
浏览器头 不需要复制 Cookie、Referer、sec-ch-ua 或伪装 User-Agent
URL 同时支持相对路径与绝对 URL,使用 new URL(task.audio_url, base) 或 Python urljoin(base, task["audio_url"]);保留全部查询参数
完成媒体 双 CDN 配置下,仅 completed 的 /audio 与 /audio/stream 使用 https://music.zr.wiki;未配置媒体域时保持同源,始终以 API 返回的 URL 为准
动态请求 queued/processing/streaming 的媒体地址、页面、API、状态、歌词和封面保持 https://music.op.wiki
时间 / 大小 API 的 duration 为秒,byte_size 为字节,bitrate 为 bit/s
空值 可选元数据可能为 null 或空字符串;调用方应允许将来新增字段

媒体使用匿名 GET/HEAD/Range,不需要 Cookie 或 Authorization。独立媒体域的跨域访问须允许浏览器读取 Content-Disposition、Content-Length、Content-Range、Accept-Ranges、Content-Encoding 和 X-Audio-Stream-Id;命令行 curl/Python 不受浏览器 CORS 限制。状态、搜索、推荐和歌词始终请求 API 基础地址;媒体域不是新的 API 入口。

同一平台、歌曲、音质通常复用同一任务;ID 不是用户专属,也不是鉴权凭据。应把它当成不透明字符串保存,不依赖其内部拼接规则。不同音质分别创建任务,播放/下载时提交当前所需音质。

当前没有取消任务、批量下载、账户管理或服务器端私人歌单管理接口。关闭连接不等于取消服务端准备任务。任务不是永久下载凭证;若状态返回 404,可以用原始平台、歌曲 ID、query 和音质重新创建。

3. 平台与音质#

平台#

使用 GET /api/v1/platforms 获取实时列表和别名。当前规范 ID:

平台 platform
Apple Music applemusic
Bilibili bilibili
酷狗音乐 kugou
网易云音乐 netease
汽水音乐 soda
QQ 音乐 tencent
YouTube Music youtubemusic

平台出现在列表中不表示所有曲目、地区和音质始终可用;平台能力及上游状态可能不同。推荐接口目前仅支持 Apple Music;歌单/专辑解析目前支持 Apple Music、网易云。

音质#

quality 建议用途
standard 标准音质
high 高品质;默认值
lossless 无损音质
hires 高解析无损音质

外部接入建议使用上表小写规范值。quality 表示请求档位,并不保证源曲目拥有对应采样率或编码。Apple Music 的 Lossless 优先选择最高 48 kHz 以内的无损变体,Hi-Res 优先选择更高采样率;其他平台按自身能力处理。实际文件格式以下载响应为准,不把 quality 当作扩展名。

4. 接口速查#

方法 路径 用途
GET /health 服务健康检查
GET /api/v1/platforms 平台列表
GET /api/v1/search 搜索歌曲
POST /api/v1/playbacks 创建或复用播放任务
GET /api/v1/playbacks/{id} 查询任务状态
GET /api/v1/playbacks/{id}/audio 普通播放 / 文件下载
GET /api/v1/playbacks/{id}/audio/stream 专用 WASM ALAC 分包流
GET /api/v1/playbacks/{id}/cover 封面
GET /api/v1/lyrics 通过平台歌曲 ID 获取歌词
GET /api/v1/playbacks/{id}/lyrics 通过任务获取歌词
GET /api/v1/playbacks/{id}/loudness 响度测量
GET /api/v1/recommendations 推荐歌曲
GET /api/v1/recommendations/home 推荐首页分区
GET / POST /api/v1/recommendations/continue 队列续播候选
GET /api/v1/collections/resolve 解析公开歌单 / 专辑
POST /api/v1/collections/match 跨平台歌曲匹配

机器可读参数与数据模型见 OpenAPI JSON,可导入支持 OpenAPI 3.0 的接口工具。以下为接入时常用说明。

5. 搜索、任务和下载接口#

GET /health#

返回:

{"status":"ok","service":"music-api"}

它确认服务可响应,不代表所有上游平台的下载能力均已通过检查。

GET /api/v1/platforms#

返回数组:[{ "id": "applemusic", "label": "Apple Music", "aliases": ["am", "..."] }]。示例中的省略号仅用于简写;实际 aliases 是完整别名数组。

GET /api/v1/search#

参数 必填 默认 / 限制 说明
platform 是 平台 ID 或别名 搜索平台
q 是 建议提供非空关键词 歌名、歌手等搜索内容
limit 否 10;按 1–20 裁剪 结果数量上限

返回 SearchItem[]:

[
  {
    "platform": "applemusic",
    "id": "示例歌曲ID",
    "song": "示例歌名",
    "singer": "示例歌手",
    "cover": "https://example.com/cover.jpg"
  }
]

cover 可能为空字符串。搜索不创建播放任务。

POST /api/v1/playbacks#

JSON 字段 必填 默认 说明
platform 是 无 平台 ID / 别名
query 是 无 非空歌曲名、链接或平台 ID
selected_id 否 null 精确指定搜索结果 ID,优先于 query 解析
quality 否 high 建议 standard / high / lossless / hires
include_cover 否 true 是否请求准备封面;只下载音频建议 false
streaming_mode 否 null 仅专业播放器使用 wasm_alac;普通下载省略

返回 {playback, status_url, audio_url, cover_url, lyrics_url}。字段 URL 即使在 queued 状态也会出现,URL 存在不代表文件已就绪。同任务复用时,已有任务的封面准备方式等设置不一定被新的请求覆盖。

应用只识别 wasm_alac 作为特殊传输模式,其他值按未指定处理。不要通过未知 mode 请求其他输出格式。

GET /api/v1/playbacks/{id}#

返回 PlaybackTask,核心字段如下。所有可空字段在早期状态可能没有值。

字段 类型 说明
id / status string 不透明任务 ID / 五种任务状态
platform / query / quality string 规范平台、原始查询和请求音质
track_id / selected_id string 或 null 解析后的平台歌曲 ID;未手动传 selected_id 时也可能填入解析结果
include_cover boolean 任务的封面准备设置
title / artist / album string 或 null 歌名 / 歌手 / 专辑
source_url string 或 null 平台来源链接,不是音频下载 URL
format / content_type string 或 null 任务源文件元信息,可能与兼容 audio 响应不同
byte_size / bitrate / duration number 或 null 源文件字节数、bit/s、秒
decrypt_elapsed_seconds number 或 null 解密耗时,秒;非所有路径都有
error string 或 null failed 时的失败信息
streaming_mode string 或 null 协商的传输模式
streaming_codec / streaming_protocol string 或 null ALAC 时为 alac / splayer-alac-v2
media_revision string 不透明的本次媒体生成标识;不是内容哈希,也不表示永久不可变
audio_url string 标准音频地址;completed 时可为配置媒体域的绝对 URL,其他状态或同源配置返回 API 域相对路径
cover_url / lyrics_url string API 域相对路径
streaming_url string 或 null 专用分包地址,不是常规音乐文件;completed 时可为配置媒体域的绝对 URL,生成中或同源配置返回相对路径

任务在多个客户端间共享:即使本次创建没有请求 WASM,后续状态查询也可能带回另一客户端协商的 wasm_alac 字段。普通下载客户端仍按 completed → audio_url 处理,不自动改用 streaming_url。

GET /api/v1/playbacks/{id}/audio#

  • completed:返回可供常规播放器使用的音频。首次访问可能仍需恢复远端缓存或准备无损兼容文件。
  • streaming 且是原生 AAC 路径:可以返回持续增长的 audio/mp4,供支持它的播放器使用;普通下载仍建议等待 completed。
  • streaming 且是 WASM ALAC 路径:该端点返回 409,等待 completed;分包播放器使用下一节的专用地址。
  • queued、processing、failed 等未完成状态:409。未知任务:404。

常见成功响应:

HTTP/1.1 200 OK
Content-Type: audio/flac
Content-Disposition: inline; filename="browser-lossless.flac"
Content-Length: 12345678
Accept-Ranges: bytes
Cache-Control: public, max-age=86400, no-transform

上面长度仅为示例。接口使用 inline;浏览器直接打开可能播放音频,而非弹出“另存为”。下载程序应主动保存响应体。

完成的本地文件支持单段 Range:

Range: bytes=0-1048575
Range: bytes=1048576-
Range: bytes=-4096

每次只使用其中一种。206 响应通过 Content-Range 表示返回范围。多段、越界或无效范围可能返回 416;仍在增长的流不支持随机 Range。远端缓存路径是否返回 206 取决于上游响应,不能无条件假定续传成功。

需要续传时,可用 curl --continue-at - --output 已有部分文件 "$AUDIO_URL",并确认服务器接受范围请求;不要把返回的 200 完整文件直接拼接到旧内容后。完成成功媒体使用 Cache-Control: public, max-age=86400, no-transform,可按正常浏览器/CDN 缓存语义读取,不要额外发送 Cache-Control: no-store。生成中音频使用 no-store, no-transform;动态 API、未就绪及错误响应使用 no-store。

任务 ID(包括旧客户端的 v=任务ID 参数)不是内容哈希。任务的 media_revision 表示本次媒体生成实例,返回 URL 中的 rev 进一步区分普通音频与 ALAC packet 表示。rev 在同一次生成从 streaming 变为 completed 时保持不变,重新生成后可能改变。它仍不是内容哈希,不能作为无限缓存依据。保留完整 URL;旧 rev 与当前版本不符时,源站返回 409 与 no-store,重新读取任务状态获得当前地址。旧客户端不传 rev 仍兼容,但没有此版本保护。

续传时还须确认 X-Audio-Stream-Id 与旧文件一致,并检查 206、Content-Range、总长度及无内容编码;身份不符时重新下载,不拼接两次生成的文件。缓存中的历史完成版本可能在 24 小时内继续由 CDN 提供,因此应结合版本 URL 和文件身份校验,不仅依赖任务 ID。

GET /api/v1/playbacks/{id}/audio/stream#

高级接口,仅用于明确支持本项目协议的解码器:

  • 创建时请求 streaming_mode: "wasm_alac",但最终以服务器返回的 transport 字段为准;不保证每个平台/文件都提供它。
  • 返回 application/x-splayer-alac,协议标记 SPLALAC1,版本 2,包含 ALAC cookie 和分包长度、时长、数据。
  • 可在 streaming 时持续接收并解码;completed 后可读取完整分包文件。
  • 未协商该模式返回 406;尚无可用流返回 409。
  • 这不是 MP3、FLAC、普通 M4A 或标准 HLS。不要将它直接交给普通 <audio>,也不要把保存结果改名为这些格式。
  • 完整分包流的 Range 与普通音频文件的 Range 是两种不同表示,不能拼接混用。
  • 分包流在生成中使用 API 域;双 CDN 配置下,completed 后的完整分包 URL 使用媒体域,同源配置仍使用 API 域。保留全部参数,缓存及身份校验要求与普通完成音频相同,不能因换域而跳过 rev、X-Audio-Stream-Id 或 Range 校验。

下载普通歌曲文件无需调用此接口。

GET /api/v1/playbacks/{id}/cover#

返回图片字节。任务未完成返回 409,没有封面或文件不可用返回 404。include_cover: true 也不能保证每首歌必有封面;搜索结果中的 cover URL 可作为展示来源。

6. 歌词和响度#

GET /api/v1/lyrics#

参数 必填 说明
platform 是 平台 ID
track_id 是 平台歌曲 ID,非空
title 否 歌名;提供后有助于元数据匹配与补充来源
artist / album 否 歌手 / 专辑
duration 否 时长,非负整数,单位秒

无需先创建音频任务,适合与音频准备并行请求。

GET /api/v1/playbacks/{id}/lyrics#

使用已有任务的歌曲信息取歌词,无需重复传入标题、歌手等字段。两种歌词接口都返回:

{
  "platform": "applemusic",
  "track_id": "示例歌曲ID",
  "available": true,
  "plain": "[00:00.00]示例歌词",
  "translation": ""
}

文本通常为逐行 LRC,不承诺逐字时间或翻译一定存在。找不到歌词通常是 200 配合 available: false、空文本,不能只用 HTTP 状态判断是否有歌词。

GET /api/v1/playbacks/{id}/loudness#

返回响度测量状态:

{"state":"pending","version":1}

就绪示例:

{
  "state": "ready",
  "version": 1,
  "integrated_lufs": -18.5,
  "true_peak_dbfs": -2.0,
  "gain_db": 1.0
}

state 为 pending / ready / unavailable;非 ready 时数值字段省略。integrated_lufs 单位 LUFS,true_peak_dbfs 虽保留这个字段名,实际测量单位为 dBTP,gain_db 为建议增益 dB。

接口只分析服务端本地已存在的完整音频,不为测量而额外下载源文件;pending 可稍后查询,unavailable 时客户端保持原音量即可。此接口不是下载歌曲的必需步骤。

7. 推荐接口#

推荐目前只支持 applemusic。它使用服务端共享推荐源,不是 API 调用者自己的个人账号推荐,不要求调用者提交 Apple Music Cookie,也没有收听历史回传接口。

GET /api/v1/recommendations#

返回 SearchItem[]。

参数 默认 说明
platform applemusic 当前仅支持此平台
limit 20 1–50,超出范围会裁剪
refresh false 请求刷新推荐来源
exclude 空字符串 逗号分隔的已见歌曲 ID,最多保留 500 个有效 ID

exclude 仅保留 1–20 位、非全零的数字 ID,去重后忽略无效项。refresh=true 不保证上游立刻变化或所有结果全新;建议持续携带已见 ID,结果数量可能少于 limit。

GET /api/v1/recommendations/home#

参数与上节相同,返回:

{
  "source": "applemusic-personal",
  "tags": [],
  "playlists": [],
  "tracks": []
}
  • tracks:SearchItem[]。
  • tags:每项含 id, label, subtitle, playlist_ids[]。
  • playlists:每项含 id, resource_type, name, curator, description, cover, url, recommendation_id。
  • limit 控制歌曲数量,不是卡片数量。
  • 歌单/专辑卡片通过 collections/resolve 解析其 URL,再逐首创建任务。点击卡片、解析卡片本身不会自动下载整份歌单。

GET / POST /api/v1/recommendations/continue#

根据当前歌曲取得队列续播候选;队列较长时优先使用 POST:

POST /api/v1/recommendations/continue
Content-Type: application/json
{
  "platform": "applemusic",
  "seed_id": "替换为当前歌曲的数字ID",
  "exclude": ["已在队列中的数字ID", "已经播放的数字ID"],
  "limit": 10
}

上面 ID 为占位值,需换成实际数字 ID。seed_id 必填且必须是 1–20 位非全零数字 ID;platform 默认 applemusic,limit 默认 10、裁剪到 1–50,exclude 默认空数组、最多保留 10000 个有效 ID。种子歌曲会自动排除。

GET 使用同名查询参数,exclude 改为逗号分隔字符串。返回 { "source": "...", "tracks": [...] },source 可能为 applemusic-related 或 applemusic-personal。候选可能混合相关推荐和共享推荐补充,不能把 source 当成逐首推荐理由。

推荐接口返回 Cache-Control: no-store。它们不创建音频任务、不修改客户端队列;调用方自己决定如何入队和播放。

8. 歌单与跨平台匹配#

GET /api/v1/collections/resolve#

参数 必填 说明
platform 是 目前支持 applemusic、netease
url 是 公开歌单/专辑链接或平台支持的资源 ID
limit 否 1–5000;不传则完整解析,超过 5000 首明确失败

返回 {platform,id,title,source_url,items: SearchItem[]}。显式 limit 用于预览;想导入完整歌单时不要无意设置较小 limit。

Apple Music 支持歌单 URL、pl.* ID、专辑 URL 和 album:<数字ID>。带 ?i=歌曲ID 的单曲链接不应作为歌单解析。网易云支持歌单/专辑 URL,以及 playlist:<ID>、album:<ID>。

该接口只返回歌曲元数据,不创建下载任务,也不把歌单保存到服务端。页面“我的歌单”和播放队列属于网页本地数据。

POST /api/v1/collections/match#

{
  "source_platform": "netease",
  "target_platform": "applemusic",
  "items": [
    {
      "id": "源平台歌曲ID",
      "song": "示例歌名",
      "singer": "示例歌手",
      "cover": ""
    }
  ]
}

单次 1–200 首;cover 可省略,默认空字符串。超过 200 首时客户端分批提交并保持原顺序。

返回字段:source_platform,target_platform,matched_count,review_count,missing_count,items。每项为:

{
  "source": {"id":"源平台歌曲ID","song":"示例歌名","singer":"示例歌手","cover":""},
  "status": "review",
  "confidence": 82,
  "candidates": []
}

此处为字段结构示意。status 为 matched / review / missing,confidence 为 0–100,candidates 为目标平台 SearchItem[]。

review 建议让用户确认候选;missing 也可能来自搜索失败或超时,不等于已证明曲目不存在。同平台匹配直接保留输入并返回 matched/100,并不重新验证每个 ID。接口不创建任务、不下载音频、不修改歌单;选定候选后使用其目标平台 ID 创建任务。

9. 错误与重试#

业务错误通常返回:

{"detail":"错误说明"}

但缺少必填字段、JSON 类型错误、错误 Content-Type 等可能由框架直接返回文本,网关错误也可能不是 JSON。客户端先判断 HTTP 状态和 Content-Type,再尝试读取 detail;JSON 解析失败时保留简短文本错误。

HTTP 状态 常见含义 / 建议
200 成功;文件接口为二进制,其他接口通常为 JSON
202 创建任务已接受,继续查状态
206 文件 Range 请求成功,按 Content-Range 处理
400 参数、平台能力或业务条件不满足,阅读 detail
404 任务或文件不存在;封面缺失也属于此类
406 请求专用 ALAC 流,但任务未协商该模式
409 文件/流尚未就绪,先检查任务状态
416 Range 无效、越界或不支持多段
415 / 422 可能的请求类型或 JSON 字段校验错误
500 / 502 / 503 服务或上游暂时异常,适度退避重试

HTTP 200 + status: failed 是任务失败,不是音频准备成功。显示 task.error,停止轮询;用户选择重试时可以重新 POST 原请求。同 ID 正在准备时不要通过不断 POST 来“催进度”。

建议对短暂网络/5xx 错误退避重试,例如 2、4、8 秒;避免高并发重复请求同一歌曲。当前文档不承诺固定的并发配额、每秒请求数或下载完成时限。

10. 常见问题#

为什么拿到链接仍下载不了?
任务创建时就返回 URL;等待 completed,再访问 audio_url。409 通常表示尚未准备好。

Hi-Res 只能下载到 FLAC,是降音质了吗?
ALAC 到 FLAC 是无损兼容表示转换,不能仅凭扩展名判断降音质。源曲目实际可用规格决定内容;接口不承诺每首歌都有高采样率版本。

能否直接使用 streaming_url 下载?
可取得专用分包数据,但它不是常规音乐文件。普通下载使用 audio_url。

需要把浏览器复制出来的整串请求头都带上吗?
不需要。正常 GET 无需浏览器伪装头,JSON POST 带 Content-Type 即可。

是否需要调用者提供自己的 Apple Music 账号或会员信息?
当前接入不需要这些凭据;调用服务公开接口即可。上游可用性由服务端配置及平台状态决定。

能不能按 API 一键下载整个歌单?
没有批量下载接口。先解析歌单,再逐首执行下载流程;客户端负责进度、失败记录和并发控制。

状态请求出现了三次,是下载了三遍吗?
不是。状态响应是小型 JSON,音频位于另一条路径。直到任务可用或完成前都可能需要轮询。