Show all accepted file types in import file picker

This commit is contained in:
RumovZ 2022-05-11 16:19:35 +02:00
parent b740be6554
commit 322e44fa3e
3 changed files with 122 additions and 90 deletions

View file

@ -1,6 +1,7 @@
importing-failed-debug-info = Import failed. Debugging info:
importing-aborted = Aborted: { $val }
importing-added-duplicate-with-first-field = Added duplicate with first field: { $val }
importing-all-supported-formats = All supported formats { $val }
importing-allow-html-in-fields = Allow HTML in fields
importing-anki-files-are-from-a-very = .anki files are from a very old version of Anki. You can import them with add-on 175027074 or with Anki 2.0, available on the Anki website.
importing-anki2-files-are-not-directly-importable = .anki2 files are not directly importable - please import the .apkg or .zip file you have received instead.

View file

@ -3,77 +3,58 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from itertools import chain
from typing import Type
import aqt.main
from anki.collection import Collection, ImportLogWithChanges, Progress
from anki.errors import Interrupted
from anki.foreign_data import mnemosyne
from anki.lang import without_unicode_isolation
from aqt.operations import CollectionOp, QueryOp
from aqt.progress import ProgressUpdate
from aqt.qt import *
from aqt.utils import askUser, getFile, showInfo, showText, showWarning, tooltip, tr
from aqt.utils import askUser, getFile, showText, showWarning, tooltip, tr
def import_file(mw: aqt.main.AnkiQt, path: str) -> None:
filename = os.path.basename(path).lower()
if filename.endswith(".anki"):
showInfo(tr.importing_anki_files_are_from_a_very())
elif filename.endswith(".anki2"):
showInfo(tr.importing_anki2_files_are_not_directly_importable())
elif is_collection_package(filename):
maybe_import_collection_package(mw, path)
elif filename.endswith(".apkg") or filename.endswith(".zip"):
import_anki_package(mw, path)
elif filename.endswith(".db"):
import_mnemosyne(mw, path)
else:
import aqt.import_export.import_dialog
class Importer(ABC):
accepted_file_endings: list[str]
aqt.import_export.import_dialog.ImportDialog(mw, path)
def prompt_for_file_then_import(mw: aqt.main.AnkiQt) -> None:
if path := get_file_path(mw):
import_file(mw, path)
def get_file_path(mw: aqt.main.AnkiQt) -> str | None:
if file := getFile(
mw, tr.actions_import(), None, key="import", filter=file_filter()
):
return str(file)
return None
def file_filter() -> str:
return ";;".join(
(
tr.importing_packaged_anki_deckcollection_apkg_colpkg_zip(),
tr.importing_text_separated_by_tabs_or_semicolons(),
tr.importing_mnemosyne_20_deck_db(),
)
@classmethod
def can_import(cls, lowercase_filename: str) -> bool:
return any(
lowercase_filename.endswith(ending) for ending in cls.accepted_file_endings
)
@classmethod
@abstractmethod
def do_import(cls, mw: aqt.main.AnkiQt, path: str) -> None:
...
def is_collection_package(filename: str) -> bool:
class ColpkgImporter(Importer):
accepted_file_endings = [".apkg", ".colpkg"]
@staticmethod
def can_import(filename: str) -> bool:
return (
filename == "collection.apkg"
or (filename.startswith("backup-") and filename.endswith(".apkg"))
or filename.endswith(".colpkg")
)
def maybe_import_collection_package(mw: aqt.main.AnkiQt, path: str) -> None:
@staticmethod
def do_import(mw: aqt.main.AnkiQt, path: str) -> None:
if askUser(
tr.importing_this_will_delete_your_existing_collection(),
msgfunc=QMessageBox.warning,
defaultno=True,
):
import_collection_package(mw, path)
ColpkgImporter._import(mw, path)
def import_collection_package(mw: aqt.main.AnkiQt, file: str) -> None:
@staticmethod
def _import(mw: aqt.main.AnkiQt, file: str) -> None:
def on_success() -> None:
mw.loadCollection()
tooltip(tr.importing_importing_complete())
@ -94,6 +75,80 @@ def import_collection_package(mw: aqt.main.AnkiQt, file: str) -> None:
).with_progress().run_in_background()
class ApkgImporter(Importer):
accepted_file_endings = [".apkg", ".zip"]
@staticmethod
def do_import(mw: aqt.main.AnkiQt, path: str) -> None:
CollectionOp(
parent=mw,
op=lambda col: col.import_anki_package(path),
).with_backend_progress(import_progress_update).success(
show_import_log
).run_in_background()
class MnemosyneImporter(Importer):
accepted_file_endings = [".db"]
@staticmethod
def do_import(mw: aqt.main.AnkiQt, path: str) -> None:
QueryOp(
parent=mw,
op=lambda _: mnemosyne.serialize(path),
success=lambda json: import_json(mw, json),
).with_progress().run_in_background()
class CsvImporter(Importer):
accepted_file_endings = [".csv", ".tsv", ".txt"]
@staticmethod
def do_import(mw: aqt.main.AnkiQt, path: str) -> None:
import aqt.import_export.import_dialog
aqt.import_export.import_dialog.ImportDialog(mw, path)
IMPORTERS: list[Type[Importer]] = [
ColpkgImporter,
ApkgImporter,
MnemosyneImporter,
CsvImporter,
]
def import_file(mw: aqt.main.AnkiQt, path: str) -> None:
filename = os.path.basename(path).lower()
for importer in IMPORTERS:
if importer.can_import(filename):
importer.do_import(mw, path)
return
showWarning("Unsupported file type.")
def prompt_for_file_then_import(mw: aqt.main.AnkiQt) -> None:
if path := get_file_path(mw):
import_file(mw, path)
def get_file_path(mw: aqt.main.AnkiQt) -> str | None:
filter = without_unicode_isolation(
tr.importing_all_supported_formats(
val="({})".format(
" ".join(f"*{ending}" for ending in all_accepted_file_endings())
)
)
)
if file := getFile(mw, tr.actions_import(), None, key="import", filter=filter):
return str(file)
return None
def all_accepted_file_endings() -> set[str]:
return set(chain(*(importer.accepted_file_endings for importer in IMPORTERS)))
def import_collection_package_op(
mw: aqt.main.AnkiQt, path: str, success: Callable[[], None]
) -> QueryOp[None]:
@ -113,23 +168,6 @@ def import_collection_package_op(
)
def import_anki_package(mw: aqt.main.AnkiQt, path: str) -> None:
CollectionOp(
parent=mw,
op=lambda col: col.import_anki_package(path),
).with_backend_progress(import_progress_update).success(
show_import_log
).run_in_background()
def import_mnemosyne(mw: aqt.main.AnkiQt, path: str) -> None:
QueryOp(
parent=mw,
op=lambda _: mnemosyne.serialize(path),
success=lambda json: import_json(mw, json),
).with_progress().run_in_background()
def import_json(mw: aqt.main.AnkiQt, json: str) -> None:
CollectionOp(parent=mw, op=lambda col: col.import_json(json)).with_backend_progress(
import_progress_update

View file

@ -13,12 +13,11 @@ import aqt.forms
import aqt.modelchooser
from anki.importing.anki2 import MediaMapInvalid, V2ImportIntoV1
from anki.importing.apkg import AnkiPackageImporter
from aqt.import_export.importing import import_collection_package
from aqt.import_export.importing import ColpkgImporter
from aqt.main import AnkiQt, gui_hooks
from aqt.qt import *
from aqt.utils import (
HelpPage,
askUser,
disable_help_button,
getFile,
getText,
@ -437,11 +436,5 @@ def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool:
if not full:
# adding
return True
if askUser(
tr.importing_this_will_delete_your_existing_collection(),
msgfunc=QMessageBox.warning,
defaultno=True,
):
import_collection_package(mw, importer.file)
ColpkgImporter.do_import(mw, importer.file)
return False