Please help, I am really stuck with Metadata and JSON Export

This script creates a JSON file for each selected record.

  • property theCMD_Identifiers : List of Custom Meta Data identifiers. Add whatever you want.
  • property theOutputFolder_Path : Path of folder where the JSON files are created.
  • property sortKeys : Whether the Keys should be sorted. If false Keys appear in the order they were added.
  • There’s a part “Add other key:value pairs here” part where you can add your other values.

Please don’t process all records in one go. You can e.g. set a label or a tag to keep track of what’s already processed. It might be a good idea to create subfolders after each script run because 23.000 files in a single folder might cause problems. Don’t forget to change property theOutputFolder_Path.

The JSON filenames are build from the record’s name without extension plus json. This means if you would create all JSON files into a single folder and not all your records got unique filenames then the script would overwrite previously created JSON files. To prevent this the record’s UUID is used when necessary.

-- Export Custom Meta Data to JSON files

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

property theCMD_Identifiers : {"primarycolor", "secondarycolor", "tertiarycolor"} -- Set the Custom Meta Data identifiers
property theOutputFolder_Path : (POSIX path of (path to desktop)) & "Script Output" -- Replace this with a path like "/Users/username/abc/xyz" (or create folder "Script Output" on your desktop)
property sortKeys : false

set theCMD_Titles to my getCustomMetaDataTitles(theCMD_Identifiers)

set theAttributes to {}
repeat with i from 1 to (count of theCMD_Titles)
	set thisCMD_Title to item i of theCMD_Titles
	set end of theAttributes to {trait_type:thisCMD_Title, value:""}
end repeat

set theDictionary to current application's NSMutableDictionary's new()
set theAttributesArray to current application's NSMutableArray's new()
set theOutputFolder_Path_String to (current application's NSString's stringWithString:theOutputFolder_Path)

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some records."
		
		repeat with thisRecord in theRecords
			
			repeat with i from 1 to (count of theCMD_Identifiers)
				set thisCMD_Title to item i of theCMD_Titles
				set thisCMD_Identifier to item i of theCMD_Identifiers
				set thisCMD_Value to get custom meta data for thisCMD_Identifier from thisRecord
				if thisCMD_Value = missing value then set thisCMD_Value to ""
				set theAttributesArray to my setValueInAttributesArray(item i of theCMD_Titles, thisCMD_Value, theAttributesArray)
			end repeat
			
			-------------------------------------------------------------------------------------------------------------------------------------------------
			
			-- Add other key:value pairs here
			
			set thisKey to "name"
			set thisValue to filename of thisRecord
			my setValue(thisKey, thisValue, theDictionary)
			
			#set thisKey to "description"
			#set thisValue to ""
			#my setValue(thisKey, thisValue, theDictionary)
			
			#set thisKey to "image"
			#set thisValue to ""
			#my setValue(thisKey, thisValue, theDictionary)
			
			#set thisKey to "edition"
			#set thisValue to ""
			#my setValue(thisKey, thisValue, theDictionary)
			
			-------------------------------------------------------------------------------------------------------------------------------------------------	
			
			my setValue("attributes", theAttributesArray, theDictionary)
			
			-------------------------------------------------------------------------------------------------------------------------------------------------	
			
			set thisJSONFile_Filename to (name without extension of thisRecord & ".json")
			set thisRecord_UUID to uuid of thisRecord
			set success to my writeToFile(theDictionary, theOutputFolder_Path_String, thisJSONFile_Filename, thisRecord_UUID)
		end repeat
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on getCustomMetaDataTitles(theCMD_Identifiers)
	try
		set theData to current application's NSFileManager's defaultManager()'s contentsAtPath:(POSIX path of (path to application support from user domain) & "DEVONthink 3/CustomMetaData.plist")
		set {theCustomMetaDataPlistArray, theError} to (current application's NSPropertyListSerialization's propertyListWithData:theData options:0 format:(current application's NSPropertyListXMLFormat_v1_0) |error|:(reference))
		if theError ≠ missing value then error (theError's localizedDescription() as string)
		set theCMD_Identifiers_withMD to "{\"md" & my tid(theCMD_Identifiers, "\",\"md") & "\"}"
		set theCustomMetaDataPlistArray_filtered to (theCustomMetaDataPlistArray's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:("self.identifier IN " & theCMD_Identifiers_withMD)))
		set theCMD_Titles to (theCustomMetaDataPlistArray_filtered's valueForKey:"title") as list
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"getCustomMetaDataTitles\"" message error_message as warning
		error number -128
	end try
end getCustomMetaDataTitles

on setValueInAttributesArray(thisCMD_Title, thisCMD_Value, theAttributesArray)
	try
		set thisDictionary to (current application's NSMutableDictionary's dictionaryWithDictionary:{trait_type:thisCMD_Title, value:thisCMD_Value})
		theAttributesArray's addObject:thisDictionary
		return theAttributesArray
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"setValueInAttributesArray\"" message error_message as warning
		error number -128
	end try
end setValueInAttributesArray

on setValue(theKey, theValue, theDictionary)
	try
		theDictionary's setValue:theValue forKey:theKey
		return theDictionary
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"setValue\"" message error_message as warning
		error number -128
	end try
end setValue

on writeToFile(theDictionary, theOutputFolder_Path_String, theJSONFile_Filename, theUUID)
	try
		set theJSON_String to my formatJSON(theDictionary, true, sortKeys)
		set theJSON_Path to (theOutputFolder_Path_String's stringByAppendingPathComponent:theJSONFile_Filename)
		set existsPath to current application's NSFileManager's defaultManager's fileExistsAtPath:theJSON_Path isDirectory:(missing value)
		if existsPath then set theJSON_Path to (theOutputFolder_Path_String's stringByAppendingPathComponent:(theUUID & ".json"))
		set {success, theError} to (theJSON_String's writeToFile:theJSON_Path atomically:no encoding:(current application's NSUTF8StringEncoding) |error|:(reference))
		if success = false then error (theErrorMessage(theError's localizedDescription()) as string)
		return success
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"writeToFile\"" message error_message as warning
		error number -128
	end try
end writeToFile

on formatJSON(theRecord, usePrettyPrint, useSortKeys)
	try
		if not (current application's NSJSONSerialization's isValidJSONObject:theRecord) then error "No valid JSON Object"
		set theJSONOptions to 0
		if usePrettyPrint then set theJSONOptions to theJSONOptions + ((current application's NSJSONWritingPrettyPrinted) as integer)
		if useSortKeys then set theJSONOptions to theJSONOptions + ((current application's NSJSONWritingSortedKeys) as integer)
		set {theJSONData, theError} to (current application's NSJSONSerialization's dataWithJSONObject:theRecord options:theJSONOptions |error|:(reference))
		if theError ≠ missing value then error (theError's localizedDescription() as string)
		set theJSONString to (current application's NSString's alloc()'s initWithData:theJSONData encoding:(current application's NSUTF8StringEncoding))
		return theJSONString
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"formatJSON\"" message error_message as warning
		error number -128
	end try
end formatJSON

on tid(theInput, theDelimiter)
	
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid


PS the QuickLook Plugin you’re using doesn’t fit into the Dark Mode scheme. You might want to take a look at SourceCodeSyntaxHighlight:


PPS FileMaker is nice but can’t replace DEVONthink. Eagerly waiting for the free version for single users.

3 Likes