#!/usr/bin/env python3 """ doocus tree indexer — replicate a local drive tree into docs-output/index.json. Walks a downloaded-drive root, preserving the full folder hierarchy. Locally extracts text for docx/pdf/pptx/xlsx (search-index sidecars, never a replacement for the original), flags videos as meetus meetings, and links everything else to the original without duplicating it. Deterministic and offline. uv run process_tree.py /mnt/drive # → docs-output/index.json uv run process_tree.py /mnt/drive --output out/docs uv run process_tree.py /mnt/drive --dry-run # counts only, no writes """ import argparse import logging import sys from doocus.tree import build_index def main() -> int: parser = argparse.ArgumentParser(description="Index a local drive tree for doocus.") parser.add_argument("source", help="Local drive-download root to index") parser.add_argument("--output", default="docs-output", help="Output directory for index.json + sidecars (default: docs-output)") parser.add_argument("--render", action="store_true", help="Render page/slide images where supported (needs extra deps)") parser.add_argument("--ocr", action="store_true", help="OCR scanned PDFs where supported") parser.add_argument("--dry-run", action="store_true", help="Walk and classify only; write nothing") parser.add_argument("--verbose", action="store_true", help="Verbose logging") args = parser.parse_args() logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO, format="%(message)s") try: index = build_index( args.source, args.output, options={"render": args.render, "ocr": args.ocr}, dry_run=args.dry_run, ) except NotADirectoryError as e: print(f"ERROR: {e}", file=sys.stderr) return 1 c = index["counts"] print(f"\n{c['total']} files: {c['extracted']} extracted, " f"{c['meeting']} meeting, {c['link']} linked" + (f", {c['warnings']} with warnings" if c.get("warnings") else "") + (" (dry run — nothing written)" if args.dry_run else "")) return 0 if __name__ == "__main__": sys.exit(main())