OA0
OA0 是一个探索 AI 的社区
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  apple-music:深度集成 Apple Music,支持 AppleScript (macOS) 与 MusicKit API

apple-music:深度集成 Apple Music,支持 AppleScript (macOS) 与 MusicKit API

 
  dune ·  2026-02-04 14:09:41 · 16 次点击  · 0 条评论  

名称: apple-music
版本: 0.6.0
描述: 通过 AppleScript (macOS) 或 MusicKit API 集成 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)

零配置。可立即与 Music 应用配合使用。

通过 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

可用操作

类别 操作
播放控制 play, pause, stop, resume, next track, previous track, fast forward, rewind
播放器状态 player position, player state, sound volume, mute, shuffle enabled/mode, song repeat
当前曲目 name, artist, album, duration, time, rating, loved, disliked, genre, year, track number
资料库 search, list tracks, get track properties, set ratings
播放列表 list, create, delete, rename, add tracks, remove tracks, get tracks
AirPlay list devices, select device, current device

曲目属性(读取)

tell application "Music"
    set t to current track
    -- 基本信息
    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

    -- 时间信息
    duration of t       -- 431.0 (秒)
    time of t           -- "7:11" (格式化)
    start of t          -- 起始时间(秒)
    finish of t         -- 结束时间(秒)

    -- 曲目信息
    track number of t   -- 21
    track count of t    -- 27
    disc number of t    -- 1
    disc count of t     -- 1

    -- 评分
    rating of t         -- 0-100 (每星20分)
    loved of t          -- true/false
    disliked of t       -- true/false

    -- 播放记录
    played count of t   -- 42
    played date of t    -- 上次播放日期
    skipped count of t  -- 3
    skipped date of t   -- 上次跳过日期

    -- ID
    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 星
    set loved of t to true
    set disliked of t to false
    set name of t to "New Name"    -- 重命名曲目
    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       -- 当前位置(秒,可读/写)
    sound volume          -- 0-100 (可读/写)
    mute                  -- true/false (可读/写)
    shuffle enabled       -- true/false (可读/写)
    shuffle mode          -- songs, albums, groupings
    song repeat           -- off, one, all (可读/写)
    current track         -- 曲目对象
    current playlist      -- 播放列表对象
    current stream URL    -- 流媒体 URL
end tell

播放命令

tell application "Music"
    -- 播放控制
    play                          -- 播放当前选中项
    pause
    stop
    resume
    playpause                     -- 切换播放/暂停
    next track
    previous track
    fast forward
    rewind

    -- 播放特定内容
    play (first track of library playlist 1 whose name contains "Hey Jude")
    play user playlist "Road Trip"

    -- 设置
    set player position to 60     -- 跳转到 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"
    -- 所有资料库曲目
    every track of library playlist 1

    -- 按名称搜索
    tracks of library playlist 1 whose name contains "Beatles"

    -- 按艺术家搜索
    tracks of library playlist 1 whose artist contains "Beatles"

    -- 按专辑搜索
    tracks of library playlist 1 whose album contains "Abbey Road"

    -- 组合搜索
    tracks of library playlist 1 whose name contains "Hey" and artist contains "Beatles"

    -- 按流派
    tracks of library playlist 1 whose genre is "Rock"

    -- 按年份
    tracks of library playlist 1 whose year is 1969

    -- 按评分
    tracks of library playlist 1 whose rating > 60  -- 3 星以上

    -- 喜爱的曲目
    tracks of library playlist 1 whose loved is true

    -- 最近播放(按播放日期排序)
    tracks of library playlist 1 whose played date > (current date) - 7 * days
end tell

播放列表操作

tell application "Music"
    -- 列出所有播放列表
    name of every user playlist

    -- 获取播放列表
    user playlist "Road Trip"
    first user playlist whose name contains "Road"

    -- 创建播放列表
    make new user playlist with properties {name:"New Playlist", description:"My playlist"}

    -- 删除播放列表
    delete user playlist "Old Playlist"

    -- 重命名播放列表
    set name of user playlist "Old Name" to "New Name"

    -- 获取播放列表曲目
    every track of user playlist "Road Trip"
    name of every track of user playlist "Road Trip"

    -- 添加曲目到播放列表(必须是资料库曲目)
    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

    -- 从播放列表移除曲目
    delete (first track of user playlist "Road Trip" whose name contains "Hey Jude")

    -- 播放列表属性
    duration of user playlist "Road Trip"   -- 总时长
    time of user playlist "Road Trip"       -- 格式化时长
    count of tracks of user playlist "Road Trip"
end tell

AirPlay

tell application "Music"
    -- 列出 AirPlay 设备
    name of every AirPlay device

    -- 获取当前设备
    current AirPlay devices

    -- 设置输出设备
    set current AirPlay devices to {AirPlay device "Living Room"}

    -- 多设备
    set current AirPlay devices to {AirPlay device "Living Room", AirPlay device "Kitchen"}

    -- 设备属性
    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 如果正在播放
    available of d      -- true 如果可访问
    selected of d       -- true 如果在当前设备中
    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/年)和令牌设置。

认证

要求:
1. Apple 开发者账户
2. 来自开发者门户的 MusicKit 密钥 (.p8 文件)
3. 开发者令牌 (JWT,最长 180 天)
4. 用户音乐令牌 (浏览器 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 GET 艺术家的专辑
/catalog/{storefront}/artists/{id}/songs GET 艺术家的热门歌曲
/catalog/{storefront}/artists/{id}/related-artists GET 相似艺术家
/catalog/{storefront}/playlists/{id} GET 播放列表详情
/catalog/{storefront}/charts GET 热门排行榜
/catalog/{storefront}/genres GET 所有流派
/catalog/{storefront}/search/suggestions GET 搜索自动补全
/catalog/{storefront}/stations/{id} GET 广播电台

资料库(需要用户令牌)

端点 方法 描述
/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 GET 最近播放
/me/recent/added GET 最近添加

评分

端点 方法 描述
/me/ratings/songs/{id} GET 获取歌曲评分
/me/ratings/songs/{id} PUT 设置歌曲评分
/me/ratings/songs/{id} DELETE 移除评分
/me/ratings/albums/{id} GET/PUT/DELETE 专辑评分
/me/ratings/playlists/{id} GET/PUT/DELETE 播放列表评分

商店区域

端点 方法 描述
/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

响应:
{
  "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. 搜索目录
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. 添加到资料库
requests.post(
    "https://api.music.apple.com/v1/me/library",
    headers=headers,
    params={"ids[songs]": catalog_id}
)

# 3. 获取资料库 ID (目录 ID → 资料库 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. 添加到播放列表(仅限资料库 ID!)
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": []
    }
  }
}

评分

# 喜爱一首歌 (值: 1 = 喜爱, -1 = 不喜欢)
PUT /v1/me/ratings/songs/{id}
Content-Type: application/json

{"attributes": {"value": 1}}

限制

  • 无播放控制 - API 无法播放/暂停/跳过
16 次点击  ∙  0 人收藏  
登录后收藏  
0 条回复
关于 ·  帮助 ·  PING ·  隐私 ·  条款   
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
耗时 39 ms
Developed with Cursor