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?
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?
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