#!/usr/bin/env python3 """ Simple web demo interface for Video Processor. This provides a basic Flask web interface to demonstrate video processing capabilities in a browser-friendly format. """ import asyncio import os import tempfile from pathlib import Path try: from flask import Flask, jsonify, render_template_string, request except ImportError: print("Flask not installed. Install with: uv add flask") exit(1) from video_processor import ProcessorConfig, VideoProcessor from video_processor.tasks import setup_procrastinate from video_processor.tasks.compat import get_version_info # Simple HTML template HTML_TEMPLATE = """ Video Processor Demo

🎬 Video Processor Demo

System Information:
Version: {{ version_info.version }}
Procrastinate: {{ version_info.procrastinate_version }}
Features: {{ version_info.features }}

Test Video Processing

Processing Logs

Ready...
""" app = Flask(__name__) async def create_test_video(output_dir: Path) -> Path: """Create a simple test video for processing.""" import subprocess video_file = output_dir / "web_demo_test.mp4" cmd = [ "ffmpeg", "-y", "-f", "lavfi", "-i", "testsrc=duration=5:size=320x240:rate=15", "-c:v", "libx264", "-preset", "ultrafast", "-crf", "30", str(video_file), ] try: result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: raise RuntimeError(f"FFmpeg failed: {result.stderr}") return video_file except FileNotFoundError: raise RuntimeError("FFmpeg not found. Please install FFmpeg.") @app.route("/") def index(): """Serve the demo web interface.""" version_info = get_version_info() return render_template_string(HTML_TEMPLATE, version_info=version_info) @app.route("/api/info") def api_info(): """Get system information.""" return jsonify(get_version_info()) @app.route("/api/process-test", methods=["POST"]) def api_process_test(): """Process a test video synchronously.""" try: with tempfile.TemporaryDirectory() as temp_dir: temp_path = Path(temp_dir) # Create test video test_video = asyncio.run(create_test_video(temp_path)) # Configure processor for fast processing config = ProcessorConfig( output_dir=temp_path / "outputs", output_formats=["mp4"], quality_preset="ultrafast", generate_thumbnails=True, generate_sprites=False, # Skip sprites for faster demo enable_360_processing=False, # Skip 360 for faster demo ) # Process video processor = VideoProcessor(config) result = processor.process_video(test_video) return jsonify( { "status": "success", "video_id": result.video_id, "encoded_files": len(result.encoded_files), "thumbnails": len(result.thumbnails), "processing_time": "< 30s (estimated)", "message": "Test video processed successfully!", } ) except Exception as e: return jsonify({"error": str(e)}), 500 @app.route("/api/async-job", methods=["POST"]) def api_async_job(): """Submit an async processing job.""" try: database_url = os.environ.get( "PROCRASTINATE_DATABASE_URL", "postgresql://video_user:video_password@postgres:5432/video_processor", ) # Set up Procrastinate app_context = setup_procrastinate(database_url) # In a real application, you would: # 1. Accept file uploads # 2. Store them temporarily # 3. Submit processing jobs # 4. Return job IDs for status tracking # For demo, we'll just simulate job submission job_id = f"demo-job-{os.urandom(4).hex()}" return jsonify( { "status": "submitted", "job_id": job_id, "queue": "video_processing", "message": "Job submitted to background worker", "note": "In production, this would submit a real Procrastinate job", } ) except Exception as e: return jsonify({"error": str(e)}), 500 def main(): """Run the web demo server.""" port = int(os.environ.get("PORT", 8080)) debug = os.environ.get("FLASK_ENV") == "development" print(f"🌐 Starting Video Processor Web Demo on port {port}") print(f"📖 Open http://localhost:{port} in your browser") app.run(host="0.0.0.0", port=port, debug=debug) if __name__ == "__main__": main()