a4f8941fca
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.
74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
import os
|
|
import re
|
|
import json
|
|
|
|
VAULT_DIR = "ObsidianNotes"
|
|
|
|
def main():
|
|
if not os.path.exists(VAULT_DIR):
|
|
print(json.dumps({"error": f"Directory {VAULT_DIR} not found."}))
|
|
return
|
|
|
|
md_files = {} # filename (without .md) -> relative path
|
|
for root, dirs, files in os.walk(VAULT_DIR):
|
|
for file in files:
|
|
if file.endswith(".md"):
|
|
name = file[:-3]
|
|
rel_path = os.path.relpath(os.path.join(root, file), VAULT_DIR)
|
|
md_files[name] = rel_path
|
|
|
|
links = {} # source file rel_path -> list of target link names
|
|
broken_links = [] # list of (source file rel_path, broken link name)
|
|
incoming_links = {name: [] for name in md_files.keys()} # target name -> list of source file rel_paths
|
|
|
|
link_pattern = re.compile(r'\[\[(.*?)\]\]')
|
|
|
|
for name, rel_path in md_files.items():
|
|
full_path = os.path.join(VAULT_DIR, rel_path)
|
|
try:
|
|
with open(full_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
except Exception as e:
|
|
print(f"Error reading {rel_path}: {e}")
|
|
continue
|
|
|
|
file_links = link_pattern.findall(content)
|
|
parsed_links = []
|
|
for raw_link in file_links:
|
|
# Handle aliases [[Link|Alias]] and headings [[Link#Heading]]
|
|
base_link = raw_link.split('|')[0].split('#')[0].strip()
|
|
if not base_link:
|
|
continue
|
|
parsed_links.append(base_link)
|
|
|
|
# Check if it exists
|
|
link_basename = os.path.basename(base_link)
|
|
if link_basename.endswith('.md'):
|
|
link_basename = link_basename[:-3]
|
|
|
|
if link_basename in md_files:
|
|
incoming_links[link_basename].append(rel_path)
|
|
else:
|
|
broken_links.append((rel_path, base_link))
|
|
|
|
links[rel_path] = parsed_links
|
|
|
|
orphans = [rel_path for name, rel_path in md_files.items() if len(incoming_links[name]) == 0]
|
|
|
|
report = {
|
|
"total_files": len(md_files),
|
|
"total_links": sum(len(l) for l in links.values()),
|
|
"broken_links_count": len(broken_links),
|
|
"orphans_count": len(orphans),
|
|
"broken_links": broken_links,
|
|
"orphans": orphans
|
|
}
|
|
|
|
with open("vault_analysis_report.json", "w", encoding="utf-8") as f:
|
|
json.dump(report, f, indent=2)
|
|
|
|
print("Analysis complete. Check vault_analysis_report.json")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|