Repository navigation
v0.13.5
Performance
- The folder-cleanup DB-reference scan no longer resolves
realpath(MUSIC_ROOT)once per Beets item.composite_workflows.norm_library_pathruns once per item during a full-library scan that repeats on every rename; on a ~5,000-folder live run that was arealpathsyscall storm that could make the run crawl or look hung. The root'srealpathis now resolved once per distinct MUSIC_ROOT string (functools.lru_cache) and reused. The normalization result is byte-for-byte identical; only the trusted root isrealpath-resolved, still never a caller path.
Fixed
-
A tracked album folder whose Beets DB path is a DANGLING symlink is now HELD (
needs_db_resync), not relocated into a loud partial move._album_db_paths_staleusedos.path.lexists, which reports a dangling symlink (link present, target gone) as present, so the relocation ran and Beets skipped every track (a rollback-ablepartial_move). It now usesos.path.exists, so a DB path with no real file behind it is treated as stale and held. Regression test:tests/test_folder_mbid_names_apply.py::TrackedRelocationTests::test_dangling_symlink_db_path_held_needs_db_resync. -
Renaming a Beets-TRACKED album folder to
Album (Year) {release-group-mbid}no longer fails withPATH_IS_TRACKEDwhen the DB and disk paths are desynced. The folder-MBID apply (_apply_folder_mbid_names) decided tracked-vs-disk-only from its own item-count map (_placeholder_folder_db), which keyed item paths with a rawos.path.dirname— no realpath rewrite and no relative-path resolution. On a symlinked/realpath-divergingMUSIC_ROOT(and after an earlier placeholder-strip left the DB naming the pre-rename path) that map reporteddb_item_count=0for a folder the engine still considered tracked, so the apply picked the disk-onlyfolder_renameand the engine's descendant-aware, realpath-aware DB-reference refusal (_library_refs_under) rejected it (folder_cleanup_rename_failed/PATH_IS_TRACKED). Both detectors now normalize through one sharedcomposite_workflows.norm_library_path, so a folder the engine treats as tracked is classified tracked by the apply and routed to the DB-aware relocation (relocate_album/ BeetsAlbum.move) — folder and DB item/album paths move together. When Beets names paths that are no longer on disk (the strip-desync), the album is HELD (needs_db_resync) rather than relocated off stale paths, so no file is lost and DB and disk never diverge. The existing holds (tracked_rgid_mismatch,tracked_multiple_albums,target_exists), disk-only renames, idempotentalready_correct, dry-run, the confirmed gate,batch_limit, resume and rollback-by-job are unchanged. Regression tests:tests/test_folder_mbid_names_apply.py::TrackedRelocationTests(realpath-desynced tracked relocation; stale-DBneeds_db_resynchold).