codex 1.7.14__py3-none-any.whl → 1.8.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codex might be problematic. Click here for more details.
- codex/__init__.py +6 -1
- codex/applications/lifespan.py +16 -12
- codex/asgi.py +1 -2
- codex/choices/admin.py +63 -59
- codex/choices/browser.py +7 -10
- codex/choices/choices_to_json.py +21 -9
- codex/choices/search.py +133 -0
- codex/choices/statii.py +40 -0
- codex/librarian/bookmark/bookmarkd.py +56 -17
- codex/librarian/bookmark/latest_version.py +65 -0
- codex/librarian/bookmark/tasks.py +11 -1
- codex/librarian/bookmark/update.py +1 -1
- codex/librarian/bookmark/user_active.py +2 -3
- codex/librarian/covers/coverd.py +4 -1
- codex/librarian/covers/create.py +31 -22
- codex/librarian/covers/path.py +1 -1
- codex/librarian/covers/purge.py +22 -22
- codex/librarian/covers/status.py +37 -6
- codex/librarian/cron/crond.py +5 -3
- codex/librarian/librariand.py +57 -84
- codex/librarian/notifier/notifierd.py +8 -3
- codex/librarian/restarter/__init__.py +1 -0
- codex/librarian/restarter/restarter.py +55 -0
- codex/librarian/restarter/status.py +32 -0
- codex/librarian/restarter/tasks.py +13 -0
- codex/librarian/scribe/__init__.py +1 -0
- codex/librarian/scribe/importer/__init__.py +1 -0
- codex/librarian/scribe/importer/const.py +361 -0
- codex/librarian/scribe/importer/create/__init__.py +37 -0
- codex/librarian/scribe/importer/create/comics.py +172 -0
- codex/librarian/scribe/importer/create/const.py +131 -0
- codex/librarian/scribe/importer/create/covers.py +123 -0
- codex/librarian/scribe/importer/create/folders.py +98 -0
- codex/librarian/scribe/importer/create/foreign_keys.py +253 -0
- codex/librarian/scribe/importer/create/link_fks.py +73 -0
- codex/librarian/scribe/importer/delete/__init__.py +28 -0
- codex/librarian/scribe/importer/delete/comics.py +68 -0
- codex/librarian/scribe/importer/delete/covers.py +35 -0
- codex/librarian/scribe/importer/delete/folders.py +33 -0
- codex/librarian/scribe/importer/failed_imports.py +168 -0
- codex/librarian/scribe/importer/finish.py +70 -0
- codex/librarian/scribe/importer/importer.py +31 -0
- codex/librarian/scribe/importer/init.py +338 -0
- codex/librarian/scribe/importer/link/__init__.py +15 -0
- codex/librarian/scribe/importer/link/const.py +31 -0
- codex/librarian/scribe/importer/link/covers.py +70 -0
- codex/librarian/scribe/importer/link/delete.py +106 -0
- codex/librarian/scribe/importer/link/many_to_many.py +88 -0
- codex/librarian/scribe/importer/link/prepare.py +132 -0
- codex/librarian/scribe/importer/link/sum.py +19 -0
- codex/librarian/scribe/importer/moved/__init__.py +52 -0
- codex/librarian/scribe/importer/moved/comics.py +125 -0
- codex/librarian/scribe/importer/moved/covers.py +88 -0
- codex/librarian/scribe/importer/moved/folders.py +205 -0
- codex/librarian/scribe/importer/query/__init__.py +44 -0
- codex/librarian/scribe/importer/query/covers.py +55 -0
- codex/librarian/scribe/importer/query/filters.py +61 -0
- codex/librarian/scribe/importer/query/links.py +29 -0
- codex/librarian/scribe/importer/query/links_fk.py +99 -0
- codex/librarian/scribe/importer/query/links_m2m.py +102 -0
- codex/librarian/scribe/importer/query/query_fks.py +203 -0
- codex/librarian/scribe/importer/query/update_comics.py +59 -0
- codex/librarian/scribe/importer/query/update_fks.py +140 -0
- codex/librarian/scribe/importer/read/__init__.py +14 -0
- codex/librarian/scribe/importer/read/aggregate_path.py +108 -0
- codex/librarian/scribe/importer/read/const.py +144 -0
- codex/librarian/scribe/importer/read/extract.py +128 -0
- codex/librarian/scribe/importer/read/folders.py +37 -0
- codex/librarian/scribe/importer/read/foreign_keys.py +145 -0
- codex/librarian/scribe/importer/read/many_to_many.py +237 -0
- codex/librarian/scribe/importer/search/__init__.py +34 -0
- codex/librarian/scribe/importer/search/const.py +50 -0
- codex/librarian/scribe/importer/search/prepare.py +85 -0
- codex/librarian/scribe/importer/search/sync_m2m.py +84 -0
- codex/librarian/scribe/importer/search/update.py +245 -0
- codex/librarian/scribe/importer/statii/1 +27 -0
- codex/librarian/scribe/importer/statii/__init__.py +19 -0
- codex/librarian/scribe/importer/statii/create.py +67 -0
- codex/librarian/scribe/importer/statii/delete.py +39 -0
- codex/librarian/scribe/importer/statii/link.py +27 -0
- codex/librarian/scribe/importer/statii/moved.py +39 -0
- codex/librarian/scribe/importer/statii/query.py +46 -0
- codex/librarian/scribe/importer/statii/read.py +30 -0
- codex/librarian/scribe/importer/statii/search.py +28 -0
- codex/librarian/scribe/importer/status.py +21 -0
- codex/librarian/scribe/importer/tasks.py +49 -0
- codex/librarian/scribe/janitor/__init__.py +1 -0
- codex/librarian/scribe/janitor/adopt_folders.py +81 -0
- codex/librarian/scribe/janitor/cleanup.py +199 -0
- codex/librarian/scribe/janitor/failed_imports.py +27 -0
- codex/librarian/scribe/janitor/integrity.py +374 -0
- codex/librarian/scribe/janitor/janitor.py +125 -0
- codex/librarian/scribe/janitor/scheduled_time.py +13 -0
- codex/librarian/scribe/janitor/status.py +151 -0
- codex/librarian/scribe/janitor/tasks.py +71 -0
- codex/librarian/scribe/janitor/update.py +88 -0
- codex/librarian/scribe/janitor/vacuum.py +53 -0
- codex/librarian/scribe/lazy_importer.py +51 -0
- codex/librarian/scribe/priority.py +65 -0
- codex/librarian/scribe/scribed.py +130 -0
- codex/librarian/scribe/search/__init__.py +1 -0
- codex/librarian/scribe/search/handler.py +28 -0
- codex/librarian/scribe/search/optimize.py +31 -0
- codex/librarian/scribe/search/remove.py +44 -0
- codex/librarian/scribe/search/status.py +66 -0
- codex/librarian/scribe/search/sync.py +391 -0
- codex/librarian/scribe/search/tasks.py +28 -0
- codex/librarian/scribe/status.py +20 -0
- codex/librarian/scribe/tasks.py +31 -0
- codex/librarian/scribe/timestamp_update.py +135 -0
- codex/librarian/status.py +76 -0
- codex/librarian/status_controller.py +164 -0
- codex/librarian/tasks.py +0 -10
- codex/librarian/telemeter/scheduled_time.py +11 -4
- codex/librarian/telemeter/stats.py +0 -2
- codex/librarian/telemeter/tasks.py +3 -1
- codex/librarian/telemeter/telemeter.py +17 -11
- codex/librarian/threads.py +148 -0
- codex/librarian/watchdog/const.py +115 -0
- codex/librarian/watchdog/db_snapshot.py +16 -10
- codex/librarian/watchdog/dir_snapshot_diff.py +19 -1
- codex/librarian/watchdog/emitter.py +128 -102
- codex/librarian/watchdog/event_batcherd.py +120 -78
- codex/librarian/watchdog/events.py +22 -211
- codex/librarian/watchdog/handlers.py +203 -0
- codex/librarian/watchdog/memory.py +56 -0
- codex/librarian/watchdog/observers.py +94 -58
- codex/librarian/watchdog/status.py +18 -5
- codex/librarian/worker.py +32 -0
- codex/middleware.py +6 -8
- codex/migrations/0011_library_groups_and_metadata_changes.py +2 -1
- codex/migrations/0013_int_issue_count_longer_charfields.py +2 -1
- codex/migrations/0023_rename_credit_creator_and_more.py +2 -1
- codex/migrations/0026_comicbox_1.py +9 -9
- codex/migrations/0034_comicbox2.py +789 -0
- codex/models/__init__.py +1 -0
- codex/models/admin.py +13 -21
- codex/models/base.py +21 -2
- codex/models/comic.py +80 -43
- codex/models/fields.py +81 -0
- codex/models/functions.py +8 -2
- codex/models/groups.py +99 -34
- codex/models/identifier.py +79 -0
- codex/models/library.py +17 -3
- codex/models/named.py +52 -55
- codex/models/paths.py +16 -12
- codex/models/query.py +7 -5
- codex/run.py +12 -18
- codex/serializers/admin/groups.py +3 -0
- codex/serializers/admin/libraries.py +13 -1
- codex/serializers/admin/stats.py +5 -4
- codex/serializers/admin/tasks.py +3 -5
- codex/serializers/admin/users.py +9 -3
- codex/serializers/auth.py +13 -6
- codex/serializers/browser/choices.py +35 -18
- codex/serializers/browser/filters.py +7 -5
- codex/serializers/browser/metadata.py +12 -10
- codex/serializers/browser/mixins.py +6 -8
- codex/serializers/browser/mtime.py +6 -2
- codex/serializers/browser/page.py +8 -3
- codex/serializers/browser/settings.py +35 -5
- codex/serializers/fields/__init__.py +2 -2
- codex/serializers/fields/auth.py +4 -5
- codex/serializers/fields/base.py +16 -0
- codex/serializers/fields/browser.py +15 -31
- codex/serializers/fields/group.py +11 -8
- codex/serializers/fields/reader.py +14 -10
- codex/serializers/fields/sanitized.py +2 -0
- codex/serializers/fields/session.py +3 -8
- codex/serializers/fields/stats.py +3 -5
- codex/serializers/fields/vuetify.py +21 -10
- codex/serializers/mixins.py +42 -0
- codex/serializers/models/base.py +1 -1
- codex/serializers/models/comic.py +6 -2
- codex/serializers/models/named.py +62 -37
- codex/serializers/models/pycountry.py +0 -3
- codex/serializers/opds/v1.py +6 -6
- codex/serializers/opds/v2/feed.py +2 -4
- codex/serializers/opds/v2/publication.py +14 -14
- codex/serializers/opds/v2/unused.py +2 -0
- codex/serializers/reader.py +52 -31
- codex/serializers/route.py +6 -4
- codex/serializers/settings.py +6 -6
- codex/settings/__init__.py +424 -1
- codex/signals/django_signals.py +2 -35
- codex/signals/os_signals.py +4 -5
- codex/startup/__init__.py +180 -0
- codex/startup/db.py +130 -0
- codex/startup/logger_init.py +45 -0
- codex/startup/registration.py +13 -0
- codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js +1 -0
- codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.br +0 -0
- codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.gz +0 -0
- codex/static_root/assets/VCheckbox-DSndl51k.js +1 -0
- codex/static_root/assets/VCheckbox-DSndl51k.js.br +0 -0
- codex/static_root/assets/VCheckbox-DSndl51k.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js +1 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js +1 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.gz +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js +1 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.br +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.gz +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.js +1 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.js.br +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.js.gz +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js +1 -0
- codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.br +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.gz +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.js +1 -0
- codex/static_root/assets/VDialog-BzaGu1HN.js.br +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.js.gz +0 -0
- codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css +1 -0
- codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css.br +0 -0
- codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css.gz +0 -0
- codex/static_root/assets/VDialog-CpWjrJ0R.css +1 -0
- codex/static_root/assets/VDialog-CpWjrJ0R.css.br +0 -0
- codex/static_root/assets/VDialog-CpWjrJ0R.css.gz +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js +1 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.br +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.gz +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.js +1 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.js.br +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js +1 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.js +1 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.js.gz +0 -0
- codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js +1 -0
- codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.br +0 -0
- codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.gz +0 -0
- codex/static_root/assets/VForm-CyCdgusw.js +1 -0
- codex/static_root/assets/VForm-CyCdgusw.js.br +0 -0
- codex/static_root/assets/VForm-CyCdgusw.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js +1 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.js +1 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.gz +0 -0
- codex/static_root/assets/VSelect-DQPZyfSb.57477277e7dd.css +1 -0
- codex/static_root/assets/VSelect-DQPZyfSb.57477277e7dd.css.br +0 -0
- codex/static_root/assets/VSelect-DQPZyfSb.57477277e7dd.css.gz +0 -0
- codex/static_root/assets/VSelect-DQPZyfSb.css +1 -0
- codex/static_root/assets/VSelect-DQPZyfSb.css.br +0 -0
- codex/static_root/assets/VSelect-DQPZyfSb.css.gz +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js +1 -0
- codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.br +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.gz +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.js +1 -0
- codex/static_root/assets/VSelect-Dv50OIkN.js.br +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js +1 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.js +1 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.js.gz +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js +1 -0
- codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.br +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.gz +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.js +1 -0
- codex/static_root/assets/VTable-BmOfHc7J.js.br +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.js.gz +0 -0
- codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css +1 -0
- codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.br +0 -0
- codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.gz +0 -0
- codex/static_root/assets/VTable-CQyv0wyO.css +1 -0
- codex/static_root/assets/VTable-CQyv0wyO.css.br +0 -0
- codex/static_root/assets/VTable-CQyv0wyO.css.gz +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js +1 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.br +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.gz +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.js +1 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.js.br +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.js.gz +0 -0
- codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css +1 -0
- codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.br +0 -0
- codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.gz +0 -0
- codex/static_root/assets/VWindowItem-ChYLiXSE.css +1 -0
- codex/static_root/assets/VWindowItem-ChYLiXSE.css.br +0 -0
- codex/static_root/assets/VWindowItem-ChYLiXSE.css.gz +0 -0
- codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js +1 -0
- codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.br +0 -0
- codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.gz +0 -0
- codex/static_root/assets/admin-Bv40vYZw.js +1 -0
- codex/static_root/assets/admin-Bv40vYZw.js.br +0 -0
- codex/static_root/assets/admin-Bv40vYZw.js.gz +0 -0
- codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css +1 -0
- codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.br +0 -0
- codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.gz +0 -0
- codex/static_root/assets/admin-DJCVf2PA.css +1 -0
- codex/static_root/assets/admin-DJCVf2PA.css.br +0 -0
- codex/static_root/assets/admin-DJCVf2PA.css.gz +0 -0
- codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js +1 -0
- codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.br +0 -0
- codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.gz +0 -0
- codex/static_root/assets/admin-kjMoKlqD.js +1 -0
- codex/static_root/assets/admin-kjMoKlqD.js.br +0 -0
- codex/static_root/assets/admin-kjMoKlqD.js.gz +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js +1 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.br +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.gz +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.js +1 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.js.br +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.js.gz +0 -0
- codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css +1 -0
- codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.br +0 -0
- codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.gz +0 -0
- codex/static_root/assets/admin-menu-hpyUS8ku.css +1 -0
- codex/static_root/assets/admin-menu-hpyUS8ku.css.br +0 -0
- codex/static_root/assets/admin-menu-hpyUS8ku.css.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.a592809d4008.css +1 -0
- codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.css +1 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js +1 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js +1 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.gz +0 -0
- codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css +1 -0
- codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.br +0 -0
- codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.gz +0 -0
- codex/static_root/assets/browser-Cdi7U5ku.css +1 -0
- codex/static_root/assets/browser-Cdi7U5ku.css.br +0 -0
- codex/static_root/assets/browser-Cdi7U5ku.css.gz +0 -0
- codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js +1 -0
- codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.br +0 -0
- codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.gz +0 -0
- codex/static_root/assets/browser-plYso4v5.js +1 -0
- codex/static_root/assets/browser-plYso4v5.js.br +0 -0
- codex/static_root/assets/browser-plYso4v5.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js +1 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.js +1 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js +1 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.br +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.js +1 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.js.br +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-YfC8mRQA.be37e8f67e0f.css +1 -0
- codex/static_root/assets/confirm-dialog-YfC8mRQA.css +1 -0
- codex/static_root/assets/datetime-column-Bt7J1qEf.css +1 -0
- codex/static_root/assets/datetime-column-Bt7J1qEf.css.br +0 -0
- codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css +1 -0
- codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css.br +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js +1 -0
- codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.br +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.gz +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.js +1 -0
- codex/static_root/assets/datetime-column-DANpNGGe.js.br +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.js.gz +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js +1 -0
- codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.br +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.gz +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.js +1 -0
- codex/static_root/assets/filter-Dhe8cVmt.js.br +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.js.gz +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js +1 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.br +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.gz +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.js +1 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.js.br +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.js.gz +0 -0
- codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css +1 -0
- codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.br +0 -0
- codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.gz +0 -0
- codex/static_root/assets/forwardRefs-B_sUWZn6.css +1 -0
- codex/static_root/assets/forwardRefs-B_sUWZn6.css.br +0 -0
- codex/static_root/assets/forwardRefs-B_sUWZn6.css.gz +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js +1 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.br +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.gz +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.js +1 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.br +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.gz +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js +1 -0
- codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.br +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.gz +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.js +1 -0
- codex/static_root/assets/group-tab-B0ASBB3_.js.br +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.js.gz +0 -0
- codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css +1 -0
- codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.br +0 -0
- codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.gz +0 -0
- codex/static_root/assets/group-tab-CQ_Qw6h8.css +1 -0
- codex/static_root/assets/group-tab-CQ_Qw6h8.css.br +0 -0
- codex/static_root/assets/group-tab-CQ_Qw6h8.css.gz +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js +1 -0
- codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.br +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.gz +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.js +1 -0
- codex/static_root/assets/http-error-BP-mMZsK.js.br +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.js.gz +0 -0
- codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css +1 -0
- codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.br +0 -0
- codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.gz +0 -0
- codex/static_root/assets/http-error-CB3k5P-n.css +1 -0
- codex/static_root/assets/http-error-CB3k5P-n.css.br +0 -0
- codex/static_root/assets/http-error-CB3k5P-n.css.gz +0 -0
- codex/static_root/assets/index-Cu9nQXJD.49795921eada.js +1 -0
- codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.br +0 -0
- codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.gz +0 -0
- codex/static_root/assets/index-Cu9nQXJD.js +1 -0
- codex/static_root/assets/index-Cu9nQXJD.js.br +0 -0
- codex/static_root/assets/index-Cu9nQXJD.js.gz +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js +1 -0
- codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.br +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.gz +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.js +1 -0
- codex/static_root/assets/library-tab-8g2eSuGN.js.br +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.js.gz +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css +1 -0
- codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.br +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.gz +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.css +1 -0
- codex/static_root/assets/library-tab-D9lxhAqv.css.br +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.css.gz +0 -0
- codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css +5 -0
- codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.br +0 -0
- codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.gz +0 -0
- codex/static_root/assets/main-B8_0rUnw.css +5 -0
- codex/static_root/assets/main-B8_0rUnw.css.br +0 -0
- codex/static_root/assets/main-B8_0rUnw.css.gz +0 -0
- codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js +39 -0
- codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.br +0 -0
- codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.gz +0 -0
- codex/static_root/assets/main-BoAlbVoF.js +39 -0
- codex/static_root/assets/main-BoAlbVoF.js.br +0 -0
- codex/static_root/assets/main-BoAlbVoF.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js +1 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.js +1 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css +1 -0
- codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-741OafNw.css +1 -0
- codex/static_root/assets/pagination-toolbar-741OafNw.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-741OafNw.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js +1 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.js +1 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.gz +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js +372 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.br +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.gz +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.js +372 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.js.br +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.js.gz +0 -0
- codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js +2 -0
- codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.br +0 -0
- codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.gz +0 -0
- codex/static_root/assets/reader-CptqnqBZ.js +2 -0
- codex/static_root/assets/reader-CptqnqBZ.js.br +0 -0
- codex/static_root/assets/reader-CptqnqBZ.js.gz +0 -0
- codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css +1 -0
- codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.br +0 -0
- codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.gz +0 -0
- codex/static_root/assets/reader-LwL05rgA.css +1 -0
- codex/static_root/assets/reader-LwL05rgA.css.br +0 -0
- codex/static_root/assets/reader-LwL05rgA.css.gz +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js +1 -0
- codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.br +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.gz +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.js +1 -0
- codex/static_root/assets/relation-chips-CAXZIswb.js.br +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.js.gz +0 -0
- codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css +1 -0
- codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.br +0 -0
- codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.gz +0 -0
- codex/static_root/assets/relation-chips-CcFgPQOM.css +1 -0
- codex/static_root/assets/relation-chips-CcFgPQOM.css.br +0 -0
- codex/static_root/assets/relation-chips-CcFgPQOM.css.gz +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js +2 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.br +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.gz +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.js +2 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.js.br +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css +1 -0
- codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.br +0 -0
- codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.gz +0 -0
- codex/static_root/assets/settings-drawer-CpS_aX4Z.css +1 -0
- codex/static_root/assets/settings-drawer-CpS_aX4Z.css.br +0 -0
- codex/static_root/assets/settings-drawer-CpS_aX4Z.css.gz +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js +1 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.br +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.gz +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.js +1 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.js.br +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.js.gz +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js +1 -0
- codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.br +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.gz +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.js +1 -0
- codex/static_root/assets/stats-tab-BZjOg19A.js.br +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.js.gz +0 -0
- codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css +1 -0
- codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.br +0 -0
- codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.gz +0 -0
- codex/static_root/assets/stats-tab-Dpqh5pF9.css +1 -0
- codex/static_root/assets/stats-tab-Dpqh5pF9.css.br +0 -0
- codex/static_root/assets/stats-tab-Dpqh5pF9.css.gz +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js +1 -0
- codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.br +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.gz +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.js +1 -0
- codex/static_root/assets/task-tab-GP2jPkRE.js.br +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.js.gz +0 -0
- codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css +1 -0
- codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.br +0 -0
- codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.gz +0 -0
- codex/static_root/assets/unauthorized-BBwsmi0O.css +1 -0
- codex/static_root/assets/unauthorized-BBwsmi0O.css.br +0 -0
- codex/static_root/assets/unauthorized-BBwsmi0O.css.gz +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js +1 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.br +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.gz +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.js +1 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.js.br +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.js.gz +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js +1 -0
- codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.br +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.gz +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.js +1 -0
- codex/static_root/assets/user-tab-BQ82qBg3.js.br +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.js.gz +0 -0
- codex/static_root/img/folder.83168d8d3119.svg +1 -0
- codex/static_root/img/folder.83168d8d3119.svg.br +1 -0
- codex/static_root/img/folder.83168d8d3119.svg.gz +0 -0
- codex/static_root/img/folder.svg +1 -1
- codex/static_root/img/folder.svg.br +0 -0
- codex/static_root/img/folder.svg.gz +0 -0
- codex/static_root/img/imprint.3ca7a779b949.svg +1 -0
- codex/static_root/img/imprint.3ca7a779b949.svg.br +0 -0
- codex/static_root/img/imprint.3ca7a779b949.svg.gz +0 -0
- codex/static_root/img/imprint.svg +1 -1
- codex/static_root/img/imprint.svg.br +0 -0
- codex/static_root/img/imprint.svg.gz +0 -0
- codex/static_root/img/logo-maskable.aeef5c2fffc8.svg +1 -0
- codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.br +0 -0
- codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.gz +0 -0
- codex/static_root/img/logo-maskable.svg +1 -1
- codex/static_root/img/logo-maskable.svg.br +0 -0
- codex/static_root/img/logo-maskable.svg.gz +0 -0
- codex/static_root/img/logo.00c902973831.svg +1 -0
- codex/static_root/img/logo.00c902973831.svg.br +0 -0
- codex/static_root/img/logo.00c902973831.svg.gz +0 -0
- codex/static_root/img/logo.svg +1 -1
- codex/static_root/img/logo.svg.br +0 -0
- codex/static_root/img/logo.svg.gz +0 -0
- codex/static_root/img/missing-cover-165.f4bb7740084c.webp +0 -0
- codex/static_root/img/missing-cover-165.webp +0 -0
- codex/static_root/img/missing-cover.7329518c5972.svg +1 -0
- codex/static_root/img/missing-cover.7329518c5972.svg.br +0 -0
- codex/static_root/img/missing-cover.7329518c5972.svg.gz +0 -0
- codex/static_root/img/missing-cover.svg +1 -1
- codex/static_root/img/missing-cover.svg.br +0 -0
- codex/static_root/img/missing-cover.svg.gz +0 -0
- codex/static_root/img/series.b092bbac0c2a.svg +1 -0
- codex/static_root/img/series.b092bbac0c2a.svg.br +0 -0
- codex/static_root/img/series.b092bbac0c2a.svg.gz +0 -0
- codex/static_root/img/series.svg +1 -1
- codex/static_root/img/series.svg.br +0 -0
- codex/static_root/img/series.svg.gz +0 -0
- codex/static_root/img/story-arc.884f7b1d95bd.svg +1 -0
- codex/static_root/img/story-arc.884f7b1d95bd.svg.br +0 -0
- codex/static_root/img/story-arc.884f7b1d95bd.svg.gz +0 -0
- codex/static_root/img/story-arc.svg +1 -1
- codex/static_root/img/story-arc.svg.br +0 -0
- codex/static_root/img/story-arc.svg.gz +0 -0
- codex/static_root/img/volume.516ec0c3018d.svg +1 -0
- codex/static_root/img/volume.516ec0c3018d.svg.br +0 -0
- codex/static_root/img/volume.516ec0c3018d.svg.gz +0 -0
- codex/static_root/img/volume.svg +1 -1
- codex/static_root/img/volume.svg.br +0 -0
- codex/static_root/img/volume.svg.gz +0 -0
- codex/static_root/manifest.0dc91d0dee6d.json +760 -0
- codex/static_root/manifest.0dc91d0dee6d.json.br +0 -0
- codex/static_root/manifest.0dc91d0dee6d.json.gz +0 -0
- codex/static_root/manifest.json +352 -349
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/templates/headers-script-globals.html +1 -0
- codex/urls/api/browser.py +10 -1
- codex/urls/converters.py +2 -5
- codex/urls/root.py +1 -1
- codex/util.py +14 -8
- codex/views/admin/api_key.py +1 -1
- codex/views/admin/flag.py +10 -9
- codex/views/admin/group.py +5 -3
- codex/views/admin/library.py +12 -9
- codex/views/admin/permissions.py +21 -0
- codex/views/admin/stats.py +6 -8
- codex/views/admin/tasks.py +47 -45
- codex/views/admin/user.py +5 -3
- codex/views/auth.py +29 -11
- codex/views/bookmark.py +25 -14
- codex/views/browser/annotate/bookmark.py +0 -3
- codex/views/browser/annotate/card.py +20 -5
- codex/views/browser/annotate/order.py +2 -6
- codex/views/browser/bookmark.py +10 -7
- codex/views/browser/breadcrumbs.py +7 -6
- codex/views/browser/browser.py +16 -16
- codex/views/browser/choices.py +81 -65
- codex/views/browser/cover.py +21 -19
- codex/views/browser/download.py +5 -5
- codex/views/browser/filters/bookmark.py +5 -0
- codex/views/browser/filters/field.py +3 -3
- codex/views/browser/filters/filter.py +3 -5
- codex/views/browser/filters/group.py +5 -5
- codex/views/browser/filters/search/field/column.py +13 -9
- codex/views/browser/filters/search/field/expression.py +1 -3
- codex/views/browser/filters/search/field/filter.py +2 -4
- codex/views/browser/filters/search/field/optimize.py +1 -1
- codex/views/browser/filters/search/field/parse.py +28 -7
- codex/views/browser/filters/search/fts.py +3 -4
- codex/views/browser/filters/search/parse.py +26 -26
- codex/views/browser/group_mtime.py +13 -10
- codex/views/browser/metadata/__init__.py +90 -1
- codex/views/browser/metadata/annotate.py +13 -27
- codex/views/browser/metadata/const.py +83 -0
- codex/views/browser/metadata/copy_intersections.py +14 -9
- codex/views/browser/metadata/query_intersections.py +67 -48
- codex/views/browser/mtime.py +4 -7
- codex/views/browser/order_by.py +4 -1
- codex/views/browser/page_in_bounds.py +5 -6
- codex/views/browser/paginate.py +3 -5
- codex/views/browser/params.py +3 -20
- codex/views/browser/settings.py +18 -4
- codex/views/browser/title.py +9 -5
- codex/views/browser/validate.py +6 -8
- codex/views/const.py +11 -9
- codex/views/download.py +2 -2
- codex/views/error.py +1 -1
- codex/views/exceptions.py +82 -0
- codex/views/frontend.py +8 -18
- codex/views/lazy_import.py +24 -0
- codex/views/mixins.py +34 -12
- codex/views/opds/auth.py +2 -2
- codex/views/opds/authentication_v1.py +2 -1
- codex/views/opds/const.py +1 -1
- codex/views/opds/urls.py +2 -1
- codex/views/opds/util.py +14 -41
- codex/views/opds/v1/entry/entry.py +12 -15
- codex/views/opds/v1/entry/links.py +15 -19
- codex/views/opds/v1/facets.py +8 -5
- codex/views/opds/v1/feed.py +23 -22
- codex/views/opds/v1/links.py +3 -7
- codex/views/opds/v1/opensearch_v1.py +7 -4
- codex/views/opds/v2/feed.py +13 -13
- codex/views/opds/v2/href.py +17 -12
- codex/views/opds/v2/links.py +3 -1
- codex/views/opds/v2/progression.py +31 -15
- codex/views/opds/v2/publications.py +18 -17
- codex/views/opds/v2/top_links.py +7 -2
- codex/views/public.py +12 -15
- codex/views/reader/arcs.py +143 -74
- codex/views/reader/books.py +72 -97
- codex/views/reader/page.py +13 -9
- codex/views/reader/params.py +32 -98
- codex/views/reader/reader.py +18 -73
- codex/views/reader/settings.py +4 -2
- codex/views/session.py +12 -19
- codex/views/settings.py +4 -9
- codex/views/template.py +8 -4
- codex/views/timezone.py +4 -5
- codex/views/util.py +3 -24
- codex/views/version.py +5 -3
- codex/websockets/consumers.py +7 -7
- codex/websockets/listener.py +4 -5
- codex-1.8.0a2.dist-info/METADATA +593 -0
- codex-1.8.0a2.dist-info/RECORD +1098 -0
- codex-1.8.0a2.dist-info/WHEEL +4 -0
- codex-1.8.0a2.dist-info/entry_points.txt +2 -0
- codex/db.py +0 -134
- codex/exceptions.py +0 -88
- codex/librarian/README.md +0 -4
- codex/librarian/delayed_taskd.py +0 -21
- codex/librarian/importer/__init__.py +0 -1
- codex/librarian/importer/aggregate.py +0 -256
- codex/librarian/importer/cache.py +0 -90
- codex/librarian/importer/const.py +0 -244
- codex/librarian/importer/create_comics.py +0 -139
- codex/librarian/importer/create_covers.py +0 -96
- codex/librarian/importer/create_fks.py +0 -346
- codex/librarian/importer/deleted.py +0 -138
- codex/librarian/importer/extract.py +0 -284
- codex/librarian/importer/failed_imports.py +0 -165
- codex/librarian/importer/importer.py +0 -101
- codex/librarian/importer/importerd.py +0 -122
- codex/librarian/importer/init.py +0 -264
- codex/librarian/importer/link_comics.py +0 -270
- codex/librarian/importer/link_covers.py +0 -73
- codex/librarian/importer/moved.py +0 -368
- codex/librarian/importer/query_covers.py +0 -53
- codex/librarian/importer/query_fks.py +0 -653
- codex/librarian/importer/status.py +0 -29
- codex/librarian/importer/tasks.py +0 -55
- codex/librarian/janitor/__init__.py +0 -1
- codex/librarian/janitor/cleanup.py +0 -167
- codex/librarian/janitor/failed_imports.py +0 -27
- codex/librarian/janitor/integrity.py +0 -378
- codex/librarian/janitor/janitor.py +0 -161
- codex/librarian/janitor/latest_version.py +0 -55
- codex/librarian/janitor/scheduled_time.py +0 -12
- codex/librarian/janitor/status.py +0 -22
- codex/librarian/janitor/tasks.py +0 -109
- codex/librarian/janitor/update.py +0 -109
- codex/librarian/janitor/vacuum.py +0 -51
- codex/librarian/search/__init__.py +0 -1
- codex/librarian/search/optimize.py +0 -43
- codex/librarian/search/remove.py +0 -53
- codex/librarian/search/searchd.py +0 -28
- codex/librarian/search/status.py +0 -13
- codex/librarian/search/tasks.py +0 -37
- codex/librarian/search/update.py +0 -305
- codex/librarian/watchdog/README.md +0 -11
- codex/logger/__init__.py +0 -1
- codex/logger/formatter.py +0 -36
- codex/logger/logger.py +0 -46
- codex/logger/loggerd.py +0 -102
- codex/logger/mp_queue.py +0 -5
- codex/logger_base.py +0 -12
- codex/memory.py +0 -56
- codex/permissions.py +0 -19
- codex/registration.py +0 -16
- codex/serializers/README.md +0 -4
- codex/settings/README.md +0 -4
- codex/settings/settings.py +0 -389
- codex/startup.py +0 -182
- codex/static_root/assets/VCheckbox-BP93zyXK.a1358c39a5fc.js +0 -1
- codex/static_root/assets/VCheckbox-BP93zyXK.a1358c39a5fc.js.br +0 -0
- codex/static_root/assets/VCheckbox-BP93zyXK.a1358c39a5fc.js.gz +0 -0
- codex/static_root/assets/VCheckbox-BP93zyXK.js +0 -1
- codex/static_root/assets/VCheckbox-BP93zyXK.js.br +0 -0
- codex/static_root/assets/VCheckbox-BP93zyXK.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CRHYDPms.a17a831d104a.js +0 -1
- codex/static_root/assets/VCheckboxBtn-CRHYDPms.a17a831d104a.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CRHYDPms.a17a831d104a.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CRHYDPms.js +0 -1
- codex/static_root/assets/VCheckboxBtn-CRHYDPms.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CRHYDPms.js.gz +0 -0
- codex/static_root/assets/VCombobox-BMwdQ72S.106aafc35928.js +0 -1
- codex/static_root/assets/VCombobox-BMwdQ72S.106aafc35928.js.br +0 -0
- codex/static_root/assets/VCombobox-BMwdQ72S.106aafc35928.js.gz +0 -0
- codex/static_root/assets/VCombobox-BMwdQ72S.js +0 -1
- codex/static_root/assets/VCombobox-BMwdQ72S.js.br +0 -0
- codex/static_root/assets/VCombobox-BMwdQ72S.js.gz +0 -0
- codex/static_root/assets/VDialog-BScRe1ug.c1e3368e7223.js +0 -1
- codex/static_root/assets/VDialog-BScRe1ug.c1e3368e7223.js.br +0 -0
- codex/static_root/assets/VDialog-BScRe1ug.c1e3368e7223.js.gz +0 -0
- codex/static_root/assets/VDialog-BScRe1ug.js +0 -1
- codex/static_root/assets/VDialog-BScRe1ug.js.br +0 -0
- codex/static_root/assets/VDialog-BScRe1ug.js.gz +0 -0
- codex/static_root/assets/VDialog-y9QOVA5M.627a99a930c7.css +0 -1
- codex/static_root/assets/VDialog-y9QOVA5M.627a99a930c7.css.br +0 -0
- codex/static_root/assets/VDialog-y9QOVA5M.627a99a930c7.css.gz +0 -0
- codex/static_root/assets/VDialog-y9QOVA5M.css +0 -1
- codex/static_root/assets/VDialog-y9QOVA5M.css.br +0 -0
- codex/static_root/assets/VDialog-y9QOVA5M.css.gz +0 -0
- codex/static_root/assets/VDivider-tFagM0PC.3cc0ce822729.js +0 -1
- codex/static_root/assets/VDivider-tFagM0PC.3cc0ce822729.js.br +0 -0
- codex/static_root/assets/VDivider-tFagM0PC.3cc0ce822729.js.gz +0 -0
- codex/static_root/assets/VDivider-tFagM0PC.js +0 -1
- codex/static_root/assets/VDivider-tFagM0PC.js.br +0 -0
- codex/static_root/assets/VDivider-tFagM0PC.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DGHiJ89C.b60a171f4cde.js +0 -1
- codex/static_root/assets/VExpansionPanels-DGHiJ89C.b60a171f4cde.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DGHiJ89C.b60a171f4cde.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DGHiJ89C.js +0 -1
- codex/static_root/assets/VExpansionPanels-DGHiJ89C.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DGHiJ89C.js.gz +0 -0
- codex/static_root/assets/VForm-B__yH-Y4.63f4a1e9770b.js +0 -1
- codex/static_root/assets/VForm-B__yH-Y4.63f4a1e9770b.js.br +0 -0
- codex/static_root/assets/VForm-B__yH-Y4.63f4a1e9770b.js.gz +0 -0
- codex/static_root/assets/VForm-B__yH-Y4.js +0 -1
- codex/static_root/assets/VForm-B__yH-Y4.js.br +0 -0
- codex/static_root/assets/VForm-B__yH-Y4.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-CPOGOEPv.20e361436bc6.js +0 -1
- codex/static_root/assets/VRadioGroup-CPOGOEPv.20e361436bc6.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CPOGOEPv.20e361436bc6.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-CPOGOEPv.js +0 -1
- codex/static_root/assets/VRadioGroup-CPOGOEPv.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CPOGOEPv.js.gz +0 -0
- codex/static_root/assets/VSelect-B_F15uRm.a7297ec26f7a.js +0 -1
- codex/static_root/assets/VSelect-B_F15uRm.a7297ec26f7a.js.br +0 -0
- codex/static_root/assets/VSelect-B_F15uRm.a7297ec26f7a.js.gz +0 -0
- codex/static_root/assets/VSelect-B_F15uRm.js +0 -1
- codex/static_root/assets/VSelect-B_F15uRm.js.br +0 -0
- codex/static_root/assets/VSelect-B_F15uRm.js.gz +0 -0
- codex/static_root/assets/VSelect-CKXqRkBF.a8be1e193eba.css +0 -1
- codex/static_root/assets/VSelect-CKXqRkBF.a8be1e193eba.css.br +0 -0
- codex/static_root/assets/VSelect-CKXqRkBF.a8be1e193eba.css.gz +0 -0
- codex/static_root/assets/VSelect-CKXqRkBF.css +0 -1
- codex/static_root/assets/VSelect-CKXqRkBF.css.br +0 -0
- codex/static_root/assets/VSelect-CKXqRkBF.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-CjjwyQ-Y.db7787ff7c1d.js +0 -1
- codex/static_root/assets/VSelectionControl-CjjwyQ-Y.db7787ff7c1d.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CjjwyQ-Y.db7787ff7c1d.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CjjwyQ-Y.js +0 -1
- codex/static_root/assets/VSelectionControl-CjjwyQ-Y.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CjjwyQ-Y.js.gz +0 -0
- codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css +0 -1
- codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.br +0 -0
- codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.gz +0 -0
- codex/static_root/assets/VTable-CHRVGI94.css +0 -1
- codex/static_root/assets/VTable-CHRVGI94.css.br +0 -0
- codex/static_root/assets/VTable-CHRVGI94.css.gz +0 -0
- codex/static_root/assets/VTable-DuRw3_Nt.d9e0088b79d2.js +0 -1
- codex/static_root/assets/VTable-DuRw3_Nt.d9e0088b79d2.js.br +0 -0
- codex/static_root/assets/VTable-DuRw3_Nt.d9e0088b79d2.js.gz +0 -0
- codex/static_root/assets/VTable-DuRw3_Nt.js +0 -1
- codex/static_root/assets/VTable-DuRw3_Nt.js.br +0 -0
- codex/static_root/assets/VTable-DuRw3_Nt.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CBh8U6qD.49437fb41631.js +0 -1
- codex/static_root/assets/VWindowItem-CBh8U6qD.49437fb41631.js.br +0 -0
- codex/static_root/assets/VWindowItem-CBh8U6qD.49437fb41631.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CBh8U6qD.js +0 -1
- codex/static_root/assets/VWindowItem-CBh8U6qD.js.br +0 -0
- codex/static_root/assets/VWindowItem-CBh8U6qD.js.gz +0 -0
- codex/static_root/assets/VWindowItem-CWBhiE_Y.css +0 -1
- codex/static_root/assets/VWindowItem-CWBhiE_Y.css.br +0 -0
- codex/static_root/assets/VWindowItem-CWBhiE_Y.css.gz +0 -0
- codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css +0 -1
- codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br +0 -0
- codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz +0 -0
- codex/static_root/assets/admin-BiuZANLl.249b6c087031.js +0 -1
- codex/static_root/assets/admin-BiuZANLl.249b6c087031.js.br +0 -0
- codex/static_root/assets/admin-BiuZANLl.249b6c087031.js.gz +0 -0
- codex/static_root/assets/admin-BiuZANLl.js +0 -1
- codex/static_root/assets/admin-BiuZANLl.js.br +0 -0
- codex/static_root/assets/admin-BiuZANLl.js.gz +0 -0
- codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css +0 -1
- codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.br +0 -0
- codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.gz +0 -0
- codex/static_root/assets/admin-klMr_GZK.css +0 -1
- codex/static_root/assets/admin-klMr_GZK.css.br +0 -0
- codex/static_root/assets/admin-klMr_GZK.css.gz +0 -0
- codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css +0 -1
- codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.br +0 -0
- codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.gz +0 -0
- codex/static_root/assets/admin-menu-CKlcsy9S.css +0 -1
- codex/static_root/assets/admin-menu-CKlcsy9S.css.br +0 -0
- codex/static_root/assets/admin-menu-CKlcsy9S.css.gz +0 -0
- codex/static_root/assets/admin-menu-DqBUjKk4.96d3ee51d1ee.js +0 -1
- codex/static_root/assets/admin-menu-DqBUjKk4.96d3ee51d1ee.js.br +0 -0
- codex/static_root/assets/admin-menu-DqBUjKk4.96d3ee51d1ee.js.gz +0 -0
- codex/static_root/assets/admin-menu-DqBUjKk4.js +0 -1
- codex/static_root/assets/admin-menu-DqBUjKk4.js.br +0 -0
- codex/static_root/assets/admin-menu-DqBUjKk4.js.gz +0 -0
- codex/static_root/assets/admin-rFfBszpt.fe7fc34dcff9.js +0 -1
- codex/static_root/assets/admin-rFfBszpt.fe7fc34dcff9.js.br +0 -0
- codex/static_root/assets/admin-rFfBszpt.fe7fc34dcff9.js.gz +0 -0
- codex/static_root/assets/admin-rFfBszpt.js +0 -1
- codex/static_root/assets/admin-rFfBszpt.js.br +0 -0
- codex/static_root/assets/admin-rFfBszpt.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-OU_loI8p.87ac446b1a6a.js +0 -1
- codex/static_root/assets/admin-settings-button-progress-OU_loI8p.87ac446b1a6a.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-OU_loI8p.87ac446b1a6a.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-OU_loI8p.js +0 -1
- codex/static_root/assets/admin-settings-button-progress-OU_loI8p.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-OU_loI8p.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.435dc945daf1.css +0 -1
- codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.css +0 -1
- codex/static_root/assets/browser-D0QppR66.501322534a7c.js +0 -1
- codex/static_root/assets/browser-D0QppR66.501322534a7c.js.br +0 -0
- codex/static_root/assets/browser-D0QppR66.501322534a7c.js.gz +0 -0
- codex/static_root/assets/browser-D0QppR66.js +0 -1
- codex/static_root/assets/browser-D0QppR66.js.br +0 -0
- codex/static_root/assets/browser-D0QppR66.js.gz +0 -0
- codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css +0 -1
- codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.br +0 -0
- codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.gz +0 -0
- codex/static_root/assets/browser-sNm790x9.css +0 -1
- codex/static_root/assets/browser-sNm790x9.css.br +0 -0
- codex/static_root/assets/browser-sNm790x9.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-DQ_0TaFN.5faa73705235.js +0 -1
- codex/static_root/assets/change-password-dialog-DQ_0TaFN.5faa73705235.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DQ_0TaFN.5faa73705235.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DQ_0TaFN.js +0 -1
- codex/static_root/assets/change-password-dialog-DQ_0TaFN.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DQ_0TaFN.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css +0 -1
- codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css.br +0 -0
- codex/static_root/assets/confirm-dialog-BI5kQLy_.css +0 -1
- codex/static_root/assets/confirm-dialog-BI5kQLy_.css.br +0 -0
- codex/static_root/assets/confirm-dialog-Bkr6kSge.f41952e0b099.js +0 -1
- codex/static_root/assets/confirm-dialog-Bkr6kSge.f41952e0b099.js.br +0 -0
- codex/static_root/assets/confirm-dialog-Bkr6kSge.f41952e0b099.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-Bkr6kSge.js +0 -1
- codex/static_root/assets/confirm-dialog-Bkr6kSge.js.br +0 -0
- codex/static_root/assets/confirm-dialog-Bkr6kSge.js.gz +0 -0
- codex/static_root/assets/datetime-column-BavtvLnf.1f3bf499e063.css +0 -1
- codex/static_root/assets/datetime-column-BavtvLnf.css +0 -1
- codex/static_root/assets/datetime-column-DN4pF5Fz.eef663675e36.js +0 -1
- codex/static_root/assets/datetime-column-DN4pF5Fz.eef663675e36.js.br +0 -2
- codex/static_root/assets/datetime-column-DN4pF5Fz.eef663675e36.js.gz +0 -0
- codex/static_root/assets/datetime-column-DN4pF5Fz.js +0 -1
- codex/static_root/assets/datetime-column-DN4pF5Fz.js.br +0 -2
- codex/static_root/assets/datetime-column-DN4pF5Fz.js.gz +0 -0
- codex/static_root/assets/filter-C84dddvE.1f40ef69fc98.js +0 -1
- codex/static_root/assets/filter-C84dddvE.1f40ef69fc98.js.br +0 -0
- codex/static_root/assets/filter-C84dddvE.1f40ef69fc98.js.gz +0 -0
- codex/static_root/assets/filter-C84dddvE.js +0 -1
- codex/static_root/assets/filter-C84dddvE.js.br +0 -0
- codex/static_root/assets/filter-C84dddvE.js.gz +0 -0
- codex/static_root/assets/flag-tab-kXJbxWWt.afd96e3b065a.js +0 -1
- codex/static_root/assets/flag-tab-kXJbxWWt.afd96e3b065a.js.br +0 -0
- codex/static_root/assets/flag-tab-kXJbxWWt.afd96e3b065a.js.gz +0 -0
- codex/static_root/assets/flag-tab-kXJbxWWt.js +0 -1
- codex/static_root/assets/flag-tab-kXJbxWWt.js.br +0 -0
- codex/static_root/assets/flag-tab-kXJbxWWt.js.gz +0 -0
- codex/static_root/assets/forwardRefs-Dbjzugu8.a95409be3194.css +0 -1
- codex/static_root/assets/forwardRefs-Dbjzugu8.a95409be3194.css.br +0 -0
- codex/static_root/assets/forwardRefs-Dbjzugu8.a95409be3194.css.gz +0 -0
- codex/static_root/assets/forwardRefs-Dbjzugu8.css +0 -1
- codex/static_root/assets/forwardRefs-Dbjzugu8.css.br +0 -0
- codex/static_root/assets/forwardRefs-Dbjzugu8.css.gz +0 -0
- codex/static_root/assets/forwardRefs-DkWUbz_i.6267360fb97d.js +0 -1
- codex/static_root/assets/forwardRefs-DkWUbz_i.6267360fb97d.js.br +0 -0
- codex/static_root/assets/forwardRefs-DkWUbz_i.6267360fb97d.js.gz +0 -0
- codex/static_root/assets/forwardRefs-DkWUbz_i.js +0 -1
- codex/static_root/assets/forwardRefs-DkWUbz_i.js.br +0 -0
- codex/static_root/assets/forwardRefs-DkWUbz_i.js.gz +0 -0
- codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css +0 -1
- codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.br +0 -0
- codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.gz +0 -0
- codex/static_root/assets/group-tab-Bi681uR0.css +0 -1
- codex/static_root/assets/group-tab-Bi681uR0.css.br +0 -0
- codex/static_root/assets/group-tab-Bi681uR0.css.gz +0 -0
- codex/static_root/assets/group-tab-jH91_dZ-.4e96931a3f26.js +0 -1
- codex/static_root/assets/group-tab-jH91_dZ-.4e96931a3f26.js.br +0 -0
- codex/static_root/assets/group-tab-jH91_dZ-.4e96931a3f26.js.gz +0 -0
- codex/static_root/assets/group-tab-jH91_dZ-.js +0 -1
- codex/static_root/assets/group-tab-jH91_dZ-.js.br +0 -0
- codex/static_root/assets/group-tab-jH91_dZ-.js.gz +0 -0
- codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css +0 -1
- codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.br +0 -0
- codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.gz +0 -0
- codex/static_root/assets/http-error-CODU7jcH.css +0 -1
- codex/static_root/assets/http-error-CODU7jcH.css.br +0 -0
- codex/static_root/assets/http-error-CODU7jcH.css.gz +0 -0
- codex/static_root/assets/http-error-CrojtCix.9d0501bde853.js +0 -1
- codex/static_root/assets/http-error-CrojtCix.9d0501bde853.js.br +0 -0
- codex/static_root/assets/http-error-CrojtCix.9d0501bde853.js.gz +0 -0
- codex/static_root/assets/http-error-CrojtCix.js +0 -1
- codex/static_root/assets/http-error-CrojtCix.js.br +0 -0
- codex/static_root/assets/http-error-CrojtCix.js.gz +0 -0
- codex/static_root/assets/index-DHunaD9D.c820322b9e49.js +0 -1
- codex/static_root/assets/index-DHunaD9D.c820322b9e49.js.br +0 -0
- codex/static_root/assets/index-DHunaD9D.c820322b9e49.js.gz +0 -0
- codex/static_root/assets/index-DHunaD9D.js +0 -1
- codex/static_root/assets/index-DHunaD9D.js.br +0 -0
- codex/static_root/assets/index-DHunaD9D.js.gz +0 -0
- codex/static_root/assets/library-tab-BzOyajRi.6c8c04906eec.js +0 -1
- codex/static_root/assets/library-tab-BzOyajRi.6c8c04906eec.js.br +0 -0
- codex/static_root/assets/library-tab-BzOyajRi.6c8c04906eec.js.gz +0 -0
- codex/static_root/assets/library-tab-BzOyajRi.js +0 -1
- codex/static_root/assets/library-tab-BzOyajRi.js.br +0 -0
- codex/static_root/assets/library-tab-BzOyajRi.js.gz +0 -0
- codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css +0 -1
- codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.br +0 -0
- codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.gz +0 -0
- codex/static_root/assets/library-tab-DLpvMqPW.css +0 -1
- codex/static_root/assets/library-tab-DLpvMqPW.css.br +0 -0
- codex/static_root/assets/library-tab-DLpvMqPW.css.gz +0 -0
- codex/static_root/assets/main-Dl2Lrwga.e767cd79bb5e.js +0 -39
- codex/static_root/assets/main-Dl2Lrwga.e767cd79bb5e.js.br +0 -0
- codex/static_root/assets/main-Dl2Lrwga.e767cd79bb5e.js.gz +0 -0
- codex/static_root/assets/main-Dl2Lrwga.js +0 -39
- codex/static_root/assets/main-Dl2Lrwga.js.br +0 -0
- codex/static_root/assets/main-Dl2Lrwga.js.gz +0 -0
- codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css +0 -5
- codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.br +0 -0
- codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.gz +0 -0
- codex/static_root/assets/main-Of3aYkZ7.css +0 -5
- codex/static_root/assets/main-Of3aYkZ7.css.br +0 -0
- codex/static_root/assets/main-Of3aYkZ7.css.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DKdyHoRL.a504cc00db7c.js +0 -1
- codex/static_root/assets/pager-full-pdf-DKdyHoRL.a504cc00db7c.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DKdyHoRL.a504cc00db7c.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DKdyHoRL.js +0 -1
- codex/static_root/assets/pager-full-pdf-DKdyHoRL.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DKdyHoRL.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-T0N6Ubp7.1f07380772ae.js +0 -1
- codex/static_root/assets/pagination-toolbar-T0N6Ubp7.1f07380772ae.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-T0N6Ubp7.1f07380772ae.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-T0N6Ubp7.js +0 -1
- codex/static_root/assets/pagination-toolbar-T0N6Ubp7.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-T0N6Ubp7.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css +0 -1
- codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-aHRrdz48.css +0 -1
- codex/static_root/assets/pagination-toolbar-aHRrdz48.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-aHRrdz48.css.gz +0 -0
- codex/static_root/assets/pdf-doc-CBiUfHpD.9e3e989242e7.js +0 -372
- codex/static_root/assets/pdf-doc-CBiUfHpD.9e3e989242e7.js.br +0 -0
- codex/static_root/assets/pdf-doc-CBiUfHpD.9e3e989242e7.js.gz +0 -0
- codex/static_root/assets/pdf-doc-CBiUfHpD.js +0 -372
- codex/static_root/assets/pdf-doc-CBiUfHpD.js.br +0 -0
- codex/static_root/assets/pdf-doc-CBiUfHpD.js.gz +0 -0
- codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css +0 -1
- codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.br +0 -0
- codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.gz +0 -0
- codex/static_root/assets/reader-BwgJtbgj.css +0 -1
- codex/static_root/assets/reader-BwgJtbgj.css.br +0 -0
- codex/static_root/assets/reader-BwgJtbgj.css.gz +0 -0
- codex/static_root/assets/reader-D3uSXJi4.6bf741d0ed65.js +0 -2
- codex/static_root/assets/reader-D3uSXJi4.6bf741d0ed65.js.br +0 -0
- codex/static_root/assets/reader-D3uSXJi4.6bf741d0ed65.js.gz +0 -0
- codex/static_root/assets/reader-D3uSXJi4.js +0 -2
- codex/static_root/assets/reader-D3uSXJi4.js.br +0 -0
- codex/static_root/assets/reader-D3uSXJi4.js.gz +0 -0
- codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css +0 -1
- codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.br +0 -0
- codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.gz +0 -0
- codex/static_root/assets/relation-chips-BuShhy1e.css +0 -1
- codex/static_root/assets/relation-chips-BuShhy1e.css.br +0 -0
- codex/static_root/assets/relation-chips-BuShhy1e.css.gz +0 -0
- codex/static_root/assets/relation-chips-DWjWPY3v.d76db684e8a8.js +0 -1
- codex/static_root/assets/relation-chips-DWjWPY3v.d76db684e8a8.js.br +0 -0
- codex/static_root/assets/relation-chips-DWjWPY3v.d76db684e8a8.js.gz +0 -0
- codex/static_root/assets/relation-chips-DWjWPY3v.js +0 -1
- codex/static_root/assets/relation-chips-DWjWPY3v.js.br +0 -0
- codex/static_root/assets/relation-chips-DWjWPY3v.js.gz +0 -0
- codex/static_root/assets/settings-drawer-Bu83HJ70.a7672fb29169.js +0 -2
- codex/static_root/assets/settings-drawer-Bu83HJ70.a7672fb29169.js.br +0 -0
- codex/static_root/assets/settings-drawer-Bu83HJ70.a7672fb29169.js.gz +0 -0
- codex/static_root/assets/settings-drawer-Bu83HJ70.js +0 -2
- codex/static_root/assets/settings-drawer-Bu83HJ70.js.br +0 -0
- codex/static_root/assets/settings-drawer-Bu83HJ70.js.gz +0 -0
- codex/static_root/assets/settings-drawer-WyG6HLH-.css +0 -1
- codex/static_root/assets/settings-drawer-WyG6HLH-.css.br +0 -0
- codex/static_root/assets/settings-drawer-WyG6HLH-.css.gz +0 -0
- codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css +0 -1
- codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.br +0 -0
- codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.gz +0 -0
- codex/static_root/assets/ssrBoot-CYaxTeZo.308983ed6c53.js +0 -1
- codex/static_root/assets/ssrBoot-CYaxTeZo.308983ed6c53.js.br +0 -0
- codex/static_root/assets/ssrBoot-CYaxTeZo.308983ed6c53.js.gz +0 -0
- codex/static_root/assets/ssrBoot-CYaxTeZo.js +0 -1
- codex/static_root/assets/ssrBoot-CYaxTeZo.js.br +0 -0
- codex/static_root/assets/ssrBoot-CYaxTeZo.js.gz +0 -0
- codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css +0 -1
- codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.br +0 -0
- codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.gz +0 -0
- codex/static_root/assets/stats-tab-CGY8r-es.css +0 -1
- codex/static_root/assets/stats-tab-CGY8r-es.css.br +0 -0
- codex/static_root/assets/stats-tab-CGY8r-es.css.gz +0 -0
- codex/static_root/assets/stats-tab-aWxmJFqf.ef7a1a878842.js +0 -1
- codex/static_root/assets/stats-tab-aWxmJFqf.ef7a1a878842.js.br +0 -0
- codex/static_root/assets/stats-tab-aWxmJFqf.ef7a1a878842.js.gz +0 -0
- codex/static_root/assets/stats-tab-aWxmJFqf.js +0 -1
- codex/static_root/assets/stats-tab-aWxmJFqf.js.br +0 -0
- codex/static_root/assets/stats-tab-aWxmJFqf.js.gz +0 -0
- codex/static_root/assets/task-tab-fAvDZsSF.607dda8657e0.js +0 -1
- codex/static_root/assets/task-tab-fAvDZsSF.607dda8657e0.js.br +0 -0
- codex/static_root/assets/task-tab-fAvDZsSF.607dda8657e0.js.gz +0 -0
- codex/static_root/assets/task-tab-fAvDZsSF.js +0 -1
- codex/static_root/assets/task-tab-fAvDZsSF.js.br +0 -0
- codex/static_root/assets/task-tab-fAvDZsSF.js.gz +0 -0
- codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css +0 -1
- codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.br +0 -0
- codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.gz +0 -0
- codex/static_root/assets/unauthorized-DE63n2Pi.css +0 -1
- codex/static_root/assets/unauthorized-DE63n2Pi.css.br +0 -0
- codex/static_root/assets/unauthorized-DE63n2Pi.css.gz +0 -0
- codex/static_root/assets/unauthorized-T8UCTUHd.16d825eec49d.js +0 -1
- codex/static_root/assets/unauthorized-T8UCTUHd.16d825eec49d.js.br +0 -0
- codex/static_root/assets/unauthorized-T8UCTUHd.16d825eec49d.js.gz +0 -0
- codex/static_root/assets/unauthorized-T8UCTUHd.js +0 -1
- codex/static_root/assets/unauthorized-T8UCTUHd.js.br +0 -0
- codex/static_root/assets/unauthorized-T8UCTUHd.js.gz +0 -0
- codex/static_root/assets/user-tab-CI1MB3ic.ed8693e40a0b.js +0 -1
- codex/static_root/assets/user-tab-CI1MB3ic.ed8693e40a0b.js.br +0 -0
- codex/static_root/assets/user-tab-CI1MB3ic.ed8693e40a0b.js.gz +0 -0
- codex/static_root/assets/user-tab-CI1MB3ic.js +0 -1
- codex/static_root/assets/user-tab-CI1MB3ic.js.br +0 -0
- codex/static_root/assets/user-tab-CI1MB3ic.js.gz +0 -0
- codex/static_root/img/folder.f28936a3701d.svg +0 -1
- codex/static_root/img/folder.f28936a3701d.svg.br +0 -0
- codex/static_root/img/folder.f28936a3701d.svg.gz +0 -0
- codex/static_root/img/imprint.7c2adebb76d6.svg +0 -1
- codex/static_root/img/imprint.7c2adebb76d6.svg.br +0 -0
- codex/static_root/img/imprint.7c2adebb76d6.svg.gz +0 -0
- codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg +0 -1
- codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.br +0 -0
- codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.gz +0 -0
- codex/static_root/img/logo.0f5344a028ca.svg +0 -1
- codex/static_root/img/logo.0f5344a028ca.svg.br +0 -0
- codex/static_root/img/logo.0f5344a028ca.svg.gz +0 -0
- codex/static_root/img/missing-cover-165.0743171f2148.webp +0 -0
- codex/static_root/img/missing-cover.ddb038cc2c56.svg +0 -1
- codex/static_root/img/missing-cover.ddb038cc2c56.svg.br +0 -0
- codex/static_root/img/missing-cover.ddb038cc2c56.svg.gz +0 -0
- codex/static_root/img/series.ec8a889b8f95.svg +0 -1
- codex/static_root/img/series.ec8a889b8f95.svg.br +0 -0
- codex/static_root/img/series.ec8a889b8f95.svg.gz +0 -0
- codex/static_root/img/story-arc.ca10014355ef.svg +0 -1
- codex/static_root/img/story-arc.ca10014355ef.svg.br +0 -1
- codex/static_root/img/story-arc.ca10014355ef.svg.gz +0 -0
- codex/static_root/img/volume.814e4c79461a.svg +0 -1
- codex/static_root/img/volume.814e4c79461a.svg.br +0 -0
- codex/static_root/img/volume.814e4c79461a.svg.gz +0 -0
- codex/static_root/manifest.b23c14b76074.json +0 -757
- codex/static_root/manifest.b23c14b76074.json.br +0 -0
- codex/static_root/manifest.b23c14b76074.json.gz +0 -0
- codex/status.py +0 -35
- codex/status_controller.py +0 -153
- codex/templates/README.md +0 -3
- codex/threads.py +0 -130
- codex/views/README.md +0 -4
- codex/views/browser/filters/search/aliases.py +0 -81
- codex/views/browser/metadata/metadata.py +0 -83
- codex/websockets/README.md +0 -4
- codex/worker_base.py +0 -14
- codex-1.7.14.dist-info/METADATA +0 -599
- codex-1.7.14.dist-info/RECORD +0 -1052
- codex-1.7.14.dist-info/WHEEL +0 -4
- codex-1.7.14.dist-info/entry_points.txt +0 -3
- {codex-1.7.14.dist-info → codex-1.8.0a2.dist-info/licenses}/LICENSE +0 -0
codex/models/__init__.py
CHANGED
|
@@ -4,6 +4,7 @@ from codex.models.admin import *
|
|
|
4
4
|
from codex.models.bookmark import *
|
|
5
5
|
from codex.models.comic import *
|
|
6
6
|
from codex.models.groups import *
|
|
7
|
+
from codex.models.identifier import *
|
|
7
8
|
from codex.models.library import *
|
|
8
9
|
from codex.models.named import *
|
|
9
10
|
from codex.models.paths import *
|
codex/models/admin.py
CHANGED
|
@@ -15,8 +15,10 @@ from django.db.models import (
|
|
|
15
15
|
TextChoices,
|
|
16
16
|
)
|
|
17
17
|
from django.utils.translation import gettext_lazy as _
|
|
18
|
+
from typing_extensions import override
|
|
18
19
|
|
|
19
|
-
from codex.choices.admin import
|
|
20
|
+
from codex.choices.admin import AdminFlagChoices
|
|
21
|
+
from codex.choices.statii import ADMIN_STATUS_TITLES
|
|
20
22
|
from codex.models.base import MAX_FIELD_LEN, MAX_NAME_LEN, BaseModel, max_choices_len
|
|
21
23
|
|
|
22
24
|
__all__ = ("AdminFlag", "LibrarianStatus", "Timestamp", "UserActive")
|
|
@@ -25,23 +27,12 @@ __all__ = ("AdminFlag", "LibrarianStatus", "Timestamp", "UserActive")
|
|
|
25
27
|
class AdminFlag(BaseModel):
|
|
26
28
|
"""Flags set by administrators."""
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
"""Choices for Admin Flags."""
|
|
30
|
-
|
|
31
|
-
FOLDER_VIEW = "FV"
|
|
32
|
-
REGISTRATION = "RG"
|
|
33
|
-
NON_USERS = "NU"
|
|
34
|
-
AUTO_UPDATE = "AU"
|
|
35
|
-
IMPORT_METADATA = "IM"
|
|
36
|
-
SEND_TELEMETRY = "ST"
|
|
37
|
-
BANNER_TEXT = "BT"
|
|
38
|
-
|
|
39
|
-
FALSE_DEFAULTS = frozenset({FlagChoices.AUTO_UPDATE})
|
|
30
|
+
FALSE_DEFAULTS = frozenset({AdminFlagChoices.AUTO_UPDATE})
|
|
40
31
|
|
|
41
32
|
key = CharField(
|
|
42
33
|
db_index=True,
|
|
43
|
-
max_length=max_choices_len(
|
|
44
|
-
choices=
|
|
34
|
+
max_length=max_choices_len(AdminFlagChoices),
|
|
35
|
+
choices=AdminFlagChoices.choices,
|
|
45
36
|
)
|
|
46
37
|
on = BooleanField(default=True)
|
|
47
38
|
value = CharField(max_length=MAX_NAME_LEN, default="", blank=True)
|
|
@@ -55,7 +46,7 @@ class AdminFlag(BaseModel):
|
|
|
55
46
|
class LibrarianStatus(BaseModel):
|
|
56
47
|
"""Active Library Tasks."""
|
|
57
48
|
|
|
58
|
-
CHOICES = TextChoices("LibrarianStatusTypes", ADMIN_STATUS_TITLES.inverse)
|
|
49
|
+
CHOICES = TextChoices("LibrarianStatusTypes", ADMIN_STATUS_TITLES.inverse.items())
|
|
59
50
|
|
|
60
51
|
status_type = CharField(
|
|
61
52
|
db_index=True,
|
|
@@ -78,7 +69,7 @@ class LibrarianStatus(BaseModel):
|
|
|
78
69
|
class Timestamp(BaseModel):
|
|
79
70
|
"""Timestamped Named Strings."""
|
|
80
71
|
|
|
81
|
-
class
|
|
72
|
+
class Choices(TextChoices):
|
|
82
73
|
"""Choices for Timestamps."""
|
|
83
74
|
|
|
84
75
|
API_KEY = "AP", _("API Key")
|
|
@@ -88,8 +79,8 @@ class Timestamp(BaseModel):
|
|
|
88
79
|
|
|
89
80
|
key = CharField(
|
|
90
81
|
db_index=True,
|
|
91
|
-
max_length=max_choices_len(
|
|
92
|
-
choices=
|
|
82
|
+
max_length=max_choices_len(Choices),
|
|
83
|
+
choices=Choices.choices,
|
|
93
84
|
)
|
|
94
85
|
version = CharField(max_length=MAX_FIELD_LEN, default="")
|
|
95
86
|
|
|
@@ -110,9 +101,10 @@ class Timestamp(BaseModel):
|
|
|
110
101
|
|
|
111
102
|
unique_together = ("key",)
|
|
112
103
|
|
|
113
|
-
|
|
104
|
+
@override
|
|
105
|
+
def __repr__(self):
|
|
114
106
|
"""Print name for choice."""
|
|
115
|
-
return self.
|
|
107
|
+
return self.Choices(self.key).name
|
|
116
108
|
|
|
117
109
|
|
|
118
110
|
class UserActive(BaseModel):
|
codex/models/base.py
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from django.db.models import DateTimeField, Model
|
|
4
4
|
from django.db.models.base import ModelBase
|
|
5
|
+
from typing_extensions import override
|
|
5
6
|
|
|
7
|
+
from codex.models.fields import CleaningCharField
|
|
6
8
|
from codex.models.query import GroupByManager
|
|
7
9
|
|
|
8
|
-
__all__ = ("BaseModel",)
|
|
10
|
+
__all__ = ("BaseModel", "NamedModel")
|
|
9
11
|
|
|
10
12
|
MAX_PATH_LEN = 4095
|
|
11
13
|
MAX_NAME_LEN = 128
|
|
@@ -27,7 +29,7 @@ class BaseModel(Model):
|
|
|
27
29
|
updated_at = DateTimeField(auto_now=True)
|
|
28
30
|
objects = GroupByManager()
|
|
29
31
|
|
|
30
|
-
class Meta(ModelBase):
|
|
32
|
+
class Meta(ModelBase):
|
|
31
33
|
"""Without this a real table is created and joined to."""
|
|
32
34
|
|
|
33
35
|
# Model.Meta is not inheritable.
|
|
@@ -37,3 +39,20 @@ class BaseModel(Model):
|
|
|
37
39
|
|
|
38
40
|
def presave(self):
|
|
39
41
|
"""Create values before save."""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class NamedModel(BaseModel):
|
|
45
|
+
"""A for simple named tables."""
|
|
46
|
+
|
|
47
|
+
name = CleaningCharField(db_index=True, max_length=MAX_NAME_LEN)
|
|
48
|
+
|
|
49
|
+
class Meta(BaseModel.Meta):
|
|
50
|
+
"""Defaults to uniquely named, must be overridden."""
|
|
51
|
+
|
|
52
|
+
abstract = True
|
|
53
|
+
unique_together: tuple[str, ...] = ("name",)
|
|
54
|
+
|
|
55
|
+
@override
|
|
56
|
+
def __repr__(self):
|
|
57
|
+
"""Return the name."""
|
|
58
|
+
return self.name
|
codex/models/comic.py
CHANGED
|
@@ -6,22 +6,21 @@ import re
|
|
|
6
6
|
from datetime import MAXYEAR, MINYEAR, date
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from comicbox.
|
|
9
|
+
from comicbox.enums.comicbox import FileTypeEnum, ReadingDirectionEnum
|
|
10
10
|
from django.db.models import (
|
|
11
11
|
CASCADE,
|
|
12
12
|
BooleanField,
|
|
13
13
|
CharField,
|
|
14
14
|
DateField,
|
|
15
15
|
DateTimeField,
|
|
16
|
-
DecimalField,
|
|
17
16
|
ForeignKey,
|
|
18
17
|
ManyToManyField,
|
|
19
18
|
OneToOneField,
|
|
20
19
|
PositiveIntegerField,
|
|
21
|
-
PositiveSmallIntegerField,
|
|
22
20
|
TextChoices,
|
|
23
21
|
TextField,
|
|
24
22
|
)
|
|
23
|
+
from typing_extensions import override
|
|
25
24
|
|
|
26
25
|
from codex.models.base import (
|
|
27
26
|
MAX_ISSUE_SUFFIX_LEN,
|
|
@@ -29,6 +28,12 @@ from codex.models.base import (
|
|
|
29
28
|
BaseModel,
|
|
30
29
|
max_choices_len,
|
|
31
30
|
)
|
|
31
|
+
from codex.models.fields import (
|
|
32
|
+
CleaningCharField,
|
|
33
|
+
CleaningTextField,
|
|
34
|
+
CoercingDecimalField,
|
|
35
|
+
CoercingPositiveSmallIntegerField,
|
|
36
|
+
)
|
|
32
37
|
from codex.models.groups import (
|
|
33
38
|
Folder,
|
|
34
39
|
Imprint,
|
|
@@ -37,13 +42,13 @@ from codex.models.groups import (
|
|
|
37
42
|
Volume,
|
|
38
43
|
WatchedPathBrowserGroup,
|
|
39
44
|
)
|
|
45
|
+
from codex.models.identifier import Identifier
|
|
40
46
|
from codex.models.named import (
|
|
41
47
|
AgeRating,
|
|
42
48
|
Character,
|
|
43
|
-
Contributor,
|
|
44
49
|
Country,
|
|
50
|
+
Credit,
|
|
45
51
|
Genre,
|
|
46
|
-
Identifier,
|
|
47
52
|
Language,
|
|
48
53
|
Location,
|
|
49
54
|
OriginalFormat,
|
|
@@ -54,6 +59,7 @@ from codex.models.named import (
|
|
|
54
59
|
Tag,
|
|
55
60
|
Tagger,
|
|
56
61
|
Team,
|
|
62
|
+
Universe,
|
|
57
63
|
)
|
|
58
64
|
|
|
59
65
|
__all__ = ("Comic",)
|
|
@@ -71,10 +77,11 @@ class ReadingDirection(TextChoices):
|
|
|
71
77
|
class FileType(TextChoices):
|
|
72
78
|
"""Identifiers for file formats."""
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
CBT =
|
|
77
|
-
|
|
80
|
+
CBR = FileTypeEnum.CBR.value
|
|
81
|
+
CBZ = FileTypeEnum.CBZ.value
|
|
82
|
+
CBT = FileTypeEnum.CBT.value
|
|
83
|
+
CB7 = FileTypeEnum.CB7.value
|
|
84
|
+
PDF = FileTypeEnum.PDF.value
|
|
78
85
|
|
|
79
86
|
|
|
80
87
|
class Comic(WatchedPathBrowserGroup):
|
|
@@ -92,15 +99,21 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
92
99
|
updated_at = DateTimeField(auto_now=True, db_index=True)
|
|
93
100
|
|
|
94
101
|
# From WatchedPath, but interferes with related_name from folders m2m field
|
|
95
|
-
parent_folder = ForeignKey(
|
|
102
|
+
parent_folder: ForeignKey | None = ForeignKey(
|
|
96
103
|
"Folder", on_delete=CASCADE, null=True, related_name="comic_in"
|
|
97
104
|
)
|
|
98
105
|
|
|
99
106
|
# Unique comic fields
|
|
100
|
-
|
|
107
|
+
collection_title = CleaningCharField(
|
|
108
|
+
db_index=True,
|
|
109
|
+
max_length=MAX_NAME_LEN,
|
|
110
|
+
default="",
|
|
111
|
+
db_collation="nocase",
|
|
112
|
+
)
|
|
113
|
+
issue_number = CoercingDecimalField(
|
|
101
114
|
db_index=True, decimal_places=2, max_digits=10, null=True
|
|
102
115
|
)
|
|
103
|
-
issue_suffix =
|
|
116
|
+
issue_suffix = CleaningCharField(
|
|
104
117
|
db_index=True,
|
|
105
118
|
max_length=MAX_ISSUE_SUFFIX_LEN,
|
|
106
119
|
default="",
|
|
@@ -111,6 +124,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
111
124
|
series = ForeignKey(Series, db_index=True, on_delete=CASCADE)
|
|
112
125
|
imprint = ForeignKey(Imprint, db_index=True, on_delete=CASCADE)
|
|
113
126
|
publisher = ForeignKey(Publisher, db_index=True, on_delete=CASCADE)
|
|
127
|
+
|
|
114
128
|
# Other FKs
|
|
115
129
|
age_rating = ForeignKey(AgeRating, db_index=True, null=True, on_delete=CASCADE)
|
|
116
130
|
original_format = ForeignKey(
|
|
@@ -118,31 +132,43 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
118
132
|
)
|
|
119
133
|
scan_info = ForeignKey(ScanInfo, db_index=True, null=True, on_delete=CASCADE)
|
|
120
134
|
tagger = ForeignKey(Tagger, db_index=True, null=True, on_delete=CASCADE)
|
|
135
|
+
main_character = ForeignKey(
|
|
136
|
+
Character,
|
|
137
|
+
db_index=True,
|
|
138
|
+
null=True,
|
|
139
|
+
on_delete=CASCADE,
|
|
140
|
+
related_name="main_character_in_comics",
|
|
141
|
+
)
|
|
142
|
+
main_team = ForeignKey(
|
|
143
|
+
Character,
|
|
144
|
+
db_index=True,
|
|
145
|
+
null=True,
|
|
146
|
+
on_delete=CASCADE,
|
|
147
|
+
related_name="main_team_in_comics",
|
|
148
|
+
)
|
|
149
|
+
|
|
121
150
|
# Alpha2 codes
|
|
122
151
|
country = ForeignKey(Country, db_index=True, null=True, on_delete=CASCADE)
|
|
123
152
|
language = ForeignKey(Language, db_index=True, null=True, on_delete=CASCADE)
|
|
124
153
|
|
|
125
154
|
# Date
|
|
126
|
-
year =
|
|
127
|
-
month =
|
|
128
|
-
day =
|
|
155
|
+
year = CoercingPositiveSmallIntegerField(db_index=True, null=True)
|
|
156
|
+
month = CoercingPositiveSmallIntegerField(db_index=True, null=True)
|
|
157
|
+
day = CoercingPositiveSmallIntegerField(db_index=True, null=True)
|
|
129
158
|
|
|
130
159
|
# Text
|
|
131
|
-
summary =
|
|
132
|
-
review =
|
|
133
|
-
notes =
|
|
160
|
+
summary = CleaningCharField(default="", db_collation="nocase")
|
|
161
|
+
review = CleaningTextField(default="", db_collation="nocase")
|
|
162
|
+
notes = CleaningTextField(default="", db_collation="nocase")
|
|
134
163
|
|
|
135
164
|
# Ratings
|
|
136
|
-
|
|
137
|
-
db_index=True, decimal_places=2, max_digits=5, default=None, null=True
|
|
138
|
-
)
|
|
139
|
-
critical_rating = DecimalField(
|
|
165
|
+
critical_rating = CoercingDecimalField(
|
|
140
166
|
db_index=True, decimal_places=2, max_digits=5, default=None, null=True
|
|
141
167
|
)
|
|
142
168
|
|
|
143
169
|
# Reader
|
|
144
|
-
page_count =
|
|
145
|
-
reading_direction =
|
|
170
|
+
page_count = CoercingPositiveSmallIntegerField(db_index=True, default=0)
|
|
171
|
+
reading_direction = CleaningCharField(
|
|
146
172
|
db_index=True,
|
|
147
173
|
choices=ReadingDirection.choices,
|
|
148
174
|
default=ReadingDirectionEnum.LTR.value,
|
|
@@ -155,7 +181,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
155
181
|
|
|
156
182
|
# ManyToMany
|
|
157
183
|
characters = ManyToManyField(Character)
|
|
158
|
-
|
|
184
|
+
credits = ManyToManyField(Credit)
|
|
159
185
|
genres = ManyToManyField(Genre)
|
|
160
186
|
identifiers = ManyToManyField(Identifier)
|
|
161
187
|
locations = ManyToManyField(Location)
|
|
@@ -164,6 +190,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
164
190
|
story_arc_numbers = ManyToManyField(StoryArcNumber)
|
|
165
191
|
tags = ManyToManyField(Tag)
|
|
166
192
|
teams = ManyToManyField(Team)
|
|
193
|
+
universes = ManyToManyField(Universe)
|
|
167
194
|
|
|
168
195
|
#####################
|
|
169
196
|
# Comicbox Ignored:
|
|
@@ -178,10 +205,10 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
178
205
|
|
|
179
206
|
# codex only
|
|
180
207
|
date = DateField(db_index=True, null=True)
|
|
181
|
-
decade =
|
|
208
|
+
decade = CoercingPositiveSmallIntegerField(db_index=True, null=True)
|
|
182
209
|
folders = ManyToManyField(Folder)
|
|
183
210
|
size = PositiveIntegerField(db_index=True)
|
|
184
|
-
file_type =
|
|
211
|
+
file_type = CleaningCharField(
|
|
185
212
|
db_index=True,
|
|
186
213
|
choices=FileType.choices,
|
|
187
214
|
max_length=max_choices_len(FileType),
|
|
@@ -189,9 +216,10 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
189
216
|
default="",
|
|
190
217
|
db_collation="nocase",
|
|
191
218
|
)
|
|
219
|
+
metadata_mtime = DateTimeField(null=True)
|
|
192
220
|
|
|
193
221
|
# Not useful
|
|
194
|
-
custom_cover = None
|
|
222
|
+
custom_cover: ForeignKey | None = None
|
|
195
223
|
|
|
196
224
|
class Meta(WatchedPathBrowserGroup.Meta):
|
|
197
225
|
"""Constraints."""
|
|
@@ -218,6 +246,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
218
246
|
else:
|
|
219
247
|
self.decade = self.year - (self.year % 10)
|
|
220
248
|
|
|
249
|
+
@override
|
|
221
250
|
def presave(self):
|
|
222
251
|
"""Set computed values."""
|
|
223
252
|
super().presave()
|
|
@@ -263,7 +292,7 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
263
292
|
|
|
264
293
|
@classmethod
|
|
265
294
|
def get_title(
|
|
266
|
-
cls, obj, volume: bool, name: bool, filename_fallback: bool, zero_pad=None
|
|
295
|
+
cls, obj, *, volume: bool, name: bool, filename_fallback: bool, zero_pad=None
|
|
267
296
|
):
|
|
268
297
|
"""Create the comic title for display."""
|
|
269
298
|
names = []
|
|
@@ -274,7 +303,8 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
274
303
|
|
|
275
304
|
# Volume
|
|
276
305
|
if volume and (vn := obj.volume.name):
|
|
277
|
-
|
|
306
|
+
vn_to = obj.volume.number_to
|
|
307
|
+
vn = Volume.to_str(vn, vn_to)
|
|
278
308
|
names.append(vn)
|
|
279
309
|
|
|
280
310
|
# Issue
|
|
@@ -291,7 +321,8 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
291
321
|
title = obj.get_filename()
|
|
292
322
|
return title
|
|
293
323
|
|
|
294
|
-
|
|
324
|
+
@override
|
|
325
|
+
def __repr__(self):
|
|
295
326
|
"""Most common text representation for logging."""
|
|
296
327
|
return self.get_title(self, volume=True, name=True, filename_fallback=True)
|
|
297
328
|
|
|
@@ -307,35 +338,41 @@ class Comic(WatchedPathBrowserGroup):
|
|
|
307
338
|
|
|
308
339
|
class ComicFTS(BaseModel):
|
|
309
340
|
comic = OneToOneField(primary_key=True, to=Comic, on_delete=CASCADE)
|
|
341
|
+
# Attributes
|
|
342
|
+
collection_title = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
343
|
+
issue = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
344
|
+
name = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
345
|
+
notes = TextField(db_collation="nocase")
|
|
346
|
+
review = TextField(db_collation="nocase")
|
|
347
|
+
summary = TextField(db_collation="nocase")
|
|
348
|
+
# FK groups
|
|
310
349
|
publisher = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
311
350
|
imprint = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
312
351
|
series = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
313
|
-
|
|
314
|
-
issue = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
315
|
-
name = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
352
|
+
# FK
|
|
316
353
|
age_rating = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
317
354
|
country = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
355
|
+
file_type = CharField(db_collation="nocase", max_length=max_choices_len(FileType))
|
|
318
356
|
language = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
319
|
-
notes = TextField(db_collation="nocase")
|
|
320
357
|
original_format = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
321
|
-
review = TextField(db_collation="nocase")
|
|
322
358
|
scan_info = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
323
|
-
summary = TextField(db_collation="nocase")
|
|
324
359
|
tagger = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
360
|
+
# M2M
|
|
325
361
|
characters = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
326
|
-
|
|
362
|
+
credits = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
327
363
|
genres = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
364
|
+
identifiers = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
365
|
+
sources = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
328
366
|
locations = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
367
|
+
reading_direction = CharField(
|
|
368
|
+
db_collation="nocase", max_length=max_choices_len(ReadingDirection)
|
|
369
|
+
)
|
|
329
370
|
series_groups = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
330
371
|
stories = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
331
372
|
story_arcs = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
332
373
|
tags = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
333
374
|
teams = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
334
|
-
|
|
335
|
-
reading_direction = CharField(
|
|
336
|
-
db_collation="nocase", max_length=max_choices_len(ReadingDirection)
|
|
337
|
-
)
|
|
338
|
-
file_type = CharField(db_collation="nocase", max_length=max_choices_len(FileType))
|
|
375
|
+
universes = CharField(db_collation="nocase", max_length=MAX_NAME_LEN)
|
|
339
376
|
|
|
340
377
|
class Meta(BaseModel.Meta):
|
|
341
378
|
managed = False
|
codex/models/fields.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Custom Django fields."""
|
|
2
|
+
|
|
3
|
+
from decimal import ROUND_DOWN, Decimal
|
|
4
|
+
from html import unescape
|
|
5
|
+
|
|
6
|
+
from django.db.models.fields import (
|
|
7
|
+
CharField,
|
|
8
|
+
DecimalField,
|
|
9
|
+
PositiveSmallIntegerField,
|
|
10
|
+
SmallIntegerField,
|
|
11
|
+
TextField,
|
|
12
|
+
)
|
|
13
|
+
from nh3 import clean
|
|
14
|
+
from typing_extensions import override
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CleaningStringFieldMixin:
|
|
18
|
+
"""Sanitizing Mixin for CharField & TextField."""
|
|
19
|
+
|
|
20
|
+
def get_prep_value(self, value):
|
|
21
|
+
"""Truncate, sanitize and unescape."""
|
|
22
|
+
if value := super().get_prep_value(value): # pyright: ignore[reportAttributeAccessIssue]
|
|
23
|
+
value = value[: self.max_length] # pyright: ignore[reportAttributeAccessIssue]
|
|
24
|
+
value = clean(value)
|
|
25
|
+
value = unescape(value)
|
|
26
|
+
return value
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CleaningCharField(CleaningStringFieldMixin, CharField):
|
|
30
|
+
"""Sanitizing Truncating CharField."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class CleaningTextField(CleaningStringFieldMixin, TextField):
|
|
34
|
+
"""Sanitizing Truncating TextField."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CoercingSmallIntegerFieldMixin:
|
|
38
|
+
"""Custom IntegerField Mixin that coerces values into a range."""
|
|
39
|
+
|
|
40
|
+
COERCE_MIN: int = 2**15 * -1
|
|
41
|
+
COERCE_MAX: int = 2**15 - 1
|
|
42
|
+
|
|
43
|
+
def get_prep_value(self, value):
|
|
44
|
+
"""Coerce int into range before insertion."""
|
|
45
|
+
value = super().get_prep_value(value) # pyright: ignore[reportAttributeAccessIssue]
|
|
46
|
+
if value is not None:
|
|
47
|
+
value = max(min(value, self.COERCE_MAX), self.COERCE_MIN)
|
|
48
|
+
return value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CoercingSmallIntegerField(CoercingSmallIntegerFieldMixin, SmallIntegerField):
|
|
52
|
+
"""Custom SmallIntegerField."""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CoercingPositiveSmallIntegerField(
|
|
56
|
+
CoercingSmallIntegerFieldMixin, PositiveSmallIntegerField
|
|
57
|
+
):
|
|
58
|
+
"""Custom PositiveSmallIntegerField."""
|
|
59
|
+
|
|
60
|
+
COERCE_MIN: int = 0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class CoercingDecimalField(DecimalField):
|
|
64
|
+
"""Custom DecimalField."""
|
|
65
|
+
|
|
66
|
+
def __init__(self, *args, **kwargs):
|
|
67
|
+
"""Init coercing values."""
|
|
68
|
+
super().__init__(*args, **kwargs)
|
|
69
|
+
self._quantize_str = Decimal(f"1e-{self.decimal_places}")
|
|
70
|
+
self._decimal_max = Decimal(10 ** (self.max_digits - 2) - 1)
|
|
71
|
+
|
|
72
|
+
@override
|
|
73
|
+
def get_prep_value(self, value):
|
|
74
|
+
"""Coerce Decimal."""
|
|
75
|
+
prepped_value: Decimal | None = super().get_prep_value(value)
|
|
76
|
+
if prepped_value is not None:
|
|
77
|
+
prepped_value = prepped_value.quantize(
|
|
78
|
+
self._quantize_str, rounding=ROUND_DOWN
|
|
79
|
+
)
|
|
80
|
+
prepped_value = prepped_value.min(self._decimal_max)
|
|
81
|
+
return prepped_value
|
codex/models/functions.py
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from django.db.models.aggregates import Aggregate
|
|
4
4
|
from django.db.models.expressions import Func
|
|
5
|
-
from django.db.models.fields import CharField, FloatField
|
|
5
|
+
from django.db.models.fields import CharField, FloatField
|
|
6
6
|
from django.db.models.fields.json import JSONField
|
|
7
7
|
from django.db.models.fields.related import OneToOneField
|
|
8
8
|
from django.db.models.lookups import Lookup
|
|
9
|
+
from typing_extensions import override
|
|
10
|
+
|
|
11
|
+
from codex.models.fields import CleaningCharField, CleaningTextField
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
class JsonGroupArray(Aggregate):
|
|
@@ -40,6 +43,7 @@ class FTS5Match(Lookup):
|
|
|
40
43
|
|
|
41
44
|
lookup_name = "match"
|
|
42
45
|
|
|
46
|
+
@override
|
|
43
47
|
def as_sql(self, compiler, connection):
|
|
44
48
|
"""Generate MATCH sql."""
|
|
45
49
|
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
@@ -51,12 +55,14 @@ class FTS5Match(Lookup):
|
|
|
51
55
|
|
|
52
56
|
|
|
53
57
|
@CharField.register_lookup
|
|
54
|
-
@
|
|
58
|
+
@CleaningCharField.register_lookup
|
|
59
|
+
@CleaningTextField.register_lookup
|
|
55
60
|
class Like(Lookup):
|
|
56
61
|
"""SQL LIKE lookup."""
|
|
57
62
|
|
|
58
63
|
lookup_name = "like"
|
|
59
64
|
|
|
65
|
+
@override
|
|
60
66
|
def as_sql(self, compiler, connection):
|
|
61
67
|
"""Generate LIKE sql."""
|
|
62
68
|
lhs, lhs_params = self.process_lhs(compiler, connection)
|