{ "info": { "author": "Pacharapol Withayasakpunt", "author_email": "patarapolw@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7" ], "description": "# AnkiSync 2\n\n[![PyPI version shields.io](https://img.shields.io/pypi/v/ankisync2.svg)](https://pypi.python.org/pypi/ankisync2/)\n[![PyPI license](https://img.shields.io/pypi/l/ankisync2.svg)](https://pypi.python.org/pypi/ankisync2/)\n\n\\*.apkg and \\*.anki2 file structure is very simple, but with some quirks of incompleteness.\n\n[\\*.apkg file structure](https://github.com/ankidroid/Anki-Android/wiki/Database-Structure) is a zip of at least two files.\n\n```\n.\n\u251c\u2500\u2500 example\n\u2502 \u251c\u2500\u2500 example.anki2\n\u2502 \u251c\u2500\u2500 media\n\u2502 \u251c\u2500\u2500 1 # Media files with the names masked as integers\n\u2502 \u251c\u2500\u2500 2\n\u2502 \u251c\u2500\u2500 3\n| \u2514\u2500\u2500 ...\n\u2514\u2500\u2500 example.apkg\n```\n\n\\*.anki2 is a SQLite file with foreign key disabled, and the usage of [some JSON schemas](/ankisync2/builder.py) instead of [some tables](/ankisync2/db.py#L46)\n\nAlso, \\*.anki2 is used internally at [`os.path.join(appdirs.user_data_dir('Anki2'), 'User 1', 'collection.anki2')`](https://github.com/patarapolw/ankisync/blob/master/ankisync/dir.py#L9), so editing the SQLite there will also edit the database.\n\nThe `media` file is a text file of at least a string of `{}`, which is actually a dictionary of keys -- stringified int; and values -- filenames.\n\n## Usage\n\nSome [extra tables](/ankisync2/db.py#L46) are created if not exists.\n\n```python\nfrom ankisync2.anki import Anki2, Apkg\napkg = Apkg(\"example.apkg\") # Or Apkg(\"example/\") also works, otherwise the folder named 'example' will be created.\napkg.db.execute_sql(SQL, PARAMS)\napkg.zip(output=\"example1.apkg\")\n```\n\nI also support adding media.\n\n```python\napkg.add_media(\"path/to/media.jpg\")\n```\n\nTo find the wanted cards and media, iterate though the `Apkg` and `Apkg.iter_media` object.\n\n```python\niter_apkg = iter(apkg)\nfor i in range(5):\n print(next(iter_apkg))\n```\n\n## Creating a new *.apkg\n\nYou 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.\n\n```python\nfrom ankisync2.anki import Apkg\napkg = Apkg(\"example\") # Create example folder\n```\n\nAfter 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.\n\n1. Model, Deck\n2. Template, Note\n3. Card\n\n```python\nfrom ankisync2 import db\nm = db.Models.create(name=\"foo\", flds=[\"field1\", \"field2\"])\nd = db.Decks.create(name=\"bar::baz\")\nt = [\n db.Templates.create(name=\"fwd\", mid=m.id, qfmt=\"{{field1}}\", afmt=\"{{field2}}\"),\n db.Templates.create(name=\"bwd\", mid=m.id, qfmt=\"{{field2}}\", afmt=\"{{field1}}\") \n]\nn = db.Notes.create(mid=m.id, flds=[\"data1\", \"\"], tags=[\"tag1\", \"tag2\"])\nc = [\n db.Cards.create(nid=n.id, did=d.id, ord=i)\n for i, _ in enumerate(t)\n]\n```\n\nYou can also add media, which is not related to the SQLite database.\n\n```python\napkg.add_media(\"path/to/media.jpg\")\n```\n\nFinally, finalize with\n\n```python\napkg.zip(output=\"example1.apkg\")\napkg.close()\n```\n\n## Updating an \\*.apkg\n\nThis is also possible, by modifying `db.Notes.data` as `sqlite_ext.JSONField`, with `peewee.signals`.\n\nIt is now as simple as,\n\n```python\nfrom ankisync2.anki import Apkg\nfrom ankisync2 import db\n\napkg = Apkg(\"example1.apkg\")\n\nfor n in db.Notes.filter(db.Notes.data[\"field1\"] == \"data1\"):\n n.data[\"field3\"] = \"data2\"\n n.save()\n\napkg.close()\n```\n\n## JSON schema of `Col.models`, `Col.decks`, `Col.conf` and `Col.dconf`\n\nI have created `dataclasses` for this at [/ankisync2/builder.py](/ankisync2/builder.py). To serialize it, use `dataclasses.asdict` or\n\n```python\nfrom ankisync2.util import DataclassJSONEncoder\nimport json\njson.dumps(dataclassObject, cls=DataclassJSONEncoder)\n```\n\nFor an example of how this works, please see [/ankisync2/anki.py#L56](/ankisync2/anki.py#L56)\n\n## Using `peewee` framework\n\nYou can also use `peewee` ORM framework; and [ArrayField](/ankisync2/db.py#L21), [X1fField](/ankisync2/db.py#L31) and [JSONField](/ankisync2/db.py#L31) will be automated. You can use Dataclasses and Lists directly, without converting them to string first.\n\n## Examples\n\nPlease see [/example.ipynb](/example.ipynb).\n\n## Installation\n\n```bash\npip install ankisync2\n```\n\n# Related projects\n\n- \n- \n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/patarapolw/ankisync2", "keywords": "anki,srs,memorization,spaced-repetition", "license": "MIT", "maintainer": "Pacharapol Withayasakpunt", "maintainer_email": "patarapolw@gmail.com", "name": "ankisync2", "package_url": "https://pypi.org/project/ankisync2/", "platform": "", "project_url": "https://pypi.org/project/ankisync2/", "project_urls": { "Homepage": "https://github.com/patarapolw/ankisync2", "Repository": "https://github.com/patarapolw/ankisync2" }, "release_url": "https://pypi.org/project/ankisync2/0.2.4.1/", "requires_dist": [ "peewee (>=3.9,<4.0)", "shortuuid (>=0.5.0,<0.6.0)" ], "requires_python": ">=3.7,<4.0", "summary": "Creating and editing *.apkg and *.anki2 safely", "version": "0.2.4.1" }, "last_serial": 5741221, "releases": { "0.2.0": [ { "comment_text": "", "digests": { "md5": "34d12741e46c4043f92188d67c9e3f26", "sha256": "641ebd3164001660891a61a092a006470388b6805b6dfc7f1c45f07cd15c7c8a" }, "downloads": -1, "filename": "ankisync2-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "34d12741e46c4043f92188d67c9e3f26", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 11130, "upload_time": "2019-07-30T06:23:05", "url": "https://files.pythonhosted.org/packages/a9/fa/a7275b655062e6b2ea800da727aaae41446cb2ce3b682adc0043ac25adbd/ankisync2-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "17cfc4a49f8a38968083837e2af0778e", "sha256": "ae3196a47dbd4f622520297c02b5636c1a9250f4575eb1af4bb114d9ba1e34d8" }, "downloads": -1, "filename": "ankisync2-0.2.0.tar.gz", "has_sig": false, "md5_digest": "17cfc4a49f8a38968083837e2af0778e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 9392, "upload_time": "2019-07-30T06:23:08", "url": "https://files.pythonhosted.org/packages/9d/5d/dd042941ea7a66e8f147e9f3becb598964e3d58e9cdb4373fea860b31ded/ankisync2-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "a34b43517fc2a2d0381ba0f7ccfb473f", "sha256": "eb9c84c744cf90967e3ad26a6ac16afc6d6047c4de837fc20e171a2ccaad5b03" }, "downloads": -1, "filename": "ankisync2-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "a34b43517fc2a2d0381ba0f7ccfb473f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 9149, "upload_time": "2019-07-30T09:37:39", "url": "https://files.pythonhosted.org/packages/66/d8/ae5e562c32e2f939f855fdc957c0e312fd06c41a3df869bdfab508141ffc/ankisync2-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "52157875210272383dc361e26c48bd19", "sha256": "5c941dda65278bc7e836028e73540755aafe3fcfe354842bbc781397dfd0d8e3" }, "downloads": -1, "filename": "ankisync2-0.2.1.tar.gz", "has_sig": false, "md5_digest": "52157875210272383dc361e26c48bd19", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 8142, "upload_time": "2019-07-30T09:37:42", "url": "https://files.pythonhosted.org/packages/c6/2c/edd9f9bfaf042888fede7cfb13ab70caaf913518fde129642dfb58e1e3a2/ankisync2-0.2.1.tar.gz" } ], "0.2.1.1": [ { "comment_text": "", "digests": { "md5": "723c5722268a3a902e1a84a9df9b6dac", "sha256": "d765713545f7b449e7665c187126d9d5b787f09efc1ad31e54c00d6495ab3f09" }, "downloads": -1, "filename": "ankisync2-0.2.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "723c5722268a3a902e1a84a9df9b6dac", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 9161, "upload_time": "2019-07-30T09:42:49", "url": "https://files.pythonhosted.org/packages/9f/8e/c31b562e6d39c0a7925d79810c6d2fa8b6c5fb1b21fdf6eba8ec795db564/ankisync2-0.2.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2da8894abba1c6e54f0d27c7d48c2b12", "sha256": "80492b0e0acc3285fee7a097431d71a6da2aca75fdce50c64e875155866da296" }, "downloads": -1, "filename": "ankisync2-0.2.1.1.tar.gz", "has_sig": false, "md5_digest": "2da8894abba1c6e54f0d27c7d48c2b12", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 8152, "upload_time": "2019-07-30T09:42:50", "url": "https://files.pythonhosted.org/packages/ff/02/5e5386d62854b3957ebe92bb0662bb696ff2c8d8c7ff6bc7e02ba80d7187/ankisync2-0.2.1.1.tar.gz" } ], "0.2.1.2": [ { "comment_text": "", "digests": { "md5": "fc584dbc65cc25768dec6f28b76c0cdb", "sha256": "e4697e9984676d116210bdbe7354cd9edb04e604cd460486b6815fa924b177d1" }, "downloads": -1, "filename": "ankisync2-0.2.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "fc584dbc65cc25768dec6f28b76c0cdb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 9244, "upload_time": "2019-07-30T10:10:01", "url": "https://files.pythonhosted.org/packages/42/60/437f1eb12923f8f81381c02c87250b7d6b93a3ff3750737cfcd417803fe3/ankisync2-0.2.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8079c9f2db2ef1d44da3274e0fe5194d", "sha256": "8d2d7ff5ee4056972ed2a481a8f8e8d06309a59e605eaa76285efc6f2da8ae60" }, "downloads": -1, "filename": "ankisync2-0.2.1.2.tar.gz", "has_sig": false, "md5_digest": "8079c9f2db2ef1d44da3274e0fe5194d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 8220, "upload_time": "2019-07-30T10:10:03", "url": "https://files.pythonhosted.org/packages/07/9b/676247e291607846385493261b0d150a0879a1b7ed7bfe1930e6d49a45f4/ankisync2-0.2.1.2.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "5b0a117d75b4df6b9a6992e3d07dab10", "sha256": "68d70e7c85795f7df56c446ea8da045d0a47c7dffb8ae00fbc1e51cddc186c14" }, "downloads": -1, "filename": "ankisync2-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5b0a117d75b4df6b9a6992e3d07dab10", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 9236, "upload_time": "2019-07-30T10:17:09", "url": "https://files.pythonhosted.org/packages/98/91/c030ff22641252f7581f53316d13c8d70cdad37cab64e30ff1432066a087/ankisync2-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "72f3cffec8e853fbd21d39b9c7bc6cd5", "sha256": "156be381a4d79374778f526d1a973f06a5c73290b79e12939da62cd99ccdee88" }, "downloads": -1, "filename": "ankisync2-0.2.2.tar.gz", "has_sig": false, "md5_digest": "72f3cffec8e853fbd21d39b9c7bc6cd5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 8228, "upload_time": "2019-07-30T10:17:11", "url": "https://files.pythonhosted.org/packages/b3/b2/a9c43bff2783205e764b653f7193ec3ef4841dadb825912b7f774b8e866a/ankisync2-0.2.2.tar.gz" } ], "0.2.2.1": [ { "comment_text": "", "digests": { "md5": "989a05eb92443b88a76df63e47085922", "sha256": "99c0c40171f072b3272afd42648d40c71d099c1af23cfbe430c9fa9b9d7a8182" }, "downloads": -1, "filename": "ankisync2-0.2.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "989a05eb92443b88a76df63e47085922", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 10967, "upload_time": "2019-07-30T10:23:36", "url": "https://files.pythonhosted.org/packages/49/2a/06c64246a667df53c4c3fc69314374b0a7a62cf9ff710dee0ec37a4e4824/ankisync2-0.2.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6666d6bc996221bc04fc3919bbd89d4b", "sha256": "8a2932f9b0da364978900cc026c36b54781538c65f4a392a589825a78ee84be3" }, "downloads": -1, "filename": "ankisync2-0.2.2.1.tar.gz", "has_sig": false, "md5_digest": "6666d6bc996221bc04fc3919bbd89d4b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 11811, "upload_time": "2019-07-30T10:23:39", "url": "https://files.pythonhosted.org/packages/51/c1/78add72c0fcb17bd28c72f624e8ad049ea277e183c0dccae501bd9a67601/ankisync2-0.2.2.1.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "cd6793fe2489b0f480735bcd2ac61c7e", "sha256": "a6f544bff0dc41bc73aa98c3a8efc0374c26a9c2102625c84baee2ae562ffa42" }, "downloads": -1, "filename": "ankisync2-0.2.3-py3-none-any.whl", "has_sig": false, "md5_digest": "cd6793fe2489b0f480735bcd2ac61c7e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 10960, "upload_time": "2019-08-28T06:11:54", "url": "https://files.pythonhosted.org/packages/15/62/b7966004ba0f6d7a1456c3b7e0860b8bb7c03477d2297e80a5f9d5a0ad68/ankisync2-0.2.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3935c910b7b3a2dd1037513d321d2cc5", "sha256": "0b9648b9668cc05588c285453ab0c99d6b6eaebe9d4cef6705c5b60154282522" }, "downloads": -1, "filename": "ankisync2-0.2.3.tar.gz", "has_sig": false, "md5_digest": "3935c910b7b3a2dd1037513d321d2cc5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 11796, "upload_time": "2019-08-28T06:11:56", "url": "https://files.pythonhosted.org/packages/85/ba/b27a9375a437c3b093de9aa5a63255186d5bb952ffa5938575ef21129759/ankisync2-0.2.3.tar.gz" } ], "0.2.4": [ { "comment_text": "", "digests": { "md5": "2bb3bb3de22cce1096cd9910163182f2", "sha256": "ff5dbca3e68f6890ec4908db166caa136678ff90808676a2e87e7bc1db584be8" }, "downloads": -1, "filename": "ankisync2-0.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "2bb3bb3de22cce1096cd9910163182f2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 11295, "upload_time": "2019-08-28T07:41:25", "url": "https://files.pythonhosted.org/packages/7b/f4/6371d63a3f6cbf51863c5d4aa151f8730e4bbeed6d727ec77064afe8f0a7/ankisync2-0.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "79ca4c636498a791725480d240ca2f08", "sha256": "a2d1abf52effaf8ab3d0f2bf624bb8eebf08ad15393786a71a13339da3974941" }, "downloads": -1, "filename": "ankisync2-0.2.4.tar.gz", "has_sig": false, "md5_digest": "79ca4c636498a791725480d240ca2f08", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 12272, "upload_time": "2019-08-28T07:41:28", "url": "https://files.pythonhosted.org/packages/0a/0f/4b8614cb54ae4f2456eb3b5f5c221ad61c15ca824546fb257e985ecbc075/ankisync2-0.2.4.tar.gz" } ], "0.2.4.1": [ { "comment_text": "", "digests": { "md5": "6b595ecdb668d02b6e3e96e73e59d5ca", "sha256": "da15326f2815660c473e3ec1b9b31e3297fd24560eb0393d4696ff1c9a92268b" }, "downloads": -1, "filename": "ankisync2-0.2.4.1-py3-none-any.whl", "has_sig": false, "md5_digest": "6b595ecdb668d02b6e3e96e73e59d5ca", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 11323, "upload_time": "2019-08-28T07:59:53", "url": "https://files.pythonhosted.org/packages/06/9b/01d7c37fc6e6bc761c85b710b9b0cdcfe4b643f9d67adf865892c7c5ae28/ankisync2-0.2.4.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e0a8bdc37f6dcbde55350643fac899a7", "sha256": "51be00ab5523f136db81d344f308fc70872859ea4310a959c67d07ee9f254b2c" }, "downloads": -1, "filename": "ankisync2-0.2.4.1.tar.gz", "has_sig": false, "md5_digest": "e0a8bdc37f6dcbde55350643fac899a7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 12293, "upload_time": "2019-08-28T07:59:55", "url": "https://files.pythonhosted.org/packages/cb/78/1eeb9e2510b2eb7ccb0d9c2a0bbbc11c9ed05a01695673bd3101af94e60e/ankisync2-0.2.4.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6b595ecdb668d02b6e3e96e73e59d5ca", "sha256": "da15326f2815660c473e3ec1b9b31e3297fd24560eb0393d4696ff1c9a92268b" }, "downloads": -1, "filename": "ankisync2-0.2.4.1-py3-none-any.whl", "has_sig": false, "md5_digest": "6b595ecdb668d02b6e3e96e73e59d5ca", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 11323, "upload_time": "2019-08-28T07:59:53", "url": "https://files.pythonhosted.org/packages/06/9b/01d7c37fc6e6bc761c85b710b9b0cdcfe4b643f9d67adf865892c7c5ae28/ankisync2-0.2.4.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e0a8bdc37f6dcbde55350643fac899a7", "sha256": "51be00ab5523f136db81d344f308fc70872859ea4310a959c67d07ee9f254b2c" }, "downloads": -1, "filename": "ankisync2-0.2.4.1.tar.gz", "has_sig": false, "md5_digest": "e0a8bdc37f6dcbde55350643fac899a7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 12293, "upload_time": "2019-08-28T07:59:55", "url": "https://files.pythonhosted.org/packages/cb/78/1eeb9e2510b2eb7ccb0d9c2a0bbbc11c9ed05a01695673bd3101af94e60e/ankisync2-0.2.4.1.tar.gz" } ] }