feat: manual exports use vid number with m{N} tag
Manual clips now follow the same pattern as scan exports: clip_003_m1_0.mp4 (manual) vs clip_003_a1_0.mp4 (auto-scan). The clip number matches the vid folder number. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+8
-2
@@ -24,17 +24,23 @@ def _log(*args) -> None:
|
|||||||
print(f"[8-cut {ts}]", *args, file=sys.stderr)
|
print(f"[8-cut {ts}]", *args, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
def build_export_path(folder: str, basename: str, counter: int, sub: int | None = None) -> str:
|
def build_export_path(folder: str, basename: str, counter: int,
|
||||||
|
sub: int | None = None, tag: str | None = None) -> str:
|
||||||
"""Build clip output path. *folder* should be the vid folder (e.g. .../mp4/vid_001)."""
|
"""Build clip output path. *folder* should be the vid folder (e.g. .../mp4/vid_001)."""
|
||||||
name = f"{basename}_{counter:03d}"
|
name = f"{basename}_{counter:03d}"
|
||||||
|
if tag is not None:
|
||||||
|
name = f"{name}_{tag}"
|
||||||
if sub is not None:
|
if sub is not None:
|
||||||
name = f"{name}_{sub}"
|
name = f"{name}_{sub}"
|
||||||
return os.path.join(folder, name + ".mp4")
|
return os.path.join(folder, name + ".mp4")
|
||||||
|
|
||||||
|
|
||||||
def build_sequence_dir(folder: str, basename: str, counter: int, sub: int | None = None) -> str:
|
def build_sequence_dir(folder: str, basename: str, counter: int,
|
||||||
|
sub: int | None = None, tag: str | None = None) -> str:
|
||||||
"""Build WebP sequence output dir. *folder* should be the vid folder."""
|
"""Build WebP sequence output dir. *folder* should be the vid folder."""
|
||||||
name = f"{basename}_{counter:03d}"
|
name = f"{basename}_{counter:03d}"
|
||||||
|
if tag is not None:
|
||||||
|
name = f"{name}_{tag}"
|
||||||
if sub is not None:
|
if sub is not None:
|
||||||
name = f"{name}_{sub}"
|
name = f"{name}_{sub}"
|
||||||
return os.path.join(folder, name)
|
return os.path.join(folder, name)
|
||||||
|
|||||||
@@ -4743,18 +4743,17 @@ class MainWindow(QMainWindow):
|
|||||||
name = self._txt_name.text() or "clip"
|
name = self._txt_name.text() or "clip"
|
||||||
vid_name = self._get_vid_folder(folder)
|
vid_name = self._get_vid_folder(folder)
|
||||||
vid_folder = os.path.join(folder, vid_name)
|
vid_folder = os.path.join(folder, vid_name)
|
||||||
# Start from the highest counter the DB knows about, so we never
|
vid_num = int(vid_name.split("_")[-1])
|
||||||
# reuse a counter if the folder is temporarily empty / unmounted.
|
# Find next manual export number (m1, m2, ...)
|
||||||
db_max = self._db.get_max_counter(vid_folder, name) if self._db else 0
|
self._export_counter = 1
|
||||||
self._export_counter = max(1, db_max + 1)
|
|
||||||
# Then also skip any files that exist on disk.
|
|
||||||
while True:
|
while True:
|
||||||
test_path = build_export_path(vid_folder, name, self._export_counter, sub=0)
|
tag = f"m{self._export_counter}"
|
||||||
|
test_path = build_export_path(vid_folder, name, vid_num, sub=0, tag=tag)
|
||||||
if not os.path.exists(test_path):
|
if not os.path.exists(test_path):
|
||||||
break
|
break
|
||||||
self._export_counter += 1
|
self._export_counter += 1
|
||||||
n = self._spn_clips.value()
|
n = self._spn_clips.value()
|
||||||
base = f"{name}_{self._export_counter:03d}"
|
base = f"{name}_{vid_num:03d}_m{self._export_counter}"
|
||||||
if n == 1:
|
if n == 1:
|
||||||
self._lbl_next.setText(f"→ {vid_name}/{base}_0")
|
self._lbl_next.setText(f"→ {vid_name}/{base}_0")
|
||||||
else:
|
else:
|
||||||
@@ -4820,27 +4819,29 @@ class MainWindow(QMainWindow):
|
|||||||
vid_name = self._get_vid_folder(folder)
|
vid_name = self._get_vid_folder(folder)
|
||||||
vid_folder = os.path.join(folder, vid_name)
|
vid_folder = os.path.join(folder, vid_name)
|
||||||
os.makedirs(vid_folder, exist_ok=True)
|
os.makedirs(vid_folder, exist_ok=True)
|
||||||
# For subprofile exports, calculate counter independently.
|
vid_num = int(vid_name.split("_")[-1])
|
||||||
|
# For subprofile exports, calculate manual counter independently.
|
||||||
if folder_suffix:
|
if folder_suffix:
|
||||||
db_max_sub = self._db.get_max_counter(vid_folder, name) if self._db else 0
|
manual_n = 1
|
||||||
counter = max(1, db_max_sub + 1)
|
|
||||||
while True:
|
while True:
|
||||||
|
tag = f"m{manual_n}"
|
||||||
if image_sequence:
|
if image_sequence:
|
||||||
p = build_sequence_dir(vid_folder, name, counter, sub=0)
|
p = build_sequence_dir(vid_folder, name, vid_num, sub=0, tag=tag)
|
||||||
else:
|
else:
|
||||||
p = build_export_path(vid_folder, name, counter, sub=0)
|
p = build_export_path(vid_folder, name, vid_num, sub=0, tag=tag)
|
||||||
if not os.path.exists(p):
|
if not os.path.exists(p):
|
||||||
break
|
break
|
||||||
counter += 1
|
manual_n += 1
|
||||||
else:
|
else:
|
||||||
counter = self._export_counter
|
manual_n = self._export_counter
|
||||||
|
tag = f"m{manual_n}"
|
||||||
jobs = []
|
jobs = []
|
||||||
for sub in range(n_clips):
|
for sub in range(n_clips):
|
||||||
start = self._cursor + sub * spread
|
start = self._cursor + sub * spread
|
||||||
if image_sequence:
|
if image_sequence:
|
||||||
out = build_sequence_dir(vid_folder, name, counter, sub=sub)
|
out = build_sequence_dir(vid_folder, name, vid_num, sub=sub, tag=tag)
|
||||||
else:
|
else:
|
||||||
out = build_export_path(vid_folder, name, counter, sub=sub)
|
out = build_export_path(vid_folder, name, vid_num, sub=sub, tag=tag)
|
||||||
jobs.append((start, out, base_ratio, base_center))
|
jobs.append((start, out, base_ratio, base_center))
|
||||||
|
|
||||||
# Apply crop keyframes (or fall back to base state).
|
# Apply crop keyframes (or fall back to base state).
|
||||||
|
|||||||
Reference in New Issue
Block a user