Skip to content

Instantly share code, notes, and snippets.

@windoverwater
Last active February 27, 2024 15:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save windoverwater/14e6990003f01188974f33da5f8660b7 to your computer and use it in GitHub Desktop.
Save windoverwater/14e6990003f01188974f33da5f8660b7 to your computer and use it in GitHub Desktop.
A modified version of https://omni-automation.com/omnifocus/plug-in-obsidian.html that supports copying all selected notes and not just one
/*{
"type": "action",
"targets": ["omnifocus"],
"author": "Otto Automator",
"identifier": "com.omni-automation.of.task-to-obsidian-mod",
"version": "2.2.2",
"description": "Creates a corresponding note in the indicated Obsidian vault, for the selected task or project. There is a preference for including the tags assigned to the task or project.",
"label": "Copy to Obsidian ",
"shortLabel": "Copy to Obsidian",
"paletteLabel": "Copy to Obsidian",
"image": "note.text.badge.plus"
}*/
(() => {
const preferences = new Preferences()
const action = new PlugIn.Action(async function(selection, sender){
try {
if (app.controlKeyDown){
var errorID = "A"
vaultTitle = preferences.readString("vaultTitle")
var vaultTitleInput = new Form.Field.String(
"vaultTitle",
null,
vaultTitle,
null
)
shouldIncludeTagsValue = preferences.readBoolean("shouldIncludeTags")
var includeTagsCheckbox = new Form.Field.Checkbox(
"shouldIncludeTags",
"Include OmniFocus tags with note",
shouldIncludeTagsValue
)
shouldRequireURIPluginValue = preferences.readBoolean("shouldRequireURIPlugin")
var requireURIpluginCheckbox = new Form.Field.Checkbox(
"shouldRequireURIPlugin",
"Use with the “Advanced Obsidian URI” plug-in",
shouldRequireURIPluginValue
)
shouldIncludeObsLinkValue = preferences.readBoolean("shouldIncludeObsLink")
var includeObsLink = new Form.Field.Checkbox(
"shouldIncludeObsLink",
"Add Obsidian link in OF note",
shouldIncludeObsLinkValue
)
shouldOverwriteFileValue = preferences.readBoolean("shouldOverwriteFile")
var overwriteFileCheckbox = new Form.Field.Checkbox(
"shouldOverwriteFile",
"Silently overwrite existing files in Obsidian",
shouldOverwriteFileValue
)
inputForm = new Form()
inputForm.addField(vaultTitleInput)
inputForm.addField(includeTagsCheckbox)
inputForm.addField(requireURIpluginCheckbox)
inputForm.addField(includeObsLink)
inputForm.addField(overwriteFileCheckbox)
formPrompt = "Enter title of the existing Obsidian vault to use:"
formObject = await inputForm.show(formPrompt,"Continue")
newVaultTitle = formObject.values["vaultTitle"]
newShowTags = formObject.values["shouldIncludeTags"]
newshouldRequireURIPlugin = formObject.values["shouldRequireURIPlugin"]
newAddLink = formObject.values["shouldIncludeObsLink"]
newOverwriteFile = formObject.values["shouldOverwriteFile"]
preferences.write("vaultTitle", newVaultTitle)
preferences.write("shouldIncludeTags", newShowTags)
preferences.write("shouldRequireURIPlugin", newshouldRequireURIPlugin)
preferences.write("shouldIncludeObsLink", newAddLink)
preferences.write("shouldOverwriteFile", newOverwriteFile)
} else {
var errorID = "B"
var vaultTitle = preferences.readString("vaultTitle")
if(!vaultTitle || vaultTitle === ""){
throw {
name: "Undeclared Vault Preference",
message: "A default Obsidian vault has not yet been indicated for this plug-in.\n\nRun this plug-in again, while holding down the Control key, to summon the preferences dialog."
}
}
console.log("Pref-vaultTitle: ", vaultTitle)
var shouldIncludeTags = preferences.readBoolean("shouldIncludeTags")
if(!shouldIncludeTags){shouldIncludeTags = false}
console.log("Pref-shouldIncludeTags: ", shouldIncludeTags)
var shouldRequireURIPlugin = preferences.readBoolean("shouldRequireURIPlugin")
if(!shouldRequireURIPlugin){shouldRequireURIPlugin = false}
console.log("Pref-shouldRequireURIPlugin: ", shouldRequireURIPlugin)
var shouldIncludeObsLink = preferences.readBoolean("shouldIncludeObsLink")
if(!shouldIncludeObsLink){shouldIncludeObsLink = false}
console.log("Pref-shouldIncludeObsLink: ", shouldIncludeObsLink)
var shouldOverwriteFile = preferences.readBoolean("shouldOverwriteFile")
if(!shouldOverwriteFile){shouldOverwriteFile = false}
console.log("Pref-shouldOverwriteFile: ", shouldOverwriteFile)
selection.databaseObjects.forEach(item => {
itemID = item.id.primaryKey
itemLink = `omnifocus:///task/${itemID}`
itemTitle = item.name
itemNote = item.note
mdLink = `[(OmniFocus Link)](${itemLink})`
encodedLink = encodeURIComponent(mdLink)
encodedTitle = encodeURIComponent(itemTitle)
encodedNote = encodeURIComponent(itemNote)
encodedVaultTitle = encodeURIComponent(vaultTitle)
encodedTags = null
// always get the creation and modified dates
ofTimes = `createdTime: ${item.added.getTime()}\nmodifiedTime: ${item.modified.getTime()}`
ofDates = `created: ${item.added}\nmodified: ${item.modified}`
YAMLheader = `---\nid: ${itemID}\n${ofTimes}\n${ofDates}`
tagArrayStr = ""
if(shouldIncludeTags && item.tags.length > 0){
tagTitles = item.tags.map(tag => tag.name)
tagArrayStr = `[${tagTitles.join(", ")}]`
YAMLheader += `\ntags: ${tagArrayStr}\n---`
} else {
YAMLheader += `\n---`
}
// Regardless, add
encodedHeader = encodeURIComponent(YAMLheader)
if(shouldRequireURIPlugin){
searchLinkStr = `obsidian://advanced-uri?vault=${encodedVaultTitle}&uid=${itemID}`
} else {
searchLinkStr = `obsidian://search?vault=${encodedVaultTitle}&query=${itemID}`
}
console.log("Search URL: ", searchLinkStr)
if(shouldIncludeObsLink){
if(app.userVersion < new Version("4")){
item.note += "\n\n" + searchLinkStr
} else {
noteObj = item.noteText
linkURL = URL.fromString(searchLinkStr)
linkObj = new Text("(Obsidian Link)", noteObj.style)
newLineObj = new Text(" \n", noteObj.style)
style = linkObj.styleForRange(linkObj.range)
style.set(Style.Attribute.Link, linkURL)
noteObj.insert(noteObj.start, linkObj)
noteObj.insert(linkObj.range.end, newLineObj)
}
}
// Handle file overwrites
if(shouldOverwriteFile){
overwriteStr = "&overwrite"
} else {
overwriteStr = ""
}
targetLink = `obsidian://new?vault=${encodedVaultTitle}${overwriteStr}&name=${encodedTitle}&content=${encodedHeader}%0A%0A${encodedLink}%0A%0A${encodedNote}`
// in pursuit of a decent log message
console.log("Copied note: project=" + item.containingProject.name + "; tags=" + tagArrayStr + "; name=" + itemTitle)
// To debug the (verbose) targetLink, uncomment this line
// console.log("Create URL: ", targetLink)
URL.fromString(targetLink).open()
})
}
}
catch(err){
if(errorID !== "A"){
new Alert(err.name, err.message).show()
}
}
});
action.validate = function(selection, sender){
return (
selection.databaseObjects.length >= 1 &&
selection.tasks.length >= 1 ||
selection.projects.length >= 1
)
};
return action;
})();
@windoverwater
Copy link
Author

If there is time I'll try to help with questions, but just in case if it would make a difference "Buy Me A Coffee"

@windoverwater
Copy link
Author

2024/02/18: added a third option to not write the obsidian link into the OmniFocus note (so that the OF task/Project is not modified by the copy). Also added four (YAML) properties to the Obsidian note copy: both an Epoch creation and modification time and long form pretty print date-time (with GMT offset and timezone). The pretty print keys in theory should match (TBD) 3rdparty plugins creation/modification times where users want to track/sort notes based on creation or modification times (independent of the underlying file system creation and modifications since that cannot really be relied on via cloud sync and git subsystems.)

@windoverwater
Copy link
Author

2024/02/27: added the preference to overwrite existing files in obsidian. Desired this so to be able to do the following workflow (when mirroring, for whatever the reason, an OmniFocus Project into Obsidian:

  • commit all pending changes to git
  • perhaps remove the obsidian target directory or not
  • run the automation with overwrite (slams potentially new versions into place)
  • inspect with git the differences; perhaps mitigate; perhaps commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment