* fix(images): background jobs skip files hidden by the removal mark; walkers skip trash folders inside output roots (#501) - Thumbnail jobs and the legacy scan_output_dir listing leave library-removed files out (one mark check, mark_hides). - Missing-file links also forgets removal marks that hide nothing any more (file gone from a folder that exists, or changed), only under a readable, non-empty source, re-checked at apply. - The sidebar Images, Favorites and Needs review counts and the collection counts are read again when an image_delete job ends. - utils/media_folders.py: one skip for thumbnails and trash folders (.Trash, .Trash-<uid>, .Trashes, $RECYCLE.BIN) used by every walker, the image monitor and the delete review. * test(browser): wait for the answers two specs raced in the merge queue (#501) - System diagnostics "level filter": wait for each level's own log answer, and poll the shown levels; the CRITICAL line is in the previous level's answer too, so it proved nothing (firefox). - Library editor "restored storage after a confirmed save": wait for the PATCH answer, which waits for a whole restore in the test's route, instead of the 5 s expect default (webkit).
32 lines
1.2 KiB
Python
32 lines
1.2 KiB
Python
"""The folders no media walker lists below an output root (#501).
|
|
|
|
``thumbnails`` holds PromptManager's own previews. A trash folder that sits
|
|
inside an output root (``D:\\$RECYCLE.BIN`` when ``D:\\`` is a root,
|
|
``.Trash-1000`` at a mount point, ``.Trashes`` on a macOS volume) holds files
|
|
the user threw away: they are not outputs, so they are never listed, scanned,
|
|
linked, tagged or previewed. Every walker asks these predicates instead of
|
|
testing names itself; only folders *below* a root are tested.
|
|
"""
|
|
|
|
TRASH_FOLDER_NAMES = frozenset({".trash", ".trashes", "$recycle.bin"})
|
|
PREVIEW_FOLDER = "thumbnails"
|
|
|
|
|
|
def is_trash_folder(name: str) -> bool:
|
|
"""A trash folder name, in any case: ``.Trash``, ``.Trash-<uid>``,
|
|
``.Trashes`` or ``$RECYCLE.BIN``."""
|
|
folded = name.casefold()
|
|
if folded in TRASH_FOLDER_NAMES:
|
|
return True
|
|
return folded.startswith(".trash-") and folded[7:].isdigit()
|
|
|
|
|
|
def is_skipped_folder(name: str) -> bool:
|
|
"""A folder no walker descends: ``thumbnails`` (exact) or a trash folder."""
|
|
return name == PREVIEW_FOLDER or is_trash_folder(name)
|
|
|
|
|
|
def in_skipped_folder(parts) -> bool:
|
|
"""Whether any of the folder names *parts* is skipped."""
|
|
return any(is_skipped_folder(part) for part in parts)
|