diff --git a/pylib/anki/hooks.py b/pylib/anki/hooks.py index 2d91ac74d..912d42fb3 100644 --- a/pylib/anki/hooks.py +++ b/pylib/anki/hooks.py @@ -387,6 +387,62 @@ class _NotesWillBeDeletedHook: notes_will_be_deleted = _NotesWillBeDeletedHook() +class _SchedulerNewLimitForSingleDeckFilter: + """Allows changing the number of new card for this deck (without + considering descendants).""" + + _hooks: List[Callable[[int, Dict[str, Any]], int]] = [] + + def append(self, cb: Callable[[int, Dict[str, Any]], int]) -> None: + """(count: int, deck: Dict[str, Any])""" + self._hooks.append(cb) + + def remove(self, cb: Callable[[int, Dict[str, Any]], int]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, count: int, deck: Dict[str, Any]) -> int: + for filter in self._hooks: + try: + count = filter(count, deck) + except: + # if the hook fails, remove it + self._hooks.remove(filter) + raise + return count + + +scheduler_new_limit_for_single_deck = _SchedulerNewLimitForSingleDeckFilter() + + +class _SchedulerReviewLimitForSingleDeckFilter: + """Allows changing the number of rev card for this deck (without + considering descendants).""" + + _hooks: List[Callable[[int, Dict[str, Any]], int]] = [] + + def append(self, cb: Callable[[int, Dict[str, Any]], int]) -> None: + """(count: int, deck: Dict[str, Any])""" + self._hooks.append(cb) + + def remove(self, cb: Callable[[int, Dict[str, Any]], int]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, count: int, deck: Dict[str, Any]) -> int: + for filter in self._hooks: + try: + count = filter(count, deck) + except: + # if the hook fails, remove it + self._hooks.remove(filter) + raise + return count + + +scheduler_review_limit_for_single_deck = _SchedulerReviewLimitForSingleDeckFilter() + + class _Schedv2DidAnswerReviewCardHook: _hooks: List[Callable[["anki.cards.Card", int, bool], None]] = [] diff --git a/pylib/anki/sched.py b/pylib/anki/sched.py index 0c7862782..258c48994 100644 --- a/pylib/anki/sched.py +++ b/pylib/anki/sched.py @@ -525,7 +525,8 @@ and due <= ? limit ?)""", if d["dyn"]: return self.reportLimit c = self.col.decks.confForDid(d["id"]) - return max(0, c["rev"]["perDay"] - d["revToday"][1]) + limit = max(0, c["rev"]["perDay"] - d["revToday"][1]) + return hooks.scheduler_review_limit_for_single_deck(limit, d) def _revForDeck(self, did: int, lim: int) -> int: # type: ignore[override] lim = min(lim, self.reportLimit) diff --git a/pylib/anki/schedv2.py b/pylib/anki/schedv2.py index 9c00e46ca..6a7a3c4cb 100644 --- a/pylib/anki/schedv2.py +++ b/pylib/anki/schedv2.py @@ -474,7 +474,8 @@ select count() from if g["dyn"]: return self.dynReportLimit c = self.col.decks.confForDid(g["id"]) - return max(0, c["new"]["perDay"] - g["newToday"][1]) + limit = max(0, c["new"]["perDay"] - g["newToday"][1]) + return hooks.scheduler_new_limit_for_single_deck(limit, g) def totalNewForCurrentDeck(self) -> int: return self.col.db.scalar( @@ -867,14 +868,12 @@ and due <= ? limit ?)""", lim = max(0, c["rev"]["perDay"] - d["revToday"][1]) if parentLimit is not None: - return min(parentLimit, lim) - elif "::" not in d["name"]: - return lim - else: + lim = min(parentLimit, lim) + elif "::" in d["name"]: for parent in self.col.decks.parents(d["id"]): # pass in dummy parentLimit so we don't do parent lookup again lim = min(lim, self._deckRevLimitSingle(parent, parentLimit=lim)) - return lim + return hooks.scheduler_review_limit_for_single_deck(lim, d) def _revForDeck(self, did: int, lim: int, childMap: Dict[int, Any]) -> Any: dids = [did] + self.col.decks.childDids(did, childMap) diff --git a/pylib/tools/genhooks.py b/pylib/tools/genhooks.py index 6cbe922dd..465a064cc 100644 --- a/pylib/tools/genhooks.py +++ b/pylib/tools/genhooks.py @@ -95,6 +95,20 @@ hooks = [ name="schedv2_did_answer_review_card", args=["card: anki.cards.Card", "ease: int", "early: bool"], ), + Hook( + name="scheduler_new_limit_for_single_deck", + args=["count: int", "deck: Dict[str, Any]"], + return_type="int", + doc="""Allows changing the number of new card for this deck (without + considering descendants).""", + ), + Hook( + name="scheduler_review_limit_for_single_deck", + args=["count: int", "deck: Dict[str, Any]"], + return_type="int", + doc="""Allows changing the number of rev card for this deck (without + considering descendants).""", + ), ] if __name__ == "__main__":