Apple Reminder to Obsidian Sync Script

This blog post dives into a powerful AppleScript for syncing reminders with markdown files. It details how to log sync processes, check for updates in lists, and efficiently create and save markdown files for modified reminders. With clear explanations on leveraging file paths and timestamps, it ...

Apple Reminder to Obsidian Sync Script
on run {outputFolderPath}
	-- Convert input path to text and ensure it ends with a slash
	set outputFolder to outputFolderPath as text
	if outputFolder does not end with "/" then
		set outputFolder to outputFolder & "/"
	end if
	
	-- Path for storing last sync timestamp and logs
	set timestampFile to outputFolder & ".last_sync"
	set logFile to outputFolder & "sync_log.txt"
	
	-- Initialize logging
	my writeToLog(logFile, "Starting sync process...")
	my writeToLog(logFile, "Output folder: " & outputFolder)
	
	-- Get last sync time
	set lastSync to my getLastSyncTime(timestampFile)
	my writeToLog(logFile, "Last sync time: " & (lastSync as text))
	
	tell application "Reminders"
		set successCount to 0
		set updateCount to 0
		set totalLists to count of every list
		my writeToLog(logFile, "Found " & totalLists & " total lists")
		
		-- Process each list
		repeat with aList in every list
			set listName to name of aList
			my writeToLog(logFile, "Checking list: " & listName)
			
			-- Check if file exists
			set filePath to outputFolder & my getSafeFileName(listName) & ".md"
			set needsUpdate to my fileNeedsCreation(filePath)
			
			if not needsUpdate then
				-- Check if any reminders in the list have been modified
				my writeToLog(logFile, "  Checking reminders for modifications...")
				repeat with aReminder in every reminder in aList
					try
						set reminderModDate to modification date of aReminder
						if reminderModDate is not missing value and reminderModDate > lastSync then
							my writeToLog(logFile, "  Found modified reminder: " & (get name of aReminder))
							set needsUpdate to true
							exit repeat
						end if
					end try
				end repeat
			end if
			
			if needsUpdate then
				my writeToLog(logFile, "  Updates needed - writing file")
				-- Create markdown content for this list
				set markdown to "# " & listName & return & return
				
				-- Add all reminders in the list
				repeat with aReminder in every reminder in aList
					set markdown to markdown & "- " & (get name of aReminder) & return
				end repeat
				
				-- Save the file
				try
					my writeToLog(logFile, "  Saving to file: " & filePath)
					set fileRef to open for access POSIX file filePath with write permission
					write markdown to fileRef
					close access fileRef
					set updateCount to updateCount + 1
					my writeToLog(logFile, "  Successfully saved file")
				on error errorMessage
					my writeToLog(logFile, "  Error saving " & listName & ": " & errorMessage)
					try
						close access fileRef
					end try
				end try
			else
				my writeToLog(logFile, "  No updates needed for this list")
			end if
			set successCount to successCount + 1
		end repeat
		
		-- Save new timestamp
		my writeToLog(logFile, "Saving new sync timestamp...")
		my saveLastSyncTime(timestampFile, current date)
		
		set finalMessage to "Sync complete: " & updateCount & " lists updated out of " & totalLists & " total lists"
		my writeToLog(logFile, finalMessage)
		return finalMessage
	end tell
end run

-- Write to log file with timestamp
on writeToLog(logFile, logMessage)
	set timestamp to do shell script "date '+%Y-%m-%d %H:%M:%S'"
	set logLine to timestamp & " " & logMessage & return
	try
		set fileRef to (open for access POSIX file logFile with write permission) as text
		write logLine to fileRef starting at eof
		close access fileRef
	on error
		try
			close access fileRef
		end try
	end try
end writeToLog

-- Get safe filename
on getSafeFileName(thisName)
	set safeFileName to my replaceText(thisName, " ", "_")
	set safeFileName to my replaceText(safeFileName, "/", "_")
	return safeFileName
end getSafeFileName

-- Check if file needs to be created
on fileNeedsCreation(filePath)
	try
		POSIX file filePath as alias
		return false
	on error
		return true
	end try
end fileNeedsCreation

-- Get last sync time from file
on getLastSyncTime(timestampFile)
	try
		POSIX file timestampFile as alias
		set fileRef to open for access POSIX file timestampFile
		set timestamp to read fileRef as text
		close access fileRef
		return date timestamp
	on error
		my writeToLog(timestampFile, "No previous sync timestamp found - using default date")
		return date "Saturday, 1. January 2000 at 12:00:00 AM"
	end try
end getLastSyncTime

-- Save last sync time to file
on saveLastSyncTime(timestampFile, syncTime)
	try
		set fileRef to open for access POSIX file timestampFile with write permission
		write (syncTime as text) to fileRef
		close access fileRef
	on error
		my writeToLog(timestampFile, "Error saving timestamp")
	end try
end saveLastSyncTime

-- Helper function to replace text
on replaceText(someText, oldItem, newItem)
	set AppleScript's text item delimiters to oldItem
	set theItems to text items of someText
	set AppleScript's text item delimiters to newItem
	set newText to theItems as text
	set AppleScript's text item delimiters to ""
	return newText
end replaceText
Data Privacy | Imprint