From 414fb78543cbd735dc3479f64a3adc3587a98261 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Mon, 10 Aug 2026 01:50:49 -0400 Subject: [PATCH] fix(videos): base convert % on elapsed/duration not file size File size ratio was wrong since output bitrate != input bitrate. Now uses ffprobe to get video duration, then elapsed/duration for %. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- modules/app_video.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/modules/app_video.py b/modules/app_video.py index e78d570..8419e87 100644 --- a/modules/app_video.py +++ b/modules/app_video.py @@ -36,12 +36,25 @@ def queue_convert(relative_path, force=False): with _converting_lock: if relative_path in _converting: return False - _converting[relative_path] = {"started_at": time.time(), "source_size": 0, "tmp_path": ""} + _converting[relative_path] = {"started_at": time.time(), "duration_s": 0, "tmp_path": ""} t = threading.Thread(target=_convert_bg, args=(relative_path,), daemon=True) t.start() return True +def _get_duration_s(path): + """Return video duration in seconds via ffprobe, or None on failure.""" + try: + result = subprocess.run( + ["ffprobe", "-v", "error", "-show_entries", "format=duration", + "-of", "default=noprint_wrappers=1:nokey=1", path], + capture_output=True, text=True, timeout=10, + ) + return float(result.stdout.strip()) + except Exception: + return None + + def _convert_bg(relative_path): try: source_path = _local_path(relative_path) @@ -53,10 +66,10 @@ def _convert_bg(relative_path): try: tmp_path = mp4_path + ".converting.mp4" - source_size = os.path.getsize(source_path) if os.path.exists(source_path) else 0 + duration_s = _get_duration_s(source_path) or 0 with _converting_lock: if relative_path in _converting: - _converting[relative_path]["source_size"] = source_size + _converting[relative_path]["duration_s"] = duration_s _converting[relative_path]["tmp_path"] = tmp_path cmd = [ "ffmpeg", "-nostdin", "-loglevel", "error", "-y", @@ -138,18 +151,11 @@ def list_local_videos(): convert_progress = None if converting and conv_info: elapsed = time.time() - conv_info["started_at"] - source_size = conv_info["source_size"] - tmp_path = conv_info["tmp_path"] - tmp_size = 0 - if tmp_path and os.path.exists(tmp_path): - try: - tmp_size = os.path.getsize(tmp_path) - except OSError: - pass - pct = round(tmp_size / source_size * 100) if source_size > 0 else 0 + duration_s = conv_info.get("duration_s", 0) + pct = min(round(elapsed / duration_s * 100), 99) if duration_s > 0 else 0 convert_progress = { "elapsed_s": int(elapsed), - "pct": min(pct, 99), # never show 100% until done + "pct": pct, } files.append( {