iTunes – Remove Russian Songs with AppleScript

apple-musicapplescriptitunes

I am from Ukraine and as you know we have a big war with Russia.

Earlier, I used to listen to many Russian songs, but now I want to remove all of them from my iTunes library in order not to give Russians availability to earn money and pay taxes in Russia and prevent sponsoring war. Maybe someone have an idea how to do this?

I think it would be very popular in Ukraine, so you will help not only me.

Thanks.

Best Answer

Thanks everyone who helped me to to find a solution. Finally I wrote the Applescript that find russian tracks and after promting delete them. The script uses musicbrainz API(thanks @SaaruLindestøkke).

PAY ATTANTION!!!

To parse JSON response from API you should install the [JSON Helper App][1] - https://apps.apple.com/us/app/json-helper-for-applescript/id453114608?mt=12, otherwise script won't work.

global russianCities
set russianCities to {"Moscow", "Saint Petersburg", "Novosibirsk", "Yekaterinburg", "Kazan", "Nizhny Novgorod", "Chelyabinsk", "Krasnoyarsk", "Samara", "Ufa", "Rostov-on-Don", "Omsk", "Krasnodar", "Voronezh", "Perm", "Volgograd", "Saratov", "Tyumen", "Barnaul", "Izhevsk", "Makhachkala", "Khabarovsk", "Ulyanovsk", "Irkutsk", "Vladivostok", "Yaroslavl", "Kemerovo", "Tomsk", "Sevastopol", "Stavropol", "Orenburg", "Ryazan", "Penza", "Cheboksary", "Lipetsk", "Kaliningrad", "Astrakhan", "Tula", "Kirov", "Kursk", "Ulan-Ude", "Tver", "Bryansk", "Ivanovo", "Yakutsk", "Vladimir", "Belgorod", "Kaluga", "Chita", "Grozny", "Smolensk", "Saransk", "Vologda", "Kurgan", "Oryol", "Arkhangelsk", "Vladikavkaz", "Yoshkar-Ola", "Murmansk", "Kostroma", "Tambov", "Nalchik", "Blagoveshchensk", "Petrozavodsk", "Veliky Novgorod", "Syktyvkar", "Pskov", "Abakan", "Yuzhno-Sakhalinsk", "Petropavlovsk-Kamchatsky", "Maykop", "Kyzyl", "Cherkessk", "Khanty-Mansiysk", "Elista", "Magadan", "Birobidzhan", "Gorno-Altaysk"}

on isMatchArtistName(appleAPIArtist, brainsAPIArtist)
    if appleAPIArtist contains |name| of brainsAPIArtist or appleAPIArtist contains |sort-name| of brainsAPIArtist then
        return true
    end if
    try
        repeat with al in |aliases| of brainsAPIArtist
            if appleAPIArtist contains |name| of al then
                return true
            end if
        end repeat
    on error errMsg
        --log "ERROR: " & errMsg
    end try
    return false
end isMatchArtistName

on getIsRussianArtist(theArtist, strict)
    
    set weblink to "'https://musicbrainz.org/ws/2/artist' --data-urlencode 'limit=10' --data-urlencode 'fmt=json' --data-urlencode " & quoted form of ("query=" & theArtist)
    log weblink
    
    set curl_command to "curl -G -v " & weblink
    log curl_command
    set res to do shell script curl_command
    
    tell application "JSON Helper"
        set parsedJSON to read JSON from res
        set artists to artists of parsedJSON
        repeat with artist in artists
            set checkArtist to true
            if strict then
                set checkArtist to my isMatchArtistName(theArtist, artist)
            end if
            
            if checkArtist then
                try
                    set theCountry to country of artist
                    if theCountry contains "UA" then
                        return false
                    end if
                    if theCountry contains "RU" then
                        return true
                    end if
                on error errMsg
                    log "ERROR: " & errMsg
                end try
                try
                    set theArea to |name| of area of artist
                    if russianCities contains theArea then
                        return true
                    end if
                on error errMsg
                    log "ERROR: " & errMsg
                end try
            end if
            
        end repeat
    end tell
    return false
end getIsRussianArtist

on composePlaylistName(name, id)
    set nextName to name & "(ID:" & id & ")"
    return nextName
end composePlaylistName

on pickThePlaylist()
    tell application "Music"
        set AllUserPlaylists to every user playlist
        set thePlaylistNames to {}
        repeat with thePlaylist in AllUserPlaylists
            set end of thePlaylistNames to my composePlaylistName(name of thePlaylist, id of thePlaylist)
        end repeat
        set thePickedPlaylistName to choose from list thePlaylistNames with prompt "Select your playlist:"
        set currentPlaylist to first item of AllUserPlaylists
        
        repeat with thePlaylist in AllUserPlaylists
            if thePickedPlaylistName contains my composePlaylistName(name of thePlaylist, id of thePlaylist) then
                return tracks of thePlaylist
            end if
        end repeat
        error "Playlist was not found."
    end tell
end pickThePlaylist


on composeTrackName(artist, name, id)
    set nextName to artist & "-" & name & "(ID:" & id & ")"
    return nextName
end composeTrackName

on pickRussianTracksToDelete(theTracks)
    tell application "Music"
        set theTrackNames to {}
        repeat with theTrack in theTracks
            set end of theTrackNames to my composeTrackName(artist of theTrack, name of theTrack, id of theTrack)
        end repeat
        set thePickedPlaylistNames to choose from list theTrackNames with prompt "Select the tracks you want to delete(this is a multiple selection list, use 'Command (⌘) + Mouse Click' to select/unselect):" default items theTrackNames with multiple selections allowed
        set selectedTracks to {}
        
        repeat with theTrack in theTracks
            repeat with pickedName in thePickedPlaylistNames
                if pickedName contains my composeTrackName(artist of theTrack, name of theTrack, id of theTrack) then
                    set end of selectedTracks to theTrack
                end if
            end repeat
        end repeat
        return selectedTracks
    end tell
end pickRussianTracksToDelete

on promptForStrictMode()
    tell application "Music"
        set theDialogText to "Hello. I will remove russian songs from your playlist. The script is working in two modes: 
    1. Strict - only russian songs will be affected but many songs may be skipped. 
    2. No Strict - finding more russian songs, but also Ukrainian songs might be affected."
        set result to display dialog theDialogText buttons {"No Strict", "Strict"} default button "Strict"
        set isStrict to button returned of result is equal to "Strict"
        return isStrict
    end tell
end promptForStrictMode

on initProgressBar(tracksCount)
    set progress total steps to tracksCount
    set progress completed steps to 0
    set progress description to "Processing Songs..."
    set progress additional description to "Preparing to process."
end initProgressBar
on updateProgressBar(a, tracksCount)
    set progress additional description to "Processing song " & a & " of " & tracksCount
    set progress completed steps to a
end updateProgressBar
on resetProgressBar()
    set progress total steps to 0
    set progress completed steps to 0
    set progress description to ""
    set progress additional description to ""
end resetProgressBar
on findAndDeleteRussianTracks()
    set strict to my promptForStrictMode()
    set currentPlaylist to my pickThePlaylist()
    set delayTime to 0.5
    set russianTracks to {}
    set tracksCount to length of currentPlaylist
    --initial set of progress bar
    my initProgressBar(tracksCount)
    
    repeat with a from 1 to length of currentPlaylist
        set theTrack to item a of currentPlaylist
        delay delayTime
        my updateProgressBar(a, tracksCount)
        tell application "Music"
            set isRussianArtist to my getIsRussianArtist(artist of theTrack, strict)
            if isRussianArtist is true then
                set end of russianTracks to theTrack
            end if
        end tell
    end repeat
    my resetProgressBar()
    tell application "Music"
        if (count of russianTracks) is equal to 0 then
            set theDialogText to "Russian songs were not found. Try another playlist."
            display dialog theDialogText
            return my copyRussianTrackToPlaylist()
        end if
        set selectedTracks to my pickRussianTracksToDelete(russianTracks)
        repeat with theTrack in currentPlaylist
            repeat with theDeleteTrack in selectedTracks
                try
                    if (id of theDeleteTrack) is (id of theTrack) then
                        log "delete" & id of theTrack
                        delete theTrack
                    end if
                on error errMsg
                    log "Error: " & errMsg
                end try
            end repeat
        end repeat
        set theDialogText to "HOORAY! Your Playlist was cleared from russian songs."
        display dialog theDialogText buttons {"Okay"} default button "Okay"
    end tell
end findAndDeleteRussianTracks

my findAndDeleteRussianTracks()
Related Question