Getting tracks that don't have artwork in iTunes

Does anyone know a filter form that will work to get a list of tracks without artwork in iTunes? I’ve tried all kinds of variations, but nothing works. I’ve had to resort to looping through the entire track list and testing for artwork with exists artwork. There must be a better way. So far I’ve tried:


	set myList to every file track of library playlist 1 where (not (exists artwork))
	set myList to every file track of library playlist 1 where (count artwork = 0)
	set myList to every file track of library playlist 1 whose artwork is missing value

Nothing seems to work. What am I missing?

Perhaps it’s a reference. I think you’re looking for artwork 1

Kevin:

I had a long, rambling reply for you, but it would not upload. Anyway, I will email it to you. Here is the short version of what seems to work here, so long as there are no videos in your iTunes library:

tell application "iTunes" to set b to every track of first library playlist whose format of artwork 1 is «class

Craig,

Got your email and though I think you’ve found a solution that works, I’m still wondering if there isn’t a way to get what I’m after through “normal” means.

If there isn’t a filter form that will work, Apple should invent one.

Do not know if this will help.

NOTE IT WILL OVERWRITE ANY COMMENTS YOU HAVE IN YOU TRACK INFO


set last_album to {}
set missing_Art to {}
global last_album, missing_Art
tell application "iTunes"
	if not ((name of playlists) contains "No Artwork") then
		display dialog "You need to make a Smart playlist with the name" & return & return & "No Artwork" & return & return & "and set the :match: to :Contains: " & return & return & "No Artwork" & return & return & " and the run the script again" buttons {"OK"} default button 1
		
	else
		my missing_()
	end if
	
end tell

on missing_()
	tell application "iTunes"
		
		set missing_Art to {}
		set the_tracks to (every file track of library playlist 1)
		
		repeat with i from 1 to number of items in the_tracks
			set the_track to item i of the_tracks
			
			tell the_track
				set album_name to album
				if album_name is not in last_album then
					--set last_album to album_name
					copy album_name to end of last_album
					try
						set artwork_data to data of artwork 1 of the_track
					on error errmsg
						if errmsg contains "Memory" then
							set album_name to album_name as string
							copy album_name to end of missing_Art
							
						end if
					end try
				end if
			end tell
			
		end repeat
	end tell
	tell application "iTunes"
		repeat with i from 1 to number of items in missing_Art
			set the_album to item i of missing_Art
			set comment of (every track of library playlist 1 whose album is the_album) to "No Artwork"
		end repeat
	end tell
end missing_

I was looking at this about 6 months ago, and couldn’t work it out.

i ended going through my 4000+ songs.

i wrote up this script which made it easy to get the quality artwork that I wanted.
http://bbs.applescript.net/viewtopic.php?id=15859

Thanks to everyone that threw ideas my way. In the end, here’s what happened…

I originally posted because I have a program that “fetches” artwork for songs in iTunes (Corripio). I have a bunch of CD’s and ripped them all rather than (PAY) download them from iTunes. Why buy the milk when you already own a cow, right?

So…the problem was that Corripio couldn’t find a lot of the artwork (I have some older CD’s and things that aren’t “mainstream”). So I wanted to know which songs/albums didn’t have artwork. I wrote a script that will take a graphic file and add it to selected tracks and one that adds art to albums and wanted to use them, but needed to find out (without searching my whole library of 800+ items) which ones didn’t have art.

In the end, I realized that Corripio had that info in the “artwork” column and I just needed to sort it by number of artworks. At that point I realized I didn’t actually need that many, so I went and found the ones I needed. (Oddly, Meatloaf’s “Bat Out of Hell” and Bill Haley’s “Rock Around The Clock” weren’t found in an automated search! Go figure…:P)

Then I ran my scripts and added the graphics I found. There were a couple of compilation albums where Corripio wouldn’t apply the same cover art to all songs because they were by different artists.

But at this point, the dragon is slain and the village is safe for music lovers…:slight_smile:

Just to finish out the topic, I thought I should post the scripts I wrote, just for completeness. I found some useful stuff in this thread by ryanpatr and kel and just adapted it to use in my own script.

Here’s the script that adds a piece of artwork to selected tracks:

tell application "iTunes" to set mySel to the selection
if length of mySel is not 0 then
	--Get the artwork file
	set theArt to choose file with prompt "Choose art file" without invisibles and multiple selections allowed
	--convert the image
	tell application "Image Events"
		launch
		set imageFile to (open theArt)
		set theArt to (theArt as text) & ".PICT"
		save imageFile as PICT in theArt
	end tell
	
	--add the artwork to the track
	tell application "iTunes"
		set theArtwork to (read file theArt from 513 as artwork)
		repeat with myTrack in items of mySel
			set myArtworks to count artwork of myTrack
			if exists artwork of myTrack then
				set data of artwork (myArtworks + 1) of myTrack to theArtwork
			else
				set data of artwork 1 of myTrack to theArtwork
			end if
		end repeat
		display dialog "Done adding artwork."
	end tell
else
	display dialog "No tracks selected." buttons {"OK"} default button "OK"
end if

And here’s the one that presents a list of albums for you to add artwork to. NOTE: This script uses my quicksort routine from my Nite Flite Script Library that’s in Scriptbuilders. This script reads your entire library and puts together a list of albums (based on the album property of the file tracks), sorts it, and lets you choose to add a graphic to all songs on the album:

set AppleScript's text item delimiters to {} --can mess up the script path if not reset
--load the sort library
set scriptPath to (path to scripts folder from user domain) & "Script Library:"
--uses the quicksort routine from my Nite Flite library
--available on Scriptbuilders
set sortLib to load script ((scriptPath as text) & "sortLib.scpt") as alias
-- get album list from iTunes
set shortAlbumList to {}
tell application "iTunes" to tell (get album of tracks of library playlist 1) to set {albumList, tcount} to {it, count it}
repeat with i from 1 to tcount
	tell my albumList's item i to if it is not in my shortAlbumList and it ≠ "" then set end of my shortAlbumList to it
end repeat
--get an album from the user
set shortAlbumList to sortLib's quickSort(shortAlbumList)
set theAlbum to (choose from list shortAlbumList with prompt "Add artwork to what album?" without multiple selections allowed) as text
--Get the artwork file
set theArt to choose file with prompt "Choose art file" without invisibles and multiple selections allowed
--convert the image
tell application "Image Events"
	launch
	set imageFile to (open theArt)
	set theArt to (theArt as text) & ".PICT"
	save imageFile as PICT in theArt
end tell
--add the artwork to the album
tell application "iTunes"
	set theArtwork to (read file theArt from 513 as artwork)
	set myList to (every file track of the library playlist 1 whose album is theAlbum)
	repeat with myTrack in myList
		set myArtworks to count artwork of myTrack
		if exists artwork of myTrack then
			set data of artwork (myArtworks + 1) of myTrack to theArtwork
		else
			set data of artwork 1 of myTrack to theArtwork
		end if
	end repeat
	display dialog "Done adding artwork."
end tell

Kevin:

I have not looked at the code, but a project was just posted over in ScriptBuilders that may be interesting:

http://scriptbuilders.net/files/itunesfindartworkless1.0.html

I checked: without a repeat loop it is impossible to get a list of tracks that do not have artworks. However, you can get this list quite quickly if you move the repeat loop outside the application tell block.

The following script gives me Database IDs of songs (180 filtered out of 195 original ones) - in 6 msec.
 

noArtworkSongs()

on noArtworkSongs() -- returns Database ID list
	local tracksList, artworksList, filteredList
	tell application "Music" to tell tracks of library playlist 1 to ¬
		set {tracksList, artworksList} to {database ID, artworks}
	set filteredList to {}
	repeat with i from 1 to count tracksList
		if artworksList's item i is {} then set end of filteredList to tracksList's item i
	end repeat
	return filteredList
end noArtworkSongs

 

FWIW, this is also easily done with the Shortcuts app.

Here is my script that set a property to tracks that have missing artwork

property badTracks : {}

on noArtworkSongs()
	local allTracks, aTrack, trackArt
	tell application "Music"
		set allTracks to tracks
		repeat with aTrack in allTracks
			set trackArt to artworks of aTrack
			if (count trackArt) = 0 then
				set end of my badTracks to contents of aTrack
			end if
		end repeat
	end tell
end noArtworkSongs

Doug’s Applescripts has some premade tools.
Also check out his tips and clippings

Your script doesn’t do the same thing, and is 10 times slower than mine. Firstly, my script does not receive all the songs in the library, but only the first playlist. Secondly, it filters song IDs, not Titles. Third, your repeat loop is not organized efficiently.

But most importantly, the iTunesLibrary framework works differently than Music.app, returning the wrong result. It also returns song IDs in integers form (some negative integers as well !!!) instead of hexadecimal. NOTE: It may have worked fine with iTunes.

Here is an AsObjC “analogue” of my plain Applescript script, which gives 183 filtered songs instead of 180. Also, no matter how hard I tried to increase the speed of the AsObjC script, it is 4-5 times slower than mine:

NOTE: I wrote it only for test purpouse, it gives wrong resuls, so I sugges to use my plan AppleScript version instead.
 

use framework "Foundation"
use framework "iTunesLibrary"
use scripting additions

-- Get the main iTunes library
set {ITLibrary, theError} to current application's ITLibrary's alloc()'s initWithAPIVersion: "1.0" |error|:(reference)
set mainPlaylist to ITLibrary's allPlaylists()'s objectAtIndex:1
set alltracks to mainPlaylist's |items|()
set IDList to (alltracks's persistentID) as list
set flagsList to (alltracks's hasArtworkAvailable) as list

-- Filter tracks with no album artwork
set tracksWithNoArtwork to {}
repeat with i from 1 to count flagsList
	if item i of flagsList is 1 then set end of tracksWithNoArtwork to IDList's item i
end repeat
return tracksWithNoArtwork

 

@Fredrik71,

I agree that for a huge library of songs it is better to use something without the AppleScript language’s repeat loop. It’s just that you didn’t notice that AsObjC can do without a repeat loop. The following script is only 3-4 times slower (for a library of 195 songs) than my plain-AppleScript version.

For a large library it will be much faster than my plain-AppleSript version:
 

use framework "Foundation"
use framework "iTunesLibrary"
use scripting additions

tracksWithNoArtwork()

on tracksWithNoArtwork()
	set {ITLibrary, theError} to current application's ITLibrary's alloc()'s initWithAPIVersion:"1.0" |error|:(reference)
	set mainPlaylist to ITLibrary's allPlaylists()'s objectAtIndex:1
	set alltracks to mainPlaylist's |items|()
	set thePred to current application's NSPredicate's predicateWithFormat:"self.hasArtworkAvailable = 1"
	return ((alltracks's filteredArrayUsingPredicate:thePred)'s title) as list
end tracksWithNoArtwork

 

1 Like

I updated my scripts to “1.0”.

NOTE: instead of the titles list the user can return persistent IDs list. Just replace in the last script the “title” with “persistentID”.

If your using the iTunesLibrary framework then you should be able to use one predicate and filter the whole thing.

AppleScript sometimes has troubles with NSPredicates