Skip to content

Instantly share code, notes, and snippets.

@nmasse-itix
Last active May 4, 2023 15:56
Show Gist options
  • Save nmasse-itix/a9475ffe8ec0bef4eba969f55408e0cf to your computer and use it in GitHub Desktop.
Save nmasse-itix/a9475ffe8ec0bef4eba969f55408e0cf to your computer and use it in GitHub Desktop.
Why I decided to move away from Apple Notes

Why I decided to move away from Apple Notes

Why playing with the Apple Notes APIs, I realized there were not working properly and thus I had no means to automatically migrate my notes to another app. So, I decided to copy/paste my notes in another app (Bearnotes) while the number of notes was still manageable.

Below are my attempts to play with the Apple Notes API.

Trials

open -a "Script Editor"
  • Window > Library
  • File > New

tell application "Notes" to activate

tell application "Notes" to get the name of front window
=> "Notes"

tell application "Notes"
	set folderList to (every folder of the default account)
	repeat with aFolder in folderList
		log "Folder: " & name of aFolder
	end repeat
end tell

=> Bug on latest version of MacOS: https://talk.automators.fm/t/applescript-error-catalina/5880

(*Folder: Blog*)
(*Folder: Bricolage*)
(*Folder: Comptes & finance*)
(*Folder: Développement Perso*)
(*Folder: Ecologie*)
(*Folder: Fact Checking*)
(*Folder: Idées Maker*)
(*Folder: Jardinage*)
(*Folder: Leboncoin*)
(*Folder: Louise*)
(*Folder: Maison*)
(*Folder: Memes*)
(*Folder: Notes*)
(*Folder: Notre future maison*)
(*Folder: Promos*)
(*Folder: Randonnées Vélo*)
(*Folder: Recently Deleted*)
(*Folder: Recettes*)
(*Folder: Recherche d'emploi*)
(*Folder: Reconversion professionnelle*)
(*Folder: Références*)
(*Folder: Santé*)
(*Folder: Tech*)
(*Folder: TODO*)
(*Folder: Véhicules*)
(*Folder: Vélo*)
(*Folder: Voyages*)

tell application "Notes"
	set folderList to (every folder of the default account)
	repeat with aFolder in folderList
		set noteList to (every note of aFolder)
		repeat with aNote in noteList
			log (name of aFolder) & "/" & (name of aNote)
		end repeat
	end repeat
end tell

set targetFolder to (choose folder)
log (quoted form of POSIX path of targetFolder)
(*''*)

on sanitize(fileName)
	set rnd to (random number from 0 to 1.0E+9)
	set tmpFile to "/tmp/notes-export-tmp-file." & rnd
	set f to (open for access (tmpFile as POSIX file) with write permission)
	try
		set eof of f to 0
		write fileName to f as «class utf8»
		close access f
	on error
		close access f
	end try
	set sanitizedName to do shell script "sed -E 's/[^-[:alnum:][:space:]_]+//g; s/[ ]+/_/g' " & tmpFile
	return sanitizedName
end sanitize

set aName to "truc/[bidule] tété"
log sanitize(aName)
(*trucbidule_tété*)

set targetFolder to (choose folder)
set quotedTargetFolder to (quoted form of POSIX path of targetFolder)

tell application "Notes"
	set folderList to (every folder of the default account)
	repeat with aFolder in folderList
		set folderPath to quotedTargetFolder & "/" & my sanitize(name of aFolder & "")
		do shell script "mkdir -p '" & folderPath & "'"
	end repeat
end tell

on sanitize(fileName)
	set rnd to (random number from 0 to 1.0E+9)
	set tmpFile to "/tmp/notes-export-tmp-file." & rnd
	set f to (open for access (tmpFile as POSIX file) with write permission)
	try
		set eof of f to 0
		write fileName to f as «class utf8»
		close access f
	on error
		close access f
	end try
	set sanitizedName to do shell script "sed -E 's/[^-[:alnum:][:space:]_]+//g; s/[ ]+/_/g' " & tmpFile
	return sanitizedName
end sanitize

set targetFolder to (choose folder)
set quotedTargetFolder to (quoted form of POSIX path of targetFolder)

tell application "Notes"
	set folderList to (every folder of the default account)
	repeat with aFolder in folderList
		set quotedFolderName to my sanitize(name of aFolder & "")
		set noteList to (every note of aFolder)
		repeat with aNote in noteList
			log (name of aFolder) & "/" & (name of aNote)
			set folderPath to quotedTargetFolder & "/" & quotedFolderName & "/" & my sanitize(name of aNote & "")
			do shell script "mkdir -p '" & folderPath & "'"
		end repeat
	end repeat
end tell

on sanitize(fileName)
	set rnd to (random number from 0 to 1.0E+9)
	set tmpFile to "/tmp/notes-export-tmp-file." & rnd
	set f to (open for access (tmpFile as POSIX file) with write permission)
	try
		set eof of f to 0
		write fileName to f as «class utf8»
		close access f
	on error
		close access f
	end try
	set sanitizedName to do shell script "sed -E 's/[^-[:alnum:][:space:]_]+//g; s/[ ]+/_/g' " & tmpFile
	return sanitizedName
end sanitize

set targetFolder to (choose folder)

tell application "Notes"
	set folderList to (every folder of the default account)
	repeat with aFolder in folderList
		set folderName to my sanitize(name of aFolder & "")
		set noteList to (every note of aFolder)
		repeat with aNote in noteList
			log (name of aFolder) & "/" & (name of aNote)
			set folderPath to (POSIX path of targetFolder) & folderName & "/" & my sanitize(name of aNote & "")
			do shell script "mkdir -p '" & folderPath & "'"
			my writeFile(folderPath & "/note.html", body of aNote & "")
			set attachmentList to (every attachment of aNote)
			repeat with anAttachment in attachmentList
				set attachmentFileName to my sanitize(name of anAttachment & "")
				set attachmentFile to (folderPath & "/" & attachmentFileName) as POSIX file
				log (attachmentFile & "")
				close access (open for access attachmentFile)
				-- tell the anAttachment to save in attachmentFile
				--save anAttachment in attachmentFile
				save anAttachment in folderPath
			end repeat
		end repeat
	end repeat
end tell

on writeFile(fileName, content)
	set f to (open for access (fileName as POSIX file) with write permission)
	try
		set eof of f to 0
		write content to f as «class utf8»
		close access f
	on error
		close access f
	end try
end writeFile

on sanitize(fileName)
	set rnd to (random number from 0 to 1.0E+9)
	set tmpFile to "/tmp/notes-export-tmp-file." & rnd
	writeFile(tmpFile, fileName)
	set sanitizedName to do shell script "sed -E 's/[^-[:alnum:][:space:]_.]+//g; s/[ ]+/_/g' " & tmpFile
	return sanitizedName
end sanitize


set targetFolder to (choose folder)

tell application "Notes"
	set folderList to (every folder of the default account)
	repeat with aFolder in folderList
		set folderName to my sanitize(name of aFolder & "")
		set noteList to (every note of aFolder)
		repeat with aNote in noteList
			log (name of aFolder) & "/" & (name of aNote)
			set folderPath to (POSIX path of targetFolder) & folderName & "/" & my sanitize(name of aNote & "")
			do shell script "mkdir -p '" & folderPath & "'"
			my writeFile(folderPath & "/note.html", body of aNote & "")
			set myAttachments to (every attachment of aNote)
			set attachmentFiles to {}
			set attachmentCount to (count myAttachments)
			if (attachmentCount > 0) then
				do shell script "mkdir -p '" & folderPath & "/attachment'{1.." & attachmentCount & "}"
				set hfsNotePath to folderPath as POSIX file
				repeat with k from 1 to attachmentCount
					set thisAttachment to item k of myAttachments
					set thisFile to ((hfsNotePath as text) & ":attachment" & k & ":" & thisAttachment's name) as «class furl»
					close access (open for access thisFile)
					save thisAttachment in thisFile -- Now it works! Thanks, Yvan!
					set end of attachmentFiles to thisFile
				end repeat
				
			end if
		end repeat
	end repeat
end tell

on writeFile(fileName, content)
	set f to (open for access (fileName as POSIX file) with write permission)
	try
		set eof of f to 0
		write content to f as «class utf8»
		close access f
	on error
		close access f
	end try
end writeFile

on sanitize(fileName)
	set rnd to (random number from 0 to 1.0E+9)
	set tmpFile to "/tmp/notes-export-tmp-file." & rnd
	writeFile(tmpFile, fileName)
	set sanitizedName to do shell script "sed -E 's/[^-[:alnum:][:space:]_.]+//g; s/[ ]+/_/g' " & tmpFile
	return sanitizedName
end sanitize

Tested this script: https://macscripter.net/viewtopic.php?id=45602

main()

on main()
	-- User choice of one or more Notes folders (by name).
	tell application "Notes"
		activate
		set folderNames to name of folders
		set chosenFolderNames to (choose from list folderNames with multiple selections allowed)
		if (chosenFolderNames is false) then error number -128 -- Cancel button.
	end tell
	
	-- Preset HFS and POSIX versions of a path to a folder on the desktop for storing any attachments.
	set tempFolderPath to (path to desktop as text) & "Attachments from Notes:"
	set tempFolderPosix to quoted form of POSIX path of tempFolderPath
	
	-- Repeat with each chosen folder name:
	repeat with i from 1 to (count chosenFolderNames)
		-- Get all the notes in the folder with this name.
		set thisFolderName to item i of chosenFolderNames
		tell application "Notes" to set theNotes to notes of folder thisFolderName
		set quotedFolderName to quoted form of thisFolderName
		
		-- Repeat with each note in the folder:
		repeat with j from 1 to (count theNotes)
			set thisNote to item j of theNotes
			
			tell application "Notes"
				-- Get the relevant note data.
				set myTitle to the name of thisNote
				set myText to the body of thisNote
				set myCreateDate to the creation date of thisNote
				set myModDate to the modification date of thisNote
				set myAttachments to the attachments of thisNote
				
				-- Any attachments will need to be extracted to the folder on the desktop and attached to the Evernote note from there.
				-- To preserve the attachment names and avoid confusion in the case of duplicated names, each attachment is saved to a separate subfolder in a hierarchy based on the folder/note/attachment structure.
				set attachmentFiles to {}
				set attachmentCount to (count myAttachments)
				if (attachmentCount > 0) then
					-- If this note has any attachments, create or add to the hierarchy of the folder on the desktop to accommodate each one.
					do shell script ("mkdir -p " & tempFolderPosix & quotedFolderName & "/'Note '" & j & "/'Attachment '{1.." & attachmentCount & "}")
					
					-- Repeat with each attachment:
					repeat with k from 1 to attachmentCount
						set thisAttachment to item k of myAttachments
						-- Put together a specifier for a file in which to save this attachment.
						set thisFile to (tempFolderPath & thisFolderName & ":Note " & j & ":Attachment " & k & ":" & thisAttachment's name) as «class furl»
						-- Create the file before trying to save to it. (Suggested by Yvan Koenig.)
						close access (open for access thisFile)
						-- Save the attachment to it.
						save thisAttachment in thisFile -- Now it works! Thanks, Yvan!
						-- Store the file specifier for the retrieval of the attachment below.
						set end of attachmentFiles to thisFile
					end repeat
					
				end if
			end tell
		end repeat
		
	end repeat
end main

=> attachments are empty => need to test on Sierra 10.12.3

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