Skip to content

Instantly share code, notes, and snippets.

@qbatten
Last active January 31, 2022 13:44
Show Gist options
  • Save qbatten/1cb7eee8a791f22cda9b080dfbfeee36 to your computer and use it in GitHub Desktop.
Save qbatten/1cb7eee8a791f22cda9b080dfbfeee36 to your computer and use it in GitHub Desktop.
Python script to rename your Roam daily notes to match Noteplan Calendar format.
'''
This is a script that tries to convert Roam Daily Notes to Noteplan Calendar
Notes. All it does is find files in the current directory that have a name
matching the Roam Daily Notes format (e.g. "August 8th, 2020.md"), rename them
to the Noteplan Calendar Notes format (YYYYMMDD, e.g. "20200808.md") and move
them into a subfolder of the current directory: 'renamed_daily_notes'.
I recommend you read this blog post before going any further:
https://axle.design/why-and-how-to-use-obsidian-and-noteplan-together.
It's not specifically about moving from Roam to Noteplan, but it provides a bunch
of helpful info about how Noteplan works with md files and how Noteplan's sync
and stuff works. Definitely read it!
NOTES:
- PLEASE PLEASE MAKE A BACKUP OF YOUR NOTEPLAN NOTES BEFORE YOU DO ANYTHING ELSE.
- THIS IS A FREE AMATEUR-MADE SCRIPT, PLEASE MAKE SURE YOU KNOW WHAT YOU'RE DOING BEFORE
RUNNING IT. I OFFER NO GUARANTEES AABOUT ITS SAFETY OR RELIABILITY WHATSOEVER.
## Steps to use:
1. Download a Markdown export of your Roam database.
a. In Roam, click the three dots on the top right
b. Click "Export All", and a little popup will appear.
c. Choose "Export Format" -> "Markdown", and click "Export All"
2. Unzip the folder. (It will download as a zip file; unzip it.)
3. Copy this script into the unzipped folder.
4. Open your Terminal and navigate to that unzipped Roam export folder. You
will probably do this by typing "cd Downloads/[roam folder name]", but it
depends on your computer.
5. Run the script! Just type: "python ./roam_to_noteplan.py", hit Enter, and
follow the prompts.
6. Now your Noteplan Calendar Notes are in a sub-directory titled
"renamed_daily_notes."
7. Delete the script file, you're all done!
## Importing files into Noteplan:
NOTE:
- IF YOU ARE STARTING FULLY FROM SCRATCH WITH NOTEPLAN, you can just copy the
contents of renamed_daily_notes into your Noteplan/Calendar folder,
and replace any files currently there. Then you can copy the rest of your Roam
export into the Noteplan/Notes folder.
- If you already have some Noteplan Calendar Notes, YOU HAVE TO BE CAREFUL!
You don't want to overwrite your Noteplan stuff with your Roam stuff.
You'll have to manually reconcile things.
With that out of the way, in order to import these into Noteplan, you'll want to check what
sync technique you use...
If you use Cloudkit, your Noteplan notes
will be in `~/Library/Containers/co.noteplan.NotePlan3/Data/Library/Application Support/co.noteplan.NotePlan3/`
and you'll want to copy your converted Calendar Notes into the "Calendar"
subfolder: `~/Library/Containers/co.noteplan.NotePlan3/Data/Library/Application Support/co.noteplan.NotePlan3/Calendar`)
If you use anything else, you should be able to go to Noteplan 3 > Preferences
> Sync > [Sync technique] > Advanced > [Open folder, or something like that].
When you find your Noteplan folder, you can just copy your converted daily
notes into the Calendar subfolder, and the rest of your notes into the Notes
subfolder.
To reiterate the warning above,
IF YOU WROTE IN BOTH ROAM AND NOTEPLAN ON A GIVEN DATE, YOU DONT WANT TO JUST
OVERWRITE YOUR NOTEPLAN FILE WITH YOUR EXPORTED ROAM FILE... THIS SCRIPT
WILL RENAME YOUR ROAM FILE TO MATCH THE NOTEPLAN FILE SO THEY WILL CONFLICT
WITH EACH OTHER... YOU HAVE TO MANUALLY COMBINE THE TWO FILES!
## More Reading
- As I mentioned above, check out this GREAT blog post about using [Obsidian](https://obsidian.md/)
and Noteplan together. https://axle.design/why-and-how-to-use-obsidian-and-noteplan-together
- Noteplan [has a subreddit](https://www.reddit.com/r/noteplanapp/)
- Roam Research [has a subreddit](https://www.reddit.com/r/RoamResearch/), too.
- Here's the [official Noteplan website](https://noteplan.co/).
- Here's the [official Roam Research website](roamresearch.com/).
Copyright Quinn Batten 2021.
'''
from datetime import datetime
import os
import re
import sys
def format_daily_notes_filename(file_name, verbose=False):
"""
Takes in filename, returns tuple of old (Roam Daily Notes) & new
(Noteplan Calendar Notes) filenames.
If filename is NOT a Roam Daily Note, returns None
If filename IS a Roam Daily Note, returns a tuple of the two values in
"Returns.""
Input
-----
fname : str, a filename to try and conver
verbose : bool, whether to announce un-moved files
Returns
-------
(file_name, add_md) : tuple of (original filename, new filename), for those
input notes that matched Roam Daily Notes filename format.
"""
remove_md = file_name.replace('.md', '')
remove_st_th = remove_md.replace('st,', ',')\
.replace('th,', ',')\
.replace('nd,', ',')\
.replace('rd,', ',')
pad_zero = re.sub(r' (\d), ', r' 0\1, ', remove_st_th)
try:
parse_date = datetime.strptime(pad_zero, '%B %d, %Y')
except ValueError:
if verbose:
print('failed to convert: ' + file_name + ' ... ' + remove_md +
' / ' + remove_st_th + ' / ' + pad_zero)
return
new_date_str = parse_date.strftime('%Y%m%d')
add_md = new_date_str + '.md'
return (file_name, add_md)
def move_daily_notes(roam_export_dir='.', output_dir='./renamed_daily_notes/'):
"""
Identifies Roam Daily Notes files baased on filename, moves them into new
directory and renames them to match Noteplan's Calendar Notes file name
format.
Input
-----
roam_export_dir : str, directory full of exported Roam md files
output_dir: str, directory you want the renamed date files to go into
Returns
-------
None
"""
if not os.path.exists(output_dir):
os.mkdir(output_dir)
files_to_move = [name_tuple for name_tuple in
(format_daily_notes_filename(file) for file in os.listdir())
if name_tuple is not None]
print('Moving ' + str(len(files_to_move)) + ' files into folder ' + os.path.realpath(output_dir))
[os.rename(original_file, output_dir + new_file)
for (original_file, new_file) in files_to_move]
if __name__ == "__main__":
# execute only if run as a script
first_warn = 'This script could cause data loss. It moves files around and renames them. It is offered as is, with no guarantees whatsoever. Do you accept full responsibility for understanding and auditing this script before running it?\nPlease answer Y/N: '
dir_check_prompt = 'You are currently in the following directory: "' + os.getcwd() + '". Is that your Roam Markdown export directory?\nAnswer Y/N: '
confirmation = input(first_warn)
if confirmation != 'Y':
print('Exiting due to user response')
sys.exit()
dir_check_response = input(dir_check_prompt)
if dir_check_response != 'Y':
print('Exiting... please move this file to your Roam export folder and run it there.')
sys.exit()
move_daily_notes()
@Rainymood
Copy link

Thanks for sharing this!

@qbatten
Copy link
Author

qbatten commented May 19, 2021

@Rainymood no prob, so glad it was useful to someone!

@yashodhankhare
Copy link

Traceback (most recent call last):
File "./roam_daily_to_noteplan.py", line 173, in
move_daily_notes()
File "./roam_daily_to_noteplan.py", line 151, in move_daily_notes
(format_daily_notes_filename(file) for file in os.listdir())
TypeError: listdir() takes exactly 1 argument (0 given)

This is the error I am getting, a folder is created for Renamed Notes, but it is empty

@qbatten
Copy link
Author

qbatten commented Jan 31, 2022

@yashodhankhare I think you may be using Python 2.7, and you need to use Python 3.2 or later (see “Changed in version 3.2” here).

Depending on your setup, you may be able to just call “python3” instead of “python”. If that doesn’t work, and you’re not sure how to use a different Python version, this seems like a reasonable introduction.

@yashodhankhare
Copy link

yashodhankhare commented Jan 31, 2022 via email

@qbatten
Copy link
Author

qbatten commented Jan 31, 2022

@yashodhankhare If you’re on a recent Mac, you should just be able to type “python3” instead of “python” on the command line, per my last comment. If that doesn’t work, please follow the tutorial I linked in my last comment.

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