#!/usr/bin/env python3 import os import sys import json from pathlib import Path # Gibt das Verzeichnis zurück, in dem dieses Skript liegt def script_dir(): return Path(__file__).parent.resolve() # Lädt die JSONC-Konfiguration (Kommentare via // werden ignoriert) def load_config(filename="config.jsonc"): config_path = script_dir() / filename if not config_path.exists(): print(" ⚠ Konfigurationsdatei nicht gefunden:", config_path) sys.exit(1) with open(config_path, encoding="utf-8") as f: # Entfernt //-Kommentare vor dem Parsen return json.loads("".join(line for line in f if not line.strip().startswith("//"))) # Parsen der Kommandozeilenargumente def parse_args(): args = sys.argv[1:] parsed = { "scan": None, # Verzeichnisse zum Scannen (List[str]) "ignore": [], # Verzeichnisse, die ignoriert werden sollen (List[str]) "reset": False, # Setzt das Logfile zurück "hilfe": False, # Zeigt die Hilfe an } # Argumente durchgehen und zuweisen while args: arg = args.pop(0) if arg in ("-h", "--hilfe"): parsed["hilfe"] = True elif arg == "--reset": parsed["reset"] = True elif arg in ("-s", "--scan") and args: parsed["scan"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()] elif arg in ("-x", "--ignore") and args: parsed["ignore"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()] else: print(f" ⚠ Unbekannter Parameter: {arg}") parsed["hilfe"] = True break return parsed # Ausgabe der Hilfetexte für CLI-Nutzer def show_help(): print(""" (C) 2025 - Adam Skotarczak (ionivation.com) 🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link. Verwendung: python3 link_collector.py [OPTIONEN] -s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad) -x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen --reset Löscht das Logfile 'processed.log' und beendet sich -h, --hilfe Zeigt diese Hilfe Beispiel: python3 link_collector.py -s docs,notes -x "docs/alt" """) # Generator: Findet Markdown-Dateien (rekursiv), ignoriert dabei definierte Pfade def find_md_files(root_dirs, ignore_dirs, extensions): for root in root_dirs: for dirpath, _, filenames in os.walk(root): # Ignorierpfade überspringen if any(str(Path(dirpath)).startswith(str(ignored)) for ignored in ignore_dirs): continue for fname in filenames: if any(fname.endswith(ext) for ext in extensions): yield Path(dirpath) / fname # Extrahiert den ersten Markdown-Titel (# ...) als Linktext def extract_title(filepath): try: with open(filepath, encoding="utf-8") as f: for line in f: if line.strip().startswith("#"): return line.strip("# ").strip() except Exception as e: print(f"⚠ Fehler beim Lesen von {filepath}: {e}") # Fallback: Dateiname ohne Endung return filepath.stem # Liest bereits verarbeitete Dateien aus dem Log (Pfadangaben im POSIX-Format) def load_processed(logfile): if not logfile.exists(): return set() with open(logfile, encoding="utf-8") as f: # Vereinheitlichung auf POSIX-Konvention return set(Path(line.strip()).as_posix() for line in f) # Hängt neue Markdown-Links ans Output-Dokument an def append_to_output(output_path, links): with open(output_path, "a", encoding="utf-8") as f: for line in links: f.write(line + "\n") # Ergänzt das Logfile um neu verarbeitete Dateien (POSIX-Format) def update_processed(log_path, new_paths): with open(log_path, "a", encoding="utf-8") as f: for path in new_paths: f.write(path.as_posix() + "\n") # Hauptfunktion mit gesamtem Ablauf def main(): config = load_config() args = parse_args() if args["hilfe"]: show_help() return log_path = script_dir() / config.get("processed_log", "processed.log") # Optionaler Reset des Logs if args["reset"]: if log_path.exists(): log_path.unlink() print("🧹 Logfile gelöscht:", log_path) else: print("ℹ Logfile existierte nicht:", log_path) return cwd = Path.cwd() output_file = cwd / config.get("output_file", "output.md") # Verzeichnisse aus CLI oder Konfiguration root_dirs = args["scan"] or config.get("root_dirs", []) root_dirs = [Path(d).resolve() for d in root_dirs if d.strip()] ignore_dirs = [Path(x).resolve() for x in args["ignore"]] extensions = config.get("extensions", [".md"]) processed = load_processed(log_path) new_links = [] new_processed = [] # Dateien durchsuchen und neue Markdown-Dateien verlinken for md_file in find_md_files(root_dirs, ignore_dirs, extensions): if md_file.resolve() == output_file.resolve(): continue # nicht sich selbst verlinken rel_path = md_file.relative_to(cwd) rel_path_posix = rel_path.as_posix() if rel_path_posix in processed: continue # bereits im Logfile title = extract_title(md_file) new_links.append(f"- [{title}]({rel_path_posix})") new_processed.append(rel_path) # Ergebnisse schreiben if new_links: append_to_output(output_file, new_links) update_processed(log_path, new_processed) print(f"✔ {len(new_links)} neue Links hinzugefügt.") else: print(" ℹ Keine neuen Dateien gefunden.") if __name__ == "__main__": main()