Creating and editing *.apkg and *.anki2 safely
Project description
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
│ ├── example.anki2
│ ├── media
│ ├── 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.
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.anki import Anki2, Apkg
apkg = Apkg("example.apkg") # Or Apkg("example/") also works, otherwise the folder named 'example' will be created.
apkg.db.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.
iter_apkg = iter(apkg)
for i in range(5):
print(next(iter_apkg))
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.
from ankisync2.anki import Apkg
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
from ankisync2 import db
m = db.Models.create(name="foo", flds=["field1", "field2"])
d = db.Decks.create(name="bar::baz")
t = [
db.Templates.create(name="fwd", mid=m.id, qfmt="{{field1}}", afmt="{{field2}}"),
db.Templates.create(name="bwd", mid=m.id, qfmt="{{field2}}", afmt="{{field1}}")
]
n = db.Notes.create(mid=m.id, flds=["data1", "<img src='media.jpg'>"], tags=["tag1", "tag2"])
c = [
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.zip(output="example1.apkg")
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.util import DataclassJSONEncoder
import json
json.dumps(dataclassObject, cls=DataclassJSONEncoder)
For an example of how this works, please see /ankisync2/anki.py#L56
Using peewee
framework
You can also use peewee
ORM framework; and ArrayField, X1fField and JSONField will be automated. You can use Dataclasses and Lists directly, without converting them to string first.
Examples
Please see /example.ipynb.
Installation
pip install ankisync2
Related projects
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for ankisync2-0.2.2.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 99c0c40171f072b3272afd42648d40c71d099c1af23cfbe430c9fa9b9d7a8182 |
|
MD5 | 989a05eb92443b88a76df63e47085922 |
|
BLAKE2b-256 | 492a06c64246a667df53c4c3fc69314374b0a7a62cf9ff710dee0ec37a4e4824 |