返回

如何用 MusicKit 获取 Apple Music 特定时间段的热门专辑?

IOS

如何使用 MusicKit 获取指定时间段内的 Apple Music 热门专辑或歌曲?

你是否曾好奇过,在 Apple Music 浩瀚的音乐库中,究竟哪些专辑或歌曲最得你心?想要回顾过去一个月,甚至一年的音乐品味?或者,想创建一个播放列表,将过去一段时间的心头好一网打尽?

Apple Music 为开发者提供了 MusicKit ,方便我们访问用户的音乐数据。然而,MusicKit 并未直接提供检索特定时间段内热门专辑或歌曲的功能。但这并不意味着我们就束手无策了。本文将介绍如何巧妙利用 MusicKit 的现有功能,实现这一目标,并提供 Swift 代码示例,助你快速上手。

MusicKit 的 "短板"

MusicKit 的 MusicLibraryRequest 对象允许开发者检索用户的音乐库数据,包括歌曲、专辑和播放列表。我们可以使用 sort(by:ascending:) 方法,根据播放次数等属性对结果进行排序。然而,MusicLibraryRequest 缺少对时间范围的过滤选项。

换句话说,如果你想知道上个月播放次数最多的歌曲,无法直接使用 MusicLibraryRequest 并指定日期范围。我们需要另辟蹊径。

解决方案:借力播放历史记录

尽管 MusicKit 无法直接按时间段筛选播放数据,但我们可以从用户的播放历史记录入手。具体步骤如下:

  1. 获取最近播放历史记录: 使用 MusicKit 的 MusicDataRequest 对象,检索用户的最近播放历史记录。我们可以指定要检索的播放记录数量。

  2. 筛选播放历史记录: 遍历播放历史记录,根据目标时间段(例如,过去一个月)进行筛选。利用播放事件的时间戳,可以确定哪些记录属于该时间段。

  3. 统计专辑或歌曲的播放次数: 创建一个字典或其他数据结构,用于存储每个专辑或歌曲的播放次数。遍历筛选后的播放历史记录,每当遇到某个专辑或歌曲,就将其对应的播放次数增加。

  4. 按播放次数排序: 对存储专辑或歌曲及其播放次数的字典进行排序。

  5. 展示结果: 向用户展示播放次数最多的专辑或歌曲列表。

代码示例

以下 Swift 代码示例展示了如何实现上述解决方案:

import MusicKit

func fetchTopPlayedAlbums(for duration: TimeInterval) async throws -> [(album: Album, playCount: Int)] {

    // 1. 获取最近播放历史记录
    let recentPlayHistoryRequest = MusicDataRequest(matching: MusicDataQuery(for: .recentlyPlayed))
    let recentPlayHistory = try await recentPlayHistoryRequest.response().recentlyPlayed

    // 2. 筛选播放历史记录
    let now = Date()
    let filteredPlayHistory = recentPlayHistory.filter { play in
        // 检查播放事件是否发生在指定的时间段内
        now.timeIntervalSince(play.datePlayed) <= duration
    }

    // 3. 统计专辑的播放次数
    var albumPlayCounts = [MusicItemID: Int]()
    for play in filteredPlayHistory {
        // 假设每个播放事件都与一首歌曲相关
        guard let track = play.playbackContext?.tracks.first else { continue }

        // 获取歌曲所属的专辑
        let albumId = track.album?.id
        albumPlayCounts[albumId, default: 0] += 1
    }

    // 4. 按播放次数排序
    let sortedAlbumPlayCounts = albumPlayCounts.sorted { $0.value > $1.value }

    // 5. 获取专辑信息并返回结果
    var topAlbums = [(album: Album, playCount: Int)]()
    for (albumId, playCount) in sortedAlbumPlayCounts {
        let albumRequest = MusicCatalogResourceRequest<Album>(matching: albumId)
        let album = try await albumRequest.response().resource

        topAlbums.append((album: album, playCount: playCount))
    }

    return topAlbums
}

代码解析:

  • 定义了一个名为 fetchTopPlayedAlbums(for:) 的异步函数,接收一个 TimeInterval 参数,表示要检索热门专辑的时间段。

  • 使用 MusicDataRequest 获取最近的播放历史记录。

  • 过滤播放历史记录,只保留在指定时间段内的播放事件。

  • 使用字典 albumPlayCounts 统计每个专辑的播放次数。

  • albumPlayCounts 进行排序,将播放次数最多的专辑排在前面。

  • 使用 MusicCatalogResourceRequest 获取每个专辑的详细信息。

  • 返回一个包含专辑及其播放次数的元组数组。

使用方法:

Task {
    do {
        // 获取过去一个月播放次数最多的 10 张专辑
        let topAlbums = try await fetchTopPlayedAlbums(for: 30 * 24 * 60 * 60)

        // 打印结果
        for (album, playCount) in topAlbums {
            print("\(album.title) - 播放次数: \(playCount)")
        }
    } catch {
        print("获取热门专辑时出错: \(error)")
    }
}

常见问题

1. 如何获取指定时间段内播放次数最多的歌曲?

修改代码示例中的 albumPlayCountssongPlayCounts,并统计歌曲 ID 对应的播放次数即可。

2. 如何处理播放历史记录为空的情况?

在访问 recentPlayHistory 之前,检查其是否为空。如果为空,可以返回空数组或提示用户。

3. 如何提高代码效率?

可以使用缓存机制,避免重复请求相同的专辑信息。

4. 如何处理可能出现的网络错误?

在调用 MusicDataRequestMusicCatalogResourceRequest 时,使用 try await 进行错误处理。

5. 如何将获取到的数据展示在用户界面上?

可以使用 ListTable 视图展示专辑或歌曲列表,并显示其播放次数。

结语

尽管 MusicKit 没有直接提供检索特定时间段内热门专辑或歌曲的功能,但通过结合播放历史记录和一些数据处理技巧,我们仍然可以实现类似的功能。本文提供的解决方案和代码示例,可以帮助你构建一个能够分析用户音乐品味的应用程序。