Exclude course/item leaves from destination picker; ease new-folder UX
The destination picker (Sort Unsorted, Manage Library Move) was listing individual course/item folders as pickable destinations whenever they held content course detection doesn't recognize as video/audio - ebooks, audiobooks in unsupported formats, etc. Add a leaf-item check scoped to the picker's own category index so these no longer show up, without touching the shared course-detection heuristic used elsewhere (Library browsing, search, stats). Also replace "Create new folder"'s single free-text path field with a parent-folder picker plus a plain new-folder-name field and a live "Will create: X/Y" preview, so the resulting path is confirmed before applying instead of hand-typed blind. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+31
-5
@@ -1263,6 +1263,29 @@ def _tokenize_ordered(name: str) -> List[str]:
|
||||
return ordered
|
||||
|
||||
|
||||
def _is_unrecognized_leaf_item(directory: Path) -> bool:
|
||||
"""
|
||||
A folder with files directly inside but no subfolders at all -
|
||||
virtually always a single downloaded item (an ebook, an audiobook in a
|
||||
format this app doesn't play, or some other misc file drop) rather
|
||||
than an organizational category, even when _looks_like_course's
|
||||
video/audio check doesn't recognize it as a course (e.g. an EPUB-only
|
||||
folder has no media files at all, so _has_direct_media never fires).
|
||||
Scoped to _build_category_index only - not a general "is this a
|
||||
course" replacement, since this app still can't do anything useful
|
||||
with the file itself, so it'd be wrong to surface it as a course
|
||||
elsewhere (Library browsing, stats, search, ...).
|
||||
"""
|
||||
try:
|
||||
entries = list(directory.iterdir())
|
||||
except (PermissionError, OSError):
|
||||
return False
|
||||
has_subdir = any(e.is_dir() and not e.name.startswith('.') for e in entries)
|
||||
if has_subdir:
|
||||
return False
|
||||
return any(e.is_file() and not e.name.startswith('.') for e in entries)
|
||||
|
||||
|
||||
def _build_category_index() -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Every category/subcategory folder currently in the library (e.g. IT,
|
||||
@@ -1282,10 +1305,13 @@ def _build_category_index() -> List[Dict[str, Any]]:
|
||||
categories' course titles) can't outweigh a specific match
|
||||
elsewhere just by sharing more of it.
|
||||
Stops recursing into a folder once it reads as a course itself
|
||||
(_looks_like_course, the same rule the Library browser uses), so
|
||||
individual courses never show up as if they were categories to file
|
||||
things under. The Unsorted folder itself is excluded - it's the
|
||||
source, never a valid destination.
|
||||
(_looks_like_course, the same rule the Library browser uses) or as an
|
||||
unrecognized leaf item (_is_unrecognized_leaf_item - an ebook/
|
||||
audiobook/misc file that isn't video or audio, so _looks_like_course
|
||||
doesn't catch it either), so individual courses and standalone files
|
||||
never show up as if they were categories to file things under. The
|
||||
Unsorted folder itself is excluded - it's the source, never a valid
|
||||
destination.
|
||||
"""
|
||||
library_root = Path(get_library_root())
|
||||
try:
|
||||
@@ -1308,7 +1334,7 @@ def _build_category_index() -> List[Dict[str, Any]]:
|
||||
continue
|
||||
except OSError:
|
||||
pass
|
||||
if _looks_like_course(entry):
|
||||
if _looks_like_course(entry) or _is_unrecognized_leaf_item(entry):
|
||||
continue
|
||||
new_parts = path_parts + [entry.name]
|
||||
path_tokens: Set[str] = set()
|
||||
|
||||
Reference in New Issue
Block a user