示例#1
0
    def localSummary(self):
        cardIds = self.cardIds()
        cStrIds = ids2str(cardIds)
        cards = self.deck.db.all("""
select id, modified from cards
where id in %s""" % cStrIds)
        notes = self.deck.db.all("""
select notes.id, notes.modified from cards, notes where
notes.id = cards.noteId and
cards.id in %s""" % cStrIds)
        models = self.deck.db.all("""
select models.id, models.modified from models, notes where
notes.modelId = models.id and
notes.id in %s""" % ids2str([f[0] for f in notes]))
        media = self.deck.db.all("""
select id, modified from media""")
        return {
            # cards
            "cards": cards,
            "delcards": [],
            # notes
            "notes": notes,
            "delnotes": [],
            # models
            "models": models,
            "delmodels": [],
            # media
            "media": media,
            "delmedia": [],
            }
示例#2
0
    def _findField(self, token, isNeg):
        field = value = ''
        parts = token.split(':', 1);
        field = parts[0].lower()
        value = "%" + parts[1].replace("*", "%") + "%"
        # find models that have that field
        mods = {}
        for m in self.col.models.all():
            for f in m['flds']:
                if f['name'].lower() == field:
                    mods[str(m['id'])] = (m, f['ord'])
        if not mods:
            # nothing has that field
            self.lims['valid'] = False
            return
        # gather nids
        regex = value.replace("_", ".").replace("%", ".*")
        nids = []
        for (id,mid,flds) in self.col.db.execute("""
select id, mid, flds from notes
where mid in %s and flds like ? escape '\\'""" % (
                         ids2str(mods.keys())),
                         "%" if self.full else value):
            flds = splitFields(flds)
            ord = mods[str(mid)][1]
            strg = flds[ord]
            if self.full:
                strg = stripHTML(strg)
            if re.search(regex, strg):
                nids.append(id)
        extra = "not" if isNeg else ""
        self.lims['preds'].append("""
n.mid in %s and n.id %s in %s""" % (
    ids2str(mods.keys()), extra, ids2str(nids)))
示例#3
0
文件: sync.py 项目: bhutley/libanki
 def rewriteIds(self, remote):
     "Rewrite local IDs so they don't conflict with server version."
     conf = simplejson.loads(remote['deck'][9])
     # cards
     id = self.deck.db.scalar(
         "select min(id) from cards where crt > ?", self.deck.lastSync)
     if id < conf['nextCid']:
         diff = conf['nextCid'] - id
         ids = self.deck.db.list(
             "select id from cards where crt > ?", self.deck.lastSync)
         sids = ids2str(ids)
         self.deck.db.execute(
             "update revlog set cid = cid + ? where cid in "+sids,
             diff)
         self.deck.db.execute(
             "update cards set id = id + ? where id in "+sids,
             diff)
     # facts
     id = self.deck.db.scalar(
         "select min(id) from facts where crt > ?", self.deck.lastSync)
     if id < conf['nextFid']:
         diff = conf['nextFid'] - id
         ids = self.deck.db.list(
             "select id from facts where crt > ?", self.deck.lastSync)
         sids = ids2str(ids)
         self.deck.db.execute(
             "update fsums set fid = fid + ? where fid in "+sids,
             diff)
         self.deck.db.execute(
             "update facts set id = id + ? where id in "+sids,
             diff)
示例#4
0
    def doExport(self, file):
        cardIds = self.cardIds()
        notes = self.deck.db.all("""
select noteId, value, notes.created from notes, fields
where
notes.id in
(select distinct noteId from cards
where cards.id in %s)
and notes.id = fields.noteId
order by noteId, ordinal""" % ids2str(cardIds))
        txt = ""
        if self.includeTags:
            self.noteTags = dict(self.deck.db.all(
                "select id, tags from notes where id in %s" %
                ids2str([note[0] for note in notes])))
        groups = itertools.groupby(notes, itemgetter(0))
        groups = [[x for x in y[1]] for y in groups]
        groups = [(group[0][2],
                   "\t".join([self.escapeText(x[1]) for x in group]) +
                   self.tags(group[0][0]))
                  for group in groups]
        groups.sort(key=itemgetter(0))
        out = [ret[1] for ret in groups]
        self.count = len(out)
        out = "\n".join(out)
        file.write(out.encode("utf-8"))
        self.deck.finishProgress()
示例#5
0
    def localSummary(self):
        cardIds = self.cardIds()
        cStrIds = ids2str(cardIds)
        cards = self.deck.s.all("""
select id, modified from cards
where id in %s""" % cStrIds)
        facts = self.deck.s.all("""
select facts.id, facts.modified from cards, facts where
facts.id = cards.factId and
cards.id in %s""" % cStrIds)
        models = self.deck.s.all("""
select models.id, models.modified from models, facts where
facts.modelId = models.id and
facts.id in %s""" % ids2str([f[0] for f in facts]))
        media = self.deck.s.all("""
select id, created from media""")
        return {
            # cards
            "cards": cards,
            "delcards": [],
            # facts
            "facts": facts,
            "delfacts": [],
            # models
            "models": models,
            "delmodels": [],
            # media
            "media": media,
            "delmedia": [],
            }
示例#6
0
 def _addFlagFieldsForTemplate(self, m, nids, tmpl):
     cids = self.col.db.list(
         "select id from cards where nid in %s and ord = ?" %
         ids2str(nids), tmpl['ord'])
     if len(cids) == len(nids):
         # not selectively used
         return
     # add a flag field
     name = tmpl['name']
     have = [f['name'] for f in m['flds']]
     while name in have:
         name += "_"
     f = self.col.models.newField(name)
     self.col.models.addField(m, f)
     # find the notes that have that card
     haveNids = self.col.db.list(
         "select nid from cards where id in "+ids2str(cids))
     # add "y" to the appended field for those notes
     self.col.db.execute(
         "update notes set flds = flds || 'y' where id in "+ids2str(
             haveNids))
     # wrap the template in a conditional
     tmpl['qfmt'] = "{{#%s}}\n%s\n{{/%s}}" % (
         f['name'], tmpl['qfmt'], f['name'])
     return True
示例#7
0
    def _findField(self, field, val):
        field = field.lower()
        val = val.replace("*", "%")
        # find models that have that field
        mods = {}
        for m in self.col.models.all():
            for f in m['flds']:
                if f['name'].lower() == field:
                    mods[str(m['id'])] = (m, f['ord'])
        if not mods:
            # nothing has that field
            return
        # gather nids
        regex = val.replace("_", ".").replace("%", ".*")
        nids = []
        for (id,mid,flds) in self.col.db.execute("""
select id, mid, flds from notes
where mid in %s and flds like ? escape '\\'""" % (
                         ids2str(mods.keys())),
                         "%"+val+"%"):
            flds = splitFields(flds)
            ord = mods[str(mid)][1]
            strg = flds[ord]
            try:
                if re.search("(?i)^"+regex+"$", strg):
                    nids.append(id)
            except sre_constants.error:
                return
        if not nids:
            return
        return "n.id in %s" % ids2str(nids)
示例#8
0
文件: find.py 项目: ChYi/libanki
    def _findField(self, token, isNeg):
        field = value = ''
        parts = token.split(':', 1);
        field = parts[0].lower()
        value = "%" + parts[1].replace("*", "%") + "%"
        # find models that have that field
        mods = {}
        for m in self.deck.models().values():
            for f in m.fields:
                if f['name'].lower() == field:
                    mods[m.id] = (m, f['ord'])
        if not mods:
            # nothing has that field
            self.lims['valid'] = False
            return
        # gather fids
        regex = value.replace("%", ".*")
        fids = []
        for (id,mid,flds) in self.deck.db.execute("""
select id, mid, flds from facts
where mid in %s and flds like ? escape '\\'""" % (
                         ids2str(mods.keys())),
                         "%" if self.full else value):
            flds = splitFields(flds)
            ord = mods[mid][1]
            str = flds[ord]
            if self.full:
                str = stripHTML(str)
            if re.search(regex, str):
                fids.append(id)
        extra = "not" if isNeg else ""
        self.lims['fact'].append("id %s in %s" % (extra, ids2str(fids)))
示例#9
0
    def basicCheck(self):
        "Basic integrity check for syncing. True if ok."
        # cards without notes
        if self.db.scalar(
            """
select 1 from cards where nid not in (select id from notes) limit 1"""
        ):
            return
        # notes without cards or models
        if self.db.scalar(
            """
select 1 from notes where id not in (select distinct nid from cards)
or mid not in %s limit 1"""
            % ids2str(self.models.ids())
        ):
            return
        # invalid ords
        for m in self.models.all():
            # ignore clozes
            if m["type"] != MODEL_STD:
                continue
            if self.db.scalar(
                """
select 1 from cards where ord not in %s and nid in (
select id from notes where mid = ?) limit 1"""
                % ids2str([t["ord"] for t in m["tmpls"]]),
                m["id"],
            ):
                return
        return True
示例#10
0
    def doExport(self, file):
        cardIds = self.cardIds()
        self.deck.startProgress()
        self.deck.updateProgress(_("Exporting..."))
        facts = self.deck.s.all("""
select factId, value, facts.created from facts, fields
where
facts.id in
(select distinct factId from cards
where cards.id in %s)
and facts.id = fields.factId
order by factId, ordinal""" % ids2str(cardIds))
        txt = ""
        self.deck.updateProgress()
        if self.includeTags:
            self.factTags = dict(self.deck.s.all(
                "select id, tags from facts where id in %s" %
                ids2str([fact[0] for fact in facts])))
        groups = itertools.groupby(facts, itemgetter(0))
        groups = [[x for x in y[1]] for y in groups]
        groups = [(group[0][2],
                   "\t".join([self.escapeText(x[1]) for x in group]) +
                   self.tags(group[0][0]))
                  for group in groups]
        self.deck.updateProgress()
        groups.sort(key=itemgetter(0))
        out = [ret[1] for ret in groups]
        self.count = len(out)
        out = "\n".join(out)
        file.write(out.encode("utf-8"))
        self.deck.finishProgress()
示例#11
0
    def genKanjiSets(self):
        self.kanjiSets = [set([]) for g in self.kanjiGrades]
        mids = self.deck.s.column0(
            '''
select id from models where tags like "%Japanese%"'''
        )
        fmids = []
        for f in KANJI_FIELDS:
            fmids2 = self.deck.s.column0("select id from fieldModels where name = :f", f=f)
            fmids.extend(fmids2)
        all = "".join(
            self.deck.s.column0(
                """
select value from cards, fields, facts
where
cards.reps > 0 and
cards.factId = fields.factId
and cards.factId = facts.id
and facts.modelId in %s
and fields.fieldModelId in %s
"""
                % (ids2str(mids), ids2str(fmids))
            )
        )
        for u in all:
            if isKanji(u):
                self.kanjiSets[self.kanjiGrade(u)].add(u)
示例#12
0
文件: decks.py 项目: Stvad/anki
    def cids(self, did, children=False, include_from_dynamic=False):
        deck_ids = [did] + ([deck_id for _, deck_id in self.children(did)] if children else [])

        request = "select id from cards where did in {}" + ("or odid in {}" if include_from_dynamic else "")
        parameters = (ids2str(deck_ids),) + ((ids2str(deck_ids),) if include_from_dynamic else tuple())

        return self.col.db.list(request.format(*parameters))
示例#13
0
文件: sched.py 项目: darodi/anki
 def resetCards(self, ids):
     "Completely reset cards for export."
     nonNew = self.col.db.list(
         "select id from cards where id in %s and (queue != 0 or type != 0)"
         % ids2str(ids))
     self.col.db.execute(
         "update cards set reps=0, lapses=0 where id in " + ids2str(nonNew))
     self.forgetCards(nonNew)
示例#14
0
文件: anki10.py 项目: ChYi/libanki
 def doImport(self):
     "Import."
     random = self.deck.newCardOrder == NEW_CARDS_RANDOM
     num = 4
     if random:
         num += 1
     src = DeckStorage.Deck(self.file, backup=False)
     client = SyncClient(self.deck)
     server = SyncServer(src)
     client.setServer(server)
     # if there is a conflict, sync local -> src
     client.localTime = self.deck.modified
     client.remoteTime = 0
     src.s.execute("update facts set modified = 1")
     src.s.execute("update models set modified = 1")
     src.s.execute("update cards set modified = 1")
     src.s.execute("update media set created = 1")
     self.deck.db.flush()
     # set up a custom change list and sync
     lsum = client.summary(0)
     self._clearDeleted(lsum)
     rsum = server.summary(0)
     self._clearDeleted(rsum)
     payload = client.genPayload((lsum, rsum))
     # no need to add anything to src
     payload['added-models'] = []
     payload['added-cards'] = []
     payload['added-facts'] = {'facts': [], 'fields': []}
     assert payload['deleted-facts'] == []
     assert payload['deleted-cards'] == []
     assert payload['deleted-models'] == []
     res = server.applyPayload(payload)
     client.applyPayloadReply(res)
     copyLocalMedia(server.deck, client.deck)
     # add tags
     fids = [f[0] for f in res['added-facts']['facts']]
     self.deck.addTags(fids, self.tagsToAdd)
     # mark import material as newly added
     self.deck.db.execute(
         "update cards set modified = :t where id in %s" %
         ids2str([x[0] for x in res['added-cards']]), t=time.time())
     self.deck.db.execute(
         "update facts set modified = :t where id in %s" %
         ids2str([x[0] for x in res['added-facts']['facts']]), t=time.time())
     self.deck.db.execute(
         "update models set modified = :t where id in %s" %
         ids2str([x['id'] for x in res['added-models']]), t=time.time())
     # update total and refresh
     self.total = len(res['added-facts']['facts'])
     src.s.rollback()
     src.engine.dispose()
     # randomize?
     if random:
         self.deck.randomizeNewCards([x[0] for x in res['added-cards']])
     self.deck.flushMod()
示例#15
0
文件: sync.py 项目: scout-zz/libanki
    def getMedia(self, ids, updateCreated=False):
        size = self.deck.s.scalar(
            "select sum(size) from media where id in %s" %
            ids2str(ids))
        if ids:
            self.mediaSyncPending = True
        if updateCreated:
            created = time.time()
        else:
            created = "created"
        return [tuple(row) for row in self.deck.s.all("""
select id, filename, size, %s, originalPath, description
from media where id in %s""" % (created, ids2str(ids)))]
示例#16
0
 def renderQA(self, ids=None, type="card"):
     # gather metadata
     if type == "card":
         where = "and c.id in " + ids2str(ids)
     elif type == "note":
         where = "and f.id in " + ids2str(ids)
     elif type == "model":
         where = "and m.id in " + ids2str(ids)
     elif type == "all":
         where = ""
     else:
         raise Exception()
     return [self._renderQA(row) for row in self._qaData(where)]
示例#17
0
    def fixIntegrity(self):
        "Fix possible problems and rebuild caches."
        problems = []
        self.save()
        oldSize = os.stat(self.path)[stat.ST_SIZE]
        if self.db.scalar("pragma integrity_check") != "ok":
            return (_("Collection is corrupt. Please see the manual."), False)
        # note types with a missing model
        ids = self.db.list("""
select id from notes where mid not in """ + ids2str(self.models.ids()))
        if ids:
            print self.db.list("select distinct mid from notes where id in " + ids2str(ids))
            problems.append(
                ngettext("Deleted %d note with missing note type.",
                         "Deleted %d notes with missing note type.", len(ids))
                         % len(ids))
            self.remNotes(ids)
        # delete any notes with missing cards
        ids = self.db.list("""
select id from notes where id not in (select distinct nid from cards)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Deleted %d note with no cards.",
                         "Deleted %d notes with no cards.", cnt) % cnt)
            self._remNotes(ids)
        # tags
        self.tags.registerNotes()
        # field cache
        for m in self.models.all():
            self.updateFieldCache(self.models.nids(m))
        # new card position
        self.conf['nextPos'] = self.db.scalar(
            "select max(due)+1 from cards where type = 0") or 0
        # reviews should have a reasonable due #
        ids = self.db.list(
            "select id from cards where queue = 2 and due > 10000")
        if ids:
            problems.append("Reviews had incorrect due date.")
            self.db.execute(
                "update cards set due = 0, mod = ?, usn = ? where id in %s"
                % ids2str(ids), intTime(), self.usn())
        # and finally, optimize
        self.optimize()
        newSize = os.stat(self.path)[stat.ST_SIZE]
        txt = _("Database rebuilt and optimized.")
        ok = not problems
        problems.append(txt)
        self.save()
        return ("\n".join(problems), ok)
示例#18
0
文件: deck.py 项目: bhutley/libanki
    def delCards(self, ids):
        "Bulk delete cards by ID."
        if not ids:
            return
        sids = ids2str(ids)
        fids = self.db.list("select fid from cards where id in "+sids)
        # remove cards
        self._logDels(ids, DEL_CARD)
        self.db.execute("delete from cards where id in "+sids)
        self.db.execute("delete from revlog where cid in "+sids)
        # then facts
        fids = self.db.list("""
select id from facts where id in %s and id not in (select fid from cards)""" %
                     ids2str(fids))
        self._delFacts(fids)
示例#19
0
    def remCards(self, ids):
        "Bulk delete cards by ID."
        if not ids:
            return
        sids = ids2str(ids)
        nids = self.db.list("select nid from cards where id in "+sids)
        # remove cards
        self._logRem(ids, REM_CARD)
        self.db.execute("delete from cards where id in "+sids)
        self.db.execute("delete from revlog where cid in "+sids)
        # then notes
        nids = self.db.list("""
select id from notes where id in %s and id not in (select nid from cards)""" %
                     ids2str(nids))
        self._remNotes(nids)
示例#20
0
文件: stats.py 项目: ChYi/libanki
 def _revlogLimit(self):
     lim = self.deck.qconf['groups']
     if self.selective and lim:
         return ("cid in (select id from cards where gid in %s)" %
                 ids2str(lim))
     else:
         return ""
示例#21
0
    def showMatching(self, force=True):
        if not self.sortKey:
            self.cards = []
            return
        # sorting
        if not self.searchStr:
            ads = ""
            self.lastSearch = ""
        else:
            if (self.searchStr.strip() == self.lastSearch.strip()
                and not force):
                # just whitespace
                return
            QApplication.instance().processEvents()
            self.lastSearch = self.searchStr
            ids = self.deck.findCards(self.searchStr)
            ads = "cards.id in %s" % ids2str(ids)
        sort = ""
        if isinstance(self.sortKey, types.StringType):
            # card property
            if self.sortKey == "fact":
                sort = "order by facts.created, cards.created"
            else:
                sort = "order by cards." + self.sortKey
            if self.sortKey in ("question", "answer"):
                sort += " collate nocase"
            if self.sortKey == "fact":
                query = """
select cards.id from cards, facts
where cards.factId = facts.id """
                if ads:
                    query += "and " + ads + " "
            else:
                query = "select id from cards "
                if ads:
                    query += "where %s " % ads
            query += sort
        else:
            # field value
            ret = self.deck.s.all(
                "select id, numeric from fieldModels where name = :name",
                name=self.sortKey[1])
            fields = ",".join([str(x[0]) for x in ret])
            # if multiple models have the same field, use the first numeric bool
            numeric = ret[0][1]
            if numeric:
                order = "cast(fields.value as real)"
            else:
                order = "fields.value collate nocase"
            if ads:
                ads = " and " + ads
            query = ("select cards.id "
                     "from fields, cards where fields.fieldModelId in (%s) "
                     "and fields.factId = cards.factId" + ads +
                     " order by cards.ordinal, %s") % (fields, order)
        # run the query
        self.cards = self.deck.s.all(query)
        if self.deck.getInt('reverseOrder'):
            self.cards.reverse()
        self.reset()
示例#22
0
文件: models.py 项目: Stvad/anki
 def _changeCards(self, nids, oldModel, newModel, map):
     d = []
     deleted = []
     for (cid, ord) in self.col.db.execute(
         "select id, ord from cards where nid in "+ids2str(nids)):
         # if the src model is a cloze, we ignore the map, as the gui
         # doesn't currently support mapping them
         if oldModel['type'] == MODEL_CLOZE:
             new = ord
             if newModel['type'] != MODEL_CLOZE:
                 # if we're mapping to a regular note, we need to check if
                 # the destination ord is valid
                 if len(newModel['tmpls']) <= ord:
                     new = None
         else:
             # mapping from a regular note, so the map should be valid
             new = map[ord]
         if new is not None:
             d.append(dict(
                 cid=cid,new=new,u=self.col.usn(),m=intTime()))
         else:
             deleted.append(cid)
     self.col.db.executemany(
         "update cards set ord=:new,usn=:u,mod=:m where id=:cid",
         d)
     self.col.remCards(deleted)
示例#23
0
文件: models.py 项目: Stvad/anki
    def remTemplate(self, m, template):
        "False if removing template would leave orphan notes."
        assert len(m['tmpls']) > 1
        # find cards using this template
        ord = m['tmpls'].index(template)
        cids = self.col.db.list("""
select c.id from cards c, notes f where c.nid=f.id and mid = ? and ord = ?""",
                                 m['id'], ord)
        # all notes with this template must have at least two cards, or we
        # could end up creating orphaned notes
        if self.col.db.scalar("""
select nid, count() from cards where
nid in (select nid from cards where id in %s)
group by nid
having count() < 2
limit 1""" % ids2str(cids)):
            return False
        # ok to proceed; remove cards
        self.col.modSchema(check=True)
        self.col.remCards(cids)
        # shift ordinals
        self.col.db.execute("""
update cards set ord = ord - 1, usn = ?, mod = ?
 where nid in (select id from notes where mid = ?) and ord > ?""",
                             self.col.usn(), intTime(), m['id'], ord)
        m['tmpls'].remove(template)
        self._updateTemplOrds(m)
        self.save(m)
        return True
示例#24
0
    def sortCards(self, cids, start=1, step=1, shuffle=False, shift=False):
        scids = ids2str(cids)
        now = intTime()
        nids = self.col.db.list(
            ("select distinct nid from cards where type = 0 and id in %s "
             "order by nid") % scids)
        if not nids:
            # no new cards
            return
        # determine nid ordering
        due = {}
        if shuffle:
            random.shuffle(nids)
        for c, nid in enumerate(nids):
            due[nid] = start+c*step
        high = start+c*step
        # shift?
        if shift:
            low = self.col.db.scalar(
                "select min(due) from cards where due >= ? and type = 0 "
                "and id not in %s" % scids,
                start)
            if low is not None:
                shiftby = high - low + 1
                self.col.db.execute("""
update cards set mod=?, usn=?, due=due+? where id not in %s
and due >= ? and queue = 0""" % scids, now, self.col.usn(), shiftby, low)
        # reorder cards
        d = []
        for id, nid in self.col.db.execute(
            "select id, nid from cards where type = 0 and id in "+scids):
            d.append(dict(now=now, due=due[nid], usn=self.col.usn(), cid=id))
        self.col.db.executemany(
            "update cards set due=:due,mod=:now,usn=:usn where id = :cid""", d)
示例#25
0
def sortFieldOrderCids(did):
    dids = [did]
    for name, id in mw.col.decks.children(did):
        dids.append(id)
    return mw.col.db.list("""
select c.id from cards c, notes n where did in %s
and c.nid = n.id order by n.sfld""" % ids2str(dids))
示例#26
0
文件: tags.py 项目: kingdynasty/anki
 def bulkAdd(self, ids, tags, add=True):
     "Add tags in bulk. TAGS is space-separated."
     newTags = self.split(tags)
     if not newTags:
         return
     # cache tag names
     self.register(newTags)
     # find notes missing the tags
     if add:
         l = "tags not "
         fn = self.addToStr
     else:
         l = "tags "
         fn = self.remFromStr
     lim = " or ".join(
         [l+"like :_%d" % c for c, t in enumerate(newTags)])
     res = self.col.db.all(
         "select id, tags from notes where id in %s and (%s)" % (
             ids2str(ids), lim),
         **dict([("_%d" % x, '%% %s %%' % y)
                 for x, y in enumerate(newTags)]))
     # update tags
     nids = []
     def fix(row):
         nids.append(row[0])
         return {'id': row[0], 't': fn(tags, row[1]), 'n':intTime(),
             'u':self.col.usn()}
     self.col.db.executemany(
         "update notes set tags=:t,mod=:n,usn=:u where id = :id",
         [fix(row) for row in res])
示例#27
0
文件: sched.py 项目: chajadan/anki
    def buryCards(self, cids):
        self.col.log(cids)
        self.remFromDyn(cids)
        self.removeLrn(cids)
        self.col.db.execute("""
update cards set queue=-2,mod=?,usn=? where id in """+ids2str(cids),
                            intTime(), self.col.usn())
示例#28
0
 def suspendCards(self, ids):
     "Suspend cards."
     self.remFromDyn(ids)
     self.removeFailed(ids)
     self.col.db.execute(
         "update cards set queue=-1,mod=?,usn=? where id in "+
         ids2str(ids), intTime(), self.col.usn())
示例#29
0
文件: sched.py 项目: chajadan/anki
 def unsuspendCards(self, ids):
     "Unsuspend cards."
     self.col.log(ids)
     self.col.db.execute(
         "update cards set queue=type,mod=?,usn=? "
         "where queue = -1 and id in "+ ids2str(ids),
         intTime(), self.col.usn())
示例#30
0
文件: sched.py 项目: chajadan/anki
    def _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<=?))""",
                card.nid, card.id, self.today):
            if queue == 2:
                if buryRev:
                    toBury.append(cid)
                # if bury disabled, we still discard to give same-day spacing
                try:
                    self._revQueue.remove(cid)
                except ValueError:
                    pass
            else:
                # if bury disabled, we still discard to give same-day spacing
                if buryNew:
                    toBury.append(cid)
                try:
                    self._newQueue.remove(cid)
                except ValueError:
                    pass
        # then bury
        if toBury:
            self.col.db.execute(
                "update cards set queue=-2,mod=?,usn=? where id in "+ids2str(toBury),
                intTime(), self.col.usn())
            self.col.log(toBury)
示例#31
0
 def remNotes(self, ids: Iterable[int]) -> None:
     """Deletes notes with the given IDs."""
     self.remCards(
         self.db.list("select id from cards where nid in " + ids2str(ids)))
示例#32
0
    def genCards(self, nids: List[int]) -> List[int]:
        "Generate cards for non-empty templates, return ids to remove."
        # build map of (nid,ord) so we don't create dupes
        snids = ids2str(nids)
        have: Dict[int, Dict[int, int]] = {}
        dids: Dict[int, Optional[int]] = {}
        dues: Dict[int, int] = {}
        for id, nid, ord, did, due, odue, odid, type in self.db.execute(
                "select id, nid, ord, did, due, odue, odid, type from cards where nid in "
                + snids):
            # existing cards
            if nid not in have:
                have[nid] = {}
            have[nid][ord] = id
            # if in a filtered deck, add new cards to original deck
            if odid != 0:
                did = odid
            # and their dids
            if nid in dids:
                if dids[nid] and dids[nid] != did:
                    # cards are in two or more different decks; revert to
                    # model default
                    dids[nid] = None
            else:
                # first card or multiple cards in same deck
                dids[nid] = did
            # save due
            if odid != 0:
                due = odue
            if nid not in dues and type == 0:
                # Add due to new card only if it's the due of a new sibling
                dues[nid] = due
        # build cards for each note
        data = []
        ts = maxID(self.db)
        now = intTime()
        rem = []
        usn = self.usn()
        for nid, mid, flds in self.db.execute(
                "select id, mid, flds from notes where id in " + snids):
            model = self.models.get(mid)
            assert model
            avail = self.models.availOrds(model, flds)
            did = dids.get(nid) or model["did"]
            due = dues.get(nid)
            # add any missing cards
            for t in self._tmplsFromOrds(model, avail):
                doHave = nid in have and t["ord"] in have[nid]
                if not doHave:
                    # check deck is not a cram deck
                    did = t["did"] or did
                    if self.decks.isDyn(did):
                        did = 1
                    # if the deck doesn't exist, use default instead
                    did = self.decks.get(did)["id"]
                    # use sibling due# if there is one, else use a new id
                    if due is None:
                        due = self.nextID("pos")
                    data.append((ts, nid, did, t["ord"], now, usn, due))
                    ts += 1
            # note any cards that need removing
            if nid in have:
                for ord, id in list(have[nid].items()):
                    if ord not in avail:
                        rem.append(id)
        # bulk update
        self.db.executemany(
            """
insert into cards values (?,?,?,?,?,?,0,0,?,0,0,0,0,0,0,0,0,"")""",
            data,
        )
        return rem
示例#33
0
    def fixIntegrity(self) -> Tuple[str, bool]:
        """Fix possible problems and rebuild caches.

        Returns tuple of (error: str, ok: bool). 'ok' will be true if no
        problems were found.
        """
        problems = []
        # problems that don't require a full sync
        syncable_problems = []
        self.save()
        oldSize = os.stat(self.path)[stat.ST_SIZE]
        if self.db.scalar("pragma integrity_check") != "ok":
            return (_("Collection is corrupt. Please see the manual."), False)
        # note types with a missing model
        ids = self.db.list("""
select id from notes where mid not in """ + ids2str(self.models.ids()))
        if ids:
            problems.append(
                ngettext(
                    "Deleted %d note with missing note type.",
                    "Deleted %d notes with missing note type.",
                    len(ids),
                ) % len(ids))
            self.remNotes(ids)
        # for each model
        for m in self.models.all():
            for t in m["tmpls"]:
                if t["did"] == "None":
                    t["did"] = None
                    problems.append(_("Fixed AnkiDroid deck override bug."))
                    self.models.save(m, updateReqs=False)
            if m["type"] == MODEL_STD:
                # model with missing req specification
                if "req" not in m:
                    self.models._updateRequired(m)
                    problems.append(_("Fixed note type: %s") % m["name"])
                # cards with invalid ordinal
                ids = self.db.list(
                    """
select id from cards where ord not in %s and nid in (
select id from notes where mid = ?)""" %
                    ids2str([t["ord"] for t in m["tmpls"]]),
                    m["id"],
                )
                if ids:
                    problems.append(
                        ngettext(
                            "Deleted %d card with missing template.",
                            "Deleted %d cards with missing template.",
                            len(ids),
                        ) % len(ids))
                    self.remCards(ids)
            # notes with invalid field count
            ids = []
            for id, flds in self.db.execute(
                    "select id, flds from notes where mid = ?", m["id"]):
                if (flds.count("\x1f") + 1) != len(m["flds"]):
                    ids.append(id)
            if ids:
                problems.append(
                    ngettext(
                        "Deleted %d note with wrong field count.",
                        "Deleted %d notes with wrong field count.",
                        len(ids),
                    ) % len(ids))
                self.remNotes(ids)
        # delete any notes with missing cards
        ids = self.db.list("""
select id from notes where id not in (select distinct nid from cards)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext(
                    "Deleted %d note with no cards.",
                    "Deleted %d notes with no cards.",
                    cnt,
                ) % cnt)
            self._remNotes(ids)
        # cards with missing notes
        ids = self.db.list("""
select id from cards where nid not in (select id from notes)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext(
                    "Deleted %d card with missing note.",
                    "Deleted %d cards with missing note.",
                    cnt,
                ) % cnt)
            self.remCards(ids)
        # cards with odue set when it shouldn't be
        ids = self.db.list("""
select id from cards where odue > 0 and (type=1 or queue=2) and not odid""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext(
                    "Fixed %d card with invalid properties.",
                    "Fixed %d cards with invalid properties.",
                    cnt,
                ) % cnt)
            self.db.execute("update cards set odue=0 where id in " +
                            ids2str(ids))
        # cards with odid set when not in a dyn deck
        dids = [id for id in self.decks.allIds() if not self.decks.isDyn(id)]
        ids = self.db.list("""
select id from cards where odid > 0 and did in %s""" % ids2str(dids))
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext(
                    "Fixed %d card with invalid properties.",
                    "Fixed %d cards with invalid properties.",
                    cnt,
                ) % cnt)
            self.db.execute("update cards set odid=0, odue=0 where id in " +
                            ids2str(ids))
        # notes with non-normalized tags
        cnt = self._normalize_tags()
        if cnt > 0:
            syncable_problems.append(
                self.tr(TR.DATABASE_CHECK_FIXED_NON_NORMALIZED_TAGS,
                        count=cnt))
        # tags
        self.tags.registerNotes()
        # field cache
        for m in self.models.all():
            self.updateFieldCache(self.models.nids(m))
        # new cards can't have a due position > 32 bits, so wrap items over
        # 2 million back to 1 million
        self.db.execute(
            """
update cards set due=1000000+due%1000000,mod=?,usn=? where due>=1000000
and type=0""",
            intTime(),
            self.usn(),
        )
        rowcount = self.db.scalar("select changes()")
        if rowcount:
            problems.append(
                "Found %d new cards with a due number >= 1,000,000 - consider repositioning them in the Browse screen."
                % rowcount)
        # new card position
        self.conf["nextPos"] = (
            self.db.scalar("select max(due)+1 from cards where type = 0") or 0)
        # reviews should have a reasonable due #
        ids = self.db.list(
            "select id from cards where queue = 2 and due > 100000")
        if ids:
            problems.append("Reviews had incorrect due date.")
            self.db.execute(
                "update cards set due = ?, ivl = 1, mod = ?, usn = ? where id in %s"
                % ids2str(ids),
                self.sched.today,
                intTime(),
                self.usn(),
            )
        # v2 sched had a bug that could create decimal intervals
        self.db.execute(
            "update cards set ivl=round(ivl),due=round(due) where ivl!=round(ivl) or due!=round(due)"
        )
        rowcount = self.db.scalar("select changes()")
        if rowcount:
            problems.append("Fixed %d cards with v2 scheduler bug." % rowcount)

        self.db.execute(
            "update revlog set ivl=round(ivl),lastIvl=round(lastIvl) where ivl!=round(ivl) or lastIvl!=round(lastIvl)"
        )
        rowcount = self.db.scalar("select changes()")
        if rowcount:
            problems.append(
                "Fixed %d review history entries with v2 scheduler bug." %
                rowcount)
        # models
        if self.models.ensureNotEmpty():
            problems.append("Added missing note type.")
        # and finally, optimize
        self.optimize()
        newSize = os.stat(self.path)[stat.ST_SIZE]
        txt = _("Database rebuilt and optimized.")
        ok = not problems
        problems.append(txt)
        # if any problems were found, force a full sync
        if not ok:
            self.modSchema(check=False)
        self.save()
        problems.extend(syncable_problems)
        return ("\n".join(problems), ok)
示例#34
0
 def _recoverOrphans(self) -> None:
     dids = list(self.decks.keys())
     mod = self.col.db.mod
     self.col.db.execute("update cards set did = 1 where did not in " +
                         ids2str(dids))
     self.col.db.mod = mod
示例#35
0
    def updateCards(self, cards):
        if not cards:
            return
        # FIXME: older clients won't send this, so this is temp compat code
        def getType(row):
            if len(row) > 36:
                return row[36]
            if row[15]:
                return 1
            elif row[14]:
                return 0
            return 2

        dlist = [{
            'id': c[0],
            'factId': c[1],
            'cardModelId': c[2],
            'created': c[3],
            'modified': c[4],
            'tags': c[5],
            'ordinal': c[6],
            'priority': c[7],
            'interval': c[8],
            'lastInterval': c[9],
            'due': c[10],
            'lastDue': c[11],
            'factor': c[12],
            'firstAnswered': c[13],
            'reps': c[14],
            'successive': c[15],
            'averageTime': c[16],
            'reviewTime': c[17],
            'youngEase0': c[18],
            'youngEase1': c[19],
            'youngEase2': c[20],
            'youngEase3': c[21],
            'youngEase4': c[22],
            'matureEase0': c[23],
            'matureEase1': c[24],
            'matureEase2': c[25],
            'matureEase3': c[26],
            'matureEase4': c[27],
            'yesCount': c[28],
            'noCount': c[29],
            'question': c[30],
            'answer': c[31],
            'lastFactor': c[32],
            'spaceUntil': c[33],
            'type': c[34],
            'combinedDue': c[35],
            'rd': getType(c)
        } for c in cards]
        self.deck.s.execute(
            """
insert or replace into cards
(id, factId, cardModelId, created, modified, tags, ordinal,
priority, interval, lastInterval, due, lastDue, factor,
firstAnswered, reps, successive, averageTime, reviewTime, youngEase0,
youngEase1, youngEase2, youngEase3, youngEase4, matureEase0,
matureEase1, matureEase2, matureEase3, matureEase4, yesCount, noCount,
question, answer, lastFactor, spaceUntil, type, combinedDue,
relativeDelay, isDue)
values
(:id, :factId, :cardModelId, :created, :modified, :tags, :ordinal,
:priority, :interval, :lastInterval, :due, :lastDue, :factor,
:firstAnswered, :reps, :successive, :averageTime, :reviewTime, :youngEase0,
:youngEase1, :youngEase2, :youngEase3, :youngEase4, :matureEase0,
:matureEase1, :matureEase2, :matureEase3, :matureEase4, :yesCount,
:noCount, :question, :answer, :lastFactor, :spaceUntil,
:type, :combinedDue, :rd, 0)""", dlist)
        self.deck.s.statement("delete from cardsDeleted where cardId in %s" %
                              ids2str([c[0] for c in cards]))
示例#36
0
 def getOneWayCards(self, ids):
     "The minimum information necessary to generate one way cards."
     return self.deck.s.all(
         "select id, factId, cardModelId, ordinal, created from cards "
         "where id in %s" % ids2str(ids))
示例#37
0
    def exportInto(self, path):
        # sched info+v2 scheduler not compatible w/ older clients
        self._v2sched = self.col.schedVer() != 1 and self.includeSched

        # create a new collection at the target
        try:
            os.unlink(path)
        except (IOError, OSError):
            pass
        self.dst = Collection(path)
        self.src = self.col
        # find cards
        if not self.did:
            cids = self.src.db.list("select id from cards")
        else:
            cids = self.src.decks.cids(self.did, children=True)
        # copy cards, noting used nids
        nids = {}
        data = []
        for row in self.src.db.execute(
            "select * from cards where id in "+ids2str(cids)):
            nids[row[1]] = True
            data.append(row)
            # clear flags
            row = list(row)
            row[-2] = 0
        self.dst.db.executemany(
            "insert into cards values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
            data)
        # notes
        strnids = ids2str(list(nids.keys()))
        notedata = []
        for row in self.src.db.all(
            "select * from notes where id in "+strnids):
            # remove system tags if not exporting scheduling info
            if not self.includeSched:
                row = list(row)
                row[5] = self.removeSystemTags(row[5])
            notedata.append(row)
        self.dst.db.executemany(
            "insert into notes values (?,?,?,?,?,?,?,?,?,?,?)",
            notedata)
        # models used by the notes
        mids = self.dst.db.list("select distinct mid from notes where id in "+
                                strnids)
        # card history and revlog
        if self.includeSched:
            data = self.src.db.all(
                "select * from revlog where cid in "+ids2str(cids))
            self.dst.db.executemany(
                "insert into revlog values (?,?,?,?,?,?,?,?,?)",
                data)
        else:
            # need to reset card state
            self.dst.sched.resetCards(cids)
        # models - start with zero
        self.dst.models.models = {}
        for m in self.src.models.all():
            if int(m['id']) in mids:
                self.dst.models.update(m)
        # decks
        if not self.did:
            dids = []
        else:
            dids = [self.did] + [
                x[1] for x in self.src.decks.children(self.did)]
        dconfs = {}
        for d in self.src.decks.all():
            if str(d['id']) == "1":
                continue
            if dids and d['id'] not in dids:
                continue
            if not d['dyn'] and d['conf'] != 1:
                if self.includeSched:
                    dconfs[d['conf']] = True
            if not self.includeSched:
                # scheduling not included, so reset deck settings to default
                d = dict(d)
                d['conf'] = 1
            self.dst.decks.update(d)
        # copy used deck confs
        for dc in self.src.decks.allConf():
            if dc['id'] in dconfs:
                self.dst.decks.updateConf(dc)
        # find used media
        media = {}
        self.mediaDir = self.src.media.dir()
        if self.includeMedia:
            for row in notedata:
                flds = row[6]
                mid = row[2]
                for file in self.src.media.filesInStr(mid, flds):
                    # skip files in subdirs
                    if file != os.path.basename(file):
                        continue
                    media[file] = True
            if self.mediaDir:
                for fname in os.listdir(self.mediaDir):
                    path = os.path.join(self.mediaDir, fname)
                    if os.path.isdir(path):
                        continue
                    if fname.startswith("_"):
                        # Scan all models in mids for reference to fname
                        for m in self.src.models.all():
                            if int(m['id']) in mids:
                                if self._modelHasMedia(m, fname):
                                    media[fname] = True
                                    break
        self.mediaFiles = list(media.keys())
        self.dst.crt = self.src.crt
        # todo: tags?
        self.count = self.dst.cardCount()
        self.dst.setMod()
        self.postExport()
        self.dst.close()
示例#38
0
 def remove_notes_by_card(self, card_ids: List[int]) -> None:
     if hooks.notes_will_be_deleted.count():
         nids = self.db.list("select nid from cards where id in " +
                             ids2str(card_ids))
         hooks.notes_will_be_deleted(self, nids)
     self.backend.remove_notes(note_ids=[], card_ids=card_ids)
示例#39
0
文件: db.py 项目: holycrepe/anknotes
def get_sql_anki_cids_from_evernote_guids(guids):
    return "c.nid IN " + ids2str(get_anki_note_ids_from_evernote_guids(guids))
示例#40
0
 def _deckLimit(self) -> str:
     return ids2str(
         self.col.decks.deck_and_child_ids(self.col.decks.get_current_id()))
示例#41
0
 def remFromDyn(self, cids):
     self.emptyDyn(None, "id in %s and odid" % ids2str(cids))
示例#42
0
 def unsuspendCards(self, ids):
     "Unsuspend cards."
     self.col.db.execute(
         "update cards set queue=type,mod=?,usn=? "
         "where queue = -1 and id in "+ ids2str(ids),
         intTime(), self.col.usn())
示例#43
0
def _resetRevCountV2(sched):
    lim = currentRevLimit(sched)
    sched.revCount = sched.col.db.scalar("""
select count() from (select id from cards where
did in %s and queue = 2 and due <= ? limit %d)""" % (
        ids2str(sched.col.decks.active()), lim), sched.today)
示例#44
0
    def fixIntegrity(self):
        "Fix possible problems and rebuild caches."
        problems = []
        curs = self.db.cursor()
        self.save()
        oldSize = os.stat(self.path)[stat.ST_SIZE]

        # whether sqlite find a problem in its database
        if self.db.scalar("pragma integrity_check") != "ok":
            return (_("Collection is corrupt. Please see the manual."), False)

        # note types with a missing model
        ids = self.db.list("""
select id from notes where mid not in """ + ids2str(self.models.ids()))
        if ids:
            problems.append(
                ngettext("Deleted %d note with missing note type.",
                         "Deleted %d notes with missing note type.", len(ids))
                % len(ids))
            self.remNotes(ids)

        # for each model
        for m in self.models.all():
            for t in m['tmpls']:
                if t['did'] == "None":
                    t['did'] = None
                    problems.append(_("Fixed AnkiDroid deck override bug."))
                    self.models.save(m)
            if m['type'] == MODEL_STD:
                # model with missing req specification
                if 'req' not in m:
                    self.models._updateRequired(m)
                    problems.append(_("Fixed note type: %s") % m['name'])
                # cards with invalid ordinal
                ids = self.db.list(
                    """
select id from cards where ord not in %s and nid in (
select id from notes where mid = ?)""" %
                    ids2str([t['ord'] for t in m['tmpls']]), m['id'])
                if ids:
                    problems.append(
                        ngettext("Deleted %d card with missing template.",
                                 "Deleted %d cards with missing template.",
                                 len(ids)) % len(ids))
                    self.remCards(ids)
            # notes with invalid field count
            ids = []
            for id, flds in self.db.execute(
                    "select id, flds from notes where mid = ?", m['id']):
                if (flds.count("\x1f") + 1) != len(m['flds']):
                    ids.append(id)
            if ids:
                problems.append(
                    ngettext("Deleted %d note with wrong field count.",
                             "Deleted %d notes with wrong field count.",
                             len(ids)) % len(ids))
                self.remNotes(ids)
        # delete any notes with missing cards
        ids = self.db.list("""
select id from notes where id not in (select distinct nid from cards)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Deleted %d note with no cards.",
                         "Deleted %d notes with no cards.", cnt) % cnt)
            self._remNotes(ids)
        # cards with missing notes
        ids = self.db.list("""
select id from cards where nid not in (select id from notes)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Deleted %d card with missing note.",
                         "Deleted %d cards with missing note.", cnt) % cnt)
            self.remCards(ids)
        # cards with odue set when it shouldn't be
        ids = self.db.list(f"""
        select id from cards where odue > 0 and (type={CARD_LRN} or queue={CARD_DUE}) and not odid"""
                           )
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Fixed %d card with invalid properties.",
                         "Fixed %d cards with invalid properties.", cnt) % cnt)
            self.db.execute("update cards set odue=0 where id in " +
                            ids2str(ids))
        # cards with odid set when not in a dyn deck
        dids = [id for id in self.decks.allIds() if not self.decks.isDyn(id)]
        ids = self.db.list("""
select id from cards where odid > 0 and did in %s""" % ids2str(dids))
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Fixed %d card with invalid properties.",
                         "Fixed %d cards with invalid properties.", cnt) % cnt)
            self.db.execute("update cards set odid=0, odue=0 where id in " +
                            ids2str(ids))
        # tags
        self.tags.registerNotes()
        # field cache
        for m in self.models.all():
            self.updateFieldCache(self.models.nids(m))
        # new cards can't have a due position > 32 bits, so wrap items over
        # 2 million back to 1 million
        curs.execute(
            """
update cards set due=1000000+due%1000000,mod=?,usn=? where due>=1000000
and type=0""", [intTime(), self.usn()])
        if curs.rowcount:
            problems.append(
                "Found %d new cards with a due number >= 1,000,000 - consider repositioning them in the Browse screen."
                % curs.rowcount)
        # new card position
        self.conf['nextPos'] = self.db.scalar(
            f"select max(due)+1 from cards where type = {CARD_NEW}") or 0
        # reviews should have a reasonable due #
        ids = self.db.list(
            "select id from cards where queue = 2 and due > 100000")
        if ids:
            problems.append("Reviews had incorrect due date.")
            self.db.execute(
                "update cards set due = ?, ivl = 1, mod = ?, usn = ? where id in %s"
                % ids2str(ids), self.sched.today, intTime(), self.usn())
        # v2 sched had a bug that could create decimal intervals
        curs.execute(
            "update cards set ivl=round(ivl),due=round(due) where ivl!=round(ivl) or due!=round(due)"
        )
        if curs.rowcount:
            problems.append("Fixed %d cards with v2 scheduler bug." %
                            curs.rowcount)

        curs.execute(
            "update revlog set ivl=round(ivl),lastIvl=round(lastIvl) where ivl!=round(ivl) or lastIvl!=round(lastIvl)"
        )
        if curs.rowcount:
            problems.append(
                "Fixed %d review history entries with v2 scheduler bug." %
                curs.rowcount)
        # models
        if self.models.ensureNotEmpty():
            problems.append("Added missing note type.")
        # and finally, optimize
        self.optimize()
        newSize = os.stat(self.path)[stat.ST_SIZE]
        txt = _("Database rebuilt and optimized.")
        ok = not problems
        problems.append(txt)
        # if any problems were found, force a full sync
        if not ok:
            self.modSchema(check=False)
        self.save()
        return ("\n".join(problems), ok)
示例#45
0
    def genCards(self, nids):
        """Ids of cards which needs to be removed.

        Generate missing cards of a note with id in nids.
        """
        # build map of (nid,ord) so we don't create dupes
        snids = ids2str(nids)
        have = {
        }  #Associated to each nid a dictionnary from card's order to card id.
        dids = {
        }  #Associate to each nid the only deck id containing its cards. Or None if there are multiple decks
        dues = {}  #Associate to each nid the due value of the last card seen.
        for id, nid, ord, did, due, odue, odid in self.db.execute(
                "select id, nid, ord, did, due, odue, odid from cards where nid in "
                + snids):
            # existing cards
            if nid not in have:
                have[nid] = {}
            have[nid][ord] = id
            # if in a filtered deck, add new cards to original deck
            if odid != 0:
                did = odid
            # and their dids
            if nid in dids:
                if dids[nid] and dids[nid] != did:
                    # cards are in two or more different decks; revert to
                    # model default
                    dids[nid] = None
            else:
                # first card or multiple cards in same deck
                dids[nid] = did
            # save due
            if odid != 0:
                due = odue
            if nid not in dues:
                dues[nid] = due
        # build cards for each note
        data = [
        ]  #Tuples for cards to create. Each tuple is newCid, nid, did, ord, now, usn, due
        ts = maxID(self.db)
        now = intTime()
        rem = []  #cards to remove
        usn = self.usn()
        for nid, mid, flds in self.db.execute(
                "select id, mid, flds from notes where id in " + snids):
            model = self.models.get(mid)
            avail = self.models.availOrds(model, flds)
            did = dids.get(nid) or model['did']
            due = dues.get(nid)
            # add any missing cards
            for t in self._tmplsFromOrds(model, avail):
                doHave = nid in have and t['ord'] in have[nid]
                if not doHave:
                    # check deck is not a cram deck
                    did = t['did'] or did
                    if self.decks.isDyn(did):
                        did = 1
                    # if the deck doesn't exist, use default instead
                    did = self.decks.get(did)['id']
                    # use sibling due# if there is one, else use a new id
                    if due is None:
                        due = self.nextID("pos")
                    data.append((ts, nid, did, t['ord'], now, usn, due))
                    ts += 1
            # note any cards that need removing
            if nid in have:
                for ord, id in list(have[nid].items()):
                    if ord not in avail:
                        rem.append(id)
        # bulk update
        self.db.executemany(
            """
insert into cards values (?,?,?,?,?,?,0,0,?,0,0,0,0,0,0,0,0,"")""", data)
        return rem
示例#46
0
 def setUserFlag(self, flag, cids):
     assert 0 <= flag <= 7
     self.db.execute(
         "update cards set flags = (flags & ~?) | ?, usn=?, mod=? where id in %s"
         % ids2str(cids), 0b111, flag, self._usn, intTime())
示例#47
0
 def setUserFlag(self, flag, cids):
     assert 0 <= flag <= 7
     self.db.execute("update cards set flags = (flags & ~?) | ? where id in %s" %
                     ids2str(cids), 0b111, flag)
示例#48
0
    def getMedia(self, ids):
        return [
            tuple(row) for row in self.deck.s.all("""
select id, filename, size, created, originalPath, description
from media where id in %s""" % ids2str(ids))
        ]
示例#49
0
 def remNotes(self, ids):
     """Removes all cards associated to the notes whose id is in ids"""
     self.remCards(
         self.db.list("select id from cards where nid in " + ids2str(ids)))
示例#50
0
 def _revlogLimit(self):
     if self.wholeCollection:
         return ""
     return ("cid in (select id from cards where did in %s)" %
             ids2str(self.col.decks.active()))
示例#51
0
文件: sched.py 项目: yukach/anki
    def totalRevForCurrentDeck(self):
        return self.col.db.scalar(
            """
select count() from cards where id in (
select id from cards where did in %s and queue = 2 and due <= ? limit ?)""" %
            ids2str(self.col.decks.active()), self.today, self.reportLimit)
def getCards( deck, fids ):
    cis = deck.s.column0( 'select id from cards where factId in %s' % ids2str(fids) )
    cs = [ deck.s.query(Card).get( id ) for id in cis ]
    return cs
示例#53
0
文件: stats.py 项目: glutanimate/anki
 def _limit(self) -> Any:
     if self.wholeCollection:
         return ids2str([d["id"] for d in self.col.decks.all()])
     return self.col.sched._deck_limit()
示例#54
0
 def _limit(self):
     if self.wholeCollection:
         return ids2str([d['id'] for d in self.col.decks.all()])
     return self.col.sched._deckLimit()
示例#55
0
    def fixIntegrity(self):
        "Fix possible problems and rebuild caches."
        problems = []
        self.save()
        oldSize = os.stat(self.path)[stat.ST_SIZE]
        if self.db.scalar("pragma integrity_check") != "ok":
            return (_("Collection is corrupt. Please see the manual."), False)
        # note types with a missing model
        ids = self.db.list("""
select id from notes where mid not in """ + ids2str(self.models.ids()))
        if ids:
            problems.append(
                ngettext("Deleted %d note with missing note type.",
                         "Deleted %d notes with missing note type.", len(ids))
                         % len(ids))
            self.remNotes(ids)
        # for each model
        for m in self.models.all():
            for t in m['tmpls']:
                if t['did'] == "None":
                    t['did'] = None
                    problems.append(_("Fixed AnkiDroid deck override bug."))
                    self.models.save(m)
            if m['type'] == MODEL_STD:
                # model with missing req specification
                if 'req' not in m:
                    self.models._updateRequired(m)
                    problems.append(_("Fixed note type: %s") % m['name'])
                # cards with invalid ordinal
                ids = self.db.list("""
select id from cards where ord not in %s and nid in (
select id from notes where mid = ?)""" %
                                   ids2str([t['ord'] for t in m['tmpls']]),
                                   m['id'])
                if ids:
                    problems.append(
                        ngettext("Deleted %d card with missing template.",
                                 "Deleted %d cards with missing template.",
                                 len(ids)) % len(ids))
                    self.remCards(ids)
            # notes with invalid field count
            ids = []
            for id, flds in self.db.execute(
                    "select id, flds from notes where mid = ?", m['id']):
                if (flds.count("\x1f") + 1) != len(m['flds']):
                    ids.append(id)
            if ids:
                problems.append(
                    ngettext("Deleted %d note with wrong field count.",
                             "Deleted %d notes with wrong field count.",
                             len(ids)) % len(ids))
                self.remNotes(ids)
        # delete any notes with missing cards
        ids = self.db.list("""
select id from notes where id not in (select distinct nid from cards)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Deleted %d note with no cards.",
                         "Deleted %d notes with no cards.", cnt) % cnt)
            self._remNotes(ids)
        # cards with missing notes
        ids = self.db.list("""
select id from cards where nid not in (select id from notes)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Deleted %d card with missing note.",
                         "Deleted %d cards with missing note.", cnt) % cnt)
            self.remCards(ids)
        # cards with odue set when it shouldn't be
        ids = self.db.list("""
select id from cards where odue > 0 and (type=1 or queue=2) and not odid""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Fixed %d card with invalid properties.",
                         "Fixed %d cards with invalid properties.", cnt) % cnt)
            self.db.execute("update cards set odue=0 where id in "+
                ids2str(ids))
        # cards with odid set when not in a dyn deck
        dids = [id for id in self.decks.allIds() if not self.decks.isDyn(id)]
        ids = self.db.list("""
select id from cards where odid > 0 and did in %s""" % ids2str(dids))
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Fixed %d card with invalid properties.",
                         "Fixed %d cards with invalid properties.", cnt) % cnt)
            self.db.execute("update cards set odid=0, odue=0 where id in "+
                ids2str(ids))
        # tags
        self.tags.registerNotes()
        # field cache
        for m in self.models.all():
            self.updateFieldCache(self.models.nids(m))
        # new cards can't have a due position > 32 bits
        self.db.execute("""
update cards set due = 1000000, mod = ?, usn = ? where due > 1000000
and queue = 0""", intTime(), self.usn())
        # new card position
        self.conf['nextPos'] = self.db.scalar(
            "select max(due)+1 from cards where type = 0") or 0
        # reviews should have a reasonable due #
        ids = self.db.list(
            "select id from cards where queue = 2 and due > 100000")
        if ids:
            problems.append("Reviews had incorrect due date.")
            self.db.execute(
                "update cards set due = ?, ivl = 1, mod = ?, usn = ? where id in %s"
                % ids2str(ids), self.sched.today, intTime(), self.usn())
        # and finally, optimize
        self.optimize()
        newSize = os.stat(self.path)[stat.ST_SIZE]
        txt = _("Database rebuilt and optimized.")
        ok = not problems
        problems.append(txt)
        # if any problems were found, force a full sync
        if not ok:
            self.modSchema(check=False)
        self.save()
        return ("\n".join(problems), ok)
示例#56
0
文件: sched.py 项目: yukach/anki
 def haveBuried(self):
     sdids = ids2str(self.col.decks.active())
     cnt = self.col.db.scalar(
         "select 1 from cards where queue = -2 and did in %s limit 1" %
         sdids)
     return not not cnt
示例#57
0
    def genCards(self, nids):
        "Generate cards for non-empty templates, return ids to remove."
        # build map of (nid,ord) so we don't create dupes
        snids = ids2str(nids)
        have = {}
        dids = {}
        for id, nid, ord, did, odid in self.db.execute(
            "select id, nid, ord, did, odid from cards where nid in "+snids):
            # existing cards
            if nid not in have:
                have[nid] = {}
            have[nid][ord] = id
            # if in a filtered deck, add new cards to original deck
            if odid != 0:
                did = odid
            # and their dids
            if nid in dids:
                if dids[nid] and dids[nid] != did:
                    # cards are in two or more different decks; revert to
                    # model default
                    dids[nid] = None
            else:
                # first card or multiple cards in same deck
                dids[nid] = did
        # build cards for each note
        data = []
        ts = maxID(self.db)
        now = intTime()
        rem = []
        usn = self.usn()
        for nid, mid, flds in self.db.execute(
            "select id, mid, flds from notes where id in "+snids):
            model = self.models.get(mid)
            avail = self.models.availOrds(model, flds)
            did = dids.get(nid) or model['did']
            # add any missing cards
            for t in self._tmplsFromOrds(model, avail):
                doHave = nid in have and t['ord'] in have[nid]
                if not doHave:
                    # check deck is not a cram deck
                    did = t['did'] or did
                    if self.decks.isDyn(did):
                        did = 1
                    # if the deck doesn't exist, use default instead
                    did = self.decks.get(did)['id']
                    # we'd like to use the same due# as sibling cards, but we
                    # can't retrieve that quickly, so we give it a new id
                    # instead
                    data.append((ts, nid, did, t['ord'],
                                 now, usn, self.nextID("pos")))
                    ts += 1
            # note any cards that need removing
            if nid in have:
                for ord, id in list(have[nid].items()):
                    if ord not in avail:
                        rem.append(id)
        # bulk update
        self.db.executemany("""
insert into cards values (?,?,?,?,?,?,0,0,?,0,0,0,0,0,0,0,0,"")""",
                            data)
        return rem
示例#58
0
 def remNotes(self, ids):
     self.remCards(self.db.list("select id from cards where nid in "+
                                ids2str(ids)))
示例#59
0
 def _deckLimit(self):
     return ids2str(self.col.decks.active())
示例#60
0
 def setDeck(self, cids, did):
     self.col.db.execute(
         "update cards set did=?,usn=?,mod=? where id in "+
         ids2str(cids), did, self.col.usn(), intTime())