chore: initialize homebrew-magic-rpg monorepo
Consolidates the HbM: RPG project (formerly the loose hbm-books working folder) into a single repo. ObsidianNotes, foundry-lore, and foundry-system are wired in as submodules pointing at their existing Gitea repos. Loose tooling scripts are organized under tools/, obsolete/one-off scripts (fix_vault.py, generate_mocs.py, debug-*.ts, write_file_helper.py) and _books/ (superseded by ObsidianNotes) are excluded via .gitignore rather than deleted. foundryvtt-admin is excluded pending its own separate repo.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
ROOT_DIR = Path(__file__).parent.parent
|
||||
VAULT_DIR = ROOT_DIR / "ObsidianNotes"
|
||||
OUTPUT_DIR = ROOT_DIR / "NotebookLM_Uploads"
|
||||
|
||||
# Folders to completely ignore
|
||||
IGNORE_FOLDERS = {".obsidian", "_assets", "_templates", "revisions", "tabletop-cards"}
|
||||
|
||||
# Thematic mapping: Which Obsidian folders go into which macro file
|
||||
THEME_MAP = {
|
||||
"01_System_Rules_and_Mechanics.txt": ["rules", "disciplines", "spells", "items", "races"],
|
||||
"02_World_Lore_and_NPCs.txt": ["concepts", "npcs", "organizations", "lore"],
|
||||
"03_Atlas_and_Locations.txt": ["locations"],
|
||||
"04_Campaigns_and_Characters.txt": ["classes", "player-characters", "conflicts"]
|
||||
}
|
||||
|
||||
# --- REGEX UTILITIES ---
|
||||
FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
|
||||
|
||||
def parse_md_file(file_path, relative_path):
|
||||
"""Reads a file, extracts YAML, cleans structure, and returns format text."""
|
||||
try:
|
||||
content = file_path.read_text(encoding="utf-8-sig")
|
||||
except Exception as e:
|
||||
return f"\n\n[ERROR READING FILE {relative_path}: {str(e)}]\n\n"
|
||||
|
||||
# Separate Frontmatter and Content
|
||||
frontmatter = ""
|
||||
match = FRONTMATTER_RE.match(content)
|
||||
if match:
|
||||
frontmatter = match.group(1).strip()
|
||||
body = content[match.end():].strip()
|
||||
else:
|
||||
body = content.strip()
|
||||
|
||||
# Format the file section so NotebookLM sees it as a discrete structured document
|
||||
builder = []
|
||||
builder.append("\n" + "="*80)
|
||||
builder.append(f"START_FILE: {relative_path}")
|
||||
builder.append(f"FILENAME: {file_path.name}")
|
||||
builder.append("="*80)
|
||||
|
||||
if frontmatter:
|
||||
builder.append("\n--- METADATA ---")
|
||||
builder.append(frontmatter)
|
||||
builder.append("----------------\n")
|
||||
|
||||
builder.append(body)
|
||||
builder.append(f"\nEND_FILE: {relative_path}\n")
|
||||
|
||||
return "\n".join(builder)
|
||||
|
||||
def main():
|
||||
if not VAULT_DIR.exists():
|
||||
print(f"[-] Error: Vault directory not found at {VAULT_DIR}")
|
||||
return
|
||||
|
||||
OUTPUT_DIR.mkdir(exist_ok=True)
|
||||
print(f"[+] Initializing vault compilation from: {VAULT_DIR}")
|
||||
|
||||
# Initialize empty text collectors for our themes
|
||||
compiled_data = {filename: [] for filename in THEME_MAP.keys()}
|
||||
|
||||
# Walk through the entire Obsidian Vault
|
||||
for root, dirs, files in os.walk(VAULT_DIR):
|
||||
# In-place filtering to skip ignored root directories
|
||||
dirs[:] = [d for d in dirs if d not in IGNORE_FOLDERS]
|
||||
|
||||
for file in files:
|
||||
if not file.endswith(".md"):
|
||||
continue
|
||||
|
||||
file_path = Path(root) / file
|
||||
# Calculate path relative to the Vault root (e.g., 'spells/academic/fire-magic/fireball.md')
|
||||
rel_path = file_path.relative_to(VAULT_DIR)
|
||||
root_parent_folder = rel_path.parts[0] # The first subfolder name
|
||||
|
||||
# Find which macro file this note belongs to based on its root parent folder
|
||||
target_macro = None
|
||||
for macro_file, monitored_folders in THEME_MAP.items():
|
||||
if root_parent_folder in monitored_folders:
|
||||
target_macro = macro_file
|
||||
break
|
||||
|
||||
# If it's a loose markdown file in the root vault or unmapped, default to Lore
|
||||
if not target_macro:
|
||||
target_macro = "02_World_Lore_and_NPCs.txt"
|
||||
|
||||
# Parse and append
|
||||
formatted_note = parse_md_file(file_path, rel_path)
|
||||
compiled_data[target_macro].append(formatted_note)
|
||||
|
||||
# Write the master compiled macro files
|
||||
for filename, pieces in compiled_data.items():
|
||||
if not pieces:
|
||||
print(f"[!] Target file {filename} is empty. Skipping output.")
|
||||
continue
|
||||
|
||||
out_path = OUTPUT_DIR / filename
|
||||
# Combine all files with clear division
|
||||
final_content = f"MASTER COMPILATION FOR CATEGORY: {filename}\n" + "\n".join(pieces)
|
||||
|
||||
out_path.write_text(final_content, encoding="utf-8")
|
||||
print(f"[+] Successfully wrote {len(pieces)} files to -> {out_path.name}")
|
||||
|
||||
print("\n[+] Done! Drag the contents of 'NotebookLM_Uploads' straight into NotebookLM.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user