From 96fac71075b95367f0a2bd34c1a7d4e6be176ec4 Mon Sep 17 00:00:00 2001 From: trav Date: Sat, 10 Oct 2026 23:48:03 -0700 Subject: [PATCH] v0.50.0: exports report the finished folder's size --- lintunes/__init__.py | 2 +- lintunes/export/exporter.py | 14 ++++++++++++++ lintunes/gui/main_window.py | 10 +++++++--- tests/test_round81.py | 20 ++++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/lintunes/__init__.py b/lintunes/__init__.py index 0097ab3..8b8466a 100644 --- a/lintunes/__init__.py +++ b/lintunes/__init__.py @@ -1,3 +1,3 @@ """LinTunes — iTunes-style music library manager and player for Linux.""" -__version__ = "0.49.1" +__version__ = "0.50.0" diff --git a/lintunes/export/exporter.py b/lintunes/export/exporter.py index c071fe5..d8aecbc 100644 --- a/lintunes/export/exporter.py +++ b/lintunes/export/exporter.py @@ -235,6 +235,19 @@ def build_index_html(plan: ExportPlan, image_names) -> str: ) +def folder_size(path: Path) -> int: + """Bytes in every file under `path` — what the exported folder weighs, + conversions, page and images included.""" + total = 0 + for p in Path(path).rglob("*"): + try: + if p.is_file(): + total += p.stat().st_size + except OSError: + pass + return total + + class _Cancelled(Exception): """Internal: unwinds _run when cancel() was requested.""" @@ -352,6 +365,7 @@ class ExportWorker(QObject): "converted": converted, "skipped": len(plan.skipped), "vanished": len(vanished), + "bytes": folder_size(plan.dest_dir), }) except _Cancelled: if dest is not None: diff --git a/lintunes/gui/main_window.py b/lintunes/gui/main_window.py index 15e4baf..c672c67 100644 --- a/lintunes/gui/main_window.py +++ b/lintunes/gui/main_window.py @@ -1086,7 +1086,8 @@ class MainWindow(QMainWindow): self._web_progress.complete( web_progress.EXPORT, f"{summary['exported']} track" - f"{'s' if summary['exported'] != 1 else ''}") + f"{'s' if summary['exported'] != 1 else ''} · " + f"{device_sync.format_bytes(summary.get('bytes', 0))}") self._web_progress.begin(web_progress.UPLOAD, "Starting…") self._upload_worker = upload.UploadWorker( run["host"], run["plan"].dest_dir, run["rdir"], self) @@ -1124,7 +1125,8 @@ class MainWindow(QMainWindow): web_progress.UPLOAD, f"{sent} file{'s' if sent != 1 else ''} sent") summary = run.get("export", {}) - msg = (f"Uploaded “{summary.get('playlist', run['slug'])}” to " + msg = (f"Uploaded “{summary.get('playlist', run['slug'])}” " + f"({device_sync.format_bytes(summary.get('bytes', 0))}) to " f"{run['host']}:{run['rdir']}") extras = [] if summary.get("converted"): @@ -1268,7 +1270,9 @@ class MainWindow(QMainWindow): self._hide_sync_widgets() what = "web mix" if summary["kind"] == exporter.WEB else "folder" msg = (f"Exported “{summary['playlist']}” as a {what}: " - f"{summary['exported']} tracks → {summary['dest']}") + f"{summary['exported']} tracks, " + f"{device_sync.format_bytes(summary.get('bytes', 0))} → " + f"{summary['dest']}") if summary["converted"]: msg += f", {summary['converted']} converted to FLAC" if summary["skipped"]: diff --git a/tests/test_round81.py b/tests/test_round81.py index f5bdb39..e8f0e9e 100644 --- a/tests/test_round81.py +++ b/tests/test_round81.py @@ -545,3 +545,23 @@ def test_image_filters_see_uppercase_suffixes(): patterns = flt[flt.index("(") + 1:-1].split() for name in ("IMG_1897.JPG", "a.jpeg", "b.PNG", "c.WebP"[:-4] + "WEBP"): assert any(fnmatch.fnmatchcase(name, p) for p in patterns), name + + +def test_export_reports_the_folder_size(tmp_path): + plan = exporter.plan_export( + "Mix", [_track(1, _audio(tmp_path, "a.mp3"))], tmp_path / "out", + exporter.WEB) + done = [] + worker = exporter.ExportWorker(plan) + worker.finished.connect(done.append) + worker._run() + assert done[0]["bytes"] == exporter.folder_size(tmp_path / "out" / "Mix") + assert done[0]["bytes"] > 100 # the song plus page and assets + + +def test_upload_window_shows_the_size(qapp, window): + config.save_config({upload.HOST_KEY: HOST, upload.PATH_KEY: "/srv/mixes"}) + window._export_playlist("abcd1234") + _wait_for(qapp, lambda: _FakeUpload.runs) + from lintunes.gui import web_upload_progress as wp + assert "KB" in window._web_progress.status(wp.EXPORT)