3d09174c16
Closes H4 and the remaining formatter half of H2. - New @shared/format.ts is the single home for fmtBytes/fmtSpeed/fmtEta, imported by both main and renderer. main/lib/formatters.ts re-exports them. - DownloadProgress now carries raw speedBytesPerSec/etaSeconds instead of pre-formatted speed/eta strings. main's parseProgress emits the raw numbers. - The renderer stores the raw numbers on DownloadItem; QueueItem formats them for per-item display, and summarizeQueue sums/maxes them directly. The lossy string->number->string round-trip in queueStats (parseSpeed / parseEtaSeconds / a local formatSpeed / formatEta) is deleted, along with a duplicate fmtEta in store/downloads.ts. - Per-item and aggregate speed now use the same 1024-based scale; the aggregate previously used a 1000-based formatter (a latent inconsistency). Tests updated for the raw-number contract (parseProgress, summarizeQueue). typecheck + 248 tests + eslint + prettier green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.3 KiB
TypeScript
35 lines
1.3 KiB
TypeScript
// Pure display formatters shared by main and renderer. Kept in @shared (not a
|
|
// main- or renderer-only lib) so byte/speed/ETA formatting has ONE definition on
|
|
// both sides of the IPC boundary — the renderer no longer re-parses formatted
|
|
// strings back into numbers to aggregate them (H2/H4).
|
|
|
|
/** Format a byte count as a binary-scaled size, e.g. 1048576 → '1.0 MB'. */
|
|
export function fmtBytes(bytes: number): string {
|
|
if (bytes < 1024) return `${bytes} B`
|
|
const units = ['KB', 'MB', 'GB', 'TB']
|
|
let v = bytes / 1024
|
|
let i = 0
|
|
while (v >= 1024 && i < units.length - 1) {
|
|
v /= 1024
|
|
i++
|
|
}
|
|
return `${v.toFixed(v >= 100 ? 0 : 1)} ${units[i]}`
|
|
}
|
|
|
|
/** Format a transfer rate, e.g. 4928307 → '4.7 MB/s'. Undefined for no rate. */
|
|
export function fmtSpeed(bytesPerSec?: number): string | undefined {
|
|
if (bytesPerSec == null) return undefined
|
|
return `${fmtBytes(bytesPerSec)}/s`
|
|
}
|
|
|
|
/** Format a duration in seconds as M:SS or H:MM:SS. Undefined for no value. */
|
|
export function fmtEta(seconds?: number): string | undefined {
|
|
if (seconds == null) return undefined
|
|
const s = Math.max(0, Math.round(seconds))
|
|
const h = Math.floor(s / 3600)
|
|
const m = Math.floor((s % 3600) / 60)
|
|
const r = s % 60
|
|
if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(r).padStart(2, '0')}`
|
|
return `${m}:${String(r).padStart(2, '0')}`
|
|
}
|