Collapsing DEVONthink groups via AppleScript

I’ve been moving to a tag-based system for organizing content in DEVONthink. All of my content for each database goes into a single group called “reference.” If I want to find something, I search the hierarchical tag structure instead of diving into some arbitrary list of groups.

But I still have groups that I’d like to collapse into the reference group. So I wrote an AppleScript to perform this action. Notably, most of the action is in the processGroup() handler which is recursive because we do not know how deep the group hierarchy goes.

Here’s the script if it’s something you can use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
-- collapse all groups into a single reference group
-- Created by Alan Duncan on 2015-11-23 03-15-56
-- Copyright (c) 2015 Alan K. Duncan.
-- Distributed under the terms of the MIT license

-- some error codes we might encounter
property InvalidRecordIndexError : -1719

-- warning string template
property ConfirmText : "Collapse all groups in database: "

-- name of groups that we don't want to move contents of
property ExcludedRecordNames : {"Inbox", "Tags", "Mobile Sync", "Trash", "reference"}

-- the reference group
global refGroup

-- list of groups to delete
global deleteGroups

tell application "DEVONthink Pro"
set questionText to ConfirmText & name of current database & "?"
set confirm to display dialog questionText buttons {"Yes", "No"} default button 2
set answer to button returned of confirm
if answer is equal to "Yes" then
set deleteGroups to {}
set refGroup to referenceGroup(current database) of me
tell current database
repeat with aRecord in (every record whose type is group)
if name of aRecord is not in ExcludedRecordNames then
-- this is a legitimate group to process
processGroup(aRecord) of me
-- this group has been processed; it can be deleted
set end of deleteGroups to aRecord
end if
end repeat

cleanupGroups() of me
end tell
end if
end tell

-- remove all groups that are marked for deletion
on cleanupGroups()
tell application "DEVONthink Pro"
repeat with deleteGroup in deleteGroups
delete record deleteGroup
end repeat
end tell
end cleanupGroups

-- recursively process groups
on processGroup(aGroup)
tell application "DEVONthink Pro"
set theChildren to children of aGroup
repeat with aRecord in theChildren
-- if this child is a group, then enter recursively
if type of aRecord is group then
processGroup(aRecord) of me
else
move record aRecord to refGroup
end if
end repeat
end tell
end processGroup

-- return the reference group, creating it if it doesn't exist
on referenceGroup(db)
using terms from application "DEVONthink Pro"
tell db
try
set referenceGroup to the first record whose name is "reference"
on error error_message number error_number
if error_number is InvalidRecordIndexError then
-- try to create a group "reference"
set refGroup to create record with {name:"reference", type:group} in root
end if
end try
end tell
end using terms from
end referenceGroup