Scrivener To Obsidian
This Python script is designed to convert markdown files and images exported from Scrivener into a format compatible with Obsidian.
Here is a detailed breakdown of what the code does:
Import necessary modules: The script begins by importing the necessary Python modules:
os
,re
,shutil
, andBeautifulSoup
frombs4
.Function
get_relative_path(output_folder, image_file)
: This function calculates and returns the relative path of an image file by eliminating the common prefix shared with the output directory.Function
convert_scrivener_to_obsidian(exported_folder, output_folder)
: This function is the main part of the script, responsible for transforming Scrivener exports into Obsidian-friendly markdown files.Initial steps: The function starts by creating a dictionary (
image_locations
) to map image file names (without their extensions) to their corresponding full file names. It then ensures that the output folder exists.Processing directories and files: The function iterates over each directory and file within the exported Scrivener folder. For each directory, an equivalent directory is created within the output folder. For each file, it checks the file extension. If it's an image file (png, jpg, jpeg, or gif), the file is copied to the equivalent directory in the output folder, and the file name (without extension) is added to the
image_locations
dictionary.Processing Markdown files: If a markdown file (extension .md) is encountered, it's read into memory and a replacement function is defined. This function checks each image reference in the markdown file, replacing the reference with the proper Obsidian-compatible format if the image is found in
image_locations
. The content, with image references replaced, is then written to the corresponding location in the output directory.
Execution and error handling: The script finally calls
convert_scrivener_to_obsidian()
with paths to the Scrivener exported files and the output folder. If any error occurs during this process, it's caught and a message is printed.
For the script to work correctly, the paths to the exported Scrivener folder and the output Obsidian folder should be provided at the end of the script. The script expects that Scrivener files have been exported in Markdown format.
import os
import re
import shutil
from bs4 import BeautifulSoup
# Define a function to get the relative path without ../
def get_relative_path(output_folder, image_file):
common_prefix = os.path.commonprefix([output_folder, image_file])
relative_path = image_file[len(common_prefix):].lstrip("/")
return relative_path
def convert_scrivener_to_obsidian(exported_folder, output_folder):
image_locations = {}
os.makedirs(output_folder, exist_ok=True)
# Loop through the exported folder to convert files
for root, dirs, files in os.walk(exported_folder):
output_subfolder = os.path.join(output_folder, os.path.relpath(root, exported_folder))
os.makedirs(output_subfolder, exist_ok=True)
for file in files:
_, extension = os.path.splitext(file)
if extension.lower() in ['.png', '.jpg', '.jpeg', '.gif']:
image_locations[file[:-4]] = os.path.basename(os.path.join(root, file))
old_image_path = os.path.join(root, file)
new_image_path = os.path.join(output_subfolder, file)
shutil.copy(old_image_path, new_image_path)
elif extension.lower() == '.md':
file_path = os.path.join(root, file)
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
output_file_path = os.path.join(output_subfolder, file)
def replace_image_reference(match):
image_name = match.group(1)
if image_name in image_locations:
return '![[{}]]'.format(image_locations[image_name])
else:
return match.group(0)
content = re.sub(r'!\[\]\[(.*?)\]', replace_image_reference, content)
with open(output_file_path, 'w', encoding='utf-8') as output_file:
output_file.write(content)
exported_folder = '/path/to/your/scrivener/export/folder'
output_folder = '/path/to/your/obsidian/output/folder'
try:
convert_scrivener_to_obsidian(exported_folder, output_folder)
except Exception as e:
print(f"An error occurred: {e}")
Replace '/path/to/your/scrivener/export/folder' and '/path/to/your/obsidian/output/folder' with the actual directories on your machine where your Scrivener exported files are located and where you want your Obsidian files to be created respectively.
Librairies
This script requires the following Python libraries:
os: This is part of the Python Standard Library, so you don't need to install it.
re: This is also part of the Python Standard Library, so you don't need to install it.
shutil: Yet another part of the Python Standard Library, no need to install it.
BeautifulSoup: This is a third-party library used for parsing HTML and XML documents. It provides a few simple methods and Pythonic idioms for navigating, searching, and modifying a parse tree. However, please note that it's imported in your code but not actually used.
You can install BeautifulSoup with pip:
pip install beautifulsoup4
Remember to use the correct version of pip associated with your Python interpreter (e.g., pip3 for Python 3).
Backup your data
As for having a backup, it's a good practice to regularly back up your scripts and data. You could commit the code to a version control system such as git and push to a remote repository (e.g., GitHub, Bitbucket). You can also manually copy your scripts and data to a separate location, such as an external hard drive or a cloud storage service.
As a note, always make sure to test your code on a small, non-critical dataset before running it on more important data, to minimize the risk of accidental data loss.
And before running any script, it's good practice to ensure that you have a recent backup of your data.