I'm new to AppleScript, I've only been practicing for a couple of weeks. I wrote a code that transfers information from an imported xml file (actually more like a plist) from the Music application (formerly iTunes) to the new Music library for tracks with a match by title, album and artist about the parameters Play Count, Play Date, Skip Count, Skip Date and even Loved .
This code even works, and may be useful to someone. However, I have questions about the correctness of the syntax of some parts of it.
-- Choose file plist или xml
set xmlFilePath to (choose file with prompt "Choose file iTunes Music Library" of type {"plist", "xml"})
set xmlTracksList to {}
set xmlTracksListRef to a reference to xmlTracksList
tell application "System Events"
tell property list file (POSIX path of xmlFilePath)
tell contents
set xmlTracks to value of property list item "Tracks"
set xmlTracksRef to a reference to xmlTracks
end tell
end tell
end tell
tell application "Music"
-- separate counter for the number of processed tracks
set processedTracksCounter to 0
-- setting progressbar parameters for reading data from XML
set theXMLitemCount to length of xmlTracks
tell me
set progress total steps to theXMLitemCount
set progress completed steps to 0
set progress description to "Analysing XML items..."
set progress additional description to "Preparing to analyse."
set xmlTracksIter to 1
end tell
repeat with t in items of xmlTracksRef
tell me
set progress additional description to "Processing xml items " & xmlTracksIter & " of " & theXMLitemCount
end tell
set xmlTrackInfo to {name:(|Name| of t), album:(|Album| of t), artist:(|Artist| of t), playCount:(missing value), playDate:(missing value), skipCount:(missing value), skipDate:(missing value), lovedStatus:(missing value)}
try
if class of (|Play Count| of t) is integer then set playCount of xmlTrackInfo to (|Play Count| of t)
end try
try
if class of (|Play Date UTC| of t) is date then set playDate of xmlTrackInfo to |Play Date UTC| of t
end try
try
if class of (|Skip Count| of t) is integer then set skipCount of xmlTrackInfo to |Skip Count| of t
end try
try
if class of (|Skip Date| of t) is date then set skipDate of xmlTrackInfo to |Skip Date| of t
end try
try
if class of (|Loved| of t) is boolean then set lovedStatus of xmlTrackInfo to |Loved| of t
end try
set end of xmlTracksListRef to xmlTrackInfo
tell me
set progress completed steps to xmlTracksIter
set xmlTracksIter to xmlTracksIter + 1
end tell
end repeat
-- Finding and setting values for each track in the list (array)
set libraryTracks to tracks
set libraryTracksRef to a reference to libraryTracks
-- setting progressbar parameters to display the number of processed tracks
set theTracksCount to length of libraryTracks
tell me
set progress total steps to theTracksCount
set progress completed steps to 0
set progress description to "Updating tracks info..."
set progress additional description to "Preparing to process."
set libraryTracksIter to 1
end tell
repeat with iTracks in libraryTracksRef
tell me
set progress additional description to "Processing track " & libraryTracksIter & " of " & theTracksCount
end tell
set libName to name of iTracks
set libAlbum to album of iTracks
set libArtist to artist of iTracks
repeat with t in xmlTracksListRef
set xmlTrackName to the name of t
set xmlAlbumName to the album of t
set xmlArtistName to the artist of t
set xmlPlayCount to playCount of t
set xmlPlayDate to playDate of t
set xmlSkipCount to skipCount of t
set xmlSkipDate to skipDate of t
set xmlLoved to lovedStatus of t
if xmlTrackName is equal to libName and ¬
xmlAlbumName is equal to libAlbum and ¬
xmlArtistName is equal to libArtist then
if xmlPlayCount is not missing value then set played count of iTracks to xmlPlayCount
if xmlPlayDate is not missing value then set played date of iTracks to xmlPlayDate
if xmlSkipCount is not missing value then set skipped count of iTracks to xmlSkipCount
if xmlSkipDate is not missing value then set skipped date of iTracks to xmlSkipDate
if xmlLoved is not missing value then
if xmlLoved is true then
set loved of iTracks to xmlLoved
else if xmlLoved is false then
set disliked of iTracks to true
end if
end if
set processedTracksCounter to processedTracksCounter + 1
exit repeat
end if
end repeat
tell me
set progress completed steps to libraryTracksIter
set libraryTracksIter to libraryTracksIter + 1
end tell
end repeat
-- Output of results (just for information)
display dialog "Moved information for " & processedTracksCounter & " matching tracks"
end tell
For example, to check that a key (for example Play Count) exists for some tracks. It would seem that it would be most appropriate to use if exists here. But this results in an error and I had to use try. But even this syntax did not give the desired result, and I had to improvise with the following result:
try
if class of (|Play Count| of t) is integer then set playCount of xmlTrackInfo to (|Play Count| of t)
end try
I couldn’t find information anywhere on how to handle such exceptions, so I used try, and so that it could return true I had to add a strange construction class of (|Play Count| of t) is integer. Perhaps there is a simpler syntax for this case?
There are also some oddities with the behavior of the progressbar. In general, it displays progress correctly. But for some reason, it does not update after each iteration, but only when information for the track has been added. Although I moved the command to update the progressbar outside the loop where the search takes place and adds when there is a match. I mean the line at the very end where:
.
After re-creating the media library and rebooting macOS, the progress bar works as expected.set progress completed steps to libraryTracksIter
I hope for help from more experienced coders
tryis generally fine as the alternative would likely be to stack if..then statements for each field. One thing you might try though is to use a singletrystatement for the five missing value fields. The try statement should allow each if..then to set its field value regardless of whether a value exists or not. Also, you shouldn't need thetell contentsstatement that's inside the System Events block. I'm not sure that it actually does anything in this context.tryblock, which causes all fields to be aborted, even if only one is missing. But I didn’t try to remove thetell contentsblock. To be honest, this is one of the few things left from the version ChatGPT offered me. Almost all the rest of the code had to be completely rewritten. But it helped me a lot with my start.