Apple Script to display current artwork from Music

So, here is the thing:

The Now Playing widget is great! But as soon as you get a Notification with sound from any non-system App such as Telegram, the Artwork of the song will remain changed - displaying the icon of the App that sent a notification. Super annoying.

So, here is the thing.
The script

-- get the raw bytes of the artwork into a var
tell application "Music" to tell artwork 1 of current track
	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
-- get the filename to ~/Desktop/cover.ext
set fileName to ((((path to application support folder from user domain) as text) & "BetterTouchTool:" as text) & "music_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
return fileName

Saves the artwork inside the BTT folder. But how can I get it from there in my Touch Bar using an Apple Script Widget? Can I transform it easily into a base64 string or can I display the jpg right away? Help is welcome!

Also, #bug-reports @Andreas_Hegenberg as I don't know if the described behavior of the native widget is normal! :slightly_smiling_face:

	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 (("/Users/" & (system attribute "USER") & "/Library/Application Support/BetterTouchTool/" as text) & "itunes_cover" & ext)
			
			tell application "Finder" to set cover_file to POSIX path of fileName
			-- write to file
			set outFile to open for access cover_file 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
		end if
	end tell
	
	--blahblah, some other code, 
	return "{\"text\":\"" & trackInfo & "\",\"font_color\": \"255,255,255,255\", \"icon_path\":\"" & (POSIX path of fileName as text) & "\"}"

I modified the code in AquaTouch, and it look like this in touch bar:

1 Like

Some very minor points:

  1. If you prefer the system attribute command to the path to command, it's better in this instance to use system attribute "HOME" rather than system attribute "USER". The latter, of course, returns the user's login name, however, not only does this definitely have to match the name of the user's home directory, but the home directory doesn't necessarily have to reside in the /Users folder. Therefore, reading the value from the "HOME" environment variable will be more reliable, and also give you a full path, i.e. /Users/%USER%/ in most cases, but /var/macOS/ in my case.

  2. "/Users/" & (system attribute ...) & "/Library/..." are three strings that are concatenated together to form a string. Therefore, there's no need to coerce it to text as well. The line simplifies to:

    set fileName to (system attribute "HOME") & "/Library/Application Support/BetterTouchTool/itunes_cover" & ext
    
  3. No need to tell application "Finder" to do anything in this script, thankfully. Finder is awful, and will just slow everything down. That line can simply reduce to:

    set cover_file to the POSIX path of the filename
    
  4. open for access and close access have a few specific uses, the most of important of which are in locking a file if the read or write operation is going to take a long time; or to obtain a reference to a file handle to use throughout various parts of a script or in different scripts. However, for the majority of cases, we can forgo their involvement, and they actually end up causing more hassle if one doesn't implement effective error-catching so as to ensure one doesn't leave a file handle open in the event of an unexpected early termination of the script before close access has been invoked. Much simpler just to write srcBytes to outFile without the open for access call, and then there's no need to close access.

    Below, you'll see that I do actually make a call to these two commands, but in immediate succession to one another. This is a quick and simple way to create a file if one doesn't already exist.

  5. Lastly, POSIX path of fileName as text, again, is a redundant coercion, as POSIX path of returns a text object. Coercions are pretty expensive operations, so doing them needlessly slows things down.

I re-worked the script slightly, which I hope benefits the OP. It should be quicker in theory but, of course, it's such a small script, one isn't going to notice in practice. It also converts whatever format the raw data is in to jpeg format, to reduce the file size. For example, a 433KB png file squeezes into a 72KB jpeg, which will be less work (data) for both Better Touch Tool, but, more valuably, the touch bar, to process and render.

use application id "com.apple.Music"
use scripting additions
---------------------------------------------------------------------
property json : a reference to [¬
	"{\"text\": \"", my trackInfo, "\",", ¬
	" \"font_color\": \"255,255,255,255\",", ¬
	" \"icon_path\": \"", my imgPath, "\"}"]

property BTTdir : POSIX path of (path to ¬
	application support folder from ¬
	user domain) & "BetterTouchTool"
property filename : "itunes_cover.jpg"

property artwork : a reference to the current track's artworks
property raw data : a reference to raw data of my artwork
property track : a reference to the current track's name
property artist : a reference to the current track's artist
---------------------------------------------------------------------
set [imgPath, trackInfo] to ["", ""]

if not (my raw data exists) then return the json's contents as text

set trackInfo to my artist & " — " & my track
set [X] to my raw data

# set BTTdir to system attribute "TMPDIR" -- for debugging
set imgPath to BTTdir & "/" & filename
close access (open for access imgPath)
set eof of imgPath to 0
write X to imgPath
set the clipboard to (read imgPath as "TIFF")
set eof of imgPath to 0
write (the clipboard as "JPEG") to imgPath
set the clipboard to

return the json's contents as text
----------------------------------------------------------------‹END›
2 Likes

Thanks a lot of your help to both of you!
Unfortunately non of the two codes really works out here :frowning:
@CJK's solution is flickering on my Touch Bar, appearing and disappearing again and again, driving me kinda nuts :smiley:
Sometimes the widget will just return {"text": "", "font_color": "225,225,225,225", "icon_path": ""} (so basically the output w/o any json content), sometimes it displays the song correctly.
Also the use of the clipboard drives me crazy as I try to copy paste some text and then the cover is pasted… :wink:

@Noon_Chen's solution doesn't give any output at all :confused:

RE: clipboard, understood. It was one way to avoid having to determine what type of image data we were dealing with, but it's not needed, or the clipboard can have its previous contents restored. I'll sort this out this week.

RE: flickering, how often have you set the script to run ? If you change this line:

if not (my raw data exists) then return the json's contents as text

to this:

if not (my raw data exists) then return

or, if you delete the line completely, how does it behave then ? I'm curious so I know for the future, as your script doesn't have any way to handle situations for when there is no track selected, yet I'm assuming this doesn't cause a problem with the touch bar widget. This implies to me that if a script throws an error, the widget doesn't get updated, which may be advantageous in many ways. Currently, that line above is ensuring a result is always returned, and I suspect the flickering is a result of the script running too often, and iTunes not being able to return the raw image data quickly enough to keep up.

I think deleting the line might be the solution, as it will then force my script to throw an error in similar situations as yours. But I'd be interested to know what happens if it just does ...then return without any JSOn data.

1 Like

@CJK Thanks! Very helpful!

@Caliguvara :joy:That's because I omitted some code...
image

You can follow CJK's suggestion and come up with a better solution~ I would try it later today.

lol Don't ask me why, but it stays still for days now, that's also the reason for my late reply :man_shrugging:t4:
Deleting the line doesn't seem to change the behaviour in a quick test neither. :smiley: Thanks for your great hint too!
And as a bonus, even the clipboard won't get messed up any more… Voodoo my Mac :flushed:

How ? I didn't update the script. Or did you do it ? Although, thinking about it, it should never have retained the cover art on the clipboard as the penultimate line set the clipboard to clears the clipboard.