Skip to main content

Overview

The ui.py module provides a Flask-based web interface for the video synchronization workflow. It includes a three-step wizard for uploading videos, previewing them, and viewing synchronized results.

Flask Application

app
Flask
Main Flask application instance.
app = Flask(__name__)

Application State

app_state
dict
Global state dictionary that tracks the synchronization workflow.Fields:
  • selected_files (list): List of selected video filenames
  • sync_progress (int): Current progress percentage (0-100)
  • sync_status (str): Current status message (“idle”, “Processing…”, etc.)
  • output_dir (str): Output directory path (defaults to config.OUTPUT_DIR)
  • current_step (int): Current wizard step (1, 2, or 3)
  • offsets (dict): Calculated time offsets for each video file
  • logs (deque): Ring buffer storing last 500 log messages
  • session_id (str): Unique session identifier
Example:
app_state = {
    "selected_files": [],
    "sync_progress": 0,
    "sync_status": "idle",
    "output_dir": config.OUTPUT_DIR,
    "current_step": 1,
    "offsets": {},
    "logs": deque(maxlen=500),
}

Logging

configure_logging

configure_logging
function
Sets up centralized logging to file, console, and UI.Configuration:
  • Log directory: logs/
  • Log file: logs/video_sync.log
  • File rotation: 10MB max size, 5 backup files
  • Format: %(asctime)s - %(name)s - %(levelname)s - %(message)s
Handlers:
  1. RotatingFileHandler: Writes to log file with rotation
  2. StreamHandler: Outputs to console
  3. UILogHandler: Captures logs for real-time UI display
Example:
from src.ui import configure_logging

configure_logging()
# Logging is now active for all modules

UILogHandler

UILogHandler
class
Custom logging handler that stores logs in app_state["logs"] for UI display.Inherits: logging.HandlerLog Entry Format:
{
    "timestamp": "2024-03-15 14:23:45,123",
    "level": "INFO",
    "message": "Processing started"
}
Storage: Logs are stored in a deque with max length 500

Routes

Step Routes

/
GET
Step 1: File SelectionRenders the file upload interface.Actions:
  • Resets app_state to initial values
  • Generates unique session ID
  • Sets current_step to 1
/step2
GET
Step 2: Video PreviewDisplays uploaded videos for review before synchronization.Redirects to: / if no files are selected
/step3
GET
Step 3: Synchronization ResultsShows progress during sync and displays results when complete.Redirects to: / if no files are selected

API Routes

/api/upload
POST
Handles file uploads from the client.Request: Multipart form data with files[] fieldValidation:
  • Minimum 2 files required
  • Allowed extensions: .mp4, .mov, .avi
  • Filenames are sanitized using secure_filename()
Response:
{
  "ok": true,
  "files": ["camera1.mp4", "camera2.mp4"]
}
/api/select
POST
Validates and selects video files for synchronization.Request Body:
{
  "files": ["camera1.mp4", "camera2.mp4"]
}
Validation:
  • Minimum 2 files required
  • All files must exist in VIDEO_DIR
Response:
{"ok": true}
/api/sync
GET
Initiates the synchronization process in a background thread.Process:
  1. Checks SYNC_METHOD configuration (“visual” or “audio”)
  2. Runs synchronization algorithm
  3. Generates sync indicators
  4. Applies offsets to videos
  5. Updates app_state progress throughout
Response:
{"ok": true}
/api/progress
GET
Returns current synchronization progress.Response:
{
  "progress": 65,
  "status": "Applying offsets to videos..."
}
/api/logs
GET
Returns recent log messages for UI display.Response:
{
  "ok": true,
  "logs": [
    {
      "timestamp": "2024-03-15 14:23:45,123 - sync - INFO - Processing started",
      "level": "INFO",
      "message": "Processing started"
    }
  ]
}
/api/logs/clear
POST
Clears the log buffer.Response:
{"ok": true}
/api/synced_files
GET
Returns list of synchronized video files.Response:
{
  "ok": true,
  "files": ["camera1_synced.mp4", "camera2_synced.mp4"]
}
/api/download_all
GET
Creates and downloads a ZIP file of all synchronized videos.Response: Binary ZIP file with MIME type application/zipFilename: synced_videos.zip

Video Serving Routes

/video/raw/<filename>
GET
Serves raw uploaded video files from VIDEO_DIR.
/video/synced/<filename>
GET
Serves synchronized video files from OUTPUT_DIR.

Main Function

run_app

run_app
function
Launches the Flask web UI.Configuration:
  • Host: 127.0.0.1 (localhost only)
  • Port: 5050
  • Debug: False
  • Threaded: True
Behavior:
  • Prints startup banner with URL
  • Automatically opens browser after 1 second
  • Runs in non-debug mode with threading enabled
Example:
from src.ui import run_app, configure_logging

configure_logging()
run_app()

UI Features

Sync Progress Tracking

The UI tracks progress through several stages:
ProgressStatus Message
0%“Initializing…“
5-10%“Initializing visual synchronization…” / “Extracting audio…“
40-55%“Analyzing audio offsets…” / “Motion analysis complete!“
58%“Generating visual sync indicators…“
65%“Applying offsets to videos…“
100%“Complete!”

Real-time Logging

The UI includes a real-time log viewer with:
  • Auto-scroll: Automatically scrolls to newest logs
  • Filtering: Filter by log level (All, INFO, WARNING, ERROR)
  • Ring buffer: Stores last 500 log messages
  • Polling: Updates every 500ms during processing

Video Playback Controls

  • Play/Pause: Toggle playback on all videos simultaneously
  • Mute/Unmute: Control audio for all videos
  • Restart: Reset all videos to beginning
  • Universal Seek Bar: Synchronized seeking across all videos

Build docs developers (and LLMs) love