diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 61f2363fc..e3113b3b9 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1071,16 +1071,13 @@ title="{}" {}>{}""".format( else: after_sync(False) - def maybe_auto_sync_media(self) -> None: - if self.can_auto_sync(): - return - # media_syncer takes care of media syncing preference check - self.media_syncer.start() - def can_auto_sync(self) -> bool: + "True if syncing on startup/shutdown enabled." + return self._can_sync_unattended() and self.pm.auto_syncing_enabled() + + def _can_sync_unattended(self) -> bool: return ( - self.pm.auto_syncing_enabled() - and bool(self.pm.sync_auth()) + bool(self.pm.sync_auth()) and not self.safeMode and not self.restoring_backup ) @@ -1441,7 +1438,9 @@ title="{}" {}>{}""".format( # refresh decks every 10 minutes self.progress.timer(10 * 60 * 1000, self.onRefreshTimer, True, parent=self) # check media sync every 5 minutes - self.progress.timer(5 * 60 * 1000, self.on_autosync_timer, True, parent=self) + self.progress.timer( + 5 * 60 * 1000, self.on_periodic_sync_timer, True, parent=self + ) # periodic garbage collection self.progress.timer( 15 * 60 * 1000, self.garbage_collect_now, True, False, parent=self @@ -1463,13 +1462,16 @@ title="{}" {}>{}""".format( elif self.state == "overview": self.overview.refresh() - def on_autosync_timer(self) -> None: + def on_periodic_sync_timer(self) -> None: elap = self.media_syncer.seconds_since_last_sync() - minutes = self.pm.auto_sync_media_minutes() + minutes = self.pm.periodic_sync_media_minutes() if not minutes: return if elap > minutes * 60: - self.maybe_auto_sync_media() + if not self._can_sync_unattended(): + return + # media_syncer takes care of media syncing preference check + self.media_syncer.start(True) # Backups ########################################################################## diff --git a/qt/aqt/mediasync.py b/qt/aqt/mediasync.py index 69cad9502..4fafd6b13 100644 --- a/qt/aqt/mediasync.py +++ b/qt/aqt/mediasync.py @@ -28,7 +28,7 @@ class MediaSyncer: self._last_progress_at = 0 gui_hooks.media_sync_did_start_or_stop.append(self._on_start_stop) - def start(self) -> None: + def start(self, is_periodic_sync: bool = False) -> None: "Start media syncing in the background, if it's not already running." if not self.mw.pm.media_syncing_enabled() or not ( auth := self.mw.pm.sync_auth() @@ -40,11 +40,13 @@ class MediaSyncer: # this will exit after the thread is spawned, but may block if there's an existing # backend lock - QueryOp(parent=aqt.mw, op=run, success=lambda _: 1).run_in_background() + QueryOp(parent=aqt.mw, op=run, success=lambda _: 1).failure( + lambda e: self._handle_sync_error(e, is_periodic_sync) + ).run_in_background() - self.start_monitoring() + self.start_monitoring(is_periodic_sync) - def start_monitoring(self) -> None: + def start_monitoring(self, is_periodic_sync: bool = False) -> None: if self._syncing: return self._syncing = True @@ -62,31 +64,35 @@ class MediaSyncer: time.sleep(0.25) self.mw.taskman.run_in_background( - monitor, self._on_finished, uses_collection=False + monitor, + lambda fut: self._on_finished(fut, is_periodic_sync), + uses_collection=False, ) def _update_progress(self, progress: str) -> None: self.last_progress = progress self.mw.taskman.run_on_main(lambda: gui_hooks.media_sync_did_progress(progress)) - def _on_finished(self, future: Future) -> None: + def _on_finished(self, future: Future, is_periodic_sync: bool = False) -> None: self._syncing = False self._last_progress_at = int_time() gui_hooks.media_sync_did_start_or_stop(False) exc = future.exception() if exc is not None: - self._handle_sync_error(exc) + self._handle_sync_error(exc, is_periodic_sync) else: self._update_progress(tr.sync_media_complete()) - def _handle_sync_error(self, exc: BaseException) -> None: + def _handle_sync_error( + self, exc: BaseException, is_periodic_sync: bool = False + ) -> None: if isinstance(exc, Interrupted): self._update_progress(tr.sync_media_aborted()) - return + elif is_periodic_sync: + print(str(exc)) else: show_info(str(exc), modality=Qt.WindowModality.NonModal) - return def abort(self) -> None: if not self.is_syncing(): diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index b1c35917d..a52a88372 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -190,7 +190,9 @@ class Preferences(QDialog): qconnect(self.form.media_log.clicked, self.on_media_log) self.form.syncOnProgramOpen.setChecked(self.mw.pm.auto_syncing_enabled()) self.form.syncMedia.setChecked(self.mw.pm.media_syncing_enabled()) - self.form.autoSyncMedia.setChecked(self.mw.pm.auto_sync_media_minutes() != 0) + self.form.autoSyncMedia.setChecked( + self.mw.pm.periodic_sync_media_minutes() != 0 + ) self.form.custom_sync_url.setText(self.mw.pm.custom_sync_url()) self.form.network_timeout.setValue(self.mw.pm.network_timeout()) @@ -234,7 +236,7 @@ class Preferences(QDialog): def update_network(self) -> None: self.prof["autoSync"] = self.form.syncOnProgramOpen.isChecked() self.prof["syncMedia"] = self.form.syncMedia.isChecked() - self.mw.pm.set_auto_sync_media_minutes( + self.mw.pm.set_periodic_sync_media_minutes( self.form.autoSyncMedia.isChecked() and 15 or 0 ) if self.form.fullSync.isChecked(): diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 6bc93f913..185fe4fd3 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -654,6 +654,7 @@ create table if not exists profiles return self.profile.get("syncMedia", True) def auto_syncing_enabled(self) -> bool: + "True if syncing on startup/shutdown enabled." return self.profile.get("autoSync", True) def sync_auth(self) -> SyncAuth | None: @@ -690,10 +691,10 @@ create table if not exists profiles self.set_current_sync_url(None) self.profile["customSyncUrl"] = url - def auto_sync_media_minutes(self) -> int: + def periodic_sync_media_minutes(self) -> int: return self.profile.get("autoSyncMediaMinutes", 15) - def set_auto_sync_media_minutes(self, val: int) -> None: + def set_periodic_sync_media_minutes(self, val: int) -> None: self.profile["autoSyncMediaMinutes"] = val def show_browser_table_tooltips(self) -> bool: