Anki/pylib/anki/find.py
2020-05-23 20:43:55 +10:00

99 lines
2.8 KiB
Python

# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Set
from anki.hooks import *
from anki.utils import ids2str, splitFields, stripHTMLMedia
if TYPE_CHECKING:
from anki.collection import Collection
class Finder:
def __init__(self, col: Optional[Collection]) -> None:
self.col = col.weakref()
print("Finder() is deprecated, please use col.find_cards() or .find_notes()")
def findCards(self, query, order):
return self.col.find_cards(query, order)
def findNotes(self, query):
return self.col.find_notes(query)
# Find and replace
##########################################################################
def findReplace(
col: Collection,
nids: List[int],
src: str,
dst: str,
regex: bool = False,
field: Optional[str] = None,
fold: bool = True,
) -> int:
"Find and replace fields in a note. Returns changed note count."
return col.backend.find_and_replace(nids, src, dst, regex, fold, field)
def fieldNamesForNotes(col: Collection, nids: List[int]) -> List[str]:
return list(col.backend.field_names_for_notes(nids))
# Find duplicates
##########################################################################
def fieldNames(col, downcase=True) -> List:
fields: Set[str] = set()
for m in col.models.all():
for f in m["flds"]:
name = f["name"].lower() if downcase else f["name"]
if name not in fields: # slower w/o
fields.add(name)
return list(fields)
# returns array of ("dupestr", [nids])
def findDupes(
col: Collection, fieldName: str, search: str = ""
) -> List[Tuple[Any, List]]:
# limit search to notes with applicable field name
if search:
search = "(" + search + ") "
search += '"%s:*"' % fieldName.replace('"', '"')
# 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