codex 1.7.3a2__py3-none-any.whl → 1.7.5__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/asgi.py +2 -1
- codex/choices/__init__.py +1 -0
- codex/{choices.py → choices/admin.py} +47 -146
- codex/choices/browser.py +85 -0
- codex/{choices_to_json.py → choices/choices_to_json.py} +25 -19
- codex/choices/notifications.py +16 -0
- codex/choices/reader.py +33 -0
- codex/db.py +2 -2
- codex/exceptions.py +7 -8
- codex/librarian/bookmark/bookmarkd.py +8 -4
- codex/librarian/bookmark/update.py +84 -49
- codex/librarian/covers/create.py +10 -8
- codex/librarian/covers/path.py +6 -5
- codex/librarian/covers/purge.py +4 -4
- codex/librarian/importer/aggregate.py +2 -2
- codex/librarian/importer/cache.py +1 -4
- codex/librarian/importer/create_comics.py +2 -2
- codex/librarian/importer/create_covers.py +1 -1
- codex/librarian/importer/create_fks.py +4 -3
- codex/librarian/importer/deleted.py +3 -3
- codex/librarian/importer/extract.py +56 -37
- codex/librarian/importer/failed_imports.py +1 -1
- codex/librarian/importer/importer.py +8 -3
- codex/librarian/importer/importerd.py +3 -3
- codex/librarian/importer/link_comics.py +2 -1
- codex/librarian/importer/moved.py +2 -7
- codex/librarian/importer/query_fks.py +1 -4
- codex/librarian/importer/tasks.py +1 -1
- codex/librarian/janitor/integrity.py +27 -20
- codex/librarian/janitor/janitor.py +1 -1
- codex/librarian/janitor/latest_version.py +1 -1
- codex/librarian/janitor/update.py +5 -2
- codex/librarian/janitor/vacuum.py +1 -1
- codex/librarian/librariand.py +3 -2
- codex/librarian/notifier/notifierd.py +2 -1
- codex/librarian/notifier/tasks.py +17 -3
- codex/librarian/search/optimize.py +1 -1
- codex/librarian/search/remove.py +1 -1
- codex/librarian/search/update.py +4 -4
- codex/librarian/telemeter/stats.py +7 -6
- codex/librarian/telemeter/telemeter.py +0 -1
- codex/librarian/watchdog/db_snapshot.py +3 -3
- codex/librarian/watchdog/dir_snapshot_diff.py +3 -4
- codex/librarian/watchdog/emitter.py +4 -4
- codex/librarian/watchdog/event_batcherd.py +2 -1
- codex/librarian/watchdog/events.py +1 -2
- codex/librarian/watchdog/observers.py +15 -10
- codex/logger/logging.py +1 -1
- codex/memory.py +3 -2
- codex/migrations/0001_init.py +1 -2
- codex/migrations/0014_pdf_issue_suffix_remove_cover_image_sort_name.py +1 -2
- codex/migrations/0018_rename_userbookmark_bookmark.py +1 -2
- codex/migrations/0028_telemeter.py +1 -5
- codex/models/base.py +3 -1
- codex/models/bookmark.py +4 -7
- codex/models/comic.py +2 -2
- codex/models/functions.py +12 -5
- codex/models/groups.py +1 -1
- codex/models/library.py +1 -1
- codex/models/paths.py +4 -4
- codex/models/query.py +8 -4
- codex/models/util.py +1 -1
- codex/permissions.py +1 -1
- codex/run.py +1 -1
- codex/serializers/admin/libraries.py +1 -3
- codex/serializers/admin/stats.py +4 -4
- codex/serializers/admin/tasks.py +12 -2
- codex/serializers/auth.py +4 -2
- codex/serializers/browser/choices.py +87 -9
- codex/serializers/browser/filters.py +9 -37
- codex/serializers/browser/metadata.py +2 -1
- codex/serializers/browser/mixins.py +7 -3
- codex/serializers/browser/mtime.py +3 -5
- codex/serializers/browser/page.py +5 -4
- codex/serializers/browser/settings.py +8 -6
- codex/serializers/fields/__init__.py +37 -0
- codex/serializers/fields/auth.py +45 -0
- codex/serializers/fields/browser.py +85 -0
- codex/serializers/fields/group.py +13 -0
- codex/serializers/fields/reader.py +22 -0
- codex/serializers/fields/sanitized.py +13 -0
- codex/serializers/fields/session.py +16 -0
- codex/serializers/fields/stats.py +36 -0
- codex/serializers/fields/vuetify.py +62 -0
- codex/serializers/models/base.py +1 -1
- codex/serializers/models/comic.py +2 -2
- codex/serializers/models/groups.py +0 -2
- codex/serializers/models/named.py +1 -1
- codex/serializers/models/pycountry.py +1 -1
- codex/serializers/opds/authentication.py +4 -2
- codex/serializers/opds/urls.py +2 -1
- codex/serializers/opds/v1.py +4 -3
- codex/serializers/opds/v2/feed.py +2 -1
- codex/serializers/opds/v2/links.py +23 -21
- codex/serializers/opds/v2/metadata.py +4 -8
- codex/serializers/opds/v2/progression.py +5 -3
- codex/serializers/opds/v2/publication.py +16 -18
- codex/serializers/opds/v2/unused.py +15 -8
- codex/serializers/reader.py +16 -14
- codex/serializers/redirect.py +2 -1
- codex/serializers/route.py +6 -4
- codex/serializers/settings.py +5 -3
- codex/serializers/versions.py +2 -1
- codex/settings/settings.py +4 -3
- codex/signals/django_signals.py +1 -1
- codex/startup.py +2 -2
- codex/static_root/assets/{VCheckbox-FaT6MGfu.f6732060f734.js → VCheckbox-CWBDr4kF.6da5bf3a4d90.js} +1 -1
- codex/static_root/assets/VCheckbox-CWBDr4kF.6da5bf3a4d90.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWBDr4kF.6da5bf3a4d90.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-FaT6MGfu.js → VCheckbox-CWBDr4kF.js} +1 -1
- codex/static_root/assets/VCheckbox-CWBDr4kF.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWBDr4kF.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CZ_P-qUM.847452d574cf.js → VCheckboxBtn-COaoh3uF.fc880a386827.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.fc880a386827.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.fc880a386827.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CZ_P-qUM.js → VCheckboxBtn-COaoh3uF.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-COaoh3uF.js.gz +0 -0
- codex/static_root/assets/{VCombobox-C8QLNlSl.6f431e19a453.js → VCombobox-DkOruNH0.f30f163ee632.js} +1 -1
- codex/static_root/assets/VCombobox-DkOruNH0.f30f163ee632.js.br +0 -0
- codex/static_root/assets/VCombobox-DkOruNH0.f30f163ee632.js.gz +0 -0
- codex/static_root/assets/{VCombobox-C8QLNlSl.js → VCombobox-DkOruNH0.js} +1 -1
- codex/static_root/assets/VCombobox-DkOruNH0.js.br +0 -0
- codex/static_root/assets/VCombobox-DkOruNH0.js.gz +0 -0
- codex/static_root/assets/{VDialog-RVLeW7je.c0c7eef71eec.js → VDialog-Dr7SuC2S.b6ec7df390f4.js} +1 -1
- codex/static_root/assets/VDialog-Dr7SuC2S.b6ec7df390f4.js.br +0 -0
- codex/static_root/assets/VDialog-Dr7SuC2S.b6ec7df390f4.js.gz +0 -0
- codex/static_root/assets/{VDialog-RVLeW7je.js → VDialog-Dr7SuC2S.js} +1 -1
- codex/static_root/assets/VDialog-Dr7SuC2S.js.br +0 -0
- codex/static_root/assets/VDialog-Dr7SuC2S.js.gz +0 -0
- codex/static_root/assets/{VDivider-D1Ot4vR2.9dbee744fb3c.js → VDivider-By4u2EsM.fd5ee9cce906.js} +1 -1
- codex/static_root/assets/VDivider-By4u2EsM.fd5ee9cce906.js.br +0 -0
- codex/static_root/assets/VDivider-By4u2EsM.fd5ee9cce906.js.gz +0 -0
- codex/static_root/assets/{VDivider-D1Ot4vR2.js → VDivider-By4u2EsM.js} +1 -1
- codex/static_root/assets/VDivider-By4u2EsM.js.br +0 -0
- codex/static_root/assets/VDivider-By4u2EsM.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-DQilGHZk.43f06d0a45e0.js → VExpansionPanels-BhO9oj0a.e99bea455c78.js} +1 -1
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.e99bea455c78.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.e99bea455c78.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-DQilGHZk.js → VExpansionPanels-BhO9oj0a.js} +1 -1
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-BhO9oj0a.js.gz +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.70c9c6fcb9e3.js +1 -0
- codex/static_root/assets/VForm-XhA6T0Lc.70c9c6fcb9e3.js.br +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.70c9c6fcb9e3.js.gz +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.js +1 -0
- codex/static_root/assets/VForm-XhA6T0Lc.js.br +0 -0
- codex/static_root/assets/VForm-XhA6T0Lc.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-DoayJpcS.fe5e0e74ffee.js → VRadioGroup-C1WCG0rO.6ebc88e4f144.js} +1 -1
- codex/static_root/assets/VRadioGroup-C1WCG0rO.6ebc88e4f144.js.br +3 -0
- codex/static_root/assets/VRadioGroup-C1WCG0rO.6ebc88e4f144.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-DoayJpcS.js → VRadioGroup-C1WCG0rO.js} +1 -1
- codex/static_root/assets/VRadioGroup-C1WCG0rO.js.br +3 -0
- codex/static_root/assets/VRadioGroup-C1WCG0rO.js.gz +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.ec45ee26818a.js +1 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.ec45ee26818a.js.br +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.ec45ee26818a.js.gz +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.js +1 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.js.br +0 -0
- codex/static_root/assets/VSelect-Bbt1vrBg.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-TaKCeZgb.ad6c96efe57c.js → VSelectionControl-BkZZAsWo.ba6eca944e2e.js} +1 -1
- codex/static_root/assets/VSelectionControl-BkZZAsWo.ba6eca944e2e.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BkZZAsWo.ba6eca944e2e.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-TaKCeZgb.js → VSelectionControl-BkZZAsWo.js} +1 -1
- codex/static_root/assets/VSelectionControl-BkZZAsWo.js.br +0 -0
- codex/static_root/assets/VSelectionControl-BkZZAsWo.js.gz +0 -0
- codex/static_root/assets/{VTable-BfcOiEpa.77ef3973bb54.js → VTable-D7P2eIc2.5e94bf2a515b.js} +1 -1
- codex/static_root/assets/VTable-D7P2eIc2.5e94bf2a515b.js.br +0 -0
- codex/static_root/assets/VTable-D7P2eIc2.5e94bf2a515b.js.gz +0 -0
- codex/static_root/assets/{VTable-BfcOiEpa.js → VTable-D7P2eIc2.js} +1 -1
- codex/static_root/assets/VTable-D7P2eIc2.js.br +0 -0
- codex/static_root/assets/VTable-D7P2eIc2.js.gz +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.e77444188aa3.js +1 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.e77444188aa3.js.br +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.e77444188aa3.js.gz +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.js +1 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.js.br +0 -0
- codex/static_root/assets/VWindowItem-Dm2szrjK.js.gz +0 -0
- codex/static_root/assets/{admin-80eqCqtz.d6deb9edb8cb.js → admin-B4z2nA5P.da0c92500311.js} +1 -1
- codex/static_root/assets/admin-B4z2nA5P.da0c92500311.js.br +0 -0
- codex/static_root/assets/admin-B4z2nA5P.da0c92500311.js.gz +0 -0
- codex/static_root/assets/{admin-80eqCqtz.js → admin-B4z2nA5P.js} +1 -1
- codex/static_root/assets/admin-B4z2nA5P.js.br +0 -0
- codex/static_root/assets/admin-B4z2nA5P.js.gz +0 -0
- codex/static_root/assets/admin-BhW3PNO0.e444048e548d.js +1 -0
- codex/static_root/assets/admin-BhW3PNO0.e444048e548d.js.br +0 -0
- codex/static_root/assets/admin-BhW3PNO0.e444048e548d.js.gz +0 -0
- codex/static_root/assets/admin-BhW3PNO0.js +1 -0
- codex/static_root/assets/admin-BhW3PNO0.js.br +0 -0
- codex/static_root/assets/admin-BhW3PNO0.js.gz +0 -0
- codex/static_root/assets/{admin-menu-_aAGknKO.0c08c9bd2e7d.js → admin-menu-CL7S-xqR.92b6d84c4b70.js} +1 -1
- codex/static_root/assets/admin-menu-CL7S-xqR.92b6d84c4b70.js.br +0 -0
- codex/static_root/assets/admin-menu-CL7S-xqR.92b6d84c4b70.js.gz +0 -0
- codex/static_root/assets/{admin-menu-_aAGknKO.js → admin-menu-CL7S-xqR.js} +1 -1
- codex/static_root/assets/admin-menu-CL7S-xqR.js.br +0 -0
- codex/static_root/assets/admin-menu-CL7S-xqR.js.gz +0 -0
- codex/static_root/assets/{admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js → admin-settings-button-progress-BgBgdELw.52d052e38bc1.js} +1 -1
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.52d052e38bc1.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.52d052e38bc1.js.gz +0 -0
- codex/static_root/assets/{admin-settings-button-progress-BqRFyhjf.js → admin-settings-button-progress-BgBgdELw.js} +1 -1
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BgBgdELw.js.gz +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.a4af87c2a667.js +1 -0
- codex/static_root/assets/browser-Bi5ov5k8.a4af87c2a667.js.br +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.a4af87c2a667.js.gz +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.js +1 -0
- codex/static_root/assets/browser-Bi5ov5k8.js.br +0 -0
- codex/static_root/assets/browser-Bi5ov5k8.js.gz +0 -0
- codex/static_root/assets/{browser-chTZ1CM4.521193ab0710.css → browser-DNzQvgkY.aea8b7d7ca40.css} +1 -1
- codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.br +0 -0
- codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.gz +0 -0
- codex/static_root/assets/{browser-chTZ1CM4.css → browser-DNzQvgkY.css} +1 -1
- codex/static_root/assets/browser-DNzQvgkY.css.br +0 -0
- codex/static_root/assets/browser-DNzQvgkY.css.gz +0 -0
- codex/static_root/assets/{change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js → change-password-dialog-BKar2Bhb.3dbc2feb3c5a.js} +1 -1
- codex/static_root/assets/change-password-dialog-BKar2Bhb.3dbc2feb3c5a.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BKar2Bhb.3dbc2feb3c5a.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-1ZVP_Q2w.js → change-password-dialog-BKar2Bhb.js} +1 -1
- codex/static_root/assets/change-password-dialog-BKar2Bhb.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BKar2Bhb.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DqCey9Iq.e315d7f8f752.js → confirm-dialog-BoBL4OoS.abef9614fea9.js} +1 -1
- codex/static_root/assets/confirm-dialog-BoBL4OoS.abef9614fea9.js.br +0 -0
- codex/static_root/assets/confirm-dialog-BoBL4OoS.abef9614fea9.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DqCey9Iq.js → confirm-dialog-BoBL4OoS.js} +1 -1
- codex/static_root/assets/confirm-dialog-BoBL4OoS.js.br +0 -0
- codex/static_root/assets/confirm-dialog-BoBL4OoS.js.gz +0 -0
- codex/static_root/assets/{datetime-column-CBA8bYeO.17a31f189d66.js → datetime-column-BsiYRUKO.cadd764c06f4.js} +1 -1
- codex/static_root/assets/datetime-column-BsiYRUKO.cadd764c06f4.js.br +0 -0
- codex/static_root/assets/datetime-column-BsiYRUKO.cadd764c06f4.js.gz +0 -0
- codex/static_root/assets/{datetime-column-CBA8bYeO.js → datetime-column-BsiYRUKO.js} +1 -1
- codex/static_root/assets/datetime-column-BsiYRUKO.js.br +0 -0
- codex/static_root/assets/datetime-column-BsiYRUKO.js.gz +0 -0
- codex/static_root/assets/{filter-mnO3lLPo.659442401b16.js → filter-HnY0knto.07f807227dcc.js} +1 -1
- codex/static_root/assets/filter-HnY0knto.07f807227dcc.js.br +0 -0
- codex/static_root/assets/filter-HnY0knto.07f807227dcc.js.gz +0 -0
- codex/static_root/assets/{filter-mnO3lLPo.js → filter-HnY0knto.js} +1 -1
- codex/static_root/assets/filter-HnY0knto.js.br +0 -0
- codex/static_root/assets/filter-HnY0knto.js.gz +0 -0
- codex/static_root/assets/{flag-tab-Bc677pNb.1b8a2f7c0dc3.js → flag-tab-CcS5pve2.a1df5d92e222.js} +1 -1
- codex/static_root/assets/flag-tab-CcS5pve2.a1df5d92e222.js.br +0 -0
- codex/static_root/assets/flag-tab-CcS5pve2.a1df5d92e222.js.gz +0 -0
- codex/static_root/assets/{flag-tab-Bc677pNb.js → flag-tab-CcS5pve2.js} +1 -1
- codex/static_root/assets/flag-tab-CcS5pve2.js.br +0 -0
- codex/static_root/assets/flag-tab-CcS5pve2.js.gz +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css +1 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.br +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.gz +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.css +1 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.css.br +0 -0
- codex/static_root/assets/flag-tab-D2MYXCHk.css.gz +0 -0
- codex/static_root/assets/{forwardRefs-DPRKg5wq.6f09e9d22fa6.js → forwardRefs-i80xmxX3.db393aeef392.js} +1 -1
- codex/static_root/assets/forwardRefs-i80xmxX3.db393aeef392.js.br +0 -0
- codex/static_root/assets/forwardRefs-i80xmxX3.db393aeef392.js.gz +0 -0
- codex/static_root/assets/{forwardRefs-DPRKg5wq.js → forwardRefs-i80xmxX3.js} +1 -1
- codex/static_root/assets/forwardRefs-i80xmxX3.js.br +0 -0
- codex/static_root/assets/forwardRefs-i80xmxX3.js.gz +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.f72e944c0ff1.js +1 -0
- codex/static_root/assets/group-tab-SY0gxmHW.f72e944c0ff1.js.br +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.f72e944c0ff1.js.gz +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.js +1 -0
- codex/static_root/assets/group-tab-SY0gxmHW.js.br +0 -0
- codex/static_root/assets/group-tab-SY0gxmHW.js.gz +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.07e291d9d955.js +1 -0
- codex/static_root/assets/http-error-EE8gtq5A.07e291d9d955.js.br +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.07e291d9d955.js.gz +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.js +1 -0
- codex/static_root/assets/http-error-EE8gtq5A.js.br +0 -0
- codex/static_root/assets/http-error-EE8gtq5A.js.gz +0 -0
- codex/static_root/assets/{index-9nBCksDQ.4561d2608773.js → index-gVdawuuE.a940fadbac00.js} +1 -1
- codex/static_root/assets/index-gVdawuuE.a940fadbac00.js.br +0 -0
- codex/static_root/assets/index-gVdawuuE.a940fadbac00.js.gz +0 -0
- codex/static_root/assets/{index-9nBCksDQ.js → index-gVdawuuE.js} +1 -1
- codex/static_root/assets/index-gVdawuuE.js.br +0 -0
- codex/static_root/assets/index-gVdawuuE.js.gz +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.4b4c606b77d6.js +1 -0
- codex/static_root/assets/library-tab-BkDIAvyS.4b4c606b77d6.js.br +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.4b4c606b77d6.js.gz +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.js +1 -0
- codex/static_root/assets/library-tab-BkDIAvyS.js.br +0 -0
- codex/static_root/assets/library-tab-BkDIAvyS.js.gz +0 -0
- codex/static_root/assets/main-B5uflU6E.77f3fcd6873f.js +35 -0
- codex/static_root/assets/main-B5uflU6E.77f3fcd6873f.js.br +0 -0
- codex/static_root/assets/main-B5uflU6E.77f3fcd6873f.js.gz +0 -0
- codex/static_root/assets/main-B5uflU6E.js +35 -0
- codex/static_root/assets/main-B5uflU6E.js.br +0 -0
- codex/static_root/assets/main-B5uflU6E.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.111d9b9d4133.js +1 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.111d9b9d4133.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.111d9b9d4133.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.js +1 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-wuQbceLs.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js → pagination-toolbar-D3JQmDiD.8513a4db85f0.js} +1 -1
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.8513a4db85f0.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.8513a4db85f0.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-Dx5JwWG-.js → pagination-toolbar-D3JQmDiD.js} +1 -1
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-D3JQmDiD.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-6ZE_HmLT.10d1e16abc78.js → pdf-doc-DRBtl9_2.225a6d89e842.js} +1 -1
- codex/static_root/assets/pdf-doc-DRBtl9_2.225a6d89e842.js.br +0 -0
- codex/static_root/assets/pdf-doc-DRBtl9_2.225a6d89e842.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-6ZE_HmLT.js → pdf-doc-DRBtl9_2.js} +1 -1
- codex/static_root/assets/pdf-doc-DRBtl9_2.js.br +0 -0
- codex/static_root/assets/pdf-doc-DRBtl9_2.js.gz +0 -0
- codex/static_root/assets/reader-DycvjN42.3e2b4f43235e.js +2 -0
- codex/static_root/assets/reader-DycvjN42.3e2b4f43235e.js.br +0 -0
- codex/static_root/assets/reader-DycvjN42.3e2b4f43235e.js.gz +0 -0
- codex/static_root/assets/reader-DycvjN42.js +2 -0
- codex/static_root/assets/reader-DycvjN42.js.br +0 -0
- codex/static_root/assets/reader-DycvjN42.js.gz +0 -0
- codex/static_root/assets/{relation-chips-C96hi5jm.js → relation-chips-CeHIEjvZ.04d302f4fa89.js} +1 -1
- codex/static_root/assets/relation-chips-CeHIEjvZ.04d302f4fa89.js.br +0 -0
- codex/static_root/assets/relation-chips-CeHIEjvZ.04d302f4fa89.js.gz +0 -0
- codex/static_root/assets/{relation-chips-C96hi5jm.9f07c9eb533a.js → relation-chips-CeHIEjvZ.js} +1 -1
- codex/static_root/assets/relation-chips-CeHIEjvZ.js.br +0 -0
- codex/static_root/assets/relation-chips-CeHIEjvZ.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.48dfaafaa00e.js +2 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.48dfaafaa00e.js.br +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.48dfaafaa00e.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.js +2 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.js.br +0 -0
- codex/static_root/assets/settings-drawer-DY8o-jF3.js.gz +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.3b5868abdd61.js +1 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.3b5868abdd61.js.br +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.3b5868abdd61.js.gz +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.js +1 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.js.br +0 -0
- codex/static_root/assets/ssrBoot-DRKt_yWP.js.gz +0 -0
- codex/static_root/assets/{stats-tab-CkT2ZGUQ.b704fa46dc88.js → stats-tab-C1XYGBKj.812896e1d09c.js} +1 -1
- codex/static_root/assets/stats-tab-C1XYGBKj.812896e1d09c.js.br +0 -0
- codex/static_root/assets/stats-tab-C1XYGBKj.812896e1d09c.js.gz +0 -0
- codex/static_root/assets/{stats-tab-CkT2ZGUQ.js → stats-tab-C1XYGBKj.js} +1 -1
- codex/static_root/assets/stats-tab-C1XYGBKj.js.br +0 -0
- codex/static_root/assets/stats-tab-C1XYGBKj.js.gz +0 -0
- codex/static_root/assets/task-tab-CW4DQ3KN.81812f9208e5.css +1 -0
- codex/static_root/assets/{task-tab-DfdUY9Rc.478e74041f80.css.br → task-tab-CW4DQ3KN.81812f9208e5.css.br} +1 -1
- codex/static_root/assets/task-tab-CW4DQ3KN.81812f9208e5.css.gz +0 -0
- codex/static_root/assets/task-tab-CW4DQ3KN.css +1 -0
- codex/static_root/assets/{task-tab-DfdUY9Rc.css.br → task-tab-CW4DQ3KN.css.br} +1 -1
- codex/static_root/assets/task-tab-CW4DQ3KN.css.gz +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.6b90f40a1a9f.js +1 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.6b90f40a1a9f.js.br +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.6b90f40a1a9f.js.gz +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.js +1 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.js.br +0 -0
- codex/static_root/assets/task-tab-lFRZ0NMd.js.gz +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.4e675fd9991c.js +1 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.4e675fd9991c.js.br +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.4e675fd9991c.js.gz +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.js +1 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.js.br +0 -0
- codex/static_root/assets/unauthorized-Dld9cV8d.js.gz +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.f88d8b1c8afe.js +1 -0
- codex/static_root/assets/user-tab-CN9nBOMS.f88d8b1c8afe.js.br +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.f88d8b1c8afe.js.gz +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.js +1 -0
- codex/static_root/assets/user-tab-CN9nBOMS.js.br +0 -0
- codex/static_root/assets/user-tab-CN9nBOMS.js.gz +0 -0
- codex/static_root/{manifest.225989a17f49.json → manifest.66d7229aa07a.json} +297 -277
- codex/static_root/manifest.66d7229aa07a.json.br +0 -0
- codex/static_root/manifest.66d7229aa07a.json.gz +0 -0
- codex/static_root/manifest.json +297 -277
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/status_controller.py +10 -13
- codex/urls/root.py +4 -3
- codex/views/admin/api_key.py +1 -4
- codex/views/admin/flag.py +2 -2
- codex/views/admin/group.py +2 -2
- codex/views/admin/library.py +4 -4
- codex/views/admin/stats.py +10 -10
- codex/views/admin/tasks.py +32 -13
- codex/views/admin/user.py +36 -10
- codex/views/auth.py +3 -8
- codex/views/bookmark.py +3 -3
- codex/views/browser/annotate/card.py +2 -2
- codex/views/browser/annotate/order.py +6 -7
- codex/views/browser/bookmark.py +3 -1
- codex/views/browser/breadcrumbs.py +6 -5
- codex/views/browser/browser.py +2 -2
- codex/views/browser/choices.py +7 -8
- codex/views/browser/cover.py +6 -3
- codex/views/browser/download.py +2 -1
- codex/views/browser/filters/bookmark.py +1 -1
- codex/views/browser/filters/field.py +1 -1
- codex/views/browser/filters/filter.py +6 -8
- codex/views/browser/filters/group.py +8 -8
- codex/views/browser/filters/search/field/expression.py +1 -2
- codex/views/browser/filters/search/field/optimize.py +1 -1
- codex/views/browser/filters/search/field/parse.py +2 -2
- codex/views/browser/filters/search/parse.py +4 -19
- codex/views/browser/group_mtime.py +1 -1
- codex/views/browser/metadata/copy_intersections.py +1 -1
- codex/views/browser/metadata/metadata.py +1 -1
- codex/views/browser/mtime.py +1 -1
- codex/views/browser/order_by.py +3 -5
- codex/views/browser/params.py +1 -1
- codex/views/browser/settings.py +1 -1
- codex/views/browser/validate.py +9 -6
- codex/views/const.py +0 -3
- codex/views/frontend.py +1 -1
- codex/views/mixins.py +3 -2
- codex/views/opds/authentication_v1.py +1 -1
- codex/views/opds/const.py +4 -4
- codex/views/opds/urls.py +1 -1
- codex/views/opds/util.py +4 -4
- codex/views/opds/v1/entry/entry.py +4 -2
- codex/views/opds/v1/entry/links.py +4 -5
- codex/views/opds/v1/facets.py +8 -4
- codex/views/opds/v1/feed.py +5 -5
- codex/views/opds/v1/links.py +11 -6
- codex/views/opds/v2/const.py +5 -2
- codex/views/opds/v2/feed.py +3 -3
- codex/views/opds/v2/links.py +18 -11
- codex/views/opds/v2/progression.py +8 -9
- codex/views/opds/v2/publications.py +10 -20
- codex/views/public.py +2 -2
- codex/views/reader/books.py +3 -2
- codex/views/reader/page.py +3 -3
- codex/views/reader/params.py +2 -2
- codex/views/reader/reader.py +6 -6
- codex/views/reader/settings.py +1 -1
- codex/views/session.py +10 -3
- codex/views/settings.py +2 -2
- codex/views/timezone.py +2 -2
- codex/views/util.py +10 -9
- codex/views/version.py +1 -1
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/METADATA +3 -1
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/RECORD +433 -415
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/WHEEL +1 -1
- codex/serializers/fields.py +0 -183
- codex/static_root/assets/VCheckbox-FaT6MGfu.f6732060f734.js.br +0 -0
- codex/static_root/assets/VCheckbox-FaT6MGfu.f6732060f734.js.gz +0 -0
- codex/static_root/assets/VCheckbox-FaT6MGfu.js.br +0 -0
- codex/static_root/assets/VCheckbox-FaT6MGfu.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.847452d574cf.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.847452d574cf.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CZ_P-qUM.js.gz +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.6f431e19a453.js.br +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.6f431e19a453.js.gz +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.js.br +0 -0
- codex/static_root/assets/VCombobox-C8QLNlSl.js.gz +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.c0c7eef71eec.js.br +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.c0c7eef71eec.js.gz +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.js.br +0 -0
- codex/static_root/assets/VDialog-RVLeW7je.js.gz +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.9dbee744fb3c.js.br +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.9dbee744fb3c.js.gz +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.js.br +0 -0
- codex/static_root/assets/VDivider-D1Ot4vR2.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.43f06d0a45e0.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.43f06d0a45e0.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DQilGHZk.js.gz +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js +0 -1
- codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js.br +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.81f3a5ff7ec3.js.gz +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.js +0 -1
- codex/static_root/assets/VForm-DNmY-qFJ.js.br +0 -0
- codex/static_root/assets/VForm-DNmY-qFJ.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.fe5e0e74ffee.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.fe5e0e74ffee.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.js.br +0 -0
- codex/static_root/assets/VRadioGroup-DoayJpcS.js.gz +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js +0 -1
- codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js.br +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.9ab865ec0fad.js.gz +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.js +0 -1
- codex/static_root/assets/VSelect-BSLmHX_P.js.br +0 -0
- codex/static_root/assets/VSelect-BSLmHX_P.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.ad6c96efe57c.js.br +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.ad6c96efe57c.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.js.br +0 -0
- codex/static_root/assets/VSelectionControl-TaKCeZgb.js.gz +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.77ef3973bb54.js.br +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.77ef3973bb54.js.gz +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.js.br +0 -0
- codex/static_root/assets/VTable-BfcOiEpa.js.gz +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js +0 -1
- codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js.br +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.e4c75ad78718.js.gz +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.js +0 -1
- codex/static_root/assets/VWindowItem-D8lWcbQY.js.br +0 -0
- codex/static_root/assets/VWindowItem-D8lWcbQY.js.gz +0 -0
- codex/static_root/assets/admin-80eqCqtz.d6deb9edb8cb.js.br +0 -0
- codex/static_root/assets/admin-80eqCqtz.d6deb9edb8cb.js.gz +0 -0
- codex/static_root/assets/admin-80eqCqtz.js.br +0 -0
- codex/static_root/assets/admin-80eqCqtz.js.gz +0 -0
- codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js +0 -1
- codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js.br +0 -0
- codex/static_root/assets/admin-CBLHOrM9.8c3c2268bc96.js.gz +0 -0
- codex/static_root/assets/admin-CBLHOrM9.js +0 -1
- codex/static_root/assets/admin-CBLHOrM9.js.br +0 -0
- codex/static_root/assets/admin-CBLHOrM9.js.gz +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.0c08c9bd2e7d.js.br +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.0c08c9bd2e7d.js.gz +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.js.br +0 -0
- codex/static_root/assets/admin-menu-_aAGknKO.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.2bb1194b21e2.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-BqRFyhjf.js.gz +0 -0
- codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js +0 -1
- codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js.br +0 -0
- codex/static_root/assets/browser-DAprXYuP.8bb92965dd9d.js.gz +0 -0
- codex/static_root/assets/browser-DAprXYuP.js +0 -1
- codex/static_root/assets/browser-DAprXYuP.js.br +0 -0
- codex/static_root/assets/browser-DAprXYuP.js.gz +0 -0
- codex/static_root/assets/browser-chTZ1CM4.521193ab0710.css.br +0 -0
- codex/static_root/assets/browser-chTZ1CM4.521193ab0710.css.gz +0 -0
- codex/static_root/assets/browser-chTZ1CM4.css.br +0 -0
- codex/static_root/assets/browser-chTZ1CM4.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js.br +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.ae0d9e5bd42b.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.js.br +0 -0
- codex/static_root/assets/change-password-dialog-1ZVP_Q2w.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.e315d7f8f752.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.e315d7f8f752.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DqCey9Iq.js.gz +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.17a31f189d66.js.br +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.17a31f189d66.js.gz +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.js.br +0 -0
- codex/static_root/assets/datetime-column-CBA8bYeO.js.gz +0 -0
- codex/static_root/assets/filter-mnO3lLPo.659442401b16.js.br +0 -0
- codex/static_root/assets/filter-mnO3lLPo.659442401b16.js.gz +0 -0
- codex/static_root/assets/filter-mnO3lLPo.js.br +0 -0
- codex/static_root/assets/filter-mnO3lLPo.js.gz +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.1b8a2f7c0dc3.js.br +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.1b8a2f7c0dc3.js.gz +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.js.br +0 -0
- codex/static_root/assets/flag-tab-Bc677pNb.js.gz +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css +0 -1
- codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css.br +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.be8eed14384e.css.gz +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.css +0 -1
- codex/static_root/assets/flag-tab-glFvEgEl.css.br +0 -0
- codex/static_root/assets/flag-tab-glFvEgEl.css.gz +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.6f09e9d22fa6.js.br +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.6f09e9d22fa6.js.gz +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.js.br +0 -0
- codex/static_root/assets/forwardRefs-DPRKg5wq.js.gz +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js +0 -1
- codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js.br +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.1127b51be6e7.js.gz +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.js +0 -1
- codex/static_root/assets/group-tab-BVlBrMwo.js.br +0 -0
- codex/static_root/assets/group-tab-BVlBrMwo.js.gz +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js +0 -1
- codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js.br +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.d29b164e80de.js.gz +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.js +0 -1
- codex/static_root/assets/http-error-C9-_aEBF.js.br +0 -0
- codex/static_root/assets/http-error-C9-_aEBF.js.gz +0 -0
- codex/static_root/assets/index-9nBCksDQ.4561d2608773.js.br +0 -0
- codex/static_root/assets/index-9nBCksDQ.4561d2608773.js.gz +0 -0
- codex/static_root/assets/index-9nBCksDQ.js.br +0 -0
- codex/static_root/assets/index-9nBCksDQ.js.gz +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js +0 -1
- codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js.br +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.22b6e123ecfb.js.gz +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.js +0 -1
- codex/static_root/assets/library-tab-BMe3dKzy.js.br +0 -0
- codex/static_root/assets/library-tab-BMe3dKzy.js.gz +0 -0
- codex/static_root/assets/main-BbNUiWEb.565b616eb122.js +0 -35
- codex/static_root/assets/main-BbNUiWEb.565b616eb122.js.br +0 -0
- codex/static_root/assets/main-BbNUiWEb.565b616eb122.js.gz +0 -0
- codex/static_root/assets/main-BbNUiWEb.js +0 -35
- codex/static_root/assets/main-BbNUiWEb.js.br +0 -0
- codex/static_root/assets/main-BbNUiWEb.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js +0 -1
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.6d4ec47c14f7.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.js +0 -1
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-JwAUlsNI.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.ba0e8b645dfa.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dx5JwWG-.js.gz +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.10d1e16abc78.js.br +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.10d1e16abc78.js.gz +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.js.br +0 -0
- codex/static_root/assets/pdf-doc-6ZE_HmLT.js.gz +0 -0
- codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js +0 -2
- codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js.br +0 -0
- codex/static_root/assets/reader-DdPKDuh5.0c55cef1e98b.js.gz +0 -0
- codex/static_root/assets/reader-DdPKDuh5.js +0 -2
- codex/static_root/assets/reader-DdPKDuh5.js.br +0 -0
- codex/static_root/assets/reader-DdPKDuh5.js.gz +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.9f07c9eb533a.js.br +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.9f07c9eb533a.js.gz +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.js.br +0 -0
- codex/static_root/assets/relation-chips-C96hi5jm.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js +0 -2
- codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js.br +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.5639fa00b301.js.gz +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.js +0 -2
- codex/static_root/assets/settings-drawer-CqbT1rid.js.br +0 -0
- codex/static_root/assets/settings-drawer-CqbT1rid.js.gz +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.b704fa46dc88.js.br +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.b704fa46dc88.js.gz +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.js.br +0 -0
- codex/static_root/assets/stats-tab-CkT2ZGUQ.js.gz +0 -0
- codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css +0 -1
- codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css.gz +0 -0
- codex/static_root/assets/task-tab-DfdUY9Rc.css +0 -1
- codex/static_root/assets/task-tab-DfdUY9Rc.css.gz +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js +0 -1
- codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js.br +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.8c2f7bf3c4c9.js.gz +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.js +0 -1
- codex/static_root/assets/task-tab-a-DcU3Tj.js.br +0 -0
- codex/static_root/assets/task-tab-a-DcU3Tj.js.gz +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js +0 -1
- codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js.br +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.f3c4b52718d5.js.gz +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.js +0 -1
- codex/static_root/assets/unauthorized-BOl5YpL3.js.br +0 -0
- codex/static_root/assets/unauthorized-BOl5YpL3.js.gz +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js +0 -1
- codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js.br +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.aa4263a68b22.js.gz +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.js +0 -1
- codex/static_root/assets/user-tab-BBDZvD8G.js.br +0 -0
- codex/static_root/assets/user-tab-BBDZvD8G.js.gz +0 -0
- codex/static_root/manifest.225989a17f49.json.br +0 -0
- codex/static_root/manifest.225989a17f49.json.gz +0 -0
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/LICENSE +0 -0
- {codex-1.7.3a2.dist-info → codex-1.7.5.dist-info}/entry_points.txt +0 -0
codex/views/browser/browser.py
CHANGED
|
@@ -173,13 +173,13 @@ class BrowserView(BrowserTitleView):
|
|
|
173
173
|
else:
|
|
174
174
|
zero_pad = 1
|
|
175
175
|
|
|
176
|
-
# self._debug_queries(page_group_count, page_book_count, group_qs, book_qs)
|
|
176
|
+
# self._debug_queries(page_group_count, page_book_count, group_qs, book_qs) # noqa: ERA001
|
|
177
177
|
|
|
178
178
|
total_page_count = page_group_count + page_book_count
|
|
179
179
|
mtime = self._get_page_mtime()
|
|
180
180
|
return group_qs, book_qs, num_pages, total_page_count, zero_pad, mtime
|
|
181
181
|
|
|
182
|
-
def get_object(self):
|
|
182
|
+
def get_object(self):
|
|
183
183
|
"""Validate settings and get the querysets."""
|
|
184
184
|
group_qs, book_qs, num_pages, total_count, zero_pad, mtime = (
|
|
185
185
|
self._get_group_and_books()
|
codex/views/browser/choices.py
CHANGED
|
@@ -8,7 +8,7 @@ from django.db.models import QuerySet
|
|
|
8
8
|
from drf_spectacular.utils import extend_schema
|
|
9
9
|
from rest_framework.response import Response
|
|
10
10
|
|
|
11
|
-
from codex.choices import DUMMY_NULL_NAME, VUETIFY_NULL_CODE
|
|
11
|
+
from codex.choices.browser import DUMMY_NULL_NAME, VUETIFY_NULL_CODE
|
|
12
12
|
from codex.logger.logging import get_logger
|
|
13
13
|
from codex.models import (
|
|
14
14
|
Comic,
|
|
@@ -18,8 +18,6 @@ from codex.models import (
|
|
|
18
18
|
from codex.models.named import IdentifierType
|
|
19
19
|
from codex.serializers.browser.choices import (
|
|
20
20
|
BrowserChoicesFilterSerializer,
|
|
21
|
-
)
|
|
22
|
-
from codex.serializers.browser.filters import (
|
|
23
21
|
BrowserFilterChoicesSerializer,
|
|
24
22
|
)
|
|
25
23
|
from codex.serializers.browser.settings import BrowserFilterChoicesInputSerilalizer
|
|
@@ -98,7 +96,7 @@ class BrowserChoicesViewBase(BrowserFilterView):
|
|
|
98
96
|
|
|
99
97
|
return rel, model
|
|
100
98
|
|
|
101
|
-
def get_object(self) -> QuerySet:
|
|
99
|
+
def get_object(self) -> QuerySet:
|
|
102
100
|
"""Get the comic subquery use for the choices."""
|
|
103
101
|
return self.get_filtered_queryset(Comic)
|
|
104
102
|
|
|
@@ -136,12 +134,13 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
|
|
|
136
134
|
|
|
137
135
|
return count
|
|
138
136
|
|
|
139
|
-
def get_object(self) -> dict[str, Any]: # type: ignore
|
|
137
|
+
def get_object(self) -> dict[str, Any]: # type: ignore[reportIncompatibleMethodOverride]
|
|
140
138
|
"""Get choice counts."""
|
|
141
139
|
qs = super().get_object()
|
|
142
140
|
filters = self.params.get("filters", {})
|
|
143
141
|
data = {}
|
|
144
|
-
|
|
142
|
+
serializer: BrowserFilterChoicesSerializer = self.serializer_class() # type: ignore[reportOptionalCall, reportAssignmentType]
|
|
143
|
+
for field_name in serializer.get_fields():
|
|
145
144
|
if field_name == "story_arcs" and qs.model is StoryArc:
|
|
146
145
|
# don't allow filtering on story arc in story arc view.
|
|
147
146
|
continue
|
|
@@ -154,7 +153,7 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
|
|
|
154
153
|
|
|
155
154
|
try:
|
|
156
155
|
is_filter_set = bool(filters.get(field_name))
|
|
157
|
-
flag = is_filter_set or count > 1
|
|
156
|
+
flag = is_filter_set or count > 1
|
|
158
157
|
except TypeError:
|
|
159
158
|
flag = False
|
|
160
159
|
data[field_name] = flag
|
|
@@ -185,7 +184,7 @@ class BrowserChoicesView(BrowserChoicesViewBase):
|
|
|
185
184
|
field_name = self.kwargs.get("field_name", "")
|
|
186
185
|
return snakecase(field_name)
|
|
187
186
|
|
|
188
|
-
def get_object(self) -> dict[str, Any]: # type: ignore
|
|
187
|
+
def get_object(self) -> dict[str, Any]: # type: ignore[reportIncompatibleMethodOverride]
|
|
189
188
|
"""Return choices with more than one choice."""
|
|
190
189
|
qs = super().get_object()
|
|
191
190
|
field_name = self._get_field_name()
|
codex/views/browser/cover.py
CHANGED
|
@@ -52,7 +52,7 @@ class CoverView(BrowserAnnotateOrderView):
|
|
|
52
52
|
BrowserAnnotateOrderView.REPARSE_JSON_FIELDS | {"parent"}
|
|
53
53
|
)
|
|
54
54
|
|
|
55
|
-
def get_group_filter(self, group=None, pks=None, page_mtime=False):
|
|
55
|
+
def get_group_filter(self, group=None, pks=None, page_mtime=False): # noqa: FBT002
|
|
56
56
|
"""Get group filter for First Cover View."""
|
|
57
57
|
if self.params.get("dynamic_covers") or self.model in (Volume, Folder):
|
|
58
58
|
return super().get_group_filter(group=group, pks=pks, page_mtime=page_mtime)
|
|
@@ -60,7 +60,10 @@ class CoverView(BrowserAnnotateOrderView):
|
|
|
60
60
|
# First cover group filter relies on sort names to look outside the browser supplied pks
|
|
61
61
|
# For multi_groups not in the browser query.
|
|
62
62
|
pks = self.kwargs["pks"]
|
|
63
|
-
|
|
63
|
+
if not self.model:
|
|
64
|
+
qs = Comic.objects.none()
|
|
65
|
+
else:
|
|
66
|
+
qs = self.model.objects.filter(pk__in=pks)
|
|
64
67
|
sort_names = qs.values_list("sort_name", flat=True).distinct()
|
|
65
68
|
model_rel = GROUP_RELATION[self.model_group]
|
|
66
69
|
group_filter = {f"{model_rel}__sort_name__in": sort_names}
|
|
@@ -142,7 +145,7 @@ class CoverView(BrowserAnnotateOrderView):
|
|
|
142
145
|
parameters=[BrowserAnnotateOrderView.input_serializer_class],
|
|
143
146
|
responses={(200, content_type): OpenApiTypes.BINARY},
|
|
144
147
|
)
|
|
145
|
-
def get(self, *args, **kwargs):
|
|
148
|
+
def get(self, *args, **kwargs):
|
|
146
149
|
"""Get comic cover."""
|
|
147
150
|
try:
|
|
148
151
|
try:
|
codex/views/browser/download.py
CHANGED
|
@@ -54,7 +54,8 @@ class GroupDownloadView(BrowserFilterView):
|
|
|
54
54
|
filename = kwargs.get("filename")
|
|
55
55
|
if not filename:
|
|
56
56
|
pks = self.kwargs.get("pks")
|
|
57
|
-
|
|
57
|
+
name = self.model.__name__ if self.model else "No Model"
|
|
58
|
+
filename = f"{name} {pks} Comics.zip"
|
|
58
59
|
|
|
59
60
|
headers = {"Content-Length": len(zs), "Last-Modified": zs.last_modified}
|
|
60
61
|
return FileResponse(
|
|
@@ -11,7 +11,7 @@ class BrowserFilterBookmarkView(BookmarkFilterMixin, BrowserValidateView):
|
|
|
11
11
|
|
|
12
12
|
def get_bookmark_filter(self, model):
|
|
13
13
|
"""Build bookmark query."""
|
|
14
|
-
choice: str = self.params.get("filters", {}).get("bookmark", "")
|
|
14
|
+
choice: str = self.params.get("filters", {}).get("bookmark", "")
|
|
15
15
|
if choice:
|
|
16
16
|
bm_rel = self.get_bm_rel(model)
|
|
17
17
|
my_bookmark_filter = self.get_my_bookmark_filter(bm_rel)
|
|
@@ -55,5 +55,5 @@ class ComicFieldFilterView(GroupFilterView):
|
|
|
55
55
|
def get_comic_field_filter(self, model):
|
|
56
56
|
"""Filter the comics based on the form filters."""
|
|
57
57
|
rel_prefix = self.get_rel_prefix(model)
|
|
58
|
-
filters = self.params["filters"]
|
|
58
|
+
filters = self.params["filters"]
|
|
59
59
|
return self.get_all_comic_field_filters(rel_prefix, filters)
|
|
@@ -13,8 +13,6 @@ LOG = get_logger(__name__)
|
|
|
13
13
|
class BrowserFilterView(BrowserFilterBookmarkView):
|
|
14
14
|
"""Browser Filters."""
|
|
15
15
|
|
|
16
|
-
TARGET = ""
|
|
17
|
-
|
|
18
16
|
def force_inner_joins(self, qs):
|
|
19
17
|
"""Force INNER JOINS to filter empty groups."""
|
|
20
18
|
demote_tables = {"codex_library"}
|
|
@@ -28,10 +26,10 @@ class BrowserFilterView(BrowserFilterBookmarkView):
|
|
|
28
26
|
def _get_query_filters(
|
|
29
27
|
self,
|
|
30
28
|
model,
|
|
29
|
+
page_mtime,
|
|
30
|
+
bookmark_filter,
|
|
31
31
|
group=None,
|
|
32
32
|
pks=None,
|
|
33
|
-
page_mtime=False,
|
|
34
|
-
bookmark_filter=True,
|
|
35
33
|
) -> Q:
|
|
36
34
|
"""Return all the filters except the group filter."""
|
|
37
35
|
big_include_filter = Q()
|
|
@@ -54,16 +52,16 @@ class BrowserFilterView(BrowserFilterBookmarkView):
|
|
|
54
52
|
model,
|
|
55
53
|
group=None,
|
|
56
54
|
pks=None,
|
|
57
|
-
page_mtime=False,
|
|
58
|
-
bookmark_filter=True,
|
|
55
|
+
page_mtime=False, # noqa: FBT002
|
|
56
|
+
bookmark_filter=True, # noqa: FBT002
|
|
59
57
|
) -> QuerySet:
|
|
60
58
|
"""Get a filtered queryset for the model."""
|
|
61
59
|
query_filters = self._get_query_filters(
|
|
62
60
|
model,
|
|
63
|
-
group=group,
|
|
64
|
-
pks=pks,
|
|
65
61
|
page_mtime=page_mtime,
|
|
66
62
|
bookmark_filter=bookmark_filter,
|
|
63
|
+
group=group,
|
|
64
|
+
pks=pks,
|
|
67
65
|
)
|
|
68
66
|
# Distinct necissary for folder view with search
|
|
69
67
|
return model.objects.filter(query_filters).distinct()
|
|
@@ -9,7 +9,7 @@ from codex.views.const import (
|
|
|
9
9
|
GROUP_RELATION,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
_GROUP_REL_TARGETS = frozenset({"cover", "choices"})
|
|
12
|
+
_GROUP_REL_TARGETS = frozenset({"cover", "choices", "bookmark"})
|
|
13
13
|
_PK_REL_TARGETS = frozenset({"metadata", "mtime"})
|
|
14
14
|
|
|
15
15
|
|
|
@@ -18,16 +18,16 @@ class GroupFilterView(BrowserParamsView):
|
|
|
18
18
|
|
|
19
19
|
SESSION_KEY = BrowserParamsView.BROWSER_SESSION_KEY
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
TARGET = ""
|
|
22
|
+
|
|
23
|
+
def _get_rel_for_pks(self, group, page_mtime: bool):
|
|
22
24
|
"""Get the relation from the model to the pks."""
|
|
23
|
-
|
|
24
|
-
target: str = self.TARGET # type: ignore
|
|
25
|
-
if target in _GROUP_REL_TARGETS:
|
|
25
|
+
if self.TARGET in _GROUP_REL_TARGETS:
|
|
26
26
|
rel = FILTER_ONLY_GROUP_RELATION[group]
|
|
27
|
-
elif
|
|
27
|
+
elif self.TARGET in _PK_REL_TARGETS or page_mtime:
|
|
28
28
|
# metadata, mtime, browser.page_mtime
|
|
29
29
|
rel = "pk"
|
|
30
|
-
elif
|
|
30
|
+
elif self.TARGET == "download":
|
|
31
31
|
rel = "comic__folders" if group == "f" else "pk"
|
|
32
32
|
else:
|
|
33
33
|
# browser.group, opds
|
|
@@ -36,7 +36,7 @@ class GroupFilterView(BrowserParamsView):
|
|
|
36
36
|
rel += "__in"
|
|
37
37
|
return rel
|
|
38
38
|
|
|
39
|
-
def get_group_filter(self, group=None, pks=None, page_mtime=False):
|
|
39
|
+
def get_group_filter(self, group=None, pks=None, page_mtime=False): # noqa: FBT002
|
|
40
40
|
"""Get filter for the displayed group."""
|
|
41
41
|
if group is None:
|
|
42
42
|
group = self.kwargs["group"]
|
|
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
|
|
22
22
|
from pyparsing.helpers import InfixNotationOperatorSpec
|
|
23
23
|
|
|
24
24
|
_QUOTES_REXP = r"(?:\".*?\")"
|
|
25
|
-
_OPERATORS_REXP = "
|
|
25
|
+
_OPERATORS_REXP = "and not|or not|and|or"
|
|
26
26
|
_BEGIN_NOT_REXP = r"^\s*\(?\s*(?P<not>not)"
|
|
27
27
|
_IMPLICIT_AND_REXP = (
|
|
28
28
|
rf"{_QUOTES_REXP}|\ (?P<ok>{_OPERATORS_REXP})\ |(?P<bare>(?:\ not)?\ )\S"
|
|
@@ -183,5 +183,5 @@ def get_field_query(rel, rel_class, exp, model, many_to_many):
|
|
|
183
183
|
bool_expr = _create_context_expression(context)
|
|
184
184
|
|
|
185
185
|
parsed_result = bool_expr.parse_string(exp)
|
|
186
|
-
root_bool_operand: BoolOperand = parsed_result[0] # type:ignore
|
|
186
|
+
root_bool_operand: BoolOperand = parsed_result[0] # type:ignore[reportAssignmentType]
|
|
187
187
|
return root_bool_operand.to_query()
|
|
@@ -149,7 +149,7 @@ class SearchFilterView(BrowserFTSFilter):
|
|
|
149
149
|
|
|
150
150
|
def _preparse_search_query(self):
|
|
151
151
|
"""Preparse search fields out of query text."""
|
|
152
|
-
text = self.params.get("q")
|
|
152
|
+
text = self.params.get("q")
|
|
153
153
|
field_tokens = {}
|
|
154
154
|
if not text:
|
|
155
155
|
return field_tokens, text
|
|
@@ -177,7 +177,7 @@ class SearchFilterView(BrowserFTSFilter):
|
|
|
177
177
|
)
|
|
178
178
|
else:
|
|
179
179
|
# AND and OR
|
|
180
|
-
#
|
|
180
|
+
# Cannot do OR queries with MATCH, it decontextualizes MATCH somehow.
|
|
181
181
|
if preop == "or":
|
|
182
182
|
self.search_error = "OR preceding column tokens with operator expressions will act as AND"
|
|
183
183
|
include_q_list, exclude_q_list = self.get_search_field_filters(
|
|
@@ -227,24 +227,9 @@ class SearchFilterView(BrowserFTSFilter):
|
|
|
227
227
|
|
|
228
228
|
return include_q, exclude_q, fts_q
|
|
229
229
|
|
|
230
|
-
def _is_search_results_limited(self) -> bool:
|
|
231
|
-
"""Get search result limit from params."""
|
|
232
|
-
# user = self.request.user # type: ignore
|
|
233
|
-
# if user and user.is_authenticated:
|
|
234
|
-
# limited = bool(
|
|
235
|
-
# self.params.get( # type: ignore
|
|
236
|
-
# "search_results_limit",
|
|
237
|
-
# MAX_OBJ_PER_PAGE,
|
|
238
|
-
# )
|
|
239
|
-
# )
|
|
240
|
-
# else:
|
|
241
|
-
# limited = True
|
|
242
|
-
# return limited
|
|
243
|
-
return True
|
|
244
|
-
|
|
245
230
|
def get_search_limit(self):
|
|
246
231
|
"""Get search scores for choices and metadata."""
|
|
247
|
-
if not self.search_mode
|
|
232
|
+
if not self.search_mode:
|
|
248
233
|
return 0
|
|
249
|
-
page = self.kwargs.get("page", 1)
|
|
234
|
+
page = self.kwargs.get("page", 1)
|
|
250
235
|
return page * MAX_OBJ_PER_PAGE + 1
|
|
@@ -54,7 +54,7 @@ class BrowserGroupMtimeView(BrowserFilterView):
|
|
|
54
54
|
args["distinct"] = True
|
|
55
55
|
return agg_func(bmua_rel, **args)
|
|
56
56
|
|
|
57
|
-
def get_group_mtime(self, model, group=None, pks=None, page_mtime=False):
|
|
57
|
+
def get_group_mtime(self, model, group=None, pks=None, page_mtime=False): # noqa: FBT002
|
|
58
58
|
"""Get a filtered mtime for browser pages and mtime checker."""
|
|
59
59
|
qs = self.get_filtered_queryset(
|
|
60
60
|
model,
|
|
@@ -47,7 +47,7 @@ class MetadataCopyIntersectionsView(MetadataQueryIntersectionsView):
|
|
|
47
47
|
@classmethod
|
|
48
48
|
def _copy_m2m_intersections(cls, obj, m2m_intersections):
|
|
49
49
|
"""Copy the m2m intersections into the object."""
|
|
50
|
-
#
|
|
50
|
+
# It might even be faster to copy everything to a dict and not use the obj.
|
|
51
51
|
for key, qs in m2m_intersections.items():
|
|
52
52
|
serializer_key = (
|
|
53
53
|
f"{PREFETCH_PREFIX}{key}"
|
|
@@ -63,7 +63,7 @@ class MetadataView(MetadataCopyIntersectionsView):
|
|
|
63
63
|
obj = qs[0]
|
|
64
64
|
if not obj:
|
|
65
65
|
reason = "Empty obj"
|
|
66
|
-
raise ValueError(reason) # noqa TRY301
|
|
66
|
+
raise ValueError(reason) # noqa: TRY301
|
|
67
67
|
except (IndexError, ValueError) as exc:
|
|
68
68
|
return self._raise_not_found(exc)
|
|
69
69
|
|
codex/views/browser/mtime.py
CHANGED
|
@@ -37,7 +37,7 @@ class MtimeView(BrowserGroupMtimeView):
|
|
|
37
37
|
"""Get max mtime for all groups."""
|
|
38
38
|
max_mtime = None
|
|
39
39
|
|
|
40
|
-
for item in self.params["groups"]:
|
|
40
|
+
for item in self.params["groups"]:
|
|
41
41
|
mtime = self._get_group_mtime(item)
|
|
42
42
|
max_mtime = max_none(max_mtime, mtime)
|
|
43
43
|
return max_mtime
|
codex/views/browser/order_by.py
CHANGED
|
@@ -55,7 +55,7 @@ class BrowserOrderByView(BrowserGroupMtimeView):
|
|
|
55
55
|
order_fields_head += ["bookmark_updated_at"]
|
|
56
56
|
return order_fields_head
|
|
57
57
|
|
|
58
|
-
def add_order_by(self, qs, order_key="",
|
|
58
|
+
def add_order_by(self, qs, order_key="", comic_sort_names=None):
|
|
59
59
|
"""Create the order_by list."""
|
|
60
60
|
order_fields_head = ()
|
|
61
61
|
if qs.model is Comic:
|
|
@@ -65,11 +65,9 @@ class BrowserOrderByView(BrowserGroupMtimeView):
|
|
|
65
65
|
|
|
66
66
|
order_fields = (*order_fields_head, "pk")
|
|
67
67
|
|
|
68
|
-
prefix = "-" if
|
|
69
|
-
order_by = []
|
|
68
|
+
prefix = "-" if self.params.get("order_reverse") else ""
|
|
70
69
|
if prefix:
|
|
71
|
-
for field in order_fields
|
|
72
|
-
order_by.append(prefix + field)
|
|
70
|
+
order_by = [prefix + field for field in order_fields]
|
|
73
71
|
else:
|
|
74
72
|
order_by = order_fields
|
|
75
73
|
|
codex/views/browser/params.py
CHANGED
|
@@ -58,7 +58,7 @@ class BrowserParamsView(SessionView):
|
|
|
58
58
|
validated_data = serializer.validated_data
|
|
59
59
|
|
|
60
60
|
if validated_data:
|
|
61
|
-
params.update(validated_data)
|
|
61
|
+
params.update(validated_data)
|
|
62
62
|
self._params = MappingProxyType(params)
|
|
63
63
|
self.validate_settings()
|
|
64
64
|
return self._params
|
codex/views/browser/settings.py
CHANGED
|
@@ -9,7 +9,7 @@ class BrowserSettingsView(SettingsView):
|
|
|
9
9
|
"""Get Browser Settings."""
|
|
10
10
|
|
|
11
11
|
# Put Browser Settings is normally done through BrowserView.get()
|
|
12
|
-
serializer_class = BrowserSettingsSerializer
|
|
12
|
+
serializer_class = BrowserSettingsSerializer
|
|
13
13
|
|
|
14
14
|
SESSION_KEY = SettingsView.BROWSER_SESSION_KEY
|
|
15
15
|
|
codex/views/browser/validate.py
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
from collections.abc import Mapping
|
|
4
4
|
from copy import deepcopy
|
|
5
5
|
from types import MappingProxyType
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from rest_framework.exceptions import NotFound
|
|
8
9
|
|
|
9
|
-
from codex.choices import DEFAULT_BROWSER_ROUTE
|
|
10
|
+
from codex.choices.browser import DEFAULT_BROWSER_ROUTE
|
|
10
11
|
from codex.exceptions import SeeOtherRedirectError
|
|
11
12
|
from codex.logger.logging import get_logger
|
|
12
13
|
from codex.models.groups import BrowserGroupModel
|
|
@@ -73,17 +74,18 @@ class BrowserValidateView(SearchFilterView):
|
|
|
73
74
|
self, reason, route_mask=None, settings_mask: Mapping | None = None
|
|
74
75
|
):
|
|
75
76
|
"""Redirect the client to a valid group url."""
|
|
76
|
-
route = mapping_to_dict(self.DEFAULT_ROUTE)
|
|
77
|
+
route: dict[str, Any] = mapping_to_dict(self.DEFAULT_ROUTE) # type:ignore[reportAssignmentType]
|
|
77
78
|
if route_mask:
|
|
78
|
-
route["params"].update(route_mask)
|
|
79
|
-
settings: dict = deepcopy(mapping_to_dict(self.params)) # type: ignore
|
|
79
|
+
route["params"].update(route_mask)
|
|
80
|
+
settings: dict[str, Any] = deepcopy(mapping_to_dict(self.params)) # type: ignore[reportAssignmentType]
|
|
80
81
|
if settings_mask:
|
|
81
82
|
settings.update(settings_mask)
|
|
82
83
|
detail = {"route": route, "settings": settings, "reason": reason}
|
|
83
84
|
raise SeeOtherRedirectError(detail=detail)
|
|
84
85
|
|
|
85
86
|
def _get_valid_browse_top_groups(self):
|
|
86
|
-
"""
|
|
87
|
+
"""
|
|
88
|
+
Get valid top groups for the current settings.
|
|
87
89
|
|
|
88
90
|
Valid top groups are determined by the Browser Settings.
|
|
89
91
|
"""
|
|
@@ -118,7 +120,8 @@ class BrowserValidateView(SearchFilterView):
|
|
|
118
120
|
self.raise_redirect(reason, route, settings_mask)
|
|
119
121
|
|
|
120
122
|
def _get_valid_browse_nav_groups(self, valid_top_groups):
|
|
121
|
-
"""
|
|
123
|
+
"""
|
|
124
|
+
Get valid nav groups for the current settings.
|
|
122
125
|
|
|
123
126
|
Valid nav groups are the top group and below that are also
|
|
124
127
|
enabled in browser settings.
|
codex/views/const.py
CHANGED
|
@@ -76,9 +76,6 @@ METADATA_GROUP_RELATION = MappingProxyType(
|
|
|
76
76
|
{
|
|
77
77
|
**GROUP_NAME_MAP,
|
|
78
78
|
COMIC_GROUP: "comic",
|
|
79
|
-
# Possible to list all groups in a non group view, but could get crazy.
|
|
80
|
-
# FOLDER_GROUP: "comic__folder",
|
|
81
|
-
# STORY_ARC_GROUP: "comic__story_arc_number__story_arc"
|
|
82
79
|
}
|
|
83
80
|
)
|
|
84
81
|
CUSTOM_COVER_GROUP_RELATION = MappingProxyType(
|
codex/views/frontend.py
CHANGED
|
@@ -17,7 +17,7 @@ class IndexView(SessionView):
|
|
|
17
17
|
SESSION_KEY = SessionView.BROWSER_SESSION_KEY
|
|
18
18
|
|
|
19
19
|
permission_classes = (AllowAny,)
|
|
20
|
-
renderer_classes: ClassVar[list] = [TemplateHTMLRenderer] # type: ignore
|
|
20
|
+
renderer_classes: ClassVar[list] = [TemplateHTMLRenderer] # type: ignore[reportIncompatibleVariableOverride]
|
|
21
21
|
template_name = "index.html"
|
|
22
22
|
|
|
23
23
|
def _get_last_route(self):
|
codex/views/mixins.py
CHANGED
|
@@ -4,6 +4,7 @@ from django.db.models.expressions import F
|
|
|
4
4
|
|
|
5
5
|
from codex.logger.logging import get_logger
|
|
6
6
|
from codex.models.comic import Comic, Imprint, Volume
|
|
7
|
+
from codex.views.browser.filters.filter import BrowserFilterView
|
|
7
8
|
from codex.views.const import GROUP_NAME_MAP
|
|
8
9
|
|
|
9
10
|
LOG = get_logger(__name__)
|
|
@@ -12,7 +13,7 @@ _GROUP_NAME_TARGETS = frozenset({"browser", "opds1", "opds2", "reader"})
|
|
|
12
13
|
_VARIABLE_SHOW = "pi"
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class SharedAnnotationsMixin:
|
|
16
|
+
class SharedAnnotationsMixin(BrowserFilterView):
|
|
16
17
|
"""Cross view annotation methods."""
|
|
17
18
|
|
|
18
19
|
@staticmethod
|
|
@@ -54,7 +55,7 @@ class SharedAnnotationsMixin:
|
|
|
54
55
|
def annotate_group_names(cls, qs):
|
|
55
56
|
"""Annotate name fields by hoisting them up."""
|
|
56
57
|
# Optimized to only lookup what is used on the frontend
|
|
57
|
-
target = cls.TARGET
|
|
58
|
+
target = cls.TARGET
|
|
58
59
|
if target not in _GROUP_NAME_TARGETS:
|
|
59
60
|
return qs
|
|
60
61
|
group_names = {}
|
codex/views/opds/const.py
CHANGED
|
@@ -48,9 +48,9 @@ class MimeType:
|
|
|
48
48
|
|
|
49
49
|
ATOM = "application/atom+xml"
|
|
50
50
|
_PROFILE_CATALOG = "profile=opds-catalog"
|
|
51
|
-
NAV = ";
|
|
52
|
-
ACQUISITION = ";
|
|
53
|
-
ENTRY_CATALOG = ";
|
|
51
|
+
NAV = f"{ATOM};{_PROFILE_CATALOG};kind=navigation"
|
|
52
|
+
ACQUISITION = f"{ATOM};{_PROFILE_CATALOG};kind=acquisition"
|
|
53
|
+
ENTRY_CATALOG = f"{ATOM};type=entry;{_PROFILE_CATALOG}"
|
|
54
54
|
AUTHENTICATION = "application/opds-authentication+json"
|
|
55
55
|
OPENSEARCH = "application/opensearchdescription+xml"
|
|
56
56
|
STREAM = "image/jpeg"
|
|
@@ -58,7 +58,7 @@ class MimeType:
|
|
|
58
58
|
OPDS_PUB = "application/opds-publication+json"
|
|
59
59
|
PROGRESSION = "application/vnd.readium.progression+json"
|
|
60
60
|
BOOK = "http://schema.org/Book"
|
|
61
|
-
# COMIC = "https://schema.org/ComicStory"
|
|
61
|
+
# COMIC = "https://schema.org/ComicStory" unused
|
|
62
62
|
JPEG = "image/jpeg"
|
|
63
63
|
WEBP = "image/webp"
|
|
64
64
|
HTML = "text/html"
|
codex/views/opds/urls.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from django.urls import reverse
|
|
4
4
|
from rest_framework.response import Response
|
|
5
5
|
|
|
6
|
-
from codex.choices import DEFAULT_BROWSER_ROUTE
|
|
6
|
+
from codex.choices.browser import DEFAULT_BROWSER_ROUTE
|
|
7
7
|
from codex.serializers.opds.urls import OPDSURLsSerializer
|
|
8
8
|
from codex.views.auth import AuthGenericAPIView
|
|
9
9
|
from codex.views.util import pop_name
|
codex/views/opds/util.py
CHANGED
|
@@ -5,7 +5,7 @@ from django.http.response import HttpResponseRedirect
|
|
|
5
5
|
from django.urls import reverse
|
|
6
6
|
from django.utils.http import urlencode
|
|
7
7
|
|
|
8
|
-
from codex.choices import DEFAULT_BROWSER_ROUTE
|
|
8
|
+
from codex.choices.browser import DEFAULT_BROWSER_ROUTE
|
|
9
9
|
from codex.models import (
|
|
10
10
|
Contributor,
|
|
11
11
|
ContributorPerson,
|
|
@@ -31,7 +31,7 @@ def update_href_query_params(href, old_query_params, new_query_params=None):
|
|
|
31
31
|
return href
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def get_contributor_people(comic_pks, roles, exclude
|
|
34
|
+
def get_contributor_people(comic_pks, roles, exclude):
|
|
35
35
|
"""Get contributors that are not authors."""
|
|
36
36
|
people = ContributorPerson.objects.filter(
|
|
37
37
|
contributor__comic__in=comic_pks,
|
|
@@ -43,7 +43,7 @@ def get_contributor_people(comic_pks, roles, exclude=False):
|
|
|
43
43
|
return people.distinct().only("name")
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def get_contributors(comic_pks, roles, exclude
|
|
46
|
+
def get_contributors(comic_pks, roles, exclude):
|
|
47
47
|
"""Get credits that are not part of other roles."""
|
|
48
48
|
contributors = Contributor.objects.filter(comic__in=comic_pks)
|
|
49
49
|
if exclude:
|
|
@@ -78,7 +78,7 @@ def full_redirect_view(url_name):
|
|
|
78
78
|
path = request.get_full_path()
|
|
79
79
|
if path:
|
|
80
80
|
parts = path.split("?")
|
|
81
|
-
if len(parts) >= 2: # noqa PLR2004
|
|
81
|
+
if len(parts) >= 2: # noqa: PLR2004
|
|
82
82
|
parts[0] = url
|
|
83
83
|
url = "?".join(parts)
|
|
84
84
|
|
|
@@ -47,8 +47,10 @@ class OPDS1Entry(OPDS1EntryLinksMixin):
|
|
|
47
47
|
elif group == "c":
|
|
48
48
|
title = Comic.get_title(
|
|
49
49
|
self.obj,
|
|
50
|
-
|
|
50
|
+
volume=True,
|
|
51
|
+
name=True,
|
|
51
52
|
filename_fallback=self.title_filename_fallback,
|
|
53
|
+
zero_pad=self.zero_pad,
|
|
52
54
|
)
|
|
53
55
|
parts.append(title)
|
|
54
56
|
|
|
@@ -133,7 +135,7 @@ class OPDS1Entry(OPDS1EntryLinksMixin):
|
|
|
133
135
|
"""Get Author names."""
|
|
134
136
|
if not self.metadata:
|
|
135
137
|
return []
|
|
136
|
-
people = get_contributor_people(self.obj.ids, AUTHOR_ROLES)
|
|
138
|
+
people = get_contributor_people(self.obj.ids, AUTHOR_ROLES, exclude=False)
|
|
137
139
|
return self._add_url_to_obj(people, "contributors")
|
|
138
140
|
|
|
139
141
|
@property
|
|
@@ -20,7 +20,7 @@ class OPDS1EntryLinksMixin:
|
|
|
20
20
|
"""OPDS v1 Entry Links Methods."""
|
|
21
21
|
|
|
22
22
|
def __init__(
|
|
23
|
-
self, obj, query_params, data: OPDS1EntryData, title_filename_fallback
|
|
23
|
+
self, obj, query_params, data: OPDS1EntryData, title_filename_fallback: bool
|
|
24
24
|
):
|
|
25
25
|
"""Initialize params."""
|
|
26
26
|
self.obj = obj
|
|
@@ -35,7 +35,6 @@ class OPDS1EntryLinksMixin:
|
|
|
35
35
|
def _cover_link(self, rel):
|
|
36
36
|
if self.fake:
|
|
37
37
|
return None
|
|
38
|
-
# cover_pk = getattr(self.obj, "cover_pk", None)
|
|
39
38
|
try:
|
|
40
39
|
kwargs = {"group": self.obj.group, "pks": self.obj.ids}
|
|
41
40
|
ts = floor(datetime.timestamp(self.obj.updated_at))
|
|
@@ -50,7 +49,7 @@ class OPDS1EntryLinksMixin:
|
|
|
50
49
|
except Exception:
|
|
51
50
|
LOG.exception("create thumb")
|
|
52
51
|
|
|
53
|
-
def _nav_href(self, metadata
|
|
52
|
+
def _nav_href(self, metadata: bool):
|
|
54
53
|
try:
|
|
55
54
|
pks = sorted(self.obj.ids)
|
|
56
55
|
kwargs = {"group": self.obj.group, "pks": pks, "page": 1}
|
|
@@ -72,7 +71,7 @@ class OPDS1EntryLinksMixin:
|
|
|
72
71
|
LOG.exception(msg)
|
|
73
72
|
raise
|
|
74
73
|
|
|
75
|
-
def _nav_link(self, metadata
|
|
74
|
+
def _nav_link(self, metadata: bool):
|
|
76
75
|
href = self._nav_href(metadata)
|
|
77
76
|
|
|
78
77
|
group = self.obj.group
|
|
@@ -154,7 +153,7 @@ class OPDS1EntryLinksMixin:
|
|
|
154
153
|
|
|
155
154
|
if self.obj.group == "c" and not self.fake:
|
|
156
155
|
result += self._links_comic()
|
|
157
|
-
elif nav := self._nav_link():
|
|
156
|
+
elif nav := self._nav_link(metadata=False):
|
|
158
157
|
result += [nav]
|
|
159
158
|
|
|
160
159
|
except Exception:
|
codex/views/opds/v1/facets.py
CHANGED
|
@@ -169,11 +169,14 @@ class OPDS1FacetsView(BrowserView):
|
|
|
169
169
|
)
|
|
170
170
|
qps = {**self.request.GET}
|
|
171
171
|
qps.update(query_params)
|
|
172
|
-
zero_pad: int = self.obj["zero_pad"]
|
|
172
|
+
zero_pad: int = self.obj["zero_pad"]
|
|
173
173
|
data = OPDS1EntryData(
|
|
174
|
-
self.opds_acquisition_groups,
|
|
174
|
+
self.opds_acquisition_groups,
|
|
175
|
+
zero_pad,
|
|
176
|
+
metadata=False,
|
|
177
|
+
mime_type_map=self.mime_type_map,
|
|
175
178
|
)
|
|
176
|
-
return OPDS1Entry(entry_obj, qps, data)
|
|
179
|
+
return OPDS1Entry(entry_obj, qps, data, title_filename_fallback=False)
|
|
177
180
|
|
|
178
181
|
def _is_facet_active(self, facet_group, facet):
|
|
179
182
|
compare = [facet.value]
|
|
@@ -231,7 +234,8 @@ class OPDS1FacetsView(BrowserView):
|
|
|
231
234
|
facets += [facet_obj]
|
|
232
235
|
return facets
|
|
233
236
|
|
|
234
|
-
def facets(self, entries
|
|
237
|
+
def facets(self, entries: bool, root: bool):
|
|
238
|
+
# entries false, root true
|
|
235
239
|
"""Return facets."""
|
|
236
240
|
facets = []
|
|
237
241
|
group = self.kwargs.get("group")
|