Niko Matsakis wrote:
>I have a program which identifies duplicates in iTunes and attempts to delete
>them automatically. It seems to work like a charm, except for one problem:
>once I have identified the set of songs to delete, I have to go through them
>one-by-one and delete them. So, if I have accumulated the database_IDs for a
>set of songs into a list 'songdbids', I do something like:
>
> allsongs = app ('iTunes').sources['Library'].playlists
> ['Library'].tracks
> for songdbid in songdbids:
> allsongs.filter (its.database_ID == songdbid).get()[0].delete ()
>
>This works fine when I test on small music collections, but when I try to run
>it across my full set of music it takes forever (as you might imagine).
Running a filter test across all tracks is expensive. On a large playlist,
doing it repeatedly is going to be murder. So this is the operation you want to
minimize/eliminate.
>Now, the number one rule of appscript performance which has been drilled into
>my head is to avoid AppleEvents like the plague.
Yes, although dispatching the events themselves are relatively cheap these days
(context switching in OS X doesn't suck like it did in OS 9); it's the cost of
packing and unpacking their payloads, evaluating queries against the
application's object model, etc. that sucks up most of the cycles. Of course,
the fewer events you send, the less packing/unpacking/querying/etc. is going to
be done as well, so it all pans out in the end. :)
>To that end, it seems like what I want to do is something like:
>
> allsongs.filter (its.database_ID in songdbids]).delete ()
>
>except I don't think that the 'in' operator works,
See ch.8 of the appscript manual for a list of supported comparison forms. Not
all Python operators were amenable to overloading; in this case you need to use
'its.database_ID.isin(songdbids)'.
>and it looks like I'm missing a get() in there in any case.
Depends what you're trying to get. iTunes scripting interface is pretty
extensive, but a lot of the implementation is rather crude and many commands
won't work on more than one object at a time. So the above might work as-is,
but it probably won't, in which case you need to get a list of track references
and tell iTunes to delete each individually:
for song in allsongs.filter (its.database_ID.isin(songdbids)): song.delete()
>Can anyone think of a better way to do this? Perhaps I am on the wrong track
>altogether in working with database_IDs?
They seem to be the obvious way to check for dupes. You just don't want to
perform multiple filter tests across your entire playlist to locate tracks by
DB ID. But a single test shouldn't be too punishing (assuming iTunes can manage
it ok).
>I can't select by album or artist, however, as that would delete both copies
>of the duplicated album (naturally).
And you'd still be running tons of filter tests to do it.
Anyway, try the fixes shown above. If it still doesn't work out well for you,
another option would be to try an alternative approach like:
tracksRef = app('iTunes').playlists['Library'].tracks
d = {}
for id, track in zip(tracksRef.database_ID(), tracksRef()):
d[id] = d.get(id, []) + [track]
for dupes in [i for i in d.values() if len(i) > 1]:
for dupe in dupes[1:]:
dupe.delete()
No idea how that'll compare; getting a list of references to every single track
won't be cheap due to packing/unpacking costs. You just have to experiment.
HTH
has
--
http://freespace.virgin.net/hamish.sanderson/
_______________________________________________
Pythonmac-SIG maillist - [email protected]
http://mail.python.org/mailman/listinfo/pythonmac-sig