Action
Add to Obsidian Daily Note Section
UPDATES
almost 2 years ago
Bugfixing
almost 2 years ago
Bugfixing
almost 2 years ago
Fix for adding text to wrong section
almost 2 years ago
added the ability to append or prepend to a section
almost 2 years ago
Added textAddPrefix to newly added line
almost 2 years ago
Added quotes around configured section in alert
created by @FlohGro / more on my Website
Add to Obsidian Daily Note Section
This action will add the contents of the current draft into the configured section in todays Daily Note in Obsidian.
If the configured section is not present, you can choose if the action should append or prepend the content. You can also configure if you want to add a text prefix (e.g. to add a todo or a bullet point to the daily note). If you want to use different prefixes, you can duplicate the action and configure and rename the duplicate accordingly.
[Configuration]
Before you can use the action you need to configure it depending on your setup in Obsidian and personal preference.
All configuration parameters are adapted in the „Define Template Tag“ steps in the Action. To change the configurations edit them to match your setup - don’t change the names of the template tags since the action won’t work anymore afterwards. The following parameters must be adapted:
obsidianVaultBookmarkName
: the name of the folder bookmark that will be created to access the files in your vault (see the Drafts documentation for more information about Folder Bookmarks). When you run the Action the first time it should prompt you to select a folder for that bookmark. Default:Obsidian Vault
dateFormat
: the date format of your daily notes in Obsidian. You need to use the Drafts specific notation documented here Default:%Y-%m-%d
which matchesYYYY-MM-DD
in ObsidiandailyNotesFolderPath
: the path where obsidian creates the daily notes (matches the setting for „New file location“ in the daily notes settings section). Default:empty
dailyNotesSection
: the section in the daily note to where you want to add the content of the current draft. the section must be unique in the Daily Note. Default:UNCONFIGURED
textAddMode
: you can choose if the action should prepend or append the draft to the configured daily note section - onlyprepend
orappend
are allowed. Default:append
textAddPrefix
: an optional prefix that will be prepended to the content of the Draft
IMPORTANT: If you‘re running the Action the first time and it shows an error that the file is not existing even when the file exists in Obsidian then please go into the Settings of Drafts, navigate to „Bookmarks“ and make sure that the configured bookmark name is not set to „-unknown-“. If it is set to Unknown then tap „Select Folder“ and navigate to your Obsidian Vault in the files UI, select it and tap „Done“ in the upper right corner.
[Usage]
The action directly accessed the files so Obsidian won’t be opened when adding something to the daily note. If you didn’t open obsidian on that day, the daily note file will not be created or synced into the folder. Make sure to open Obsidian on the device if you see the alert that the file is missing. This is to prevent sync issues and ensure that potential templates for daily notes are applied first.
Simply run the the Action to add the content of the current draft into the configured section of your Daily Note in Obsidian. When you e.g. want to use the Action to add tasks to your Daily Note then you need to configure - [ ]
as textAddPrefix
. If you have different usecases, just duplicate the Action and configure it differently.
If you find this useful and want to support me you can
Steps
-
defineTemplateTag
name obsidianVaultBookmarkName
template Obsidian Vault
-
defineTemplateTag
name dateFormat
template %Y-%m-%d
-
defineTemplateTag
name dailyNotesFolderPath
template -
defineTemplateTag
name dailyNotesSection
template UNCONFIGURED
-
defineTemplateTag
name textAddMode
template append
-
defineTemplateTag
name textAddPrefix
template -
script
// add to section in obsidian daily note const obsidianVaultBookmarkName = draft.processTemplate("[[obsidianVaultBookmarkName]]") const dateFormat = draft.processTemplate("[[dateFormat]]"); let dailyNoteFileName = draft.processTemplate("[[date|" + dateFormat + "]]") + ".md"; const dailyNotesFolderPath = draft.processTemplate("[[dailyNotesFolderPath]]") + "/"; let tmpDailyNoteSection = draft.processTemplate("[[dailyNotesSection]]").trim() while(tmpDailyNoteSection.length > 0 &&tmpDailyNoteSection.startsWith("#")){ tmpDailyNoteSection = tmpDailyNoteSection.slice(1) } const dailyNoteSection = tmpDailyNoteSection.trim(); dailyNoteFileName = dailyNotesFolderPath + dailyNoteFileName //"2022\.10\.25.md" let bookmark = Bookmark.findOrCreate(obsidianVaultBookmarkName); const configEntryPrefix = "- " const textAddPrefix = draft.processTemplate("[[textAddPrefix]]"); const textAddMode = draft.processTemplate("[[textAddMode]]"); let gLinesToRepace = [] let gFirstSection = "" let gSecondSection = "" let gFoundSections = []; let fm = FileManager.createForBookmark(bookmark); if (fm.exists(dailyNoteFileName)) { // file exists let fileContent = fm.readString(dailyNoteFileName) let fileSections = getMdSections(fileContent) if (fileSections.includes(dailyNoteSection)) { if (fileSections.filter(x => x === dailyNoteSection).length > 1) { const errorStr = "Section \"" + dailyNoteSection + "\" was found multiple times in the Daily Note. Clean up this mess and try again" context.fail(errorStr) alert("Error:\n" + errorStr) } else { let relevantSections = getConfiguredAndFollowingSection(fileSections, dailyNoteSection) let adaptText = true; let relevantText = "" if (relevantSections.length == 1) { // its the last section in the note // send some random generated text that noone will ever have in a note into the function to enforce that it will be identified as the last section in the note relevantText = getTextBetweenSections(fileContent, relevantSections[0], "dad45439-1713-426e-b873-2c6a4883381a-28a6d320-3859-4d8f-b71c-05b3a0c8d323-a2f46eb4-2c86-42d8-a23b-26fa2c8f5f94") } else if (relevantSections.length == 2) { // get text between the two sections relevantText = getTextBetweenSections(fileContent, relevantSections[0], relevantSections[1]) } let textToInsert = "" let linesToInsert = [gFirstSection,gSecondSection] // distinguish newline amount if there is currently no text between the two sections: alert(gSecondSection) let firstSectionInsert = "" let secondSectionInsert = "" if(gLinesToReplace.join("\n") == linesToInsert.join("\n")) { firstSectionInsert = gFirstSection + "\n" secondSectionInsert = (gSecondSection == "" ? "" : "\n\n" + gSecondSection) } else{ firstSectionInsert = gFirstSection + "\n\n" secondSectionInsert = (gSecondSection == "" ? "" : "\n\n" + gSecondSection) } // check text add mode and add text accordingly: if (textAddMode == "append") { alert(relevantText) textToInsert = fileContent.replace(gLinesToReplace.join("\n"), firstSectionInsert + relevantText + "\n" + textAddPrefix + draft.content + secondSectionInsert) } else if (textAddMode == "prepend") { textToInsert = fileContent.replace(gLinesToReplace.join("\n"), firstSectionInsert + textAddPrefix + draft.content + "\n" + relevantText + secondSectionInsert) } else { console.log("invalid text add mode") alert("invalid text add mode configured - only \"append\" or \"prepend\" are allowed") context.fail() adaptText = false; } if (adaptText && !fm.writeString(dailyNoteFileName, textToInsert)) { console.log("failed writing content to file") alert("failed writing content to file - this should not happen. please contact FlohGro via Twitter or the Drafts Forum.") context.fail() } } } else { let p = new Prompt() p.title = "Section not existing" p.message = "the configured section \"" + draft.processTemplate("[[dailyNotesSection]]") + "\" is not existing in the Daily Note right now.\nFound the following sections:\n" + gFoundSections + "\nmaybe check for additional space characters in your configuration or the daily note sections.\n\nSelect one of the following options:" p.addButton("append draft to Daily Note", 1) p.addButton("prepend draft to Daily Note", 2) p.addButton("abort adding draft to Daily Note", 0) p.isCancellable = false p.show() switch (p.buttonPressed) { case 0: context.cancel("aborted by user"); app.displayWarningMessage("Aborted adding to Daily Note"); break; case 1: fileContent = fileContent + "\n\n" + textAddPrefix + draft.content; break; case 2: fileContent = textAddPrefix + draft.content + "\n\n" + fileContent; break; } if (!fm.writeString(dailyNoteFileName, fileContent)) { console.log("failed writing content to file") alert("failed writing content to file - this should not happen. please contact FlohGro via Twitter or the Drafts Forum.") context.fail() } } } else { // file does note exist console.log("daily notes file does not (yet) exist") alert("daily notes file does not (yet) exist, create it in obsidian") context.fail() } function getMdSections(content) { // regex based on this thread: https://stackoverflow.com/questions/70801756/regex-extract-all-headers-from-markdown-string const regex = /#{1,6} (.+)(?=\n)/g; let sections = []; let m; let trimmedSections = []; while ((m = regex.exec(content)) !== null) { if (m.index === regex.lastIndex) { regex.lastIndex++; } m.forEach((match, groupIndex) => { if (groupIndex == 1) { sections.push(match) } }); } gFoundSections = sections return sections } function getConfiguredAndFollowingSection(sections, configuredSection) { let result = [] // get index of the configuredSection let sectionIndex = sections.indexOf(configuredSection) // check if another section is existing after the configured one if (sections.length > sectionIndex) { result.push(sections[sectionIndex]) result.push(sections[sectionIndex + 1]) } else { result.push(sections[sectionIndex]) } return result } function getTextBetweenSections(content, firstSection, secondSection) { let lines = content.split("\n"); firstIndex = -1 secondIndex = -1 let curIndex = 0; for (line of lines) { if (line.endsWith(firstSection) && line.startsWith("#")) { firstIndex = curIndex; gFirstSection = line } // prevent that secondSection is found above first section if (firstIndex != -1) { if (line.endsWith(secondSection) && line.startsWith("#")) { secondIndex = curIndex; gSecondSection = line } } curIndex++ } // if secondIndex is still -1 the configured section is the last section in the document if (secondIndex == -1) { secondIndex = lines.length } // get lines between the two sections into an array let relevantLines = lines.slice(firstIndex + 1, secondIndex) gLinesToReplace = lines.slice(firstIndex, secondIndex + 1); // remove empty lines at the beginning let i = 0 while (relevantLines.length > 0 && relevantLines[0].trim() == "") { relevantLines.shift() } // remove empty lines at the end while (relevantLines.length > 0 && relevantLines[relevantLines.length - 1].trim() == "") { relevantLines.pop() } return relevantLines.join("\n") }
Options
-
After Success Trash Notification Info Log Level Info