Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import anki
- import anki.sched
- import time
- import random
- import itertools
- from operator import itemgetter
- from heapq import *
- #from anki.cards import Card
- from anki.utils import ids2str, intTime, fmtTimeSpan
- from anki.lang import _
- from anki.consts import *
- from anki.hooks import runHook
- from aqt import mw
- addon_config = mw.addonManager.getConfig(__name__)
- if not addon_config:
- addon_config = {
- "change_sched_v1": True,
- "disable_again_ease_change": True,
- "override_max_review_cards": True,
- "reset_ease": True,
- "answer_button_overhaul": True,
- "force_minimum_failure_interval_factor": 20,
- }
- # force_minimum_failure_interval_factor
- def v1_lapseConf(self, card):
- conf = self._cardConf(card)
- # normal deck
- if not card.odid:
- return conf['lapse']
- # dynamic deck; override some attributes, use original deck for others
- oconf = self.col.decks.confForDid(card.odid)
- delays = conf['delays'] or oconf['lapse']['delays']
- return dict(
- # original deck
- minInt=oconf['lapse']['minInt'],
- leechFails=oconf['lapse']['leechFails'],
- leechAction=oconf['lapse']['leechAction'],
- mult=max(addon_config['force_minimum_failure_interval_factor'], oconf['lapse']['mult']), #####################
- # overrides
- delays=delays,
- resched=conf['resched'],
- )
- # reset_ease
- def v1_answerRevCard(self, card, ease):
- delay = 0
- if ease == 1:
- delay = self._rescheduleLapse(card)
- else:
- self._rescheduleRev(card, ease)
- if addon_config['reset_ease']: #####################
- conf = self._newConf(card)
- card.factor = conf['initialFactor']
- self._logRev(card, ease, delay)
- # disable_again_ease_change
- def v1_rescheduleLapse(self, card):
- conf = self._lapseConf(card)
- card.lastIvl = card.ivl
- if self._resched(card):
- card.lapses += 1
- card.ivl = self._nextLapseIvl(card, conf)
- if not addon_config['disable_again_ease_change']: #####################
- card.factor = max(1300, card.factor-200)
- card.due = self.today + card.ivl
- # if it's a filtered deck, update odue as well
- if card.odid:
- card.odue = card.due
- # if suspended as a leech, nothing to do
- delay = 0
- if self._checkLeech(card, conf) and card.queue == -1:
- return delay
- # if no relearning steps, nothing to do
- if not conf['delays']:
- return delay
- # record rev due date for later
- if not card.odue:
- card.odue = card.due
- delay = self._delayForGrade(conf, 0)
- card.due = int(delay + time.time())
- card.left = self._startingLeft(card)
- # queue 1
- if card.due < self.dayCutoff:
- self.lrnCount += card.left // 1000
- card.queue = 1
- heappush(self._lrnQueue, (card.due, card.id))
- else:
- # day learn queue
- ahead = ((card.due - self.dayCutoff) // 86400) + 1
- card.due = self.today + ahead
- card.queue = 3
- return delay
- # override_max_review_cards
- def v1_deckRevLimitSingle(self, d):
- if d['dyn']:
- return self.reportLimit
- c = self.col.decks.confForDid(d['id'])
- if addon_config['override_max_review_cards']: ###############
- return max(0, 9999 - d['revToday'][1])
- else:
- return max(0, c['rev']['perDay'] - d['revToday'][1])
- # override_max_review_cards
- def v1_groupChildrenMain(self, grps):
- tree = []
- # group and recurse
- def key(grp):
- return grp[0][0]
- for (head, tail) in itertools.groupby(grps, key=key):
- tail = list(tail)
- did = None
- rev = 0
- new = 0
- lrn = 0
- children = []
- for c in tail:
- if len(c[0]) == 1:
- # current node
- did = c[1]
- rev += c[2]
- lrn += c[3]
- new += c[4]
- else:
- # set new string to tail
- c[0] = c[0][1:]
- children.append(c)
- children = self._groupChildrenMain(children)
- # tally up children counts
- for ch in children:
- rev += ch[2]
- lrn += ch[3]
- new += ch[4]
- # limit the counts to the deck's limits
- conf = self.col.decks.confForDid(did)
- deck = self.col.decks.get(did)
- if not conf['dyn']:
- if addon_config['override_max_review_cards']: ###############
- rev = max(0, min(rev, 9999-deck['revToday'][1]))
- else:
- rev = max(0, min(rev, conf['rev']['perDay']-deck['revToday'][1]))
- new = max(0, min(new, conf['new']['perDay']-deck['newToday'][1]))
- tree.append((head, did, rev, lrn, new, children))
- return tuple(tree)
- # answer_button_overhaul
- def v1_answerButtons(self, card):
- if card.odue:
- # normal review in dyn deck?
- if card.odid and card.queue == 2:
- if addon_config['answer_button_overhaul']: ###############
- return 2
- else:
- return 4
- conf = self._lrnConf(card)
- if card.type in (0,1) or len(conf['delays']) > 1:
- return 3
- return 2
- elif card.queue == 2:
- if addon_config['answer_button_overhaul']: ###############
- return 2
- else:
- return 4
- else:
- return 3
- # answer_button_overhaul
- def v1_answerLrnCard(self, card, ease):
- ##############
- if addon_config['answer_button_overhaul'] and card.left == self._startingLeft(card) and ease == 1:
- ease = 2
- ##############
- # ease 1=no, 2=yes, 3=remove
- conf = self._lrnConf(card)
- if card.odid and not card.wasNew:
- type = 3
- elif card.type == 2:
- type = 2
- else:
- type = 0
- leaving = False
- # lrnCount was decremented once when card was fetched
- lastLeft = card.left
- # immediate graduate?
- if ease == 3:
- self._rescheduleAsRev(card, conf, True)
- leaving = True
- # graduation time?
- elif ease == 2 and (card.left%1000)-1 <= 0:
- self._rescheduleAsRev(card, conf, False)
- leaving = True
- else:
- # one step towards graduation
- if ease == 2:
- # decrement real left count and recalculate left today
- left = (card.left % 1000) - 1
- card.left = self._leftToday(conf['delays'], left)*1000 + left
- # failed
- else:
- card.left = self._startingLeft(card)
- resched = self._resched(card)
- if 'mult' in conf and resched:
- # review that's lapsed
- card.ivl = max(1, conf['minInt'], card.ivl*conf['mult'])
- else:
- # new card; no ivl adjustment
- pass
- if resched and card.odid:
- card.odue = self.today + 1
- delay = self._delayForGrade(conf, card.left)
- if card.due < time.time():
- # not collapsed; add some randomness
- delay *= random.uniform(1, 1.25)
- card.due = int(time.time() + delay)
- # due today?
- if card.due < self.dayCutoff:
- self.lrnCount += card.left // 1000
- # if the queue is not empty and there's nothing else to do, make
- # sure we don't put it at the head of the queue and end up showing
- # it twice in a row
- card.queue = 1
- if self._lrnQueue and not self.revCount and not self.newCount:
- smallestDue = self._lrnQueue[0][0]
- card.due = max(card.due, smallestDue+1)
- heappush(self._lrnQueue, (card.due, card.id))
- else:
- # the card is due in one or more days, so we need to use the
- # day learn queue
- ahead = ((card.due - self.dayCutoff) // 86400) + 1
- card.due = self.today + ahead
- card.queue = 3
- self._logLrn(card, ease, conf, leaving, type, lastLeft)
- # answer_button_overhaul
- def v1_nextLrnIvl(self, card, ease):
- if card.queue == 0:
- card.left = self._startingLeft(card)
- ##############
- if addon_config['answer_button_overhaul'] and card.left == self._startingLeft(card) and ease == 1:
- ease = 2
- ##############
- conf = self._lrnConf(card)
- if ease == 1:
- # fail
- return self._delayForGrade(conf, len(conf['delays']))
- elif ease == 3:
- # early removal
- if not self._resched(card):
- return 0
- return self._graduatingIvl(card, conf, True, adj=False) * 86400
- else:
- left = card.left%1000 - 1
- if left <= 0:
- # graduate
- if not self._resched(card):
- return 0
- return self._graduatingIvl(card, conf, False, adj=False) * 86400
- else:
- return self._delayForGrade(conf, left)
- # answer_button_overhaul
- def v1_nextRevIvl(self, card, ease):
- "Ideal next interval for CARD, given EASE."
- delay = self._daysLate(card)
- conf = self._revConf(card)
- fct = card.factor / 1000
- if addon_config['answer_button_overhaul']: ################
- interval = self._constrainedIvl((card.ivl + delay // 2) * fct, conf, card.ivl)
- else:
- ivl2 = self._constrainedIvl((card.ivl + delay // 4) * 1.2, conf, card.ivl)
- ivl3 = self._constrainedIvl((card.ivl + delay // 2) * fct, conf, ivl2)
- ivl4 = self._constrainedIvl(
- (card.ivl + delay) * fct * conf['ease4'], conf, ivl3)
- if ease == 2:
- interval = ivl2
- elif ease == 3:
- interval = ivl3
- elif ease == 4:
- interval = ivl4
- return min(interval, conf['maxIvl'])
- if addon_config['change_sched_v1']:
- # override_max_review_cards
- anki.sched.Scheduler._deckRevLimitSingle = v1_deckRevLimitSingle
- anki.sched.Scheduler._groupChildrenMain = v1_groupChildrenMain
- # disable_again_ease_change
- anki.sched.Scheduler._rescheduleLapse = v1_rescheduleLapse
- # reset_ease
- anki.sched.Scheduler._answerRevCard = v1_answerRevCard
- # force_minimum_failure_interval_factor
- anki.sched.Scheduler._lapseConf = v1_lapseConf
- # answer_button_overhaul
- anki.sched.Scheduler.answerButtons = v1_answerButtons
- anki.sched.Scheduler._answerLrnCard = v1_answerLrnCard
- anki.sched.Scheduler._nextLrnIvl = v1_nextLrnIvl
- anki.sched.Scheduler._nextRevIvl = v1_nextRevIvl
Advertisement
Add Comment
Please, Sign In to add comment