Major Features: - 🖥️ Standalone desktop app (VideoMatcher.app) - double-click to run - 🎨 Black & gold branded UI (Montserrat font, #FFC407 accent) - 📁 Local file browser for master/adaptation folders - ⚡ Fast mode processing (10-20x faster, disables AKAZE/AI Vision) - 🤖 Smart AI Vision fallback (auto-retry when no matches found) - 📊 Real-time progress bars (fingerprinting & matching) - 💾 Local processing (no cloud, no authentication) - 📤 CSV export with master filenames Web Application (Enterprise): - 🌐 Flask web app with Azure AD authentication - 📦 Box.com integration for cloud storage - 🐳 Docker support for deployment - 🔐 JWT validation with httpOnly cookies - 🎯 REST API endpoints Enhancements: - Fixed master filename lookup (was showing "Unknown") - Automatic fingerprint recovery (detects missing files) - Improved CSV format (master file next to adaptation) - Port conflict handling (auto-finds available port) - Environment variable fixes for standalone mode Documentation: - Updated README with standalone app section - Added 10+ guide documents (UI improvements, fingerprint recovery, etc.) - Build instructions with PyInstaller - Comprehensive troubleshooting guide Technical: - PyInstaller build configuration (video_matcher.spec) - Launcher with environment setup (launcher.py) - Mock authentication for standalone mode - Video matcher service layer - Metadata parser and AKAZE video matching 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
90 lines
3.5 KiB
Python
90 lines
3.5 KiB
Python
"""
|
|
Configuration module for Video Master Detection web application.
|
|
Handles environment-based configuration for development and production.
|
|
"""
|
|
|
|
import os
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
|
|
class Config:
|
|
"""Configuration class for Flask application."""
|
|
|
|
# Flask Core Settings
|
|
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key-change-in-production')
|
|
|
|
# Azure AD Authentication (SAME as reference app)
|
|
AZURE_TENANT_ID = os.environ.get('AZURE_TENANT_ID', 'e519c2e6-bc6d-4fdf-8d9c-923c2f002385')
|
|
AZURE_CLIENT_ID = os.environ.get('AZURE_CLIENT_ID', '9079054c-9620-4757-a256-23413042f1ef')
|
|
|
|
# Box.com Configuration
|
|
BOX_CONFIG_PATH = os.environ.get('BOX_CONFIG_PATH', 'config/box_config.json')
|
|
BOX_ROOT_FOLDER_ID = os.environ.get('BOX_ROOT_FOLDER_ID', '') # To be provided
|
|
|
|
# Video Processing Settings
|
|
VIDEO_TEMP_DIR = os.environ.get('VIDEO_TEMP_DIR', 'tmp/video_downloads')
|
|
MAX_VIDEOS_PER_JOB = int(os.environ.get('MAX_VIDEOS_PER_JOB', '20'))
|
|
|
|
# File Size Limits (in bytes)
|
|
MAX_FILE_SIZE = int(os.environ.get('MAX_FILE_SIZE', str(2 * 1024 * 1024 * 1024))) # 2GB per file
|
|
MAX_JOB_SIZE = int(os.environ.get('MAX_JOB_SIZE', str(10 * 1024 * 1024 * 1024))) # 10GB total per job
|
|
WARNING_FILE_SIZE = int(os.environ.get('WARNING_FILE_SIZE', str(500 * 1024 * 1024))) # 500MB warning threshold
|
|
MIN_DISK_SPACE_GB = int(os.environ.get('MIN_DISK_SPACE_GB', '10')) # Minimum 10GB free space required
|
|
|
|
# Video Format Settings
|
|
ALLOWED_FORMATS = ['.mp4', '.webm', '.m4v'] # Recommended formats
|
|
WARNING_FORMATS = ['.mov', '.avi', '.mkv'] # Large format warning
|
|
BLOCKED_FORMATS = ['.mxf', '.ari', '.r3d', '.dpx'] # Raw/uncompressed formats blocked
|
|
|
|
# Cleanup Settings
|
|
CLEANUP_AGE_HOURS = int(os.environ.get('CLEANUP_AGE_HOURS', '24')) # Delete temp files older than 24 hours
|
|
AUTO_CLEANUP = os.environ.get('AUTO_CLEANUP', 'true').lower() == 'true' # Automatic cleanup after jobs
|
|
|
|
# Video Matcher Settings
|
|
DATA_DIR = os.environ.get('DATA_DIR', 'data')
|
|
ENABLE_AI_VISION = os.environ.get('ENABLE_AI_VISION', 'true').lower() == 'true'
|
|
ENABLE_AKAZE = os.environ.get('ENABLE_AKAZE', 'true').lower() == 'true'
|
|
ENABLE_METADATA_FILTER = os.environ.get('ENABLE_METADATA_FILTER', 'true').lower() == 'true'
|
|
|
|
# OpenAI Configuration (for AI Vision matching)
|
|
OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', '')
|
|
|
|
# Server Configuration
|
|
HOST = os.environ.get('HOST', '0.0.0.0')
|
|
PORT = int(os.environ.get('PORT', '5000'))
|
|
|
|
# Logging Configuration
|
|
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')
|
|
ACCESS_LOG = os.environ.get('ACCESS_LOG', 'logs/access.log')
|
|
ERROR_LOG = os.environ.get('ERROR_LOG', 'logs/error.log')
|
|
|
|
# Flask Environment
|
|
FLASK_ENV = os.environ.get('FLASK_ENV', 'development')
|
|
DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
|
|
|
|
|
|
class DevelopmentConfig(Config):
|
|
"""Development-specific configuration."""
|
|
DEBUG = True
|
|
PORT = 7183 # Match reference app port for consistency
|
|
|
|
|
|
class ProductionConfig(Config):
|
|
"""Production-specific configuration."""
|
|
DEBUG = False
|
|
|
|
# Ensure critical settings are set in production
|
|
def __init__(self):
|
|
super().__init__()
|
|
if self.SECRET_KEY == 'dev-secret-key-change-in-production':
|
|
raise ValueError('SECRET_KEY must be set in production environment')
|
|
|
|
|
|
# Configuration dictionary
|
|
config = {
|
|
'development': DevelopmentConfig,
|
|
'production': ProductionConfig,
|
|
'default': Config
|
|
}
|