From ffd02733a99fd0069c06fc052128ea8943ad3658 Mon Sep 17 00:00:00 2001 From: Jarrett Ye Date: Mon, 22 Apr 2024 22:24:39 +0800 Subject: [PATCH] Feat/disperse siblings after reschedule (#393) --- __init__.py | 18 +++++++++++++-- config.json | 3 ++- configuration.py | 22 +++++++++++++----- schedule/disperse_siblings.py | 2 +- schedule/reschedule.py | 42 +++++++++++++++++++++++++---------- sync_hook.py | 3 +++ 6 files changed, 68 insertions(+), 22 deletions(-) diff --git a/__init__.py b/__init__.py index 657c2f4..15a36a4 100644 --- a/__init__.py +++ b/__init__.py @@ -89,7 +89,7 @@ def set_auto_disperse_after_sync(checked, _): def set_auto_disperse_when_review(checked, _): - config.auto_disperse = checked + config.auto_disperse_when_review = checked menu_auto_disperse = checkable( @@ -97,6 +97,16 @@ def set_auto_disperse_when_review(checked, _): ) +def set_auto_disperse_after_reschedule(checked, _): + config.auto_disperse_after_reschedule = checked + + +menu_auto_disperse_after_reschedule = checkable( + title="Disperse siblings after rescheduling (breaks Load Balance)", + on_click=set_auto_disperse_after_reschedule, +) + + def set_display_memory_state(checked, _): config.display_memory_state = checked @@ -145,6 +155,7 @@ def reschedule_recent(did): menu_for_helper.addAction(menu_auto_disperse) menu_for_helper.addAction(menu_display_memory_state) menu_for_helper.addAction(menu_load_balance) +menu_for_helper.addAction(menu_auto_disperse_after_reschedule) menu_for_easy_days = menu_for_helper.addMenu( "Less Anki on Easy Days (requires Load Balancing)" ) @@ -228,9 +239,12 @@ def adjust_menu(): ) menu_auto_reschedule_after_sync.setChecked(config.auto_reschedule_after_sync) menu_auto_disperse_after_sync.setChecked(config.auto_disperse_after_sync) - menu_auto_disperse.setChecked(config.auto_disperse) + menu_auto_disperse.setChecked(config.auto_disperse_when_review) menu_display_memory_state.setChecked(config.display_memory_state) menu_load_balance.setChecked(config.load_balance) + menu_auto_disperse_after_reschedule.setChecked( + config.auto_disperse_after_reschedule + ) menu_for_auto_easy_days.setChecked(config.auto_easy_days) menu_for_easy_0.setChecked(0 in config.easy_days) menu_for_easy_1.setChecked(1 in config.easy_days) diff --git a/config.json b/config.json index de29f03..fe82c2e 100644 --- a/config.json +++ b/config.json @@ -5,7 +5,8 @@ "days_to_reschedule": 7, "auto_reschedule_after_sync": false, "auto_disperse_after_sync": false, - "auto_disperse": false, + "auto_disperse_when_review": false, + "auto_disperse_after_reschedule": false, "mature_ivl": 21, "debug_notify": false, "fsrs_stats": true, diff --git a/configuration.py b/configuration.py index da7bb31..cd7a9b9 100644 --- a/configuration.py +++ b/configuration.py @@ -8,7 +8,8 @@ DAYS_TO_RESCHEDULE = "days_to_reschedule" AUTO_RESCHEDULE_AFTER_SYNC = "auto_reschedule_after_sync" AUTO_DISPERSE_AFTER_SYNC = "auto_disperse_after_sync" -AUTO_DISPERSE = "auto_disperse" +AUTO_DISPERSE_WHEN_REVIEW = "auto_disperse_when_review" +AUTO_DISPERSE_AFTER_RESCHEDULE = "auto_disperse_after_reschedule" MATURE_IVL = "mature_ivl" DEBUG_NOTIFY = "debug_notify" FSRS_STATS = "fsrs_stats" @@ -95,12 +96,21 @@ def auto_disperse_after_sync(self, value): self.save() @property - def auto_disperse(self): - return self.data[AUTO_DISPERSE] + def auto_disperse_when_review(self): + return self.data[AUTO_DISPERSE_WHEN_REVIEW] - @auto_disperse.setter - def auto_disperse(self, value): - self.data[AUTO_DISPERSE] = value + @auto_disperse_when_review.setter + def auto_disperse_when_review(self, value): + self.data[AUTO_DISPERSE_WHEN_REVIEW] = value + self.save() + + @property + def auto_disperse_after_reschedule(self): + return self.data[AUTO_DISPERSE_AFTER_RESCHEDULE] + + @auto_disperse_after_reschedule.setter + def auto_disperse_after_reschedule(self, value): + self.data[AUTO_DISPERSE_AFTER_RESCHEDULE] = value self.save() @property diff --git a/schedule/disperse_siblings.py b/schedule/disperse_siblings.py index 0774e7b..37a240c 100644 --- a/schedule/disperse_siblings.py +++ b/schedule/disperse_siblings.py @@ -210,7 +210,7 @@ def disperse_siblings_when_review(reviewer, card: Card, ease): config = Config() config.load() - if not config.auto_disperse: + if not config.auto_disperse_when_review: return siblings = get_siblings_when_review(card) diff --git a/schedule/reschedule.py b/schedule/reschedule.py index 3adee7a..6707877 100644 --- a/schedule/reschedule.py +++ b/schedule/reschedule.py @@ -1,4 +1,6 @@ from aqt import QAction, browser + +from .disperse_siblings import disperse_siblings from ..utils import * from ..configuration import Config from anki.cards import Card, FSRSMemoryState @@ -140,9 +142,18 @@ def reschedule( start_time = time.time() def on_done(future): - mw.progress.finish() - tooltip(f"{future.result()} in {time.time() - start_time:.2f} seconds") - mw.reset() + config = Config() + config.load() + if config.auto_disperse_after_reschedule: + finish_text, filtered_nid_string = future.result() + mw.progress.finish() + mw.reset() + disperse_siblings(did, True, filtered_nid_string, finish_text) + else: + finish_text = future.result() + mw.progress.finish() + tooltip(f"{finish_text} in {time.time() - start_time:.2f} seconds") + mw.reset() fut = mw.taskman.run_in_background( lambda: reschedule_background( @@ -189,14 +200,15 @@ def reschedule_background( if filter_flag: filter_query = f"AND id IN {ids2str(filtered_cids)}" - cards = mw.col.db.all( + cid_did_nid = mw.col.db.all( f""" SELECT id, CASE WHEN odid==0 THEN did ELSE odid - END + END, + nid FROM cards WHERE queue IN ({QUEUE_TYPE_LRN}, {QUEUE_TYPE_REV}, {QUEUE_TYPE_DAY_LEARN_RELEARN}) {did_query if did is not None else ""} @@ -205,16 +217,16 @@ def reschedule_background( ORDER BY ivl """ ) - total_cnt = len(cards) + total_cnt = len(cid_did_nid) undo_entry = mw.col.add_custom_undo_entry("Reschedule") mw.taskman.run_on_main( lambda: mw.progress.start(label="Rescheduling", max=total_cnt, immediate=False) ) # x[0]: cid # x[1]: did - # x[2]: desired retention - # x[3]: max interval - # x[4]: weights + # x[2]: nid + # x[3]: desired retention + # x[4]: max interval cards = map( lambda x: ( x @@ -223,11 +235,11 @@ def reschedule_background( DM.config_dict_for_deck_id(x[1])["rev"]["maxIvl"], ] ), - cards, + cid_did_nid, ) cnt = 0 cancelled = False - for cid, _, desired_retention, maximum_interval in cards: + for cid, _, _, desired_retention, maximum_interval in cards: if cancelled: break fsrs.desired_retention = desired_retention @@ -249,7 +261,13 @@ def reschedule_background( if mw.progress.want_cancel(): cancelled = True - return f"{cnt} cards rescheduled" + finish_text = f"{cnt} cards rescheduled" + + if config.auto_disperse_after_reschedule: + filtered_nid_string = ids2str(set(map(lambda x: x[2], cid_did_nid))) + return (finish_text, filtered_nid_string) + + return finish_text def reschedule_card(cid, fsrs: FSRS, recompute=False): diff --git a/sync_hook.py b/sync_hook.py index 90f8c7a..4ad82f6 100644 --- a/sync_hook.py +++ b/sync_hook.py @@ -59,6 +59,9 @@ def auto_disperse(local_rids: List[int], texts: List[str]): if not config.auto_disperse_after_sync: return + if config.auto_reschedule_after_sync and config.auto_disperse_after_reschedule: + return + remote_reviewed_cids = review_cid_remote(local_rids) remote_reviewed_cid_string = ids2str(remote_reviewed_cids) remote_reviewed_nids = [