import os import json """ This was written almost entirely by Google Gemini 2.5 (apps and code) on 18 Sept. 2025 Google Takeout is accessible from the browser when logged in to your Google account. It can be set up to export dozens of different types of data. Here we only export "Keep" data. After running this, move the generated file to expoweb/handbook/troggle and git add/commit/push Philip Sargent """ # --- CONFIGURATION --- # šŸ“Œ IMPORTANT: Replace this with the actual path to your Google Keep Takeout folder. TAKEOUT_DIRECTORY = 'Takeout/Keep' # Example for Linux/macOS # def process_keep_files_to_dict(directory_path): """ Scans a directory for Google Keep JSON files, filters for a specific label, prints the content, and returns the data as a list of dictionaries. Args: directory_path (str): The path to the folder containing the JSON files. Returns: list: A list of dictionaries, where each dictionary represents a note. """ print(f"šŸ“ Processing files in: {directory_path}\n") # This list will store the dictionary for each matching note extracted_notes = [] if not os.path.isdir(directory_path): print(f"āŒ Error: Directory not found at '{directory_path}'.") print("Please update the TAKEOUT_DIRECTORY variable with the correct path.") return extracted_notes # Iterate over every file in the specified directory for filename in os.listdir(directory_path): if filename.endswith('.json'): file_path = os.path.join(directory_path, filename) try: with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) # --- Label Check --- has_expo_label = False if 'labels' in data: if any(label.get('name', '').lower() == 'expo' for label in data['labels']): has_expo_label = True if not has_expo_label: continue # Skip this file # --- Data Extraction & Storage --- # Create a dictionary to hold the current note's data current_note = { 'title': data.get('title') or 'Untitled Note', 'source_file': filename, 'content_type': None, 'color': data.get('color', 'DEFAULT'), 'content': None } # As before, print to the console for immediate feedback print("-" * 40) print(f"āœ… Title: {current_note['title']}") # Handle text notes if 'textContent' in data: content = data['textContent'] current_note['content_type'] = 'text' current_note['content'] = content print(content) # Handle list notes elif 'listContent' in data: current_note['content_type'] = 'list' list_items = [] checked_items = [] # print("Tasks:") for item in data['listContent']: # Create a clean dictionary for the list item item_data = { 'text': item.get('text', ''), 'is_checked': item.get('isChecked', False) } list_items.append(item_data) if item_data['is_checked']: checked_items.append(item_data) # Print the list item to the console status = 'x' if item_data['is_checked'] else ' ' # print(f" [{status}] {item_data['text']}") print(f"Tasks: {len(list_items)} of which {len(checked_items)} are done.") current_note['content'] = list_items # Add the completed dictionary for this note to our main list extracted_notes.append(current_note) # print("-" * 40 + "\n") except Exception as e: print(f"ā—ļø An unexpected error occurred with file {filename}: {e}") if not extracted_notes: print("No notes with the 'EXPO' label were found in the directory.") return extracted_notes import html from datetime import datetime def write_html_output(notes_data, filename="keep_export.html"): """ Generates an HTML file from the extracted Keep notes data. Args: notes_data (list): A list of note dictionaries. filename (str): The name of the output HTML file. """ # These are the standard Google Keep colors. color_map = { "DEFAULT": "#ffffff", "RED": "#f28b82", "ORANGE": "#fbbc04", "YELLOW": "#fff475", "GREEN": "#ccff90", "TEAL": "#a7ffeb", "BLUE": "#cbf0f8", "DARK_BLUE": "#aecbfa", "PURPLE": "#d7aefb", "PINK": "#fdcfe8", "BROWN": "#e6c9a8", "GRAY": "#e8eaed", } # --- HTML Head and CSS Styling --- # The CSS is embedded directly in the HTML file for simplicity. html_head = f""" Google Keep Export """ # --- HTML Body Generation --- html_body_content = "" for note in notes_data: # Sanitize title to prevent HTML injection issues title = html.escape(note['title']) # Start building the content for this specific note note_content_html = "" # MODIFICATION 2: Get the color and apply it as an inline style note_color_name = note.get('color', 'DEFAULT') # Safely get the color from the map, falling back to the default white bg_color = color_map.get(note_color_name, color_map['DEFAULT']) # Handle text notes if note['content_type'] == 'text': # Sanitize text content and replace newlines with
tags text = html.escape(note['content']) note_content_html = f'

{text}

' # Handle list notes elif note['content_type'] == 'list': unchecked_items = [] checked_items = [] for item in note['content']: # Sanitize list item text item_text = html.escape(item['text']) if item['is_checked']: checked_items.append( f'
  • {item_text}
  • ' ) else: unchecked_items.append( f'
  • {item_text}
  • ' ) # Combine unchecked items note_content_html += '' # Add checked items inside a collapsible
    element if checked_items: item_count = len(checked_items) plural_s = 's' if item_count > 1 else '' note_content_html += f"""
    {item_count} completed item{plural_s}
    """ # Combine title and content into a single note card html_body_content += f"""

    {title}

    {note_content_html}
    """ # --- Final HTML Assembly --- full_html = f""" {html_head}

    Troggle coding and design to-do lists

    (Exported from Philip Sargent's Google Keep notes on {datetime.now().strftime('%Y-%m-%d %H:%M')})

    Contact Philip if you wish to share these lists on your Google Keep account.

    {html_body_content}
    """ # --- Writing to File --- try: with open(filename, 'w', encoding='utf-8') as f: f.write(full_html) print(f"\nšŸŽ‰ Successfully wrote {len(notes_data)} notes to '{filename}'") except Exception as e: print(f"ā—ļø An error occurred while writing the file: {e}") # --- Run the program --- if __name__ == "__main__": all_notes_data = process_keep_files_to_dict(TAKEOUT_DIRECTORY) if all_notes_data: print("\n" + "="*50) print("šŸŽ‰ Successfully processed all matching files.") print(f"Total notes extracted: {len(all_notes_data)}") # print("Data has been stored in the 'all_notes_data' variable.") print("="*50) write_html_output(all_notes_data)