Obsidian => Omnifocus workflows

I’ve moved my note-taking from Drafts to Obsidian recently and am loving it.

The one thing I miss is the ability to get my to-dos from a note and into OmniFocus, which I was able to do in Drafts.

I’ve been thinking about using Hazel to scan for “- [ ]” and then copy that line as an Omnifocus inbox task using apple script, but I haven’t figured it out yet.

Do you have any other workflows that achieve this?

1 Like

I’ve actually done this! It worked pretty well for a while. I doubt it will still work but I’ll post the script (with no warranties!) when I get back to my desk.

1 Like

Finally! Apologies for the delay. Suffice it to say I am looking forward to getting a new laptop—getting to sit down at my Mac mini while on parental leave is a rare occurrence. :wink:

The following script sat on the following Hazel rule:

Provided with no warranties:

set aFile to choose file

hazelProcessFile(aFile, null)



on hazelProcessFile(theFile, inputAttributes)
	
	set filePath to (theFile as string)
	if package folder of (info for theFile as alias) then --deal with textbundles
		set theFile to (theFile as string) & "text.md"
		log theFile
		set filePath to text 1 thru -2 of (theFile as string)
	end if
	log filePath
	set theList to readAndSplitFile(theFile)
	try
		tell application id "DNtp"
			--trying to find the record in DEVONthink
			log "----Start DEVONthink Actions----"
			log "Trying to find the record in DEVONthink"
			set theDatabase to get database with uuid "DCCA1AD7-FAFC-41C2-995E-5A725EDE7BBD"
			log "Database " & name of theDatabase & " found."
			log "The database has DEVONthink record path x-devonthink-item://" & uuid of theDatabase
			
			log "Looking for records with file path " & POSIX path of theFile & " in the " & name of theDatabase & " database."
			set fileList to lookup records with path POSIX path of theFile in theDatabase
			log "Found " & (count of fileList) & " records."
			set theRecord to item 1 of fileList
			set theLink to get reference URL of theRecord
		end tell
	end try
	log "——End DEVONthink Actions----"
	repeat with theCurrentListItem in theList
		if theCurrentListItem starts with "	" then
			set taskName to trimTabs(theCurrentListItem)
			set theCurrentListItem to taskName
		end if
		if theCurrentListItem starts with "- [ ]" then
			-- log theCurrentListItem with title "Update"
			set taskName to trimText(theCurrentListItem, "- [ ]", "beginning")
			set theTask to taskName
			try
				set theTask to taskName & " //" & theLink
			end try
			tell application "OmniFocus"
				tell default document
					parse tasks into it with transport text theTask
				end tell
			end tell
		else if theCurrentListItem starts with " - [ ]" then --check for task entries with a space in front of the first - character
			set taskName to trimText(theCurrentListItem, "- [ ]", "beginning")
			set theTask to taskName
			try
				set theTask to taskName & " //" & theLink
			end try
			tell application "OmniFocus"
				tell default document
					parse tasks into it with transport text theTask
				end tell
			end tell
		end if
	end repeat
end hazelProcessFile

on readAndSplitFile(aFile)
	-- Convert the file to a string
	set targetFile to aFile as string
	log "success"
	log targetFile
	-- Read the file and split any "## Agenda" parts out.
	set fileText to read file targetFile as «class utf8»
	log fileText
	
	set AppleScript's text item delimiters to "## Agenda"
	set targetTextBlocks to every text item of fileText
	log "*********"
	log "The good text block:"
	log item 1 of targetTextBlocks
	log "*********"
	
	set targetText to item 1 of targetTextBlocks
	set AppleScript's text item delimiters to {return & linefeed, return, linefeed, character id 8233, character id 8232}
	set targetTextItems to every text item of targetText
	set AppleScript's text item delimiters to ""
	return targetTextItems
	log targetTextItems
	
	-- Read the file using a specific delimiter and return the results
	--return read file targetFile using delimiter {return & linefeed, return, linefeed, character id 8233, character id 8232} as «class utf8»
end readAndSplitFile

on trimText(theText, theCharactersToTrim, theTrimDirection)
	set theTrimLength to length of theCharactersToTrim
	if theTrimDirection is in {"beginning", "both"} then
		repeat while theText begins with theCharactersToTrim
			try
				set theText to characters (theTrimLength + 1) thru -1 of theText as string
			on error
				-- text contains nothing but trim characters
				return ""
			end try
		end repeat
	end if
	if theTrimDirection is in {"end", "both"} then
		repeat while theText ends with theCharactersToTrim
			try
				set theText to characters 1 thru -(theTrimLength + 1) of theText as string
			on error
				-- text contains nothing but trim characters
				return ""
			end try
		end repeat
	end if
	return theText
end trimText

on trimTabs(theText)
	set theTrimLength to length of "	"
	repeat while theText begins with "	"
		try
			set theText to characters (theTrimLength + 1) thru -1 of theText as string
		on error
			-- text contains nothing but trim characters
			return ""
		end try
	end repeat
	return theText
end trimTabs

I can barely remember how it works, but if you have questions, ask 'em—I might be able to answer!

3 Likes

I should add: I used this two or three years ago, before Obsidian. There are probably smarter ways of doing it now, but hopefully it helps you figure out what those are.

1 Like

It should be possible to create an Obsidian plugin that uses the OmniFocus URL Scheme to create tasks.

(Says me, having no wherewithal to do what I opined is possible.)

2 Likes

Thanks for the idea! I did this: Obsidian to Omnifocus plugin