예제 #1
0
파일: notes.py 프로젝트: dae/anki
 def dupeOrEmpty(self):
     "1 if first is empty; 2 if first is a duplicate, False otherwise."
     val = self.fields[0]
     if not val.strip():
         return 1
     csum = fieldChecksum(val)
     # find any matching csums and compare
     for flds in self.col.db.list(
         "select flds from notes where csum = ? and id != ? and mid = ?", csum, self.id or 0, self.mid
     ):
         if stripHTMLMedia(splitFields(flds)[0]) == stripHTMLMedia(self.fields[0]):
             return 2
     return False
예제 #2
0
 def dupeOrEmpty(self):
     "1 if first is empty; 2 if first is a duplicate, False otherwise."
     val = self.fields[0]
     if not val.strip():
         return 1
     csum = fieldChecksum(val)
     # find any matching csums and compare
     for flds in self.col.db.list(
             "select flds from notes where csum = ? and id != ? and mid = ?",
             csum, self.id or 0, self.mid):
         if stripHTMLMedia(splitFields(flds)[0]) == stripHTMLMedia(
                 self.fields[0]):
             return 2
     return False
예제 #3
0
파일: editor.py 프로젝트: ACEfanatic02/anki
 def showDupes(self):
     contents = stripHTMLMedia(self.note.fields[0])
     browser = aqt.dialogs.open("Browser", self.mw)
     browser.form.searchEdit.lineEdit().setText(
         '"dupe:%s,%s"' % (self.note.model()['id'],
                           contents))
     browser.onSearch()
예제 #4
0
파일: find.py 프로젝트: Glutanimate/anki
def findDupes(col, fieldName, search=""):
    # limit search to notes with applicable field name
    if search:
        search = "("+search+") "
    search += "'%s:*'" % fieldName
    # go through notes
    vals = {}
    dupes = []
    fields = {}
    def ordForMid(mid):
        if mid not in fields:
            model = col.models.get(mid)
            for c, f in enumerate(model['flds']):
                if f['name'].lower() == fieldName.lower():
                    fields[mid] = c
                    break
        return fields[mid]
    for nid, mid, flds in col.db.all(
        "select id, mid, flds from notes where id in "+ids2str(
            col.findNotes(search))):
        flds = splitFields(flds)
        ord = ordForMid(mid)
        if ord is None:
            continue
        val = flds[ord]
        val = stripHTMLMedia(val)
        # empty does not count as duplicate
        if not val:
            continue
        if val not in vals:
            vals[val] = []
        vals[val].append(nid)
        if len(vals[val]) == 2:
            dupes.append((val, vals[val]))
    return dupes
예제 #5
0
    def findDupes(self,
                  fieldName: str,
                  search: str = "") -> List[Tuple[Any, list]]:
        nids = self.findNotes(search, SearchNode(field_name=fieldName))
        # go through notes
        vals: Dict[str, List[int]] = {}
        dupes = []
        fields: Dict[int, int] = {}

        def ordForMid(mid: int) -> int:
            if mid not in fields:
                model = self.models.get(mid)
                for c, f in enumerate(model["flds"]):
                    if f["name"].lower() == fieldName.lower():
                        fields[mid] = c
                        break
            return fields[mid]

        for nid, mid, flds in self.db.all(
                f"select id, mid, flds from notes where id in {ids2str(nids)}"
        ):
            flds = splitFields(flds)
            ord = ordForMid(mid)
            if ord is None:
                continue
            val = flds[ord]
            val = stripHTMLMedia(val)
            # empty does not count as duplicate
            if not val:
                continue
            vals.setdefault(val, []).append(nid)
            if len(vals[val]) == 2:
                dupes.append((val, vals[val]))
        return dupes
예제 #6
0
 def showDupes(self):
     contents = stripHTMLMedia(self.note.fields[0])
     browser = aqt.dialogs.open("Browser", self.mw)
     browser.form.searchEdit.lineEdit().setText(
         '"dupe:%s,%s"' % (self.note.model()['id'],
                           contents))
     browser.onSearchActivated()
예제 #7
0
파일: notes.py 프로젝트: wo4wangle/anki
    def flush(self, mod=None):
        """If fields or tags have changed, write changes to disk.


        If there exists a note with same id, tags and fields, and mod is not set, do nothing.
        Change the mod to given argument or current time
        Change the USNk
        If the not is not new, according to _preFlush, generate the cards
        Add its tag to the collection
        Add the note in the db

        Keyword arguments:
        mod -- A modification timestamp"""
        assert self.scm == self.col.scm
        self._preFlush()
        sfld = stripHTMLMedia(self.fields[self.col.models.sortIdx(self._model)])
        tags = self.stringTags()
        fields = self.joinedFields()
        if not mod and self.col.db.scalar(
            "select 1 from notes where id = ? and tags = ? and flds = ?",
            self.id, tags, fields):
            return
        csum = fieldChecksum(self.fields[0])
        self.mod = mod if mod else intTime()
        self.usn = self.col.usn()
        res = self.col.db.execute("""
insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)""",
                            self.id, self.guid, self.mid,
                            self.mod, self.usn, tags,
                            fields, sfld, csum, self.flags,
                            self.data)
        self.col.tags.register(self.tags)
        self._postFlush()
예제 #8
0
    def render_sections(self, template, context):
        """Expands sections."""
        while 1:
            match = self.section_re.search(template)
            if match is None:
                break

            section, section_name, inner = match.group(0, 1, 2)
            section_name = section_name.strip()

            # check for cloze
            val = None
            m = re.match(r"c[qa]:(\d+):(.+)", section_name)
            if m:
                # get full field text
                txt = get_or_attr(context, m.group(2), None)
                m = re.search(clozeReg%m.group(1), txt)
                if m:
                    val = m.group(1)
            else:
                val = get_or_attr(context, section_name, None)

            replacer = ''
            inverted = section[2] == "^"
            if val:
                val = stripHTMLMedia(val).strip()
            if (val and not inverted) or (not val and inverted):
                replacer = inner

            template = template.replace(section, replacer)

        return template
예제 #9
0
    def render_sections(self, template, context) -> str:
        """Expands sections."""
        while 1:
            match = self.section_re.search(template)
            if match is None:
                break

            section, section_name, inner = match.group(0, 1, 2)
            section_name = section_name.strip()

            # check for cloze
            val = None
            m = re.match(r"c[qa]:(\d+):(.+)", section_name)
            if m:
                # get full field text
                txt = get_or_attr(context, m.group(2), None)
                m = re.search(clozeReg % m.group(1), txt)
                if m:
                    val = m.group(CLOZE_REGEX_MATCH_GROUP_TAG)
            else:
                val = get_or_attr(context, section_name, None)

            replacer = ""
            inverted = section[2] == "^"
            if val:
                val = stripHTMLMedia(val).strip()
            if (val and not inverted) or (not val and inverted):
                replacer = inner

            template = template.replace(section, replacer)

        return template
예제 #10
0
파일: notes.py 프로젝트: dae/anki
    def flush(self, mod=None):
        "If fields or tags have changed, write changes to disk."
        assert self.scm == self.col.scm
        self._preFlush()
        sfld = stripHTMLMedia(self.fields[self.col.models.sortIdx(self._model)])
        tags = self.stringTags()
        fields = self.joinedFields()
        if not mod and self.col.db.scalar(
            "select 1 from notes where id = ? and tags = ? and flds = ?", self.id, tags, fields
        ):
            return
        csum = fieldChecksum(self.fields[0])
        self.mod = mod if mod else intTime()
        self.usn = self.col.usn()
        res = self.col.db.execute(
            """
insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)""",
            self.id,
            self.guid,
            self.mid,
            self.mod,
            self.usn,
            tags,
            fields,
            sfld,
            csum,
            self.flags,
            self.data,
        )
        self.col.tags.register(self.tags)
        self._postFlush()
예제 #11
0
def findDupes(col, fieldName, search="") -> List[Tuple[Any, List]]:
    # limit search to notes with applicable field name
    if search:
        search = "(" + search + ") "
    search += "'%s:*'" % fieldName
    # go through notes
    vals: Dict[str, List[int]] = {}
    dupes = []
    fields: Dict[int, int] = {}

    def ordForMid(mid):
        if mid not in fields:
            model = col.models.get(mid)
            for c, f in enumerate(model["flds"]):
                if f["name"].lower() == fieldName.lower():
                    fields[mid] = c
                    break
        return fields[mid]

    for nid, mid, flds in col.db.all(
        "select id, mid, flds from notes where id in " + ids2str(col.findNotes(search))
    ):
        flds = splitFields(flds)
        ord = ordForMid(mid)
        if ord is None:
            continue
        val = flds[ord]
        val = stripHTMLMedia(val)
        # empty does not count as duplicate
        if not val:
            continue
        vals.setdefault(val, []).append(nid)
        if len(vals[val]) == 2:
            dupes.append((val, vals[val]))
    return dupes
예제 #12
0
파일: editor.py 프로젝트: sinpat/anki
 def showDupes(self):
     contents = html.escape(stripHTMLMedia(self.note.fields[0]),
                            quote=False).replace('"', r"\"")
     browser = aqt.dialogs.open("Browser", self.mw)
     browser.form.searchEdit.lineEdit().setText(
         '"dupe:%s,%s"' % (self.note.model()["id"], contents))
     browser.onSearchActivated()
예제 #13
0
    def flush(self, mod: Optional[int] = None) -> None:
        "If fields or tags have changed, write changes to disk."
        assert self.scm == self.col.scm
        self._preFlush()
        sfld = stripHTMLMedia(self.fields[self.col.models.sortIdx(
            self._model)])
        tags = self.stringTags()
        fields = self.joinedFields()
        if not mod and self.col.db.scalar(
                "select 1 from notes where id = ? and tags = ? and flds = ?",
                self.id,
                tags,
                fields,
        ):
            return
        csum = fieldChecksum(self.fields[0])
        self.mod = mod if mod else intTime()
        self.usn = self.col.usn()
        res = self.col.db.execute(
            """
insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)""",
            self.id,
            self.guid,
            self.mid,
            self.mod,
            self.usn,
            tags,
            fields,
            sfld,
            csum,
            self.flags,
            self.data,
        )
        self.col.tags.register(self.tags)
        self._postFlush()
예제 #14
0
def sub_section(self, match, context):
    section, section_name, inner = match.group(0, 1, 2)
    section_name = section_name.strip()

    # val will contain the content of the field considered
    # right now
    val = None
    m = re.match("c[qa]:(\d+):(.+)", section_name)
    if m:
        # get full field text
        txt = get_or_attr(context, m.group(2), None)
        m = re.search(clozeReg % m.group(1), txt)
        if m:
            val = m.group(1)
    else:
        val = get_or_attr(context, section_name, None)
    replacer = ''
    # Whether it's {{^
    inverted = section[2] == "^"
    # Ensuring we don't consider whitespace in wval
    if val:
        val = stripHTMLMedia(val).strip()
    if (val and not inverted) or (not val and inverted):
        replacer = inner
    return replacer
예제 #15
0
    def flush(self, mod=None):
        "If fields or tags have changed, write changes to disk."
        assert self.scm == self.col.scm
        self.newlyAdded = (self.id is None)

        sfld = stripHTMLMedia(self.fields[self.col.models.sortIdx(
            self._model)])
        tags = self.stringTags()
        fields = self.joinedFields()
        if not mod and self.col.db.scalar(
                "select 1 from notes where id = ? and tags = ? and flds = ?",
                self.id, tags, fields):
            return
        csum = fieldChecksum(self.fields[0])
        self.mod = mod if mod else intTime()
        self.usn = self.col.usn()

        if self.id is None:
            self.id = timestampID(self.col.db, "notes")
            self.col.db.execute(
                """insert into notes values (?,?,?,?,?,?,?,?,?,?,?)""",
                self.id, self.guid, self.mid, self.mod, self.usn, tags, fields,
                sfld, csum, self.flags, self.data)
        else:
            self.col.db.execute(
                """update notes set guid=?, mid=?, mod=?, usn=?, tags=?, flds=?, sfld=?, csum=?, flags=?, data=?
                 where id = ?""", self.guid, self.mid, self.mod, self.usn,
                tags, fields, sfld, csum, self.flags, self.data, self.id)

        self.col.tags.register(self.tags)
        self._postFlush()
예제 #16
0
 def showDupes(self):
     contents = stripHTMLMedia(self.note.fields[0])
     browser = aqt.dialogs.open("Browser", self.mw)
     browser.form.searchEdit.lineEdit().setText(
         "'note:%s' '%s:%s'" %
         (self.note.model()['name'], self.note.model()['flds'][0]['name'],
          contents))
     browser.onSearch()
예제 #17
0
 def formatQA(self, txt):
     s = txt.replace("<br>", u" ")
     s = s.replace("<br />", u" ")
     s = s.replace("\n", u" ")
     s = re.sub("\[sound:[^]]+\]", "", s)
     s = stripHTMLMedia(s)
     s = s.strip()
     return s
예제 #18
0
 def formatQA(self, txt):
     s = txt.replace("<br>", u" ")
     s = s.replace("<br />", u" ")
     s = s.replace("\n", u" ")
     s = re.sub("\[sound:[^]]+\]", "", s)
     s = stripHTMLMedia(s)
     s = s.strip()
     return s
예제 #19
0
파일: editor.py 프로젝트: AidanJones/anki
 def showDupes(self):
     contents = stripHTMLMedia(self.note.fields[0])
     browser = aqt.dialogs.open("Browser", self.mw)
     browser.form.searchEdit.lineEdit().setText(
         "'note:%s' '%s:%s'" % (
             self.note.model()['name'],
             self.note.model()['flds'][0]['name'],
             contents))
     browser.onSearch()
예제 #20
0
def onGetSoundFile(editor):
    datasource.setConfig(get_config()['profiles'][mw.pm.name])
    word = stripHTMLMedia(getWordToLookup(editor))
    filename = datasource.lookup(word)
    if filename:
        if datasource.use_text_selection and editor.web.hasSelection():
            editor.web.triggerPageAction(QWebEnginePage.Unselect)
        editor.addMedia(filename)
    else:
        showWarning('{0}: no sound data found'.format(word, title='Sound Files'))
예제 #21
0
def htmlToTextLine(s):
    s = s.replace("<br>", " ")
    s = s.replace("<br />", " ")
    s = s.replace("<div>", " ")
    s = s.replace("\n", " ")
    s = re.sub("\[sound:[^]]+\]", "", s)
    s = re.sub("\[\[type:[^]]+\]\]", "", s)
    s = stripHTMLMedia(s)
    s = s.strip()
    return s
예제 #22
0
 def from_anki(cls, local_id):
     if is_remote_note(local_id):
         remote_id = get_remote_note_id(local_id)
     else:
         remote_id = None
     anki_note = mw.col.getNote(local_id)
     tags = anki_note.tags
     fields = anki_note.joinedFields()
     model_id = anki_note.mid
     sfld = stripHTMLMedia(anki_note.fields[anki_note.col.models.sortIdx(anki_note._model)])
     return cls(tags, fields, model_id, sfld, remote_id, local_id)
예제 #23
0
파일: facts.py 프로젝트: bmabey/libanki
 def setModified(self, textChanged=False):
     "Mark modified and update cards."
     self.modified = time.time()
     if textChanged:
         d = {}
         for f in self.model.fieldModels:
             d[f.name] = (f.id, self[f.name])
         self.spaceUntil = stripHTMLMedia(u" ".join([x[1] for x in d.values()]))
         for card in self.cards:
             qa = formatQA(None, self.modelId, d, card.splitTags(), card.cardModel)
             card.question = qa['question']
             card.answer = qa['answer']
             card.setModified()
예제 #24
0
파일: addcards.py 프로젝트: zachlungu/anki
 def onHistory(self):
     m = QMenu(self)
     for nid in self.history:
         if self.mw.col.findNotes("nid:%s" % nid):
             fields = self.mw.col.getNote(nid).fields
             txt = stripHTMLMedia(",".join(fields))[:30]
             a = m.addAction(_("Edit %s") % txt)
             a.triggered.connect(lambda b, nid=nid: self.editHistory(nid))
         else:
             a = m.addAction(_("(Note deleted)"))
             a.setEnabled(False)
     runHook("AddCards.onHistory", self, m)
     m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
예제 #25
0
def exportDeck():
    deckId = chooseDeck(prompt="Choose deck to export scheduling from")
    if deckId == 0:
        return
    cids = mw.col.decks.cids(deckId, children=False)
    cards = {}

    for cid in cids:
        card = mw.col.getCard(cid)
        note = mw.col.getNote(card.nid)
        sfld = stripHTMLMedia(note.fields[note.col.models.sortIdx(
            note._model)])
        # Skip new cards
        if card.queue == 0:
            continue
        if sfld in cards:
            showText("Card with duplicated field found; aborting.")
            return

        revlogKeys = ["id", "ease", "ivl", "lastIvl", "factor", "time", "type"]
        revlogsArray = mw.col.db.all(
            "select " + ", ".join(revlogKeys) + " from revlog " +
            "where cid = ?", cid)
        revlogsDict = list(
            map(
                lambda row:
                {revlogKeys[i]: row[i]
                 for i in range(0, len(revlogKeys))}, revlogsArray))

        cards[sfld] = dict(due=card.due,
                           queue=card.queue,
                           ivl=card.ivl,
                           factor=card.factor,
                           left=card.left,
                           type=card.type,
                           lapses=card.lapses,
                           reps=card.reps,
                           flags=card.flags,
                           revlogs=revlogsDict)

    file = getSaveFile(
        mw, "Export scheduling info to file", "anki-times", "JSON", ".json",
        re.sub('[\\\\/?<>:*|"^]', '_', mw.col.decks.name(deckId)) +
        "-scheduling")
    if not file:
        return

    output = {"meta": {"crt": mw.col.crt}, "cards": cards}

    with open(file, "w") as f:
        json.dump(output, f, ensure_ascii=False)
예제 #26
0
 def updateFieldCache(self, nids):
     "Update field checksums and sort cache, after find&replace, etc."
     snids = ids2str(nids)
     r = []
     for (nid, mid, flds) in self._fieldData(snids):
         fields = splitFields(flds)
         model = self.models.get(mid)
         if not model:
             # note points to invalid model
             continue
         r.append((stripHTMLMedia(fields[self.models.sortIdx(model)]),
                   fieldChecksum(fields[0]), nid))
     # apply, relying on calling code to bump usn+mod
     self.db.executemany("update notes set sfld=?, csum=? where id=?", r)
예제 #27
0
 def _findDupes(self, val):
     # caller must call stripHTMLMedia on passed val
     try:
         mid, val = val.split(",", 1)
     except OSError:
         return
     csum = fieldChecksum(val)
     nids = []
     for nid, flds in self.col.db.execute(
             "select id, flds from notes where mid=? and csum=?", mid,
             csum):
         if stripHTMLMedia(splitFields(flds)[0]) == val:
             nids.append(nid)
     return "n.id in %s" % ids2str(nids)
예제 #28
0
파일: find.py 프로젝트: fingul/anki
 def _findDupes(self, val):
     # caller must call stripHTMLMedia on passed val
     try:
         mid, val = val.split(",", 1)
     except OSError:
         return
     csum = fieldChecksum(val)
     nids = []
     for nid, flds in self.col.db.execute(
             "select id, flds from notes where mid=? and csum=?",
             mid, csum):
         if stripHTMLMedia(splitFields(flds)[0]) == val:
             nids.append(nid)
     return "n.id in %s" % ids2str(nids)
예제 #29
0
def dupeOrEmptyWithOrds(self):
    """
    Returns a tuple. The contents of each element are as follows:

    1) 1 if first is empty; 2 if first is a duplicate, False otherwise.
    2) For a duplicate (2), this returns the list of ordinals that make up the key.
       Otherwise this is None.
    """

    val = self.fields[0]
    if not val.strip():
        return 1, None
    csum = fieldChecksum(val)
    # find any matching csums and compare
    for flds in self.col.db.list(
            "select flds from notes where csum = ? and id != ? and mid = ?",
            csum, self.id or 0, self.mid):

        model = self.model()
        field_ords = [0]
        for fld in model["flds"]:
            if fld["ord"] == 0:
                continue
            elif fld["name"].endswith(KEY_SUFFIX):
                field_ords.append(fld["ord"])

        all_fields_equal = True
        fields_split = splitFields(flds)
        for field_ord in field_ords:
            if stripHTMLMedia(fields_split[field_ord]) != stripHTMLMedia(
                    self.fields[field_ord]):
                all_fields_equal = False

        if all_fields_equal:
            return 2, field_ords

    return False, None
예제 #30
0
def showDupes(self):
    """
    Shows the duplicates for the current note in the editor by conducting a search in the browser.

    This basically performs the normal dupes search that Anki does but appends additional search
    terms for other keys that have the _pk suffix.
    """

    contents = stripHTMLMedia(self.note.fields[0])
    browser = aqt.dialogs.open("Browser", self.mw)

    model = self.note.model()

    # Find other notes with the same content for the first field.
    search_cmds = ['"dupe:%s,%s"' % (model['id'], contents)]

    # If any other field names end in the special suffix, then they are considered part of the "key"
    # that uniquely identifies a note.  Search for notes that have the same content for these fields,
    # in addition to having the first field match.
    for fld in model["flds"]:
        # First field is already filtered on by the dupe check.
        if fld["ord"] == 0:
            continue
        elif fld["name"].endswith(KEY_SUFFIX):
            term = stripHTMLMedia(self.note.fields[fld["ord"]])
            cmd_args = (fld["name"], term)
            if '"' in term and "'" in term:
                # ignore, unfortunately we can't search for it
                pass
            elif '"' in term:
                search_cmds.append("%s:'%s'" % cmd_args)
            else:
                search_cmds.append("%s:\"%s\"" % cmd_args)

    browser.form.searchEdit.lineEdit().setText(" ".join(search_cmds))
    browser.onSearchActivated()
예제 #31
0
 def updateFieldCache(self, nids):
     "Update field checksums and sort cache, after find&replace, etc."
     snids = ids2str(nids)
     r = []
     for (nid, mid, flds) in self._fieldData(snids):
         fields = splitFields(flds)
         model = self.models.get(mid)
         if not model:
             # note points to invalid model
             continue
         r.append((stripHTMLMedia(fields[self.models.sortIdx(model)]),
                   fieldChecksum(fields[0]),
                   nid))
     # apply, relying on calling code to bump usn+mod
     self.db.executemany("update notes set sfld=?, csum=? where id=?", r)
예제 #32
0
파일: notes.py 프로젝트: AidanJones/anki
    def flush(self, mod=None):
        assert self.scm == self.col.scm
        self._preFlush()
        self.mod = mod if mod else intTime()
        self.usn = self.col.usn()
        sfld = stripHTMLMedia(self.fields[self.col.models.sortIdx(self._model)])
        tags = self.stringTags()
        csum = fieldChecksum(self.fields[0])
        res = self.col.db.execute("""
insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)""",
                            self.id, self.guid, self.mid,
                            self.mod, self.usn, tags,
                            self.joinedFields(), sfld, csum, self.flags,
                            self.data)
        self.col.tags.register(self.tags)
        self._postFlush()
예제 #33
0
 def setModified(self, textChanged=False, deck=None, media=True):
     "Mark modified and update cards."
     self.modified = time.time()
     if textChanged:
         if not deck:
             # FIXME: compat code
             import ankiqt
             if not getattr(ankiqt, 'setModWarningShown', None):
                 import sys; sys.stderr.write(
                     "plugin needs to pass deck to fact.setModified()")
                 ankiqt.setModWarningShown = True
             deck = ankiqt.mw.deck
         assert deck
         self.spaceUntil = stripHTMLMedia(u" ".join(
             self.values()))
         for card in self.cards:
             card.rebuildQA(deck)
예제 #34
0
def swap_meaning_and_extra_info():
    note = current_note_in_review()
    if not note or MEANING not in note or EXTRA_INFO not in note:
        return
    meaning = note[MEANING]
    extra_info = note[EXTRA_INFO]

    if levenshtein(stripHTMLMedia(meaning), PRACTICE_SENTENCE) < 5:
        # PRACTICE SENTENCE!!!!
        note[MEANING] = extra_info
        note[EXTRA_INFO] = ""
    else:
        note[MEANING] = extra_info
        note[EXTRA_INFO] = meaning

    note.flush()
    reshow_card()
예제 #35
0
def allSearch(note):
    model = note.model()
    sortIdx = note.col.models.sortIdx(model)
    fields = note.fields
    allfields = [stripHTMLMedia(field) for field in fields]
    sfields = [
        allfields[idx] for idx in range(len(fields))
        if idx != sortIdx and allfields[idx] != fields[idx]
    ]
    if allfields[sortIdx] != fields[sortIdx] or getUserOption(
            "sort field", True):
        firstField = [allfields[sortIdx]]
    else:
        firstField = []
    sfields = firstField + sfields
    sfield = " ".join(sfields)
    changeSfield(note, sfield)
예제 #36
0
 def setModified(self, textChanged=False, deck=None, media=True):
     "Mark modified and update cards."
     self.modified = time.time()
     if textChanged:
         if not deck:
             # FIXME: compat code
             import ankiqt
             if not getattr(ankiqt, 'setModWarningShown', None):
                 import sys
                 sys.stderr.write(
                     "plugin needs to pass deck to fact.setModified()")
                 ankiqt.setModWarningShown = True
             deck = ankiqt.mw.deck
         assert deck
         self.spaceUntil = stripHTMLMedia(u" ".join(self.values()))
         for card in self.cards:
             card.rebuildQA(deck)
예제 #37
0
    def extract_field(model_id, field_name) -> Iterable[Tuple[int, str]]:
        # type works better in future anki
        model = self.models.get(model_id)
        assert model  # type is optional, but None should never come back

        note_ids = self.findNotes(" ".join(search_filters +
                                           [f'note:{model["name"]}']))

        field_ord: int = next(field["ord"] for field in model["flds"]
                              if field["name"] == field_name)

        assert self.db

        for note_id, fields in self.db.all(
                "select id, flds from notes where id in " + ids2str(note_ids)):
            value = splitFields(fields)[field_ord]
            yield note_id, stripHTMLMedia(value)
예제 #38
0
    def render_sections(self, template, context):
        """Expands sections."""
        while 1:
            match = self.section_re.search(template)
            if match is None:
                break

            section, section_name, inner = match.group(0, 1, 2)
            section_name = section_name.strip()

            # check for cloze
            m = re.match("c[qa]:(\d+):(.+)", section_name)
            if m:
                # get full field text
                txt = get_or_attr(context, m.group(2), None)
                m = re.search(clozeReg % m.group(1), txt)
                if m:
                    it = m.group(1)
                else:
                    it = None
            else:
                it = get_or_attr(context, section_name, None)

            replacer = ''
            # if it and isinstance(it, collections.Callable):
            #     replacer = it(inner)
            if isinstance(it, basestring):
                it = stripHTMLMedia(it).strip()
            if it and not hasattr(it, '__iter__'):
                if section[2] != '^':
                    replacer = inner
            elif it and hasattr(it, 'keys') and hasattr(it, '__getitem__'):
                if section[2] != '^':
                    replacer = self.render(inner, it)
            elif it:
                insides = []
                for item in it:
                    insides.append(self.render(inner, item))
                replacer = ''.join(insides)
            elif not it and section[2] == '^':
                replacer = inner

            template = template.replace(section, replacer)

        return template
예제 #39
0
    def render_sections(self, template, context):
        """Expands sections."""
        while 1:
            match = self.section_re.search(template)
            if match is None:
                break

            section, section_name, inner = match.group(0, 1, 2)
            section_name = section_name.strip()

            # check for cloze
            m = re.match("c[qa]:(\d+):(.+)", section_name)
            if m:
                # get full field text
                txt = get_or_attr(context, m.group(2), None)
                m = re.search(clozeReg%m.group(1), txt)
                if m:
                    it = m.group(1)
                else:
                    it = None
            else:
                it = get_or_attr(context, section_name, None)

            replacer = ''
            # if it and isinstance(it, collections.Callable):
            #     replacer = it(inner)
            if isinstance(it, basestring):
                it = stripHTMLMedia(it).strip()
            if it and not hasattr(it, '__iter__'):
                if section[2] != '^':
                    replacer = inner
            elif it and hasattr(it, 'keys') and hasattr(it, '__getitem__'):
                if section[2] != '^':
                    replacer = self.render(inner, it)
            elif it:
                insides = []
                for item in it:
                    insides.append(self.render(inner, item))
                replacer = ''.join(insides)
            elif not it and section[2] == '^':
                replacer = inner

            template = template.replace(section, replacer)

        return template
예제 #40
0
def createNote(deck, model, fields):
    m = _find_model(model)
    m['did'] = _find_deck(deck)
    
    note = Note(mw.col, m)
    _set_fields(note, fields)
    mw.col.addNote(note)
    
    duplicateOrEmpty = note.dupeOrEmpty()
    if duplicateOrEmpty == 1:
        raise Exception('cannot create note because it is empty')
    elif duplicateOrEmpty == 2:
        key = m['flds'][0]['name']
        value = stripHTMLMedia(fields[key]) if key in fields else ''
        raise DuplicateException('"{0}" note already exists for "{1}"'.format(model, value))
    elif duplicateOrEmpty == False:
        return
    else:
        raise Exception('cannot create note for unknown reason')
예제 #41
0
def get_data(editor):
    ""

    ""

    # get word from current field
    word = stripHTMLMedia(editor.note.fields[editor.currentField])

    clean_word = _normalize_word(word)

    audio_file = save_audio(clean_word)
    if (audio_file == None):
        showWarning(
            'Vocabolaudio: no information found for the word: {}'.format(word))
        return

    editor.addMedia(audio_file)

    for field in editor.note.keys():
        if field == 'Audio' and audio_file != None:
            editor.note[field] = str('[sound:{}.{}]'.format(clean_word, 'mp3'))
            editor.note.flush()

    mw.reset()
예제 #42
0
    def render_sections(self, template, context):
        """replace {{#foo}}bar{{/foo}} and {{^foo}}bar{{/foo}} by
        their normal value."""
        while 1:
            match = self.section_re.search(template)
            if match is None:
                break

            section, section_name, inner = match.group(0, 1, 2)
            section_name = section_name.strip()

            # val will contain the content of the field considered
            # right now
            val = None
            m = re.match(r"c[qa]:(\d+):(.+)", section_name)
            if m:
                # get full field text
                txt = get_or_attr(context, m.group(2), None)
                m = re.search(clozeReg % m.group(1), txt)
                if m:
                    val = m.group(1)
            else:
                val = get_or_attr(context, section_name, None)

            replacer = ''
            # Whether it's {{^
            inverted = section[2] == "^"
            # Ensuring we don't consider whitespace in wval
            if val:
                val = stripHTMLMedia(val).strip()
            if (val and not inverted) or (not val and inverted):
                replacer = inner

            template = template.replace(section, replacer)

        return template
예제 #43
0
파일: find.py 프로젝트: nickgieschen/anki
            except sre_constants.error:
                return
        if not nids:
            return "0"
        return "n.id in %s" % ids2str(nids)

    def _findDupes(self, (val, args)):
        # caller must call stripHTMLMedia on passed val
        try:
            mid, val = val.split(",", 1)
        except OSError:
            return
        csum = fieldChecksum(val)
        nids = []
        for nid, flds in self.col.db.execute("select id, flds from notes where mid=? and csum=?", mid, csum):
            if stripHTMLMedia(splitFields(flds)[0]) == val:
                nids.append(nid)
        return "n.id in %s" % ids2str(nids)


# Find and replace
##########################################################################


def findReplace(col, nids, src, dst, regex=False, field=None, fold=True):
    "Find and replace fields in a note."
    mmap = {}
    if field:
        for m in col.models.all():
            for f in m["flds"]:
                if f["name"] == field:
예제 #44
0
파일: addcards.py 프로젝트: kchien/ankiqt
 def addHistory(self, note):
     txt = stripHTMLMedia(",".join(note.fields))[:30]
     self.history.append((note.id, txt))
     self.history = self.history[-15:]
     self.historyButton.setEnabled(True)
예제 #45
0
def _copyScheduling(deckFrom, deckTo):
    now = intTime()
    logs = []
    cids = mw.col.decks.cids(deckTo["id"], children=False)
    copiedN = 0
    updates = []
    
    for cid in cids:
        card = mw.col.getCard(cid)
        note = mw.col.getNote(card.nid)
        sfld = stripHTMLMedia(note.fields[note.col.models.sortIdx(note._model)])
        sourceCids = mw.col.db.list(
            "select distinct(c.id) from cards c, notes n where c.nid=n.id and c.did=? and n.sfld=?",
            deckFrom["id"],
            sfld
        )
        
        # If there are no source cards, skip
        if not sourceCids:
            continue
        if len(sourceCids) > 1:
            logs.append("Multiple source cards not supported. Matched field={0}".format(sfld))
            continue
        sourceCid = sourceCids[0]
        sourceCard = mw.col.getCard(sourceCid)
        # Skip new cards
        if sourceCard.queue == 0:
            continue

        logs.append("Matched card {0}".format(sfld))
        
        updates.append(dict(
            cid=cid,
            due=sourceCard.due,
            queue=sourceCard.queue,
            ivl=sourceCard.ivl,
            factor=sourceCard.factor,
            left=sourceCard.left,
            type=sourceCard.type,
            now=now,
            usn=mw.col.usn()
        ))

        def copyRevlog(offset):
            mw.col.db.execute(
                "insert into revlog "
                "select r.id + :offset, :newcid, :usn, r.ease, r.ivl, r.lastIvl, r.factor, r.time, r.type "
                "from revlog as r "
                "where cid=:oldcid",
                offset=offset,
                oldcid=sourceCid,
                newcid=cid,
                usn=mw.col.usn()
            )
        for i in range(0, MAX_RETRIES + 1):
            try:
                copyRevlog(2 << i)
                break
            except:
                if i == MAX_RETRIES:
                    raise

        copiedN += 1

    #logs.append("updates {0}".format(updates))

    mw.col.db.executemany(
        "update cards set "
        "due=:due, mod=:now, usn=:usn, queue=:queue, "
        "ivl=:ivl, factor=:factor, left=:left, type=:type "
        "where id=:cid",
        updates
    )
    
    logs.append("Copied {0} cards".format(copiedN))

    showText("\n".join(logs), title="Copy scheduling log")
    mw.reset()
예제 #46
0
파일: addcards.py 프로젝트: samba6/ankiqt
 def addHistory(self, note):
     txt = stripHTMLMedia(",".join(note.fields))[:30]
     self.history.insert(0, (note.id, txt))
     self.history = self.history[:15]
     self.historyButton.setEnabled(True)
예제 #47
0
    def deck_notes(self, did):
        import re, os
        from anki import utils

        #afx = AnkiFx(self.col)
        #cids = afx.did2cids(did=did)
        cids = self.cids(did, utils)

        components = self.col.split(os.sep)
        mediadir = ('/'.join(components[:-1]) + '/collection.media')

        nids = []
        for cid in cids:
            card = self.card_spec('nid', cid=cid)
            nids.append(card[0])

        notes = []
        for nid in nids:

            ndict = {
                'nid': None,
                'flds': None,
                'tags': None,
                'mid': None,
                'mname': None,
                'img': None
            }

            # note info for each note id
            note = self.note_info(nid=nid)

            # readable note fields, strip HTML
            flds = filter(None, note['flds'].split('\x1f'))
            m = lambda i: [
                re.findall('src="([^"]+)"', f, re.DOTALL) for f in i
            ]
            img = [x[0] for x in m(flds) if x]
            f = lambda x: [utils.stripHTMLMedia(i) for i in x]
            flds = f(flds)

            #f = lambda x: [utils.stripHTMLMedia(i) for i in x]
            #flds = f(filter(None, note['flds'].split('\x1f')))

            # from note model id, retrieve model fields
            mid = str(note['mid'])

            #model = afx.did2cids(mid=mid)
            model = self.model_info(mid=mid)

            # get field names for model
            mflds = [mfld['name'] for mfld in model['flds']]

            ndict['nid'] = nid
            #ndict['flds']  = (' '.join(flds)).encode('utf-8')
            ndict['flds'] = flds
            ndict['tags'] = note['tags']
            ndict['mid'] = mid
            ndict['mname'] = model['name']
            if img:
                ndict['img'] = '{}/{}'.format(mediadir, img[0])

            notes.append(ndict)

        return notes
예제 #48
0
def importMedia(self, mime, _old):
    """import audios and images from goldendict"""

    # find out where we are
    if dialogs._dialogs['AddCards'][1]:
        # we are adding cards
        window = dialogs._dialogs['AddCards'][1]
    elif dialogs._dialogs['Browser'][1]:
        # we are browsing cards
        window = dialogs._dialogs['Browser'][1]
    elif dialogs._dialogs['EditCurrent'][1]:
        # we are editing cards
        window = dialogs._dialogs['EditCurrent'][1]
    else:
        # I don't know where we are, just exit
        return _old(self, mime) 

    html = mime.html()
    soup = BeautifulSoup(html)
    newMime = QMimeData()
    addressMap = Setup.config['addressMap']

    # sound
    links = [link for link in soup.findAll('a') if 'gdau' in link['href']]

    # images
    links += [link for link in soup.findAll('img') if 'bres' in link['src']]


    for link in links:
        if link.get('href'):
            # audio
            attr = 'href'
        elif link.get('src'):
            # image
            attr = 'src'
        else:
            # something else, I don't know, at least not 
            # something we're looking for, skip
            continue

        goldenPath = link.get(attr)
        matchObj = re.search(r'(?<=(gdau|bres)://)[^/\\]*', goldenPath)
        if not matchObj:
            continue
        code = matchObj.group(0)
        if code not in addressMap:
            # new media
            filename = os.path.basename(goldenPath)
            res = addNewMedia(code, filename)
            if not res:
                # media import failed, continue to
                # process the next link
                continue

        # get the full path of the media file
        prefix = re.search(r'^(gdau|bres)://[^/\\]*', goldenPath).group(0)
        filePath = link[attr].replace(prefix, addressMap[code])

        # import the file to anki
        ankiMedia = window.editor._addMedia(filePath, canDelete=True)
        # sound
        if attr == 'href': 
            span = link.parent
            # delete the original link, 
            # because we don't need it any more
            del link
            # append ankiMedia
            span.string = ankiMedia

        # images
        else:
            img = BeautifulSoup(ankiMedia)
            link.replaceWith(img)

    html = str(soup).decode('utf8')

    # assign the modified html to new Mime
    newMime = QMimeData()
    newMime.setHtml(html)

    # set text so the addon is able to work even when StripHTML is on
    newMime.setText(stripHTMLMedia(html))

    # default _processHtml method
    return _old(self, newMime)