AnkiSync 2
*.apkg and *.anki2 file structure is very simple, but with some quirks of incompleteness.
*.apkg file structure is a zip of at least two files.
.
├── example
│ ├── collection.anki2
│ ├── collection.anki21 # newer Anki Desktop creates and uses this file instead, while retaining the old one as stub.
│ ├── media # JSON of dict[int, str]
│ ├── 1 # Media files with the names masked as integers
│ ├── 2
│ ├── 3
| └── ...
└── example.apkg
*.anki2 is a SQLite file with foreign key disabled, and the usage of some JSON schemas instead of some tables
Also, *.anki2 is used internally at os.path.join(appdirs.user_data_dir('Anki2'), 'User 1', 'collection.anki2'), so editing the SQLite there will also edit the database.
However, internal *.anki2 has recently changed. If you need to edit internally, if maybe safer to do in Anki<=2.1.26. If you have trouble running two Anki versions (latest and 2.1.26), see /__utils__/anki2.1.26.
The media file is a text file of at least a string of {}, which is actually a dictionary of keys -- stringified int; and values -- filenames.
Usage
Some extra tables are created if not exists.
from ankisync2 import Apkg
with Apkg("example.apkg") as apkg:
# Or Apkg("example/") also works - the folder named 'example' will be created.
apkg.db.database.execute_sql(SQL, PARAMS)
apkg.zip(output="example1.apkg")
I also support adding media.
apkg.add_media("path/to/media.jpg")
To find the wanted cards and media, iterate though the Apkg and Apkg.iter_media object.
for card in apkg:
print(card)
Creating a new *.apkg
You can create a new *.apkg via Apkg with any custom filename (and *.anki2 via Anki2()). A folder required to create *.apkg needs to be created first.
apkg = Apkg("example") # Create example folder
After that, the Apkg will require at least 1 card, which is connected to at least 1 note, 1 model, 1 template, and 1 deck; which should be created in this order.
- Model, Deck
- Template, Note
- Card
with Apkg("example.apkg") as apkg:
m = apkg.db.Models.create(name="foo", flds=["field1", "field2"])
d = apkg.db.Decks.create(name="bar::baz")
t = [
apkg.db.Templates.create(name="fwd", mid=m.id, qfmt="{{field1}}", afmt="{{field2}}"),
apkg.db.Templates.create(name="bwd", mid=m.id, qfmt="{{field2}}", afmt="{{field1}}")
]
n = apkg.db.Notes.create(mid=m.id, flds=["data1", "<img src='media.jpg'>"], tags=["tag1", "tag2"])
c = [
apkg.db.Cards.create(nid=n.id, did=d.id, ord=i)
for i, _ in enumerate(t)
]
You can also add media, which is not related to the SQLite database.
apkg.add_media("path/to/media.jpg")
Finally, finalize with
apkg.export("example1.apkg")
Updating an *.apkg
This is also possible, by modifying db.Notes.data as sqlite_ext.JSONField, with peewee.signals.
It is now as simple as,
with Apkg("example1.apkg") as apkg:
for n in apkg.db.Notes.filter(db.Notes.data["field1"] == "data1"):
n.data["field3"] = "data2"
n.save()
apkg.close()
JSON schema of Col.models, Col.decks, Col.conf and Col.dconf
I have created dataclasses for this at /ankisync2/builder.py. To serialize it, use dataclasses.asdict or
from ankisync2 import DataclassJSONEncoder
import json
json.dumps(dataclassObject, cls=DataclassJSONEncoder)
Editing user's collection.anki2
This can be found at ${ankiPath}/${user}/collection.anki2. Of course, do this at your own risk. Always backup first.
from ankisync2 import AnkiDesktop
AnkiDesktop.backup("/path/to/anki-desktop.db")
anki = AnkiDesktop(filename="/path/to/anki-desktop.db")
... # Edit as you please
AnkiDesktop.restore("/path/to/anki-desktop.db")
Using peewee framework
This is based on peewee ORM framework. You can use Dataclasses and Lists directly, without converting them to string first.
Examples
Please see /__examples__, and /tests.
Installation
pip install ankisync2
Related projects
Metadata
Release files for ankisync2 0.3.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ankisync2-0.3.4.tar.gz | 16.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ankisync2-0.3.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.0 kB
Release files / ankisync2-0.3.4.tar.gz
| Download URL | ankisync2-0.3.4.tar.gz |
|---|---|
| Size | 16.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2d339c70b95ba39d2746c0f9825835354bc9adcde517b10a05380abc7031282d
|
|
BLAKE2b-256 checksum How to use checksums |
556cadcce683ec92c2fee19fa0fc8f3ab9522cd816b3b491db07fdb7774dc26e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.1.12 CPython/3.10.2 Linux/5.16.5-arch1-1
|
Release files / ankisync2-0.3.4-py3-none-any.whl
| Download URL | ankisync2-0.3.4-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57343fa0ce2c57166184440c5bf07b16114a5f4f69069eb5c40dd5b2cc84863c
|
|
BLAKE2b-256 checksum How to use checksums |
34c40a4e7b3878a5b5f1ebeec6e0395ad552131c96f1b9f7af066c74666ddc82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.1.12 CPython/3.10.2 Linux/5.16.5-arch1-1
|