0

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: set progress completed steps to libraryTracksIter. After re-creating the media library and rebooting macOS, the progress bar works as expected.

I hope for help from more experienced coders

2
  • I think your use of try is 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 single try statement 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 the tell contents statement that's inside the System Events block. I'm not sure that it actually does anything in this context. Commented Jan 11, 2024 at 22:56
  • 2
    Thanks for the comment! I've tried using a single try block, which causes all fields to be aborted, even if only one is missing. But I didn’t try to remove the tell contents block. 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. Commented Jan 12, 2024 at 22:26

1 Answer 1

0

If I well understand, you want to manage error when playCount does not exist or is not an integer. Then I suggest the following:

try
   set playCount of xmlTrackInfo to (|Play Count| of t)
on error -- it only goes here is previous statment can't be executed
   Set playCount to 0
end try
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.