Iterate NSDictionary to create further NSDictionary's in Music.app

I’m experimenting with NSDictionary in hope I can optimise code and clean up thousands of tags in Music.app. Mostly Ive been using NSArray in the past.
The end goal is to have a persistent ID as the key with each track property so I can focus on cleaning up that mp3 tag.

I’ve created a master NSDictionary which I want to iterate and create further NSDictionary’s from the key/values within it. You’ll see I can achieve this one way, but need to understand why I’m not able to achieve it in an iterative loop.

Also, Is there anything else I’m forgetting here as far as missing value goes? Was wondering about the potential of the persistent ID becoming mismatched with the values. Let me know if there’s a better way :slight_smile:

use AppleScript version "2.5"
use framework "Foundation"
use scripting additions

tell application "Music"
	set theID to (get persistent ID of every file track of library playlist 1)
	set nsDict to current application's NSDictionary's dictionaryWithObjects:{"name", "artist", "album"} forKeys:{"theName", "theArtist", "theAlbum"}
	
	(*  ----- An example of what I am trying to achieve in a loop --------
		set theName to (current application's NSDictionary's dictionaryWithObjects:(get name of every file track of library playlist 1) forKeys:theID)
		set theArtist to (current application's NSDictionary's dictionaryWithObjects:(get artist of every file track of library playlist 1) forKeys:theID)
		set theAlbum to (current application's NSDictionary's dictionaryWithObjects:(get album of every file track of library playlist 1) forKeys:theID)
	*)
	
set theKeys to nsDict's allKeys()
repeat with thisKey in theKeys
	set thisObject to (nsDict's valueForKey:thisKey)
	set thisKey to (current application's NSDictionary's dictionaryWithObjects:(get thisObject of every file track of library playlist 1) forKeys:theID)
end repeat
	
end tell

I’ve done lots of ITunes scripting working with tab clean up.
Ultimately what is going to be your purpose
And your workflow?

I’ve found it’s going to be slow and potentially dangerous to
Operate on all of your files in your music library.

I’ve found it much better to work with a playlist or selected tracks.
You can then build up your own personal “model” from
There. And process and iterate thru those easier.

Really rethink your code.
I see your trying to create your own dictionary of every
Track getting the persistentID, Name, Artist, Album.
But why?

ITunes already has all of this done for you.
You should consider how your accessing this data.

In your code I was confused by the variable
trackID, you should name it as trackIDs since it
Is a list of IDs.
(same with trackName, trackArtist etc)

I would also rethink the concept of Dictionaries and Arrays.
A Dictionary is usually a record of info/detail about a object.
A Array is a list of objects (which can be a list of Dictionaries)
(use an analogy of sticking things in a folder)

I would approach each track as having it’s own dictionary.
And store these tracks in a Array.

You can then use that Array as a object for a key in a dictionary.
Like a playlist would. A playlist Dict would have keys for “playlistName”, “persistentID”
and “playlistTracks”.


I get that your trying to get 4 lists (Arrays)
trackIDs
trackNames
trackArtists
trackAlbums

and then trying to create a dictionary from that by iterating over them.
But while those lists (remember at this point from your code they are lists and
not NSArrays). are just like folders.

your hoping that each of those 4 lists has in order this info for each track.
But this may not be so. Say your 14th track doesn’t have an Artist…
and your 27th track doesn’t have an album. No all of a sudden your 4
lists are not “linked”.

You can’t use a repeat with I from 1 to (count of trackIDs)
set aID to item I of trackIDs
set aName to item I of trackNames
etc

and hope that those are going to match up.

a few other things about your code:

set theKeys to nsDict's allKeys()
repeat with thisKey in theKeys
	set thisObject to (nsDict's valueForKey:thisKey)
	set thisKey to (current application's NSDictionary's dictionaryWithObjects:(get thisObject of every file track of library playlist 1) forKeys:theID)
end repeat

this is all very confusing.

your repeating with thisKey which is NSString
then your trying to set thisKey as a NSDictionary?
even if you change that to a variable like foundItems

set foundItems to (current application's NSDictionary's dictionaryWithObjects:(get thisObject of every file track of library playlist 1) forKeys:theID)

your not storing it anyplace.
I think what your wanting to do is change your nsDict.
You want to be doing
nsDict’s setObjects:forKeys:
(You’ll need to change to NSMutableDictionary)
And I think you may want to create an intermediate NSDictionary (foundItems)
And then
nsDict’s setValue:foundItems forKey:thisKey


why not just create a list of your keys theKeys
repeat with thisKey
get theItems first
then create a dictionary.


I would also look into NSMutableDictionay which seems I think a bit more what your after.
And also NSMutableArray

Substitute Music for iTunes …

use AppleScript version "2.4"
use framework "Foundation"

-- classes, constants, and enums used
property NSMutableDictionary : a reference to current application's NSMutableDictionary
property NSMutableArray : a reference to current application's NSMutableArray

property processedItems : missing value


on run {}
	set selTracks to my getSelectedTracks()
	set my processedItems to my processTracks:selTracks
end run


-- MAIN FUNCTIONS

on getSelectedTracks()
	set selectedTracks to {}
	try
		tell application "iTunes"
			set sel to selection
			if sel is not {} then
				--	log {"selection is Tracks"}
				repeat with aTrack in sel
					copy aTrack to the end of selectedTracks
				end repeat
			else
				--	log {"selection is Playlist"}
				set thePlaylist to view of the front browser window
				repeat with i from 1 to (index of last track of thePlaylist)
					set aTrack to track i of thePlaylist
					copy aTrack to the end of selectedTracks
				end repeat
			end if
		end tell
	end try
	return selectedTracks
end getSelectedTracks

on processTracks:tracksToProcess
	set theProcessedList to {}
	set theProcessedTracks to NSMutableArray's new()
	repeat with i from 1 to (count of tracksToProcess)
		set aTrack to item i of tracksToProcess
		set theResults to (my processTrack:aTrack)
		set the end of theProcessedList to theResults
		(theProcessedTracks's addObject:theResults)
	end repeat
	-- return theProcessedList
	return theProcessedTracks
end processTracks:

on processTrack:aTrack
	-- do further subFunctions / Processing
	--set theResults to missing value
	set theResults to my createTrackDict:aTrack
	return theResults
end processTrack:

on createTrackDict:aTrack
	set aTrackDict to NSMutableDictionary's dictionary()
	
	tell application "iTunes"
		set aTrackID to persistent ID of aTrack
		set aTrackName to name of aTrack
		set aTrackArtist to artist of aTrack
		set aTrackAlbum to album of aTrack
	end tell
	
	if aTrackName is "" then set aTrackName to "Missing Name"
	if aTrackArtist is "" then set aTrackArtist to "Missing Artist"
	if aTrackAlbum is "" then set aTrackAlbum to "Missing Album"
	
	aTrackDict's setValue:aTrackID forKey:"trackPersistentID"
	aTrackDict's setValue:aTrackName forKey:"trackName"
	aTrackDict's setValue:aTrackArtist forKey:"trackArtist"
	aTrackDict's setValue:aTrackAlbum forKey:"trackAlbum"
	
	return aTrackDict
end createTrackDict: