Building a library playlist on macOS that mixes catalog songs and the user's own uploads in a fixed order – supported route, and how to know when an upload is registered?

Our sandboxed macOS app digitises audio cassettes and builds one playlist per cassette in the user's Apple Music library that follows the tape's order: catalog songs where a title was recognised, and the user's own recordings (AAC files the app exported from the tape) where it was not. The user has an Apple Music subscription and Sync Library on.

On macOS every write on MusicLibrary is marked @available(macOS, unavailable) in the 26.5 SDK – add, add(_:to:), createPlaylist and edit (see thread 844114, which got no answer). So we build the playlist through Music.app's scripting interface: make new user playlist, duplicate <library track> to <playlist> for catalog songs, add <file> to <playlist> for own recordings. That works, with one exception that leads to our questions.

What we observe

Reproducible on macOS 26.6.2 / Music 26; a standalone AppleScript is at the end.

  • A playlist built in one go from 14 subscription tracks keeps all 14.
  • The same playlist with one local file added after the second track: all 15 entries are there right after the build and one second later. About 15 s later the playlist has 3 entries – the two catalog entries before the file, the file, and nothing that was added after it. No error anywhere.
  • If the file has been in the library for several minutes before the playlist is built, everything stays. Adding it to the library and waiting 45 s is not enough. Meanwhile the track's cloud status stays unknown, and GET /v1/me/library/search?types=library-songs does not list it (checked for 10 minutes).
  • Emptying the playlist and building it again ~30 s after the entries were removed keeps everything, every time. That is what we do today; it costs 30–40 s per import, and we have to tell the user that entries were removed and put back.

Our reading: while the freshly added file is not yet registered in iCloud Music Library, the playlist as pushed to the server is cut at the first item the server cannot reference, and the next sync adopts the shorter list for cloud items while keeping the local-only item in place.

Questions

  1. Is there a supported way for a macOS app to create a library playlist and add tracks to it? Specifically: is the Apple Music API (POST /v1/me/library/playlists with relationships.tracks, and POST /v1/me/library/playlists/{id}/tracks) the intended route from a macOS app holding a MusicKit user token, and can such a playlist reference the user's own uploaded songs by their library id (i.…)?
  2. After a local file has been added to the library (via Music.app's add, or any other supported way), how can an app learn that iCloud Music Library has registered it, and what its library song id is? A notification, a MusicKit property, an Apple Music API endpoint? We would wait on that signal instead of rebuilding.
  3. Is the removal described above expected behaviour?

Catalog ids are re-resolved at import time via id, ISRC and search as recommended in thread 122110, so stale catalog ids are not the cause.

Reproduction

Needs Sync Library on, at least 14 subscription tracks in the library, and a local audio file the library does not know yet. Prints the counts after 1 s, 21 s and 41 s, then cleans up.

on run argv
	set localFile to POSIX file (item 1 of argv)
	tell application "Music"
		set cloudTracks to (every track of library playlist 1 whose cloud status is subscription)
		set idsBefore to persistent ID of every track of library playlist 1
		set pl to make new user playlist with properties {name:"Reconciliation repro"}
		repeat with i from 1 to 2
			duplicate (item i of cloudTracks) to pl
		end repeat
		set fileTrack to add localFile to pl
		set fileID to persistent ID of fileTrack
		repeat with i from 3 to 14
			duplicate (item i of cloudTracks) to pl
		end repeat
		set n0 to count of tracks of pl
		delay 1
		set n1 to count of tracks of pl
		delay 20
		set n2 to count of tracks of pl
		delay 20
		set n3 to count of tracks of pl
		delete pl
		if fileID is not in idsBefore then delete (first track of library playlist 1 whose persistent ID is fileID)
		return "after build: " & n0 & ", after 1 s: " & n1 & ", after 21 s: " & n2 & ", after 41 s: " & n3
	end tell
end run

Output here: after build: 15, after 1 s: 15, after 21 s: 3, after 41 s: 3.

Building a library playlist on macOS that mixes catalog songs and the user's own uploads in a fixed order – supported route, and how to know when an upload is registered?
 
 
Q