Apple Music
Apple Music 集成
关于与 Apple Music 集成的指南。涵盖 AppleScript (macOS)、MusicKit API (跨平台) 和关键的“先加入资料库”要求。
何时使用
当用户要求以下操作时调用:

- 管理播放列表 (创建、添加/移除曲目、列出)
- 控制播放 (播放、暂停、跳过、音量)
- 搜索目录或资料库
- 将歌曲添加到资料库
- 访问收听历史或推荐
关键规则:先加入资料库的工作流程
你不能直接将目录中的歌曲添加到播放列表。
歌曲必须首先在用户的资料库中:
- ❌ 目录 ID → 播放列表 (失败)
- ✅ 目录 ID → 资料库 → 播放列表 (成功)
原因:播放列表使用资料库 ID (i.abc123),而不是目录 ID (1234567890)。
这同时适用于AppleScript和API方法。
平台对比
| 功能 | AppleScript(macOS) | MusicKit API |
|---|---|---|
| 所需设置 | 无需 | 开发者账户 + 令牌 |
| 播放列表管理 | 完整 | 仅限API创建的列表 |
| 播放控制 | 完整 | 无 |
| 目录搜索 | 不支持 | 支持 |
| 资料库访问 | 即时 | 需使用令牌 |
| 跨平台 | 不支持 | 支持 |
AppleScript(macOS)
无需设置。可立即配合音乐应用使用。
通过Bash运行:
osascript -e 'tell application "Music" to playpause'
osascript -e 'tell application "Music" to return name of current track'
多行脚本:
osascript <<'EOF'
tell application "Music"
set t to current track
return {name of t, artist of t}
end tell
EOF
可用操作
| 类别 | 操作 |
|---|---|
| 播放控制 | 播放,暂停,停止,恢复,下一曲,上一曲,快进,快退 |
| 播放器状态 | 播放位置,播放器状态,音量,静音,随机播放启用/模式,歌曲重复 |
| 当前曲目 | 名称,艺术家,专辑,时长,时间,评分,喜爱,不喜欢,流派,年份,曲目编号 |
| 媒体库 | 搜索,列出曲目,获取曲目属性,设置评分 |
| 播放列表 | 列出,创建,删除,重命名,添加曲目,移除曲目,获取曲目 |
| AirPlay | 列出设备,选择设备,当前设备 |
曲目属性(只读)
tell application "Music"
set t to current track
-- Basic info
name of t -- "Hey Jude"
artist of t -- "The Beatles"
album of t -- "1 (Remastered)"
album artist of t -- "The Beatles"
composer of t -- "Lennon-McCartney"
genre of t -- "Rock"
year of t -- 1968
-- Timing
duration of t -- 431.0 (seconds)
time of t -- "7:11" (formatted)
start of t -- start time in seconds
finish of t -- end time in seconds
-- Track info
track number of t -- 21
track count of t -- 27
disc number of t -- 1
disc count of t -- 1
-- Ratings
rating of t -- 0-100 (20 per star)
loved of t -- true/false
disliked of t -- true/false
-- Playback
played count of t -- 42
played date of t -- date last played
skipped count of t -- 3
skipped date of t -- date last skipped
-- IDs
persistent ID of t -- "ABC123DEF456"
database ID of t -- 12345
end tell
曲目属性(可写)
tell application "Music"
set t to current track
set rating of t to 80 -- 4 stars
set loved of t to true
set disliked of t to false
set name of t to "New Name" -- rename track
set genre of t to "Alternative"
set year of t to 1995
end tell
播放器状态属性
tell application "Music"
player state -- stopped, playing, paused, fast forwarding, rewinding
player position -- current position in seconds (read/write)
sound volume -- 0-100 (read/write)
mute -- true/false (read/write)
shuffle enabled -- true/false (read/write)
shuffle mode -- songs, albums, groupings
song repeat -- off, one, all (read/write)
current track -- track object
current playlist -- playlist object
current stream URL -- URL if streaming
end tell
播放控制命令
tell application "Music"
-- Play controls
play -- play current selection
pause
stop
resume
playpause -- toggle play/pause
next track
previous track
fast forward
rewind
-- Play specific content
play (first track of library playlist 1 whose name contains "Hey Jude")
play user playlist "Road Trip"
-- Settings
set player position to 60 -- seek to 1:00
set sound volume to 50 -- 0-100
set mute to true
set shuffle enabled to true
set song repeat to all -- off, one, all
end tell
图书馆查询
tell application "Music"
-- All library tracks
every track of library playlist 1
-- Search by name
tracks of library playlist 1 whose name contains "Beatles"
-- Search by artist
tracks of library playlist 1 whose artist contains "Beatles"
-- Search by album
tracks of library playlist 1 whose album contains "Abbey Road"
-- Combined search
tracks of library playlist 1 whose name contains "Hey" and artist contains "Beatles"
-- By genre
tracks of library playlist 1 whose genre is "Rock"
-- By year
tracks of library playlist 1 whose year is 1969
-- By rating
tracks of library playlist 1 whose rating > 60 -- 3+ stars
-- Loved tracks
tracks of library playlist 1 whose loved is true
-- Recently played (sort by played date)
tracks of library playlist 1 whose played date > (current date) - 7 * days
end tell
播放列表操作
tell application "Music"
-- List all playlists
name of every user playlist
-- Get playlist
user playlist "Road Trip"
first user playlist whose name contains "Road"
-- Create playlist
make new user playlist with properties {name:"New Playlist", description:"My playlist"}
-- Delete playlist
delete user playlist "Old Playlist"
-- Rename playlist
set name of user playlist "Old Name" to "New Name"
-- Get playlist tracks
every track of user playlist "Road Trip"
name of every track of user playlist "Road Trip"
-- Add track to playlist (must be library track)
set targetPlaylist to user playlist "Road Trip"
set targetTrack to first track of library playlist 1 whose name contains "Hey Jude"
duplicate targetTrack to targetPlaylist
-- Remove track from playlist
delete (first track of user playlist "Road Trip" whose name contains "Hey Jude")
-- Playlist properties
duration of user playlist "Road Trip" -- total duration
time of user playlist "Road Trip" -- formatted duration
count of tracks of user playlist "Road Trip"
end tell
隔空播放
tell application "Music"
-- List AirPlay devices
name of every AirPlay device
-- Get current device
current AirPlay devices
-- Set output device
set current AirPlay devices to {AirPlay device "Living Room"}
-- Multiple devices
set current AirPlay devices to {AirPlay device "Living Room", AirPlay device "Kitchen"}
-- Device properties
set d to AirPlay device "Living Room"
name of d
kind of d -- computer, AirPort Express, Apple TV, AirPlay device, Bluetooth device
active of d -- true if playing
available of d -- true if reachable
selected of d -- true if in current devices
sound volume of d -- 0-100
end tell
字符串转义
始终对用户输入进行转义:
def escape_applescript(s):
return s.replace('\\', '\\\\').replace('"', '\\"')
safe_name = escape_applescript(user_input)
script = f'tell application "Music" to play user playlist "{safe_name}"'
限制
- 无法访问目录- 仅限图书馆内容
- 仅限 macOS- 不支持 Windows/Linux
MusicKit API
跨平台但需要 Apple 开发者账户(每年 99 美元)和令牌设置。
身份验证
要求:
- Apple 开发者账户
- 来自开发者门户的 MusicKit 密钥(.p8 文件)
- 开发者令牌(JWT,最长 180 天)
- 用户音乐令牌(浏览器 OAuth)
生成开发者令牌:
import jwt, datetime
with open('AuthKey_XXXXXXXXXX.p8') as f:
private_key = f.read()
token = jwt.encode(
{
'iss': 'TEAM_ID',
'iat': int(datetime.datetime.now().timestamp()),
'exp': int((datetime.datetime.now() + datetime.timedelta(days=180)).timestamp())
},
private_key,
algorithm='ES256',
headers={'alg': 'ES256', 'kid': 'KEY_ID'}
)
获取用户令牌:浏览器 OAuth 至https://authorize.music.apple.com/woa
所有请求的头部:
Authorization: Bearer {developer_token}
Music-User-Token: {user_music_token}
基础URL: https://api.music.apple.com/v1
可用端点
目录(公开 - 仅限开发者令牌)
| 端点 | 方法 | 描述 |
|---|---|---|
/catalog/{storefront}/search | GET | 搜索歌曲、专辑、艺术家、播放列表 |
/catalog/{storefront}/songs/{id} | GET | 歌曲详情 |
/catalog/{storefront}/albums/{id} | GET | 专辑详情 |
/catalog/{storefront}/albums/{id}/tracks | GET | 专辑曲目 |
/catalog/{storefront}/artists/{id} | GET | 艺术家详情 |
/catalog/{storefront}/artists/{id}/albums | 获取 | 歌手的专辑 |
/catalog/{storefront}/artists/{id}/songs | 获取 | 歌手的热门歌曲 |
/catalog/{storefront}/artists/{id}/related-artists | 获取 | 相似歌手 |
/catalog/{storefront}/playlists/{id} | 获取 | 播放列表详情 |
/catalog/{storefront}/charts | 获取 | 热门排行榜 |
/catalog/{storefront}/genres | 获取 | 所有流派 |
/catalog/{storefront}/search/suggestions | 获取 | 搜索自动补全 |
/catalog/{storefront}/stations/{id} | 获取 | 广播电台 |
资料库(需要用户令牌)
| 端点 | 方法 | 描述 |
|---|---|---|
/me/library/songs | GET | 所有库内歌曲 |
/me/library/albums | GET | 所有库内专辑 |
/me/library/artists | GET | 所有库内艺术家 |
/me/library/playlists | GET | 所有库内播放列表 |
/me/library/playlists/{id} | GET | 播放列表详情 |
/me/library/playlists/{id}/tracks | GET | 播放列表曲目 |
/me/library/search | GET | 搜索库 |
/me/library | POST | 添加到资料库 |
/catalog/{sf}/songs/{id}/library | GET | 从目录ID获取资料库ID |
播放列表管理
| 端点 | 方法 | 描述 |
|---|---|---|
/me/library/playlists | POST | 创建播放列表 |
/me/library/playlists/{id}/tracks | POST | 向播放列表添加曲目 |
个性化推荐
| 端点 | 方法 | 描述 |
|---|---|---|
/me/recommendations | GET | 个性化推荐 |
/me/history/heavy-rotation | GET | 高频播放曲目 |
/me/recent/played | 获取 | 最近播放 |
/me/recent/added | 获取 | 最近添加 |
评分
| 端点 | 方法 | 描述 |
|---|---|---|
/me/ratings/songs/{id} | 获取 | 获取歌曲评分 |
/me/ratings/songs/{id} | PUT | 设置歌曲评分 |
/me/ratings/songs/{id} | 删除 | 移除评分 |
/me/ratings/albums/{id} | 获取/PUT/删除 | 专辑评分 |
/me/ratings/playlists/{id} | 获取/PUT/删除 | 播放列表评分 |
商店页面
| 端点 | 方法 | 描述 |
|---|---|---|
/storefronts | GET | 所有店面 |
/storefronts/{id} | GET | 店面详情 |
/me/storefront | GET | 用户店面 |
通用查询参数
| 参数 | 描述 | 示例 |
|---|---|---|
term | 搜索查询 | term=beatles |
types | 资源类型 | types=songs,albums |
limit | 每页结果数(最多25个) | limit=10 |
offset | 分页偏移量 | offset=25 |
include | 相关资源 | include=artists,albums |
extend | 附加属性 | extend=editorialNotes |
l | 语言代码 | l=en-US |
搜索示例
GET /v1/catalog/us/search?term=wonderwall&types=songs&limit=10
Response:
{
"results": {
"songs": {
"data": [{
"id": "1234567890",
"type": "songs",
"attributes": {
"name": "Wonderwall",
"artistName": "Oasis",
"albumName": "(What's the Story) Morning Glory?",
"durationInMillis": 258773,
"releaseDate": "1995-10-02",
"genreNames": ["Alternative", "Music"]
}
}]
}
}
}
库优先工作流程(完整版)
将目录歌曲添加到播放列表需要4个API调用:
import requests
headers = {
"Authorization": f"Bearer {dev_token}",
"Music-User-Token": user_token
}
# 1. Search catalog
r = requests.get(
"https://api.music.apple.com/v1/catalog/us/search",
headers=headers,
params={"term": "Wonderwall Oasis", "types": "songs", "limit": 1}
)
catalog_id = r.json()['results']['songs']['data'][0]['id']
# 2. Add to library
requests.post(
"https://api.music.apple.com/v1/me/library",
headers=headers,
params={"ids[songs]": catalog_id}
)
# 3. Get library ID (catalog ID → library ID)
r = requests.get(
f"https://api.music.apple.com/v1/catalog/us/songs/{catalog_id}/library",
headers=headers
)
library_id = r.json()['data'][0]['id']
# 4. Add to playlist (library IDs only!)
requests.post(
f"https://api.music.apple.com/v1/me/library/playlists/{playlist_id}/tracks",
headers={**headers, "Content-Type": "application/json"},
json={"data": [{"id": library_id, "type": "library-songs"}]}
)
创建播放列表
POST /v1/me/library/playlists
Content-Type: application/json
{
"attributes": {
"name": "Road Trip",
"description": "Summer vibes"
},
"relationships": {
"tracks": {
"data": []
}
}
}
评分
# Love a song (value: 1 = love, -1 = dislike)
PUT /v1/me/ratings/songs/{id}
Content-Type: application/json
{"attributes": {"value": 1}}
限制
- 无播放控制- API无法播放/暂停/跳过
- 播放列表编辑- 只能修改通过API创建的播放列表
- 令牌管理- 开发者令牌每180天过期
- 速率限制- Apple强制执行请求限制
常见错误
❌ 在播放列表中使用目录ID:
# WRONG
json={"data": [{"id": "1234567890", "type": "songs"}]}
修正方法:先添加到资料库,获取资料库ID,再添加。
❌ 通过AppleScript播放目录歌曲:
# WRONG
play track id "1234567890"
修正方法:歌曲必须位于资料库中。
❌ 未转义的AppleScript字符串:
# WRONG
name = "Rock 'n Roll"
script = f'tell application "Music" to play playlist "{name}"'
修正方法:转义引号。
❌ 令牌过期:开发令牌最长有效期为180天。修正方法:检查有效期,处理401错误。
简便方法:使用 mcp-applemusic
该mcp-applemusicMCP服务器会自动处理所有这些复杂问题:AppleScript转义、令牌管理、资料库优先工作流程、ID转换。
安装方法:
git clone https://github.com/epheterson/mcp-applemusic.git
cd mcp-applemusic && python3 -m venv venv && source venv/bin/activate
pip install -e .
配置Claude Desktop:
{
"mcpServers": {
"Apple Music": {
"command": "/path/to/mcp-applemusic/venv/bin/python",
"args": ["-m", "applemusic_mcp"]
}
}
}
在macOS上,大多数功能可立即使用。如需目录功能或在Windows/Linux上使用,请参阅仓库README文件。
| 手册 | mcp-applemusic |
|---|---|
| 4次API调用以添加歌曲 | 播放列表(动作="添加", 自动搜索=True) |
| AppleScript转义 | 自动 |
| 令牌管理 | 自动管理并附带警告 |


微信扫一扫,打赏作者吧~