feat: '+ To library' — add the current audio area straight to the clip library
This commit is contained in:
@@ -5170,6 +5170,10 @@ class MainWindow(QMainWindow):
|
||||
self._btn_edit_clip.setToolTip(
|
||||
"Open the current audio area in the destructive editor")
|
||||
self._btn_edit_clip.clicked.connect(self._on_edit_clip)
|
||||
self._btn_add_library = QPushButton("+ To library")
|
||||
self._btn_add_library.setToolTip(
|
||||
"Add the current audio area (with edits) to the clip library")
|
||||
self._btn_add_library.clicked.connect(self._on_add_selection_to_library)
|
||||
self._wave.selection_changed.connect(self._on_wave_selection_changed)
|
||||
self._wave.view_changed.connect(self._on_wave_view_changed)
|
||||
self._wave_pending_view = None
|
||||
@@ -5546,7 +5550,8 @@ class MainWindow(QMainWindow):
|
||||
g.addWidget(self._wave, 4, 0, 1, 4)
|
||||
g.addWidget(self._btn_wave_refresh, 5, 0, 1, 2)
|
||||
g.addWidget(self._btn_audio_play, 5, 2, 1, 2)
|
||||
g.addWidget(self._btn_edit_clip, 6, 0, 1, 4) # own row: destructive editor entry
|
||||
g.addWidget(self._btn_edit_clip, 6, 0, 1, 2) # destructive editor entry
|
||||
g.addWidget(self._btn_add_library, 6, 2, 1, 2) # straight into the clip library
|
||||
g.addWidget(self._btn_extract_audio, 7, 0, 1, 4)
|
||||
g.setColumnStretch(4, 1) # spare gutter column clusters label/field pairs to the left
|
||||
g.setRowStretch(8, 1) # anchor content to the top
|
||||
@@ -7388,6 +7393,48 @@ class MainWindow(QMainWindow):
|
||||
self._merge_temps.add(tmp) # reuse the close-time temp sweep
|
||||
self._open_audio_editor(tmp)
|
||||
|
||||
def _on_add_selection_to_library(self) -> None:
|
||||
"""Render the current audio area (with edits) into a managed library
|
||||
folder and add it to the clip library — no save dialog."""
|
||||
if not self._file_path:
|
||||
self._show_status("Load a video first", 3000)
|
||||
return
|
||||
start = self._cursor
|
||||
dur = self._spn_audio_len.value()
|
||||
base = (self._settings.value("audio_extract_dir", "")
|
||||
or self._tab_export_folder()
|
||||
or os.path.dirname(self._file_path))
|
||||
lib_dir = (self._settings.value("audio_library_dir", "")
|
||||
or os.path.join(base, "audio_library"))
|
||||
self._settings.setValue("audio_library_dir", lib_dir)
|
||||
try:
|
||||
os.makedirs(lib_dir, exist_ok=True)
|
||||
except OSError:
|
||||
self._show_status("Could not create the library folder", 4000)
|
||||
return
|
||||
stem = os.path.splitext(os.path.basename(self._file_path))[0]
|
||||
out = os.path.join(lib_dir, f"{stem}_{start:.2f}-{start + dur:.2f}s.wav")
|
||||
cmd = build_audio_clip_command(self._file_path, start, dur, out,
|
||||
filters=self._current_edit_filters() or None)
|
||||
self._show_status("Adding to library…")
|
||||
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
||||
try:
|
||||
proc = subprocess.run(cmd, capture_output=True, timeout=120)
|
||||
except Exception:
|
||||
proc = None
|
||||
finally:
|
||||
QApplication.restoreOverrideCursor()
|
||||
if proc is not None and proc.returncode == 0 and os.path.exists(out):
|
||||
self._scan_panel._library.add_clip(out)
|
||||
self._show_status(f"Added to library: {os.path.basename(out)}", 4000)
|
||||
else:
|
||||
try:
|
||||
if os.path.exists(out):
|
||||
os.remove(out)
|
||||
except OSError:
|
||||
pass
|
||||
self._show_status("Could not add the clip to the library", 3000)
|
||||
|
||||
def _open_audio_editor(self, path: str) -> None:
|
||||
"""Open the destructive editor on *path*; if the user Saves-as, add the
|
||||
result to the clip library."""
|
||||
|
||||
@@ -448,6 +448,38 @@ def test_extract_no_edits_passes_no_filters(win, monkeypatch, tmp_path):
|
||||
assert seen["filters"] is None
|
||||
|
||||
|
||||
def test_add_selection_to_library(win, tmp_path, monkeypatch):
|
||||
import main as m
|
||||
win._file_path = "/vids/Chloe.mp4"
|
||||
win._cursor = 7.0
|
||||
win._spn_audio_len.setValue(3.0)
|
||||
win._settings.setValue("audio_extract_dir", str(tmp_path))
|
||||
win._settings.setValue("audio_library_dir", "") # force derive
|
||||
seen = {}
|
||||
def fake_cmd(inp, start, dur, out, filters=None):
|
||||
seen["out"] = out; seen["start"] = start; seen["dur"] = dur; return ["true"]
|
||||
monkeypatch.setattr(m, "build_audio_clip_command", fake_cmd)
|
||||
monkeypatch.setattr(m.subprocess, "run",
|
||||
lambda *a, **k: type("P", (), {"returncode": 0})())
|
||||
monkeypatch.setattr(m.os.path, "exists", lambda p: True)
|
||||
monkeypatch.setattr(m, "probe_duration", lambda p: 3.0)
|
||||
lib = win._scan_panel._library
|
||||
lib._key = "audio_library_addsel_test"
|
||||
win._settings.setValue(lib._key, [])
|
||||
lib._list.clear()
|
||||
win._on_add_selection_to_library()
|
||||
# rendered the current area with the managed-folder auto-name
|
||||
assert seen["start"] == 7.0 and seen["dur"] == 3.0
|
||||
assert os.path.join("audio_library", "Chloe_7.00-10.00s.wav") in seen["out"]
|
||||
# and it was added to the library
|
||||
assert seen["out"] in lib.clips()
|
||||
|
||||
|
||||
def test_add_selection_to_library_no_file_safe(win):
|
||||
win._file_path = ""
|
||||
win._on_add_selection_to_library() # must not raise
|
||||
|
||||
|
||||
def test_waveform_strip_present_and_safe(win):
|
||||
from PyQt6.QtWidgets import QPushButton
|
||||
assert win._wave is not None
|
||||
|
||||
Reference in New Issue
Block a user