I’m looking for ways to query/filter/lookup/update all music ID3 tags from Music.app (iTunes). Essentially I’d like to be able to query all arrays like a database without a repeat loop, working with 20+ arrays which all have this same count/index.
I’m thinking that coercing back to AppleScript as text & list should come last, after I have completed every evaluation and updated arrays before I write to file.
If anyone can provide some suggestions as how to go about this while remaining optimised as ASOC NSArray (without repeat loops if possible) that would be greatly appreciated.
In my code below, I wasn’t sure if I needed to first join arrays, using one as the predicate to return the value of other, or if there is a more straight forward way. As an example, I’m trying to find ‘theID’ of all files where ‘thePosixPath’ is NSNull.
tell application "Music"
set theID to current application's NSArray's arrayWithArray:(get persistent ID of every file track in library playlist 1)
set theLocation to current application's NSArray's arrayWithArray:(get location of every file track in library playlist 1)
set theName to current application's NSArray's arrayWithArray:(get name of every file track in library playlist 1)
set theArtist to current application's NSArray's arrayWithArray:(get artist of every file track in library playlist 1)
end tell
--create custom arrays
set thePosixPath to theLocation's valueForKey:"path"
set theParentFolder to theLocation's valueForKeyPath:"URLByDeletingLastPathComponent.lastPathComponent"
-- work in progress, trying to join a few NSArrays....
set joinedArray to {theID:theID, thePosixPath:thePosixPath, theName:theName, theArtist:theArtist}
its itemsWhose:"thePosixPath" isEqualTo:"" inList:joinedArray
on itemsWhose:theProperty isEqualTo:theValue inList:theList
set theArray to current application's NSArray's arrayWithArray:theList
set thePred to current application's NSPredicate's predicateWithFormat:"%K = %@" argumentArray:{theProperty, theValue}
return (theArray's filteredArrayUsingPredicate:thePred)
end itemsWhose:isEqualTo:inList:
You’ll have to build an array of dictionaries, and that’s going to require a repeat loop*. Assuming the data doesn’t change too often, it might make sense to do that and write it to a file, assuming you want to search it regularly.
There are some shortcuts in my BridgePlus script library, using columnsToRowsIn:error: and subarraysIn:asDictionariesUsingLabels:error:, which would do it quite fast.
PS I’m not sure if it’s just using the ITLibrary Framework or just OS X security scopes.
But I had difficulty accessing the location. As I believe it’s a security scoped book mark.
I had to do things like setting up sandbox privileges and then access like this:
Interesting about using the ITLibrary framework. The documents say you app must be code-signed to access it, and that was indeed the case when I last tried it, which was probably when it came out (10.13?). But trying just now on 10.15, that seems no longer to be the case. Even for location:
use framework "Foundation"
use framework "iTunesLibrary"
use scripting additions
set {theLib, theError} to current application's ITLibrary's libraryWithAPIVersion:"1.0" |error|:(reference)
set theFile to theLib's allPlaylists()'s firstObject()'s |items|()'s firstObject()'s location() as «class furl»
It’s not private (it’s in ITLibMediaEntity), but being block-based it’s useless from AppleScript.