understanding commited on
Commit
9660ed3
·
verified ·
1 Parent(s): 0acffa0

Update bot/core/progress.py

Browse files
Files changed (1) hide show
  1. bot/core/progress.py +84 -30
bot/core/progress.py CHANGED
@@ -1,38 +1,92 @@
1
- # PATH: bot/core/progress.py
 
 
 
 
2
  import time
 
 
 
3
 
4
  class SpeedETA:
5
- def __init__(self):
6
- self.t0 = time.time()
7
- self.last_t = self.t0
8
- self.last_bytes = 0
9
- self.total = 0
10
-
11
- def update(self, done_bytes: int, total_bytes: int) -> dict:
12
- now = time.time()
13
- self.total = total_bytes
14
- dt = max(1e-6, now - self.last_t)
15
- db = done_bytes - self.last_bytes
16
- speed = db / dt # bytes/sec
17
- remaining = max(0, total_bytes - done_bytes)
18
- eta = remaining / max(1e-6, speed)
19
- self.last_t = now
20
- self.last_bytes = done_bytes
21
- return {"done": done_bytes, "total": total_bytes, "speed_bps": speed, "eta_sec": eta}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  def human_bytes(n: float) -> str:
24
- units = ["B", "KB", "MB", "GB"]
25
- x = float(n)
26
- for u in units:
27
- if x < 1024 or u == units[-1]:
28
- return f"{x:.2f}{u}"
29
- x /= 1024
30
- return f"{x:.2f}GB"
31
-
32
- def human_eta(sec: float) -> str:
33
- s = int(max(0, sec))
 
 
 
 
 
 
 
 
 
 
 
 
34
  m, s = divmod(s, 60)
35
  h, m = divmod(m, 60)
36
- if h: return f"{h}h {m}m"
37
- if m: return f"{m}m {s}s"
 
 
38
  return f"{s}s"
 
1
+ # FILE: bot/core/progress.py
2
+ # NOTE: Updated so SpeedETA matches handlers.py (returns float speed, has eta_seconds)
3
+
4
+ from __future__ import annotations
5
+
6
  import time
7
+ from collections import deque
8
+ from typing import Deque, Optional, Tuple
9
+
10
 
11
  class SpeedETA:
12
+ """Tracks moving-average speed and ETA.
13
+
14
+ - update(sent, total) returns speed in bytes/sec (float)
15
+ - eta_seconds is an int or None
16
+ """
17
+
18
+ def __init__(self, window_seconds: float = 12.0) -> None:
19
+ self.window_seconds = float(window_seconds)
20
+ self.samples: Deque[Tuple[float, int]] = deque()
21
+ self.speed_bps: float = 0.0
22
+ self.eta_seconds: Optional[int] = None
23
+
24
+ def update(self, sent: int, total: int) -> float:
25
+ # Be defensive: sent/total can be weird types in callbacks
26
+ try:
27
+ s = int(sent)
28
+ except Exception:
29
+ s = 0
30
+ try:
31
+ t = int(total) if total else 0
32
+ except Exception:
33
+ t = 0
34
+
35
+ now = time.monotonic()
36
+ self.samples.append((now, s))
37
+
38
+ # keep only recent samples
39
+ while self.samples and (now - self.samples[0][0]) > self.window_seconds:
40
+ self.samples.popleft()
41
+
42
+ if len(self.samples) >= 2:
43
+ t0, b0 = self.samples[0]
44
+ t1, b1 = self.samples[-1]
45
+ dt = t1 - t0
46
+ db = b1 - b0
47
+ if dt > 0 and db >= 0:
48
+ self.speed_bps = db / dt
49
+ else:
50
+ self.speed_bps = 0.0
51
+ else:
52
+ self.speed_bps = 0.0
53
+
54
+ if t > 0 and self.speed_bps > 0:
55
+ remaining = max(0, t - s)
56
+ self.eta_seconds = int(remaining / self.speed_bps)
57
+ else:
58
+ self.eta_seconds = None
59
+
60
+ return self.speed_bps
61
+
62
 
63
  def human_bytes(n: float) -> str:
64
+ try:
65
+ n = float(n)
66
+ except Exception:
67
+ n = 0.0
68
+
69
+ units = ["B", "KB", "MB", "GB", "TB"]
70
+ i = 0
71
+ while n >= 1024 and i < len(units) - 1:
72
+ n /= 1024
73
+ i += 1
74
+ return f"{n:.2f}{units[i]}"
75
+
76
+
77
+ def human_eta(seconds: Optional[float]) -> str:
78
+ if seconds is None:
79
+ return "—"
80
+ try:
81
+ s = int(seconds)
82
+ except Exception:
83
+ return "—"
84
+ if s < 0:
85
+ s = 0
86
  m, s = divmod(s, 60)
87
  h, m = divmod(m, 60)
88
+ if h:
89
+ return f"{h}h {m}m"
90
+ if m:
91
+ return f"{m}m {s}s"
92
  return f"{s}s"