diff --git a/anki/decks.py b/anki/decks.py index fe1c980bb..efd109853 100644 --- a/anki/decks.py +++ b/anki/decks.py @@ -432,13 +432,45 @@ class DeckManager: return self.col.db.list("select id from cards where did in "+ ids2str(dids)) - def recoverOrphans(self): + def _recoverOrphans(self): dids = list(self.decks.keys()) mod = self.col.db.mod self.col.db.execute("update cards set did = 1 where did not in "+ ids2str(dids)) self.col.db.mod = mod + def _checkDeckTree(self): + decks = self.col.decks.all() + decks.sort(key=operator.itemgetter('name')) + names = set() + + for deck in decks: + # two decks with the same name? + if deck['name'] in names: + print("fix duplicate deck name", deck['name']) + deck['name'] += "%d" % intTime(1000) + self.save(deck) + + # ensure no sections are blank + if not all(deck['name'].split("::")): + print("fix deck with missing sections", deck['name']) + deck['name'] = "recovered%d" % intTime(1000) + self.save(deck) + + # immediate parent must exist + if "::" in deck['name']: + immediateParent = "::".join(deck['name'].split("::")[:-1]) + if immediateParent not in names: + print("fix deck with missing parent", deck['name']) + self._ensureParents(deck['name']) + names.add(immediateParent) + + names.add(deck['name']) + + def checkIntegrity(self): + self._recoverOrphans() + self._checkDeckTree() + # Deck selection ############################################################# diff --git a/anki/sched.py b/anki/sched.py index 8dccfea20..bdc83bc9c 100644 --- a/anki/sched.py +++ b/anki/sched.py @@ -216,7 +216,7 @@ order by due""" % self._deckLimit(), def deckDueList(self): "Returns [deckname, did, rev, lrn, new]" self._checkDay() - self.col.decks.recoverOrphans() + self.col.decks.checkIntegrity() decks = self.col.decks.all() decks.sort(key=itemgetter('name')) lims = {} @@ -228,27 +228,10 @@ order by due""" % self._deckLimit(), parts = parts[:-1] return "::".join(parts) for deck in decks: - # if we've already seen the exact same deck name, rename the - # invalid duplicate and reload - if deck['name'] in lims: - deck['name'] += "1" - self.col.decks.save(deck) - return self.deckDueList() - # ensure no sections are blank - if not all(deck['name'].split("::")): - deck['name'] = "recovered" - self.col.decks.save(deck) - return self.deckDueList() - p = parent(deck['name']) # new nlim = self._deckNewLimitSingle(deck) if p: - if p not in lims: - # if parent was missing, this deck is invalid - deck['name'] = "recovered" - self.col.decks.save(deck) - return self.deckDueList() nlim = min(nlim, lims[p][0]) new = self._newForDeck(deck['id'], nlim) # learning diff --git a/anki/schedv2.py b/anki/schedv2.py index e647beb18..74bba3183 100644 --- a/anki/schedv2.py +++ b/anki/schedv2.py @@ -205,7 +205,7 @@ order by due""" % self._deckLimit(), def deckDueList(self): "Returns [deckname, did, rev, lrn, new]" self._checkDay() - self.col.decks.recoverOrphans() + self.col.decks.checkIntegrity() decks = self.col.decks.all() decks.sort(key=itemgetter('name')) lims = {} @@ -218,27 +218,10 @@ order by due""" % self._deckLimit(), return "::".join(parts) childMap = self.col.decks.childMap() for deck in decks: - # if we've already seen the exact same deck name, rename the - # invalid duplicate and reload - if deck['name'] in lims: - deck['name'] += "1" - self.col.decks.save(deck) - return self.deckDueList() - # ensure no sections are blank - if not all(deck['name'].split("::")): - deck['name'] = "recovered" - self.col.decks.save(deck) - return self.deckDueList() - p = parent(deck['name']) # new nlim = self._deckNewLimitSingle(deck) if p: - if p not in lims: - # if parent was missing, this deck is invalid - deck['name'] = "recovered" - self.col.decks.save(deck) - return self.deckDueList() nlim = min(nlim, lims[p][0]) new = self._newForDeck(deck['id'], nlim) # learning