Import Anki decks with their files and history

Files in content: the person's images and sounds as asset rows synced like
all content, their files kept by hash on each device, uploaded after each
sync, downloaded on demand and checked against their hash
(core/asset/AssetRepository). Rich text names them as asset:<id> URLs, in
the editor's image block and an audio block of ours; any other URL is never
fetched. Sounds play through audioplayers, one at a time. Content holding
only an image or a sound isn't blank, and lists show it as such.

The Anki import ("Import from Anki" under Add material): .apkg and .colpkg
packages in all three formats Anki has written, read on an isolate of their
own. Modern packages compress everything with zstd in frames that don't
record their size, which pure_zstd v1.0.0 refuses; our fork decodes them.
Fields become rich text by a converter of our own (lines, lists, formatting,
images, sounds, cloze deletions hidden on the front). One card per note,
the files first, studysets as chosen (flatten, sub-studysets, or tags by
subdeck), the notes' tags, and, if wanted, the review history, which FSRS
replays: the first template's reviews to the card's schedule, a reversed
note type's second to the reverse one.

Imported cards say where they came from in their first revision (card
schema 3); the dashboard doesn't count them as written. The test fixtures
are exported by Anki itself (tool/anki/make_fixtures.py).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-02 04:52:02 +02:00
commit a6d5769a2e
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -90,6 +90,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.13.1"
audioplayers:
dependency: transitive
description:
name: audioplayers
sha256: "2ba4bb2944baacbdd5372ff8254a8e7feb8c10d7739545e392f5605a8f618745"
url: "https://pub.dev"
source: hosted
version: "6.8.1"
audioplayers_android:
dependency: transitive
description:
name: audioplayers_android
sha256: f5ff5b15620fbab8cb0849e9636c48e2b96c3f0f71723bbbe2ad3c761b205f05
url: "https://pub.dev"
source: hosted
version: "5.3.0"
audioplayers_darwin:
dependency: transitive
description:
name: audioplayers_darwin
sha256: "1ca553add991384ecf421b9569da850f3ab2472ffb83f6970b0416365abc51be"
url: "https://pub.dev"
source: hosted
version: "6.5.0"
audioplayers_linux:
dependency: transitive
description:
name: audioplayers_linux
sha256: "15178b726b7cdee5364d0463c8d445630c4e0fb7d26612b73c767e7d25de9417"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
audioplayers_platform_interface:
dependency: transitive
description:
name: audioplayers_platform_interface
sha256: "765f6f0e6dca55cb471c9483fc77700564b3484d19198aca4ebb5147c6c85acb"
url: "https://pub.dev"
source: hosted
version: "7.2.0"
audioplayers_web:
dependency: transitive
description:
name: audioplayers_web
sha256: ae1e0103c865a03e273f6d13d97b93f5595eac09915729cd5e37ef96e2857319
url: "https://pub.dev"
source: hosted
version: "5.3.0"
audioplayers_windows:
dependency: transitive
description:
name: audioplayers_windows
sha256: a70ae82bba2dfcb6eb03dd4815d737a2d46d33ea5a96a03f535cfcaac490e413
url: "https://pub.dev"
source: hosted
version: "4.4.1"
barcode:
dependency: transitive
description:
@ -418,6 +474,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
file_selector:
dependency: transitive
description:
name: file_selector
sha256: bd15e43e9268db636b53eeaca9f56324d1622af30e5c34d6e267649758c84d9a
url: "https://pub.dev"
source: hosted
version: "1.1.0"
file_selector_android:
dependency: transitive
description:
name: file_selector_android
sha256: d670cd0ce77a2e785b18d8b4d0a8d6a222d6a813ec9b7ddf2790a1b4fb6fa92c
url: "https://pub.dev"
source: hosted
version: "0.5.2+11"
file_selector_ios:
dependency: transitive
description:
name: file_selector_ios
sha256: "97269e5307a0ab813b1fa2430bada0a96e0afb74848417f8676f64ba5de0051c"
url: "https://pub.dev"
source: hosted
version: "0.5.3+6"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: da76400e7872ce7637ffdce12749ec24169c25f6195c28372208e65a24bcd2ab
url: "https://pub.dev"
source: hosted
version: "0.9.4+1"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: d57c62362766b5e7ae739448650b66c6aab7a68ba7ecc65e04018652645ae0f4
url: "https://pub.dev"
source: hosted
version: "0.9.5+1"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85"
url: "https://pub.dev"
source: hosted
version: "2.7.0"
file_selector_web:
dependency: transitive
description:
name: file_selector_web
sha256: "73181fbc5257776d8ecaa6a94ab3c8e920ad143b9132a6d984a9271dfc6928d3"
url: "https://pub.dev"
source: hosted
version: "0.9.5"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: fbefc5fb92c6d3cbe8d284a2cd971b593bb07d2cd6da8557b81a862250b4acec
url: "https://pub.dev"
source: hosted
version: "0.9.3+6"
fixnum:
dependency: transitive
description:
@ -1096,6 +1216,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.1"
pure_zstd:
dependency: transitive
description:
path: "."
ref: "596b63d5741d479073fbfc78377cc7dbdd342da3"
resolved-ref: "596b63d5741d479073fbfc78377cc7dbdd342da3"
url: "https://code.halkyon.app/project-halkyon/pure-zstd.git"
source: git
version: "1.0.0"
qr:
dependency: transitive
description: