Post not yet marked as solved
Is it possible to play songs/playlists on another device on the same account of the user.
Effectively, remote control.
ex: I own a Mac Book and an iPad, my iPad is connected to speakers, I want to stop and start playing music on the iPad using my Mac Book, through APIs.
Post not yet marked as solved
Is there a way to use the MusicLibraryRequest to get the users loved songs, playlists, albums and artists? I don't see a way in documentation but maybe I am missing it.
Thanks,
Dan
Post not yet marked as solved
I have MusicKit integrated into an Android app and it works fine for most users, but some users report that it seems to successfully authenticate but it doesn't play their music.
Logs from their devices show errors like this during MediaPlayerController configuration:
log
D/SVAudioRendererNative: FootHillConfig::config() id: 0123456789abcde
E/SVAudioRendererNative: KDSetAndroidID() ERROR status: 4294924646
I omitted the id value in the config log, but the number of characters is accurate - 15 in the logs from problem devices, while I've noticed that logs from test devices seem to have 16 character ids in this log entry.
Throughout the time that MediaPlayerController is active (and should be playing music), this log is continually seen:
log
E/SVAudioRendererNative: SVFootHillPExchange::SVFootHillPExchange() ERROR 4294924645 retrieving SPC
I haven't seen any other errors propagating to the Java level or being logged. What can I do to solve this issue for our users?
Hi,
I'm trying out the beta for music kit. In the current version of my app, my widget can show multiple albums. I preload the images of the album covers. In the beta's the url that is returned for the artwork starts with: "musickit://", which does not work with URLSession. How can I preload the data using the new url scheme?
Current code:
func fetchArtworkFor (musicID: MusicItemID, url : URL?) async throws -> UIImage? {
guard let url = url else {
return nil
}
let urlRequest = URLRequest (url: url)
let data = try await URLSession.shared.data(for: urlRequest)
let image = UIImage(data: data.0)
return image
}
// Some other function
for album in albumsToShow {
if let url = album.artwork?.url(width: context.family.imageHeight, height: context.family.imageHeight), let image = try? await fetchArtworkFor(musicID: album.id, url:url) {
images[album] = image
}
}
Post not yet marked as solved
Hi I am working on a music app where I can do some sound analysis, my end goal is to integrate Apple Music API in my app where users can search songs. When the song is played I want to show a type of soundwave/spectrogram. For sound visualization I have AVFoundation but the Music API returns only song ID which could be played using Apple MediaPlayer framework only. Is there any API for doing sound analysis or can I play the Apple music songs using AVFoundation.
Post not yet marked as solved
Hi there,
tl;dr: What's the best way to get all tracks (with catalog IDs) from a playlist that has more than 100 tracks, using MusicLibraryRequest.
I'm doing something dumb, not understanding something, and possibly both.
I've got an existing, kinda okay function that uses the MusicDataRequest and the Apple Music API to fetch all tracks from a playlist, with pagination like this:
func getTracksFromAppleMusicLibraryPlaylist(playlist: AppleMusicPlaylist) async throws -> [MusicKit.Track]? {
var tracksToReturn: [MusicKit.Track] = []
var libraryTracks: [AppleMusicLibraryTrack] = []
@Sendable
func fetchTracks(playlist: AppleMusicPlaylist, offset: Int) async -> AppleMusicPlaylistFetchResponse? {
do {
let playlistId = playlist.id
var playlistRequestURLComponents = URLComponents()
playlistRequestURLComponents.scheme = "https"
playlistRequestURLComponents.host = "api.music.apple.com"
playlistRequestURLComponents.path = "/v1/me/library/playlists/\(playlistId)/tracks"
playlistRequestURLComponents.queryItems = [
URLQueryItem(name: "include", value: "catalog"),
URLQueryItem(name: "limit", value: "100"),
URLQueryItem(name: "offset", value: String(offset)),
]
if let playlistRequestURL = playlistRequestURLComponents.url {
let playlistRequest = MusicDataRequest(urlRequest: URLRequest(url: playlistRequestURL))
let playlistResponse = try await playlistRequest.response()
let decoder = JSONDecoder()
// print("Get Tracks Dump")
// print(String(data: playlistResponse.data, encoding: .utf8)!)
let response = try decoder.decode(AppleMusicPlaylistFetchResponse.self, from: playlistResponse.data)
return response
} else {
print("Bad URL!")
}
} catch {
print(error)
}
return nil
}
Logger.log(.info, "Fetching inital tracks from \(playlist.attributes.name)")
if let response = await fetchTracks(playlist: playlist, offset: 0) {
if let items = response.data {
libraryTracks = items
}
if let totalItemCount = response.meta?.total {
Logger.log(.info, "There are \(totalItemCount) track(s) in \(playlist.attributes.name)")
if totalItemCount > 100 {
let remainingItems = (totalItemCount - 100)
let calls = remainingItems <= 100 ? 1 : (totalItemCount - 100) / 100
Logger.log(.info, "Total items: \(totalItemCount)")
Logger.log(.info, "Remaining items: \(remainingItems)")
Logger.log(.info, "Calls: \(calls)")
await withTaskGroup(of: [AppleMusicLibraryTrack]?.self) { group in
for offset in stride(from: 100, to: calls * 100, by: 100) {
Logger.log(.info, "Fetching additional tracks from \(playlist.attributes.name) with offset of \(offset)")
group.addTask {
if let response = await fetchTracks(playlist: playlist, offset: offset) {
if let items = response.data {
return items
}
}
return nil
}
}
for await (fetchedTracks) in group {
if let tracks = fetchedTracks {
libraryTracks.append(contentsOf: tracks)
}
}
}
}
}
}
// props to @JoeKun for this bit of magic
Logger.log(.info, "Matching library playlist tracks with catalog tracks...")
for (i, track) in libraryTracks.enumerated() {
if let correspondingCatalogTrack = track.relationships?.catalog?.first {
tracksToReturn.append(correspondingCatalogTrack)
print("\(i) => \(track.id) corresponds to catalog track with ID: \(correspondingCatalogTrack.id).")
} else {
Logger.log(.warning, "\(i) => \(track.id) doesn't have any corresponding catalog track.")
}
}
if tracksToReturn.count == 0 {
return nil
}
return tracksToReturn
}
While not the most elegant, it gets the job done, and it's kinda quick due to the use of withTaskGroup .esp with playlists containing more than 100 songs/tracks.
Regardless, I'm kinda stuck, trying to do something similar with the new MusicLibraryReqeust in iOS 16.
The only way I can think of to get tracks from a playlist, using MusicLibraryRequest, having read the new docs, is like this:
@available(iOS 16.0, *)
func getAllTracksFromHugePlaylist(id: MusicItemID) async throws -> [MusicKit.Track]? {
do {
var request = MusicLibraryRequest<MusicKit.Playlist>()
request.filter(matching: \.id, equalTo: id)
let response = try await request.response()
if response.items.count > 0 {
if let tracks = try await response.items[0].with(.tracks, preferredSource: .catalog).tracks {
Logger.log(.info, "Playlist track count: \(tracks.count)")
return tracks.compactMap{$0}
}
}
} catch {
Logger.log(.error, "Could not: \(error)")
}
return nil
}
The problem with this is that .with seems to be capped at 100 songs/tracks, and I can't see any way to change that.
Knowing that, I can't seem to tell MusicLibraryRequest that I want the tracks of the playlist with the initial request, where before I could use request.properties = .tracks, which I could then paginate if available.
Any help setting me on the right course would be greatly appreciated.
Post not yet marked as solved
Hi there!
I have been trying to play the music videos we get from Apple Music API and have been unsuccessful.
Here's my code:
var video: MusicVideo
var body: some View {
VideoPlayer(player: AVPlayer(url: video.url!))
}
I know the URL from the MusicVideo is not in a music format but just the URL to the video in the Apple Music catalog.
How do I go about playing it without using something like MPMusicPlayerController.systemMusicPlayer.openToPlay(queueDescriptor) and provide an in-app experience (and not take the user to the Apple Music app)?
Hi there!
I am working on the genres screen and realised that I can directly use MusicCatalogResourceRequest for fetching genre with a particular ID:
func getGenres() async {
do {
let genreID = MusicItemID("17")
let request = MusicCatalogResourceRequest<Genre>(matching: \.id, equalTo: genreID)
let genreResponse = try await request.response()
print(genreResponse.items)
} catch {
print(error)
}
}
Apple Music also has an API to get the top charts genres. How would I do it without using MusicDataRequest, or is it the only way?
My current approach:
typealias Genres = MusicItemCollection<Genre>
do {
let countryCode = try await MusicDataRequest.currentCountryCode
let genreURL = "https://api.music.apple.com/v1/catalog/\(countryCode)/genres"
guard let url = URL(string: genreURL) else {
throw URLError(.badURL)
}
let request = MusicDataRequest(urlRequest: URLRequest(url: url))
let response = try await request.response()
let genre = try JSONDecoder().decode(Genres.self, from: response.data)
print(genre)
} catch {
print(error)
}
Thank you!
Hi there!
I was experimenting with the MusicCatalogChartsRequest. I have one doubt, and I do not know if it is the intended behavior.
If I have the kinds as [.cityTop] and the types as [Song.self], why does it print the city playlists and the top played playlists?
Ideally, it should print an empty array, right? As I have only Song as a type?
var request = MusicCatalogChartsRequest(kinds: [.cityTop], types: [Song.self])
request.limit = 1
let response = try await request.response()
print(response.playlistCharts)
The output is:
[MusicCatalogChart<Playlist>(
id: "city-top:cityCharts",
kind: .cityTop,
title: "City Charts",
items: [
Playlist(
id: "pl.db537759ae3341eaa600bc5482209f7c",
name: "Top 25: Mumbai",
curatorName: "Apple Music",
isChart: true,
kind: "editorial",
lastModifiedDate: "2022-06-21",
url: "https://music.apple.com/in/playlist/top-25-mumbai/pl.db537759ae3341eaa600bc5482209f7c"
)
],
hasNextBatch: true
), MusicCatalogChart<Playlist>(
id: "most-played:playlists",
kind: .mostPlayed,
title: "Top Playlists",
items: [
Playlist(
id: "pl.f4d106fed2bd41149aaacabb233eb5eb",
name: "Today’s Hits",
curatorName: "Apple Music Hits",
isChart: false,
kind: "editorial",
lastModifiedDate: "2022-06-21",
shortDescription: "Drake gets loose with “Sticky”.",
standardDescription: "Among the many surprises of Drake’s <i>Honestly, Nevermind</i>—not the least of which is the album’s very existence—is that it isn’t really a hip-hop album at all; he’s mainly singing. But “Sticky” is one of the few tracks where the project’s commitment to exploring dance music—courtesy here of production work from Australian artist RY X and Gordo (aka DJ Carnage)—meets actual rapping. Add Today’s Hits to your library to stay up on the biggest songs in pop, hip-hop, R&B and more.",
url: "https://music.apple.com/in/playlist/todays-hits/pl.f4d106fed2bd41149aaacabb233eb5eb"
)
],
hasNextBatch: true
)]
Thank you!
Post not yet marked as solved
Hi there,
This is more of a "how-to," "am I doing this right?" question, as I've never done this before, and I couldn't find any definitive write up for how to do this, so I'm asking here.
With the release of iOS16 beta, I've been implementing some new MusicKit features in an iOS app I'm working on that was initially built for iOS 15.
Setup:
dev machine: masOS Monterey 12.4
test device 1: iOS 15.4
test device 2: iOS 16 beta 2
Xcode versions:
14.0 beta 2 (14A5229c)
13.4.1 (13F100)
The original app was written, using Xcode 13 and has an iOS Development Target of 15.0
Steps:
create new branch off main called beta16
open Xcode beta2 and switch to new branch
set the iOS Development Target for the project to 15.0
make code changes in the new branch, using ifavailable to handle both iOS 16 and fallback version code.
Results:
When I test the new code using Xcode 14 beta 2 on an iOS 16 device, things work as expected.
When I test the new code using Xcode 14 beta on an iOS 15 device, the app builds and then crashes immediately upon open with:
dyld[38909]: Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs
Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp
Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit
Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs
Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp
Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit
When coding, I followed all of Xcodes prompting that says when a potentially unsupported new feature is being used.
When I look to where .includeTopResults is being used, I can see that it was not wrapped with ifavailable:
var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])
request.includeTopResults = true
let response = try await request.response()
If I comment out the line with .includeTopResults, the app runs on the iOS 15 device w/o issue.
If I wrap it in ifavailable, like this, it crashes as before:
var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])
if #available(iOS 16, *) {
request.includeTopResults = true
}
let response = try await request.response()
If I check the docs here, I think I'm using .includeTopResults correctly.
Question:
My main question here is if I'm correctly developing the app toward the goal of supporting new iOS 16 features, while also supporting devices using iOS 15, via fallback.
Ultimately, I plan to merge the beta16 branch into a branch from which I'll deploy the app.
The app crashing when using .includeTopResults has me hesitant because I don't know if that's a bug or if I'm the bug. Usually, it's the latter.
It seems like the steps outlined above are the correct way to develop toward supporting upcoming features and "legacy iOS versions", but I'm not sure.
Any clarity on this would be most appreciated.
Thanks!
Hi ,
I have a usecase where I need to add multiple songs to apple music playlists. I am using MPMediaplaylist.addItem(withProductID: ) function to add a single song to the playlist. Is there a way to convert the song to MPMediaItem so that I can use MPMediaplaylist.add([MPMediaItem]) to add multiple songs to the playlist?
Regards
Whether the apple Music kit provides support to download audio or video songs?
Post not yet marked as solved
I'm trying to stream an array of Apple music songs that are not tied to a single playlist. I have all the id's of these songs and I can play them individually if I use "setQueue" such as this:
await musicKit.value.setQueue({
songs: ["1616228595", "1564530724"],
autoplay: true,
});
After the first song finishes playing it just stops altogether. How can I have the next song in the array play? I'm able to use:
await musicKit.value.skipToNextItem();
await musicKit.value.skipToPreviousItem();
And that works fine to toggle between the songs in the array, but I haven't found anything that shows an example of how this would be done with an array of songs such as I have. What do I need to add in order to get this playing songs back to back in from the song array?
Post not yet marked as solved
Hello,
I'm new to the Swift MusicKit API and am starting with the implementation in iOS 16.
I'm getting stuck on an issue where there is no background or text color associated with the Artwork object. Is this something you have to make an additional property request for, and if so, how do you do that?
var catalogSearch = MusicCatalogResourceRequest<Album>(matching: \.id, equalTo: item.id)
let catalogResponse = try await request.response()
guard let firstItem = catalogResponse.items.first else {
return
}
In this example, firstItem.artwork only contains the url and what look like incorrect max width/height values.
here's a printout of firstItem.artwork
Optional(Artwork(
urlFormat: "musicKit://artwork/library/5F37858D-F46B-4F12-BA67-40FA8DD63D87/{w}x{h}?at=item&fat=&id=7718670444435992305&lid=5F37858D-F46B-4F12-BA67-40FA8DD63D87&mt=music&aat=Music122/v4/37/25/f5/3725f515-249f-7b91-77bb-f479cd48201c/22UMGIM32254.rgb.jpg",
maximumWidth: 0,
maximumHeight: 0
))
Post not yet marked as solved
Do we have any development allowance/tools for playback from Apple Music without a necessity to pay for the subscription?
I am making a media player for Apple iOS and wanted it to be able to pull my music library using an API. The closest thing I found to this is this:
https://developer.apple.com/musickit/
However, I don't know if it will allow users to play their music purchased by apple. Does anyone know how to do this so the user logs into their apple account through my app and then has complete access to their movies, tv shows, and music?
Any answers are really appreciated I did my best to find the answer to this and know its annoying to ask these questions when google or apple has it documented somewhere.
Is there any sign of an update to MusicKit JS? The 1.x version still seems to be the only one available despite updates to the iOS and MacOS SDKs. The 1.x version has been fairly unreliable for me and I've paused updates to Apple Music support in my app in hopes that a better version is coming soon.
Post not yet marked as solved
I have my music kit instance setup with a few songs:
await musicKitInstance.setQueue({
songs: ["726416473", "1099848811"],
startPlaying: true,
});
Previously I was having issues with tracks playing back to back, but with these tracks I don't have this issue. I wanted this queue to continue looping. I then thought to add:
await musicKitInstance.setQueue({
songs: ["726416473", "1099848811"],
startPlaying: true,
repeatMode:1
});
and that does loop, but it only loops the last song. I also changed it to 2 and it does the same thing.
I looked through the docs, but they don't really explain this from what I saw. If there's some documentation that clearly explains the various options I can use for the music kit instance I'd like to see it.
Post not yet marked as solved
We're using
https://developer.apple.com/documentation/musickitjs to authorize Apple music, on Desktop it opens a new window to authorize to apple.
But It's NOT working on mobile In-App Browser (both iOS & Android), probably because on mobile messenger, it's not possible to allow the opening of multiple windows.
Are we missing something here? Any workaround for it?
Has anyone done that?
Hi there!
I was using the Apple Music app and stumbled upon Categories. For example, if you search for Apple Music Party, the first result is a Category that shows a list of playlists.
How do I access these using MusicKit? Is Categories Music exclusive only or available to third-party developers?