├── .gitignore ├── LICENSE ├── README.md ├── compilescripts ├── installscripts └── src ├── Airmail 3 └── Attach Selected from DEVONthink.applescript ├── DEVONthink Pro └── Send with Airmail.applescript └── Microsoft Outlook ├── Add attachments to DEVONthink.applescript ├── Add message(s) and attachments to DEVONthink.applescript └── Attach Selected from DEVONthink.applescript /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # .gitignore 3 | script 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEVONthink-scripts 2 | Useful and interesting scripts for DEVONthink. 3 | 4 | The AppleScript native file format is binary, and contains the text version of the script and a compiled version. This makes it difficult to view, compare, share, and edit these scripts using anything other that the AppleScript Editor. I have chosen to store all these scripts as plain text in the src directory. It's easy to version control them and compare differences, but it also means they need to be turned into real AppleScript files in order to use them. 5 | 6 | To create usable script files, just type: 7 | 8 | $ ./compilescripts 9 | 10 | Then go look in the newly created `script` directory, and you will see all the binary script files which you can edit and run with Script Editor. 11 | 12 | To install the scripts, type: 13 | 14 | $ ./installscripts 15 | 16 | ## Airmail 17 | **Attach Selected from DEVONthink** - Attach the selected files from the topmost DEVONthink viewer window to the message you are currently composing 18 | 19 | ## DEVONthink Pro 20 | **Send with Airmail** - DEVONthink has a "Send via Email" command, which uses Apple Mail. This script sends the selected files via Airmail. 21 | 22 | ## Microsoft Outlook 23 | **Add attachments to DEVONthink** - save the attachements from the current message to the DEVONthink inbox. 24 | 25 | **Add message(s) and attachments to DEVONthink** - import selected messages and their attachments into the Inbox in DEVONthink 26 | 27 | **Attach Selected from DEVONthink** - Attach the selected files from the topmost DEVONthink viewer window to the message you are currently composing 28 | 29 | -------------------------------------------------------------------------------- /compilescripts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # simple script to compile the source text script files 4 | 5 | OSACOMPILE=/usr/bin/osacompile 6 | SRC_DIR=src 7 | APPLESCRIPT_EXT=applescript 8 | JAVASCRIPT_EXT=javascript 9 | APPLESCRIPT_LANG=AppleScript 10 | JAVASCRIPT_LANG=JavaScript 11 | SCPT_DIR=script 12 | SCPT_EXT=scpt 13 | 14 | # delete the output dir 15 | rm -rf $SCPT_DIR 16 | # and then recreate it 17 | mkdir -p $SCPT_DIR 18 | 19 | find src -type d -depth 1 -exec basename {} \; | while read APPNAME 20 | do 21 | mkdir -p "$SCPT_DIR/$APPNAME" 22 | 23 | # compile applescripts 24 | find "$SRC_DIR/$APPNAME" -iname "*.$APPLESCRIPT_EXT" | while read SRC 25 | do 26 | SCPT=$(basename "$SRC" .$APPLESCRIPT_EXT).$SCPT_EXT 27 | echo "Compiling $APPLESCRIPT_LANG $SRC...." >&2 28 | $OSACOMPILE -l $APPLESCRIPT_LANG -o "$SCPT_DIR/$APPNAME/$SCPT" "$SRC" 29 | done 30 | 31 | # compile javascripts 32 | find "$SRC_DIR/$APPNAME" -iname "*.$JAVASCRIPT_EXT" | while read SRC 33 | do 34 | SCPT=$(basename "$SRC" .$JAVASCRIPT_EXT).$SCPT_EXT 35 | echo "Compiling $JAVASCRIPT_LANG $SRC...." >&2 36 | $OSACOMPILE -l $JAVASCRIPT_LANG -o "$SCPT_DIR/$APPNAME/$SCPT" "$SRC" 37 | done 38 | done 39 | echo "Done." >&2 40 | 41 | -------------------------------------------------------------------------------- /installscripts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # install the compiled scripts 4 | 5 | DEST="~/Library/Scripts/Applications/" 6 | # this bit of magic does parameter expansion in the DEST variable 7 | DEST="${DEST/#\~/$HOME}" 8 | 9 | echo "Installing scripts to $DEST...." >&2 10 | mkdir -p $DEST 11 | cp -rvp script/* "$DEST" 12 | echo "Done." >&2 -------------------------------------------------------------------------------- /src/Airmail 3/Attach Selected from DEVONthink.applescript: -------------------------------------------------------------------------------- 1 | -- Attach the selected files from DEVONthink to the current Airmail composer 2 | -- Tested with Airmail 3 3 | 4 | -- get the paths of the currently selected records in DEVONthink 5 | tell application id "DNtp" 6 | -- select the topmost viewer window, i.e. one with a list of documents 7 | -- this skips over windows like PDF reader windows 8 | set theWindow to false as boolean 9 | repeat with x from 1 to (count windows) 10 | if class of window x is viewer window then 11 | set theWindow to window x 12 | exit repeat 13 | end if 14 | end repeat 15 | 16 | if theWindow is false then 17 | display notification "No DEVONthink viewer window found." 18 | return 19 | end if 20 | 21 | set theRecords to selection of theWindow 22 | set thePaths to {} 23 | repeat with theRecord in theRecords 24 | set thePath to the path of theRecord 25 | copy thePath to end of thePaths 26 | end repeat 27 | end tell 28 | 29 | -- now tell Airmail to attach each one of the selected files 30 | repeat with thePath in thePaths 31 | tell application "System Events" to tell process "Airmail 3" 32 | -- make sure Airmail is frontmost so we can click the menu 33 | set frontmost to true 34 | click menu item "Attach..." of menu 1 of menu bar item "Composer" of menu bar 1 35 | 36 | -- wait for the file dialog to appear 37 | repeat until exists sheet 1 of window 1 38 | delay 0.1 39 | end repeat 40 | 41 | tell sheet 1 of window 1 42 | -- open the "Go To Folder" sheet 43 | keystroke "g" using {command down, shift down} 44 | -- wait for it to appear 45 | repeat until exists sheet 1 46 | delay 0.1 47 | end repeat 48 | -- put in the path and click Go 49 | keystroke thePath 50 | tell sheet 1 to click button "Go" 51 | -- our file is now selected, attach it 52 | click button "Attach File" 53 | end tell 54 | end tell 55 | end repeat 56 | 57 | -------------------------------------------------------------------------------- /src/DEVONthink Pro/Send with Airmail.applescript: -------------------------------------------------------------------------------- 1 | -- Using Airmail, compose a new message and attach the selected items 2 | -- Tested with Airmail 3 3 | 4 | -- get the paths of the currently selected records in DEVONthink 5 | tell application id "DNtp" 6 | -- go find the first viewer window 7 | -- this doesn't seem to select the topmost viewer window 8 | -- if you have multiple viewer windows open, but it works great 9 | -- if you only have one 10 | set theWindow to false as boolean 11 | repeat with x from 1 to (count windows) 12 | if class of window x is viewer window then 13 | set theWindow to window x 14 | exit repeat 15 | end if 16 | end repeat 17 | 18 | if theWindow is false then 19 | display notification "No DEVONthink viewer window found." 20 | return 21 | end if 22 | 23 | set theRecords to selection of theWindow 24 | set thePaths to {} 25 | repeat with theRecord in theRecords 26 | set thePath to the path of theRecord 27 | copy thePath to end of thePaths 28 | end repeat 29 | end tell 30 | 31 | set theSubject to "Files From DEVONthink" 32 | 33 | tell application "Airmail 3" 34 | 35 | -- we give the message a subject so we can find the window later 36 | set theMessage to make new outgoing message with properties {subject:theSubject} 37 | 38 | -- loop through the paths from the records and add them 39 | -- as attachments to the message 40 | repeat with thePath in thePaths 41 | tell theMessage 42 | make new mail attachment with properties {filename:thePath} 43 | end tell 44 | end repeat 45 | 46 | activate 47 | compose theMessage 48 | end tell 49 | 50 | tell application "System Events" 51 | tell process "Airmail 3" 52 | -- go find the window that just got created, using the subject we created 53 | -- it with 54 | repeat with x from 1 to (count windows) 55 | if name of window x starts with theSubject then 56 | exit repeat 57 | end if 58 | end repeat 59 | -- set focus to the "To:" field 60 | set focused of text field 1 of scroll area 1 of window x to true 61 | -- set the subject field to empty 62 | set value of text field 1 of window x to "" 63 | end tell 64 | end tell 65 | -------------------------------------------------------------------------------- /src/Microsoft Outlook/Add attachments to DEVONthink.applescript: -------------------------------------------------------------------------------- 1 | -- Install in ~/Library/Scripts/Applications/Microsoft Outlook 2 | -- Import attachments of selected Microsoft Outlook messages to DEVONthink Pro. 3 | -- Created by Christian Grunenberg on Fri May 18 2012. 4 | -- Copyright (c) 2012-2015. All rights reserved. 5 | 6 | -- TODO this script breaks if the Outlook appointment reminder window is open 7 | 8 | tell application "Microsoft Outlook" 9 | try 10 | tell application id "DNtp" 11 | if not (exists current database) then error "No database is in use." 12 | set theGroup to preferred import destination 13 | end tell 14 | set theSelection to the selection 15 | set theFolder to (POSIX path of (path to temporary items)) 16 | if the theSelection is {} then error "One or more messages must be selected." 17 | repeat with theMessage in theSelection 18 | set theSender to the sender of theMessage 19 | repeat with theAttachment in attachments of theMessage 20 | set theSubject to subject of theMessage 21 | set theFile to theFolder & (name of theAttachment) 22 | tell theAttachment to save in theFile 23 | tell application id "DNtp" 24 | set theAttachmentRecord to import theFile to theGroup 25 | set URL of theAttachmentRecord to theSender 26 | end tell 27 | end repeat 28 | display notification "Saved " & ((count of attachments of theMessage) as string) & " attachments from '" & theSubject & "' to DEVONthink." 29 | end repeat 30 | on error error_message number error_number 31 | if error_number is not -128 then display alert "Microsoft Outlook" message error_message as warning 32 | end try 33 | end tell 34 | -------------------------------------------------------------------------------- /src/Microsoft Outlook/Add message(s) and attachments to DEVONthink.applescript: -------------------------------------------------------------------------------- 1 | -- Install in ~/Library/Scripts/Applications/Microsoft Outlook 2 | -- Import selected Microsoft Outlook messages & attachments to DEVONthink Pro. 3 | -- Created by Christian Grunenberg on Mon Mar 05 2012. 4 | -- Copyright (c) 2012-2015. All rights reserved. 5 | 6 | -- TODO this script breaks if the Outlook appointment reminder window is open 7 | 8 | -- this string is used when the message subject is empty 9 | property pNoSubjectString : "(no subject)" 10 | 11 | tell application "Microsoft Outlook" 12 | try 13 | tell application id "DNtp" 14 | if not (exists current database) then error "No database is in use." 15 | set theGroup to preferred import destination 16 | end tell 17 | set theSelection to the selection 18 | set theFolder to (POSIX path of (path to temporary items)) 19 | if the theSelection is {} then error "One or more messages must be selected." 20 | repeat with theMessage in theSelection 21 | my importMessage(theMessage, theFolder, theGroup) 22 | end repeat 23 | on error error_message number error_number 24 | if error_number is not -128 then display alert "Microsoft Outlook" message error_message as warning 25 | end try 26 | end tell 27 | 28 | on importMessage(theMessage, theFolder, theGroup) 29 | tell application "Microsoft Outlook" 30 | try 31 | tell theMessage 32 | set {theDateReceived, theDateSent, theSender, theSubject, theSource, theReadFlag} to {the time received, the time sent, the sender, subject, the source, the is read} 33 | end tell 34 | if theSubject is equal to "" then set theSubject to pNoSubjectString 35 | set theAttachmentCount to count of attachments of theMessage 36 | tell application id "DNtp" 37 | if theAttachmentCount is greater than 0 then set theGroup to create record with {name:theSubject, type:group} in theGroup 38 | create record with {name:theSubject & ".eml", type:unknown, creation date:theDateSent, modification date:theDateReceived, URL:theSender, source:(theSource as string), unread:(not theReadFlag)} in theGroup 39 | end tell 40 | repeat with theAttachment in attachments of theMessage 41 | set theFile to theFolder & (name of theAttachment) 42 | tell theAttachment to save in theFile 43 | tell application id "DNtp" 44 | set theAttachmentRecord to import theFile to theGroup 45 | set unread of theAttachmentRecord to (not theReadFlag) 46 | set URL of theAttachmentRecord to theSender 47 | end tell 48 | end repeat 49 | display notification "Saved '" & theSubject & "' to DEVONthink." 50 | on error error_message number error_number 51 | if error_number is not -128 then display alert "Microsoft Outlook" message error_message as warning 52 | end try 53 | end tell 54 | end importMessage 55 | -------------------------------------------------------------------------------- /src/Microsoft Outlook/Attach Selected from DEVONthink.applescript: -------------------------------------------------------------------------------- 1 | -- Attach the selected files from DEVONthink to the current Outlook draft 2 | -- Tested with Outlook 15.33, i.e. Outlook 2016 for Mac 3 | 4 | -- get the posix paths of the currently selected records in DEVONthink 5 | tell application id "DNtp" 6 | -- go find the first viewer window 7 | -- this doesn't seem to select the topmost viewer window 8 | -- if you have multiple viewer windows open, but it works great 9 | -- if you only have one 10 | set theWindow to false as boolean 11 | repeat with x from 1 to (count windows) 12 | if class of window x is viewer window then 13 | set theWindow to window x 14 | exit repeat 15 | end if 16 | end repeat 17 | 18 | if theWindow is false then 19 | display notification "No DEVONthink viewer window found." 20 | return 21 | end if 22 | 23 | set theRecords to selection of theWindow 24 | set thePaths to {} 25 | repeat with theRecord in theRecords 26 | set thePath to the path of theRecord as POSIX file 27 | copy thePath to end of thePaths 28 | end repeat 29 | end tell 30 | 31 | tell application "Microsoft Outlook" 32 | 33 | -- loop through the open Outlook windows looking for 34 | -- draft message windows. If there is only one draft window open 35 | -- this finds it. Experimentation indicates that when multiple 36 | -- draft windows are open this finds the topmost one first 37 | set theWindow to false as boolean 38 | repeat with x from 1 to (count windows) 39 | if class of window x is draft window then 40 | set theWindow to window x 41 | exit repeat 42 | end if 43 | end repeat 44 | 45 | if theWindow is false then 46 | display notification "No draft messages are currently open." 47 | return 48 | end if 49 | 50 | --display notification "have draft window" 51 | get the id of the object of theWindow 52 | set myObjectID to id of (object of theWindow) 53 | set theMessage to message id myObjectID 54 | 55 | -- loop through the paths from the records and add them 56 | -- as attachments to the message 57 | repeat with thePath in thePaths 58 | tell theMessage 59 | make new attachment with properties {file:thePath} 60 | end tell 61 | end repeat 62 | end tell 63 | 64 | --------------------------------------------------------------------------------