Fix endless Filmotéka hardlink churn and show pool/output paths in the status bar
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
||||
"""Auto-generated — do not edit manually."""
|
||||
__version__ = "1.8.0"
|
||||
__version__ = "1.9.0"
|
||||
|
||||
@@ -478,15 +478,27 @@ class HardlinkManager:
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
# Every link the tag tree *should* contain, given current files+tags.
|
||||
expected_all: set[Path] = set()
|
||||
# Every link the tag tree *should* contain, mapped to the inode(s) it may
|
||||
# point at. A path can be wanted by more than one movie (same rendered
|
||||
# name in the same folder), so the value is a *set* of valid inodes.
|
||||
# Matching by inode too — not just the path — is what catches an **orphan
|
||||
# that squats the expected name**: a link whose name is right but which
|
||||
# points to an old inode (movie re-imported/replaced) is still obsolete,
|
||||
# while the correctly re-created link (forced to a ``_1`` suffix because
|
||||
# the orphan holds the base name) is *not* wrongly swept.
|
||||
expected: dict[Path, set[int]] = {}
|
||||
for file_obj in files:
|
||||
try:
|
||||
file_inode = file_obj.file_path.stat().st_ino
|
||||
except OSError:
|
||||
continue
|
||||
for tag in file_obj.tags:
|
||||
target_dir = self._target_dir(tag, roots, category_transforms)
|
||||
if target_dir is None:
|
||||
continue
|
||||
expected_all.add(target_dir / self._link_name(
|
||||
file_obj, tag, category_filename_templates))
|
||||
path = target_dir / self._link_name(
|
||||
file_obj, tag, category_filename_templates)
|
||||
expected.setdefault(path, set()).add(file_inode)
|
||||
|
||||
# Scan only the tag-tree's own top-level folders (skip copy-as-is mirrors).
|
||||
# Inside them, any file that isn't an expected link is obsolete — whether
|
||||
@@ -503,13 +515,18 @@ class HardlinkManager:
|
||||
for link_file in top.rglob("*"):
|
||||
if not link_file.is_file():
|
||||
continue
|
||||
if link_file in expected_all:
|
||||
continue
|
||||
try:
|
||||
source = inode_to_file[link_file.stat().st_ino].file_path
|
||||
except (OSError, KeyError):
|
||||
source = link_file # orphan (no current pool movie)
|
||||
obsolete.append((link_file, source))
|
||||
link_inode = link_file.stat().st_ino
|
||||
except OSError:
|
||||
continue
|
||||
# Valid only when both the path *and* the inode match a current
|
||||
# movie; a name-only match (orphan squatting the name) is stale.
|
||||
if link_inode in expected.get(link_file, ()):
|
||||
continue
|
||||
source = inode_to_file.get(link_inode)
|
||||
obsolete.append(
|
||||
(link_file, source.file_path if source else link_file)
|
||||
)
|
||||
|
||||
return obsolete
|
||||
|
||||
|
||||
+9
-4
@@ -579,6 +579,12 @@ class QtApp(QMainWindow):
|
||||
|
||||
def _build_statusbar(self) -> None:
|
||||
self.status = self.statusBar()
|
||||
# Pool / Filmotéka paths as permanent widgets on the right so they stay
|
||||
# visible even while the transient area shows counts or a selection.
|
||||
self.pool_label = QLabel()
|
||||
self.output_label = QLabel()
|
||||
self.status.addPermanentWidget(self.pool_label)
|
||||
self.status.addPermanentWidget(self.output_label)
|
||||
self._update_path_status()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
@@ -717,10 +723,9 @@ class QtApp(QMainWindow):
|
||||
def _update_path_status(self) -> None:
|
||||
pool = self.filehandler.pool_dir
|
||||
out = self.filehandler.filmoteka_dir
|
||||
self.status.showMessage(
|
||||
f"Pool: {pool or '—'} | Filmotéka: {out or '—'} | "
|
||||
f"{len(self.filehandler.filelist)} filmů"
|
||||
)
|
||||
self.pool_label.setText(f"Pool: {pool or '—'}")
|
||||
self.output_label.setText(f"Output: {out or '—'}")
|
||||
self.status.showMessage(f"{len(self.filehandler.filelist)} filmů")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Actions
|
||||
|
||||
Reference in New Issue
Block a user