├── .gitignore ├── README.md └── notion-to-joplin.py /.gitignore: -------------------------------------------------------------------------------- 1 | /backup-notion-test.zip 2 | /import to joplin/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Import Notion to Joplin 2 | 3 | Simple script to convert a Notion export to a Joplin import (MD - Markdown directory). 4 | 5 | ## Requirements 6 | 7 | - Python 3.6+ 8 | 9 | ## Usage 10 | 11 | 1. Export your Notion workspace as Markdown & CSV (with subpages). 12 | 13 | 2. Download script. 14 | 15 | ```bash 16 | curl -O https://github.com/tanrax/notion-to-joplin/raw/main/notion-to-joplin.py 17 | ``` 18 | 19 | 3. Run the script: 20 | 21 | ```bash 22 | python3 notion-to-joplin.py -f 23 | ``` 24 | 25 | Example: 26 | 27 | ```bash 28 | python3 notion-to-joplin.py -f b25c8352-f87b-4b5b-ce0a-61d09c5bd81b_Export-9e0c6ec4-762b-4d70-b30e-045ece8b4722.zip 29 | ``` 30 | 31 | 4. Import the generated folder into Joplin. 32 | 33 | You can now import the folder `import to joplin` to Joplin (File > Import > MD - Markdown directory). 34 | 35 | Done! 36 | -------------------------------------------------------------------------------- /notion-to-joplin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # This script is used to convert a Notion export to a Joplin import (MD - Markdown directory). 3 | # Step 1: Get the notion export zip file 4 | # Step 2: Unzip the notion export zip file 5 | # Step 3: Rename every file with a .md extension with the heading of the file and fix all the links 6 | # Step 4: Rename all folder. Remove the "hash" from the ending of the folder name and fix all the links 7 | 8 | from argparse import ArgumentParser 9 | import sys 10 | import zipfile 11 | import glob 12 | import shutil 13 | from os import path 14 | import ntpath 15 | import urllib.parse 16 | 17 | # VARIABLES 18 | FOLDER_EXTRACTION = "import to joplin" 19 | MARKDOWN_EXTENSION = "md" 20 | filename_backup = "" 21 | 22 | ## Step 1: Get the notion export zip file 23 | # Delete the folder if it exists 24 | if path.exists(FOLDER_EXTRACTION): 25 | shutil.rmtree(FOLDER_EXTRACTION) 26 | # Get parameter 27 | parser = ArgumentParser( 28 | prog="ProgramName", 29 | description="What the program does", 30 | epilog="Text at the bottom of help", 31 | ) 32 | parser.add_argument("-f", "--file", help="File to be processed", required=True) 33 | try: 34 | args = parser.parse_args() 35 | filename_backup = args.file 36 | except: 37 | parser.print_help() 38 | sys.exit(0) 39 | 40 | ## Step 2: Unzip the file 41 | print("Unzipping backup file...") 42 | with zipfile.ZipFile(filename_backup, "r") as zip_ref: 43 | zip_ref.extractall(FOLDER_EXTRACTION) 44 | print("Unzipping done.") 45 | 46 | ## Step 3: Rename every file with a .md extension with the heading of the file and fix all the links 47 | print("Renaming files and fixing links...") 48 | # Get all markdown files 49 | path_to_files = path.join(FOLDER_EXTRACTION, "**/*." + MARKDOWN_EXTENSION) 50 | for filename in glob.iglob(path_to_files, recursive=True): 51 | # Get the heading of the file 52 | with open(filename, "r", encoding="utf-8") as file: 53 | # Get the heading 54 | first_line = file.readline() 55 | heading = first_line.replace("# ", "").replace("\n", "").replace("/", "-") 56 | # Delete two first lines 57 | lines = file.readlines() 58 | lines_without_heading = lines[1:] 59 | # Write the file without the heading 60 | with open(filename, "w", encoding="utf-8") as file: 61 | file.write("".join(lines_without_heading)) 62 | # Rename the file 63 | new_filename = path.join(path.dirname(filename), heading + "." + MARKDOWN_EXTENSION) 64 | shutil.move(filename, new_filename) 65 | # Fix all the links 66 | old_filename_encoded = urllib.parse.quote(ntpath.basename(filename)) 67 | heading_encoded = urllib.parse.quote(heading) + "." + MARKDOWN_EXTENSION 68 | for filename_to_fix in glob.iglob(path_to_files, recursive=True): 69 | with open(filename_to_fix, "r", encoding="utf-8") as file: 70 | lines_to_fix = file.readlines() 71 | with open(filename_to_fix, "w", encoding="utf-8") as file: 72 | text_to_write = "".join(lines_to_fix).replace( 73 | old_filename_encoded, heading_encoded 74 | ) 75 | file.write(text_to_write) 76 | print("Renaming files and fixing links done.") 77 | 78 | ## Step 4: Rename all folder. Remove the "hash" from the ending of the folder name 79 | print("Renaming folders...") 80 | path_of_folders = path.join(FOLDER_EXTRACTION, '**/*') 81 | for folder in glob.iglob(path_of_folders, recursive=True): 82 | if path.isdir(folder): 83 | current_folder_name = path.basename(folder) 84 | new_folder_name = " ".join(current_folder_name.split(" ")[:-1]) 85 | shutil.move(folder, path.join(path.dirname(folder), new_folder_name)) 86 | # Fix all the links 87 | old_folder_name_encoded = urllib.parse.quote(current_folder_name) 88 | new_folder_name_encoded = urllib.parse.quote(new_folder_name) 89 | for filename_to_fix in glob.iglob(path_to_files, recursive=True): 90 | with open(filename_to_fix, "r", encoding="utf-8") as file: 91 | lines_to_fix = file.readlines() 92 | with open(filename_to_fix, "w", encoding="utf-8") as file: 93 | text_to_write = "".join(lines_to_fix).replace( 94 | old_folder_name_encoded, new_folder_name_encoded 95 | ) 96 | file.write(text_to_write) 97 | print("Renaming folders done.") 98 | print("All done. You can now import the folder \"" + FOLDER_EXTRACTION + "\" to Joplin (File > Import > MD - Markdown directory)") 99 | --------------------------------------------------------------------------------