#!/usr/bin/env python3 """ Fast batch matching without AKAZE - uses original perceptual hash only """ import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent / "src")) from video_matcher.matcher import VideoMatcher from rich.console import Console from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn from datetime import datetime console = Console() if len(sys.argv) < 2: console.print("[red]Usage: python batch_match_fast.py [output.html][/red]") sys.exit(1) folder_path = Path(sys.argv[1]) output_file = sys.argv[2] if len(sys.argv) > 2 else None if not folder_path.exists(): console.print(f"[red]Folder not found: {folder_path}[/red]") sys.exit(1) # Find all video files VIDEO_EXTENSIONS = {'.mp4', '.mov', '.avi', '.mkv', '.webm', '.flv', '.wmv', '.m4v'} video_files = [] for ext in VIDEO_EXTENSIONS: video_files.extend(folder_path.glob(f"*{ext}")) video_files.extend(folder_path.glob(f"*{ext.upper()}")) if not video_files: console.print(f"[yellow]No video files found in {folder_path}[/yellow]") sys.exit(1) console.print(f"\n[bold]Found {len(video_files)} video file(s) to process[/bold]\n") # Initialize matcher WITHOUT AKAZE (faster) console.print("[cyan]Using fast mode (perceptual hash only)[/cyan]") matcher = VideoMatcher( use_akaze=False, # Disable AKAZE use_metadata_filter=True, # Keep metadata filtering enable_ai_vision=True # Keep AI Vision ) # Check if we have masters masters = matcher.list_masters() if not masters: console.print("[red]✗[/red] No master videos found in library.") console.print("Use 'python cli.py add-master' to add masters first.") sys.exit(1) console.print(f"[cyan]Comparing against {len(masters)} master(s)...[/cyan]\n") # Process each video results = [] with Progress( SpinnerColumn(), TextColumn("[progress.description]{task.description}"), BarColumn(), TextColumn("[progress.percentage]{task.percentage:>3.0f}%"), console=console ) as progress: task = progress.add_task("[cyan]Processing adaptations...", total=len(video_files)) for video_file in video_files: progress.update(task, description=f"[cyan]Processing {video_file.name}...") try: matches = matcher.match_adaptation(str(video_file)) results.append({ 'adaptation_name': video_file.name, 'adaptation_path': str(video_file), 'matches': matches, 'error': None }) except Exception as e: console.print(f"[red]✗[/red] Error processing {video_file.name}: {e}") results.append({ 'adaptation_name': video_file.name, 'adaptation_path': str(video_file), 'matches': [], 'error': str(e) }) progress.advance(task) # Generate output filename if not specified if output_file is None: timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') output_file = f"matching_report_fast_{timestamp}.html" output_path = Path(output_file) # Generate HTML report console.print(f"\n[cyan]Generating HTML report...[/cyan]") # Import the generation function from batch_match sys.path.insert(0, str(Path(__file__).parent)) from batch_match import generate_html_report generate_html_report(results, output_path, str(folder_path)) # Summary console.print(f"\n[bold green]✓ Report generated successfully![/bold green]") console.print(f"\n[bold]Summary:[/bold]") console.print(f" Total adaptations: {len(results)}") console.print(f" Matched: {sum(1 for r in results if r['matches'])}") console.print(f" No matches: {sum(1 for r in results if not r['matches'])}") console.print(f" Total master matches: {sum(len(r['matches']) for r in results)}") console.print(f"\n[bold cyan]📄 Report saved to:[/bold cyan] {output_path.absolute()}") console.print(f"\n[dim]Open in browser: file://{output_path.absolute()}[/dim]")