codex 1.6.0a7__py3-none-any.whl → 1.6.0a9__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/integrity.py +5 -6
- codex/librarian/importer/{aggregate_metadata.py → aggregate.py} +54 -76
- codex/librarian/importer/cache.py +162 -29
- codex/librarian/importer/const.py +15 -6
- codex/librarian/importer/create_comics.py +101 -17
- codex/librarian/importer/create_covers.py +96 -0
- codex/librarian/importer/create_fks.py +73 -170
- codex/librarian/importer/deleted.py +59 -46
- codex/librarian/importer/{clean_metadata.py → extract.py} +33 -4
- codex/librarian/importer/failed_imports.py +42 -64
- codex/librarian/importer/importer.py +96 -0
- codex/librarian/importer/importerd.py +71 -397
- codex/librarian/importer/init.py +265 -0
- codex/librarian/importer/link_comics.py +26 -81
- codex/librarian/importer/link_covers.py +73 -0
- codex/librarian/importer/moved.py +76 -104
- codex/librarian/importer/query_covers.py +52 -0
- codex/librarian/importer/query_fks.py +128 -172
- codex/librarian/importer/status.py +2 -39
- codex/librarian/importer/tasks.py +22 -13
- codex/librarian/janitor/cleanup.py +2 -2
- codex/librarian/janitor/janitor.py +10 -0
- codex/librarian/librariand.py +7 -1
- codex/migrations/0027_import_order_and_covers.py +345 -0
- codex/models/comic.py +1 -2
- codex/models/groups.py +3 -2
- codex/models/paths.py +0 -1
- codex/search/query.py +25 -2
- codex/search/writing.py +1 -1
- codex/serializers/browser/mixins.py +0 -18
- codex/serializers/browser/mtime.py +21 -0
- codex/serializers/browser/settings.py +2 -3
- codex/serializers/choices.py +10 -1
- codex/serializers/fields.py +8 -9
- codex/serializers/reader.py +5 -5
- codex/serializers/route.py +9 -4
- codex/settings/settings.py +2 -2
- codex/static_root/assets/{VCheckbox-BOUtyxuo.c690f0cdbe48.js → VCheckbox-eNspVUje.da8282a08876.js} +1 -1
- codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js.br +0 -0
- codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-BOUtyxuo.js → VCheckbox-eNspVUje.js} +1 -1
- codex/static_root/assets/VCheckbox-eNspVUje.js.br +0 -0
- codex/static_root/assets/VCheckbox-eNspVUje.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js → VCheckboxBtn-DLzF_WHB.9a47873b8548.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.9a47873b8548.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.9a47873b8548.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-B1-m5pEh.js → VCheckboxBtn-DLzF_WHB.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-DLzF_WHB.js.gz +0 -0
- codex/static_root/assets/{VCombobox-DjkDXe33.22617ea193b1.js → VCombobox-BIO7lU_B.d607ada71b06.js} +1 -1
- codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js.br +0 -0
- codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js.gz +0 -0
- codex/static_root/assets/{VCombobox-DjkDXe33.js → VCombobox-BIO7lU_B.js} +1 -1
- codex/static_root/assets/VCombobox-BIO7lU_B.js.br +0 -0
- codex/static_root/assets/VCombobox-BIO7lU_B.js.gz +0 -0
- codex/static_root/assets/{VDialog-X0zn9AGX.0d89c749b9a6.js → VDialog-87AymJC5.4a46716358c0.js} +1 -1
- codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js.br +0 -0
- codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js.gz +0 -0
- codex/static_root/assets/{VDialog-X0zn9AGX.js → VDialog-87AymJC5.js} +1 -1
- codex/static_root/assets/VDialog-87AymJC5.js.br +0 -0
- codex/static_root/assets/VDialog-87AymJC5.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-CRevojaF.43d65c777c58.js → VExpansionPanels-CgA3shsd.9e524c73726a.js} +1 -1
- codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-CRevojaF.js → VExpansionPanels-CgA3shsd.js} +1 -1
- codex/static_root/assets/VExpansionPanels-CgA3shsd.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CgA3shsd.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-8nrrxjDv.2b4dfb984a8c.js → VRadioGroup-B--7K_v5.4a4e9c2d6c42.js} +1 -1
- codex/static_root/assets/VRadioGroup-B--7K_v5.4a4e9c2d6c42.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B--7K_v5.4a4e9c2d6c42.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-8nrrxjDv.js → VRadioGroup-B--7K_v5.js} +1 -1
- codex/static_root/assets/VRadioGroup-B--7K_v5.js.br +0 -0
- codex/static_root/assets/VRadioGroup-B--7K_v5.js.gz +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css +1 -0
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.br +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.gz +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.css +1 -0
- codex/static_root/assets/VSelect-ARDhJiQK.css.br +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.css.gz +0 -0
- codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js +1 -0
- codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js.br +0 -0
- codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js.gz +0 -0
- codex/static_root/assets/VSelect-BoJq222l.js +1 -0
- codex/static_root/assets/VSelect-BoJq222l.js.br +0 -0
- codex/static_root/assets/VSelect-BoJq222l.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-CGu0oz0K.3030b7a270d6.js → VSelectionControl-CVQ9wkE2.c02186cceba6.js} +1 -1
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.c02186cceba6.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.c02186cceba6.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-CGu0oz0K.js → VSelectionControl-CVQ9wkE2.js} +1 -1
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CVQ9wkE2.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-D_oNvCOd.71a7101cdddd.js → VSlideGroup-Ce0j2BKK.85e64443a928.js} +1 -1
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js.br +0 -0
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-D_oNvCOd.js → VSlideGroup-Ce0j2BKK.js} +1 -1
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.js.br +0 -0
- codex/static_root/assets/VSlideGroup-Ce0j2BKK.js.gz +0 -0
- codex/static_root/assets/{VTable-C7pKI7gU.087912f706f5.js → VTable-CrWkhkiP.6d530eea0c09.js} +1 -1
- codex/static_root/assets/VTable-CrWkhkiP.6d530eea0c09.js.br +0 -0
- codex/static_root/assets/VTable-CrWkhkiP.6d530eea0c09.js.gz +0 -0
- codex/static_root/assets/{VTable-C7pKI7gU.js → VTable-CrWkhkiP.js} +1 -1
- codex/static_root/assets/VTable-CrWkhkiP.js.br +0 -0
- codex/static_root/assets/VTable-CrWkhkiP.js.gz +0 -0
- codex/static_root/assets/{VTextField-Bs8oq9mk.js → VTextField-CkWbil3K.2cac13161dfe.js} +1 -1
- codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js.br +0 -0
- codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js.gz +0 -0
- codex/static_root/assets/{VTextField-Bs8oq9mk.7999fef12a03.js → VTextField-CkWbil3K.js} +1 -1
- codex/static_root/assets/VTextField-CkWbil3K.js.br +0 -0
- codex/static_root/assets/VTextField-CkWbil3K.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-iyZ1XOkP.409f7d292253.js → VWindowItem-7z55Y4lK.98eb7487e039.js} +1 -1
- codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js.br +0 -0
- codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-iyZ1XOkP.js → VWindowItem-7z55Y4lK.js} +1 -1
- codex/static_root/assets/VWindowItem-7z55Y4lK.js.br +0 -0
- codex/static_root/assets/VWindowItem-7z55Y4lK.js.gz +0 -0
- codex/static_root/assets/{admin-B0pCBjma.2407da79bd20.js → admin-D3OK784R.f69891726ec5.js} +1 -1
- codex/static_root/assets/admin-D3OK784R.f69891726ec5.js.br +0 -0
- codex/static_root/assets/admin-D3OK784R.f69891726ec5.js.gz +0 -0
- codex/static_root/assets/{admin-B0pCBjma.js → admin-D3OK784R.js} +1 -1
- codex/static_root/assets/admin-D3OK784R.js.br +0 -0
- codex/static_root/assets/admin-D3OK784R.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js → admin-drawer-panel-1pnfvY8O.5438f252970e.js} +11 -11
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-BxoNUHQr.js → admin-drawer-panel-1pnfvY8O.js} +11 -11
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js.gz +0 -0
- codex/static_root/assets/browser-BuU2x9y7.css +1 -0
- codex/static_root/assets/browser-BuU2x9y7.css.br +0 -0
- codex/static_root/assets/browser-BuU2x9y7.css.gz +0 -0
- codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css +1 -0
- codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css.br +0 -0
- codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css.gz +0 -0
- codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js +1 -0
- codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js.br +0 -0
- codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js.gz +0 -0
- codex/static_root/assets/browser-CO9EYHIr.js +1 -0
- codex/static_root/assets/browser-CO9EYHIr.js.br +0 -0
- codex/static_root/assets/browser-CO9EYHIr.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-DZ9dP8_F.930f4cae3cb0.js → change-password-dialog-CjZdzaIk.188c765431ab.js} +1 -1
- codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js.br +0 -0
- codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-DZ9dP8_F.js → change-password-dialog-CjZdzaIk.js} +1 -1
- codex/static_root/assets/change-password-dialog-CjZdzaIk.js.br +0 -0
- codex/static_root/assets/change-password-dialog-CjZdzaIk.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-RP7JNStF.a752a7c1e697.js → confirm-dialog-jwL7B98r.1cfd579cbcfe.js} +1 -1
- codex/static_root/assets/confirm-dialog-jwL7B98r.1cfd579cbcfe.js.br +0 -0
- codex/static_root/assets/confirm-dialog-jwL7B98r.1cfd579cbcfe.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-RP7JNStF.js → confirm-dialog-jwL7B98r.js} +1 -1
- codex/static_root/assets/confirm-dialog-jwL7B98r.js.br +0 -0
- codex/static_root/assets/confirm-dialog-jwL7B98r.js.gz +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js +1 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js.br +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js.gz +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.js +1 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.js.br +0 -0
- codex/static_root/assets/datetime-column-9w3GcKvo.js.gz +0 -0
- codex/static_root/assets/datetime-column-DeCthByU.1f3bf499e063.css +1 -0
- codex/static_root/assets/datetime-column-DeCthByU.css +1 -0
- codex/static_root/assets/{filter-DAdGUt-1.3261cbcd50b5.js → filter-C-pghOri.eeb7c2ecf398.js} +1 -1
- codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js.br +0 -0
- codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js.gz +0 -0
- codex/static_root/assets/{filter-DAdGUt-1.js → filter-C-pghOri.js} +1 -1
- codex/static_root/assets/filter-C-pghOri.js.br +0 -0
- codex/static_root/assets/filter-C-pghOri.js.gz +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js +1 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js.br +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js.gz +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.js +1 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.js.br +0 -0
- codex/static_root/assets/flag-tab-Da2DBNyz.js.gz +0 -0
- codex/static_root/assets/{group-tab-DEwh4jfB.a95097b5e320.js → group-tab-BONYWOc1.6ddf321a4a56.js} +1 -1
- codex/static_root/assets/group-tab-BONYWOc1.6ddf321a4a56.js.br +0 -0
- codex/static_root/assets/group-tab-BONYWOc1.6ddf321a4a56.js.gz +0 -0
- codex/static_root/assets/{group-tab-DEwh4jfB.js → group-tab-BONYWOc1.js} +1 -1
- codex/static_root/assets/group-tab-BONYWOc1.js.br +0 -0
- codex/static_root/assets/group-tab-BONYWOc1.js.gz +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js +1 -0
- codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js.br +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js.gz +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.js +1 -0
- codex/static_root/assets/http-error-D2Jnc20C.js.br +0 -0
- codex/static_root/assets/http-error-D2Jnc20C.js.gz +0 -0
- codex/static_root/assets/{library-tab-DrXvD9B2.js → library-tab-B419agXA.d4b778172aaa.js} +1 -1
- codex/static_root/assets/library-tab-B419agXA.d4b778172aaa.js.br +0 -0
- codex/static_root/assets/library-tab-B419agXA.d4b778172aaa.js.gz +0 -0
- codex/static_root/assets/{library-tab-DrXvD9B2.f765f9d3bae4.js → library-tab-B419agXA.js} +1 -1
- codex/static_root/assets/library-tab-B419agXA.js.br +0 -0
- codex/static_root/assets/library-tab-B419agXA.js.gz +0 -0
- codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js +32 -0
- codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js.br +0 -0
- codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js.gz +0 -0
- codex/static_root/assets/main-CMQwJ9aG.js +32 -0
- codex/static_root/assets/main-CMQwJ9aG.js.br +0 -0
- codex/static_root/assets/main-CMQwJ9aG.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css +1 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css +1 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js +1 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.js +1 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-LTuj5U-G.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-obrBwxa6.ec9bd13a5786.js → pdf-doc-8RVZqILx.2e7166dd26fb.js} +1 -1
- codex/static_root/assets/pdf-doc-8RVZqILx.2e7166dd26fb.js.br +0 -0
- codex/static_root/assets/pdf-doc-8RVZqILx.2e7166dd26fb.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-obrBwxa6.js → pdf-doc-8RVZqILx.js} +1 -1
- codex/static_root/assets/pdf-doc-8RVZqILx.js.br +0 -0
- codex/static_root/assets/pdf-doc-8RVZqILx.js.gz +0 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css +1 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.br +0 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.gz +0 -0
- codex/static_root/assets/reader-CCCfpM3x.css +1 -0
- codex/static_root/assets/reader-CCCfpM3x.css.br +0 -0
- codex/static_root/assets/reader-CCCfpM3x.css.gz +0 -0
- codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js +2 -0
- codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js.br +0 -0
- codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js.gz +0 -0
- codex/static_root/assets/reader-DNnK_Chr.js +2 -0
- codex/static_root/assets/reader-DNnK_Chr.js.br +0 -0
- codex/static_root/assets/reader-DNnK_Chr.js.gz +0 -0
- codex/static_root/assets/{relation-chips-CZJcLjc8.1d7426dab654.js → relation-chips-PYua7aXv.428ba0b5861e.js} +1 -1
- codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js.br +0 -0
- codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js.gz +0 -0
- codex/static_root/assets/{relation-chips-CZJcLjc8.js → relation-chips-PYua7aXv.js} +1 -1
- codex/static_root/assets/relation-chips-PYua7aXv.js.br +0 -0
- codex/static_root/assets/relation-chips-PYua7aXv.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-7iTnAdjf.337eecf2fdbb.js → settings-drawer-DbN6ISRH.d14f525d8eee.js} +2 -2
- codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-7iTnAdjf.js → settings-drawer-DbN6ISRH.js} +2 -2
- codex/static_root/assets/settings-drawer-DbN6ISRH.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbN6ISRH.js.gz +0 -0
- codex/static_root/assets/{stats-tab-CQsK1n8O.544bf50ffb22.js → stats-tab-DImNhH8O.d5026283841a.js} +1 -1
- codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js.br +0 -0
- codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js.gz +0 -0
- codex/static_root/assets/{stats-tab-CQsK1n8O.js → stats-tab-DImNhH8O.js} +1 -1
- codex/static_root/assets/stats-tab-DImNhH8O.js.br +0 -0
- codex/static_root/assets/stats-tab-DImNhH8O.js.gz +0 -0
- codex/static_root/assets/{task-tab-C60TLP6e.63aa929a4ed6.js → task-tab-DPD53kjv.e56a35ff1691.js} +1 -1
- codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js.br +0 -0
- codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js.gz +0 -0
- codex/static_root/assets/{task-tab-C60TLP6e.js → task-tab-DPD53kjv.js} +1 -1
- codex/static_root/assets/task-tab-DPD53kjv.js.br +0 -0
- codex/static_root/assets/task-tab-DPD53kjv.js.gz +0 -0
- codex/static_root/assets/to-case-ehC9Ccyj.a7b8e25b391f.js +1 -0
- codex/static_root/assets/to-case-ehC9Ccyj.js +1 -0
- codex/static_root/assets/{unauthorized-Bs7NSqea.c55650fac055.js → unauthorized-BOIx7Y18.ee3961abfccb.js} +1 -1
- codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js.br +0 -0
- codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js.gz +0 -0
- codex/static_root/assets/{unauthorized-Bs7NSqea.js → unauthorized-BOIx7Y18.js} +1 -1
- codex/static_root/assets/unauthorized-BOIx7Y18.js.br +0 -0
- codex/static_root/assets/unauthorized-BOIx7Y18.js.gz +0 -0
- codex/static_root/assets/{user-tab-ChuH7Atm.7e80cf1fb78e.js → user-tab-BABwfxLO.37dd0440fbdd.js} +1 -1
- codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js.br +0 -0
- codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js.gz +0 -0
- codex/static_root/assets/{user-tab-ChuH7Atm.js → user-tab-BABwfxLO.js} +1 -1
- codex/static_root/assets/user-tab-BABwfxLO.js.br +0 -0
- codex/static_root/assets/user-tab-BABwfxLO.js.gz +0 -0
- codex/static_root/js/choices-admin.d790df01c20a.json +1 -0
- codex/static_root/js/choices-admin.d790df01c20a.json.br +0 -0
- codex/static_root/js/choices-admin.d790df01c20a.json.gz +0 -0
- codex/static_root/js/choices-admin.json +1 -1
- codex/static_root/js/choices-admin.json.br +0 -0
- codex/static_root/js/choices-admin.json.gz +0 -0
- codex/static_root/js/{choices.079a01e0be1a.json → choices.a0aaaa6c7ef7.json} +1 -1
- codex/static_root/js/choices.a0aaaa6c7ef7.json.br +0 -0
- codex/static_root/js/choices.a0aaaa6c7ef7.json.gz +0 -0
- codex/static_root/js/choices.json +1 -1
- codex/static_root/js/choices.json.br +0 -0
- codex/static_root/js/choices.json.gz +0 -0
- codex/static_root/{manifest.dad79c8475ae.json → manifest.cbea5663003a.json} +239 -239
- codex/static_root/manifest.cbea5663003a.json.br +0 -0
- codex/static_root/manifest.cbea5663003a.json.gz +0 -0
- codex/static_root/manifest.json +239 -239
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/urls/api/browser.py +11 -2
- codex/urls/api/reader.py +1 -7
- codex/urls/api/v3.py +1 -1
- codex/urls/opds/binary.py +1 -1
- codex/views/admin/auth.py +0 -2
- codex/views/admin/tasks.py +10 -1
- codex/views/auth.py +2 -4
- codex/views/bookmark.py +44 -40
- codex/views/browser/annotations.py +38 -174
- codex/views/browser/base.py +6 -22
- codex/views/browser/breadcrumbs.py +16 -14
- codex/views/browser/browser.py +11 -20
- codex/views/browser/choices.py +15 -39
- codex/views/browser/cover.py +177 -0
- codex/views/browser/filters/annotations.py +63 -18
- codex/views/browser/filters/bookmark.py +21 -5
- codex/views/browser/filters/field.py +1 -2
- codex/views/browser/filters/group.py +19 -11
- codex/views/browser/filters/search.py +19 -10
- codex/views/browser/metadata.py +20 -25
- codex/views/browser/mtime.py +72 -0
- codex/views/const.py +20 -0
- codex/views/opds/binary.py +1 -1
- codex/views/opds/urls.py +2 -1
- codex/views/opds/util.py +2 -4
- codex/views/opds/v1/entry/links.py +18 -33
- codex/views/opds/v1/facets.py +2 -1
- codex/views/opds/v1/feed.py +42 -23
- codex/views/opds/v1/links.py +2 -1
- codex/views/opds/v2/feed.py +11 -9
- codex/views/opds/v2/links.py +2 -1
- codex/views/opds/v2/publications.py +13 -34
- codex/views/public.py +0 -2
- codex/views/reader/books.py +7 -9
- codex/views/reader/reader.py +25 -22
- codex/views/session.py +5 -3
- codex/views/util.py +32 -0
- {codex-1.6.0a7.dist-info → codex-1.6.0a9.dist-info}/METADATA +8 -7
- {codex-1.6.0a7.dist-info → codex-1.6.0a9.dist-info}/RECORD +324 -325
- codex/librarian/importer/update_comics.py +0 -85
- codex/migrations/0027_sort_name.py +0 -139
- codex/migrations/0028_custom_covers.py +0 -166
- codex/migrations/0029_choices_adminflag_and_timestamp.py +0 -44
- codex/serializers/mtime.py +0 -25
- codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js.br +0 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.c690f0cdbe48.js.gz +0 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.js.br +0 -0
- codex/static_root/assets/VCheckbox-BOUtyxuo.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.e2b8cbdb92c9.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B1-m5pEh.js.gz +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js.br +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.22617ea193b1.js.gz +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.js.br +0 -0
- codex/static_root/assets/VCombobox-DjkDXe33.js.gz +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js.br +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.0d89c749b9a6.js.gz +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.js.br +0 -0
- codex/static_root/assets/VDialog-X0zn9AGX.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.43d65c777c58.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CRevojaF.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js.br +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.2b4dfb984a8c.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.js.br +0 -0
- codex/static_root/assets/VRadioGroup-8nrrxjDv.js.gz +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js +0 -1
- codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js.br +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.fa7a73a9c415.js.gz +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.js +0 -1
- codex/static_root/assets/VSelect-DgfIKRnC.js.br +0 -0
- codex/static_root/assets/VSelect-DgfIKRnC.js.gz +0 -0
- codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css +0 -1
- codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css.br +0 -0
- codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css.gz +0 -0
- codex/static_root/assets/VSelect-MGVSeLgr.css +0 -1
- codex/static_root/assets/VSelect-MGVSeLgr.css.br +0 -0
- codex/static_root/assets/VSelect-MGVSeLgr.css.gz +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.3030b7a270d6.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CGu0oz0K.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js.br +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.71a7101cdddd.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.js.br +0 -0
- codex/static_root/assets/VSlideGroup-D_oNvCOd.js.gz +0 -0
- codex/static_root/assets/VTable-C7pKI7gU.087912f706f5.js.br +0 -0
- codex/static_root/assets/VTable-C7pKI7gU.087912f706f5.js.gz +0 -0
- codex/static_root/assets/VTable-C7pKI7gU.js.br +0 -0
- codex/static_root/assets/VTable-C7pKI7gU.js.gz +0 -0
- codex/static_root/assets/VTextField-Bs8oq9mk.7999fef12a03.js.br +0 -0
- codex/static_root/assets/VTextField-Bs8oq9mk.7999fef12a03.js.gz +0 -0
- codex/static_root/assets/VTextField-Bs8oq9mk.js.br +0 -0
- codex/static_root/assets/VTextField-Bs8oq9mk.js.gz +0 -0
- codex/static_root/assets/VWindowItem-iyZ1XOkP.409f7d292253.js.br +0 -0
- codex/static_root/assets/VWindowItem-iyZ1XOkP.409f7d292253.js.gz +0 -0
- codex/static_root/assets/VWindowItem-iyZ1XOkP.js.br +0 -0
- codex/static_root/assets/VWindowItem-iyZ1XOkP.js.gz +0 -0
- codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js.br +0 -0
- codex/static_root/assets/admin-B0pCBjma.2407da79bd20.js.gz +0 -0
- codex/static_root/assets/admin-B0pCBjma.js.br +0 -0
- codex/static_root/assets/admin-B0pCBjma.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.5e2e1a4a255d.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BxoNUHQr.js.gz +0 -0
- codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js +0 -1
- codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js.br +0 -0
- codex/static_root/assets/browser-DbyAjCNh.577a228a966b.js.gz +0 -0
- codex/static_root/assets/browser-DbyAjCNh.js +0 -1
- codex/static_root/assets/browser-DbyAjCNh.js.br +0 -0
- codex/static_root/assets/browser-DbyAjCNh.js.gz +0 -0
- codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css +0 -1
- codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css.br +0 -0
- codex/static_root/assets/browser-VnzNj1t3.cff861ad2ca3.css.gz +0 -0
- codex/static_root/assets/browser-VnzNj1t3.css +0 -1
- codex/static_root/assets/browser-VnzNj1t3.css.br +0 -0
- codex/static_root/assets/browser-VnzNj1t3.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.930f4cae3cb0.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.930f4cae3cb0.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DZ9dP8_F.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-RP7JNStF.a752a7c1e697.js.br +0 -0
- codex/static_root/assets/confirm-dialog-RP7JNStF.a752a7c1e697.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-RP7JNStF.js.br +0 -0
- codex/static_root/assets/confirm-dialog-RP7JNStF.js.gz +0 -0
- codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js +0 -1
- codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js.br +0 -0
- codex/static_root/assets/datetime-column-Cu3WYyPj.54b4c3817b74.js.gz +0 -0
- codex/static_root/assets/datetime-column-Cu3WYyPj.js +0 -1
- codex/static_root/assets/datetime-column-Cu3WYyPj.js.br +0 -0
- codex/static_root/assets/datetime-column-Cu3WYyPj.js.gz +0 -0
- codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css +0 -1
- codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css.br +0 -0
- codex/static_root/assets/datetime-column-Dg_RxTVM.css +0 -1
- codex/static_root/assets/datetime-column-Dg_RxTVM.css.br +0 -0
- codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js.br +0 -0
- codex/static_root/assets/filter-DAdGUt-1.3261cbcd50b5.js.gz +0 -0
- codex/static_root/assets/filter-DAdGUt-1.js.br +0 -0
- codex/static_root/assets/filter-DAdGUt-1.js.gz +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js +0 -1
- codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js.br +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.cb16ef6363d4.js.gz +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.js +0 -1
- codex/static_root/assets/flag-tab-BP7Zs7iQ.js.br +0 -0
- codex/static_root/assets/flag-tab-BP7Zs7iQ.js.gz +0 -0
- codex/static_root/assets/group-tab-DEwh4jfB.a95097b5e320.js.br +0 -0
- codex/static_root/assets/group-tab-DEwh4jfB.a95097b5e320.js.gz +0 -0
- codex/static_root/assets/group-tab-DEwh4jfB.js.br +0 -0
- codex/static_root/assets/group-tab-DEwh4jfB.js.gz +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js +0 -1
- codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js.br +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.e143c472a96c.js.gz +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.js +0 -1
- codex/static_root/assets/http-error-xs3mIL8U.js.br +0 -0
- codex/static_root/assets/http-error-xs3mIL8U.js.gz +0 -0
- codex/static_root/assets/library-tab-DrXvD9B2.f765f9d3bae4.js.br +0 -0
- codex/static_root/assets/library-tab-DrXvD9B2.f765f9d3bae4.js.gz +0 -0
- codex/static_root/assets/library-tab-DrXvD9B2.js.br +0 -0
- codex/static_root/assets/library-tab-DrXvD9B2.js.gz +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js +0 -32
- codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js.br +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.2f99b1914b3e.js.gz +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.js +0 -32
- codex/static_root/assets/main-Dy9Uqpmh.js.br +0 -0
- codex/static_root/assets/main-Dy9Uqpmh.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js +0 -1
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.81222ab51ef4.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.js +0 -1
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DbS_HOT1.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css +0 -1
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.4088ab042c0c.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.css +0 -1
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-r6nbtWxg.css.gz +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js.br +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.ec9bd13a5786.js.gz +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.js.br +0 -0
- codex/static_root/assets/pdf-doc-obrBwxa6.js.gz +0 -0
- codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js +0 -2
- codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js.br +0 -0
- codex/static_root/assets/reader-BXKUaUeC.953d30b969ef.js.gz +0 -0
- codex/static_root/assets/reader-BXKUaUeC.js +0 -2
- codex/static_root/assets/reader-BXKUaUeC.js.br +0 -0
- codex/static_root/assets/reader-BXKUaUeC.js.gz +0 -0
- codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css +0 -1
- codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css.br +0 -0
- codex/static_root/assets/reader-OXJ1KVaW.a463b19d0508.css.gz +0 -0
- codex/static_root/assets/reader-OXJ1KVaW.css +0 -1
- codex/static_root/assets/reader-OXJ1KVaW.css.br +0 -0
- codex/static_root/assets/reader-OXJ1KVaW.css.gz +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js.br +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.1d7426dab654.js.gz +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.js.br +0 -0
- codex/static_root/assets/relation-chips-CZJcLjc8.js.gz +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js.br +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.337eecf2fdbb.js.gz +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.js.br +0 -0
- codex/static_root/assets/settings-drawer-7iTnAdjf.js.gz +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js.br +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.544bf50ffb22.js.gz +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.js.br +0 -0
- codex/static_root/assets/stats-tab-CQsK1n8O.js.gz +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js.br +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.63aa929a4ed6.js.gz +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.js.br +0 -0
- codex/static_root/assets/task-tab-C60TLP6e.js.gz +0 -0
- codex/static_root/assets/to-case-CR9beRR0.21bb805fdab4.js +0 -1
- codex/static_root/assets/to-case-CR9beRR0.js +0 -1
- codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js.br +0 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.c55650fac055.js.gz +0 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.js.br +0 -0
- codex/static_root/assets/unauthorized-Bs7NSqea.js.gz +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js.br +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.7e80cf1fb78e.js.gz +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.js.br +0 -0
- codex/static_root/assets/user-tab-ChuH7Atm.js.gz +0 -0
- codex/static_root/js/choices-admin.ef1ff3a8b9da.json +0 -1
- codex/static_root/js/choices-admin.ef1ff3a8b9da.json.br +0 -0
- codex/static_root/js/choices-admin.ef1ff3a8b9da.json.gz +0 -0
- codex/static_root/js/choices.079a01e0be1a.json.br +0 -0
- codex/static_root/js/choices.079a01e0be1a.json.gz +0 -0
- codex/static_root/manifest.dad79c8475ae.json.br +0 -0
- codex/static_root/manifest.dad79c8475ae.json.gz +0 -0
- codex/views/cover.py +0 -76
- codex/views/mtime.py +0 -70
- codex/views/utils.py +0 -26
- {codex-1.6.0a7.dist-info → codex-1.6.0a9.dist-info}/LICENSE +0 -0
- {codex-1.6.0a7.dist-info → codex-1.6.0a9.dist-info}/WHEEL +0 -0
- {codex-1.6.0a7.dist-info → codex-1.6.0a9.dist-info}/entry_points.txt +0 -0
|
@@ -14,6 +14,16 @@ from codex.librarian.importer.const import (
|
|
|
14
14
|
DICT_MODEL_CLASS_FIELDS_MAP,
|
|
15
15
|
DICT_MODEL_FIELD_MODEL_MAP,
|
|
16
16
|
DICT_MODEL_REL_MAP,
|
|
17
|
+
FK_CREATE,
|
|
18
|
+
FKC_CONTRIBUTORS,
|
|
19
|
+
FKC_CREATE_FKS,
|
|
20
|
+
FKC_CREATE_GROUPS,
|
|
21
|
+
FKC_FOLDER_PATHS,
|
|
22
|
+
FKC_IDENTIFIERS,
|
|
23
|
+
FKC_STORY_ARC_NUMBERS,
|
|
24
|
+
FKC_TOTAL_FKS,
|
|
25
|
+
FKC_UPDATE_GROUPS,
|
|
26
|
+
FKS,
|
|
17
27
|
GROUP_COMPARE_FIELDS,
|
|
18
28
|
GROUP_TREES,
|
|
19
29
|
IDENTIFIERS_FIELD_NAME,
|
|
@@ -23,7 +33,8 @@ from codex.librarian.importer.const import (
|
|
|
23
33
|
SERIES,
|
|
24
34
|
STORY_ARCS_METADATA_KEY,
|
|
25
35
|
)
|
|
26
|
-
from codex.librarian.importer.
|
|
36
|
+
from codex.librarian.importer.query_covers import QueryCustomCoversImporter
|
|
37
|
+
from codex.librarian.importer.status import ImportStatusTypes
|
|
27
38
|
from codex.logger.logging import get_logger
|
|
28
39
|
from codex.models import (
|
|
29
40
|
Comic,
|
|
@@ -36,13 +47,9 @@ from codex.models import (
|
|
|
36
47
|
Volume,
|
|
37
48
|
)
|
|
38
49
|
from codex.models.named import Identifier
|
|
39
|
-
from codex.models.paths import CustomCover
|
|
40
50
|
from codex.settings.settings import FILTER_BATCH_SIZE
|
|
41
51
|
from codex.status import Status
|
|
42
|
-
from codex.threads import QueuedThread
|
|
43
52
|
|
|
44
|
-
_CREATE_GROUPS = "create_groups"
|
|
45
|
-
_UPDATE_GROUPS = "update_groups"
|
|
46
53
|
_CLASS_QUERY_FIELDS_MAP = MappingProxyType(
|
|
47
54
|
{
|
|
48
55
|
Contributor: ("role__name", "person__name"),
|
|
@@ -58,18 +65,23 @@ _DEFAULT_QUERY_FIELDS = ("name",)
|
|
|
58
65
|
_EXTRA_UPDATE_FIELDS_MAP = MappingProxyType(
|
|
59
66
|
{Series: ("volume_count",), Volume: ("issue_count",)}
|
|
60
67
|
)
|
|
61
|
-
|
|
68
|
+
_DICT_MODEL_KEY_MAP = MappingProxyType(
|
|
69
|
+
{
|
|
70
|
+
CONTRIBUTORS_FIELD_NAME: FKC_CONTRIBUTORS,
|
|
71
|
+
STORY_ARCS_METADATA_KEY: FKC_STORY_ARC_NUMBERS,
|
|
72
|
+
IDENTIFIERS_FIELD_NAME: FKC_IDENTIFIERS,
|
|
73
|
+
}
|
|
74
|
+
)
|
|
62
75
|
LOG = get_logger(__name__)
|
|
63
76
|
|
|
64
77
|
|
|
65
|
-
class
|
|
78
|
+
class QueryForeignKeysImporter(QueryCustomCoversImporter):
|
|
66
79
|
"""Methods for querying what fks are missing."""
|
|
67
80
|
|
|
68
|
-
|
|
69
|
-
def _get_query_fks_totals(fks):
|
|
81
|
+
def _get_query_fks_totals(self):
|
|
70
82
|
"""Get the query foreign keys totals."""
|
|
71
83
|
fks_total = 0
|
|
72
|
-
for key, objs in
|
|
84
|
+
for key, objs in self.metadata[FKS].items():
|
|
73
85
|
if key == GROUP_TREES:
|
|
74
86
|
for groups in objs.values():
|
|
75
87
|
fks_total += len(groups)
|
|
@@ -94,11 +106,11 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
94
106
|
update_mds,
|
|
95
107
|
q_obj: Q,
|
|
96
108
|
status,
|
|
109
|
+
and_q_obj: Q | None = None,
|
|
97
110
|
):
|
|
98
111
|
"""Get create metadata by comparing proposed meatada to existing rows."""
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
status.subtitle = vnp
|
|
112
|
+
vnp = fk_cls._meta.verbose_name_plural.title()
|
|
113
|
+
status.subtitle = vnp
|
|
102
114
|
offset = 0
|
|
103
115
|
num_qs = len(q_obj.children)
|
|
104
116
|
while offset < num_qs:
|
|
@@ -106,6 +118,8 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
106
118
|
# django.db.utils.OperationalError: Expression tree is too large (maximum depth 1000)
|
|
107
119
|
children_chunk = q_obj.children[offset : offset + FILTER_BATCH_SIZE]
|
|
108
120
|
filter_chunk = Q(*children_chunk, _connector=Q.OR)
|
|
121
|
+
if and_q_obj:
|
|
122
|
+
filter_chunk = and_q_obj & filter_chunk
|
|
109
123
|
|
|
110
124
|
existing_mds = self._query_existing_mds(fk_cls, filter_chunk)
|
|
111
125
|
create_mds.difference_update(existing_mds)
|
|
@@ -117,13 +131,12 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
117
131
|
)
|
|
118
132
|
update_mds.difference_update(match_with_extra_fields_mds)
|
|
119
133
|
|
|
120
|
-
status.
|
|
134
|
+
status.add_complete(len(filter_chunk))
|
|
121
135
|
self.status_controller.update(status)
|
|
122
136
|
|
|
123
137
|
offset += FILTER_BATCH_SIZE
|
|
124
138
|
|
|
125
|
-
|
|
126
|
-
status.subtitle = ""
|
|
139
|
+
status.subtitle = ""
|
|
127
140
|
|
|
128
141
|
return num_qs
|
|
129
142
|
|
|
@@ -172,11 +185,11 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
172
185
|
update_group_set.update(update_groups)
|
|
173
186
|
return count
|
|
174
187
|
|
|
175
|
-
@classmethod
|
|
176
188
|
def _update_action_group(
|
|
177
|
-
|
|
189
|
+
self, group_cls, action_groups_key, group_tree, count_value: int | None
|
|
178
190
|
):
|
|
179
191
|
"""Update the create or update group dict with the count dict."""
|
|
192
|
+
action_groups = self.metadata[FK_CREATE][action_groups_key]
|
|
180
193
|
if group_cls not in action_groups:
|
|
181
194
|
action_groups[group_cls] = {}
|
|
182
195
|
if group_tree not in action_groups[group_cls]:
|
|
@@ -189,13 +202,12 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
189
202
|
create_group_set,
|
|
190
203
|
update_group_set,
|
|
191
204
|
group_cls,
|
|
192
|
-
create_and_update_groups,
|
|
193
205
|
status,
|
|
194
206
|
) = data
|
|
195
207
|
if group_tree in create_group_set:
|
|
196
208
|
self._update_action_group(
|
|
197
209
|
group_cls,
|
|
198
|
-
|
|
210
|
+
FKC_CREATE_GROUPS,
|
|
199
211
|
group_tree,
|
|
200
212
|
count_value,
|
|
201
213
|
)
|
|
@@ -203,14 +215,11 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
203
215
|
# This always updates Volume or Series
|
|
204
216
|
self._update_action_group(
|
|
205
217
|
group_cls,
|
|
206
|
-
|
|
218
|
+
FKC_UPDATE_GROUPS,
|
|
207
219
|
group_tree,
|
|
208
220
|
count_value,
|
|
209
221
|
)
|
|
210
|
-
|
|
211
|
-
status.complete = status.complete or 0
|
|
212
|
-
status.complete += 1
|
|
213
|
-
self.status_controller.update(status)
|
|
222
|
+
status.add_complete(1)
|
|
214
223
|
|
|
215
224
|
@staticmethod
|
|
216
225
|
def _prune_group_updates_get_filter(group_cls, update_group_trees):
|
|
@@ -281,22 +290,19 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
281
290
|
prune_count = len(update_group_trees) - len(pruned_update_group_trees)
|
|
282
291
|
self.log.debug(f"Pruned {prune_count} {vnp} from updates.")
|
|
283
292
|
|
|
284
|
-
@status_notify()
|
|
285
293
|
def _query_missing_group(
|
|
286
294
|
self,
|
|
287
295
|
groups,
|
|
288
296
|
group_cls,
|
|
289
|
-
|
|
290
|
-
status=None,
|
|
297
|
+
status,
|
|
291
298
|
):
|
|
292
299
|
"""Get missing groups from proposed groups to create."""
|
|
293
300
|
count = 0
|
|
294
301
|
if not groups:
|
|
295
302
|
return count
|
|
296
303
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
status.subtitle = vnp
|
|
304
|
+
vnp = group_cls._meta.verbose_name_plural.title()
|
|
305
|
+
status.subtitle = vnp
|
|
300
306
|
|
|
301
307
|
create_group_set = set()
|
|
302
308
|
update_group_set = set()
|
|
@@ -308,24 +314,23 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
308
314
|
create_group_set,
|
|
309
315
|
update_group_set,
|
|
310
316
|
group_cls,
|
|
311
|
-
create_and_update_groups,
|
|
312
317
|
status,
|
|
313
318
|
)
|
|
314
319
|
for group_tree, count_value in groups.items():
|
|
315
320
|
self._query_group_tree(data, group_tree, count_value)
|
|
321
|
+
self.status_controller.update(status)
|
|
316
322
|
|
|
317
323
|
# after counts have been tallied, prune the ones that don't need an update.
|
|
318
|
-
update_groups =
|
|
324
|
+
update_groups = self.metadata[FK_CREATE][FKC_UPDATE_GROUPS]
|
|
319
325
|
self._prune_group_updates(group_cls, update_groups)
|
|
320
326
|
|
|
321
|
-
|
|
322
|
-
status.subtitle = ""
|
|
327
|
+
status.subtitle = ""
|
|
323
328
|
|
|
324
329
|
create_count = len(
|
|
325
|
-
|
|
330
|
+
self.metadata[FK_CREATE][FKC_CREATE_GROUPS].get(group_cls, {})
|
|
326
331
|
)
|
|
327
332
|
update_count = len(
|
|
328
|
-
|
|
333
|
+
self.metadata[FK_CREATE][FKC_UPDATE_GROUPS].get(group_cls, {})
|
|
329
334
|
)
|
|
330
335
|
count = create_count + update_count
|
|
331
336
|
if count:
|
|
@@ -421,9 +426,9 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
421
426
|
restored_create_objs.append((*create_obj, url))
|
|
422
427
|
return restored_create_objs
|
|
423
428
|
|
|
424
|
-
def _query_missing_dict_model(self, field_name,
|
|
429
|
+
def _query_missing_dict_model(self, field_name, create_objs_key, status):
|
|
425
430
|
"""Find missing dict type m2m models."""
|
|
426
|
-
possible_objs =
|
|
431
|
+
possible_objs = self.metadata[FKS].pop(field_name, None)
|
|
427
432
|
if not possible_objs:
|
|
428
433
|
return 0
|
|
429
434
|
|
|
@@ -443,38 +448,51 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
443
448
|
)
|
|
444
449
|
|
|
445
450
|
# Build combined query object from the value_filter
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
451
|
+
model = DICT_MODEL_FIELD_MODEL_MAP[field_name]
|
|
452
|
+
if model == Identifier:
|
|
453
|
+
for filter_and_prefix, value_filter in query_filter_map.items():
|
|
454
|
+
self._query_create_metadata(
|
|
455
|
+
model,
|
|
456
|
+
possible_create_objs,
|
|
457
|
+
None,
|
|
458
|
+
value_filter,
|
|
459
|
+
status,
|
|
460
|
+
and_q_obj=filter_and_prefix,
|
|
461
|
+
)
|
|
462
|
+
else:
|
|
463
|
+
combined_q_obj = Q()
|
|
464
|
+
for filter_and_prefix, value_filter in query_filter_map.items():
|
|
465
|
+
combined_q_obj |= filter_and_prefix & value_filter
|
|
466
|
+
self._query_create_metadata(
|
|
467
|
+
model,
|
|
468
|
+
possible_create_objs,
|
|
469
|
+
None,
|
|
470
|
+
combined_q_obj,
|
|
471
|
+
status,
|
|
472
|
+
)
|
|
449
473
|
|
|
450
474
|
# Finally run the query and get only the correct create_objs
|
|
451
|
-
model = DICT_MODEL_FIELD_MODEL_MAP[field_name]
|
|
452
|
-
self._query_create_metadata(
|
|
453
|
-
model, possible_create_objs, None, combined_q_obj, status
|
|
454
|
-
)
|
|
455
475
|
possible_create_objs = self._query_missing_dict_model_identifiers_restore_urls(
|
|
456
476
|
field_name, possible_create_objs, url_restore_map
|
|
457
477
|
)
|
|
458
478
|
|
|
459
479
|
# Final Cleanup
|
|
460
|
-
|
|
461
|
-
count = len(
|
|
480
|
+
self.metadata[FK_CREATE][create_objs_key].update(possible_create_objs)
|
|
481
|
+
count = len(self.metadata[FK_CREATE][create_objs_key])
|
|
462
482
|
if count:
|
|
463
483
|
model = DICT_MODEL_FIELD_MODEL_MAP[field_name]
|
|
464
484
|
vnp = model._meta.verbose_name_plural
|
|
465
485
|
vnp = vnp.title() if vnp else "Nothings"
|
|
466
486
|
self.log.info(f"Prepared {count} new {vnp}.")
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
status.complete += count
|
|
487
|
+
status.add_complete(count)
|
|
488
|
+
self.status_controller.update(status, notify=False)
|
|
470
489
|
return count
|
|
471
490
|
|
|
472
491
|
##########
|
|
473
492
|
# SIMPLE #
|
|
474
493
|
##########
|
|
475
494
|
|
|
476
|
-
|
|
477
|
-
def _query_missing_simple_models(self, names, fk_data, status=None):
|
|
495
|
+
def _query_missing_simple_models(self, names, fk_data, status):
|
|
478
496
|
"""Find missing named models and folders."""
|
|
479
497
|
# count = 0
|
|
480
498
|
if not names:
|
|
@@ -488,9 +506,8 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
488
506
|
create_names = set(names)
|
|
489
507
|
num_proposed_names = len(proposed_names)
|
|
490
508
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
status.subtitle = vnp
|
|
509
|
+
vnp = fk_cls._meta.verbose_name_plural.title()
|
|
510
|
+
status.subtitle = vnp
|
|
494
511
|
while start < num_proposed_names:
|
|
495
512
|
# Do this in batches so as not to exceed the 1k line sqlite limit
|
|
496
513
|
end = start + FILTER_BATCH_SIZE
|
|
@@ -499,11 +516,8 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
499
516
|
fk_filter = Q(**filter_args)
|
|
500
517
|
create_names -= self._query_existing_mds(fk_cls, fk_filter)
|
|
501
518
|
num_in_batch = len(batch_proposed_names)
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
status.complete = status.complete or 0
|
|
505
|
-
status.complete += num_in_batch
|
|
506
|
-
self.status_controller.update(status)
|
|
519
|
+
status.add_complete(num_in_batch)
|
|
520
|
+
self.status_controller.update(status)
|
|
507
521
|
start += FILTER_BATCH_SIZE
|
|
508
522
|
|
|
509
523
|
if status:
|
|
@@ -520,7 +534,7 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
520
534
|
self.log.log(level, f"Prepared {len(create_names)} new {vnp}.")
|
|
521
535
|
return len(names)
|
|
522
536
|
|
|
523
|
-
def _query_one_simple_model(self, fk_field,
|
|
537
|
+
def _query_one_simple_model(self, fk_field, status):
|
|
524
538
|
"""Batch query one simple model name."""
|
|
525
539
|
for cls, names in DICT_MODEL_CLASS_FIELDS_MAP.items():
|
|
526
540
|
if fk_field in names:
|
|
@@ -528,25 +542,24 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
528
542
|
break
|
|
529
543
|
else:
|
|
530
544
|
base_cls = Comic
|
|
531
|
-
fk_data =
|
|
532
|
-
names =
|
|
533
|
-
status.
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
545
|
+
fk_data = self.metadata[FK_CREATE][FKC_CREATE_FKS], base_cls, fk_field, "name"
|
|
546
|
+
names = self.metadata[FKS].pop(fk_field)
|
|
547
|
+
status.add_complete(
|
|
548
|
+
self._query_missing_simple_models(
|
|
549
|
+
names,
|
|
550
|
+
fk_data,
|
|
551
|
+
status,
|
|
552
|
+
)
|
|
537
553
|
)
|
|
554
|
+
self.status_controller.update(status, notify=False)
|
|
538
555
|
|
|
539
556
|
###########
|
|
540
557
|
# FOLDERS #
|
|
541
558
|
###########
|
|
542
|
-
|
|
543
|
-
@status_notify()
|
|
544
|
-
def query_missing_folder_paths(
|
|
545
|
-
self, comic_paths, library_path, create_folder_paths, status=None
|
|
546
|
-
):
|
|
559
|
+
def query_missing_folder_paths(self, comic_paths, status):
|
|
547
560
|
"""Find missing folder paths."""
|
|
548
561
|
# Get the proposed folder_paths
|
|
549
|
-
library_path = Path(
|
|
562
|
+
library_path = Path(self.library.path)
|
|
550
563
|
proposed_folder_paths = set()
|
|
551
564
|
for comic_path in comic_paths:
|
|
552
565
|
for path in Path(comic_path).parents:
|
|
@@ -559,136 +572,79 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
559
572
|
self._query_missing_simple_models(
|
|
560
573
|
proposed_folder_paths,
|
|
561
574
|
fk_data,
|
|
562
|
-
status
|
|
575
|
+
status,
|
|
563
576
|
)
|
|
564
|
-
|
|
565
|
-
|
|
577
|
+
create_folder_paths = create_folder_paths_dict.get(Folder, set())
|
|
578
|
+
if FK_CREATE not in self.metadata:
|
|
579
|
+
self.metadata[FK_CREATE] = {}
|
|
580
|
+
if FKC_FOLDER_PATHS not in self.metadata[FK_CREATE]:
|
|
581
|
+
self.metadata[FK_CREATE][FKC_FOLDER_PATHS] = set()
|
|
582
|
+
self.metadata[FK_CREATE][FKC_FOLDER_PATHS] |= create_folder_paths
|
|
566
583
|
count = len(create_folder_paths)
|
|
567
584
|
if count:
|
|
568
585
|
self.log.info(f"Prepared {count} new Folders.")
|
|
569
586
|
return count
|
|
570
587
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
(
|
|
574
|
-
create_groups,
|
|
575
|
-
update_groups,
|
|
576
|
-
create_folder_paths,
|
|
577
|
-
create_fks,
|
|
578
|
-
create_contributors,
|
|
579
|
-
create_story_arc_numbers,
|
|
580
|
-
create_identifiers,
|
|
581
|
-
) = create_data
|
|
588
|
+
def _get_create_fks_totals(self):
|
|
589
|
+
fkc = self.metadata[FK_CREATE]
|
|
582
590
|
total_fks = 0
|
|
583
591
|
for data_group in chain(
|
|
584
|
-
|
|
592
|
+
fkc[FKC_CREATE_GROUPS].values(),
|
|
593
|
+
fkc[FKC_UPDATE_GROUPS].values(),
|
|
594
|
+
fkc[FKC_CREATE_FKS].values(),
|
|
585
595
|
):
|
|
586
596
|
total_fks += len(data_group)
|
|
587
597
|
total_fks += (
|
|
588
|
-
len(
|
|
589
|
-
+ len(
|
|
590
|
-
+ len(
|
|
591
|
-
+ len(
|
|
598
|
+
len(fkc[FKC_FOLDER_PATHS])
|
|
599
|
+
+ len(fkc[FKC_CONTRIBUTORS])
|
|
600
|
+
+ len(fkc[FKC_STORY_ARC_NUMBERS])
|
|
601
|
+
+ len(fkc[FKC_IDENTIFIERS])
|
|
592
602
|
)
|
|
593
603
|
return total_fks
|
|
594
604
|
|
|
595
|
-
def query_all_missing_fks(self
|
|
605
|
+
def query_all_missing_fks(self):
|
|
596
606
|
"""Get objects to create by querying existing objects for the proposed fks."""
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
IDENTIFIERS_FIELD_NAME: create_identifiers,
|
|
611
|
-
}
|
|
607
|
+
if FKS not in self.metadata:
|
|
608
|
+
return
|
|
609
|
+
self.metadata[FK_CREATE] = {
|
|
610
|
+
FKC_CONTRIBUTORS: set(),
|
|
611
|
+
FKC_STORY_ARC_NUMBERS: set(),
|
|
612
|
+
FKC_IDENTIFIERS: set(),
|
|
613
|
+
FKC_CREATE_GROUPS: {},
|
|
614
|
+
FKC_UPDATE_GROUPS: {},
|
|
615
|
+
FKC_FOLDER_PATHS: set(),
|
|
616
|
+
FKC_CREATE_FKS: {},
|
|
617
|
+
}
|
|
618
|
+
self.log.debug(
|
|
619
|
+
f"Querying existing foreign keys for comics in {self.library.path}"
|
|
612
620
|
)
|
|
613
|
-
status = Status(ImportStatusTypes.QUERY_MISSING_FKS
|
|
621
|
+
status = Status(ImportStatusTypes.QUERY_MISSING_FKS)
|
|
614
622
|
try:
|
|
615
623
|
self.status_controller.start(status)
|
|
616
|
-
for field_name,
|
|
624
|
+
for field_name, create_objs_key in _DICT_MODEL_KEY_MAP.items():
|
|
617
625
|
self._query_missing_dict_model(
|
|
618
626
|
field_name,
|
|
619
|
-
|
|
620
|
-
create_objs,
|
|
627
|
+
create_objs_key,
|
|
621
628
|
status,
|
|
622
629
|
)
|
|
623
|
-
|
|
624
|
-
create_and_update_groups = {
|
|
625
|
-
_CREATE_GROUPS: create_groups,
|
|
626
|
-
_UPDATE_GROUPS: update_groups,
|
|
627
|
-
}
|
|
628
|
-
for group_class, groups in fks.pop(GROUP_TREES, {}).items():
|
|
630
|
+
for group_class, groups in self.metadata[FKS].pop(GROUP_TREES, {}).items():
|
|
629
631
|
self._query_missing_group(
|
|
630
632
|
groups,
|
|
631
633
|
group_class,
|
|
632
|
-
|
|
633
|
-
status=status,
|
|
634
|
+
status,
|
|
634
635
|
)
|
|
635
636
|
|
|
636
637
|
self.query_missing_folder_paths(
|
|
637
|
-
|
|
638
|
-
library_path,
|
|
639
|
-
create_folder_paths,
|
|
640
|
-
status=status,
|
|
638
|
+
self.metadata[FKS].pop(COMIC_PATHS, ()), status
|
|
641
639
|
)
|
|
642
640
|
|
|
643
|
-
for fk_field in sorted(
|
|
644
|
-
self._query_one_simple_model(fk_field,
|
|
641
|
+
for fk_field in sorted(self.metadata[FKS].keys()):
|
|
642
|
+
self._query_one_simple_model(fk_field, status)
|
|
643
|
+
self.metadata.pop(FKS)
|
|
645
644
|
finally:
|
|
646
645
|
self.status_controller.finish(status)
|
|
647
646
|
|
|
648
|
-
|
|
649
|
-
create_groups,
|
|
650
|
-
update_groups,
|
|
651
|
-
create_folder_paths,
|
|
652
|
-
create_fks,
|
|
653
|
-
create_contributors,
|
|
654
|
-
create_story_arc_numbers,
|
|
655
|
-
create_identifiers,
|
|
656
|
-
)
|
|
657
|
-
|
|
658
|
-
total_fks = self._get_create_fks_totals(create_data)
|
|
647
|
+
total_fks = self._get_create_fks_totals()
|
|
659
648
|
status = Status(ImportStatusTypes.CREATE_FKS, 0, total_fks)
|
|
660
649
|
self.status_controller.update(status, notify=False)
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
@status_notify(ImportStatusTypes.QUERY_MISSING_COVERS, updates=False)
|
|
664
|
-
def query_missing_custom_covers(
|
|
665
|
-
self, cover_paths: frozenset, library, query_data: list, status=None
|
|
666
|
-
):
|
|
667
|
-
"""Identify update & create covers."""
|
|
668
|
-
self.log.debug(f"Querying {len(cover_paths)} custom cover_paths")
|
|
669
|
-
if status:
|
|
670
|
-
status.total = len(cover_paths)
|
|
671
|
-
|
|
672
|
-
update_covers_qs = CustomCover.objects.filter(
|
|
673
|
-
library=library, path__in=cover_paths
|
|
674
|
-
)
|
|
675
|
-
query_data.append(update_covers_qs)
|
|
676
|
-
update_cover_paths = frozenset(update_covers_qs.values_list("path", flat=True))
|
|
677
|
-
update_count = len(update_cover_paths)
|
|
678
|
-
update_status = Status(ImportStatusTypes.COVERS_MODIFIED, 0, update_count)
|
|
679
|
-
self.status_controller.update(update_status, notify=False)
|
|
680
|
-
|
|
681
|
-
create_cover_paths = cover_paths - update_cover_paths
|
|
682
|
-
query_data.append(create_cover_paths)
|
|
683
|
-
create_count = len(create_cover_paths)
|
|
684
|
-
create_status = Status(ImportStatusTypes.COVERS_CREATED, 0, create_count)
|
|
685
|
-
self.status_controller.update(create_status, notify=False)
|
|
686
|
-
|
|
687
|
-
count = create_count + update_count
|
|
688
|
-
if count:
|
|
689
|
-
self.log.debug(
|
|
690
|
-
f"Discovered {update_count} custom covers to update and {create_count} to create."
|
|
691
|
-
)
|
|
692
|
-
if status:
|
|
693
|
-
status.add_complete(count)
|
|
694
|
-
return count
|
|
650
|
+
self.metadata[FK_CREATE][FKC_TOTAL_FKS] = total_fks
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
"""Librarian Status for imports."""
|
|
2
2
|
|
|
3
|
-
from collections.abc import Callable
|
|
4
|
-
from enum import Enum
|
|
5
|
-
from time import time
|
|
6
|
-
|
|
7
3
|
from django.db.models import Choices
|
|
8
4
|
|
|
9
|
-
from codex.status import Status
|
|
10
|
-
|
|
11
5
|
|
|
12
6
|
class ImportStatusTypes(Choices):
|
|
13
7
|
"""Keys for Import tasks."""
|
|
@@ -31,36 +25,5 @@ class ImportStatusTypes(Choices):
|
|
|
31
25
|
COVERS_CREATED = "ICC"
|
|
32
26
|
COVERS_DELETED = "ICD"
|
|
33
27
|
COVERS_LINK = "ICL"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def status_notify(status_type: str | Enum = "", updates=True):
|
|
37
|
-
"""Wrap a function with status changes."""
|
|
38
|
-
# https://stackoverflow.com/questions/5929107/decorators-with-parameters
|
|
39
|
-
|
|
40
|
-
def decorator(func) -> Callable[..., int]:
|
|
41
|
-
def wrapper(self, data, *args, status=None, **kwargs) -> int:
|
|
42
|
-
"""Run a function bracketed by status changes."""
|
|
43
|
-
num_elements = len(data)
|
|
44
|
-
if not num_elements:
|
|
45
|
-
return 0
|
|
46
|
-
|
|
47
|
-
if status:
|
|
48
|
-
finish = False
|
|
49
|
-
else:
|
|
50
|
-
complete = 0 if updates else None
|
|
51
|
-
status = Status(status_type, complete, num_elements, time())
|
|
52
|
-
self.status_controller.start(status)
|
|
53
|
-
finish = True
|
|
54
|
-
|
|
55
|
-
kwargs["status"] = status
|
|
56
|
-
try:
|
|
57
|
-
count = func(self, data, *args, **kwargs)
|
|
58
|
-
finally:
|
|
59
|
-
if finish:
|
|
60
|
-
self.status_controller.finish(status)
|
|
61
|
-
|
|
62
|
-
return count
|
|
63
|
-
|
|
64
|
-
return wrapper
|
|
65
|
-
|
|
66
|
-
return decorator
|
|
28
|
+
GROUP_UPDATE = "IGU"
|
|
29
|
+
ADOPT_FOLDERS = "IAF"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""DB Import Tasks."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from datetime import datetime
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
@dataclass
|
|
@@ -14,20 +16,20 @@ class ImportDBDiffTask(ImportTask):
|
|
|
14
16
|
|
|
15
17
|
library_id: int
|
|
16
18
|
|
|
17
|
-
dirs_moved:
|
|
18
|
-
dirs_modified: frozenset[str]
|
|
19
|
-
# dirs_created: frozenset[str]
|
|
20
|
-
dirs_deleted: frozenset[str]
|
|
19
|
+
dirs_moved: Mapping[str, str] = field(default_factory=dict)
|
|
20
|
+
dirs_modified: frozenset[str] = frozenset()
|
|
21
|
+
# dirs_created: frozenset[str] | None = frozenset()
|
|
22
|
+
dirs_deleted: frozenset[str] = frozenset()
|
|
21
23
|
|
|
22
|
-
files_moved:
|
|
23
|
-
files_modified: frozenset[str]
|
|
24
|
-
files_created: frozenset[str]
|
|
25
|
-
files_deleted: frozenset[str]
|
|
24
|
+
files_moved: Mapping[str, str] = field(default_factory=dict)
|
|
25
|
+
files_modified: frozenset[str] = frozenset()
|
|
26
|
+
files_created: frozenset[str] = frozenset()
|
|
27
|
+
files_deleted: frozenset[str] = frozenset()
|
|
26
28
|
|
|
27
|
-
covers_moved:
|
|
28
|
-
covers_modified: frozenset[str]
|
|
29
|
-
covers_created: frozenset[str]
|
|
30
|
-
covers_deleted: frozenset[str]
|
|
29
|
+
covers_moved: Mapping[str, str] = field(default_factory=dict)
|
|
30
|
+
covers_modified: frozenset[str] = frozenset()
|
|
31
|
+
covers_created: frozenset[str] = frozenset()
|
|
32
|
+
covers_deleted: frozenset[str] = frozenset()
|
|
31
33
|
|
|
32
34
|
force_import_metadata: bool = False
|
|
33
35
|
|
|
@@ -42,3 +44,10 @@ class LazyImportComicsTask(ImportTask):
|
|
|
42
44
|
@dataclass
|
|
43
45
|
class AdoptOrphanFoldersTask(ImportTask):
|
|
44
46
|
"""Move orphaned folders into a correct tree position."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class UpdateGroupsFirstComic(ImportTask):
|
|
51
|
+
"""Force the update of the first comics."""
|
|
52
|
+
|
|
53
|
+
start_time: datetime | None = None
|
|
@@ -6,7 +6,7 @@ from time import time
|
|
|
6
6
|
from types import MappingProxyType
|
|
7
7
|
|
|
8
8
|
from django.contrib.sessions.models import Session
|
|
9
|
-
from django.
|
|
9
|
+
from django.db.models.functions.datetime import Now
|
|
10
10
|
|
|
11
11
|
from codex.librarian.janitor.status import JanitorStatusTypes
|
|
12
12
|
from codex.models import (
|
|
@@ -137,7 +137,7 @@ class CleanupMixin(WorkerBaseMixin):
|
|
|
137
137
|
status = Status(JanitorStatusTypes.CLEANUP_SESSIONS)
|
|
138
138
|
try:
|
|
139
139
|
self.status_controller.start(status)
|
|
140
|
-
count, _ = Session.objects.filter(expire_date__lt=
|
|
140
|
+
count, _ = Session.objects.filter(expire_date__lt=Now()).delete()
|
|
141
141
|
if count:
|
|
142
142
|
self.log.info(f"Deleted {count} expired sessions.")
|
|
143
143
|
|