Hi there,
after closing a database I often have something I want to add to it, within minutes. Pretty annoying. Sure, I could use the global inbox but in my case that’s the best place to never see things again. I also tried to use groups in the global inbox to collect stuff in order to move it to the closed database’s inbox next time it is open. That was the plan.
In the end I wrote a Reminder Script that moves things automatically when the database is available. Big help. But this Script only gets triggered every hour. I adapted it to a Triggered Script and attached it to the parent group of the groups that hold stuff for inboxes which are not open at that time and to every database’s inbox. Now if I open a database and go to its inbox stuff from the global inbox group is right there. Nice!
To help me attach the script to all inboxes (and to future ones) and create the groups … another script.
I then realized that this setup is perfect for me - if I keep up with creating groups and attaching the Triggered Script to new inboxes…
So I wrote yet another script, one that gets triggered when Keyboard Maestro sees a new file in my database folder (but you could use a macOS folder action (and I think Hazel) as well). This one creates a group for the new database in the global inbox and attaches the Trigger Script to the database’s inbox without any action from my side.
While testing I deleted a lot of groups from the global inbox whose databases didn’t exist anymore. Ok, one more script, this time triggered when a file is removed from the database folder: If the group in the global inbox is empty it gets deleted when the database is gone.
It’s a second inbox structure that can be used when a database is not open, and when it is open again it takes maximal one hour until the Reminder Script moves the stuff into the real inbox - or it’s earlier triggered by clicking on the database’s inbox.
Once set up there’s nothing more to do, everything will be in its place when the time has come.
It might seem a little bit overkill. But if you know the situation of “Where should I store this? I just closed this database!” or you don’t want to open it just to add one record then you should really try those scripts.
It works well and helps a lot (at least me), but use a testdatabase first!
Reminder Script:
-- Reminder Script, moves all children to the database's incoming group (if it is available). I've set it to run every hour
on performReminder(theRecord)
tell application id "DNtp"
try
set theChildGroups to (every child of theRecord whose type is group)
set theDatabases to databases
repeat with thisChildGroup in theChildGroups
if (count of child of thisChildGroup) > 0 then
set theName to name of thisChildGroup
set theDatabaseName to (characters 17 thru -1 in theName) as string -- adjust to your group name (I use "Zwischeneingang" & space & [DATABASENAME])
repeat with thisDatabase in theDatabases
set thisDatabaseName to name of thisDatabase
if (theDatabaseName as string) = (thisDatabaseName as string) then
move record (every child of thisChildGroup) to incoming group of thisDatabase
end if
end repeat
end if
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
end try
end tell
end performReminder
Triggered Script:
-- Triggered Script, moves all children to the database's incoming group (if it is available). I attached it to the deputy incoming group's parent group and to every database's incoming group
on triggered(theRecord)
tell application id "DNtp"
try
set theGroup to (get record with uuid "") -- set the UUID of the deputy incoming group's parent group (I used the UUID instead of "theRecord" as this script is attached to every incoming group)
set theChildGroups to (every child of theGroup whose type is group)
set theDatabases to databases
repeat with thisChildGroup in theChildGroups
if (count of child of thisChildGroup) > 0 then
set theName to name of thisChildGroup
set theDatabaseName to (characters 17 thru -1 in theName) as string -- adjust to your group name (I use "Zwischeneingang" & space & [DATABASENAME])
repeat with thisDatabase in theDatabases
set thisDatabaseName to name of thisDatabase
if (theDatabaseName as string) = (thisDatabaseName as string) then
move record (every child of thisChildGroup) to incoming group of thisDatabase
end if
end repeat
end if
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
end try
end tell
end triggered
Helper Script for existing databases (attaches the Trigger Script and creates the group in global inbox):
-- Attach Triggered Script to current database and create group in global inbox (the group must be inside a parent group, otherwise the other scripts won't work)
property newGroupNameBeginning : "Zwischeneingang"
tell application id "DNtp"
try
set attached script of incoming group of current database to "" -- set the POSIX path of the Triggered Script
set newGroupName to newGroupNameBeginning & space & (name of current database)
set newGroup to create record with {name:newGroupName, type:group} in display group selector
on error error_message number error_number
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
end try
end tell
“OnAdd” new database - Attach Triggered Script and create new group in global inbox (this script needs Keyboard Maestro, macOS folder actions or another app that watches your database folder. I think Hazel could do this too)
-- "OnAdd" new database → create new deputy incoming group and attach the Triggered Script to the database's incoming group
-- This script can be used manually, but the whole point is that it runs automatically, e.g. with Keyboard Maestro (that's what I do). Or with a macOS folder action, in this case the Finder part is unnecessary (see https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_folder_actions.html). I think Hazel could do this too.
delay 30 -- (now and then I rename a new database..)
tell application "Finder"
try
-- Get name of new database
set latestAdded to item -1 of (sort (get files of (POSIX file "/DEVONthink Datenbanken/" as alias)) by creation date) as alias -- set the POSIX path of your database folder
set theName to name of latestAdded
set theDatabaseName to my Basename(theName)
on error error_message number error_number
if the error_number is not -128 then display alert "Finder" message error_message as warning
end try
end tell
tell application id "DNtp"
try
-- Create deputy incoming group
set theGroup to (get record with uuid "") -- set the UUID of the parent group
set newGroupName to "Zwischeneingang " & theDatabaseName
set newGroup to create record with {name:newGroupName, type:group} in theGroup
-- Attach Triggered Script
set theDatabase to database named theDatabaseName
set attached script of incoming group of theDatabase to "" -- set the POSIX path of the Triggered Script, (e.g. "/Users/USER/Library/Application Scripts/com.devon-technologies.think3/Triggered Scripts/Zwischeneingänge leeren.scpt")
#-- Rename incoming group (optionally)
#set name of incoming group of theDatabase to "Eingang [" & theDatabaseName & "]"
on error error_message number error_number
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
end try
end tell
on Basename(filename)
set revName to reverse of characters of filename as string
set revNameWithoutExtension to characters ((character offset of "." in revName) + 1) thru -1 in revName as string
set theBasename to reverse of characters of revNameWithoutExtension as string
end Basename
“OnDelete” database - Delete group from gobal inbox if it’s empty (this script needs Keyboard Maestro, macOS folder actions or another app that watches your database folder. I think Hazel could do this too)
-- "OnDelete" database → delete deputy incoming group (if it's empty)
-- This script can be used manually, but the whole point is that it runs automatically, e.g. with Keyboard Maestro (that's what I do). Or with a macOS folder action, in this case the Finder part is unnecessary (see https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_folder_actions.html). I think Hazel could do this too)
tell application "Finder"
try
-- Get names of all databases in the folder
set theDatabaseNames to name of files of folder (POSIX file "/DEVONthink Datenbanken" as alias) -- set the POSIX path of your database folder
on error error_message number error_number
if the error_number is not -128 then display alert "Finder" message error_message as warning
end try
end tell
tell application id "DNtp"
try
-- Get all deputy incoming groups
set theGroup to (get record with uuid "") -- set the UUID of the parent group
set theChildGroups to (every child of theGroup whose type is group)
-- Compare names and delete the matching one if it's empty
repeat with thisChildGroup in theChildGroups
set thisChildGroupName to name of thisChildGroup
set thisChildGroupDatabaseName to my Remove_From_String(thisChildGroupName, "Zwischeneingang ") -- adjust to your group name
if (thisChildGroupDatabaseName & ".dtBase2") is not in theDatabaseNames then
if (count of child of thisChildGroup) = 0 then
delete record thisChildGroup
else
open window for record thisChildGroup
activate
end if
end if
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
end try
end tell
on Remove_From_String(theText, CharOrString)
local ASTID, theText, CharOrString, lst
set ASTID to AppleScript's text item delimiters
try
considering case
if theText does not contain CharOrString then ¬
return theText
set AppleScript's text item delimiters to CharOrString
set lst to theText's text items
end considering
set AppleScript's text item delimiters to ASTID
return lst as text
on error eMsg number eNum
set AppleScript's text item delimiters to ASTID
error "Can't RemoveFromString: " & eMsg number eNum
end try
end Remove_From_String