feat: preview healed joins and save editor clips to library

This commit is contained in:
2026-07-04 20:18:50 +02:00
parent 9838a4fcfd
commit 6cfac8baa9
2 changed files with 111 additions and 5 deletions
+66 -4
View File
@@ -4258,8 +4258,10 @@ class AudioEditorDialog(QDialog):
self._btn_trim = QPushButton("Trim to selection")
self._btn_undo = QPushButton("Undo")
self._btn_redo = QPushButton("Redo")
self._btn_loop_join = QPushButton("Loop Join")
self._btn_play = QPushButton("▶ Play")
self._btn_play.setCheckable(True)
self._btn_save_library = QPushButton("Save to Library")
self._btn_save_as = QPushButton("Save as…")
self._btn_close = QPushButton("Close")
for b, slot in ((self._btn_heal_cut, self._on_heal_cut),
@@ -4269,7 +4271,9 @@ class AudioEditorDialog(QDialog):
(self._btn_trim, self._on_trim),
(self._btn_undo, self._on_undo),
(self._btn_redo, self._on_redo),
(self._btn_loop_join, self._on_loop_join),
(self._btn_play, self._on_play),
(self._btn_save_library, self._on_save_to_library),
(self._btn_save_as, self._on_save_as),
(self._btn_close, self.close)):
b.clicked.connect(slot)
@@ -4285,9 +4289,11 @@ class AudioEditorDialog(QDialog):
self._status = QLabel("")
outer.addWidget(self._status)
bottom = QHBoxLayout()
for b in (self._btn_undo, self._btn_redo, self._btn_play):
for b in (self._btn_undo, self._btn_redo, self._btn_loop_join,
self._btn_play):
bottom.addWidget(b)
bottom.addStretch()
bottom.addWidget(self._btn_save_library)
bottom.addWidget(self._btn_save_as)
bottom.addWidget(self._btn_close)
outer.addLayout(bottom)
@@ -4403,15 +4409,33 @@ class AudioEditorDialog(QDialog):
if not checked:
self._stop_play()
return
self._play_current()
def _play_current(self, start: float | None = None,
end: float | None = None) -> None:
from PyQt6.QtCore import QProcess
self._stop_play()
self._play_proc = QProcess(self)
self._play_proc.finished.connect(self._on_play_finished)
self._play_proc.errorOccurred.connect(self._on_play_error)
self._play_proc.start(
_bin("ffplay"),
["-autoexit", "-nodisp", "-loglevel", "error", self._current()])
args = ["-autoexit", "-nodisp", "-loglevel", "error"]
if start is not None:
args += ["-ss", str(start)]
if end is not None and start is not None and end > start:
args += ["-t", str(end - start)]
args.append(self._current())
self._play_proc.start(_bin("ffplay"), args)
self._btn_play.setText("■ Stop")
if not self._btn_play.isChecked():
self._btn_play.blockSignals(True)
self._btn_play.setChecked(True)
self._btn_play.blockSignals(False)
def _on_loop_join(self) -> None:
if not self._join_preview:
self._set_status("No healed join to preview")
return
self._play_current(*self._join_preview)
def _on_play_error(self, _err) -> None:
self._set_status("Playback unavailable (ffplay not found)")
@@ -4488,6 +4512,44 @@ class AudioEditorDialog(QDialog):
else:
self._set_status("Save failed")
def _on_save_to_library(self) -> None:
parent = self.parent()
settings = getattr(parent, "_settings", None)
scan_panel = getattr(parent, "_scan_panel", None)
if settings is None or scan_panel is None:
self._set_status("Library unavailable")
return
base = settings.value("audio_library_dir", "")
if not base:
base = os.path.join(str(Path.home()), "8cut_audio_library")
settings.setValue("audio_library_dir", base)
try:
os.makedirs(base, exist_ok=True)
except OSError:
self._set_status("Could not create library folder")
return
stem = os.path.splitext(os.path.basename(self._current()))[0] or "clip"
out = os.path.join(base, f"{stem}_edited.wav")
i = 1
while os.path.exists(out):
out = os.path.join(base, f"{stem}_edited_{i}.wav")
i += 1
dur = probe_duration(self._current()) or self._clip_dur or 0.0
cmd = build_audio_clip_command(self._current(), 0.0, dur, out)
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
try:
proc = subprocess.run(cmd, capture_output=True, timeout=300)
except Exception:
proc = None
finally:
QApplication.restoreOverrideCursor()
if proc is not None and proc.returncode == 0 and os.path.exists(out):
scan_panel._library.add_clip(out)
self._last_saved = out
self._set_status(f"Saved to library: {os.path.basename(out)}")
else:
self._set_status("Save to library failed")
class AudioLibraryTab(QWidget):
"""A persistent library of extracted audio clips: add (auto/manual/drag),