codex 1.8.0a2__py3-none-any.whl → 1.8.0a4__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/choices/admin.py +4 -4
- codex/choices/statii.py +1 -1
- codex/librarian/covers/status.py +1 -1
- codex/librarian/librariand.py +2 -0
- codex/librarian/scribe/importer/const.py +8 -0
- codex/librarian/scribe/importer/create/foreign_keys.py +1 -1
- codex/librarian/scribe/importer/delete/covers.py +3 -1
- codex/librarian/scribe/importer/failed/__init__.py +1 -0
- codex/librarian/scribe/importer/failed/create.py +97 -0
- codex/librarian/scribe/importer/failed/failed.py +54 -0
- codex/librarian/scribe/importer/failed/query.py +103 -0
- codex/librarian/scribe/importer/init.py +2 -2
- codex/librarian/scribe/importer/link/covers.py +1 -1
- codex/librarian/scribe/importer/read/aggregate_path.py +4 -2
- codex/librarian/scribe/importer/search/__init__.py +1 -1
- codex/librarian/scribe/importer/search/update.py +45 -19
- codex/librarian/scribe/importer/statii/__init__.py +2 -0
- codex/librarian/scribe/importer/statii/failed.py +50 -0
- codex/librarian/scribe/importer/status.py +0 -12
- codex/librarian/scribe/janitor/janitor.py +13 -5
- codex/librarian/scribe/janitor/status.py +3 -2
- codex/librarian/scribe/search/optimize.py +1 -2
- codex/librarian/scribe/search/remove.py +2 -2
- codex/librarian/scribe/search/status.py +8 -8
- codex/librarian/scribe/search/sync.py +10 -3
- codex/librarian/scribe/status.py +2 -1
- codex/librarian/status.py +5 -5
- codex/librarian/status_controller.py +55 -25
- codex/librarian/watchdog/const.py +26 -2
- codex/librarian/watchdog/emitter.py +26 -34
- codex/librarian/watchdog/event_batcherd.py +18 -14
- codex/librarian/watchdog/observers.py +11 -15
- codex/migrations/0035_alter_librarianstatus_status_type.py +72 -0
- codex/startup/__init__.py +1 -1
- codex/static_root/assets/{VCheckbox-DSndl51k.1e28c443c3cb.js → VCheckbox--x5j8A4a.47af0eec9cc5.js} +1 -1
- codex/static_root/assets/VCheckbox--x5j8A4a.47af0eec9cc5.js.br +0 -0
- codex/static_root/assets/VCheckbox--x5j8A4a.47af0eec9cc5.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-DSndl51k.js → VCheckbox--x5j8A4a.js} +1 -1
- codex/static_root/assets/VCheckbox--x5j8A4a.js.br +0 -0
- codex/static_root/assets/VCheckbox--x5j8A4a.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js → VCheckboxBtn-C44aiFUU.3d08a2da4b68.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-C44aiFUU.3d08a2da4b68.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-C44aiFUU.3d08a2da4b68.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-Bu2Pf64q.js → VCheckboxBtn-C44aiFUU.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-C44aiFUU.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-C44aiFUU.js.gz +0 -0
- codex/static_root/assets/{VCombobox-Uogv6Ckp.9f900e703605.js → VCombobox-DuJ5WhJs.d4d57278cd15.js} +1 -1
- codex/static_root/assets/VCombobox-DuJ5WhJs.d4d57278cd15.js.br +0 -0
- codex/static_root/assets/VCombobox-DuJ5WhJs.d4d57278cd15.js.gz +0 -0
- codex/static_root/assets/{VCombobox-Uogv6Ckp.js → VCombobox-DuJ5WhJs.js} +1 -1
- codex/static_root/assets/VCombobox-DuJ5WhJs.js.br +0 -0
- codex/static_root/assets/VCombobox-DuJ5WhJs.js.gz +0 -0
- codex/static_root/assets/{VDialog-BzaGu1HN.34f52763c3f8.js → VDialog-BxuI97hb.250bc105e373.js} +1 -1
- codex/static_root/assets/VDialog-BxuI97hb.250bc105e373.js.br +0 -0
- codex/static_root/assets/VDialog-BxuI97hb.250bc105e373.js.gz +0 -0
- codex/static_root/assets/{VDialog-BzaGu1HN.js → VDialog-BxuI97hb.js} +1 -1
- codex/static_root/assets/VDialog-BxuI97hb.js.br +0 -0
- codex/static_root/assets/VDialog-BxuI97hb.js.gz +0 -0
- codex/static_root/assets/{VDivider-C3ikm0Ko.4938e9ced53e.js → VDivider-DSzkVD8n.9346c2b22bde.js} +1 -1
- codex/static_root/assets/VDivider-DSzkVD8n.9346c2b22bde.js.br +0 -0
- codex/static_root/assets/VDivider-DSzkVD8n.9346c2b22bde.js.gz +0 -0
- codex/static_root/assets/{VDivider-C3ikm0Ko.js → VDivider-DSzkVD8n.js} +1 -1
- codex/static_root/assets/VDivider-DSzkVD8n.js.br +0 -0
- codex/static_root/assets/VDivider-DSzkVD8n.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-AmsInZN0.5cb7c833de3d.js → VExpansionPanels-7DSA7BWQ.7fc1339ad9d6.js} +1 -1
- codex/static_root/assets/VExpansionPanels-7DSA7BWQ.7fc1339ad9d6.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-7DSA7BWQ.7fc1339ad9d6.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-AmsInZN0.js → VExpansionPanels-7DSA7BWQ.js} +1 -1
- codex/static_root/assets/VExpansionPanels-7DSA7BWQ.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-7DSA7BWQ.js.gz +0 -0
- codex/static_root/assets/{VForm-CyCdgusw.c737973a1e85.js → VForm-BZtlScrY.bf87851b598f.js} +1 -1
- codex/static_root/assets/VForm-BZtlScrY.bf87851b598f.js.br +0 -0
- codex/static_root/assets/VForm-BZtlScrY.bf87851b598f.js.gz +0 -0
- codex/static_root/assets/{VForm-CyCdgusw.js → VForm-BZtlScrY.js} +1 -1
- codex/static_root/assets/VForm-BZtlScrY.js.br +0 -0
- codex/static_root/assets/VForm-BZtlScrY.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js → VRadioGroup-CRzhTpe9.1fc9e0e7a980.js} +1 -1
- codex/static_root/assets/VRadioGroup-CRzhTpe9.1fc9e0e7a980.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CRzhTpe9.1fc9e0e7a980.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-BF0Xjrzi.js → VRadioGroup-CRzhTpe9.js} +1 -1
- codex/static_root/assets/VRadioGroup-CRzhTpe9.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CRzhTpe9.js.gz +0 -0
- codex/static_root/assets/{VSelect-Dv50OIkN.js → VSelect-_Cduank3.65530f781519.js} +1 -1
- codex/static_root/assets/VSelect-_Cduank3.65530f781519.js.br +0 -0
- codex/static_root/assets/VSelect-_Cduank3.65530f781519.js.gz +0 -0
- codex/static_root/assets/{VSelect-Dv50OIkN.390adb1fe7fa.js → VSelect-_Cduank3.js} +1 -1
- codex/static_root/assets/VSelect-_Cduank3.js.br +0 -0
- codex/static_root/assets/VSelect-_Cduank3.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-DbKYScD5.js → VSelectionControl-C0Md0bXa.0b96d6d65ba2.js} +1 -1
- codex/static_root/assets/VSelectionControl-C0Md0bXa.0b96d6d65ba2.js.br +0 -0
- codex/static_root/assets/VSelectionControl-C0Md0bXa.0b96d6d65ba2.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-DbKYScD5.8d2ab1ebe546.js → VSelectionControl-C0Md0bXa.js} +1 -1
- codex/static_root/assets/VSelectionControl-C0Md0bXa.js.br +0 -0
- codex/static_root/assets/VSelectionControl-C0Md0bXa.js.gz +0 -0
- codex/static_root/assets/{VTable-BmOfHc7J.b2e1311009d1.js → VTable-lswnBwdy.f27115046a94.js} +1 -1
- codex/static_root/assets/VTable-lswnBwdy.f27115046a94.js.br +0 -0
- codex/static_root/assets/VTable-lswnBwdy.f27115046a94.js.gz +0 -0
- codex/static_root/assets/{VTable-BmOfHc7J.js → VTable-lswnBwdy.js} +1 -1
- codex/static_root/assets/VTable-lswnBwdy.js.br +0 -0
- codex/static_root/assets/VTable-lswnBwdy.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-BLEDgagD.4b67c4a63c59.js → VWindowItem-hsPEpCj_.4bf66f9ba4b1.js} +1 -1
- codex/static_root/assets/VWindowItem-hsPEpCj_.4bf66f9ba4b1.js.br +0 -0
- codex/static_root/assets/VWindowItem-hsPEpCj_.4bf66f9ba4b1.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-BLEDgagD.js → VWindowItem-hsPEpCj_.js} +1 -1
- codex/static_root/assets/VWindowItem-hsPEpCj_.js.br +0 -0
- codex/static_root/assets/VWindowItem-hsPEpCj_.js.gz +0 -0
- codex/static_root/assets/{admin-kjMoKlqD.55a1dd908124.js → admin-6qrzqcJO.2b8351e2c2c6.js} +1 -1
- codex/static_root/assets/admin-6qrzqcJO.2b8351e2c2c6.js.br +0 -0
- codex/static_root/assets/admin-6qrzqcJO.2b8351e2c2c6.js.gz +0 -0
- codex/static_root/assets/{admin-kjMoKlqD.js → admin-6qrzqcJO.js} +1 -1
- codex/static_root/assets/admin-6qrzqcJO.js.br +0 -0
- codex/static_root/assets/admin-6qrzqcJO.js.gz +0 -0
- codex/static_root/assets/{admin-Bv40vYZw.8179e1ece835.js → admin-CVe4N6vl.5e8ec2bd60d3.js} +1 -1
- codex/static_root/assets/admin-CVe4N6vl.5e8ec2bd60d3.js.br +0 -0
- codex/static_root/assets/admin-CVe4N6vl.5e8ec2bd60d3.js.gz +0 -0
- codex/static_root/assets/{admin-Bv40vYZw.js → admin-CVe4N6vl.js} +1 -1
- codex/static_root/assets/admin-CVe4N6vl.js.br +0 -0
- codex/static_root/assets/admin-CVe4N6vl.js.gz +0 -0
- codex/static_root/assets/admin-menu-B6raGfpC.790d01e1ec98.js +1 -0
- codex/static_root/assets/admin-menu-B6raGfpC.790d01e1ec98.js.br +0 -0
- codex/static_root/assets/admin-menu-B6raGfpC.790d01e1ec98.js.gz +0 -0
- codex/static_root/assets/admin-menu-B6raGfpC.js +1 -0
- codex/static_root/assets/admin-menu-B6raGfpC.js.br +0 -0
- codex/static_root/assets/admin-menu-B6raGfpC.js.gz +0 -0
- codex/static_root/assets/{admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js → admin-settings-button-progress-D0jgpe2z.f9d1511fe4a7.js} +1 -1
- codex/static_root/assets/admin-settings-button-progress-D0jgpe2z.f9d1511fe4a7.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-D0jgpe2z.f9d1511fe4a7.js.gz +0 -0
- codex/static_root/assets/{admin-settings-button-progress-RfwaqLl2.js → admin-settings-button-progress-D0jgpe2z.js} +1 -1
- codex/static_root/assets/admin-settings-button-progress-D0jgpe2z.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-D0jgpe2z.js.gz +0 -0
- codex/static_root/assets/{browser-plYso4v5.js → browser-DPWgTJvq.aa42fd45fdc5.js} +1 -1
- codex/static_root/assets/browser-DPWgTJvq.aa42fd45fdc5.js.br +0 -0
- codex/static_root/assets/browser-DPWgTJvq.aa42fd45fdc5.js.gz +0 -0
- codex/static_root/assets/{browser-plYso4v5.87ef04b44d37.js → browser-DPWgTJvq.js} +1 -1
- codex/static_root/assets/browser-DPWgTJvq.js.br +0 -0
- codex/static_root/assets/browser-DPWgTJvq.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-DyhQwNv1.26383853ccc0.js → change-password-dialog-f0bnLsTX.ad5174bfd6b9.js} +1 -1
- codex/static_root/assets/change-password-dialog-f0bnLsTX.ad5174bfd6b9.js.br +0 -0
- codex/static_root/assets/change-password-dialog-f0bnLsTX.ad5174bfd6b9.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-DyhQwNv1.js → change-password-dialog-f0bnLsTX.js} +1 -1
- codex/static_root/assets/change-password-dialog-f0bnLsTX.js.br +0 -0
- codex/static_root/assets/change-password-dialog-f0bnLsTX.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-B7ndwV5M.d1f0728d4bd0.js → confirm-dialog-D2RCUHSr.ccb67b05d69e.js} +1 -1
- codex/static_root/assets/confirm-dialog-D2RCUHSr.ccb67b05d69e.js.br +0 -0
- codex/static_root/assets/confirm-dialog-D2RCUHSr.ccb67b05d69e.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-B7ndwV5M.js → confirm-dialog-D2RCUHSr.js} +1 -1
- codex/static_root/assets/confirm-dialog-D2RCUHSr.js.br +0 -0
- codex/static_root/assets/confirm-dialog-D2RCUHSr.js.gz +0 -0
- codex/static_root/assets/{datetime-column-DANpNGGe.13985ff7d484.js → datetime-column-C544paek.4b5c5cd44e86.js} +1 -1
- codex/static_root/assets/datetime-column-C544paek.4b5c5cd44e86.js.br +0 -0
- codex/static_root/assets/datetime-column-C544paek.4b5c5cd44e86.js.gz +0 -0
- codex/static_root/assets/{datetime-column-DANpNGGe.js → datetime-column-C544paek.js} +1 -1
- codex/static_root/assets/datetime-column-C544paek.js.br +0 -0
- codex/static_root/assets/datetime-column-C544paek.js.gz +0 -0
- codex/static_root/assets/{filter-Dhe8cVmt.ad92d3b618e3.js → filter-C2tmS7Gm.59b3cb2ccc7e.js} +1 -1
- codex/static_root/assets/filter-C2tmS7Gm.59b3cb2ccc7e.js.br +0 -0
- codex/static_root/assets/filter-C2tmS7Gm.59b3cb2ccc7e.js.gz +0 -0
- codex/static_root/assets/{filter-Dhe8cVmt.js → filter-C2tmS7Gm.js} +1 -1
- codex/static_root/assets/filter-C2tmS7Gm.js.br +0 -0
- codex/static_root/assets/filter-C2tmS7Gm.js.gz +0 -0
- codex/static_root/assets/{flag-tab-BZ9S7U8D.0b814b215567.js → flag-tab-BVUqzGNH.307659fba7b5.js} +1 -1
- codex/static_root/assets/flag-tab-BVUqzGNH.307659fba7b5.js.br +0 -0
- codex/static_root/assets/flag-tab-BVUqzGNH.307659fba7b5.js.gz +0 -0
- codex/static_root/assets/{flag-tab-BZ9S7U8D.js → flag-tab-BVUqzGNH.js} +1 -1
- codex/static_root/assets/flag-tab-BVUqzGNH.js.br +0 -0
- codex/static_root/assets/flag-tab-BVUqzGNH.js.gz +0 -0
- codex/static_root/assets/{forwardRefs-Z0d4Mnc7.js → forwardRefs-Byns6lbl.018798a57db2.js} +1 -1
- codex/static_root/assets/forwardRefs-Byns6lbl.018798a57db2.js.br +0 -0
- codex/static_root/assets/forwardRefs-Byns6lbl.018798a57db2.js.gz +0 -0
- codex/static_root/assets/{forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js → forwardRefs-Byns6lbl.js} +1 -1
- codex/static_root/assets/forwardRefs-Byns6lbl.js.br +0 -0
- codex/static_root/assets/forwardRefs-Byns6lbl.js.gz +0 -0
- codex/static_root/assets/{group-tab-B0ASBB3_.8e10b90ff052.js → group-tab-TNxZJJZ6.6d88969a9263.js} +1 -1
- codex/static_root/assets/group-tab-TNxZJJZ6.6d88969a9263.js.br +0 -0
- codex/static_root/assets/group-tab-TNxZJJZ6.6d88969a9263.js.gz +0 -0
- codex/static_root/assets/{group-tab-B0ASBB3_.js → group-tab-TNxZJJZ6.js} +1 -1
- codex/static_root/assets/group-tab-TNxZJJZ6.js.br +0 -0
- codex/static_root/assets/group-tab-TNxZJJZ6.js.gz +0 -0
- codex/static_root/assets/{http-error-BP-mMZsK.72c4d00b40d2.js → http-error-D3uGBdtN.39e149587f96.js} +1 -1
- codex/static_root/assets/http-error-D3uGBdtN.39e149587f96.js.br +0 -0
- codex/static_root/assets/http-error-D3uGBdtN.39e149587f96.js.gz +0 -0
- codex/static_root/assets/{http-error-BP-mMZsK.js → http-error-D3uGBdtN.js} +1 -1
- codex/static_root/assets/http-error-D3uGBdtN.js.br +0 -0
- codex/static_root/assets/http-error-D3uGBdtN.js.gz +0 -0
- codex/static_root/assets/{index-Cu9nQXJD.49795921eada.js → index-J6F_OMTQ.2a8861f7acc1.js} +1 -1
- codex/static_root/assets/index-J6F_OMTQ.2a8861f7acc1.js.br +0 -0
- codex/static_root/assets/index-J6F_OMTQ.2a8861f7acc1.js.gz +0 -0
- codex/static_root/assets/{index-Cu9nQXJD.js → index-J6F_OMTQ.js} +1 -1
- codex/static_root/assets/index-J6F_OMTQ.js.br +0 -0
- codex/static_root/assets/index-J6F_OMTQ.js.gz +0 -0
- codex/static_root/assets/{library-tab-D9lxhAqv.02f7064c20f3.css → library-tab-5StL67ei.0fad8998a237.css} +1 -1
- codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.br +0 -0
- codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.gz +0 -0
- codex/static_root/assets/{library-tab-D9lxhAqv.css → library-tab-5StL67ei.css} +1 -1
- codex/static_root/assets/library-tab-5StL67ei.css.br +0 -0
- codex/static_root/assets/library-tab-5StL67ei.css.gz +0 -0
- codex/static_root/assets/library-tab-DX9ZW9uM.8419900ed9b8.js +1 -0
- codex/static_root/assets/library-tab-DX9ZW9uM.8419900ed9b8.js.br +0 -0
- codex/static_root/assets/library-tab-DX9ZW9uM.8419900ed9b8.js.gz +0 -0
- codex/static_root/assets/library-tab-DX9ZW9uM.js +1 -0
- codex/static_root/assets/library-tab-DX9ZW9uM.js.br +0 -0
- codex/static_root/assets/library-tab-DX9ZW9uM.js.gz +0 -0
- codex/static_root/assets/main-CXE4elND.b45c7c290af2.js +39 -0
- codex/static_root/assets/main-CXE4elND.b45c7c290af2.js.br +0 -0
- codex/static_root/assets/main-CXE4elND.b45c7c290af2.js.gz +0 -0
- codex/static_root/assets/main-CXE4elND.js +39 -0
- codex/static_root/assets/main-CXE4elND.js.br +0 -0
- codex/static_root/assets/main-CXE4elND.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-C8QcluEe.99a4c4dddf53.js +1 -0
- codex/static_root/assets/pager-full-pdf-C8QcluEe.99a4c4dddf53.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-C8QcluEe.99a4c4dddf53.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-C8QcluEe.js +1 -0
- codex/static_root/assets/pager-full-pdf-C8QcluEe.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-C8QcluEe.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-DGfRDeRW.c3f463ad6edd.js → pagination-toolbar-BqvFln9z.d38452f8ce48.js} +1 -1
- codex/static_root/assets/pagination-toolbar-BqvFln9z.d38452f8ce48.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-BqvFln9z.d38452f8ce48.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-DGfRDeRW.js → pagination-toolbar-BqvFln9z.js} +1 -1
- codex/static_root/assets/pagination-toolbar-BqvFln9z.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-BqvFln9z.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-D6Meu4vZ.91b43d057670.js → pdf-doc-BeNzjayP.e6b65a74287b.js} +14 -14
- codex/static_root/assets/pdf-doc-BeNzjayP.e6b65a74287b.js.br +0 -0
- codex/static_root/assets/pdf-doc-BeNzjayP.e6b65a74287b.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-D6Meu4vZ.js → pdf-doc-BeNzjayP.js} +14 -14
- codex/static_root/assets/pdf-doc-BeNzjayP.js.br +0 -0
- codex/static_root/assets/pdf-doc-BeNzjayP.js.gz +0 -0
- codex/static_root/assets/reader-DG9FVXqI.366a61e33d8b.js +2 -0
- codex/static_root/assets/reader-DG9FVXqI.366a61e33d8b.js.br +0 -0
- codex/static_root/assets/reader-DG9FVXqI.366a61e33d8b.js.gz +0 -0
- codex/static_root/assets/reader-DG9FVXqI.js +2 -0
- codex/static_root/assets/reader-DG9FVXqI.js.br +0 -0
- codex/static_root/assets/reader-DG9FVXqI.js.gz +0 -0
- codex/static_root/assets/{reader-LwL05rgA.c022ad3b7b94.css → reader-HE07eoaG.8626eeb7c718.css} +1 -1
- codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.br +0 -0
- codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.gz +0 -0
- codex/static_root/assets/{reader-LwL05rgA.css → reader-HE07eoaG.css} +1 -1
- codex/static_root/assets/reader-HE07eoaG.css.br +0 -0
- codex/static_root/assets/reader-HE07eoaG.css.gz +0 -0
- codex/static_root/assets/{relation-chips-CAXZIswb.e991a259ce59.js → relation-chips-BrO8HnXq.fa4a7390c640.js} +1 -1
- codex/static_root/assets/relation-chips-BrO8HnXq.fa4a7390c640.js.br +0 -0
- codex/static_root/assets/relation-chips-BrO8HnXq.fa4a7390c640.js.gz +0 -0
- codex/static_root/assets/{relation-chips-CAXZIswb.js → relation-chips-BrO8HnXq.js} +1 -1
- codex/static_root/assets/relation-chips-BrO8HnXq.js.br +0 -0
- codex/static_root/assets/relation-chips-BrO8HnXq.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-B4gD41g6.js → settings-drawer-a2xwlRQb.41475006862d.js} +2 -2
- codex/static_root/assets/settings-drawer-a2xwlRQb.41475006862d.js.br +0 -0
- codex/static_root/assets/settings-drawer-a2xwlRQb.41475006862d.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-B4gD41g6.82718694498e.js → settings-drawer-a2xwlRQb.js} +2 -2
- codex/static_root/assets/settings-drawer-a2xwlRQb.js.br +0 -0
- codex/static_root/assets/settings-drawer-a2xwlRQb.js.gz +0 -0
- codex/static_root/assets/{ssrBoot-O6yTJ_UV.7180d77d283e.js → ssrBoot-BUdwZUw6.964a0734eff2.js} +1 -1
- codex/static_root/assets/ssrBoot-BUdwZUw6.964a0734eff2.js.br +0 -0
- codex/static_root/assets/ssrBoot-BUdwZUw6.964a0734eff2.js.gz +0 -0
- codex/static_root/assets/{ssrBoot-O6yTJ_UV.js → ssrBoot-BUdwZUw6.js} +1 -1
- codex/static_root/assets/ssrBoot-BUdwZUw6.js.br +0 -0
- codex/static_root/assets/ssrBoot-BUdwZUw6.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BZjOg19A.afb2e6b0d648.js → stats-tab-D_Sf0W-w.7dd721aef1d7.js} +1 -1
- codex/static_root/assets/stats-tab-D_Sf0W-w.7dd721aef1d7.js.br +0 -0
- codex/static_root/assets/stats-tab-D_Sf0W-w.7dd721aef1d7.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BZjOg19A.js → stats-tab-D_Sf0W-w.js} +1 -1
- codex/static_root/assets/stats-tab-D_Sf0W-w.js.br +0 -0
- codex/static_root/assets/stats-tab-D_Sf0W-w.js.gz +0 -0
- codex/static_root/assets/task-tab-CuZPm55f.827f36543dcc.js +1 -0
- codex/static_root/assets/task-tab-CuZPm55f.827f36543dcc.js.br +0 -0
- codex/static_root/assets/task-tab-CuZPm55f.827f36543dcc.js.gz +0 -0
- codex/static_root/assets/task-tab-CuZPm55f.js +1 -0
- codex/static_root/assets/task-tab-CuZPm55f.js.br +0 -0
- codex/static_root/assets/task-tab-CuZPm55f.js.gz +0 -0
- codex/static_root/assets/{unauthorized-Bo3ThIrX.12d2efd95d7d.js → unauthorized-Bx_I2aj6.4846dbaf53c3.js} +1 -1
- codex/static_root/assets/unauthorized-Bx_I2aj6.4846dbaf53c3.js.br +0 -0
- codex/static_root/assets/unauthorized-Bx_I2aj6.4846dbaf53c3.js.gz +0 -0
- codex/static_root/assets/{unauthorized-Bo3ThIrX.js → unauthorized-Bx_I2aj6.js} +1 -1
- codex/static_root/assets/unauthorized-Bx_I2aj6.js.br +0 -0
- codex/static_root/assets/unauthorized-Bx_I2aj6.js.gz +0 -0
- codex/static_root/assets/{user-tab-BQ82qBg3.17190dc83452.js → user-tab-6FMrYQKf.ac405e881ade.js} +1 -1
- codex/static_root/assets/user-tab-6FMrYQKf.ac405e881ade.js.br +0 -0
- codex/static_root/assets/user-tab-6FMrYQKf.ac405e881ade.js.gz +0 -0
- codex/static_root/assets/{user-tab-BQ82qBg3.js → user-tab-6FMrYQKf.js} +1 -1
- codex/static_root/assets/user-tab-6FMrYQKf.js.br +0 -0
- codex/static_root/assets/user-tab-6FMrYQKf.js.gz +0 -0
- codex/static_root/{manifest.0dc91d0dee6d.json → manifest.dfd8ee684697.json} +297 -297
- codex/static_root/manifest.dfd8ee684697.json.br +0 -0
- codex/static_root/manifest.dfd8ee684697.json.gz +0 -0
- codex/static_root/manifest.json +297 -297
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/views/admin/library.py +4 -1
- codex/views/browser/params.py +21 -17
- codex/views/reader/arcs.py +16 -6
- codex/views/reader/params.py +4 -1
- codex/views/session.py +1 -0
- {codex-1.8.0a2.dist-info → codex-1.8.0a4.dist-info}/METADATA +2 -2
- {codex-1.8.0a2.dist-info → codex-1.8.0a4.dist-info}/RECORD +297 -293
- codex/librarian/scribe/importer/failed_imports.py +0 -168
- codex/librarian/scribe/importer/statii/1 +0 -27
- codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.br +0 -0
- codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.gz +0 -0
- codex/static_root/assets/VCheckbox-DSndl51k.js.br +0 -0
- codex/static_root/assets/VCheckbox-DSndl51k.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.gz +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.br +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.gz +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.js.br +0 -0
- codex/static_root/assets/VCombobox-Uogv6Ckp.js.gz +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.br +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.gz +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.js.br +0 -0
- codex/static_root/assets/VDialog-BzaGu1HN.js.gz +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.br +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.gz +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.js.br +0 -0
- codex/static_root/assets/VDivider-C3ikm0Ko.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-AmsInZN0.js.gz +0 -0
- codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.br +0 -0
- codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.gz +0 -0
- codex/static_root/assets/VForm-CyCdgusw.js.br +0 -0
- codex/static_root/assets/VForm-CyCdgusw.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.gz +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.br +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.gz +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.js.br +0 -0
- codex/static_root/assets/VSelect-Dv50OIkN.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DbKYScD5.js.gz +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.br +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.gz +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.js.br +0 -0
- codex/static_root/assets/VTable-BmOfHc7J.js.gz +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.br +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.gz +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.js.br +0 -0
- codex/static_root/assets/VWindowItem-BLEDgagD.js.gz +0 -0
- codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.br +0 -0
- codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.gz +0 -0
- codex/static_root/assets/admin-Bv40vYZw.js.br +0 -0
- codex/static_root/assets/admin-Bv40vYZw.js.gz +0 -0
- codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.br +0 -0
- codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.gz +0 -0
- codex/static_root/assets/admin-kjMoKlqD.js.br +0 -0
- codex/static_root/assets/admin-kjMoKlqD.js.gz +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js +0 -1
- codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.br +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.gz +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.js +0 -1
- codex/static_root/assets/admin-menu-BNpuOmbI.js.br +0 -0
- codex/static_root/assets/admin-menu-BNpuOmbI.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.gz +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.br +0 -0
- codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.gz +0 -0
- codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.br +0 -0
- codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.gz +0 -0
- codex/static_root/assets/browser-plYso4v5.js.br +0 -0
- codex/static_root/assets/browser-plYso4v5.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DyhQwNv1.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.br +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.js.br +0 -0
- codex/static_root/assets/confirm-dialog-B7ndwV5M.js.gz +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.br +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.gz +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.js.br +0 -0
- codex/static_root/assets/datetime-column-DANpNGGe.js.gz +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.br +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.gz +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.js.br +0 -0
- codex/static_root/assets/filter-Dhe8cVmt.js.gz +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.br +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.gz +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.js.br +0 -0
- codex/static_root/assets/flag-tab-BZ9S7U8D.js.gz +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.br +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.gz +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.br +0 -0
- codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.gz +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.br +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.gz +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.js.br +0 -0
- codex/static_root/assets/group-tab-B0ASBB3_.js.gz +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.br +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.gz +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.js.br +0 -0
- codex/static_root/assets/http-error-BP-mMZsK.js.gz +0 -0
- codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.br +0 -0
- codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.gz +0 -0
- codex/static_root/assets/index-Cu9nQXJD.js.br +0 -0
- codex/static_root/assets/index-Cu9nQXJD.js.gz +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js +0 -1
- codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.br +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.gz +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.js +0 -1
- codex/static_root/assets/library-tab-8g2eSuGN.js.br +0 -0
- codex/static_root/assets/library-tab-8g2eSuGN.js.gz +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.br +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.gz +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.css.br +0 -0
- codex/static_root/assets/library-tab-D9lxhAqv.css.gz +0 -0
- codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js +0 -39
- codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.br +0 -0
- codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.gz +0 -0
- codex/static_root/assets/main-BoAlbVoF.js +0 -39
- codex/static_root/assets/main-BoAlbVoF.js.br +0 -0
- codex/static_root/assets/main-BoAlbVoF.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js +0 -1
- codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.js +0 -1
- codex/static_root/assets/pager-full-pdf-DShiSKPO.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-DShiSKPO.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.gz +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.br +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.gz +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.js.br +0 -0
- codex/static_root/assets/pdf-doc-D6Meu4vZ.js.gz +0 -0
- codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js +0 -2
- codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.br +0 -0
- codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.gz +0 -0
- codex/static_root/assets/reader-CptqnqBZ.js +0 -2
- codex/static_root/assets/reader-CptqnqBZ.js.br +0 -0
- codex/static_root/assets/reader-CptqnqBZ.js.gz +0 -0
- codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.br +0 -0
- codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.gz +0 -0
- codex/static_root/assets/reader-LwL05rgA.css.br +0 -0
- codex/static_root/assets/reader-LwL05rgA.css.gz +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.br +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.gz +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.js.br +0 -0
- codex/static_root/assets/relation-chips-CAXZIswb.js.gz +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.br +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.gz +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.js.br +0 -0
- codex/static_root/assets/settings-drawer-B4gD41g6.js.gz +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.br +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.gz +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.js.br +0 -0
- codex/static_root/assets/ssrBoot-O6yTJ_UV.js.gz +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.br +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.gz +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.js.br +0 -0
- codex/static_root/assets/stats-tab-BZjOg19A.js.gz +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js +0 -1
- codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.br +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.gz +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.js +0 -1
- codex/static_root/assets/task-tab-GP2jPkRE.js.br +0 -0
- codex/static_root/assets/task-tab-GP2jPkRE.js.gz +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.br +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.gz +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.js.br +0 -0
- codex/static_root/assets/unauthorized-Bo3ThIrX.js.gz +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.br +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.gz +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.js.br +0 -0
- codex/static_root/assets/user-tab-BQ82qBg3.js.gz +0 -0
- codex/static_root/manifest.0dc91d0dee6d.json.br +0 -0
- codex/static_root/manifest.0dc91d0dee6d.json.gz +0 -0
- {codex-1.8.0a2.dist-info → codex-1.8.0a4.dist-info}/WHEEL +0 -0
- {codex-1.8.0a2.dist-info → codex-1.8.0a4.dist-info}/entry_points.txt +0 -0
- {codex-1.8.0a2.dist-info → codex-1.8.0a4.dist-info}/licenses/LICENSE +0 -0
codex/choices/admin.py
CHANGED
|
@@ -118,23 +118,23 @@ ADMIN_TASK_GROUPS: MappingProxyType[
|
|
|
118
118
|
{
|
|
119
119
|
"value": "db_fts_rebuild",
|
|
120
120
|
"title": "Repair Search Index",
|
|
121
|
-
"desc": "Probably faster than Rebuild if integrity check fails.",
|
|
121
|
+
"desc": "Probably faster than Rebuild if the integrity check fails.",
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
"value": "search_index_abort",
|
|
125
|
-
"title": "Abort
|
|
125
|
+
"title": "Abort Search Index Sync",
|
|
126
126
|
"desc": "Aborts search index sync tasks.",
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"value": "search_index_update",
|
|
130
130
|
"title": "Sync Search Index",
|
|
131
|
-
"desc": "with recently changed comics.
|
|
131
|
+
"desc": "with recently changed comics.",
|
|
132
132
|
"confirm": "This can take a long time",
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"value": "search_index_rebuild",
|
|
136
136
|
"title": "Rebuild Search Index Using Sync.",
|
|
137
|
-
"desc": "Delete and rebuild the search index from scratch using the
|
|
137
|
+
"desc": "Delete and rebuild the search index from scratch using the syncer.",
|
|
138
138
|
"confirm": "This can take a long time",
|
|
139
139
|
},
|
|
140
140
|
),
|
codex/choices/statii.py
CHANGED
|
@@ -8,11 +8,11 @@ from codex.librarian.covers.status import COVERS_STATII
|
|
|
8
8
|
from codex.librarian.restarter.status import RESTARTER_STATII
|
|
9
9
|
from codex.librarian.scribe.importer.statii.create import CREATE_STATII
|
|
10
10
|
from codex.librarian.scribe.importer.statii.delete import REMOVE_STATII
|
|
11
|
+
from codex.librarian.scribe.importer.statii.failed import FAILED_IMPORTS_STATII
|
|
11
12
|
from codex.librarian.scribe.importer.statii.link import LINK_STATII
|
|
12
13
|
from codex.librarian.scribe.importer.statii.query import QUERY_STATII
|
|
13
14
|
from codex.librarian.scribe.importer.statii.read import READ_STATII
|
|
14
15
|
from codex.librarian.scribe.importer.statii.search import IMPORTER_SEARCH_INDEX_STATII
|
|
15
|
-
from codex.librarian.scribe.importer.status import FAILED_IMPORTS_STATII
|
|
16
16
|
from codex.librarian.scribe.janitor.status import JANITOR_STATII
|
|
17
17
|
from codex.librarian.scribe.search.status import SEARCH_INDEX_STATII
|
|
18
18
|
from codex.librarian.scribe.status import SCRIBE_STATII
|
codex/librarian/covers/status.py
CHANGED
codex/librarian/librariand.py
CHANGED
|
@@ -21,6 +21,7 @@ from codex.librarian.restarter.restarter import CodexRestarter
|
|
|
21
21
|
from codex.librarian.restarter.tasks import CodexRestarterTask
|
|
22
22
|
from codex.librarian.scribe.janitor.tasks import JanitorAdoptOrphanFoldersTask
|
|
23
23
|
from codex.librarian.scribe.scribed import ScribeThread
|
|
24
|
+
from codex.librarian.scribe.search.tasks import SearchIndexSyncTask
|
|
24
25
|
from codex.librarian.scribe.tasks import ScribeTask
|
|
25
26
|
from codex.librarian.tasks import LibrarianShutdownTask, WakeCronTask
|
|
26
27
|
from codex.librarian.watchdog.event_batcherd import WatchdogEventBatcherThread
|
|
@@ -63,6 +64,7 @@ class LibrarianDaemon(Process):
|
|
|
63
64
|
startup_tasks = (
|
|
64
65
|
JanitorAdoptOrphanFoldersTask(),
|
|
65
66
|
WatchdogSyncTask(),
|
|
67
|
+
SearchIndexSyncTask(),
|
|
66
68
|
)
|
|
67
69
|
|
|
68
70
|
for task in startup_tasks:
|
|
@@ -359,3 +359,11 @@ ALL_COMIC_GROUP_FIELD_NAMES = (
|
|
|
359
359
|
"story_arc_numbers",
|
|
360
360
|
"folders",
|
|
361
361
|
)
|
|
362
|
+
|
|
363
|
+
##########
|
|
364
|
+
# Failed #
|
|
365
|
+
##########
|
|
366
|
+
UPDATE_FIS = "update_fis"
|
|
367
|
+
CREATE_FIS = "create_fis"
|
|
368
|
+
DELETE_FI_PATHS = "delete_fi_paths"
|
|
369
|
+
BULK_UPDATE_FAILED_IMPORT_FIELDS = ("name", "stat", "updated_at")
|
|
@@ -174,7 +174,7 @@ class CreateForeignKeysCreateUpdateImporter(CreateForeignKeysFolderImporter):
|
|
|
174
174
|
self.status_controller.update(status)
|
|
175
175
|
key_args_map, update_args_map = MODEL_CREATE_ARGS_MAP[model]
|
|
176
176
|
update_objs = []
|
|
177
|
-
update_tuples = sorted(update_tuples, key=
|
|
177
|
+
update_tuples = sorted(update_tuples, key=str)
|
|
178
178
|
fts_update_pks = set()
|
|
179
179
|
for values_tuple in update_tuples:
|
|
180
180
|
key_args, update_args = self._get_create_update_args(
|
|
@@ -16,7 +16,9 @@ class DeletedCoversImporter(SearchIndexImporter):
|
|
|
16
16
|
|
|
17
17
|
def bulk_covers_deleted(self, **kwargs):
|
|
18
18
|
"""Bulk delete comics found missing from the filesystem."""
|
|
19
|
-
status = ImporterRemoveCoversStatus(
|
|
19
|
+
status = ImporterRemoveCoversStatus(
|
|
20
|
+
0, len(self.task.covers_deleted), log_success=False
|
|
21
|
+
)
|
|
20
22
|
try:
|
|
21
23
|
if not self.task.covers_deleted:
|
|
22
24
|
return 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Failed imports."""
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Update and create failed imports."""
|
|
2
|
+
|
|
3
|
+
from django.db.models.functions import Now
|
|
4
|
+
|
|
5
|
+
from codex.librarian.scribe.importer.const import (
|
|
6
|
+
BULK_UPDATE_FAILED_IMPORT_FIELDS,
|
|
7
|
+
CREATE_FIS,
|
|
8
|
+
UPDATE_FIS,
|
|
9
|
+
)
|
|
10
|
+
from codex.librarian.scribe.importer.failed.query import FailedImportsQueryImporter
|
|
11
|
+
from codex.librarian.scribe.importer.statii.failed import (
|
|
12
|
+
ImporterFailedImportsCreateStatus,
|
|
13
|
+
ImporterFailedImportsUpdateStatus,
|
|
14
|
+
)
|
|
15
|
+
from codex.models import FailedImport
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FailedImportsCreateUpdateImporter(FailedImportsQueryImporter):
|
|
19
|
+
"""Methods for failed imports."""
|
|
20
|
+
|
|
21
|
+
def _bulk_update_failed_imports(
|
|
22
|
+
self, status: ImporterFailedImportsUpdateStatus | None
|
|
23
|
+
):
|
|
24
|
+
"""Bulk update failed imports."""
|
|
25
|
+
update_failed_imports = self.metadata.pop(UPDATE_FIS, None)
|
|
26
|
+
try:
|
|
27
|
+
if not update_failed_imports:
|
|
28
|
+
return
|
|
29
|
+
if status:
|
|
30
|
+
self.status_controller.start(status)
|
|
31
|
+
update_failed_import_objs = FailedImport.objects.filter(
|
|
32
|
+
library=self.library, path__in=update_failed_imports.keys()
|
|
33
|
+
).only(*BULK_UPDATE_FAILED_IMPORT_FIELDS)
|
|
34
|
+
if not update_failed_import_objs:
|
|
35
|
+
return
|
|
36
|
+
for fi in update_failed_import_objs:
|
|
37
|
+
try:
|
|
38
|
+
exc = update_failed_imports.pop(fi.path)
|
|
39
|
+
fi.set_reason(exc)
|
|
40
|
+
fi.updated_at = Now()
|
|
41
|
+
fi.presave()
|
|
42
|
+
except OSError as exc:
|
|
43
|
+
self.log.warning(f"Presaving failed import {fi.path}: {exc}")
|
|
44
|
+
except Exception:
|
|
45
|
+
self.log.exception(
|
|
46
|
+
f"Error preparing failed import update for {fi.path}"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
FailedImport.objects.bulk_update(
|
|
50
|
+
update_failed_import_objs, fields=BULK_UPDATE_FAILED_IMPORT_FIELDS
|
|
51
|
+
)
|
|
52
|
+
count = len(update_failed_import_objs)
|
|
53
|
+
level = "INFO" if count else "DEBUG"
|
|
54
|
+
self.log.log(level, f"Updated {count} old failed imports.")
|
|
55
|
+
finally:
|
|
56
|
+
self.status_controller.finish(status)
|
|
57
|
+
|
|
58
|
+
def _bulk_create_failed_imports(
|
|
59
|
+
self, status: ImporterFailedImportsCreateStatus | None
|
|
60
|
+
):
|
|
61
|
+
"""Bulk create failed imports."""
|
|
62
|
+
create_failed_imports = self.metadata.pop(CREATE_FIS, None)
|
|
63
|
+
try:
|
|
64
|
+
if not create_failed_imports:
|
|
65
|
+
return 0
|
|
66
|
+
if status:
|
|
67
|
+
self.status_controller.start(status)
|
|
68
|
+
create_objs = []
|
|
69
|
+
for path, exc in create_failed_imports.items():
|
|
70
|
+
try:
|
|
71
|
+
fi = FailedImport(
|
|
72
|
+
library=self.library, path=path, parent_folder=None
|
|
73
|
+
)
|
|
74
|
+
fi.set_reason(exc)
|
|
75
|
+
create_objs.append(fi)
|
|
76
|
+
fi.presave()
|
|
77
|
+
except OSError:
|
|
78
|
+
self.log.warning(
|
|
79
|
+
f"Error preparing failed import create for {path}: {exc}"
|
|
80
|
+
)
|
|
81
|
+
except Exception:
|
|
82
|
+
self.log.exception(
|
|
83
|
+
f"Error preparing failed import create for {path}"
|
|
84
|
+
)
|
|
85
|
+
count = len(create_objs)
|
|
86
|
+
if count:
|
|
87
|
+
FailedImport.objects.bulk_create(
|
|
88
|
+
create_objs,
|
|
89
|
+
update_conflicts=True,
|
|
90
|
+
update_fields=BULK_UPDATE_FAILED_IMPORT_FIELDS,
|
|
91
|
+
unique_fields=FailedImport._meta.unique_together[0],
|
|
92
|
+
)
|
|
93
|
+
level = "INFO" if count else "DEBUG"
|
|
94
|
+
self.log.log(level, f"Added {count} comics to failed imports.")
|
|
95
|
+
finally:
|
|
96
|
+
self.status_controller.finish(status)
|
|
97
|
+
return count
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Update and create failed imports."""
|
|
2
|
+
|
|
3
|
+
from codex.librarian.scribe.importer.const import DELETE_FI_PATHS
|
|
4
|
+
from codex.librarian.scribe.importer.failed.create import (
|
|
5
|
+
FailedImportsCreateUpdateImporter,
|
|
6
|
+
)
|
|
7
|
+
from codex.librarian.scribe.importer.statii.failed import (
|
|
8
|
+
ImporterFailedImportsDeleteStatus,
|
|
9
|
+
)
|
|
10
|
+
from codex.models import FailedImport
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FailedImportsImporter(FailedImportsCreateUpdateImporter):
|
|
14
|
+
"""Methods for failed imports."""
|
|
15
|
+
|
|
16
|
+
def _bulk_cleanup_failed_imports(
|
|
17
|
+
self, status: ImporterFailedImportsDeleteStatus | None
|
|
18
|
+
):
|
|
19
|
+
"""Remove FailedImport objects that have since succeeded."""
|
|
20
|
+
delete_failed_imports_paths = self.metadata.pop(DELETE_FI_PATHS, None)
|
|
21
|
+
try:
|
|
22
|
+
if not delete_failed_imports_paths:
|
|
23
|
+
return 0
|
|
24
|
+
if status:
|
|
25
|
+
self.status_controller.start(status)
|
|
26
|
+
# Cleanup FailedImports that were actually successful
|
|
27
|
+
qs = FailedImport.objects.filter(library=self.library).filter(
|
|
28
|
+
path__in=delete_failed_imports_paths
|
|
29
|
+
)
|
|
30
|
+
count, _ = qs.delete()
|
|
31
|
+
level = "INFO" if count else "DEBUG"
|
|
32
|
+
self.log.log(
|
|
33
|
+
level, f"Cleaned up {count} failed imports from {self.library.path}"
|
|
34
|
+
)
|
|
35
|
+
return count
|
|
36
|
+
finally:
|
|
37
|
+
self.status_controller.finish(status)
|
|
38
|
+
|
|
39
|
+
def fail_imports(self):
|
|
40
|
+
"""Handle failed imports."""
|
|
41
|
+
created_count = 0
|
|
42
|
+
update_status = create_status = delete_status = None
|
|
43
|
+
try:
|
|
44
|
+
update_status, create_status, delete_status = self._query_failed_imports()
|
|
45
|
+
self._bulk_update_failed_imports(update_status)
|
|
46
|
+
created_count += self._bulk_create_failed_imports(create_status)
|
|
47
|
+
self._bulk_cleanup_failed_imports(delete_status)
|
|
48
|
+
except Exception:
|
|
49
|
+
self.log.exception("Processing failed imports")
|
|
50
|
+
finally:
|
|
51
|
+
self.status_controller.finish_many(
|
|
52
|
+
(update_status, create_status, delete_status)
|
|
53
|
+
)
|
|
54
|
+
self.counts.failed_imports = created_count
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Update and create failed imports."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from codex.librarian.scribe.importer.const import (
|
|
6
|
+
CREATE_FIS,
|
|
7
|
+
DELETE_FI_PATHS,
|
|
8
|
+
FIS,
|
|
9
|
+
UPDATE_FIS,
|
|
10
|
+
)
|
|
11
|
+
from codex.librarian.scribe.importer.delete import DeletedImporter
|
|
12
|
+
from codex.librarian.scribe.importer.statii.failed import (
|
|
13
|
+
ImporterFailedImportsCreateStatus,
|
|
14
|
+
ImporterFailedImportsDeleteStatus,
|
|
15
|
+
ImporterFailedImportsQueryStatus,
|
|
16
|
+
ImporterFailedImportsUpdateStatus,
|
|
17
|
+
)
|
|
18
|
+
from codex.models import Comic, FailedImport
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FailedImportsQueryImporter(DeletedImporter):
|
|
22
|
+
"""Methods for failed imports."""
|
|
23
|
+
|
|
24
|
+
def _query_failed_import_deletes(self, existing_failed_import_paths, new_fis_paths):
|
|
25
|
+
"""Calculate Deletes."""
|
|
26
|
+
untouched_failed_import_paths = existing_failed_import_paths - frozenset(
|
|
27
|
+
new_fis_paths
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
qs = Comic.objects.filter(
|
|
31
|
+
library=self.library, path__in=untouched_failed_import_paths
|
|
32
|
+
).only("path")
|
|
33
|
+
succeeded_failed_imports = frozenset(qs.values_list("path", flat=True))
|
|
34
|
+
|
|
35
|
+
possibly_missing_failed_import_paths = (
|
|
36
|
+
untouched_failed_import_paths - succeeded_failed_imports
|
|
37
|
+
)
|
|
38
|
+
missing_failed_import_paths = set()
|
|
39
|
+
for path in possibly_missing_failed_import_paths:
|
|
40
|
+
name = path.casefold()
|
|
41
|
+
# Case sensitive matching. exists() and is_file() are case insensitive.
|
|
42
|
+
# This will fail if there is a parent directory case mismatch.
|
|
43
|
+
# Rather than do a recursive solution, add it to missing if it fails.
|
|
44
|
+
try:
|
|
45
|
+
for path_obj in Path(path).parent.iterdir():
|
|
46
|
+
if path_obj.name.casefold() == name:
|
|
47
|
+
break
|
|
48
|
+
else:
|
|
49
|
+
missing_failed_import_paths.add(path)
|
|
50
|
+
except FileNotFoundError:
|
|
51
|
+
missing_failed_import_paths.add(path)
|
|
52
|
+
|
|
53
|
+
return succeeded_failed_imports | missing_failed_import_paths
|
|
54
|
+
|
|
55
|
+
def _query_failed_imports(
|
|
56
|
+
self,
|
|
57
|
+
) -> tuple[
|
|
58
|
+
ImporterFailedImportsUpdateStatus | None,
|
|
59
|
+
ImporterFailedImportsCreateStatus | None,
|
|
60
|
+
ImporterFailedImportsDeleteStatus | None,
|
|
61
|
+
]:
|
|
62
|
+
"""Determine what to do with failed imports."""
|
|
63
|
+
status = ImporterFailedImportsQueryStatus(0)
|
|
64
|
+
update_status = create_status = delete_status = None
|
|
65
|
+
try:
|
|
66
|
+
self.status_controller.start(status)
|
|
67
|
+
# Calculate creates and updates
|
|
68
|
+
fis = self.metadata.pop(FIS, {})
|
|
69
|
+
existing_failed_import_paths = set(
|
|
70
|
+
FailedImport.objects.filter(library=self.library).values_list(
|
|
71
|
+
"path", flat=True
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
status.total = len(fis) + len(existing_failed_import_paths)
|
|
75
|
+
self.status_controller.update(status)
|
|
76
|
+
self.metadata[UPDATE_FIS] = {}
|
|
77
|
+
self.metadata[CREATE_FIS] = {}
|
|
78
|
+
for path, exc in fis.items():
|
|
79
|
+
if path in existing_failed_import_paths:
|
|
80
|
+
self.metadata[UPDATE_FIS][path] = exc
|
|
81
|
+
else:
|
|
82
|
+
self.metadata[CREATE_FIS][path] = exc
|
|
83
|
+
status.increment_complete()
|
|
84
|
+
self.status_controller.update(status)
|
|
85
|
+
if num_update := len(self.metadata[UPDATE_FIS]):
|
|
86
|
+
update_status = ImporterFailedImportsUpdateStatus(0, num_update)
|
|
87
|
+
self.status_controller.update(update_status)
|
|
88
|
+
if num_create := len(self.metadata[CREATE_FIS]):
|
|
89
|
+
create_status = ImporterFailedImportsCreateStatus(0, num_create)
|
|
90
|
+
self.status_controller.update(create_status)
|
|
91
|
+
|
|
92
|
+
if DELETE_FI_PATHS not in self.metadata:
|
|
93
|
+
self.metadata[DELETE_FI_PATHS] = set()
|
|
94
|
+
self.metadata[DELETE_FI_PATHS] |= self._query_failed_import_deletes(
|
|
95
|
+
existing_failed_import_paths, fis.keys()
|
|
96
|
+
)
|
|
97
|
+
status.increment_complete(len(existing_failed_import_paths))
|
|
98
|
+
if num_delete := len(self.metadata[DELETE_FI_PATHS]):
|
|
99
|
+
delete_status = ImporterFailedImportsDeleteStatus(0, num_delete)
|
|
100
|
+
self.status_controller.update(delete_status)
|
|
101
|
+
finally:
|
|
102
|
+
self.status_controller.finish(status, notify=True)
|
|
103
|
+
return update_status, create_status, delete_status
|
|
@@ -38,7 +38,7 @@ from codex.librarian.scribe.importer.statii.query import (
|
|
|
38
38
|
)
|
|
39
39
|
from codex.librarian.scribe.importer.statii.read import (
|
|
40
40
|
ImporterAggregateStatus,
|
|
41
|
-
|
|
41
|
+
ImporterReadComicsStatus,
|
|
42
42
|
)
|
|
43
43
|
from codex.librarian.scribe.importer.statii.search import (
|
|
44
44
|
ImporterFTSCreateStatus,
|
|
@@ -214,7 +214,7 @@ class InitImporter(WorkerStatusMixin):
|
|
|
214
214
|
"""Initialize librarian statuses for modified or created ops."""
|
|
215
215
|
total_paths = len(self.task.files_modified) + len(self.task.files_created)
|
|
216
216
|
status_list += [
|
|
217
|
-
|
|
217
|
+
ImporterReadComicsStatus(0, total_paths, subtitle=path),
|
|
218
218
|
ImporterAggregateStatus(0, total_paths, subtitle=path),
|
|
219
219
|
ImporterQueryMissingTagsStatus(subtitle=path),
|
|
220
220
|
ImporterQueryComicUpdatesStatus(subtitle=path),
|
|
@@ -6,7 +6,7 @@ from codex.librarian.scribe.importer.const import (
|
|
|
6
6
|
CLASS_CUSTOM_COVER_GROUP_MAP,
|
|
7
7
|
LINK_COVER_PKS,
|
|
8
8
|
)
|
|
9
|
-
from codex.librarian.scribe.importer.
|
|
9
|
+
from codex.librarian.scribe.importer.failed.failed import FailedImportsImporter
|
|
10
10
|
from codex.librarian.scribe.importer.statii.link import ImporterLinkCoversStatus
|
|
11
11
|
from codex.models import CustomCover, Folder
|
|
12
12
|
|
|
@@ -18,8 +18,10 @@ from codex.librarian.scribe.importer.const import (
|
|
|
18
18
|
QUERY_MODELS,
|
|
19
19
|
)
|
|
20
20
|
from codex.librarian.scribe.importer.read.folders import AggregatePathMetadataImporter
|
|
21
|
+
from codex.librarian.scribe.importer.statii.failed import (
|
|
22
|
+
ImporterFailedImportsQueryStatus,
|
|
23
|
+
)
|
|
21
24
|
from codex.librarian.scribe.importer.statii.read import ImporterAggregateStatus
|
|
22
|
-
from codex.librarian.scribe.importer.status import ImporterFailedImportsStatus
|
|
23
25
|
|
|
24
26
|
_UNUSED_COMICBOX_FIELDS = (
|
|
25
27
|
"alternate_images",
|
|
@@ -102,7 +104,7 @@ class AggregateMetadataImporter(AggregatePathMetadataImporter):
|
|
|
102
104
|
fis = self.metadata[FIS].keys()
|
|
103
105
|
|
|
104
106
|
# Set statii
|
|
105
|
-
fi_status =
|
|
107
|
+
fi_status = ImporterFailedImportsQueryStatus(0, len(fis))
|
|
106
108
|
self.status_controller.update(fi_status, notify=False)
|
|
107
109
|
self.status_controller.finish(status)
|
|
108
110
|
return status.complete
|
|
@@ -21,7 +21,7 @@ class SearchIndexImporter(SearchIndexPrepareImporter):
|
|
|
21
21
|
indexer = SearchIndexer(
|
|
22
22
|
self.log, self.librarian_queue, self.db_write_lock, event=self.abort_event
|
|
23
23
|
)
|
|
24
|
-
return indexer.remove_stale_records()
|
|
24
|
+
return indexer.remove_stale_records(log_success=False)
|
|
25
25
|
|
|
26
26
|
def full_text_search(self):
|
|
27
27
|
"""Sync the fts index with the imported database."""
|
|
@@ -22,6 +22,7 @@ from codex.librarian.scribe.importer.search.sync_m2m import (
|
|
|
22
22
|
)
|
|
23
23
|
from codex.librarian.scribe.importer.statii.search import (
|
|
24
24
|
ImporterFTSCreateStatus,
|
|
25
|
+
ImporterFTSStatus,
|
|
25
26
|
ImporterFTSUpdateStatus,
|
|
26
27
|
)
|
|
27
28
|
from codex.librarian.status import Status
|
|
@@ -128,7 +129,7 @@ class SearchIndexCreateUpdateImporter(SearchIndexSyncManyToManyImporter):
|
|
|
128
129
|
*,
|
|
129
130
|
create: bool,
|
|
130
131
|
):
|
|
131
|
-
if self.abort_event.is_set():
|
|
132
|
+
if not obj_list or self.abort_event.is_set():
|
|
132
133
|
return
|
|
133
134
|
verb = "create" if create else "update"
|
|
134
135
|
verbing = (verb[:-1] + "ing").capitalize()
|
|
@@ -144,10 +145,40 @@ class SearchIndexCreateUpdateImporter(SearchIndexSyncManyToManyImporter):
|
|
|
144
145
|
|
|
145
146
|
def _update_search_index_operate_get_status(
|
|
146
147
|
self, total_entries: int, *, create: bool
|
|
147
|
-
):
|
|
148
|
+
) -> ImporterFTSStatus:
|
|
148
149
|
status_class = ImporterFTSCreateStatus if create else ImporterFTSUpdateStatus
|
|
149
150
|
return status_class(total=total_entries)
|
|
150
151
|
|
|
152
|
+
def _update_search_index_operate_create(
|
|
153
|
+
self, obj_list: list, status: ImporterFTSStatus
|
|
154
|
+
):
|
|
155
|
+
entries = self.metadata.pop(FTS_CREATE, {})
|
|
156
|
+
pks = tuple(entries.keys())
|
|
157
|
+
for pk in pks:
|
|
158
|
+
if self.abort_event.is_set():
|
|
159
|
+
return ()
|
|
160
|
+
|
|
161
|
+
entry = entries.pop(pk)
|
|
162
|
+
self._create_comicfts_entry(pk, entry, obj_list, status)
|
|
163
|
+
return pks
|
|
164
|
+
|
|
165
|
+
def _update_search_index_operate_update(
|
|
166
|
+
self, obj_list: list, status: ImporterFTSStatus
|
|
167
|
+
):
|
|
168
|
+
if pks := tuple(self.metadata.get(FTS_UPDATE, {}).keys()):
|
|
169
|
+
comicftss = ComicFTS.objects.filter(comic_id__in=pks)
|
|
170
|
+
for comicfts in comicftss:
|
|
171
|
+
if self.abort_event.is_set():
|
|
172
|
+
return ()
|
|
173
|
+
self._update_comicfts_entry(comicfts, obj_list, status)
|
|
174
|
+
if self.metadata[FTS_UPDATE]:
|
|
175
|
+
# If updates not popped, turn them into creates.
|
|
176
|
+
if FTS_CREATE not in self.metadata:
|
|
177
|
+
self.metadata[FTS_CREATE] = {}
|
|
178
|
+
self.metadata[FTS_CREATE].update(self.metadata[FTS_UPDATE])
|
|
179
|
+
self.metadata.pop(FTS_UPDATE)
|
|
180
|
+
return pks
|
|
181
|
+
|
|
151
182
|
def _update_search_index_operate(self, *, create: bool) -> tuple[int, ...]:
|
|
152
183
|
key = FTS_CREATE if create else FTS_UPDATE
|
|
153
184
|
total_entries = len(self.metadata.get(key, {}))
|
|
@@ -161,27 +192,22 @@ class SearchIndexCreateUpdateImporter(SearchIndexSyncManyToManyImporter):
|
|
|
161
192
|
self.log.debug(f"No search entries to {verb}.")
|
|
162
193
|
return updated_pks
|
|
163
194
|
self.status_controller.start(status)
|
|
195
|
+
verbing = "creating" if create else "updating"
|
|
196
|
+
self.log.debug(
|
|
197
|
+
f"Preparing {total_entries} comics for search index {verbing}..."
|
|
198
|
+
)
|
|
164
199
|
|
|
165
200
|
obj_list = []
|
|
166
201
|
if create:
|
|
167
|
-
|
|
168
|
-
pks = tuple(entries.keys())
|
|
169
|
-
for pk in pks:
|
|
170
|
-
if self.abort_event.is_set():
|
|
171
|
-
return updated_pks
|
|
172
|
-
entry = entries.pop(pk)
|
|
173
|
-
self._create_comicfts_entry(pk, entry, obj_list, status)
|
|
174
|
-
updated_pks = pks
|
|
202
|
+
updated_pks = self._update_search_index_operate_create(obj_list, status)
|
|
175
203
|
else:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
for
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
self.log.debug(f"Preparing {total_entries} comics for search indexing...")
|
|
204
|
+
updated_pks = self._update_search_index_operate_update(obj_list, status)
|
|
205
|
+
self.log.debug(
|
|
206
|
+
f"Prepared {len(obj_list)} comics for search index {verbing}..."
|
|
207
|
+
)
|
|
208
|
+
if self.abort_event.is_set():
|
|
209
|
+
return updated_pks
|
|
210
|
+
|
|
185
211
|
self._update_search_index_create_or_update(
|
|
186
212
|
obj_list,
|
|
187
213
|
status,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from codex.librarian.scribe.importer.statii.create import CREATE_STATII
|
|
4
4
|
from codex.librarian.scribe.importer.statii.delete import REMOVE_STATII
|
|
5
|
+
from codex.librarian.scribe.importer.statii.failed import FAILED_IMPORTS_STATII
|
|
5
6
|
from codex.librarian.scribe.importer.statii.link import LINK_STATII
|
|
6
7
|
from codex.librarian.scribe.importer.statii.moved import MOVED_STATII
|
|
7
8
|
from codex.librarian.scribe.importer.statii.query import QUERY_STATII
|
|
@@ -16,4 +17,5 @@ IMPORTER_STATII = (
|
|
|
16
17
|
*QUERY_STATII,
|
|
17
18
|
*READ_STATII,
|
|
18
19
|
*IMPORTER_SEARCH_INDEX_STATII,
|
|
20
|
+
*FAILED_IMPORTS_STATII,
|
|
19
21
|
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Importer Failed Imports Sattii."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC
|
|
4
|
+
|
|
5
|
+
from codex.librarian.scribe.importer.status import ImporterStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ImporterFailedImportStatus(ImporterStatus, ABC):
|
|
9
|
+
"""Importer Failed Imports Statii."""
|
|
10
|
+
|
|
11
|
+
ITEM_NAME = "failed imports"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ImporterFailedImportsQueryStatus(ImporterFailedImportStatus, ABC):
|
|
15
|
+
"""Importer Failed Imports Query Statii."""
|
|
16
|
+
|
|
17
|
+
CODE = "IFQ"
|
|
18
|
+
VERB = "Query"
|
|
19
|
+
_verbed = "Queried"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ImporterFailedImportsUpdateStatus(ImporterFailedImportStatus, ABC):
|
|
23
|
+
"""Importer Failed Imports Update Statii."""
|
|
24
|
+
|
|
25
|
+
CODE = "IFU"
|
|
26
|
+
VERB = "Update"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ImporterFailedImportsCreateStatus(ImporterFailedImportStatus, ABC):
|
|
30
|
+
"""Importer Failed Imports Create Statii."""
|
|
31
|
+
|
|
32
|
+
CODE = "IFC"
|
|
33
|
+
VERB = "Mark Failed"
|
|
34
|
+
_verbed = "Marked Failed"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ImporterFailedImportsDeleteStatus(ImporterFailedImportStatus, ABC):
|
|
38
|
+
"""Importer Failed Imports Create Statii."""
|
|
39
|
+
|
|
40
|
+
CODE = "IFD"
|
|
41
|
+
VERB = "Clean up"
|
|
42
|
+
_verbed = "Cleaned up"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
FAILED_IMPORTS_STATII = (
|
|
46
|
+
ImporterFailedImportsQueryStatus,
|
|
47
|
+
ImporterFailedImportsUpdateStatus,
|
|
48
|
+
ImporterFailedImportsCreateStatus,
|
|
49
|
+
ImporterFailedImportsDeleteStatus,
|
|
50
|
+
)
|
|
@@ -7,15 +7,3 @@ from codex.librarian.scribe.status import ScribeStatus
|
|
|
7
7
|
|
|
8
8
|
class ImporterStatus(ScribeStatus, ABC):
|
|
9
9
|
"""Importer Status."""
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ImporterFailedImportsStatus(ImporterStatus):
|
|
13
|
-
"""Importer Failed Imports Status."""
|
|
14
|
-
|
|
15
|
-
CODE = "IFI"
|
|
16
|
-
VERB = "Mark"
|
|
17
|
-
_verbed = "Marked"
|
|
18
|
-
ITEM_NAME = "failed imports"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
FAILED_IMPORTS_STATII = (ImporterFailedImportsStatus,)
|
|
@@ -13,6 +13,7 @@ from codex.librarian.scribe.janitor.status import (
|
|
|
13
13
|
JanitorCodexLatestVersionStatus,
|
|
14
14
|
JanitorDBBackupStatus,
|
|
15
15
|
JanitorDBFKIntegrityStatus,
|
|
16
|
+
JanitorDBFTSIntegrityStatus,
|
|
16
17
|
JanitorDBIntegrityStatus,
|
|
17
18
|
JanitorDBOptimizeStatus,
|
|
18
19
|
)
|
|
@@ -36,28 +37,34 @@ from codex.librarian.scribe.janitor.update import JanitorCodexUpdate
|
|
|
36
37
|
from codex.librarian.scribe.search.status import (
|
|
37
38
|
SearchIndexCleanStatus,
|
|
38
39
|
SearchIndexOptimizeStatus,
|
|
40
|
+
SearchIndexSyncCreateStatus,
|
|
41
|
+
SearchIndexSyncUpdateStatus,
|
|
39
42
|
)
|
|
40
43
|
from codex.librarian.scribe.search.tasks import (
|
|
41
44
|
SearchIndexOptimizeTask,
|
|
45
|
+
SearchIndexSyncTask,
|
|
42
46
|
)
|
|
43
47
|
from codex.models import Timestamp
|
|
44
48
|
|
|
45
49
|
_JANITOR_STATII = (
|
|
46
50
|
JanitorCodexLatestVersionStatus,
|
|
51
|
+
JanitorAdoptOrphanFoldersStatus,
|
|
52
|
+
ImporterMoveFoldersStatus,
|
|
47
53
|
JanitorDBFKIntegrityStatus,
|
|
48
54
|
JanitorDBIntegrityStatus,
|
|
49
|
-
|
|
55
|
+
JanitorDBFTSIntegrityStatus,
|
|
50
56
|
JanitorCleanupTagsStatus,
|
|
57
|
+
JanitorCleanupCoversStatus,
|
|
51
58
|
JanitorCleanupSessionsStatus,
|
|
52
59
|
JanitorCleanupBookmarksStatus,
|
|
60
|
+
SearchIndexCleanStatus,
|
|
61
|
+
SearchIndexSyncUpdateStatus,
|
|
62
|
+
SearchIndexSyncCreateStatus,
|
|
63
|
+
SearchIndexOptimizeStatus,
|
|
53
64
|
JanitorDBOptimizeStatus,
|
|
54
65
|
JanitorDBBackupStatus,
|
|
55
66
|
FindOrphanCoversStatus,
|
|
56
67
|
RemoveCoversStatus,
|
|
57
|
-
JanitorAdoptOrphanFoldersStatus,
|
|
58
|
-
ImporterMoveFoldersStatus,
|
|
59
|
-
SearchIndexCleanStatus,
|
|
60
|
-
SearchIndexOptimizeStatus,
|
|
61
68
|
)
|
|
62
69
|
|
|
63
70
|
|
|
@@ -78,6 +85,7 @@ class Janitor(JanitorCodexUpdate):
|
|
|
78
85
|
JanitorCleanCoversTask(),
|
|
79
86
|
JanitorCleanupSessionsTask(),
|
|
80
87
|
JanitorCleanupBookmarksTask(),
|
|
88
|
+
SearchIndexSyncTask(),
|
|
81
89
|
SearchIndexOptimizeTask(),
|
|
82
90
|
JanitorVacuumTask(),
|
|
83
91
|
JanitorBackupTask(),
|