mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
exporting, latex
This commit is contained in:
parent
55795822b5
commit
f170763ef1
2 changed files with 24 additions and 19 deletions
|
@ -11,23 +11,26 @@ from anki.hooks import runHook
|
||||||
from anki.storage import Collection
|
from anki.storage import Collection
|
||||||
from typing import Any, Dict, List, Tuple
|
from typing import Any, Dict, List, Tuple
|
||||||
|
|
||||||
|
from io import BufferedWriter
|
||||||
|
from anki.collection import _Collection
|
||||||
|
from zipfile import ZipFile
|
||||||
class Exporter:
|
class Exporter:
|
||||||
includeHTML: typing.Union[bool, None] = None
|
includeHTML: typing.Union[bool, None] = None
|
||||||
|
|
||||||
def __init__(self, col, did=None) -> None:
|
def __init__(self, col: _Collection, did: None = None) -> None:
|
||||||
self.col = col
|
self.col = col
|
||||||
self.did = did
|
self.did = did
|
||||||
|
|
||||||
def doExport(self, path) -> None:
|
def doExport(self, path) -> None:
|
||||||
raise Exception("not implemented")
|
raise Exception("not implemented")
|
||||||
|
|
||||||
def exportInto(self, path) -> None:
|
def exportInto(self, path: str) -> None:
|
||||||
self._escapeCount = 0
|
self._escapeCount = 0
|
||||||
file = open(path, "wb")
|
file = open(path, "wb")
|
||||||
self.doExport(file)
|
self.doExport(file)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
def processText(self, text) -> str:
|
def processText(self, text: str) -> str:
|
||||||
if self.includeHTML is False:
|
if self.includeHTML is False:
|
||||||
text = self.stripHTML(text)
|
text = self.stripHTML(text)
|
||||||
|
|
||||||
|
@ -35,7 +38,7 @@ class Exporter:
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def escapeText(self, text) -> str:
|
def escapeText(self, text: str) -> str:
|
||||||
"Escape newlines, tabs, CSS and quotechar."
|
"Escape newlines, tabs, CSS and quotechar."
|
||||||
# fixme: we should probably quote fields with newlines
|
# fixme: we should probably quote fields with newlines
|
||||||
# instead of converting them to spaces
|
# instead of converting them to spaces
|
||||||
|
@ -47,7 +50,7 @@ class Exporter:
|
||||||
text = "\"" + text.replace("\"", "\"\"") + "\""
|
text = "\"" + text.replace("\"", "\"\"") + "\""
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def stripHTML(self, text) -> str:
|
def stripHTML(self, text: str) -> str:
|
||||||
# very basic conversion to text
|
# very basic conversion to text
|
||||||
s = text
|
s = text
|
||||||
s = re.sub(r"(?i)<(br ?/?|div|p)>", " ", s)
|
s = re.sub(r"(?i)<(br ?/?|div|p)>", " ", s)
|
||||||
|
@ -101,11 +104,11 @@ class TextNoteExporter(Exporter):
|
||||||
includeTags = True
|
includeTags = True
|
||||||
includeHTML = True
|
includeHTML = True
|
||||||
|
|
||||||
def __init__(self, col) -> None:
|
def __init__(self, col: _Collection) -> None:
|
||||||
Exporter.__init__(self, col)
|
Exporter.__init__(self, col)
|
||||||
self.includeID = False
|
self.includeID = False
|
||||||
|
|
||||||
def doExport(self, file) -> None:
|
def doExport(self, file: BufferedWriter) -> None:
|
||||||
cardIds = self.cardIds()
|
cardIds = self.cardIds()
|
||||||
data = []
|
data = []
|
||||||
for id, flds, tags in self.col.db.execute("""
|
for id, flds, tags in self.col.db.execute("""
|
||||||
|
@ -138,10 +141,10 @@ class AnkiExporter(Exporter):
|
||||||
includeSched: typing.Union[bool, None] = False
|
includeSched: typing.Union[bool, None] = False
|
||||||
includeMedia = True
|
includeMedia = True
|
||||||
|
|
||||||
def __init__(self, col) -> None:
|
def __init__(self, col: _Collection) -> None:
|
||||||
Exporter.__init__(self, col)
|
Exporter.__init__(self, col)
|
||||||
|
|
||||||
def exportInto(self, path) -> None:
|
def exportInto(self, path: str) -> None:
|
||||||
# sched info+v2 scheduler not compatible w/ older clients
|
# sched info+v2 scheduler not compatible w/ older clients
|
||||||
self._v2sched = self.col.schedVer() != 1 and self.includeSched
|
self._v2sched = self.col.schedVer() != 1 and self.includeSched
|
||||||
|
|
||||||
|
@ -259,7 +262,7 @@ class AnkiExporter(Exporter):
|
||||||
# such as update the deck description
|
# such as update the deck description
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def removeSystemTags(self, tags) -> Any:
|
def removeSystemTags(self, tags: str) -> Any:
|
||||||
return self.src.tags.remFromStr("marked leech", tags)
|
return self.src.tags.remFromStr("marked leech", tags)
|
||||||
|
|
||||||
def _modelHasMedia(self, model, fname) -> bool:
|
def _modelHasMedia(self, model, fname) -> bool:
|
||||||
|
@ -280,10 +283,10 @@ class AnkiPackageExporter(AnkiExporter):
|
||||||
key = _("Anki Deck Package")
|
key = _("Anki Deck Package")
|
||||||
ext = ".apkg"
|
ext = ".apkg"
|
||||||
|
|
||||||
def __init__(self, col):
|
def __init__(self, col: _Collection) -> None:
|
||||||
AnkiExporter.__init__(self, col)
|
AnkiExporter.__init__(self, col)
|
||||||
|
|
||||||
def exportInto(self, path):
|
def exportInto(self, path: str) -> None:
|
||||||
# open a zip file
|
# open a zip file
|
||||||
z = zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED, allowZip64=True)
|
z = zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED, allowZip64=True)
|
||||||
media = self.doExport(z, path)
|
media = self.doExport(z, path)
|
||||||
|
@ -291,7 +294,7 @@ class AnkiPackageExporter(AnkiExporter):
|
||||||
z.writestr("media", json.dumps(media))
|
z.writestr("media", json.dumps(media))
|
||||||
z.close()
|
z.close()
|
||||||
|
|
||||||
def doExport(self, z, path) -> Dict[str, str]:
|
def doExport(self, z: ZipFile, path: str) -> Dict[str, str]:
|
||||||
# export into the anki2 file
|
# export into the anki2 file
|
||||||
colfile = path.replace(".apkg", ".anki2")
|
colfile = path.replace(".apkg", ".anki2")
|
||||||
AnkiExporter.exportInto(self, colfile)
|
AnkiExporter.exportInto(self, colfile)
|
||||||
|
@ -315,7 +318,7 @@ class AnkiPackageExporter(AnkiExporter):
|
||||||
shutil.rmtree(path.replace(".apkg", ".media"))
|
shutil.rmtree(path.replace(".apkg", ".media"))
|
||||||
return media
|
return media
|
||||||
|
|
||||||
def _exportMedia(self, z, files, fdir) -> Dict[str, str]:
|
def _exportMedia(self, z: ZipFile, files: List[str], fdir: str) -> Dict[str, str]:
|
||||||
media = {}
|
media = {}
|
||||||
for c, file in enumerate(files):
|
for c, file in enumerate(files):
|
||||||
cStr = str(c)
|
cStr = str(c)
|
||||||
|
|
|
@ -8,6 +8,8 @@ from anki.hooks import addHook
|
||||||
from anki.lang import _
|
from anki.lang import _
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
from typing import Any, Dict, List, Optional, Union
|
||||||
pngCommands = [
|
pngCommands = [
|
||||||
["latex", "-interaction=nonstopmode", "tmp.tex"],
|
["latex", "-interaction=nonstopmode", "tmp.tex"],
|
||||||
["dvipng", "-D", "200", "-T", "tight", "tmp.dvi", "-o", "tmp.png"]
|
["dvipng", "-D", "200", "-T", "tight", "tmp.dvi", "-o", "tmp.png"]
|
||||||
|
@ -38,7 +40,7 @@ def stripLatex(text) -> Any:
|
||||||
text = text.replace(match.group(), "")
|
text = text.replace(match.group(), "")
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def mungeQA(html, type, fields, model, data, col) -> Any:
|
def mungeQA(html: str, type: Optional[str], fields: Optional[Dict[str, str]], model: Dict[str, Any], data: Optional[List[Union[int, str]]], col) -> Any:
|
||||||
"Convert TEXT with embedded latex tags to image links."
|
"Convert TEXT with embedded latex tags to image links."
|
||||||
for match in regexps['standard'].finditer(html):
|
for match in regexps['standard'].finditer(html):
|
||||||
html = html.replace(match.group(), _imgLink(col, match.group(1), model))
|
html = html.replace(match.group(), _imgLink(col, match.group(1), model))
|
||||||
|
@ -51,7 +53,7 @@ def mungeQA(html, type, fields, model, data, col) -> Any:
|
||||||
"\\begin{displaymath}" + match.group(1) + "\\end{displaymath}", model))
|
"\\begin{displaymath}" + match.group(1) + "\\end{displaymath}", model))
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def _imgLink(col, latex, model) -> Any:
|
def _imgLink(col, latex: str, model: Dict[str, Any]) -> Any:
|
||||||
"Return an img link for LATEX, creating if necesssary."
|
"Return an img link for LATEX, creating if necesssary."
|
||||||
txt = _latexFromHtml(col, latex)
|
txt = _latexFromHtml(col, latex)
|
||||||
|
|
||||||
|
@ -76,13 +78,13 @@ def _imgLink(col, latex, model) -> Any:
|
||||||
else:
|
else:
|
||||||
return link
|
return link
|
||||||
|
|
||||||
def _latexFromHtml(col, latex) -> Any:
|
def _latexFromHtml(col, latex: str) -> Any:
|
||||||
"Convert entities and fix newlines."
|
"Convert entities and fix newlines."
|
||||||
latex = re.sub("<br( /)?>|<div>", "\n", latex)
|
latex = re.sub("<br( /)?>|<div>", "\n", latex)
|
||||||
latex = stripHTML(latex)
|
latex = stripHTML(latex)
|
||||||
return latex
|
return latex
|
||||||
|
|
||||||
def _buildImg(col, latex, fname, model) -> Any:
|
def _buildImg(col, latex: str, fname: str, model: Dict[str, Any]) -> Any:
|
||||||
# add header/footer
|
# add header/footer
|
||||||
latex = (model["latexPre"] + "\n" +
|
latex = (model["latexPre"] + "\n" +
|
||||||
latex + "\n" +
|
latex + "\n" +
|
||||||
|
@ -130,7 +132,7 @@ package in the LaTeX header instead.""") % bad
|
||||||
os.chdir(oldcwd)
|
os.chdir(oldcwd)
|
||||||
log.close()
|
log.close()
|
||||||
|
|
||||||
def _errMsg(type, texpath) -> Any:
|
def _errMsg(type: str, texpath: str) -> Any:
|
||||||
msg = (_("Error executing %s.") % type) + "<br>"
|
msg = (_("Error executing %s.") % type) + "<br>"
|
||||||
msg += (_("Generated file: %s") % texpath) + "<br>"
|
msg += (_("Generated file: %s") % texpath) + "<br>"
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue