From 1ea22d8b55045140379749ddcc369b3a9abcc9f3 Mon Sep 17 00:00:00 2001 From: Steffen Schuhmann Date: Sun, 29 Mar 2026 15:47:10 +0200 Subject: [PATCH] fix: each file in a dated session folder becomes its own song MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files directly in YYMMDD/ (e.g. 231015/take1.wav, 231015/take2.wav) all shared the same nc_folder_path, so take2 was silently merged as a new version of the take1 song instead of being a separate recording. Fix: when a file's parent == the session folder, append the file stem to make a unique virtual nc_folder_path per file. Files in subfolders (e.g. 231015/groove/take1.wav) are unaffected — they still group by folder. Applied in both nc_scan.py (manual scan) and internal.py (watcher uploads). Co-Authored-By: Claude Sonnet 4.6 --- api/src/rehearsalhub/routers/internal.py | 8 +++++++- api/src/rehearsalhub/services/nc_scan.py | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/api/src/rehearsalhub/routers/internal.py b/api/src/rehearsalhub/routers/internal.py index 63c099e..7755c66 100644 --- a/api/src/rehearsalhub/routers/internal.py +++ b/api/src/rehearsalhub/routers/internal.py @@ -13,7 +13,7 @@ from rehearsalhub.repositories.band import BandRepository from rehearsalhub.repositories.rehearsal_session import RehearsalSessionRepository from rehearsalhub.repositories.song import SongRepository from rehearsalhub.schemas.audio_version import AudioVersionCreate -from rehearsalhub.services.session import parse_rehearsal_date +from rehearsalhub.services.session import extract_session_folder, parse_rehearsal_date from rehearsalhub.services.song import SongService log = logging.getLogger(__name__) @@ -72,6 +72,12 @@ async def nc_upload( nc_folder = parent.rstrip("/") + "/" title = Path(path).stem + # If the file sits directly inside a dated session folder, give it a unique + # virtual folder so it becomes its own song (not merged with other takes). + session_folder_path = extract_session_folder(path) + if session_folder_path and session_folder_path.rstrip("/") == nc_folder.rstrip("/"): + nc_folder = nc_folder + title + "/" + version_repo = AudioVersionRepository(session) if event.nc_file_etag and await version_repo.get_by_etag(event.nc_file_etag): return {"status": "skipped", "reason": "version already registered"} diff --git a/api/src/rehearsalhub/services/nc_scan.py b/api/src/rehearsalhub/services/nc_scan.py index d06358e..4183345 100644 --- a/api/src/rehearsalhub/services/nc_scan.py +++ b/api/src/rehearsalhub/services/nc_scan.py @@ -120,6 +120,13 @@ async def scan_band_folder( song_folder = str(Path(nc_file_path).parent).rstrip("/") + "/" song_title = Path(nc_file_path).stem + # If the file sits directly inside a dated session folder (YYMMDD/file.wav), + # give it a unique virtual folder so each file becomes its own song rather + # than being merged as a new version of the first file in that folder. + session_folder_path = extract_session_folder(nc_file_path) + if session_folder_path and session_folder_path.rstrip("/") == song_folder.rstrip("/"): + song_folder = song_folder + song_title + "/" + yield {"type": "progress", "message": f"Checking {Path(nc_file_path).name}…"} # Fetch file metadata (etag + size) — one PROPFIND per file