I have this script that someone helped me write that creates .md files from my Notes app:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application "Notes"
tell folder "Notes" of account "iCloud"
set theCount to (count notes)
set invalid to ((theCount = 0) or ((theCount = 1) and (note 1's body = "")))
end tell
end tell
if (invalid) then error number -128 -- "User canceled" error.
set rootFolder to "Macintosh HD:Users:dannywyatt:Library:Mobile Documents:iCloud~md~obsidian:Documents:Tiago:Inbox"
tell application "Finder"
set exportFolder to make new folder at folder rootFolder with properties {name:"Converted notes from NOTES app"}
set exportFolder to exportFolder as text
end tell
tell application "Notes" to activate
-- Simple text replacing
on replaceText(find, replace, subject)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set subject to text items of subject
set text item delimiters of AppleScript to replace
set subject to "" & subject
set text item delimiters of AppleScript to prevTIDs
return subject
end replaceText
-- Get an .md file to save the note in. We have to escape
-- the colons or AppleScript gets upset.
on noteNameToFilePath(noteName)
global exportFolder
set strLength to the length of noteName
if strLength > 250 then
set noteName to text 1 thru 250 of noteName
end if
set fileName to (exportFolder & replaceText(":", "_", noteName) & ".md")
return fileName
end noteNameToFilePath
tell application "Notes"
repeat with theNote in notes of folder "Notes"
set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to "/"
set AppleScript's text item delimiters to oldDelimiters
set fileName to name of theNote as string
set filepath to noteNameToFilePath(fileName) of me
set noteFile to open for access filepath with write permission
set theText to body of theNote as string
write theText to noteFile as Ā«class utf8Ā»
close access noteFile
end repeat
end tell
I use Keyboard Maestro and I am able to make some changes to the file name as well as replacing some stuff in the file itself:
1 - Remove ... from the file name
2 - Replace the string " with " (fileās content)
3 - Using RegEx, remove <.{1,4}> (fileās content). This is HTML āgarbageā that I donāt want to keep, such as <div>, etc.
So yes, I can achieve this with some extra Keyboard Maestro actions, but if I can achieve this just with the script, even better.
Iām still learning AS, so this is a bit complex for me.
When it comes to the ... issue I assume itās something similar to this?
set fileName to (exportFolder & replaceText("...", "", noteName) & ".md")
But when I tried this, it didn't work, so I'm obviously doing something wrong:
set fileName to (exportFolder & replaceText(":", "_", noteName) & replaceText("...", "", noteName) ".md")
alltiagocom. The handler included below will accomplish your first and third requests. I donāt understand your second request, although I suspect the handler can do this as well.
use framework "Foundation"
use scripting additions
set fileName to "Test...File.txt"
set cleanedFileName to getCleanedString(fileName, "\\.{3}")
set theString to "<div><h1>Travel Data</h1></div>
<div> </div>
<div>Burnby Hall & Gardens, The Balk, Pocklington, York, YO42 2QF</div>
<div>57 minutes</div>"
set cleanedString to getCleanedString(theString, "<.{1,4}>")
on getCleanedString(theString, thePattern)
set theString to current application's NSMutableString's stringWithString:theString
(theString's replaceOccurrencesOfString:thePattern withString:"" options:1024 range:{0, theString's |length|()})
return theString as text
end getCleanedString
BTW, the same task can be accomplished with basic AppleScript using text item delimiters and with the shell. Iām more comfortable using ASObjC for its speed and simplicity.
When the fileās content includes something like this: This is my "best" year ever, it becomes This is my "best" year ever, so I want to replace all instances of " with "
I tried your script with Script Debugger and I can see the output, which indeed removes the HTML stuff, as well as the file name without ...
As I mentioned, Iām still learning AS so I canāt really understand how that would be added to my script? Is that possible? If so, where would I put that?
You also mention ASObjC, which I have no idea what it isā¦
If itās too complicated to merge the two, I understand. No worries. I can still use Keyboard Maestro to make all of those changes.
Iām in the very beginning of learning AS and Iāve been learning a lot (at least itās not 100% foreign to me), but still not on a level where I can fully play with it, comfortably to merge them.
alltiagocom. Sorry for not explaining moreāitās always a bit difficult to know if Iām explaining too much or not enough.
As far as my scriptās operation goes, you copy the handler to the end of your script and call it wherever you need to remove unwanted characters from a string. The parameters when you call the handler are the source string (which is simple text) and the regex pattern that matches the characters that will be deleted. For example:
use framework "Foundation"
use scripting additions
-- first part of the script
-- cleaned text is required here
set fileName to "Test...File.txt"
set cleanedFileName to getCleanedString(fileName, "\\.{3}") --> "TestFile.txt"
-- more of the script
-- cleaned text is required here
set theString to "This is my "best" year ever"
set cleanedString to getCleanedString(theString, """) --> "This is my best year ever"
-- more of the script
-- put this handler at end of script
on getCleanedString(theString, thePattern) -- thePattern is the regex pattern
set theString to current application's NSMutableString's stringWithString:theString
(theString's replaceOccurrencesOfString:thePattern withString:"" options:1024 range:{0, theString's |length|()})
return theString as text
end getCleanedString
The only thing to note is that regex metacharacters have to be escaped with two instead of just one backslash. If you arenāt familiar with regex, just ask and a forum member will supply the required pattern.
ASObjC refers to the AppleScript implementation of Objective-C. Itās not something you need to learn, but it can be useful in situations like this, where you donāt really need to understand it to use it.
Since your script works with Keyboard Maestro, I would just stick with that for now. You can then play around with my suggestion when you have the time and inclination.
Unless Iāve misunderstood what youāre trying to do, the simplest way to get a noteās text without the HTML is to use its plaintext instead of its body.
Hey! It seems to work You mean this line, right? set theText to plaintext of theNote as string
I changed it and I got the files without all the HMTL āgarbageā.
Would you also know how to fix the fileās name, by removing the ...?
This is the section:
on noteNameToFilePath(noteName)
global exportFolder
set strLength to the length of noteName
if strLength > 250 then
set noteName to text 1 thru 250 of noteName
end if
set fileName to (exportFolder & replaceText(":", "_", noteName) & ".md")
return fileName
end noteNameToFilePath
You can see that it replaces : with _, but I canāt figure out how to completely remove the ...
Yes. Thatās right. You shouldnāt need the as string, but it doesnāt hurt.
The code you tried in your first post above nominally appends the result of deleting group(s) of three dots in the original note name to the result of replacing colons(s) with underscore(s) in that same original note name. So you get one after the other in the file name. You need instead to perform one of the actions on the original name and then perform the other action on the result of that.
Another thing that occurs to me is that your three dots may actually be the ellipsis character (character id 8230), so ideally you need to cover both possibilites.
set editedNoteName to replaceText(":", "_", noteName)
set editedNoteName to replaceText({"...", "ā¦"}, "", editedNoteName)
set fileName to (exportFolder & editedNoteName & ".md")
Nigelās plaintext suggestion greatly simplifies matters. I tested the following script on my Sonoma computer without issue. It replaces colons with underscores and deletes three periods in file names. I set the maximum length of file names to 20 characters, although this can be changed to whatever is desired:
use framework "Foundation"
use scripting additions
set theFolder to "/Users/Robert/Desktop/Note Copies/" -- user set to desired value
tell application "Notes"
activate
set theNotes to notes of folder "Notes"
set theCount to count theNotes
if theCount is 0 then display dialog "No notes were found" buttons {"OK"} cancel button 1 default button 1
end tell
set fileManager to current application's NSFileManager's defaultManager()
fileManager's createDirectoryAtPath:theFolder withIntermediateDirectories:false attributes:(missing value) |error|:(missing value)
tell application "Notes"
repeat with aNote in theNotes
set noteText to plaintext of aNote
set noteName to name of aNote
set noteNameCount to (count noteName)
if noteNameCount is greater than 20 then set noteName to characters 1 thru 20 of noteName as text
set noteName to searchAndReplace(noteName, ":", "_") of me -- replace colon with underscore
set noteName to searchAndReplace(noteName, "...", "") of me -- delete 3 periods
writeFile(noteText, theFolder, noteName) of me -- existing files are overwritten
end repeat
end tell
on searchAndReplace(theString, searchString, replaceString)
set theString to (current application's NSString's stringWithString:theString)
return (theString's stringByReplacingOccurrencesOfString:searchString withString:replaceString)
end searchAndReplace
on writeFile(theString, theFolder, fileName) -- overwrites existing files
set theString to current application's NSString's stringWithString:theString
set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
set theFile to (theFolder's URLByAppendingPathComponent:fileName)'s URLByAppendingPathExtension:"md"
theString's writeToURL:theFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeFile
Iāve included a shortcut solution below. As written, it saves the notes in TXT format but is easily modified to save them as RTF or HTML. The folder that will contain the saved notes is set in the shortcutās first action.
My macOS is still Catalina and I donāt have Shortcuts. I also use Keyboard Maestro, which seems to be more advanced overall, even though Shortcuts is good when it comes to having things that work on both Mac and iPhone/iPad (at least thatās what it seems from what I read online).
The format of the files needs to be .md, because I use Obsidian as my app for notes.
Today I was playing around with ChatGPT (havenāt tried it before) and I actually asked about this script and it gave me a few extra tips, such as adding the current date and time to the end of the folder, which I was adding with Keyboard Maestro.
It seems that ChatGPT is gonna be a good tool for me to learn a few things here and there as well, along with this forum, as long as I am able to create a good prompt, which seems to be the case so far.
Hereās the final script I got and now I donāt have to rely on anything but the AppleScript action in Keyboard Maestro (by the way, the āellipsisā was actually the Horizontal Ellipsis, which seems to be what you just described as well):
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
tell application "Notes"
tell folder "Notes" of account "iCloud"
set theCount to (count notes)
set invalid to ((theCount = 0) or ((theCount = 1) and (note 1's body = "")))
end tell
end tell
if (invalid) then error number -128 -- "User canceled" error.
-- Get current date and time
set currentDate to current date
set dateFormatter to current application's NSDateFormatter's new()
-- Set your desired date format here
dateFormatter's setDateFormat:"EEEE, MMM d, yyyy 'at' h'h' mm'm' ss's' a"
set formattedDate to (dateFormatter's stringFromDate:currentDate) as text
set rootFolder to "Macintosh HD:Users:dannywyatt:Library:Mobile Documents:iCloud~md~obsidian:Documents:Tiago:Inbox"
-- Append current date and time to the folder name
set folderName to "Converted notes from NOTES app " & formattedDate
tell application "Finder"
set exportFolder to make new folder at folder rootFolder with properties {name:folderName}
set exportFolder to exportFolder as text
end tell
tell application "Notes" to activate
-- Simple text replacing
on replaceText(find, replace, subject)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set subject to text items of subject
set text item delimiters of AppleScript to replace
set subject to "" & subject
set text item delimiters of AppleScript to prevTIDs
return subject
end replaceText
-- Get an .md file to save the note in. We have to escape
-- the colons or AppleScript gets upset.
on noteNameToFilePath(noteName)
global exportFolder
set strLength to the length of noteName
if strLength > 250 then
set noteName to text 1 thru 250 of noteName
end if
-- Construct file path
set fileName to (exportFolder & replaceText(":", "_", noteName) & ".md")
-- Remove Horizontal Ellipsis (U+2026) from filename
set fileName to my replaceText("ā¦", "", fileName)
return fileName
end noteNameToFilePath
tell application "Notes"
repeat with theNote in notes of folder "Notes"
set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to "/"
set AppleScript's text item delimiters to oldDelimiters
set fileName to name of theNote as string
set filepath to noteNameToFilePath(fileName) of me
set noteFile to open for access filepath with write permission
set theText to plaintext of theNote as string
write theText to noteFile as Ā«class utf8Ā»
close access noteFile
end repeat
end tell
When you use this line:
set editedNoteName to replaceText({"...", "ā¦"}, "", editedNoteName)
The {"...", "ā¦"}, "" section works kind of like an OR operator, right? The content inside the curly brackets works as a single element that gets replaced, but itās āthisā or āthatā, correct? Hope Iām making senseā¦
The solutions provided in threads like this will be consulted by users for years to come. Scripts or shortcuts that do not meet your needs will likely be of use to others in the future. That has always been my thinking when posting multiple solutions to a request.
Agree 100%. I was just stating that for my current case, Shortcuts wonāt be a good alternative, not only because of my OS, but also because I use Keyboard Maestro, and because I was looking for a simplified version using only AS.
These solutions also help me understand AS a bit more as well.
peavine answered this, but I see heās now deleted his post for some reason. Maybe heās reformulating it. But yes. Without going into detail myself about how AppleScriptās text item delimiters work, by passing a list of strings to be replaced to the scriptās replaceText() handler, youāre specifying that you want every instance in the main text of any of these substrings to be replaced with the given replacement string. In the example above, you get back a copy of the main text which doesnāt contain any of the substrings.
If youāre interested and havenāt already done it, there are a few ways your script might be tidied up:
The two handlers (the subroutine blocks beginning with āonā) should ideally be placed right at the end of the script or just below the use statements at the top. This is because the rest of the code is notionally in something called an āimplicit run handlerā and itās considered good form to keep this as a block itself, not interspersed with code for other handlers. If the run handler were explicit, the script wouldnāt compile unless all the handlers were in their own space.
Your ācurrentDateā variable isnāt used, so the line setting it is redundant.
Similarly, in the tell block currently at the bottom, the three lines involving AppleScriptās text item delimiters simply change the delimiter value and immediately change it back again, so theyāre superfluous too.
With regard to the statements in that block which write the text to the file, itās a good idea to protect them with a try statement to ensure that, should an error occur while the fileās open for access, the script wonāt just crash and leave the file open. I personally would put the writing to file in its own handler.
Iāve implemented these suggestions below, but havenāt run the script to test it. Of course itās entirely up to you whether or not you wish to adopt them.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
(* Implicit run handler starts here *)
tell application "Notes"
set notesFolder to folder "Notes" of account "iCloud"
tell notesFolder
set theCount to (count notes)
set invalid to ((theCount = 0) or ((theCount = 1) and (note 1's body = "")))
end tell
end tell
if (invalid) then error number -128 -- "User canceled" error.
-- Get current date and time
set dateFormatter to current application's NSDateFormatter's new()
-- Set your desired date format here
dateFormatter's setDateFormat:"EEEE, MMM d, yyyy 'at' h'h' mm'm' ss's' a"
set formattedDate to (dateFormatter's stringFromDate:currentDate) as text
set rootFolder to "Macintosh HD:Users:dannywyatt:Library:Mobile Documents:iCloud~md~obsidian:Documents:Tiago:Inbox"
-- Append current date and time to the folder name
set folderName to "Converted notes from NOTES app " & formattedDate
tell application "Finder"
set exportFolder to make new folder at folder rootFolder with properties {name:folderName}
set exportFolder to exportFolder as text
end tell
tell application "Notes"
activate
repeat with theNote in notes of notesFolder
set fileName to name of theNote
set filePath to my noteNameToFilePath(fileName)
set theText to plaintext of theNote
my writeToFile(theText, filePath, Ā«class utf8Ā»)
end repeat
end tell
(* Other handlers *)
-- Simple text replacing
on replaceText(find, replace, subject)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set subject to text items of subject
set text item delimiters of AppleScript to replace
set subject to "" & subject
set text item delimiters of AppleScript to prevTIDs
return subject
end replaceText
-- Get an .md file to save the note in. We have to escape
-- the colons or AppleScript gets upset.
on noteNameToFilePath(noteName)
global exportFolder
set strLength to the length of noteName
if strLength > 250 then
set noteName to text 1 thru 250 of noteName
end if
-- Construct file path
set fileName to (exportFolder & replaceText(":", "_", noteName) & ".md")
-- Remove Horizontal Ellipsis (U+2026) from filename
set fileName to my replaceText("ā¦", "", fileName)
return fileName
end noteNameToFilePath
on writeToFile(theData, filePath, saveFormat)
set fileRef to (open for access file filePath with write permission)
try
set eof fileRef to 0 -- Delete existing content, if any.
write theData to fileRef as saveFormat
close access fileRef
on error errMsg -- If anything goes wrong, close the file, display a message, and continue.
close access fileRef
tell application (path to frontmost application as text) to display dialog errMsg
end try
end writeToFile
Nigel. After responding to alltiagocomās question, I noticed that he had directed it to you. So, just as a matter of forum etiquette, I deleted my post.