From 270da185432210cd66a32eaf4c6e4150c52f5635 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 31 Jul 2026 08:42:59 +0200 Subject: [PATCH] fix: emit download_progress events during direct stream downloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When _try_direct_stream() succeeded, it streamed chunks directly via requests.get() without firing any progress events. This caused the WebSocket frontend to only see 'started' (0%) and 'completed' (100%) — no incremental updates. Add per-chunk progress events to _try_direct_stream that mirror yt-dlp's hook format (downloaded_bytes, total_bytes, speed, eta, status), emitted at ~1% intervals. These flow through the existing download_progress handler chain (SeriesApp → anime_service → progress_service → WebSocket → frontend). --- src/server/providers/aniworld_provider.py | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/server/providers/aniworld_provider.py b/src/server/providers/aniworld_provider.py index 9e23884..0946d0b 100644 --- a/src/server/providers/aniworld_provider.py +++ b/src/server/providers/aniworld_provider.py @@ -5,6 +5,7 @@ import logging import os import re import shutil +import time import threading from pathlib import Path from urllib.parse import quote @@ -383,6 +384,12 @@ class AniworldLoader(Loader): "Direct stream download starting (type=%s)", content_type ) + total_size = int(response.headers.get( + "Content-Length", 0 + )) + received = 0 + last_emit = 0 + start_time = time.monotonic() with open(output_path, "wb") as fh: for chunk in response.iter_content(chunk_size=1024 * 1024): if self._cancel_flag.is_set(): @@ -391,7 +398,33 @@ class AniworldLoader(Loader): ) return False if chunk: + received += len(chunk) fh.write(chunk) + # Emit progress events at ~1% intervals + if total_size > 0: + pct = (received / total_size) * 100 + if pct - last_emit >= 1.0 or received == total_size: + elapsed = time.monotonic() - start_time + speed_bps = ( + received / elapsed + if elapsed > 0 else 0 + ) + eta = ( + int((total_size - received) / speed_bps) + if speed_bps > 0 else None + ) + self.events.download_progress({ + "downloaded_bytes": received, + "total_bytes": total_size, + "speed": speed_bps, + "eta": eta, + "status": ( + "finished" + if received >= total_size + else "downloading" + ), + }) + last_emit = pct return True except requests.RequestException as exc: logger.warning("Direct stream download failed: %s", exc)