Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save thrasher/f07fb66db0dfdb77b93a94d02085274a to your computer and use it in GitHub Desktop.

Select an option

Save thrasher/f07fb66db0dfdb77b93a94d02085274a to your computer and use it in GitHub Desktop.
Export Google Docs to Obsidian Markdown, extracting inline images to attachments
import re
import base64
import argparse
import os
import sys
def export_images(md_file, update=False, folder=None):
if not os.path.exists(md_file):
print(f"Error: File '{md_file}' not found.")
return
# Determine target folder
if folder:
if not os.path.isdir(folder):
print(f"Error: The folder '{folder}' does not exist.")
print(f"To create it, run: mkdir -p \"{folder}\"")
sys.exit(1)
target_folder = folder
else:
target_folder = os.path.dirname(os.path.abspath(md_file))
try:
with open(md_file, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
print(f"Error reading file: {e}")
return
# Pattern to match [name]: <data:image/mimetype;base64,DATA>
pattern_def = r'^\[(?P<name>[^\]]+)\]:\s*<data:(?P<mimetype>[^;]+);base64,(?P<data>[^>]+)>'
defs = list(re.finditer(pattern_def, content, flags=re.MULTILINE))
if not defs:
print("No base64 images found matching the pattern.")
return
replacements = {}
exported_count = 0
for match in defs:
name = match.group('name')
mimetype = match.group('mimetype')
b64_data = match.group('data')
# Determine extension from mimetype (e.g., image/png -> .png)
extension = ""
if '/' in mimetype:
extension = "." + mimetype.split('/')[1]
filename = f"{name}{extension}"
file_path = os.path.join(target_folder, filename)
try:
image_data = base64.b64decode(b64_data)
with open(file_path, 'wb') as img_file:
img_file.write(image_data)
print(f"Exported: {file_path}")
exported_count += 1
# The reference in the markdown file
md_ref_path = os.path.join(folder, filename) if folder else filename
replacements[name] = f"![[{filename}]]"
except Exception as e:
print(f"Error exporting {name}: {e}")
if update and exported_count > 0:
# 1. Remove the definition lines
new_content = re.sub(pattern_def, "", content, flags=re.MULTILINE)
# 2. Replace the placeholders ![][name] with ![[filename]]
for name, update_str in replacements.items():
placeholder = f"![][{name}]"
new_content = new_content.replace(placeholder, update_str)
# Clean up possible trailing whitespace from removing lines
new_content = new_content.rstrip() + "\n"
try:
with open(md_file, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"Updated '{md_file}': moved image tags to their reference locations.")
except Exception as e:
print(f"Error writing to file: {e}")
print(f"Done. Extracted {exported_count} images.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Export base64 images from a Markdown file to an Obsidian-friendly format.")
parser.add_argument("file", help="The Markdown file to process.")
parser.add_argument("--update", action="store_true", help="Replace placeholders and remove base64 data.")
parser.add_argument("--folder", help="The folder to save images into. Defaults to the markdown file's location.")
if len(sys.argv) == 1:
parser.print_help()
print()
print("Example: python export_google_docs_to_obsidian_markdown.py --update --folder attachments markdown.md")
sys.exit(1)
args = parser.parse_args()
export_images(args.file, args.update, args.folder)
@thrasher

Copy link
Copy Markdown
Author

This script transforms Google Docs exported markdown with inline images for use with Obsidian.

From your Google Docs editor, choose the menus for File / Download / Markdown (.md) to export it in markdown format. Google Docs will inline all of the images with reference links that do not work in Obsidian. This exporter will extract those inline images as individual files in a directory and update the markdown file for use in Obsidian.

If you choose to use a folder to store attachments in Obsidian (which keeps your vaults cleaner), you will need to set the folder configuration within Obsidian. The menu navigation is Settings / Files and links / Subfolder name. I set mine to "attachments", but you do you.

Run with something like:

mkdir attachments
python export_google_docs_to_obsidian_markdown.py --update --folder attachments markdown.md

If you don't specify the --update flag, the images will be exported without modifying the markdown file.

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