Exemple #1
0
 def _style(self):
     from anki import version
     style = '* {font-family: sans-serif; }'
     if version.startswith('2.0.'):
         return style
     style += 'td { font-size: 80%; }'
     return style
    def _style(self):
        from anki import version
        anki_version = int(version.replace('.', ''))
        if anki_version > 2119:
            from aqt.theme import theme_manager
        config = mw.addonManager.getConfig(__name__)
        sidebar_theme = config['Card Info sidebar_ theme']
        sidebar_font = config['Card Info sidebar_ Font']
        from . import styles
        dark_styles = styles.dark
        light_styles = styles.light
        if anki_version > 2119:
            if sidebar_theme == 2:
                mystyle = dark_styles
            elif sidebar_theme == 1:
                mystyle = light_styles
            else:
                if theme_manager.night_mode:
                    mystyle = dark_styles
                else:
                    mystyle = light_styles
        else:
            if sidebar_theme == 2:
                mystyle = dark_styles
            else:
                mystyle = light_styles

        from anki import version
        if version.startswith("2.0."):
            return ""
        return mystyle + "td { font-size: 75%; font-family:" + "{}".format(
            sidebar_font) + ";}"
Exemple #3
0
def todayStats_old(self):
    """We need to overwrite the entire method to change the mature ivl"""
    b = self._title(_("Today"))
    # studied today
    lim = self._revlogLimit()
    if lim:
        lim = " and " + lim
    cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first(
        """
select count(), sum(time)/1000,
sum(case when ease = 1 then 1 else 0 end), /* failed */
sum(case when type = 0 then 1 else 0 end), /* learning */
sum(case when type = 1 then 1 else 0 end), /* review */
sum(case when type = 2 then 1 else 0 end), /* relearn */
sum(case when type = 3 then 1 else 0 end) /* filter */
from revlog where id > ? """ + lim, (self.col.sched.dayCutoff - 86400) * 1000)
    cards = cards or 0
    thetime = thetime or 0
    failed = failed or 0
    lrn = lrn or 0
    rev = rev or 0
    relrn = relrn or 0
    filt = filt or 0
    # studied
    if anki_version.startswith("2.0."):

        def bold(s):
            return "<b>" + unicode(s) + "</b>"
    else:

        def bold(s):
            return "<b>" + str(s) + "</b>"

    msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards",
                     cards) % cards
    b += _("Studied %(a)s in %(b)s today.") % dict(
        a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1)))
    # again/pass count
    b += "<br>" + _("Again count: %s") % bold(failed)
    if cards:
        b += " " + _("(%s correct)") % bold("%0.1f%%" % (
            (1 - failed / float(cards)) * 100))
    # type breakdown
    b += "<br>"
    b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s") %
          dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt)))
    # mature today
    mcnt, msum = self.col.db.first(
        """
select count(), sum(case when ease = 1 then 0 else 1 end) from revlog
where lastIvl >= %d and id > ?""" % MATURE_IVL + lim,
        (self.col.sched.dayCutoff - 86400) * 1000)
    b += "<br>"
    if mcnt:
        b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)"
               ) % dict(a=msum, b=mcnt, c=(msum / float(mcnt) * 100))
    else:
        b += _("No mature cards were studied today.")
    return b
    def showDebugInfo():
        from aqt import mw
        from anki import version as anki_version
        from aqt.utils import showInfo, showText

        txt = """
    <h2>Bug Status: Affected</h2>

    <p>It seems like your system is affected by a module import bug.</p>

    <p>To report your findings, please copy the debug info below and post it 
    <a href="https://anki.tenderapp.com/discussions/add-ons/35343">here</a>. 
    (no account needed).
    Feel free to uninstall "Import Bug Test" once you're done</p>

    <p>Thanks so much for your help in tracking this issue down!</p>

    <p><b>Debug info</b>:</p>
    """
        txt += "<div style='white-space: pre-wrap'>"

        if not anki_version.startswith("2.0"):
            from aqt.utils import supportText
            txt += "\n" + supportText() + "\n"
            addmgr = mw.addonManager
            txt += "Add-ons:\n\n" + "\n".join(
                addmgr.annotatedName(d) for d in addmgr.allAddons()) + "\n\n"
        else:
            from aqt import appVersion
            from aqt.qt import QT_VERSION_STR, PYQT_VERSION_STR
            txt += '<p>' + "Version %s" % appVersion + '\n'
            txt += ("Qt %s PyQt %s\n\n") % (QT_VERSION_STR, PYQT_VERSION_STR)
            txt += "Add-ons:\n\n" + repr(mw.addonManager.files()) + "\n\n"

        txt += "Import Errors:\n\n"
        txt += "\n\n".join(error[0] + ":\n" + error[1] for error in errors)

        txt += "</div>"

        kwargs = dict(title="Import Bug Test", type="html")

        if not anki_version.startswith("2.0"):
            kwargs["copyBtn"] = True

        showText(txt, **kwargs)
def todayStats_old(self):
    """We need to overwrite the entire method to change the mature ivl"""
    b = self._title(_("Today"))
    # studied today
    lim = self._revlogLimit()
    if lim:
        lim = " and " + lim
    cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first("""
select count(), sum(time)/1000,
sum(case when ease = 1 then 1 else 0 end), /* failed */
sum(case when type = 0 then 1 else 0 end), /* learning */
sum(case when type = 1 then 1 else 0 end), /* review */
sum(case when type = 2 then 1 else 0 end), /* relearn */
sum(case when type = 3 then 1 else 0 end) /* filter */
from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000)
    cards = cards or 0
    thetime = thetime or 0
    failed = failed or 0
    lrn = lrn or 0
    rev = rev or 0
    relrn = relrn or 0
    filt = filt or 0
    # studied
    if anki_version.startswith("2.0."):
        def bold(s):
            return "<b>"+unicode(s)+"</b>"
    else:
        def bold(s):
            return "<b>"+str(s)+"</b>"
    msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards
    b += _("Studied %(a)s in %(b)s today.") % dict(
        a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1)))
    # again/pass count
    b += "<br>" + _("Again count: %s") % bold(failed)
    if cards:
        b += " " + _("(%s correct)") % bold(
            "%0.1f%%" %((1-failed/float(cards))*100))
    # type breakdown
    b += "<br>"
    b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s")
          % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt)))
    # mature today
    mcnt, msum = self.col.db.first("""
select count(), sum(case when ease = 1 then 0 else 1 end) from revlog
where lastIvl >= %d and id > ?""" % MATURE_IVL +lim, (self.col.sched.dayCutoff-86400)*1000)
    b += "<br>"
    if mcnt:
        b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)") % dict(
            a=msum, b=mcnt, c=(msum / float(mcnt) * 100))
    else:
        b += _("No mature cards were studied today.")
    return b
Exemple #6
0
############## USER CONFIGURATION START ##############

# These settings only apply to Anki 2.0. For Anki 2.1 please use
# Anki's built-in add-on configuration menu

HOTKEY_TOGGLE_LIST = "Alt+Shift+L"

##############  USER CONFIGURATION END  ##############

from aqt import editor, mw
from anki.hooks import wrap, addHook

from anki import version

ANKI21 = version.startswith("2.1")

if ANKI21:
    config = mw.addonManager.getConfig(__name__)
    HOTKEY_TOGGLE_LIST = config["hotkeyToggleList"]

editor_style = """
<style>
ul.shuffle{
    background-color: yellow;
}
</style>
"""


def toggleRandUl(self):
Exemple #7
0
# -*- coding: utf-8 -*-
# Copyright: (C) 2018-2020 Lovac42
# Support: https://github.com/lovac42/ReMemorize
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html

from anki import version
CCBC = version.endswith("ccbc")
ANKI21 = version.startswith("2.1.") and not CCBC

BROWSER_TAG = "_reschedule" if ANKI21 else "reschedule"
from __future__ import (absolute_import, division,
                        print_function, unicode_literals)

############## USER CONFIGURATION START ##############

STRIP_TAGS = ['b', 'i', 'u']  # list of html tags to remove

##############  USER CONFIGURATION END  ##############

from aqt.qt import *
from aqt import mw
from aqt.utils import tooltip
from anki.hooks import addHook
from anki import version as anki_version

if anki_version.startswith("2.1"):
    from bs4 import BeautifulSoup
    ANKI21 = True
else:
    from BeautifulSoup import BeautifulSoup
    ANKI21 = False


def stripFormatting(fields):
    """
    Uses BeautifulSoup to remove STRIP_TAGS from each string in
    supplied list.

    Parameters
    ----------
    fields : list of strings
from anki import version

assert version.startswith("2.1.")
minor_ver = int(version.split(".")[-1])

COMPAT = {
    # backend.find_and_replace
    "find_replace": minor_ver >= 27,
    # media.write_data()
    "write_data": minor_ver >= 22
}

from . import editor
    "Default": 2,  # show 1 new card every 2 days in "Default" deck
    u"Very Slöw": 7  # deck names with unicode need to be prepended with u
}

option_limits = {
    "hard": 5,
    "Chapter": 2,
}
#In ANKI21, you can edit the options in the configuration manager,
#instead of here. Thus, the configurations will be kept when the
#add-on is updated.

##############  USER CONFIGURATION END  ##############
from anki import version as anki_version
import aqt
anki21 = anki_version.startswith("2.1.")
if anki21:
    userOption = aqt.mw.addonManager.getConfig(__name__)
    deck_limits.update(userOption["deck limits"])
    option_limits.update(userOption["option limits"])

from anki.sched import Scheduler
from anki.schedv2 import Scheduler as SchedulerV2


def debug(t):
    print(t)
    pass


def myDeckNewLimitSingle(self, g):
# Unix (Linux/macOS)
external_handler_unix = r"notify-send"

##############  USER CONFIGURATION END  ##############

import subprocess
import re

from aqt.utils import tooltip
from aqt.reviewer import Reviewer
from anki.hooks import wrap, addHook

from anki.utils import isWin

from anki import version as anki_version
anki21 = anki_version.startswith("2.1.")

pycmd = "pycmd" if anki21 else "py.link"

regex_link = r"(qv.+?\..+?\b(#\b.+?\b)?)"
replacement = r"""<a href='' class="flink" onclick='{}("open:\1");return false;'>\1</a>""".format(pycmd)


def openFileHandler(file):
    try:
        if isWin:
            external_handler = external_handler_win
        else:
            external_handler = external_handler_unix
        subprocess.Popen([external_handler, file])
    except OSError:
Exemple #12
0
    # Remove that annoying separator strip if we have Night Mode, avoiding conflicts with this add-on.
    import Night_Mode

    Night_Mode.nm_css_menu \
        += Night_Mode.nm_css_menu \
           + '''
        QMainWindow::separator
    {
        width: 0px;
        height: 0px;
    }
    '''
except ImportError:
    nmUnavailable = 1

useOldAnkiAPI = anki_version.startswith("2.0.") or (
    anki_version.startswith("2.1.") and int(anki_version.split(".")[-1]) < 28)


def initPB() -> None:
    """Initialize and set parameters for progress bar, adding it to the dock."""
    global progressBar
    progressBar = QProgressBar()
    progressBar.setTextVisible(showPercent or showNumber)
    progressBar.setInvertedAppearance(invertTF)
    progressBar.setOrientation(orientationHV)
    if pbdStyle is None:
        progressBar.setStyleSheet('''
                QProgressBar
                {
                    text-align:center;
Exemple #13
0
     // Cloze Overlapper support
     if (typeof olToggle === "function") { 
         olToggle();
     }
     // Image Occlusion Enhanced support
     var ioBtn = document.getElementById("io-revl-btn");
     if (!(typeof ioBtn === 'undefined' || !ioBtn)) { 
         ioBtn.click();
     }
     for (var i=0; i<arr.length; i++) {
        var l=arr[i];
        if (l.style.display === 'none') {
          continue;
        }
        if (l.href.charAt(l.href.length-1) === '#') {
          l.dispatchEvent(customEvent);
          if ('%s' === 'True') {
            break;
          }
        }
     }
     """ % incremental)


# Hooks and Patches

if ankiversion.startswith("2.0"):  # 2.0.x
    Reviewer._keyHandler = wrap(Reviewer._keyHandler, _newKeyHandler, "around")
else:  # 2.1.x
    addHook("reviewStateShortcuts", _addShortcuts)
Exemple #14
0
    for check_ivl in range(min_ivl, max_ivl + 1):
        num_cards = self.col.db.scalar(
            """select count() from cards where due = ? and queue = 2""",
            self.today + check_ivl)
        if num_cards < lowest_num_cards_in_range:
            acceptable_ivls = [check_ivl]
            lowest_num_cards_in_range = num_cards
        elif num_cards == lowest_num_cards_in_range:
            acceptable_ivls.append(check_ivl)
            min_num_cards = num_cards
        else:
            log_debug("  ")
        log_debug(
            "check_ivl {0:<4} num_cards {1:<4} acceptable_ivls {2}\n".format(
                check_ivl, num_cards, acceptable_ivls))
    best_ivl = choice(acceptable_ivls)
    log_info(
        "{0:<28} orig_ivl {1:<4} min_ivl {2:<4} max_ivl {3:<4} acceptable_ivls {4}\n best_ivl {5:<4}"
        .format(str(datetime.datetime.now()), orig_ivl, min_ivl, max_ivl,
                acceptable_ivls, best_ivl))
    return best_ivl


# Patch Anki 2.0 and Anki 2.1 default scheduler
anki.sched.Scheduler._fuzzedIvl = load_balanced_ivl

# Patch Anki 2.1 experimental v2 scheduler
if version.startswith("2.1"):
    from anki.schedv2 import Scheduler
    anki.schedv2.Scheduler._fuzzedIvl = load_balanced_ivl
# -*- coding: utf-8 -*-

"""
This file is part of the Image Occlusion Enhanced add-on for Anki.

Global variables

Copyright: (c) 2018 Glutanimate <https://glutanimate.com/>
License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl.html>
"""

import sys
import os
from anki import version

ANKI21 = version.startswith("2.1.")
SYS_ENCODING = sys.getfilesystemencoding()

if ANKI21:
    ADDON_PATH = os.path.dirname(__file__)
else:
    ADDON_PATH = os.path.dirname(__file__).decode(SYS_ENCODING)

ICONS_PATH = os.path.join(ADDON_PATH, "icons")
Exemple #16
0
# -*- coding: utf-8 -*-
# Copyright: (C) 2019-2020 Lovac42
# Support: https://github.com/lovac42/Hashworth
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html


from aqt import mw

from anki import version
CCBC = version.endswith("ccbc")
ANKI21 = not CCBC and version.startswith("2.1.")
ANKI20 = version.startswith("2.0.")

ADDONNAME = "Hashworth"

TITLE = "Hashworth: Field Duplicate Finder"

DEFAULT_HOTKEY = "Ctrl+Shift+H"
Note: For debugging, use either sys.stderr.write() or aqt.utils.showInfo().
"""

import sys
import os
import aqt

from anki import version
from anki.hooks import addHook, wrap
from aqt import editor, browser, reviewer, utils, mw

from .symbol_manager import SymbolManager
from .browser_replacer import BrowserReplacer
from .symbol_window import SymbolWindow

ANKI_VER_21 = version.startswith("2.1.")
SYS_ENCODING = sys.getfilesystemencoding()

if ANKI_VER_21:
    ADDON_PATH = os.path.dirname(__file__)
else:
    ADDON_PATH = os.path.dirname(__file__).decode(SYS_ENCODING)


""" Keeps track of all WebViews with symbol replacement Javascript. """
ins_sym_webviews = {
    "editors": [],
    "reviewer": None
}

def _update_JS(webview):
 def _style(self):
     from anki import version
     if version.startswith("2.0."):
         return ""
     return "td { font-size: 80%; }"
    if getMX() >= 1:
        if mx > getMX():
            _updatePB()
        else:
            mx = getMX()
            progressBar.setRange(0, mx)
            progressBar.reset()
    else:
        progressBar.setValue(mx)


addHook("afterStateChange", _renderBar)
addHook("showQuestion", _updatePB)

if anki_version.startswith("2.0.x"):
    """Workaround for QSS issue in EditCurrent,
    only necessary on Anki 2.0.x"""

    from aqt.editcurrent import EditCurrent

    def changeStylesheet(*args):
        mw.setStyleSheet('''
            QMainWindow::separator
        {
            width: 0px;
            height: 0px;
        }
        ''')

    def restoreStylesheet(*args):
Exemple #20
0
 def _style(self):
     from anki import version
     if version.startswith("2.0."):
         return ""
     return "td { font-size: 80%; }"
Exemple #21
0
lapsed = '_ansfeed_lapsed.png'
# image for passed cards
passed = '_ansfeed_passed.png'

##############  USER CONFIGURATION END  ##############

__version__ = "1.1.0"

from aqt.reviewer import Reviewer
from anki.hooks import addHook, wrap
from aqt import mw
from aqt.qt import *
import shutil, os

from anki import version
ANKI20 = version.startswith("2.0")

folder = 'images'


def imgLoad():
    lp = [lapsed, passed]
    for p in lp:
        pth = os.path.join(mw.col.media.dir(), p)
        if not os.path.exists(pth):
            shutil.copy(
                os.path.join(mw.pm.addonFolder(), "visual_feedback", folder,
                             p), p)


addHook("profileLoaded", imgLoad)
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

############## USER CONFIGURATION START ##############

STRIP_TAGS = ['b', 'i', 'u']  # list of html tags to remove

##############  USER CONFIGURATION END  ##############

from aqt.qt import *
from aqt import mw
from aqt.utils import tooltip
from anki.hooks import addHook
from anki import version as anki_version

if anki_version.startswith("2.1"):
    from bs4 import BeautifulSoup
    ANKI21 = True
else:
    from BeautifulSoup import BeautifulSoup
    ANKI21 = False


def stripFormatting(fields):
    """
    Uses BeautifulSoup to remove STRIP_TAGS from each string in
    supplied list.

    Parameters
    ----------
    fields : list of strings
Exemple #23
0
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import os
import tempfile

from aqt.qt import *
from aqt.utils import tooltip, askUser, getFile

from anki.hooks import addHook
from anki.lang import _
from anki import version as anki_version

from .gui import initializeQtResources

ANKI20 = anki_version.startswith("2.0")
unicode = str if not ANKI20 else unicode

initializeQtResources()


class BatchEditDialog(QDialog):
    """Browser batch editing dialog"""
    def __init__(self, browser, nids):
        QDialog.__init__(self, parent=browser)
        self.browser = browser
        self.nids = nids
        self._setupUi()

    def _setupUi(self):
        tlabel = QLabel("Content to add to or replace with:")

from pprint import pprint as pp

from anki import version
from anki.hooks import addHook
from anki.lang import getLang
from anki.sched import Scheduler as schedv1
from anki.utils import ids2str, intTime

from aqt import mw
from aqt.utils import showInfo, tooltip
from aqt.qt import *


anki20 = version.startswith("2.0.")
if not anki20:
    from anki.schedv2 import Scheduler as schedv2
German = getLang() == "de"


def my_burySiblings(self, card):
    toBury = []
    nconf = self._newConf(card)
    buryNew = nconf.get("bury", True)
    rconf = self._revConf(card)
    buryRev = rconf.get("bury", True)
    # loop through and remove from queues
    for cid, queue in self.col.db.execute("""
select id, queue from cards where nid=? and id!=?
and (queue=0 or (queue=2 and due<=?))""",
Exemple #25
0
#Based on    | xquercus code, in add-on "Load Balanced Scheduler"
#License     | GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
#Source in   | https://github.com/cjdduarte/Free_Weekend_Load_Balancer

# LOG_LEVEL = 0  Disables logging.
# LOG_LEVEL = 1  Logs a one line summary each time a card is load balanced.
# LOG_LEVEL = 2  Logs additional detailed information about each step of the load balancing process.
LOG_LEVEL = 0

import sys
import anki
import datetime
from aqt import mw

from anki import version
ANKI21 = version.startswith("2.1.")

from anki.sched import Scheduler
from aqt.utils import tooltip

import aqt
import aqt.deckconf
from anki.hooks import wrap

if ANKI21:
    from PyQt5 import QtCore, QtGui, QtWidgets
else:
    from PyQt4 import QtCore, QtGui as QtWidgets
#from random import *
#seed()
Exemple #26
0
import aqt
from aqt.qt import *
from aqt import mw

from aqt.overview import Overview
from aqt.deckbrowser import DeckBrowser
from aqt.stats import DeckStats
from aqt.webview import AnkiWebView
from aqt.utils import restoreGeom, maybeHideClose, addCloseShortcut

from anki.stats import CollectionStats
from anki.find import Finder
from anki.hooks import wrap, addHook

from anki import version as anki_version
isAnki20 = anki_version.startswith("2.0.")

from .config import *
from .html import (heatmap_boilerplate, streak_css, streak_div, heatmap_css,
                   heatmap_div, heatmap_script, ov_body)

### Stats and Heatmap generation ###


def report_activity(self, limhist, limfcst, smode=False):
    """Calculate stats and generate report"""
    #self is anki.stats.CollectionStats
    config = mw.col.conf["heatmap"]
    limhist = None if limhist == 0 else limhist
    limfcst = None if limfcst == 0 else limfcst
    # get data