feat: cache waveform data to disk, skip ffmpeg on reload

Waveform peaks are saved as .npy files keyed by MD5 of the video
path. Subsequent loads of the same video read from cache instead
of re-running ffmpeg extraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 12:19:00 +02:00
parent f268d61fe4
commit 387ed7bc6a
+23 -1
View File
@@ -1368,8 +1368,14 @@ class ScanResultsPanel(QWidget):
super().keyPressEvent(event) super().keyPressEvent(event)
_WAVEFORM_CACHE_DIR = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"cache", "waveforms",
)
class WaveformWorker(QThread): class WaveformWorker(QThread):
"""Extract a low-res waveform envelope in the background.""" """Extract a low-res waveform envelope in the background (with disk cache)."""
done = pyqtSignal(object) # emits numpy array of peak values done = pyqtSignal(object) # emits numpy array of peak values
def __init__(self, video_path: str, n_bins: int = 2000): def __init__(self, video_path: str, n_bins: int = 2000):
@@ -1377,9 +1383,22 @@ class WaveformWorker(QThread):
self._path = video_path self._path = video_path
self._n_bins = n_bins self._n_bins = n_bins
@staticmethod
def _cache_path(video_path: str) -> str:
import hashlib
h = hashlib.md5(video_path.encode()).hexdigest()
return os.path.join(_WAVEFORM_CACHE_DIR, f"{h}.npy")
def run(self): def run(self):
import numpy as np import numpy as np
try: try:
# Check cache first
cache = self._cache_path(self._path)
if os.path.exists(cache):
peaks = np.load(cache)
self.done.emit(peaks)
return
cmd = [ cmd = [
_bin("ffmpeg"), "-i", self._path, _bin("ffmpeg"), "-i", self._path,
"-vn", "-ac", "1", "-ar", "8000", "-vn", "-ac", "1", "-ar", "8000",
@@ -1399,6 +1418,9 @@ class WaveformWorker(QThread):
mx = peaks.max() mx = peaks.max()
if mx > 0: if mx > 0:
peaks = peaks / mx peaks = peaks / mx
# Save to cache
os.makedirs(_WAVEFORM_CACHE_DIR, exist_ok=True)
np.save(cache, peaks)
self.done.emit(peaks) self.done.emit(peaks)
except Exception: except Exception:
pass pass