fix: vid counter reuse and non-deterministic lookup in get_vid_folder

Two bugs caused vid number collisions (multiple files sharing a vid_NNN):

1. "First gap" assignment (n=1; while vid_n in existing: n++) would
   reuse deleted vid numbers. Changed to max(existing) + 1 so numbers
   always increase.

2. LIMIT 1 without ORDER BY returned arbitrary rows when a file had
   entries in multiple vid folders. Added ORDER BY rowid DESC for
   deterministic latest-wins behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 11:00:57 +02:00
parent e7d47331c6
commit b75fa85ff5
+17 -11
View File
@@ -423,22 +423,25 @@ class ProcessedDB:
"""Return the vid_NNN folder name for a source video.
Checks existing DB output_paths first; if the video already has a
vid_NNN folder, returns it. Otherwise assigns the next available
number, also checking disk for orphan vid folders.
vid_NNN folder, returns it. Otherwise assigns max(existing) + 1,
also checking disk for orphan vid folders.
"""
if not self._enabled:
return "vid_001"
# Use the most recent entry (ORDER BY rowid DESC) for determinism
# when a file has entries across multiple vid folders.
row = self._con.execute(
"SELECT output_path FROM processed"
" WHERE filename = ? AND profile = ? LIMIT 1",
" WHERE filename = ? AND profile = ?"
" ORDER BY rowid DESC LIMIT 1",
(filename, profile),
).fetchone()
if row:
parent = os.path.basename(os.path.dirname(row[0]))
if parent.startswith("vid_"):
return parent
# Collect all existing vid_NNN names from DB + disk
existing: set[str] = set()
# Collect max vid_NNN number from DB + disk (never reuse old numbers)
max_n = 0
rows = self._con.execute(
"SELECT DISTINCT output_path FROM processed WHERE profile = ?",
(profile,),
@@ -446,17 +449,20 @@ class ProcessedDB:
for (op,) in rows:
p = os.path.basename(os.path.dirname(op))
if p.startswith("vid_"):
existing.add(p)
try:
max_n = max(max_n, int(p.split("_")[1]))
except (IndexError, ValueError):
pass
if os.path.isdir(export_folder):
for d in os.listdir(export_folder):
if d.startswith("vid_") and os.path.isdir(
os.path.join(export_folder, d)
):
existing.add(d)
n = 1
while f"vid_{n:03d}" in existing:
n += 1
return f"vid_{n:03d}"
try:
max_n = max(max_n, int(d.split("_")[1]))
except (IndexError, ValueError):
pass
return f"vid_{max_n + 1:03d}"
def get_export_folders(self, profile: str = "default",
include_scan_exports: bool = False) -> list[str]: