A library whose media cannot be reached has its rows swept away #231

Closed
opened 2026-09-16 01:13:38 +02:00 by Claude · 1 comment
Collaborator

A library whose media cannot be reached at scan time sweeps its rows away.

Shape

crates/ephyra-server/src/libraries.rs:492-497 sweeps with whatever the walk kept. A walk that listed nothing — an unmounted CIFS share, a disconnected disk, a permissions change — keeps nothing, so the removal takes the library's rows. The rows come back on the next scan once the mount is back, with new ids: played state, favourites, collections and playlists that named them do not.

This is pre-existing. #216 widened it to the rows a title owns (stack parts and alternate versions) by reaching them through their owner.

The shape of the fix

Guard the sweep on the walk having succeeded: a library whose root could not be listed, or that produced no files where it previously had many, is skipped rather than emptied. Check what upstream does first — its scan treats a missing path as an error rather than an empty directory.

Verifying

A scan test over a tree that is removed between two passes, asserting the rows survive the second.

Found reviewing #216.

A library whose media cannot be reached at scan time sweeps its rows away. ## Shape `crates/ephyra-server/src/libraries.rs:492-497` sweeps with whatever the walk kept. A walk that listed nothing — an unmounted CIFS share, a disconnected disk, a permissions change — keeps nothing, so the removal takes the library's rows. The rows come back on the next scan once the mount is back, with new ids: played state, favourites, collections and playlists that named them do not. This is pre-existing. #216 widened it to the rows a title owns (stack parts and alternate versions) by reaching them through their owner. ## The shape of the fix Guard the sweep on the walk having succeeded: a library whose root could not be listed, or that produced no files where it previously had many, is skipped rather than emptied. Check what upstream does first — its scan treats a missing path as an error rather than an empty directory. ## Verifying A scan test over a tree that is removed between two passes, asserting the rows survive the second. Found reviewing #216.
Author
Collaborator

Fixed, and landed on main at 94f7a924.

A library whose root cannot be listed, or that lists nothing, keeps its rows: it is left out of what the pass swept, so the removal never scopes to it, and the libraries beside it still scan.

This is upstream's own rule, not a guard invented here. Folder.IsLibraryFolderAccessible skips a top-level library wholesale when DirectoryService.IsAccessible is false, before a single child is added or removed, and that check is "does listing this path yield anything" — with a missing directory, an unreadable one and a genuinely empty one all swallowed to the same empty answer.

The guard is scoped to the library root. A library that still lists files loses the row whose file went, which the test's third pass asserts.

Two tests: rows survive a root that vanishes between passes, and a library that cannot be listed stops no other library from scanning.

Fixed, and landed on `main` at `94f7a924`. A library whose root cannot be listed, or that lists nothing, keeps its rows: it is left out of what the pass swept, so the removal never scopes to it, and the libraries beside it still scan. This is upstream's own rule, not a guard invented here. `Folder.IsLibraryFolderAccessible` skips a top-level library wholesale when `DirectoryService.IsAccessible` is false, before a single child is added or removed, and that check is "does listing this path yield anything" — with a missing directory, an unreadable one and a genuinely empty one all swallowed to the same empty answer. The guard is scoped to the library root. A library that still lists files loses the row whose file went, which the test's third pass asserts. Two tests: rows survive a root that vanishes between passes, and a library that cannot be listed stops no other library from scanning.
Sign in to join this conversation.
No description provided.