diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py index 75dcb8e3..ada54b5b 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py @@ -144,13 +144,43 @@ class command: ] = current_time return + # Pattern 1a2: Curl classic progress format (percentage without % symbol) + # Extract percentage from curl's classic format + curl_classic_match = re.search( + r"^\s*(\d+)\s+\d+[kMGT]?\s+(\d+)\s+\d+[kMGT]?\s+\d+\s+\d+\s+\d+[kMGT]?\s+\d+\s+\d+:\d+:\d+\s+\d+:\d+:\d+\s+\d+:\d+:\d+\s+\d+[kMGT]?\s*$", text + ) + if curl_classic_match: + # Use the first percentage (total progress) + percentage = float(curl_classic_match.group(1)) + if 0 <= percentage <= 100: + self.env["runtime"]["DebugManager"].write_debug_out( + "found curl classic percentage: " + str(percentage), + debug.DebugLevel.INFO, + ) + if ( + percentage + != self.env["commandBuffer"]["lastProgressValue"] + ): + self.env["runtime"]["DebugManager"].write_debug_out( + "Playing tone for curl: " + str(percentage), + debug.DebugLevel.INFO, + ) + self.play_progress_tone(percentage) + self.env["commandBuffer"][ + "lastProgressValue" + ] = percentage + self.env["commandBuffer"][ + "lastProgressTime" + ] = current_time + return + # Pattern 1b: Time/token activity (not percentage-based, so use single # beep) time_match = re.search(r"(?:(?:remaining|elapsed|left|ETA|eta)[:;\s]*(\d+)s|(\d+)s\s+(?:remaining|elapsed|left))", text, re.IGNORECASE) token_match = re.search(r"(?:processing|generating|used|consumed)\s+(\d+)\s+tokens", text, re.IGNORECASE) # Pattern 1c: dd command output (bytes copied with transfer rate) dd_match = re.search(r"\d+\s+bytes.*copied.*\d+\s+s.*[kMGT]?B/s", text) - # Pattern 1d: Curl-style transfer data (bytes, speed indicators) + # Pattern 1d: Curl-style transfer data (bytes, speed indicators - legacy) curl_match = re.search( r"(\d+\s+\d+\s+\d+\s+\d+.*?(?:k|M|G)?.*?--:--:--|Speed)", text ) @@ -285,9 +315,21 @@ class command: self.play_quiet_tone(800, 0.08) def play_quiet_tone(self, frequency, duration): - """Play a quiet tone using Sox directly""" + """Play a quiet tone using Sox directly with flood protection""" import shlex import subprocess + import time + + # Flood protection: prevent beeps closer than 0.1 seconds apart + current_time = time.time() + if not hasattr(self, '_last_beep_time'): + self._last_beep_time = 0 + + if current_time - self._last_beep_time < 0.1: + # Skip this beep to prevent audio crackling on low-resource systems + return + + self._last_beep_time = current_time # Build the Sox command: play -qn synth tri gain # -8 diff --git a/src/fenrirscreenreader/fenrirVersion.py b/src/fenrirscreenreader/fenrirVersion.py index a35af8df..f7054342 100644 --- a/src/fenrirscreenreader/fenrirVersion.py +++ b/src/fenrirscreenreader/fenrirVersion.py @@ -4,6 +4,6 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributors. -version = "2025.08.20" +version = "2025.08.21" codeName = "testing" code_name = "testing"