diff --git a/src/app.py b/src/app.py index de3603a..9f742c4 100644 --- a/src/app.py +++ b/src/app.py @@ -66,7 +66,6 @@ class MainWindow(QMainWindow): self.library_tab._scan_library() self._resume_playback_if_saved() self._restore_library_state() - self.ipod_tab._on_refresh_devices_clicked() self._start_device_monitor() def _setup_player(self): @@ -427,7 +426,17 @@ class MainWindow(QMainWindow): def closeEvent(self, event): if self.device_monitor: self.device_monitor.stop() + self.ipod_tab.stop_monitoring(self.device_monitor) + for tab in (self.ipod_tab, self.library_tab): + if hasattr(tab, 'worker_thread') and tab.worker_thread: + try: + if tab.worker_thread.isRunning(): + tab.worker_thread.stop() + except RuntimeError: + tab.worker_thread = None self._save_settings() + from PyQt6.QtWidgets import QApplication + QApplication.processEvents() event.accept() diff --git a/src/device_monitor.py b/src/device_monitor.py index c87d467..cbcd2b3 100644 --- a/src/device_monitor.py +++ b/src/device_monitor.py @@ -11,6 +11,9 @@ logger = logging.getLogger(__name__) class _DetectWorker(QThread): finished = pyqtSignal(object) + def __init__(self, parent=None): + super().__init__(parent) + def run(self): try: devices = IPodDevice().detect_devices() @@ -38,19 +41,29 @@ class DeviceMonitor(QObject): def stop(self): self.timer.stop() - if self._poll_worker and self._poll_worker.isRunning(): + if self._poll_worker: self._poll_worker.quit() - self._poll_worker.wait(3000) + self._poll_worker.wait() + self._poll_worker = None self._device_ids.clear() def _poll(self): - if self._poll_worker and self._poll_worker.isRunning(): - return - self._poll_worker = _DetectWorker() - self._poll_worker.finished.connect(self._on_devices_detected) - self._poll_worker.start() + if self._poll_worker: + try: + if self._poll_worker.isRunning(): + return + except RuntimeError: + self._poll_worker = None + worker = _DetectWorker() + worker.finished.connect(self._on_devices_detected) + worker.start() + self._poll_worker = worker def _on_devices_detected(self, devices): + if self._poll_worker: + self._poll_worker.quit() + self._poll_worker.wait() + self._poll_worker = None current_ids = {d["id"] for d in devices} if current_ids != self._device_ids: self._device_ids = current_ids diff --git a/src/ui/ipod_tab.py b/src/ui/ipod_tab.py index a084e17..0cd9462 100644 --- a/src/ui/ipod_tab.py +++ b/src/ui/ipod_tab.py @@ -107,7 +107,7 @@ class iPodTab(QWidget): layout.addWidget(self.delete_status) def _on_refresh_devices_clicked(self): - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): return self.device_combo.clear() @@ -122,6 +122,8 @@ class iPodTab(QWidget): self.device_info_label.setText(status) def _on_device_detection_finished(self, success, message, result): + self._cleanup_worker() + if success: self.ipod_devices = result self.device_combo.clear() @@ -140,8 +142,6 @@ class iPodTab(QWidget): else: self._set_device_not_found() - self._cleanup_worker() - def _start_mount_and_load(self, device: dict, mount_point=None, already_mounted=False): self.device_status_label.setText("Mounting and loading tracks...") self.mount_button.setEnabled(False) @@ -320,11 +320,12 @@ class iPodTab(QWidget): if reply != QMessageBox.StandardButton.Yes: return - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): QMessageBox.information(self, "Info", "Please wait for the current task to finish") return pids = [] + for item in selected: track_data = item.data(Qt.ItemDataRole.UserRole) if track_data and "pid" in track_data: @@ -391,7 +392,7 @@ class iPodTab(QWidget): QMessageBox.warning(self, "Error", "No valid track files found on device") return - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): QMessageBox.information(self, "Info", "Please wait for the current task to finish") return @@ -470,7 +471,7 @@ class iPodTab(QWidget): QMessageBox.warning(self, "Error", "No iPod device mounted.") return - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): QMessageBox.information(self, "Info", "Please wait for the current task to finish") return @@ -506,12 +507,20 @@ class iPodTab(QWidget): pass def _on_auto_state_changed(self, devices): - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): return self._on_device_detection_finished(True, f"Found {len(devices)} devices", devices) def _cleanup_worker(self): if self.worker_thread: - self.worker_thread.wait(3000) - self.worker_thread.deleteLater() + self.worker_thread.quit() + self.worker_thread.wait() self.worker_thread = None + + def _is_worker_running(self): + if self.worker_thread: + try: + return self.worker_thread.isRunning() + except RuntimeError: + self.worker_thread = None + return False diff --git a/src/ui/library_tab.py b/src/ui/library_tab.py index a887fdf..2f6ced8 100644 --- a/src/ui/library_tab.py +++ b/src/ui/library_tab.py @@ -957,7 +957,7 @@ class LibraryTab(QWidget): ) return - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): QMessageBox.information(self, "Info", "Please wait for the current task to finish") return @@ -1025,7 +1025,7 @@ class LibraryTab(QWidget): QMessageBox.warning(self, "Error", "No iPod device mounted. Go to iPod tab and mount first.") return - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): QMessageBox.information(self, "Info", "Please wait for the current task to finish") return @@ -1070,7 +1070,7 @@ class LibraryTab(QWidget): QMessageBox.warning(self, "Error", "No iPod device mounted.") return - if self.worker_thread and self.worker_thread.isRunning(): + if self._is_worker_running(): QMessageBox.information(self, "Info", "Please wait for the current task to finish") return @@ -1140,10 +1140,18 @@ class LibraryTab(QWidget): def _cleanup_worker(self): if self.worker_thread: - self.worker_thread.wait(3000) - self.worker_thread.deleteLater() + self.worker_thread.quit() + self.worker_thread.wait() self.worker_thread = None + def _is_worker_running(self): + if self.worker_thread: + try: + return self.worker_thread.isRunning() + except RuntimeError: + self.worker_thread = None + return False + def on_device_mounted(self, mount_point: str): self._current_mount_point = mount_point self.library_progress.setVisible(True) diff --git a/src/worker.py b/src/worker.py index 74acad9..4184cb7 100644 --- a/src/worker.py +++ b/src/worker.py @@ -27,8 +27,8 @@ class WorkerThread(QThread): progress_signal = pyqtSignal(int, str) finished_signal = pyqtSignal(bool, str, object) - def __init__(self, task_type: str, **kwargs): - super().__init__() + def __init__(self, task_type: str, parent=None, **kwargs): + super().__init__(parent) self.task_type = task_type self.kwargs = kwargs self.is_running = True