With SFTP remotes rclone lists the tree while transferring, so the
`Transferred:` total grows during the run: the first ticks showed a
single file's percentage (e.g. 2.9 MiB / 8.6 MiB, 35%) which then
collapsed to 0% once the real 113 GiB total appeared. That is what
looked like "progress per album".
- pass --check-first: rclone finishes the remote listing before any
transfer starts, so the byte total is final and the gauge is a true
overall percentage for the whole mirror
- while scanning, no bytes move yet, so the panel now shows
`Scanning remote · 11,810 items listed` and `0 B / 113 GiB to transfer`
(parsed from rclone's `Checks: … Listed N`) instead of a bogus 0% bar
- once transfers start the display switches back to percentage +
bytes + current file
Verified against the real storagebox remote (capped with
RCLONE_MAX_TRANSFER): scan ticks show listed counts climbing to 11,810
with the pending total, then transfers show `9.984 MiB / 113.477 GiB`
with the final denominator and no per-file percentage jumps.
Bump to 0.3.2.
parse_rclone_stats still accepted rclone's `Transferring:` entries
(`* a.bin: 25% / 60 MiB, 0 B/s, -`) because they contain " / " and "%".
rclone writes them right after the byte-weighted line on every tick, and
since the last per-file entry is glued to the *next* tick's byte line,
the parsed order per second is: good byte line -> per-file 0% -> (one
second later) glued byte line. The gauge therefore displayed 0% almost
continuously and only ever looked right at the end.
Require a real stats body to start with the transferred byte amount.
Per-file lines now only feed the "current file" display (they already
did, as a fallback) and can no longer touch pct/done/total.
Verified with the real engine + rclone (bwlimit): mirror state now goes
0 -> 25 -> 50 -> 75 -> 100 with proper byte counts. The replay test now
asserts the exact parse sequence [10%, 40%] so a regression fails when a
per-file or file-count line sneaks in as 0%.
Bump to 0.3.1.
Dashboard:
- DEVICE card: storage is now a compact "276.2 GiB free · 40%" value plus a
usage bar on its own row (only when it cannot collide with the text) — the
old "total · free" value was truncated mid-number; gauge labels no longer
set an explicit fg so ratatui's colour swap keeps them readable over both
filled and empty bar cells
- LIBRARY card: paths are marked ✓/✗ (missing dirs are a common failure) and
long values are ellipsized instead of hard-clipped; absolute local
storagebox sources get the same check
- SYNC STATUS: device names adapt to the card width, statuses go time-only on
narrow cards, and the summary footer is two compact lines (no trailing "…")
- responsive: sidebar 28/34 cols, compact labels for narrow cards, short
terminal drops the decorative SYNC PATH card (it previously lost its only
content row and rendered empty)
Sync tab:
- hero "READY TO SYNC" panel for the selected device (name, firmware, mount
state, key hint, last sync) instead of a mostly empty LAST SYNC card
- after a run finishes, keep the step timeline visible with final statuses and
a LAST RUN result banner, plus an "s run again" hint (previously the steps
were discarded and only a summary line remained)
- steps connected as a timeline
Chrome:
- shared panel/firmware/chip/arrow/key-hint helpers in components; softer
panel borders (theme::BORDER) and a softer sidebar selection highlight
- title bar reduced to one row and now shows mirror on/off + ready/syncing
instead of the truncated config path
- logs header shows warning/error counts; cards use one consistent style
Bump to 0.3.0.
Real `rclone sync --progress --stats 1s` output piped (non-TTY) contains
two traps that made the mirror gauge show no progress:
- after the byte-weighted `Transferred: 8 MiB / 80 MiB, 10%, …` line,
rclone prints a unit-less file-count summary `Transferred: 0 / 6, 0%`
on every tick; the parser accepted it and reset done/total/pct to 0
immediately after each real update
- rclone does not newline-terminate the last `Transferring:` entry, so
the next stats line arrives glued to a per-file line
(` * file: 51% / 8 MiB, … -Transferred: 32 MiB / 80 MiB, 40%, …`),
which parsed as garbage with pct 0 (after the first tick the only byte
lines arrive this way)
parse_rclone_stats now takes the text after the last `Transferred:`
marker and requires byte units, so the count summary and glued variants
are handled. Per-file lines are parsed into the mirror's "current file"
display, and progress-block noise (Checks/Elapsed/Transferring/count
summary) is consumed instead of spamming the log every second.
Tests: replay of captured multi-tick rclone blocks (keeps 40%, never 0%),
glued-line and summary rejection cases, plus a TestBackend render test
asserting the mirror gauge, bytes and current file appear on the Sync tab.
Engine / safety:
- verify mount points against /proc/self/mountinfo instead of path
existence; refuse to sync into a leftover (unmounted) directory that
would otherwise receive the library on the root filesystem
- resolve udisks block devices by label when the path is not mounted,
and never let findmnt fall back to the containing root filesystem
- abort now SIGTERMs the whole child process group (sh -c/podkit and
rsync children included), escalating to SIGKILL after 2s
- quitting while a sync runs aborts and waits for the engine instead of
orphaning the child
- atomically mark the engine busy before spawning to prevent double
syncs; persist state before publishing completion
- don't follow symlinked directories while scanning (recursion loops)
- prune empty directories recursively when removing stale files
UI:
- help overlay was clipped (hardcoded height): size it from content
- speed/ETA were pushed onto a line the progress panel clipped; show
them right-aligned on the bytes row
- leaving log follow with u/d now scrolls from the bottom instead of
jumping to the top of the log
- reload config with r (label updated), refresh mounts on completion so
last-sync ages are current
- fix width underflows on narrow terminals; terminal-aware sidebar
scrolling
Tests: mountinfo unescape, process-group abort, and a TestBackend render
smoke test covering all tabs, small terminals and the help overlay.
--stats-one-line is carriage-return-rewritten when stdout/stderr are
piped (non-TTY), so the cloud->local mirror step showed no progress and
jumped straight to 100% at the end. --progress emits newline-terminated
Transferred: stats that stream live; also strip the 'Transferred:' label
from the done column in parse_rclone_stats.
- New SYNC STATUS card on the dashboard: every device with its last sync
result (✓ ok / ✗ error / — never) + ages, and an ok/error/never/last summary
- Sidebar: the sync spinner is now bright cyan on unselected (dark) rows and
dark on the selected (accent) row, so it's visible in both states
- m key toggles mount/unmount of the selected device via udisksctl
(resolves the block device from mount point or lsblk label)
- rsync-style device sync auto-mounts the target first
- mlove finalize unmounts via udisksctl, falling back to sudo -n umount
- keybar/help/README updated
- New Firmware::Sony mapped from firmware = "sony"; behaves like
rockbox/android (rsync to mounted volume, no fatsort)
- Green badge on dashboard; config parsing test included
- Real config: Sony NW-A55 + Walkman WM1 switched to firmware = "sony"
- Remove the separate Config tab (3 tabs now); each player's settings
(content type, mount point, music folder, fat order, sync command) are shown
in a PLAYER SETTINGS card on the dashboard
- Show mounted storage on the device card: total/free space (statvfs) plus a
usage gauge
- Add library + sync-pipeline cards and full-width SYNC PATH chain
- Update keybar/help/README for 3 tabs
- Use rsync --info=progress2 + --out-format=%n for device sync so the gauge
shows byte-weighted overall progress instead of per-completed-file jumps
- Fix oscillation: starting a new file no longer resets the bar to 0% (set_current_file
only updates the filename, never the percentage)
- Mirror step: per-file byte segments only update speed/ETA, not the overall pct
- Parse rsync live per-file byte progress (\r segments without xfr#) so the
progress bar advances continuously during large file transfers instead of
only per completed file; also stops logging those lines as noise
- Update the active step detail during scan/remove/copy phases
- smooth_pct helper combines completed files + current file's byte fraction
- unit tests for byte-progress parsing and smooth_pct
Full rewrite of dap-sync as a Rust TUI on ratatui:
- Tokyo Night theme, gradient title rule, rounded panels
- Devices sidebar with live mount status + last-sync age
- Dashboard / Sync / Logs / Config tabs
- Live sync engine: rclone mirror, NFC-aware diff, rsync
progress parsing, podkit + mlove (fatsort) finalize
- Abort-safe subprocess handling, persisted sync state