from app.db import get_db from pathlib import Path def get_tenant_row(db, tenant): cur = db.cursor() cur.execute( "SELECT id, storage_root FROM tenants WHERE slug = %s LIMIT 1", (tenant,) ) row = cur.fetchone() if not row: return None return row def get_device_row(db, device_id): cur = db.cursor() cur.execute( "SELECT id, device_name, relative_path FROM devices WHERE id = %s LIMIT 1", (device_id,) ) row = cur.fetchone() if not row: return None return row def resolve_source_relative_path(storage_root, device_relative_path, input_filename): base = Path(storage_root) / device_relative_path if not base.exists(): raise FileNotFoundError(f"Device base path not found: {base}") candidates = [] for p in base.rglob("*"): if not p.is_file(): continue name = p.name if name == input_filename or name.endswith("__" + input_filename): candidates.append(p) if not candidates: raise FileNotFoundError( f"Could not locate source file for {input_filename} under {base}" ) candidates.sort(key=lambda p: p.stat().st_mtime, reverse=True) chosen = candidates[0] rel = chosen.relative_to(Path(storage_root)) return str(rel) def create_video_job(tenant, device_id, input_filename, profile="default"): db = get_db() tenant_row = get_tenant_row(db, tenant) if not tenant_row: raise Exception(f"Tenant not found: {tenant}") device_row = get_device_row(db, device_id) if not device_row: raise Exception(f"Device not found: {device_id}") tenant_id = tenant_row["id"] storage_root = tenant_row["storage_root"] device_relative_path = device_row["relative_path"] source_relative_path = resolve_source_relative_path( storage_root, device_relative_path, input_filename ) cur = db.cursor() cur.execute( """ INSERT INTO video_jobs ( tenant_id, device_id, source_file_id, source_relative_path, source_original_filename, requested_profile, requested_gpu_preference, status, progress_percent ) VALUES (%s, %s, NULL, %s, %s, %s, 'auto', 'queued', 0) """, (tenant_id, device_id, source_relative_path, input_filename, profile) ) db.commit() return cur.lastrowid def list_jobs_for_tenant(tenant): db = get_db() tenant_row = get_tenant_row(db, tenant) if not tenant_row: return [] tenant_id = tenant_row["id"] cur = db.cursor() cur.execute( """ SELECT id, device_id, source_original_filename, requested_profile, status, progress_percent, assigned_processor, output_relative_path, error_message, created_at, started_at, completed_at FROM video_jobs WHERE tenant_id = %s ORDER BY id DESC LIMIT 100 """, (tenant_id,) ) rows = cur.fetchall() out = [] for r in rows: out.append({ "id": r["id"], "device_id": r["device_id"], "filename": r["source_original_filename"], "profile": r["requested_profile"], "status": r["status"], "progress_percent": r["progress_percent"], "assigned_processor": r["assigned_processor"], "output_relative_path": r["output_relative_path"], "error_message": r["error_message"], "created_at": str(r["created_at"]) if r["created_at"] is not None else None, "started_at": str(r["started_at"]) if r["started_at"] is not None else None, "completed_at": str(r["completed_at"]) if r["completed_at"] is not None else None, }) return out