Identifying repeat tracks on iTunes script - applescript

(Frustrated I can't figure out to do this with a 'where...' command.)
How can I add a song from my iTunes library to my playlist xMusic, ensuring it hasn't been added already?
At the moment I have an 'add some song whose genre is...' command and then a separate script to remove duplicates, but I'd rather make sure I'm not adding duplicates in the first place.
Is there a way I can write something like 'set theSong to some song from playlist Music whose genre is Rock and whose name is not {go through titles of all other tracks so far added to xMusic}
Copy/Duplicate theSong to xMusic'.

use application "iTunes"
set thePlaylistThatNeedsMoreSongs to user playlist "Music To Die To"
--> user playlist id 22255 of source id 66 of application "iTunes"
set theSongIWantToAdd to the first file track whose artist is "Raign"
-- These are the playlists that contain theSongIWantToAdd
playlists of theSongIWantToAdd
--> {user playlist id 20895 of source id 66 of application "iTunes",¬
--> user playlist id 22255 of source id 66 of application "iTunes"}
-- Now check if thePlaylistThatNeedsMoreSongs is in that list:
id of thePlaylistThatNeedsMoreSongs is in id of playlists of theSongIWantToAdd
if the result is true then
"Pick another track"
else
add theSongIWantToAdd to thePlaylistThatNeedsMoreSongs
end if
Is that sort of what you wanted ?

Related

How can I delete Apple Music tracks from my Library using AppleScript?

My Apple Music library is too big. I want to weed it out by removing a whole load of tracks that I have never listened to. I already did the same thing successfully with playlists but my script isn't working to remove tracks:
tell application "Music"
activate
set mytracks_list to (get the id of (every track whose loved is false and played count is 0 and rating is less than 60))
repeat with mytrack_id in mytracks_list
delete (the track whose id is mytrack_id)
end repeat
end tell
The mytracks_list is populated with no problems. The error message I get is:
error "Can’t get track whose id = item 1 of {130098, [............] }
Am I doing something wrong, and can it be made to work?
P.S. This is what worked for my playlists:
tell application "Music"
activate
set myplaylists_to_delete to (get the name of every playlist whose name does not contain "Adrian" and name does not contain "Loved" and name does not contain "Shazam" and name does not contain "Library" and name is not "Music" and name does not contain "Recent" and name does not contain "5 Stars" and name does not contain "Duo")
repeat with myplaylist in myplaylists_to_delete
delete playlist myplaylist
end repeat
end tell
Did you try:
tell app "Music"
delete every track whose loved is false and played count is 0 and rating is less than 60
end tell
Well-designed, well-implemented “AppleScriptable" apps can usually apply a command to multiple objects; you don’t need to iterate the objects yourself. (Hint: Apple event IPC = RPC + queries, not OOP.)

AppleScript - Get complete information of current iTunes track

I'm trying to return the information of the current iTunes Track, which is playing on my computer.
I can get single informations like this:
tell application "iTunes"
get name of current track
end tell
This returns Thunderstruck for example.
But is it possible that I can get more information of the current track so it returns something like this:
"AC/DC, Thunderstruck, Iron Man 2"
Is this possible? Or do I have to create multiple scripts?
Thanks
To get name, artist and album
tell application "iTunes"
get {name, artist, album} of current track
end tell
The result is a list
To get everything
tell application "iTunes"
get properties of current track
end tell
The result is a record

iTunes AppleScript: query all playlists that contain a certain track

Working on a complex AppleScript for iTunes. One task is to accumulate a list of all playlists which contain a given track. I have this track object from somewhere else (a selection or whatever).
Currently, I've got a snippet something like this:
on containingPlaylists(theTrack)
tell application "iTunes"
set librarySource to the source named "Library"
set candidateLists to every user playlist in librarySource
set candidateId to (get id of theTrack)
set matchLists to {}
repeat with candidateList in candidateLists
set matchTracks to (file tracks in candidateList whose id = candidateId)
if (count of matchTracks) > 0 then
copy candidateList to end of matchLists
end if
end repeat
return matchLists
end tell
end containingPlaylists
This works but requires one Apple Event per playlist in the loop, which is expensive (perf) and throws away the intermediate results. What I'd RATHER do is something all in one query:
set matchLists to every playlist in librarySource whose file tracks contain theTrack
But this of course doesn't work (the particular error is "Handler only handles single objects." but not sure if that's insightful). I'm really just not sure if the language/app supports a query like this.
Can anyone confirm/deny/offer any insight? Thanks!
You can use this (work on iTunes 11 and 12):
tell application "iTunes"
set theTrack to item 1 of (get selection)
return user playlists of theTrack
end tell
Updated --
In the AppleScript dictionary:
artwork n [inh. item] : a piece of art within a track |
elements : contained by tracks. So artworks of thisTrack works
track n [inh. item] : playable audio source |
elements : contains artworks; contained by playlists. So playlists of thisTrack works, you can use user playlists of thisTrack
In iTunes.h (ObjC scripting bridge):
#interface iTunesTrack : iTunesItem
- (SBElementArray *) artworks;
it's not possible because playlists is not in the SBElementArray's list.
But I do not know why there is a difference between the AppleScript dictionary and the iTunes.h file.
I too wish a whose clause like that could be used. But alas. Someone else might come up with a better plan, but I'm pretty sure this is how I would find the playlists containing the selected track (it may be the most efficient):
set persisID to persistent ID of selection
set pp to playlists
set playListsWithIt to {}
repeat with p in pp
set tt to (tracks of p whose persistent ID is persisID)
if tt ≠ {} then set playListsWithIt to (playListsWithIt & (id of p))
end repeat
Then I can use those IDs for the next step. This includes, of course, playlists like "Recently Added", which may or may not be what you want; you'd have to put another step in there to 'filter' out such a result.

Any way to improve the performance of this Applescript iTunes Code?

I wrote a script that would identify duplicates in iTunes, find their instances in playlists, and other things which I don't think are relevant. In order to check if a track is a duplicate, I have the following code:
set duplicateSongs to ¬
get (every track of playlist 1 where ¬
(name is equal to (name of currentTrackToCheck as text) and ¬
database ID is not equal to (database ID of currentTrackToCheck as integer) and ¬
time is equal to (time of currentTrackToCheck as text)))
I wrote and tested this against a test library with 1,000 songs and it was speedy. When I tested it against my iTunes library which is about 30,000 songs, then all hell broke loose.
That snippet of code takes 2 minutes to finish processing! Is there any way to make this faster code-wise? I've been reading a lot on AppleScript and I believe using where/whose is the fastest way to filter down results from a query.
Thanks! :-)
It won't affect speed, but I would write it like this...
tell application "iTunes"
set {trackName, trackDatabaseID, trackTime} to {name, database ID, time} of current track
set duplicateSongs to (get every track of playlist 1 whose name = trackName and time = trackTime and database ID ≠ trackDatabaseID)
end tell
Just changed to using the search function and then doing a search within that and it takes less than a second - yay! :-)
on SearchForDuplicates(currentTrackToCheck, iTunesLibrary)
tell application "iTunes"
set duplicateSongs to {}
set preSearch to search iTunesLibrary for (name of currentTrackToCheck as text) only songs
repeat with aTrack in preSearch
tell aTrack
if (name is equal to (name of currentTrackToCheck as text) and ¬
database ID is not equal to (database ID of currentTrackToCheck as integer) and ¬
time is equal to (time of currentTrackToCheck as text)) then
set end of duplicateSongs to aTrack
end if
end tell
end repeat
return duplicateSongs
end tell
end SearchForDuplicates

Error: Can't get some «class» of {«class», «class», ...}

I'm writing an Applescript for use in iTunes in which at some point I want to select any track from a list of tracks, but the way I expected it to work gives an error. Here's the code:
tell application "iTunes"
set thePlaylist to the first playlist whose name is "Missing track count"
-- ...
-- populate a list of strings: albumList
-- ...
repeat with albumName in the albumList
set theAlbum to (the tracks of thePlaylist whose album is albumName)
display dialog "Found " & (count theAlbum) & " tracks in the album"
set aTrack to some track of theAlbum -- ERROR OCCURS HERE
end repeat
end tell
The error I get when I execute the script from within iTunes is:
Can't get some «class cTrk» of {«class cFlT» id 16112 of «class cUsP» id 15982 of «class cSrc» id 65 of application "iTunes", ... etc}
Now, I don't really see why it doesn't work, although I guess it must have something to do with the fact that the items in theAlbum are file tracks from a user playlist from the source from the iTunes application instead of 'just' tracks. Can anyone help me out here?
In this example I use some item instead of some track, which works OK.
tell application "iTunes"
set thePlaylist to the first playlist
set x to (the tracks of thePlaylist)
set aTrack to some item in x
end tell
results in
URL track id 87 of library playlist id 82 of source id 64 of application "iTunes"
Since all the items in your example inherit from track, I don't know why it doesn't work, but it doesn't.
theAlbum is a list, not a playlist, so it doesn't have track elements; it only has items.
The documentation on lists, where it states "You can also refer to indexed list items by class." is incomplete and thus misleading. It seems you can only do this with to built-in classes. From what I can glean, here's why:
Object specifiers (2) are based on key-value coding. A specifier might identify a property (an object attribute or a to-one relationship) or element (a to-many relationship). In the example, we're dealing with elements. To handle elements, the underlying Objective-C class must implement a collection accessor pattern. That is, it must implement at least -<key>, or -countOf<Key> and -objectIn<Key>AtIndex: (it can, of course, implement all of them). The list class does this for a set number of Applescript classes (if you peeked at the ObjC source for the list class, you'd find methods like countOfApplication and -objectInNumberAtIndex:). It could conceivably support arbitrary element object specifiers with an appropriate -doesNotRecognizeSelector: handler, but lists don't appear to have been implemented this way. Since lists don't have -track, -countOfTrack or -objectInTrackAtIndex: handlers, they can't deal with a specifier such as "first track of trackList".

Resources