if application "Spotify" is running then
tell application "Spotify"
if player state is playing then
set sName to (get name of current track)
set sArtist to (get artist of current track)
if (length of sName) > 25 then
set sName to text 1 thru 22 of sName & "..."
else
set sName to (get name of current track)
end if
if (length of sArtist) > 25 then
set sArtist to text 1 thru 22 of sArtist & "..."
else
set sArtist to (get artist of current track)
end if
set nowPlaying to sName & " — " & sArtist
set artworkURL to artwork url of current track
do shell script "curl " & artworkURL & " -o ~/Library/Application\\ Support/BetterTouchTool/spotify_cover.png"
set fileName to ((((path to application support folder from user domain) as text) & "BetterTouchTool:" as text) & "spotify_cover.png")
return "{\"text\":\"" & nowPlaying & "\", \"icon_path\":\"" & (POSIX path of fileName as text) & "\" }"
return nowPlaying
else
return "Paused"
end if
end tell
else
return ""
end if
Hi there, I have tried this and 3 other ways to get an iTunes now playing widget to work in Mojave dev beta 6 - is it the case that AppleScript is not functioning correctly in the beta yet? I just cannot get any widget to appear at all.
This script is rather inefficient regenerating the artwork and fetching the data upon each check. Personally I use an (old) script/app I wrote that polls when the track changes (and also uses non-embedded artwork).
However here's an updated script for iTunes that avoids much of the overhead by simply checking if the track actually changed before going off and doing stuff—so not unduly expensive on a frequency of say 8 seconds. Recommended with action of 'Play/Pause', icon size of 30, 0 radius, black background, and font size of 12 because it displays album, track and artist on two lines. (Does not change on pause.)
A similar approach should be possible with other apps, but if they don't provide an ID or URL you can just check if the album name changed. Could reuse the same BTT variable across apps although better as string if so.
if application "iTunes" is running then
tell application "BetterTouchTool" to set priorTrackId to get_number_variable "trackId"
tell application "iTunes"
if player state is playing and id of current track is not priorTrackId then
tell current track
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)
-- 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
set fileName to (((path to application "iTunes") as text) & "Contents:Resources:iTunes.icns")
end if
set maxSize to 60
set artistName to artist
set albumName to album
set trackName to name
-- must escape double quotes such as in «12" mix»
set delimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to "\""
set trackName to every text item of trackName
set albumName to every text item of albumName
set artistName to every text item of artistName
set AppleScript's text item delimiters to "\\\""
set trackName to trackName as string
set albumName to albumName as string
set artistName to artistName as string
set AppleScript's text item delimiters to delimiters
if length of trackName is greater than (maxSize / 2) then
set trackName to text 1 thru (maxSize / 2) of trackName & "…"
end if
if length of artistName is greater than (maxSize / 2) then
set artistName to text 1 thru (maxSize / 2) of artistName & "…"
end if
set trackRating to " "
repeat (rating / 20) times
set trackRating to trackRating & "⭑"
end repeat
if length of (albumName & trackRating) is greater than maxSize then
set albumName to text 1 thru (maxSize - (length of trackRating)) of albumName & "…"
end if
set trackInfo to albumName & trackRating & "\\n‘" & trackName & "’ by " & artistName
set trackId to id
tell application "BetterTouchTool" to set_number_variable "trackId" to trackId
end tell
return "{\"text\":\"" & trackInfo & "\", \"icon_path\":\"" & (POSIX path of fileName as text) & "\"}"
end if
end tell
end if
I've got this same issue. Works great for music I have put into my Library, but if I am listening to non-downloaded/non-library music, the icon disappears.
Edit: I am an idiot and did not read replied posts. . Nevermind.
if application "iTunes" is running then
tell application "BetterTouchTool" to set priorTrackId to get_number_variable "trackId"
tell application "iTunes"
if player state is playing and id of current track is not priorTrackId then
tell current track
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)
-- 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
set searchTerm to name & " " & artist & " " & album
set responseJson to do shell script "curl --data-urlencode \"term=" & searchTerm & "\" --data-urlencode \"limit=1\" https://itunes.apple.com/search"
tell application "JSON Helper"
set responseData to read JSON from responseJson
set resultCount to resultCount of responseData
if (resultCount is not 0) then
set previewUrl to artworkUrl60 of item 1 of results of responseData
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")
else
set fileName to (((path to application "iTunes") as text) & "Contents:Resources:iTunes.icns")
end if
end if
set maxSize to 60
set artistName to artist
set albumName to album
set trackName to name
set trackInfo to artistName & " - " & trackName
set trackId to id
tell application "BetterTouchTool" to set_number_variable "trackId" to trackId
end tell
return "{\"text\":\"" & trackInfo & "\", \"icon_path\":\"" & (POSIX path of fileName as text) & "\"}"
end if
end tell
else
return "{\"text\":\"\"}"
end if
Very very nice!! I'm desperately failing to do something like this for weeks now!
Would you mind if I added this to my next Preset update? Credits given at the end of the code of course. Man I love this!!
Edit: I encounter an error that seems to appear randomly: The script gets an error displaying "Can’t get resultCount of ""." (second line after using the JSON helper).
Right now it works (typical ). If it bugs it happens because the Script is unable to get the ID of current track (like with the Riddle). Perdermi by Zero Assoluto returns the iTunes cover. The Riddle by Nik Kershaw prevents showing anything, neither the cover with your script, nor the song information through mine
Also: I use the widget twice, once in my main strip, and in a group. If I change the song to another album while one of them is hidden, the hidden one won't update when it becomes visible - so basically I have always one showing the album of the previous song (yes, 1sec interval refreshment is active, and so is the "Always run when widget becomes visible" box). But this might be rather a #bug-reports for @Andreas_Hegenberg? idk
Also: I use the widget twice, once in my main strip, and in a group. If I change the song to another album while one of them is hidden, the hidden one won't update when it becomes visible - so basically I have always one showing the album of the previous song
This is [probably] because this version of the script checks wether the current song has already been handled to avoid running it multiple times at every X seconds based on your settings. See this line:
if player state is playing and id of current track is not priorTrackId then
You have two scripts. The first one will run, setting the priorTrackID to the current song. The second script will start running a few seconds later, and the current track will be the same with "prior track", so it will do nothing. To check if this is the problem, you can change that line on both scripts to:
if player state is playing then
This isn't very good performance-wise. Could be improved by keeping the actual track data, maybe I'll add an updated version tomorrow if this fixes your problem.
Regarding the artwork problem. On some songs, the iTunes Search API has no data, IDK why. You can check that out doing the curl in Terminal manually or using Postman. For instance, there's no record for Perdermi by Zero Assoluto. The others work fine for me both with the script or by manually sending the request
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
Hey,
You already tested this with Catalina? I tried to replace all iTunes coming up with "Music", but it still fails unfortunately
Don't know if apple may have changed something in their links you get the covers from?
Greetings from Zorilor
Here is my non working script by the way
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!
Unfortunately not, but I didn't dive in either I'll check one of these days if I find the correct links! @buseco any chance you already looked into it?
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.