feat: Merge sequence — add (file/selection), reorder, remove
This commit is contained in:
@@ -4544,6 +4544,7 @@ class MainWindow(QMainWindow):
|
||||
self._merge_list.setSelectionMode(
|
||||
QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self._merge_list.setToolTip("Clips to merge, top to bottom")
|
||||
self._merge_temps: set[str] = set()
|
||||
self._spn_crossfade = QDoubleSpinBox()
|
||||
self._spn_crossfade.setRange(0.0, 10.0)
|
||||
self._spn_crossfade.setDecimals(2)
|
||||
@@ -6579,17 +6580,74 @@ class MainWindow(QMainWindow):
|
||||
start = self._cursor
|
||||
self._timeline.set_audio_region(start, start + self._spn_audio_len.value())
|
||||
|
||||
def _on_merge_add_selection(self) -> None:
|
||||
pass # implemented in M3
|
||||
def _merge_add_paths(self, paths: list[str]) -> None:
|
||||
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
||||
try:
|
||||
for p in paths:
|
||||
ap = os.path.abspath(p)
|
||||
dur = probe_duration(ap)
|
||||
text = (f"{os.path.basename(ap)} ({dur:.2f}s)"
|
||||
if dur is not None else os.path.basename(ap))
|
||||
item = QListWidgetItem(text)
|
||||
item.setData(Qt.ItemDataRole.UserRole, ap)
|
||||
item.setData(Qt.ItemDataRole.UserRole + 1, dur)
|
||||
self._merge_list.addItem(item)
|
||||
finally:
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
def _on_merge_add_file(self) -> None:
|
||||
pass # implemented in M3
|
||||
default_dir = (self._settings.value("audio_extract_dir", "")
|
||||
or os.path.dirname(self._file_path or ""))
|
||||
paths, _sel = QFileDialog.getOpenFileNames(
|
||||
self, "Add audio file(s)", default_dir,
|
||||
"Audio (*.wav *.mp3 *.flac *.m4a *.ogg *.opus *.aac);;All files (*)")
|
||||
if paths:
|
||||
self._merge_add_paths(paths)
|
||||
|
||||
def _on_merge_add_selection(self) -> None:
|
||||
if not self._file_path:
|
||||
self._show_status("Load a video first", 3000)
|
||||
return
|
||||
import tempfile
|
||||
start = self._cursor
|
||||
dur = self._spn_audio_len.value()
|
||||
fd, tmp = tempfile.mkstemp(suffix=".wav", prefix="8cut_merge_")
|
||||
os.close(fd)
|
||||
self._show_status("Rendering selection…")
|
||||
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
||||
try:
|
||||
cmd = build_audio_clip_command(self._file_path, start, dur, tmp,
|
||||
filters=self._current_edit_filters() or None)
|
||||
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(tmp):
|
||||
self._merge_temps.add(tmp)
|
||||
self._merge_add_paths([tmp])
|
||||
else:
|
||||
try:
|
||||
os.remove(tmp)
|
||||
except OSError:
|
||||
pass
|
||||
self._show_status("Could not render selection", 3000)
|
||||
|
||||
def _merge_move(self, delta: int) -> None:
|
||||
pass # implemented in M3
|
||||
row = self._merge_list.currentRow()
|
||||
if row < 0:
|
||||
return
|
||||
new = row + delta
|
||||
if new < 0 or new >= self._merge_list.count():
|
||||
return
|
||||
item = self._merge_list.takeItem(row)
|
||||
self._merge_list.insertItem(new, item)
|
||||
self._merge_list.setCurrentRow(new)
|
||||
|
||||
def _merge_remove_selected(self) -> None:
|
||||
pass # implemented in M3
|
||||
row = self._merge_list.currentRow()
|
||||
if row >= 0:
|
||||
self._merge_list.takeItem(row)
|
||||
|
||||
def _on_merge_preview(self) -> None:
|
||||
pass # implemented in M4
|
||||
|
||||
Reference in New Issue
Block a user