diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index 900ba00ce..c609a1eb8 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -17,6 +17,7 @@ from anki.errors import * from anki.sound import hasSound, playFromText from anki.utils import addTags, deleteTags from anki.media import rebuildMediaDir +from anki.db import OperationalError import anki.lang import ankiqt ui = ankiqt.ui @@ -473,7 +474,7 @@ class AnkiQt(QMainWindow): else: try: self.rebuildQueue() - except: + except OperationalError: ui.utils.showWarning(_( "Error building queue. Attempting recovery..")) self.onCheckDB() @@ -985,7 +986,8 @@ class AnkiQt(QMainWindow): # Syncing ########################################################################## - def syncDeck(self, interactive=True, create=False, onlyMerge=False, reload=True): + def syncDeck(self, interactive=True, create=False, onlyMerge=False, + reload=True, checkSources=True): "Synchronise a deck with the server." # vet input u=self.config['syncUsername'] @@ -1002,9 +1004,17 @@ class AnkiQt(QMainWindow): # save first, so we can rollback on failure self.deck.save() self.deck.close() + # store data we need before closing the deck self.deckPath = self.deck.path self.syncName = self.deck.syncName or self.deck.name() self.lastSync = self.deck.lastSync + if checkSources: + self.sourcesToCheck = self.deck.s.column0( + "select id from sources where syncPeriod != -1 " + "and syncPeriod = 0 or :t - lastSync > syncPeriod", + t=time.time()) + else: + self.sourcesToCheck = [] self.deck = None self.loadAfterSync = reload # bug triggered by preferences dialog - underlying c++ widgets are not @@ -1012,7 +1022,8 @@ class AnkiQt(QMainWindow): import gc; gc.collect() self.bodyView.clearWindow() self.bodyView.flush() - self.syncThread = ui.sync.Sync(self, u, p, interactive, create, onlyMerge) + self.syncThread = ui.sync.Sync(self, u, p, interactive, create, + onlyMerge, self.sourcesToCheck) self.connect(self.syncThread, SIGNAL("setStatus"), self.setSyncStatus) self.connect(self.syncThread, SIGNAL("showWarning"), ui.utils.showWarning) self.connect(self.syncThread, SIGNAL("moveToState"), self.moveToState) diff --git a/ankiqt/ui/sync.py b/ankiqt/ui/sync.py index da3131e43..f8ee236e9 100644 --- a/ankiqt/ui/sync.py +++ b/ankiqt/ui/sync.py @@ -3,7 +3,7 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * -import os, types, socket, time +import os, types, socket, time, traceback import ankiqt import anki from anki.sync import SyncClient, HttpSyncServerProxy @@ -16,7 +16,8 @@ import ankiqt.forms class Sync(QThread): - def __init__(self, parent, user, pwd, interactive, create, onlyMerge): + def __init__(self, parent, user, pwd, interactive, create, + onlyMerge, sourcesToCheck): QThread.__init__(self) self.parent = parent self.interactive = interactive @@ -25,6 +26,7 @@ class Sync(QThread): self.create = create self.ok = True self.onlyMerge = onlyMerge + self.sourcesToCheck = sourcesToCheck def setStatus(self, msg, timeout=5000): self.emit(SIGNAL("setStatus"), msg, timeout) @@ -54,6 +56,7 @@ class Sync(QThread): def connect(self, *args): # connect, check auth proxy = HttpSyncServerProxy(self.user, self.pwd) + proxy.sourcesToCheck = self.sourcesToCheck proxy.connect("ankiqt-" + ankiqt.appVersion) return proxy @@ -87,38 +90,56 @@ class Sync(QThread): client.setServer(proxy) proxy.deckName = self.parent.syncName # need to do anything? - if not client.prepareSync(): - self.setStatus(_("Sync: nothing to do")) - self.deck.close() - self.emit(SIGNAL("syncFinished")) - return start = time.time() - # summary - self.setStatus(_("Fetching summary from server.."), 0) - sums = client.summaries() - # diff - self.setStatus(_("Determining differences.."), 0) - payload = client.genPayload(sums) - # send payload - pr = client.payloadChangeReport(payload) - self.setStatus("
" + pr + "
", 0) - self.setStatus(_("Sending payload..."), 0) - res = client.server.applyPayload(payload) - # apply reply - self.setStatus(_("Applying reply.."), 0) - client.applyPayloadReply(res) - # finished. save deck, preserving mod time - self.setStatus(_("Sync complete.")) - self.deck.lastLoaded = self.deck.modified - self.deck.s.flush() - self.deck.s.commit() + if client.prepareSync(): + # summary + self.setStatus(_("Fetching summary from server.."), 0) + sums = client.summaries() + # diff + self.setStatus(_("Determining differences.."), 0) + payload = client.genPayload(sums) + # send payload + pr = client.payloadChangeReport(payload) + self.setStatus("
" + pr + "
", 0) + self.setStatus(_("Sending payload..."), 0) + res = client.server.applyPayload(payload) + # apply reply + self.setStatus(_("Applying reply.."), 0) + client.applyPayloadReply(res) + # finished. save deck, preserving mod time + self.setStatus(_("Sync complete.")) + self.deck.lastLoaded = self.deck.modified + self.deck.s.flush() + self.deck.s.commit() + else: + self.setStatus(_("Sync: nothing to do")) + # check sources + if self.sourcesToCheck: + self.setStatus(_("

Checking shared decks..")) + for source in self.sourcesToCheck: + if not proxy.hasDeck(str(source)): + self.setStatus(_("%x no longer exists.") % source) + continue + proxy.deckName = str(source) + if not client.prepareOneWaySync(): + self.setStatus(_("%x up to date.") % source) + continue + self.setStatus(_("Getting payload from %x..") % source) + payload = proxy.genOneWayPayload(client.lastSync) + self.setStatus(_("Applying %d modified cards..") % + len(payload['cards'])) + client.applyOneWayPayload(payload) + self.setStatus(_("Check complete.")) + self.deck.s.flush() + self.deck.s.commit() # close and send signal to main thread self.deck.close() taken = time.time() - start - if taken < 2.5: - time.sleep(2.5 - taken) + if taken < 20.5: + time.sleep(20.5 - taken) self.emit(SIGNAL("syncFinished")) except Exception, e: + traceback.print_exc() self.deck.close() # cheap hack to ensure message is displayed err = `getattr(e, 'data', None) or e` @@ -168,4 +189,3 @@ class DeckChooser(QDialog): else: self.name = self.decks[self.dialog.decks.currentRow() - offset] self.close() -