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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Create Custom Covers."""
|
|
2
|
+
|
|
3
|
+
from django.db.models.functions.datetime import Now
|
|
4
|
+
|
|
5
|
+
from codex.librarian.importer.const import (
|
|
6
|
+
COVERS_CREATE,
|
|
7
|
+
COVERS_UPDATE,
|
|
8
|
+
CUSTOM_COVER_UPDATE_FIELDS,
|
|
9
|
+
LINK_COVER_PKS,
|
|
10
|
+
)
|
|
11
|
+
from codex.librarian.importer.create_comics import CreateComicsImporter
|
|
12
|
+
from codex.librarian.importer.status import ImportStatusTypes
|
|
13
|
+
from codex.models import (
|
|
14
|
+
CustomCover,
|
|
15
|
+
)
|
|
16
|
+
from codex.status import Status
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CreateCoversImporter(CreateComicsImporter):
|
|
20
|
+
"""Create Custom Covers."""
|
|
21
|
+
|
|
22
|
+
def update_custom_covers(self, status=None):
|
|
23
|
+
"""Update Custom Covers."""
|
|
24
|
+
update_covers_qs = self.metadata.pop(COVERS_UPDATE, None)
|
|
25
|
+
if not update_covers_qs:
|
|
26
|
+
return
|
|
27
|
+
update_covers_count = update_covers_qs.count()
|
|
28
|
+
if not update_covers_count:
|
|
29
|
+
return
|
|
30
|
+
status = Status(ImportStatusTypes.COVERS_MODIFIED, 0, update_covers_count)
|
|
31
|
+
self.status_controller.start(status)
|
|
32
|
+
|
|
33
|
+
update_covers = []
|
|
34
|
+
for cover in update_covers_qs.only(*CUSTOM_COVER_UPDATE_FIELDS):
|
|
35
|
+
cover.updated_at = Now()
|
|
36
|
+
cover.presave()
|
|
37
|
+
update_covers.append(cover)
|
|
38
|
+
|
|
39
|
+
count = 0
|
|
40
|
+
if update_covers:
|
|
41
|
+
CustomCover.objects.bulk_update(update_covers, CUSTOM_COVER_UPDATE_FIELDS)
|
|
42
|
+
update_cover_pks = update_covers_qs.values_list("pk", flat=True)
|
|
43
|
+
if LINK_COVER_PKS not in self.metadata:
|
|
44
|
+
self.metadata[LINK_COVER_PKS] = set()
|
|
45
|
+
self.metadata[LINK_COVER_PKS].update(update_cover_pks)
|
|
46
|
+
self._remove_covers(update_cover_pks, custom=True) # type: ignore
|
|
47
|
+
count = len(update_covers)
|
|
48
|
+
if status:
|
|
49
|
+
status.add_complete(count)
|
|
50
|
+
|
|
51
|
+
link_covers_status = Status(
|
|
52
|
+
ImportStatusTypes.COVERS_LINK, 0, len(self.metadata[LINK_COVER_PKS])
|
|
53
|
+
)
|
|
54
|
+
self.status_controller.update(link_covers_status, notify=False)
|
|
55
|
+
|
|
56
|
+
self.changed += count
|
|
57
|
+
self.status_controller.finish(status)
|
|
58
|
+
|
|
59
|
+
def create_custom_covers(self, status=None):
|
|
60
|
+
"""Create Custom Covers."""
|
|
61
|
+
create_cover_paths = self.metadata.pop(COVERS_CREATE, ())
|
|
62
|
+
num_create_cover_paths = len(create_cover_paths)
|
|
63
|
+
if not num_create_cover_paths:
|
|
64
|
+
return
|
|
65
|
+
status = Status(ImportStatusTypes.COVERS_MODIFIED, 0, num_create_cover_paths)
|
|
66
|
+
self.status_controller.start(status)
|
|
67
|
+
|
|
68
|
+
create_covers = []
|
|
69
|
+
for path in create_cover_paths:
|
|
70
|
+
cover = CustomCover(library=self.library, path=path)
|
|
71
|
+
cover.presave()
|
|
72
|
+
create_covers.append(cover)
|
|
73
|
+
|
|
74
|
+
count = 0
|
|
75
|
+
if create_covers:
|
|
76
|
+
objs = CustomCover.objects.bulk_create(
|
|
77
|
+
create_covers,
|
|
78
|
+
update_conflicts=True,
|
|
79
|
+
update_fields=("path", "stat"),
|
|
80
|
+
unique_fields=CustomCover._meta.unique_together[0],
|
|
81
|
+
)
|
|
82
|
+
created_pks = frozenset(obj.pk for obj in objs)
|
|
83
|
+
if LINK_COVER_PKS not in self.metadata:
|
|
84
|
+
self.metadata[LINK_COVER_PKS] = set()
|
|
85
|
+
self.metadata[LINK_COVER_PKS].update(created_pks)
|
|
86
|
+
count = len(created_pks)
|
|
87
|
+
if status:
|
|
88
|
+
status.add_complete(count)
|
|
89
|
+
|
|
90
|
+
link_covers_status = Status(
|
|
91
|
+
ImportStatusTypes.COVERS_LINK, 0, len(self.metadata[LINK_COVER_PKS])
|
|
92
|
+
)
|
|
93
|
+
self.status_controller.update(link_covers_status, notify=False)
|
|
94
|
+
|
|
95
|
+
self.changed += count
|
|
96
|
+
self.status_controller.finish(status)
|
|
@@ -6,14 +6,21 @@ So we may safely create the comics next.
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
8
|
from django.core.exceptions import ObjectDoesNotExist
|
|
9
|
-
from django.db.models.functions.datetime import Now
|
|
10
9
|
|
|
11
10
|
from codex.librarian.importer.const import (
|
|
12
11
|
BULK_UPDATE_FOLDER_FIELDS,
|
|
13
12
|
CLASS_CUSTOM_COVER_GROUP_MAP,
|
|
14
13
|
COUNT_FIELDS,
|
|
15
14
|
CREATE_DICT_UPDATE_FIELDS,
|
|
16
|
-
|
|
15
|
+
FK_CREATE,
|
|
16
|
+
FKC_CONTRIBUTORS,
|
|
17
|
+
FKC_CREATE_FKS,
|
|
18
|
+
FKC_CREATE_GROUPS,
|
|
19
|
+
FKC_FOLDER_PATHS,
|
|
20
|
+
FKC_IDENTIFIERS,
|
|
21
|
+
FKC_STORY_ARC_NUMBERS,
|
|
22
|
+
FKC_TOTAL_FKS,
|
|
23
|
+
FKC_UPDATE_GROUPS,
|
|
17
24
|
GROUP_BASE_FIELDS,
|
|
18
25
|
GROUP_UPDATE_FIELDS,
|
|
19
26
|
IMPRINT,
|
|
@@ -23,7 +30,8 @@ from codex.librarian.importer.const import (
|
|
|
23
30
|
SERIES,
|
|
24
31
|
VOLUME_COUNT,
|
|
25
32
|
)
|
|
26
|
-
from codex.librarian.importer.
|
|
33
|
+
from codex.librarian.importer.create_covers import CreateCoversImporter
|
|
34
|
+
from codex.librarian.importer.status import ImportStatusTypes
|
|
27
35
|
from codex.models import (
|
|
28
36
|
Contributor,
|
|
29
37
|
ContributorPerson,
|
|
@@ -39,10 +47,9 @@ from codex.models import (
|
|
|
39
47
|
)
|
|
40
48
|
from codex.models.named import Identifier, IdentifierType
|
|
41
49
|
from codex.status import Status
|
|
42
|
-
from codex.threads import QueuedThread
|
|
43
50
|
|
|
44
51
|
|
|
45
|
-
class
|
|
52
|
+
class CreateForeignKeysImporter(CreateCoversImporter):
|
|
46
53
|
"""Methods for creating foreign keys."""
|
|
47
54
|
|
|
48
55
|
@staticmethod
|
|
@@ -107,12 +114,11 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
107
114
|
obj = None
|
|
108
115
|
return obj
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
def _bulk_group_create(self, group_tree_counts, group_class, status=None) -> int:
|
|
117
|
+
def _bulk_group_create(self, group_tree_counts, group_class, status):
|
|
112
118
|
"""Bulk creates groups."""
|
|
113
119
|
count = 0
|
|
114
120
|
if not group_tree_counts:
|
|
115
|
-
return
|
|
121
|
+
return
|
|
116
122
|
create_groups = []
|
|
117
123
|
for group_param_tuple, group_count in group_tree_counts.items():
|
|
118
124
|
obj = self._create_group_obj(group_class, group_param_tuple, group_count)
|
|
@@ -130,18 +136,14 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
130
136
|
if count:
|
|
131
137
|
vnp = group_class._meta.verbose_name_plural.title()
|
|
132
138
|
self.log.info(f"Created {count} {vnp}.")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
self.status_controller.update(status)
|
|
137
|
-
return count
|
|
139
|
+
status.add_complete(count)
|
|
140
|
+
self.status_controller.update(status)
|
|
141
|
+
return
|
|
138
142
|
|
|
139
|
-
|
|
140
|
-
def _bulk_group_updater(self, group_tree_counts, group_class, status=None):
|
|
143
|
+
def _bulk_group_updater(self, group_tree_counts, group_class, status):
|
|
141
144
|
"""Bulk update groups."""
|
|
142
|
-
count = 0
|
|
143
145
|
if not group_tree_counts:
|
|
144
|
-
return
|
|
146
|
+
return
|
|
145
147
|
update_groups = []
|
|
146
148
|
for group_param_tuple, group_count in group_tree_counts.items():
|
|
147
149
|
obj = self._update_group_obj(group_class, group_param_tuple, group_count)
|
|
@@ -149,30 +151,27 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
149
151
|
update_groups.append(obj)
|
|
150
152
|
count_field = COUNT_FIELDS[group_class]
|
|
151
153
|
group_class.objects.bulk_update(update_groups, fields=[count_field])
|
|
152
|
-
count
|
|
154
|
+
count = len(update_groups)
|
|
153
155
|
if count:
|
|
154
156
|
vnp = group_class._meta.verbose_name_plural.title()
|
|
155
157
|
self.log.info(f"Updated {count} {vnp}.")
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
status.complete += count
|
|
159
|
-
self.status_controller.update(status)
|
|
160
|
-
return count
|
|
158
|
+
status.add_complete(count)
|
|
159
|
+
self.status_controller.update(status)
|
|
161
160
|
|
|
162
|
-
def _bulk_folders_create_add_folder(self,
|
|
161
|
+
def _bulk_folders_create_add_folder(self, path, create_folders):
|
|
163
162
|
"""Add one folder to the create list."""
|
|
164
163
|
parent_path = str(path.parent)
|
|
165
164
|
parent = None
|
|
166
165
|
try:
|
|
167
166
|
parent = Folder.objects.get(path=parent_path)
|
|
168
167
|
except Folder.DoesNotExist:
|
|
169
|
-
if path.parent != Path(library.path):
|
|
168
|
+
if path.parent != Path(self.library.path):
|
|
170
169
|
self.log.warning(
|
|
171
170
|
f"Can't find parent folder {parent_path}"
|
|
172
|
-
f" for {path} in library {library.path}"
|
|
171
|
+
f" for {path} in library {self.library.path}"
|
|
173
172
|
)
|
|
174
173
|
folder = Folder(
|
|
175
|
-
library=library,
|
|
174
|
+
library=self.library,
|
|
176
175
|
path=str(path),
|
|
177
176
|
name=path.name,
|
|
178
177
|
parent_folder=parent,
|
|
@@ -181,11 +180,11 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
181
180
|
self._add_custom_cover_to_group(Folder, folder)
|
|
182
181
|
create_folders.append(folder)
|
|
183
182
|
|
|
184
|
-
def _bulk_folders_create_depth_level(self,
|
|
183
|
+
def _bulk_folders_create_depth_level(self, paths, status):
|
|
185
184
|
"""Create a depth level of folders."""
|
|
186
185
|
create_folders = []
|
|
187
186
|
for path in sorted(paths):
|
|
188
|
-
self._bulk_folders_create_add_folder(
|
|
187
|
+
self._bulk_folders_create_add_folder(path, create_folders)
|
|
189
188
|
Folder.objects.bulk_create(
|
|
190
189
|
create_folders,
|
|
191
190
|
update_conflicts=True,
|
|
@@ -193,18 +192,15 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
193
192
|
unique_fields=Folder._meta.unique_together[0], # type: ignore
|
|
194
193
|
)
|
|
195
194
|
count = len(create_folders)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
status.complete += count
|
|
199
|
-
self.status_controller.update(status)
|
|
195
|
+
status.add_complete(count)
|
|
196
|
+
self.status_controller.update(status)
|
|
200
197
|
return count
|
|
201
198
|
|
|
202
|
-
|
|
203
|
-
def bulk_folders_create(self, folder_paths: set, library, status=None):
|
|
199
|
+
def bulk_folders_create(self, folder_paths: frozenset, status):
|
|
204
200
|
"""Create folders breadth first."""
|
|
205
201
|
count = 0
|
|
206
202
|
if not folder_paths:
|
|
207
|
-
return
|
|
203
|
+
return
|
|
208
204
|
# group folder paths by depth
|
|
209
205
|
folder_path_dict = {}
|
|
210
206
|
for path_str in folder_paths:
|
|
@@ -215,19 +211,18 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
215
211
|
folder_path_dict[path_length].add(path)
|
|
216
212
|
|
|
217
213
|
# create each depth level first to ensure we can assign parents
|
|
218
|
-
for
|
|
219
|
-
count += self._bulk_folders_create_depth_level(
|
|
214
|
+
for paths in sorted(folder_path_dict.values()):
|
|
215
|
+
count += self._bulk_folders_create_depth_level(paths, status)
|
|
220
216
|
|
|
221
217
|
if count:
|
|
222
218
|
self.log.info(f"Created {count} Folders.")
|
|
223
|
-
|
|
219
|
+
self.status_controller.update(status)
|
|
224
220
|
|
|
225
|
-
|
|
226
|
-
def _bulk_create_named_models(self, names, named_class, status=None):
|
|
221
|
+
def _bulk_create_named_models(self, names, named_class, status):
|
|
227
222
|
"""Bulk create named models."""
|
|
228
223
|
count = len(names)
|
|
229
224
|
if not count:
|
|
230
|
-
return
|
|
225
|
+
return
|
|
231
226
|
create_named_objs = []
|
|
232
227
|
is_story_arc = named_class == StoryArc
|
|
233
228
|
for name in names:
|
|
@@ -250,11 +245,8 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
250
245
|
if count:
|
|
251
246
|
vnp = named_class._meta.verbose_name_plural.title()
|
|
252
247
|
self.log.info(f"Created {count} {vnp}.")
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
status.complete += count
|
|
256
|
-
self.status_controller.update(status)
|
|
257
|
-
return count
|
|
248
|
+
status.add_complete(count)
|
|
249
|
+
self.status_controller.update(status)
|
|
258
250
|
|
|
259
251
|
@staticmethod
|
|
260
252
|
def _create_contributor_args(values):
|
|
@@ -275,17 +267,23 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
275
267
|
"url": values[2],
|
|
276
268
|
}
|
|
277
269
|
|
|
278
|
-
|
|
270
|
+
_CREATE_DICT_FUNCTION_MAP = (
|
|
271
|
+
(Contributor, FKC_CONTRIBUTORS, _create_contributor_args),
|
|
272
|
+
(StoryArcNumber, FKC_STORY_ARC_NUMBERS, _create_story_arc_number_args),
|
|
273
|
+
(Identifier, FKC_IDENTIFIERS, _create_identifier_args),
|
|
274
|
+
)
|
|
275
|
+
|
|
279
276
|
def _bulk_create_dict_models(
|
|
280
|
-
self,
|
|
277
|
+
self, create_tuples_key, create_args_func, model, status
|
|
281
278
|
):
|
|
282
279
|
"""Bulk create a dict type m2m model."""
|
|
280
|
+
create_tuples = self.metadata[FK_CREATE].pop(create_tuples_key, None)
|
|
283
281
|
if not create_tuples:
|
|
284
|
-
return
|
|
282
|
+
return
|
|
285
283
|
|
|
286
284
|
create_objs = []
|
|
287
285
|
for values_tuple in create_tuples:
|
|
288
|
-
args =
|
|
286
|
+
args = create_args_func(values_tuple)
|
|
289
287
|
obj = model(**args)
|
|
290
288
|
create_objs.append(obj)
|
|
291
289
|
|
|
@@ -299,139 +297,44 @@ class CreateForeignKeysMixin(QueuedThread):
|
|
|
299
297
|
if count:
|
|
300
298
|
vnp = model._meta.verbose_name_plural.title()
|
|
301
299
|
self.log.info(f"Created {count} {vnp}.")
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
status.complete += count
|
|
305
|
-
self.status_controller.update(status)
|
|
306
|
-
return count
|
|
300
|
+
status.add_complete(count)
|
|
301
|
+
self.status_controller.update(status)
|
|
307
302
|
|
|
308
|
-
def create_all_fks(self
|
|
303
|
+
def create_all_fks(self):
|
|
309
304
|
"""Bulk create all foreign keys."""
|
|
310
|
-
(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
create_contributors,
|
|
316
|
-
create_story_arc_numbers,
|
|
317
|
-
create_identifiers,
|
|
318
|
-
total_fks,
|
|
319
|
-
) = create_data
|
|
320
|
-
|
|
321
|
-
status = Status(ImportStatusTypes.CREATE_FKS, 0, total_fks)
|
|
305
|
+
fkc = self.metadata.get(FK_CREATE)
|
|
306
|
+
if not fkc:
|
|
307
|
+
return
|
|
308
|
+
|
|
309
|
+
status = Status(ImportStatusTypes.CREATE_FKS, 0, fkc.pop(FKC_TOTAL_FKS, None))
|
|
322
310
|
try:
|
|
323
311
|
self.status_controller.start(status)
|
|
324
312
|
|
|
325
|
-
for group_class, group_tree_counts in
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
status=status,
|
|
330
|
-
)
|
|
331
|
-
status.add_complete(count)
|
|
313
|
+
for group_class, group_tree_counts in fkc.pop(
|
|
314
|
+
FKC_CREATE_GROUPS, {}
|
|
315
|
+
).items():
|
|
316
|
+
self._bulk_group_create(group_tree_counts, group_class, status)
|
|
332
317
|
|
|
333
|
-
for group_class, group_tree_counts in
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
status=status,
|
|
338
|
-
)
|
|
339
|
-
status.add_complete(count)
|
|
318
|
+
for group_class, group_tree_counts in fkc.pop(
|
|
319
|
+
FKC_UPDATE_GROUPS, {}
|
|
320
|
+
).items():
|
|
321
|
+
self._bulk_group_updater(group_tree_counts, group_class, status)
|
|
340
322
|
|
|
341
|
-
|
|
342
|
-
sorted(create_folder_paths),
|
|
343
|
-
library,
|
|
344
|
-
status=status,
|
|
345
|
-
)
|
|
346
|
-
status.add_complete(count)
|
|
323
|
+
self.bulk_folders_create(fkc.pop(FKC_FOLDER_PATHS, frozenset()), status)
|
|
347
324
|
|
|
348
|
-
for named_class, names in
|
|
349
|
-
|
|
350
|
-
names,
|
|
351
|
-
named_class,
|
|
352
|
-
status=status,
|
|
353
|
-
)
|
|
354
|
-
status.add_complete(count)
|
|
325
|
+
for named_class, names in fkc.pop(FKC_CREATE_FKS, {}).items():
|
|
326
|
+
self._bulk_create_named_models(names, named_class, status)
|
|
355
327
|
|
|
356
328
|
# These all depend on bulk_create_named_models running first
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
(
|
|
360
|
-
StoryArcNumber,
|
|
361
|
-
create_story_arc_numbers,
|
|
362
|
-
self._create_story_arc_number_args,
|
|
363
|
-
),
|
|
364
|
-
(Identifier, create_identifiers, self._create_identifier_args),
|
|
365
|
-
)
|
|
366
|
-
for model, create_objs, func in create_dict_data:
|
|
367
|
-
count = self._bulk_create_dict_models(
|
|
329
|
+
for model, create_objs, func in self._CREATE_DICT_FUNCTION_MAP:
|
|
330
|
+
self._bulk_create_dict_models(
|
|
368
331
|
create_objs,
|
|
369
332
|
func,
|
|
370
333
|
model,
|
|
371
|
-
status
|
|
334
|
+
status,
|
|
372
335
|
)
|
|
373
|
-
status.add_complete(count)
|
|
374
336
|
|
|
375
337
|
finally:
|
|
338
|
+
self.metadata.pop(FK_CREATE, None)
|
|
376
339
|
self.status_controller.finish(status)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
@status_notify(ImportStatusTypes.COVERS_MODIFIED, updates=False)
|
|
380
|
-
def update_custom_covers(
|
|
381
|
-
self, update_covers_qs, link_cover_pks, status=None
|
|
382
|
-
) -> int:
|
|
383
|
-
"""Update Custom Covers."""
|
|
384
|
-
count = 0
|
|
385
|
-
update_covers_count = update_covers_qs.count()
|
|
386
|
-
if not update_covers_count:
|
|
387
|
-
return count
|
|
388
|
-
if status:
|
|
389
|
-
status.total = update_covers_count
|
|
390
|
-
now = Now()
|
|
391
|
-
|
|
392
|
-
update_covers = []
|
|
393
|
-
for cover in update_covers_qs.only(*CUSTOM_COVER_UPDATE_FIELDS):
|
|
394
|
-
cover.updated_at = now
|
|
395
|
-
cover.presave()
|
|
396
|
-
update_covers.append(cover)
|
|
397
|
-
|
|
398
|
-
if update_covers:
|
|
399
|
-
CustomCover.objects.bulk_update(update_covers, CUSTOM_COVER_UPDATE_FIELDS)
|
|
400
|
-
update_cover_pks = update_covers_qs.values_list("pk", flat=True)
|
|
401
|
-
link_cover_pks.update(update_cover_pks)
|
|
402
|
-
self._remove_covers(update_cover_pks, custom=True) # type: ignore
|
|
403
|
-
count = len(update_covers)
|
|
404
|
-
if status:
|
|
405
|
-
status.add_complete(count)
|
|
406
|
-
return count
|
|
407
|
-
|
|
408
|
-
@status_notify(ImportStatusTypes.COVERS_CREATED, updates=False)
|
|
409
|
-
def create_custom_covers(
|
|
410
|
-
self, create_cover_paths, library, link_cover_pks, status=None
|
|
411
|
-
) -> int:
|
|
412
|
-
"""Create Custom Covers."""
|
|
413
|
-
count = 0
|
|
414
|
-
if not create_cover_paths:
|
|
415
|
-
return count
|
|
416
|
-
if status:
|
|
417
|
-
status.total = len(create_cover_paths)
|
|
418
|
-
|
|
419
|
-
create_covers = []
|
|
420
|
-
for path in create_cover_paths:
|
|
421
|
-
cover = CustomCover(library=library, path=path)
|
|
422
|
-
cover.presave()
|
|
423
|
-
create_covers.append(cover)
|
|
424
|
-
|
|
425
|
-
if create_covers:
|
|
426
|
-
objs = CustomCover.objects.bulk_create(
|
|
427
|
-
create_covers,
|
|
428
|
-
update_conflicts=True,
|
|
429
|
-
update_fields=("path", "stat"),
|
|
430
|
-
unique_fields=CustomCover._meta.unique_together[0],
|
|
431
|
-
)
|
|
432
|
-
created_pks = frozenset(obj.pk for obj in objs)
|
|
433
|
-
link_cover_pks.update(created_pks)
|
|
434
|
-
count = len(created_pks)
|
|
435
|
-
if status:
|
|
436
|
-
status.add_complete(count)
|
|
437
|
-
return count
|
|
340
|
+
self.changed += status.complete if status.complete else 0
|
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
"""Clean up the database after moves or imports."""
|
|
2
2
|
|
|
3
3
|
from codex.librarian.covers.tasks import CoverRemoveTask
|
|
4
|
+
from codex.librarian.importer.cache import CacheUpdateImporter
|
|
4
5
|
from codex.librarian.importer.const import COMIC_GROUP_FIELD_NAMES
|
|
5
|
-
from codex.librarian.importer.status import ImportStatusTypes
|
|
6
|
+
from codex.librarian.importer.status import ImportStatusTypes
|
|
6
7
|
from codex.models import Comic, Folder, StoryArc
|
|
7
8
|
from codex.models.paths import CustomCover
|
|
8
9
|
from codex.settings.settings import MAX_CHUNK_SIZE
|
|
9
|
-
from codex.
|
|
10
|
+
from codex.status import Status
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
class
|
|
13
|
+
class DeletedImporter(CacheUpdateImporter):
|
|
13
14
|
"""Clean up database methods."""
|
|
14
15
|
|
|
15
16
|
def _remove_covers(self, delete_pks, custom=False):
|
|
16
17
|
task = CoverRemoveTask(delete_pks, custom)
|
|
17
18
|
self.librarian_queue.put(task)
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
def _bulk_folders_deleted(self, delete_folder_paths, library, **kwargs):
|
|
20
|
+
def _bulk_folders_deleted(self, **kwargs):
|
|
21
21
|
"""Bulk delete folders."""
|
|
22
|
-
if not
|
|
22
|
+
if not self.task.dirs_deleted:
|
|
23
23
|
return 0
|
|
24
|
-
|
|
24
|
+
status = Status(ImportStatusTypes.DIRS_DELETED, 0, len(self.task.dirs_deleted))
|
|
25
|
+
self.status_controller.start(status)
|
|
26
|
+
folders = Folder.objects.filter(
|
|
27
|
+
library=self.library, path__in=self.task.dirs_deleted
|
|
28
|
+
)
|
|
29
|
+
self.task.dirs_deleted = frozenset()
|
|
25
30
|
delete_comic_pks = frozenset(
|
|
26
|
-
Comic.objects.filter(library=library, folders__in=folders)
|
|
31
|
+
Comic.objects.filter(library=self.library, folders__in=folders)
|
|
27
32
|
.distinct()
|
|
28
33
|
.values_list("pk", flat=True)
|
|
29
34
|
)
|
|
@@ -31,14 +36,27 @@ class DeletedMixin(QueuedThread):
|
|
|
31
36
|
|
|
32
37
|
self._remove_covers(delete_comic_pks)
|
|
33
38
|
|
|
34
|
-
count = len(
|
|
39
|
+
count = len(delete_comic_pks)
|
|
35
40
|
if count:
|
|
36
41
|
self.log.info(
|
|
37
42
|
f"Deleted {count} folders and {len(delete_comic_pks)} comics"
|
|
38
|
-
f"from {library.path}"
|
|
43
|
+
f"from {self.library.path}"
|
|
39
44
|
)
|
|
45
|
+
self.status_controller.finish(status)
|
|
40
46
|
return count
|
|
41
47
|
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _init_deleted_comic_groups():
|
|
50
|
+
"""Init deleted_comic_groups, used later even if no deletes."""
|
|
51
|
+
deleted_comic_groups = {}
|
|
52
|
+
for field_name in COMIC_GROUP_FIELD_NAMES:
|
|
53
|
+
if field_name == "story_arc_numbers":
|
|
54
|
+
related_model = StoryArc
|
|
55
|
+
else:
|
|
56
|
+
related_model = Comic._meta.get_field(field_name).related_model
|
|
57
|
+
deleted_comic_groups[related_model] = set()
|
|
58
|
+
return deleted_comic_groups
|
|
59
|
+
|
|
42
60
|
@staticmethod
|
|
43
61
|
def _populate_deleted_comic_groups(delete_qs, deleted_comic_groups):
|
|
44
62
|
"""Populate changed groups for cover timestamp updater."""
|
|
@@ -60,21 +78,18 @@ class DeletedMixin(QueuedThread):
|
|
|
60
78
|
related_id = getattr(comic, field_name).pk
|
|
61
79
|
deleted_comic_groups[related_model].add(related_id)
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
def _init_deleted_comic_groups(deleted_comic_groups):
|
|
65
|
-
"""Init deleted_comic_groups, used later even if no deletes."""
|
|
66
|
-
for field_name in COMIC_GROUP_FIELD_NAMES:
|
|
67
|
-
related_model = Comic._meta.get_field(field_name).related_model
|
|
68
|
-
deleted_comic_groups[related_model] = set()
|
|
69
|
-
|
|
70
|
-
@status_notify(status_type=ImportStatusTypes.FILES_DELETED, updates=False)
|
|
71
|
-
def _bulk_comics_deleted(
|
|
72
|
-
self, delete_comic_paths, library, deleted_comic_groups, **kwargs
|
|
73
|
-
):
|
|
81
|
+
def _bulk_comics_deleted(self, deleted_comic_groups, **kwargs):
|
|
74
82
|
"""Bulk delete comics found missing from the filesystem."""
|
|
75
|
-
if not
|
|
83
|
+
if not self.task.files_deleted:
|
|
76
84
|
return 0
|
|
77
|
-
|
|
85
|
+
status = Status(
|
|
86
|
+
ImportStatusTypes.FILES_DELETED, 0, len(self.task.files_deleted)
|
|
87
|
+
)
|
|
88
|
+
self.status_controller.start(status)
|
|
89
|
+
delete_qs = Comic.objects.filter(
|
|
90
|
+
library=self.library, path__in=self.task.files_deleted
|
|
91
|
+
)
|
|
92
|
+
self.task.files_deleted = frozenset()
|
|
78
93
|
|
|
79
94
|
self._populate_deleted_comic_groups(delete_qs, deleted_comic_groups)
|
|
80
95
|
|
|
@@ -83,43 +98,41 @@ class DeletedMixin(QueuedThread):
|
|
|
83
98
|
|
|
84
99
|
self._remove_covers(delete_comic_pks)
|
|
85
100
|
|
|
86
|
-
count = len(
|
|
101
|
+
count = len(delete_comic_pks)
|
|
87
102
|
if count:
|
|
88
|
-
self.log.info(f"Deleted {count} comics from {library.path}")
|
|
89
|
-
|
|
103
|
+
self.log.info(f"Deleted {count} comics from {self.library.path}")
|
|
104
|
+
self.status_controller.finish(status)
|
|
90
105
|
return count
|
|
91
106
|
|
|
92
|
-
|
|
93
|
-
def _bulk_covers_deleted(self, delete_cover_paths, library, **kwargs):
|
|
107
|
+
def _bulk_covers_deleted(self, **kwargs):
|
|
94
108
|
"""Bulk delete comics found missing from the filesystem."""
|
|
95
|
-
if not
|
|
109
|
+
if not self.task.covers_deleted:
|
|
96
110
|
return 0
|
|
111
|
+
status = Status(
|
|
112
|
+
ImportStatusTypes.COVERS_DELETED, 0, len(self.task.covers_deleted)
|
|
113
|
+
)
|
|
114
|
+
self.status_controller.start(status)
|
|
97
115
|
covers = CustomCover.objects.filter(
|
|
98
|
-
library=library, path__in=
|
|
116
|
+
library=self.library, path__in=self.task.covers_deleted
|
|
99
117
|
)
|
|
118
|
+
self.task.covers_deleted = frozenset()
|
|
100
119
|
delete_cover_pks = frozenset(covers.values_list("pk", flat=True))
|
|
101
120
|
covers.delete()
|
|
102
121
|
|
|
103
122
|
self._remove_covers(delete_cover_pks, custom=True)
|
|
104
123
|
|
|
105
|
-
count = len(
|
|
124
|
+
count = len(delete_cover_pks)
|
|
106
125
|
if count:
|
|
107
|
-
self.log.info(f"Deleted {count} custom covers from {library.path}")
|
|
126
|
+
self.log.info(f"Deleted {count} custom covers from {self.library.path}")
|
|
108
127
|
|
|
128
|
+
self.status_controller.finish(status)
|
|
109
129
|
return count
|
|
110
130
|
|
|
111
|
-
def delete(self
|
|
131
|
+
def delete(self):
|
|
112
132
|
"""Delete files and folders."""
|
|
113
|
-
count = self._bulk_folders_deleted(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
self.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
120
|
-
task.files_deleted = None
|
|
121
|
-
|
|
122
|
-
count += self._bulk_covers_deleted(task.covers_deleted, library)
|
|
123
|
-
task.covers_deleted = None
|
|
124
|
-
|
|
125
|
-
return count
|
|
133
|
+
count = self._bulk_folders_deleted()
|
|
134
|
+
deleted_comic_groups = self._init_deleted_comic_groups()
|
|
135
|
+
count += self._bulk_comics_deleted(deleted_comic_groups)
|
|
136
|
+
count += self._bulk_covers_deleted()
|
|
137
|
+
self.changed += count
|
|
138
|
+
return deleted_comic_groups
|