Display iTunes Cover & Currently Playing Track

The execute every 1 second caused the problem in the first place.

Actually, it's something with the iTunes Search API, it stopps working after a few sent requests (~25 / minute they say), randomly. See discussion here:
https://forums.developer.apple.com/thread/66399

In order to avoid that, you could make the script execute every 5-10 seconds. I've abused the iTunes API a bit today and I've still encountered some errors (I'm intrigued how yesterday it worked seamlessly), so I've added some changes to the script to retry fetching the artwork if it previously failed.

Here is an updated version that will work with two widget instances (the problem you mentioned earlier) and will handle the iTunes API error (empty response, --Can't get resultCount of ""--). It will display the iTunes Logo but will also retry to fetch the artwork during the next execution.

if application "iTunes" is running then
	tell application "BetterTouchTool" to set priorTrackId to get_number_variable "trackId"
	tell application "iTunes"
		try
			set crtTrckId to id of current track
			set hasCurrentTrack to true
		on error
			set hasCurrentTrack to false
		end try
		--this will show the current track information even if the song is paused 
		--can be changed to display only if playing by removing this: "or hasCurrentTrack is true"
		if player state is playing or hasCurrentTrack is true then
			if id of current track is not priorTrackId then
				tell current track
					--track from Library, has local artwork 
					if exists (every artwork) then
						tell artwork 1
							set srcBytes to raw data
							-- figure out the proper file extension
							if format is «class PNG » then
								set ext to ".png"
							else
								set ext to ".jpg"
							end if
						end tell
						set fileName to ((((path to application support folder from user domain) as text) & "BetterTouchTool:" as text) & "itunes_cover" & ext)
						tell application "BetterTouchTool" to set_number_variable "failedToRetrieveArtwork" to 0
						-- write to file
						set outFile to open for access file fileName with write permission
						-- truncate the file
						set eof outFile to 0
						-- write the image bytes to the file
						write srcBytes to outFile
						close access outFile
					else
						--no artwork, will get the info using iTunes API 
						set fileName to my getArtworkFromAPI(name, artist, album)
					end if
					set currentTrackInfo to my updateTrackInfo(id, name, artist, fileName)
				end tell
				return currentTrackInfo
			else
				tell application "BetterTouchTool" to set failedToRetrieveArtwork to get_number_variable "failedToRetrieveArtwork"
				if (failedToRetrieveArtwork is 0) then
					--serve the previously found track info 
					tell application "BetterTouchTool" to set currentTrackInfo to get_string_variable "currentTrackInfo"
					return currentTrackInfo
				else
					--failed to fetch the artwork, retry
					set fileName to my getArtworkFromAPI(name of current track, artist of current track, album of current track)
					set currentTrackInfo to my updateTrackInfo(id of current track, name of current track, artist of current track, fileName)
					return currentTrackInfo
				end if
			end if
		else
			--itunes is running but has no current track, hide the widget
			return ""
		end if
	end tell
else
	--itunes is not running, hide the widget
	return ""
end if

on getArtworkFromAPI(name, artist, album)
	--sets the artwork to the iTunes icon as a fallback. Will get overwritten if the real one is found 
	set fileName to (((path to application "iTunes") as text) & "Contents:Resources:iTunes.icns")
	
	set searchTerm to name & " " & artist & " " & album
	set responseData to do shell script "curl --data-urlencode \"term=" & searchTerm & "\" --data-urlencode \"limit=1\" https://itunes.apple.com/search"
	
	tell application "JSON Helper"
		set responseJson to read JSON from responseData
		try
			set resultCount to resultCount of responseJson
			tell application "BetterTouchTool" to set_number_variable "failedToRetrieveArtwork" to 0
		on error
			tell application "BetterTouchTool" to set_number_variable "failedToRetrieveArtwork" to 1
			set resultCount to 0
		end try
		
		if (resultCount is not 0) then
			set previewUrl to artworkUrl60 of item 1 of results of responseJson
			do shell script "curl " & previewUrl & " > $HOME/Library/Application\\ Support/BetterTouchTool/itunes_cover.jpg"
		end if
	end tell
	
	if (resultCount is not 0) then
		set fileName to ((((path to application support folder from user domain) as text) & "BetterTouchTool:" as text) & "itunes_cover" & ".jpg")
	end if
	
	return fileName
end getArtworkFromAPI


on updateTrackInfo(trackId, artistName, trackName, fileName)
	set maxSize to 60
	set trackInfo to artistName & " - " & trackName
	
	set currentTrackInfo to "{\"text\":\"" & trackInfo & "\", \"icon_path\":\"" & (POSIX path of fileName as text) & "\"}"
	tell application "BetterTouchTool" to set_string_variable "currentTrackInfo" to currentTrackInfo
	tell application "BetterTouchTool" to set_number_variable "trackId" to trackId
	
	return currentTrackInfo
end updateTrackInfo
1 Like

Changed the script, lowered the refresh rate, and it seems to work! :slightly_smiling_face:
I'm gonna do my little adjustments later on, but this is really great! Nice work!

1 Like

Hey,
You already tested this with Catalina? I tried to replace all iTunes coming up with "Music", but it still fails unfortunately :confused:

Don't know if apple may have changed something in their links you get the covers from?

Greetings from Zorilor :wink:

Here is my non working script by the way :slightly_smiling_face:

if application "Music" is running then
	tell application "BetterTouchTool" to set priorTrackId to get_number_variable "trackId"
	try
		tell application "Music"
			try
				set crtTrckId to id of current track
				set hasCurrentTrack to true
			on error
				set hasCurrentTrack to false
			end try
			--this will show the current track information even if the song is paused 
			--can be changed to display only if playing by removing this: "or hasCurrentTrack is true"
			if player state is playing or hasCurrentTrack is true then
				if id of current track is not priorTrackId then
					tell current track
						--track from Library, has local artwork 
						if exists (every artwork) then
							tell artwork 1
								set srcBytes to raw data
								-- figure out the proper file extension
								if format is «class PNG » then
									set ext to ".png"
								else
									set ext to ".jpg"
								end if
							end tell
							set fileName to ((((path to application support folder from user domain) as text) & "BetterTouchTool:" as text) & "music_cover" & ext)
							tell application "BetterTouchTool" to set_number_variable "failedToRetrieveArtwork" to 0
							-- write to file
							set outFile to open for access file fileName with write permission
							-- truncate the file
							set eof outFile to 0
							-- write the image bytes to the file
							write srcBytes to outFile
							close access outFile
						else
							--no artwork, will get the info using Music API 
							set fileName to my getArtworkFromAPI(name, artist, album)
						end if
						set currentTrackInfo to my updateTrackInfo(id, name, artist, fileName)
					end tell
					return currentTrackInfo
				else
					tell application "BetterTouchTool" to set failedToRetrieveArtwork to get_number_variable "failedToRetrieveArtwork"
					if (failedToRetrieveArtwork is 0) then
						--serve the previously found track info 
						tell application "BetterTouchTool" to set currentTrackInfo to get_string_variable "currentTrackInfo"
						return currentTrackInfo
					else
						--failed to fetch the artwork, retry
						set fileName to my getArtworkFromAPI(name of current track, artist of current track, album of current track)
						set currentTrackInfo to my updateTrackInfo(id of current track, name of current track, artist of current track, fileName)
						return currentTrackInfo
					end if
				end if
			else
				--Music is running but has no current track, hide the widget
				return "^Music"
			end if
		end tell
	end try
	
else
	--Music is not running, hide the widget
	return "^Music"
end if

on getArtworkFromAPI(name, artist, album)
	--sets the artwork to the Music icon as a fallback. Will get overwritten if the real one is found 
	try
		set fileName to (((path to application "Music") as text) & "Contents:Resources:Music.icns")
		
		set searchTerm to name & " " & artist & " " & album
		set responseData to do shell script "curl --data-urlencode \"term=" & searchTerm & "\" --data-urlencode \"limit=1\" https://music.apple.com/search"
	end try
	
	tell application "JSON Helper"
		try
			set responseJson to read JSON from responseData
			try
				set resultCount to resultCount of responseJson
				tell application "BetterTouchTool" to set_number_variable "failedToRetrieveArtwork" to 0
			on error
				tell application "BetterTouchTool" to set_number_variable "failedToRetrieveArtwork" to 1
				set resultCount to 0
			end try
		end try
		
		if (resultCount is not 0) then
			set previewUrl to artworkUrl60 of item 1 of results of responseJson
			do shell script "curl " & previewUrl & " > $HOME/Library/Application\\ Support/BetterTouchTool/music_cover.jpg"
		end if
	end tell
	
	if (resultCount is not 0) then
		set fileName to ((((path to application support folder from user domain) as text) & "BetterTouchTool:" as text) & "music_cover" & ".jpg")
	end if
	
	return fileName
end getArtworkFromAPI


on updateTrackInfo(trackId, artistName, trackName, fileName)
	set maxSize to 60
	set trackInfo to artistName & " - " & trackName
	
	set currentTrackInfo to "{\"text\":\"" & trackInfo & "\", \"icon_path\":\"" & (POSIX path of fileName as text) & "\"}"
	tell application "BetterTouchTool" to set_string_variable "currentTrackInfo" to currentTrackInfo
	tell application "BetterTouchTool" to set_number_variable "trackId" to trackId
	
	return currentTrackInfo
end updateTrackInfo

--Thanks to @buseco for the base of the code!

Do you have a working version now? :sweat_smile:

Unfortunately not, but I didn't dive in either :confused: I'll check one of these days if I find the correct links! @buseco any chance you already looked into it? :innocent:
For now I ended up using the native Now Playing widget with the "Icon only, no text" setting, and my personal script for the artist & title. Looks quite the same.



Encounters some trouble though with covers of songs that are not in Apple Music and added manually to my library. #bug-reports @Andreas_Hegenberg