Synchronizing Spotlight comment tags with "tag groups"

Here’s the scenario: You have a bunch of files on disk that you’ve tagged using Leap. You’ve also configured Leap to write those tags out as Spotlight comments, so you can search for them quickly with the Finder. This means your files have comments like “&python &script” and such.

You then index/import this collection of files into DEVONthink. If you’ve configured “Preferences | Import | Import Finder comments” in DEVONthink, you’ll notice that your record comments are now the same as your Finder comments were. And if you enabled Spotlight indexing for your DEVONthink database, you’ll find you can still search with “&python” just as you could before in the Finder. All very cool!

The next step is to automate the creation of tag “groups” in DEVONthink, and the replication of tagged records into these groups. That’s what the attached script is for.

This script can take a LONG time to run, so it should probably be used only once after each major import. It assumes the existence of a group named “Tags” at the root level of your database. Please change the script if you don’t like this name. Once you run the script, it will populate this “Tags” group with a bunch of subgroups – one for each tag you had applied to your records. The tags have to be in the form “&tag”, which is what popular tools like Quicksilver, TagBot, Nifty Box, Leap, etc., are used to.

Be sure to see my next post, “Assigning tags in DTP”, which automates the assigning of tags to records once you have such a tag group setup.

John

(*
  Synchronize tags.scpt
  Version 1.0
  by John Wiegley <johnw@newartisans.com>
*)

-- This is the global location of the Tags hierarchy; customize to your tastes!
set tagsPath to "/Tags"

on scanChildren(tagsPath, tagsRecord, theRecord)
	tell application "DEVONthink Pro"
		if id of theRecord is not the id of tagsRecord then
			repeat with theChild in children of theRecord
				if type of theChild is group then
					my scanChildren(tagsPath, tagsRecord, theChild)
				else
					step progress indicator (name of theChild as string)
					set theComment to comment of theChild
					if theComment is not "" then
						repeat with childTag in text items of theComment
							if texts 1 thru 1 of childTag is "&" then
								set childTag to texts 2 thru -1 of childTag
								set tagPath to tagsPath & "/" & childTag
								if not (exists record at tagPath) then
									set childTagRecord to ¬
										create record with {name:childTag, type:group} ¬
											in tagsRecord
								else
									set childTagRecord to get record at tagPath
								end if
								if not (exists record at (tagPath & "/" & name of theChild)) then
									replicate record theChild to childTagRecord
								end if
							end if
						end repeat
					end if
				end if
			end repeat
		end if
	end tell
end scanChildren

tell application "DEVONthink Pro"
	-- Setup a progress indicator so that the user knows when to expect completion.
	-- This process could take a VERY long time!
	show progress indicator ¬
		"Synchronizing tags" cancel button true ¬
		steps count of contents of front database
	
	-- Set up our globals and begin the recursive process
	set tid to AppleScript's text item delimiters
	try
		set AppleScript's text item delimiters to space
		set theRoot to root of front database
		my scanChildren(tagsPath, get record at tagsPath, theRoot)
		
	on error error_message number error_number
		-- If any errors occur, let the user know with a nice dialog
		if the error_number is not -128 then
			try
				display alert "DEVONthink Pro" message error_message
			on error number error_number
				if error_number is -1708 then
					display dialog error_message buttons {"OK"} default button 1
				end if
			end try
		end if
	end try
	
	-- Restore the environment on our way out, whether things succeeded or not
	set AppleScript's text item delimiters to tid
	hide progress indicator
end tell