From 0b3a1b4d1a6fa782dc492aaa7a079a2e3650bb5b Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 11 Dec 2025 14:51:58 -0700 Subject: [PATCH] better time formatting and ETA --- ...press-png-sequences-with-multithreading.md | 310 ++++++++++++++++++ compress_pngs.py | 20 +- 2 files changed, 325 insertions(+), 5 deletions(-) diff --git a/.specstory/history/2025-12-11_18-21Z-compress-png-sequences-with-multithreading.md b/.specstory/history/2025-12-11_18-21Z-compress-png-sequences-with-multithreading.md index 6e948f9..7bf0e9b 100644 --- a/.specstory/history/2025-12-11_18-21Z-compress-png-sequences-with-multithreading.md +++ b/.specstory/history/2025-12-11_18-21Z-compress-png-sequences-with-multithreading.md @@ -2198,3 +2198,313 @@ The script now preserves 16-bit depth where possible and avoids unnecessary conv --- +_**User (2025-12-11 21:39Z)**_ + +It tells time elapsed, but can you have it estimate time remaining, too? + +--- + +_**Agent (model default, mode Agent)**_ + + + +--- + + +Checking the current ETA implementation and improving its visibility and formatting: + + +--- + + +
Tool use: **read_file** • Read file: compress_pngs.py + +
+
+ +--- + + + +--- + + + + + +--- + + +
Tool use: **read_file** • Read file: compress_pngs.py + +
+
+ +--- + + + +--- + + +Adding a time formatting function and improving ETA visibility and accuracy: + + +--- + + + +
Tool use: **search_replace** • Edit file: compress_pngs.py + +**Chunk 1** +Lines added: 16, lines removed: undefined + +```diff +@@ -131,4 +131,20 @@ + return f"{size_bytes:.2f} TB" + ++ def format_time(seconds): ++ """Format time in human readable format (e.g., '2m 30s' or '1h 15m').""" ++ if seconds < 60: ++ return f"{seconds:.0f}s" ++ elif seconds < 3600: ++ minutes = int(seconds // 60) ++ secs = int(seconds % 60) ++ return f"{minutes}m {secs}s" ++ else: ++ hours = int(seconds // 3600) ++ minutes = int((seconds % 3600) // 60) ++ if minutes > 0: ++ return f"{hours}h {minutes}m" ++ else: ++ return f"{hours}h" ++ + def main(): + input_dir = Path('input') +``` + +
+ +
+ +--- + + + +
Tool use: **search_replace** • Edit file: compress_pngs.py + +**Chunk 1** +Lines added: 6, lines removed: 4 + +```diff +@@ -217,15 +217,17 @@ + rate = processed / elapsed if elapsed > 0 else 0 + remaining = len(png_files) - processed +- eta = remaining / rate if rate > 0 else 0 ++ eta_seconds = remaining / rate if rate > 0 and remaining > 0 else 0 + + total_savings = total_original_size - total_new_size + total_savings_pct = (total_savings / total_original_size * 100) if total_original_size > 0 else 0 ++ ++ eta_str = format_time(eta_seconds) if eta_seconds > 0 else "calculating..." ++ elapsed_str = format_time(elapsed) + + print(f"[{processed:5d}/{len(png_files)}] " + f"Compressed: {compressed} | Skipped: {skipped} | " + f"Speed: {rate:.1f} files/sec | " +- f"ETA: {eta:.1f}s | " +- f"Saved: {format_size(total_savings)} ({total_savings_pct:.1f}%) | " +- f"Elapsed: {elapsed:.1f}s", end='\r') ++ f"Elapsed: {elapsed_str} | ETA: {eta_str} | " ++ f"Saved: {format_size(total_savings)} ({total_savings_pct:.1f}%)", end='\r') + last_update_time = current_time + else: +``` + +
+ +
+ +--- + + + +
Tool use: **search_replace** • Edit file: compress_pngs.py + +**Chunk 1** +Lines added: 1, lines removed: 1 + +```diff +@@ -248,5 +248,5 @@ + print(f"Ignored (JPG/JPEG): {len(jpg_files)} files") + print(f"Failed: {failed} files") +- print(f"Total time: {total_time:.2f} seconds") ++ print(f"Total time: {format_time(total_time)}") + print(f"Average speed: {avg_rate:.2f} files/second") + print(f"Original size: {format_size(total_original_size)}") +``` + +
+ +
+ +--- + + + +--- + + + + + +--- + + +
+ Tool use: **read_lints** • Read lints for 1 file + +Lint paths: + +- `compress_pngs.py` + +Lint results + + +**No lint errors found** +
+
+ +--- + + + +--- + + +Updated the script to show time remaining (ETA) more clearly: + +1. **Added a time formatting function** that converts seconds to readable format: + - Less than 60 seconds: "45s" + - Less than 1 hour: "2m 30s" + - 1 hour or more: "1h 15m" + +2. **Made ETA more prominent** in the progress output — it now appears right after elapsed time + +3. **Improved time display** — both elapsed time and total time in the summary are now formatted + +The progress line now shows something like: +``` +[ 1234/5000] Compressed: 1200 | Skipped: 34 | Speed: 45.2 files/sec | Elapsed: 27s | ETA: 1m 23s | Saved: 125.50 MB (15.2%) +``` + +ETA is calculated based on the current processing rate and updates as the rate changes. + +--- + +_**User (2025-12-11 21:39Z)**_ + +I'd rather the time format be (HH):MM:SS:MsMs + +--- + +_**Agent (model default, mode Agent)**_ + + + +--- + + +Updating the time formatting function to use HH:MM:SS:MsMs: + + +--- + + + +
Tool use: **search_replace** • Edit file: compress_pngs.py + +**Chunk 1** +Lines added: 6, lines removed: 14 + +```diff +@@ -132,18 +132,10 @@ + + def format_time(seconds): +- """Format time in human readable format (e.g., '2m 30s' or '1h 15m').""" +- if seconds < 60: +- return f"{seconds:.0f}s" +- elif seconds < 3600: +- minutes = int(seconds // 60) +- secs = int(seconds % 60) +- return f"{minutes}m {secs}s" +- else: +- hours = int(seconds // 3600) +- minutes = int((seconds % 3600) // 60) +- if minutes > 0: +- return f"{hours}h {minutes}m" +- else: +- return f"{hours}h" ++ """Format time as HH:MM:SS:MsMs (hours:minutes:seconds:centiseconds).""" ++ hours = int(seconds // 3600) ++ minutes = int((seconds % 3600) // 60) ++ secs = int(seconds % 60) ++ centiseconds = int((seconds % 1) * 100) ++ return f"{hours:02d}:{minutes:02d}:{secs:02d}:{centiseconds:02d}" + + def main(): +``` + +
+ +
+ +--- + + + +--- + + + + + +--- + + +
+ Tool use: **read_lints** • Read lints for 1 file + +Lint paths: + +- `compress_pngs.py` + +Lint results + + +**No lint errors found** +
+
+ +--- + + + +--- + + +Updated the time format to `HH:MM:SS:MsMs`. Times display as: +- **HH**: Hours (00-99, always 2 digits) +- **MM**: Minutes (00-59, always 2 digits) +- **SS**: Seconds (00-59, always 2 digits) +- **MsMs**: Centiseconds (00-99, always 2 digits, hundredths of a second) + +Examples: +- `00:00:45:23` (45 seconds and 23 centiseconds) +- `00:02:30:50` (2 minutes, 30 seconds, 50 centiseconds) +- `01:15:30:75` (1 hour, 15 minutes, 30 seconds, 75 centiseconds) + +This format is used for elapsed time, ETA, and total time in the summary. + +--- + diff --git a/compress_pngs.py b/compress_pngs.py index d1f6b97..233aa27 100644 --- a/compress_pngs.py +++ b/compress_pngs.py @@ -130,6 +130,14 @@ def format_size(size_bytes): size_bytes /= 1024.0 return f"{size_bytes:.2f} TB" +def format_time(seconds): + """Format time as HH:MM:SS:MsMs (hours:minutes:seconds:centiseconds).""" + hours = int(seconds // 3600) + minutes = int((seconds % 3600) // 60) + secs = int(seconds % 60) + centiseconds = int((seconds % 1) * 100) + return f"{hours:02d}:{minutes:02d}:{secs:02d}:{centiseconds:02d}" + def main(): input_dir = Path('input') output_dir = Path('output') @@ -200,17 +208,19 @@ def main(): if processed == 1 or time_since_update >= 0.5: rate = processed / elapsed if elapsed > 0 else 0 remaining = len(png_files) - processed - eta = remaining / rate if rate > 0 else 0 + eta_seconds = remaining / rate if rate > 0 and remaining > 0 else 0 total_savings = total_original_size - total_new_size total_savings_pct = (total_savings / total_original_size * 100) if total_original_size > 0 else 0 + eta_str = format_time(eta_seconds) if eta_seconds > 0 else "calculating..." + elapsed_str = format_time(elapsed) + print(f"[{processed:5d}/{len(png_files)}] " f"Compressed: {compressed} | Skipped: {skipped} | " f"Speed: {rate:.1f} files/sec | " - f"ETA: {eta:.1f}s | " - f"Saved: {format_size(total_savings)} ({total_savings_pct:.1f}%) | " - f"Elapsed: {elapsed:.1f}s", end='\r') + f"Elapsed: {elapsed_str} | ETA: {eta_str} | " + f"Saved: {format_size(total_savings)} ({total_savings_pct:.1f}%)", end='\r') last_update_time = current_time else: failed += 1 @@ -229,7 +239,7 @@ def main(): if jpg_files: print(f"Ignored (JPG/JPEG): {len(jpg_files)} files") print(f"Failed: {failed} files") - print(f"Total time: {total_time:.2f} seconds") + print(f"Total time: {format_time(total_time)}") print(f"Average speed: {avg_rate:.2f} files/second") print(f"Original size: {format_size(total_original_size)}") print(f"Compressed size: {format_size(total_new_size)}")