#!/usr/bin/env python3 import os import re from collections import defaultdict from pathlib import Path import argparse # ---- args ---- parser = argparse.ArgumentParser() parser.add_argument("-v", "--vault", default=".", help="Path to Obsidian vault") parser.add_argument("-d", "--dict", default="Dictionary", help="Name of the dictionary directory") args = parser.parse_args() # ---- config ---- VAULT_DIR = Path(args.vault) DICT_DIR = VAULT_DIR / args.dict WORD_REGEX = re.compile(r"\b[a-zA-Z]{3,}\b") # ---- prep ---- DICT_DIR.mkdir(exist_ok=True) lemma_map = defaultdict(lambda: {"forms": set(), "files": set()}) # ---- stopwords ---- STOPWORDS = { os.path.basename(os.getcwd()), "author", "jpeg", "jpg", "post", "like", "likes", "repost", "avatar", "bsky", "media", "thumbnail", "thumnail", "http", "https", "com", "followers", "following", "unknown", "date", "social", "replier", "replie", "for", "you", "from", "to", "script", "grep", "localhost", "sudo", "not" } # ---- scan vault ---- for md_file in VAULT_DIR.rglob("*.md"): if DICT_DIR.name in md_file.parts: continue text = md_file.read_text(encoding="utf-8", errors="ignore").lower() words = WORD_REGEX.findall(text) for word in words: if word in STOPWORDS: continue lemma_map[word]["forms"].add(word) lemma_map[word]["files"].add(md_file) print(f"Found {len(lemma_map)} lemmas.") # ---- write dictionary ---- for lemma, data in lemma_map.items(): if len(data["files"]) < 2: continue file_path = DICT_DIR / f"{lemma}.md" with open(file_path, "w", encoding="utf-8") as f: f.write(f"# {lemma}\n\n---\n") f.write(f"lemma: {lemma}\n") f.write(f"forms: [{', '.join(sorted(data['forms']))}]\n---\n\n") f.write("## Forms\n") for form in sorted(data["forms"]): f.write(f"- {form}\n") f.write("\n## Found in\n") for md in sorted(data["files"]): rel_path = md.relative_to(VAULT_DIR) f.write(f"- [[{rel_path}]]\n") print(f"Dictionary generated in {DICT_DIR}")