# Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html from __future__ import annotations import json import os import unicodedata import zipfile from typing import Any from anki.importing.anki2 import Anki2Importer, MediaMapInvalid from anki.utils import tmpfile class AnkiPackageImporter(Anki2Importer): nameToNum: dict[str, str] zip: zipfile.ZipFile | None def run(self) -> None: # type: ignore # extract the deck from the zip file self.zip = z = zipfile.ZipFile(self.file) # v2 scheduler? try: z.getinfo("collection.anki21") suffix = ".anki21" except KeyError: suffix = ".anki2" col = z.read(f"collection{suffix}") colpath = tmpfile(suffix=".anki2") with open(colpath, "wb") as f: f.write(col) self.file = colpath # we need the media dict in advance, and we'll need a map of fname -> # number to use during the import self.nameToNum = {} dir = self.col.media.dir() try: media_dict = json.loads(z.read("media").decode("utf8")) except Exception as exc: raise MediaMapInvalid() from exc for k, v in list(media_dict.items()): path = os.path.abspath(os.path.join(dir, v)) if os.path.commonprefix([path, dir]) != dir: raise Exception("Invalid file") self.nameToNum[unicodedata.normalize("NFC", v)] = k # run anki2 importer Anki2Importer.run(self, importing_v2=suffix == ".anki21") # import static media for file, c in list(self.nameToNum.items()): if not file.startswith("_") and not file.startswith("latex-"): continue path = os.path.join(self.col.media.dir(), file) if not os.path.exists(path): with open(path, "wb") as f: f.write(z.read(c)) def _srcMediaData(self, fname: str) -> Any: if fname in self.nameToNum: return self.zip.read( self.nameToNum[fname] ) # pytype: disable=attribute-error return None