Replacing one song with another in all playlists

I want to replace song(s) in my playlists with new updated versions. Here’s what I have so far:

tell application "Music"
	set selectedTracks to selection
	
	if (count of selectedTracks) is not equal to 2 then
		display dialog "Please select exactly two tracks."
		return
	end if
	set oldTrack to item 1 of selectedTracks
	set newTrack to item 2 of selectedTracks
	set containingPlaylists to (every user playlist of oldTrack whose smart is false and special kind is none)

	repeat with thisPlaylist in containingPlaylists
		
		-- Get the index of the old track
		
		set trackIndex to (get index of oldTrack)
		
		-- Remove the old track from the playlist
		delete oldTrack
		
		-- Replace the old track with the new track
		duplicate newTrack to thisPlaylist
		set index of newTrack to trackIndex
	end repeat
end tell

My problem is the line

set index of newTrack to trackIndex

How do I set the location of newTrack to match the location of oldTrack?

Track index s in playlist are read only.

You have to recreate in order you want,
Delete all tracks the. Replace one by one.

Here’s something I found on the net


- figure out the index of the first selected track out of the entire playlist
    set playlistTracks to tracks of currentPlaylist
    repeat with i from 1 to count of playlistTracks
        if (item i of playlistTracks) is firstSelectedTrack then exit repeat
    end repeat

    -- now we make one big list of the sorted playlist
    set tracksBeforeSelection to {}
    set tracksAfterSelection to {}
    try
        set tracksBeforeSelection to items 1 thru (i - 1) of playlistTracks
    end try
    try
        set tracksAfterSelection to items (i + selectionCount) thru end of playlistTracks
    end try
    set finalTrackList to tracksBeforeSelection & sortedSelection & tracksAfterSelection

    -- now we get references to all these tracks from the main library so we can delete the playlist and reorganize it
    set finalTrackListRefs to {}
    repeat with aTrack in finalTrackList
        set trackID to persistent ID of aTrack
        set refTrack to (first track of library playlist 1 whose persistent ID is trackID)
        set end of finalTrackListRefs to refTrack
    end repeat

    -- remove all the tracks from the playlist
    delete tracks of currentPlaylist

    -- put the playlist back in the new order
    repeat with aTrack in finalTrackListRefs
        duplicate aTrack to currentPlaylist
    end repeat

I would do something more like.


set playlistTracks to tracks of currentPlaylist
    repeat with aTrack in playlistTracks
        if aTrack’s persistentID is removeTrackID then
duplicate newTrack to newPlaylist
else
duplicate aTrack to newPlaylist
    end repeat


The. Either delete current playlist tracks , then duplicate from newPlaylist or rename newPlaylist

If you can work with ScriptingBridge the playlist tracks are returned as a SBElemwntArray (mutable array) which you can add insert at index, replace object at index etc. then you get set the playlist’s tracks properly to the changed SBElemwntArray

Sorry, none of your first example was helpful. Too many unspecified variables to translate to my code.

Your second set has a line

duplicate aTrack to newPlaylist

that gives me an error
(Error: Can’t set {} to item 1 of {file track id 790330 of user playlist id 425509 of source id 65}.)
when used in the following code:

tell application "Music"
	set selectedTracks to selection
	
	if (count of selectedTracks) is not equal to 2 then
		display dialog "Please select exactly two tracks."
		return
	end if
	
	set oldTrack to item 1 of selectedTracks
	set newTrack to item 2 of selectedTracks
	
	set oldPID to persistent ID of oldTrack
	
	set containingPlaylists to (every user playlist of oldTrack whose smart is false and special kind is none)
	
	repeat with thisPlaylist in containingPlaylists
		
		tell thisPlaylist
			set thisPlaylistTracks to every track
			set rebuiltPlaylist to {}
			
			repeat with aTrack in thisPlaylistTracks
				
				if persistent ID of aTrack is oldPID then
					duplicate newTrack to rebuiltPlaylist
				else
					duplicate aTrack to rebuiltPlaylist
				end if
			end repeat
			
			delete every track
			
			repeat with addTrack in rebuiltPlaylist
				duplicate addTrack to thisPlaylist
			end repeat
			
		end tell
	end repeat
end tell

After a lot of back and forth with Claude, I’ve settled on the following:

tell application "Music"
	set selectedTracks to selection
	
	if (count of selectedTracks) is not equal to 2 then
		display dialog "Please select exactly two tracks."
		return
	end if
	
	set oldTrack to item 1 of selectedTracks
	set newTrack to item 2 of selectedTracks
	set oldPID to persistent ID of oldTrack
	set newPID to persistent ID of newTrack
	
	-- Ask Music directly which playlists contain oldTrack
	set containingPlaylists to (every user playlist of oldTrack whose smart is false and special kind is none)
	
	repeat with thisPlaylist in containingPlaylists
		set rebuiltRefs to {}
		set playlistTracks to every track of thisPlaylist
		set playlistPIDs to persistent ID of every track of thisPlaylist
		set playlistDBIDs to database ID of every track of thisPlaylist
		
		repeat with i from 1 to count of playlistPIDs
			if item i of playlistPIDs is oldPID then
				set end of rebuiltRefs to newTrack
			else
				-- Resolve to library track via database ID before playlist is cleared
				set dbid to item i of playlistDBIDs
				set libTrack to (first track of library playlist 1 whose database ID is dbid)
				set end of rebuiltRefs to libTrack
			end if
		end repeat
		
		tell thisPlaylist to delete every track
		repeat with aRef in rebuiltRefs
			duplicate aRef to thisPlaylist
		end repeat
		
	end repeat
	
end tell

OK, it works as I want. The use of both database ID and persistent ID seems redundant but I can’t figure out why. Any insights?

newPlaylist must be a playlist not a list.

Your new code use is correct

Your probably best just to get the item I of playlistPIDs. As you’ll need it in both if/else

repeat with i from 1 to count of playlistPIDs  
         set aPID to item i of playlistPIDs
		if aPID is oldPID then
	         	set end of rebuiltRefs to newTrack
		else
			-- -- Resolve to library track via persistent ID before playlist is cleared
			set libTrack to (first track of library playlist 1 whose persistent ID is aPID)
			set end of rebuiltRefs to libTrack
		end if
	end repeat