""" bpm_worker.py — QThread til BPM-analyse i baggrunden. Ny v0.9 arkitektur: sange er i songs, filer i files, libraries i libraries. """ import sqlite3 from PyQt6.QtCore import QThread, pyqtSignal class BpmScanWorker(QThread): progress = pyqtSignal(int, int) # done, total finished = pyqtSignal(int) # antal analyseret def __init__(self, library_id: int, db_path: str, scan_all: bool = False): super().__init__() self._library_id = library_id self._db_path = db_path self._scan_all = scan_all self._cancelled = False def cancel(self): self.requestInterruption() self._cancelled = True def run(self): import time self._cancelled = False try: from local.tag_reader import analyze_bpm conn = sqlite3.connect(self._db_path) conn.row_factory = sqlite3.Row conn.execute("PRAGMA journal_mode=WAL") # Ny arkitektur: JOIN songs + files + libraries lib_row = conn.execute( "SELECT path FROM libraries WHERE id=?", (self._library_id,) ).fetchone() if not lib_row: self.finished.emit(0) conn.close() return lib_path = lib_row["path"] if self._scan_all: songs = conn.execute(""" SELECT s.id, f.local_path FROM songs s JOIN files f ON f.song_id = s.id AND f.file_missing = 0 WHERE f.local_path LIKE ? """, (lib_path + "%",)).fetchall() else: songs = conn.execute(""" SELECT s.id, f.local_path FROM songs s JOIN files f ON f.song_id = s.id AND f.file_missing = 0 WHERE f.local_path LIKE ? AND (s.bpm IS NULL OR s.bpm = 0) """, (lib_path + "%",)).fetchall() total = len(songs) done = 0 for song in songs: if self._cancelled or self.isInterruptionRequested(): break try: bpm = analyze_bpm(song["local_path"]) if bpm and bpm > 0: conn.execute( "UPDATE songs SET bpm=? WHERE id=?", (int(round(bpm)), song["id"]) ) conn.commit() except Exception: pass done += 1 self.progress.emit(done, total) time.sleep(0.01) conn.close() self.finished.emit(done) except Exception: self.finished.emit(0)