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
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
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.
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_
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…
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
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
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
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
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