feat: bulk update source paths in train dialog
Add ProcessedDB.update_source_paths() to re-resolve missing or stale source_path entries by matching filenames against a directory listing and the current playlist. Exposed as "Update paths" button in the train dialog next to the video dir field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+43
@@ -263,6 +263,49 @@ class ProcessedDB:
|
|||||||
)
|
)
|
||||||
self._con.commit()
|
self._con.commit()
|
||||||
|
|
||||||
|
def update_source_paths(self, new_dir: str,
|
||||||
|
playlist_paths: list[str] | None = None,
|
||||||
|
profile: str = "") -> int:
|
||||||
|
"""Re-resolve source_path for all rows whose current path is missing.
|
||||||
|
|
||||||
|
Checks *new_dir* and *playlist_paths* by filename match.
|
||||||
|
Returns the number of rows updated.
|
||||||
|
"""
|
||||||
|
if not self._enabled:
|
||||||
|
return 0
|
||||||
|
lookup: dict[str, str] = {}
|
||||||
|
if playlist_paths:
|
||||||
|
for p in playlist_paths:
|
||||||
|
lookup[os.path.basename(p)] = p
|
||||||
|
if new_dir and os.path.isdir(new_dir):
|
||||||
|
for f in os.listdir(new_dir):
|
||||||
|
fp = os.path.join(new_dir, f)
|
||||||
|
if os.path.isfile(fp):
|
||||||
|
lookup[f] = fp
|
||||||
|
if not lookup:
|
||||||
|
return 0
|
||||||
|
query = "SELECT DISTINCT filename, source_path FROM processed"
|
||||||
|
params: tuple = ()
|
||||||
|
if profile:
|
||||||
|
query += " WHERE profile = ?"
|
||||||
|
params = (profile,)
|
||||||
|
rows = self._con.execute(query, params).fetchall()
|
||||||
|
updated = 0
|
||||||
|
with self._lock:
|
||||||
|
for fn, sp in rows:
|
||||||
|
if sp and os.path.exists(sp):
|
||||||
|
continue
|
||||||
|
new_path = lookup.get(fn)
|
||||||
|
if new_path and os.path.isfile(new_path):
|
||||||
|
self._con.execute(
|
||||||
|
"UPDATE processed SET source_path = ? WHERE filename = ?",
|
||||||
|
(new_path, fn),
|
||||||
|
)
|
||||||
|
updated += 1
|
||||||
|
if updated:
|
||||||
|
self._con.commit()
|
||||||
|
return updated
|
||||||
|
|
||||||
def get_labels(self) -> list[str]:
|
def get_labels(self) -> list[str]:
|
||||||
"""Return distinct non-empty labels ordered by most recently used."""
|
"""Return distinct non-empty labels ordered by most recently used."""
|
||||||
if not self._enabled:
|
if not self._enabled:
|
||||||
|
|||||||
@@ -517,6 +517,12 @@ class TrainDialog(QDialog):
|
|||||||
btn_browse.setFixedWidth(30)
|
btn_browse.setFixedWidth(30)
|
||||||
btn_browse.clicked.connect(self._browse_video_dir)
|
btn_browse.clicked.connect(self._browse_video_dir)
|
||||||
vid_row.addWidget(btn_browse)
|
vid_row.addWidget(btn_browse)
|
||||||
|
self._btn_update_paths = QPushButton("Update paths")
|
||||||
|
self._btn_update_paths.setToolTip(
|
||||||
|
"Re-resolve missing source_path entries using the video dir and playlist")
|
||||||
|
self._btn_update_paths.setFixedWidth(90)
|
||||||
|
self._btn_update_paths.clicked.connect(self._update_source_paths)
|
||||||
|
vid_row.addWidget(self._btn_update_paths)
|
||||||
self._lbl_video_dir = QLabel("Video dir:")
|
self._lbl_video_dir = QLabel("Video dir:")
|
||||||
self._video_dir_widget = QWidget()
|
self._video_dir_widget = QWidget()
|
||||||
self._video_dir_widget.setLayout(vid_row)
|
self._video_dir_widget.setLayout(vid_row)
|
||||||
@@ -558,6 +564,17 @@ class TrainDialog(QDialog):
|
|||||||
if d:
|
if d:
|
||||||
self._txt_video_dir.setText(d)
|
self._txt_video_dir.setText(d)
|
||||||
|
|
||||||
|
def _update_source_paths(self):
|
||||||
|
video_dir = self._txt_video_dir.text()
|
||||||
|
n = self._db.update_source_paths(
|
||||||
|
video_dir, playlist_paths=self._playlist_paths,
|
||||||
|
profile=self._profile)
|
||||||
|
if n:
|
||||||
|
self._lbl_stats.setText(f"Updated {n} source path(s)")
|
||||||
|
self._debounce.start()
|
||||||
|
else:
|
||||||
|
self._lbl_stats.setText("No paths to update (all resolved or no matches)")
|
||||||
|
|
||||||
def _manage_negatives(self):
|
def _manage_negatives(self):
|
||||||
dlg = HardNegativesDialog(self._db, self._profile, parent=self)
|
dlg = HardNegativesDialog(self._db, self._profile, parent=self)
|
||||||
dlg.exec()
|
dlg.exec()
|
||||||
|
|||||||
Reference in New Issue
Block a user