Created
March 21, 2026 15:03
-
-
Save thrasher/f07fb66db0dfdb77b93a94d02085274a to your computer and use it in GitHub Desktop.
Export Google Docs to Obsidian Markdown, extracting inline images to attachments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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:
If you don't specify the --update flag, the images will be exported without modifying the markdown file.