codex 1.6.0a4__py3-none-any.whl → 1.6.0a5__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/exceptions.py +17 -6
- codex/integrity.py +67 -3
- codex/librarian/covers/coverd.py +2 -2
- codex/librarian/covers/create.py +29 -13
- codex/librarian/covers/path.py +8 -6
- codex/librarian/covers/purge.py +27 -16
- codex/librarian/covers/tasks.py +3 -2
- codex/librarian/importer/aggregate_metadata.py +2 -2
- codex/librarian/importer/const.py +23 -3
- codex/librarian/importer/create_fks.py +88 -28
- codex/librarian/importer/deleted.py +26 -2
- codex/librarian/importer/importerd.py +124 -27
- codex/librarian/importer/link_comics.py +55 -0
- codex/librarian/importer/moved.py +78 -3
- codex/librarian/importer/query_fks.py +65 -1
- codex/librarian/importer/status.py +6 -0
- codex/librarian/importer/tasks.py +11 -3
- codex/librarian/importer/update_comics.py +1 -3
- codex/librarian/janitor/cleanup.py +24 -0
- codex/librarian/janitor/failed_imports.py +1 -1
- codex/librarian/janitor/janitor.py +5 -0
- codex/librarian/janitor/janitord.py +1 -1
- codex/librarian/janitor/status.py +1 -0
- codex/librarian/janitor/tasks.py +5 -0
- codex/librarian/librariand.py +3 -3
- codex/librarian/search/update.py +1 -1
- codex/librarian/watchdog/db_snapshot.py +9 -6
- codex/librarian/watchdog/emitter.py +3 -0
- codex/librarian/watchdog/event_batcherd.py +19 -3
- codex/librarian/watchdog/events.py +176 -36
- codex/librarian/watchdog/observers.py +13 -3
- codex/migrations/0027_sort_name.py +2 -12
- codex/migrations/0028_custom_covers.py +166 -0
- codex/models/admin.py +0 -1
- codex/models/base.py +3 -0
- codex/models/comic.py +15 -9
- codex/models/groups.py +30 -14
- codex/models/library.py +11 -3
- codex/models/paths.py +62 -14
- codex/models/{const.py → util.py} +15 -2
- codex/serializers/admin.py +11 -2
- codex/serializers/browser/mixins.py +1 -0
- codex/serializers/browser/settings.py +3 -0
- codex/settings/settings.py +11 -5
- codex/startup.py +77 -3
- codex/static_root/assets/{VCheckbox-CN6Sn_k7.9bf27129091c.js → VCheckbox-BF_99tgB.7fe59e56d9d4.js} +1 -1
- codex/static_root/assets/VCheckbox-BF_99tgB.7fe59e56d9d4.js.br +0 -0
- codex/static_root/assets/VCheckbox-BF_99tgB.7fe59e56d9d4.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-CN6Sn_k7.js → VCheckbox-BF_99tgB.js} +1 -1
- codex/static_root/assets/VCheckbox-BF_99tgB.js.br +0 -0
- codex/static_root/assets/VCheckbox-BF_99tgB.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CN1RPZPQ.b763c6a7abaf.js → VCheckboxBtn-Coc7g8m7.31e1e6aa44c9.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-Coc7g8m7.31e1e6aa44c9.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Coc7g8m7.31e1e6aa44c9.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CN1RPZPQ.js → VCheckboxBtn-Coc7g8m7.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-Coc7g8m7.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Coc7g8m7.js.gz +0 -0
- codex/static_root/assets/VCombobox-CTRWnOuM.0f00903c2ebc.js +1 -0
- codex/static_root/assets/VCombobox-CTRWnOuM.0f00903c2ebc.js.br +0 -0
- codex/static_root/assets/VCombobox-CTRWnOuM.0f00903c2ebc.js.gz +0 -0
- codex/static_root/assets/VCombobox-CTRWnOuM.js +1 -0
- codex/static_root/assets/VCombobox-CTRWnOuM.js.br +0 -0
- codex/static_root/assets/VCombobox-CTRWnOuM.js.gz +0 -0
- codex/static_root/assets/{VDialog-DC3KGsMT.71e2a460e44b.js → VDialog-pzwzInEh.51acf566a069.js} +1 -1
- codex/static_root/assets/VDialog-pzwzInEh.51acf566a069.js.br +0 -0
- codex/static_root/assets/VDialog-pzwzInEh.51acf566a069.js.gz +0 -0
- codex/static_root/assets/{VDialog-DC3KGsMT.js → VDialog-pzwzInEh.js} +1 -1
- codex/static_root/assets/VDialog-pzwzInEh.js.br +0 -0
- codex/static_root/assets/VDialog-pzwzInEh.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-DJQYXCn2.f0d471a1b80a.js → VExpansionPanels-CKSq1GpG.0ecf702c5b67.js} +1 -1
- codex/static_root/assets/VExpansionPanels-CKSq1GpG.0ecf702c5b67.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CKSq1GpG.0ecf702c5b67.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-DJQYXCn2.js → VExpansionPanels-CKSq1GpG.js} +1 -1
- codex/static_root/assets/VExpansionPanels-CKSq1GpG.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-CKSq1GpG.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-CgodTThy.b20290d57146.js → VRadioGroup-CW5GobGU.b72925bca3de.js} +1 -1
- codex/static_root/assets/VRadioGroup-CW5GobGU.b72925bca3de.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CW5GobGU.b72925bca3de.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-CgodTThy.js → VRadioGroup-CW5GobGU.js} +1 -1
- codex/static_root/assets/VRadioGroup-CW5GobGU.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CW5GobGU.js.gz +0 -0
- codex/static_root/assets/VSelect-ChOlLRyH.00b11751b25e.js +1 -0
- codex/static_root/assets/VSelect-ChOlLRyH.00b11751b25e.js.br +0 -0
- codex/static_root/assets/VSelect-ChOlLRyH.00b11751b25e.js.gz +0 -0
- codex/static_root/assets/VSelect-ChOlLRyH.js +1 -0
- codex/static_root/assets/VSelect-ChOlLRyH.js.br +0 -0
- codex/static_root/assets/VSelect-ChOlLRyH.js.gz +0 -0
- codex/static_root/assets/VSelect-MGVSeLgr.7cabd30bc5e4.css +1 -0
- 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 +1 -0
- 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-zPp4DXWq.635b7f5aa882.js → VSelectionControl-DKOhc2zB.061dca094303.js} +1 -1
- codex/static_root/assets/VSelectionControl-DKOhc2zB.061dca094303.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DKOhc2zB.061dca094303.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-zPp4DXWq.js → VSelectionControl-DKOhc2zB.js} +1 -1
- codex/static_root/assets/VSelectionControl-DKOhc2zB.js.br +0 -0
- codex/static_root/assets/VSelectionControl-DKOhc2zB.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-pK9Xompk.67014b86fc74.js → VSlideGroup-zFz5_byd.e0e246b7acbb.js} +1 -1
- codex/static_root/assets/VSlideGroup-zFz5_byd.e0e246b7acbb.js.br +0 -0
- codex/static_root/assets/VSlideGroup-zFz5_byd.e0e246b7acbb.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-pK9Xompk.js → VSlideGroup-zFz5_byd.js} +1 -1
- codex/static_root/assets/VSlideGroup-zFz5_byd.js.br +0 -0
- codex/static_root/assets/VSlideGroup-zFz5_byd.js.gz +0 -0
- codex/static_root/assets/{VTable-CMi6sDtP.8445f91d9023.js → VTable-FKMTcdkF.6c1eed84d25e.js} +1 -1
- codex/static_root/assets/VTable-FKMTcdkF.6c1eed84d25e.js.br +0 -0
- codex/static_root/assets/VTable-FKMTcdkF.6c1eed84d25e.js.gz +0 -0
- codex/static_root/assets/{VTable-CMi6sDtP.js → VTable-FKMTcdkF.js} +1 -1
- codex/static_root/assets/VTable-FKMTcdkF.js.br +0 -0
- codex/static_root/assets/VTable-FKMTcdkF.js.gz +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css +1 -0
- codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.br +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.gz +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.css +1 -0
- codex/static_root/assets/VTextField-BssVoDhB.css.br +0 -0
- codex/static_root/assets/VTextField-BssVoDhB.css.gz +0 -0
- codex/static_root/assets/VTextField-Dftcik85.cb2f1dda87e1.js +1 -0
- codex/static_root/assets/VTextField-Dftcik85.cb2f1dda87e1.js.br +0 -0
- codex/static_root/assets/VTextField-Dftcik85.cb2f1dda87e1.js.gz +0 -0
- codex/static_root/assets/VTextField-Dftcik85.js +1 -0
- codex/static_root/assets/VTextField-Dftcik85.js.br +0 -0
- codex/static_root/assets/VTextField-Dftcik85.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-DNsRQx9l.c42f636c386e.js → VWindowItem-CYCwnt3s.28025dc36c6a.js} +1 -1
- codex/static_root/assets/VWindowItem-CYCwnt3s.28025dc36c6a.js.br +0 -0
- codex/static_root/assets/VWindowItem-CYCwnt3s.28025dc36c6a.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-DNsRQx9l.js → VWindowItem-CYCwnt3s.js} +1 -1
- codex/static_root/assets/VWindowItem-CYCwnt3s.js.br +0 -0
- codex/static_root/assets/VWindowItem-CYCwnt3s.js.gz +0 -0
- codex/static_root/assets/{admin-BbrOU9Y9.29936748af9e.css → admin-B8Bp2Uih.82c98714bcf1.css} +1 -1
- codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.br +0 -0
- codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.gz +0 -0
- codex/static_root/assets/{admin-BbrOU9Y9.css → admin-B8Bp2Uih.css} +1 -1
- codex/static_root/assets/admin-B8Bp2Uih.css.br +0 -0
- codex/static_root/assets/admin-B8Bp2Uih.css.gz +0 -0
- codex/static_root/assets/admin-DH_DrB0F.dc45fb726e07.js +1 -0
- codex/static_root/assets/admin-DH_DrB0F.dc45fb726e07.js.br +0 -0
- codex/static_root/assets/admin-DH_DrB0F.dc45fb726e07.js.gz +0 -0
- codex/static_root/assets/admin-DH_DrB0F.js +1 -0
- codex/static_root/assets/admin-DH_DrB0F.js.br +0 -0
- codex/static_root/assets/admin-DH_DrB0F.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-B2rmpAVA.a9e72fbfdadc.js +30 -0
- codex/static_root/assets/admin-drawer-panel-B2rmpAVA.a9e72fbfdadc.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-B2rmpAVA.a9e72fbfdadc.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-B2rmpAVA.js +30 -0
- codex/static_root/assets/admin-drawer-panel-B2rmpAVA.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-B2rmpAVA.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css +1 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.bd2c1d6148bb.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.css +1 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BHdNPwzF.css.gz +0 -0
- codex/static_root/assets/browser-CpppBvim.a1b5d4fe97b1.css +1 -0
- codex/static_root/assets/browser-CpppBvim.a1b5d4fe97b1.css.br +0 -0
- codex/static_root/assets/browser-CpppBvim.a1b5d4fe97b1.css.gz +0 -0
- codex/static_root/assets/browser-CpppBvim.css +1 -0
- codex/static_root/assets/browser-CpppBvim.css.br +0 -0
- codex/static_root/assets/browser-CpppBvim.css.gz +0 -0
- codex/static_root/assets/browser-lKU7rqLd.cdb86e625ed9.js +1 -0
- codex/static_root/assets/browser-lKU7rqLd.cdb86e625ed9.js.br +0 -0
- codex/static_root/assets/browser-lKU7rqLd.cdb86e625ed9.js.gz +0 -0
- codex/static_root/assets/browser-lKU7rqLd.js +1 -0
- codex/static_root/assets/browser-lKU7rqLd.js.br +0 -0
- codex/static_root/assets/browser-lKU7rqLd.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-BHTkpC6Z.2d5d5dd57ad3.js → change-password-dialog-BIBG6Bk8.3583021c124a.js} +1 -1
- codex/static_root/assets/change-password-dialog-BIBG6Bk8.3583021c124a.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BIBG6Bk8.3583021c124a.js.gz +0 -0
- codex/static_root/assets/{change-password-dialog-BHTkpC6Z.js → change-password-dialog-BIBG6Bk8.js} +1 -1
- codex/static_root/assets/change-password-dialog-BIBG6Bk8.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BIBG6Bk8.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DmXGDg4z.284812bd376d.js → confirm-dialog-DARLmXRf.53fc6938fb8c.js} +1 -1
- codex/static_root/assets/confirm-dialog-DARLmXRf.53fc6938fb8c.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DARLmXRf.53fc6938fb8c.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DmXGDg4z.js → confirm-dialog-DARLmXRf.js} +1 -1
- codex/static_root/assets/confirm-dialog-DARLmXRf.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DARLmXRf.js.gz +0 -0
- codex/static_root/assets/{datetime-column-DKaH5S3z.5c6042016200.js → datetime-column-LpLgWpkf.16ce3324970f.js} +1 -1
- codex/static_root/assets/datetime-column-LpLgWpkf.16ce3324970f.js.br +0 -0
- codex/static_root/assets/datetime-column-LpLgWpkf.16ce3324970f.js.gz +0 -0
- codex/static_root/assets/{datetime-column-DKaH5S3z.js → datetime-column-LpLgWpkf.js} +1 -1
- codex/static_root/assets/datetime-column-LpLgWpkf.js.br +0 -0
- codex/static_root/assets/datetime-column-LpLgWpkf.js.gz +0 -0
- codex/static_root/assets/{filter-DUVATQW3.e1e7aa6d0b18.js → filter-jRB1Ob6r.6a559a53e805.js} +1 -1
- codex/static_root/assets/filter-jRB1Ob6r.6a559a53e805.js.br +0 -0
- codex/static_root/assets/filter-jRB1Ob6r.6a559a53e805.js.gz +0 -0
- codex/static_root/assets/{filter-DUVATQW3.js → filter-jRB1Ob6r.js} +1 -1
- codex/static_root/assets/filter-jRB1Ob6r.js.br +0 -0
- codex/static_root/assets/filter-jRB1Ob6r.js.gz +0 -0
- codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +1 -0
- codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
- codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
- codex/static_root/assets/flag-tab-BNwbLfrN.css +1 -0
- codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
- codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
- codex/static_root/assets/flag-tab-mYS2wg5e.17829c46cae9.js +1 -0
- codex/static_root/assets/flag-tab-mYS2wg5e.17829c46cae9.js.br +0 -0
- codex/static_root/assets/flag-tab-mYS2wg5e.17829c46cae9.js.gz +0 -0
- codex/static_root/assets/flag-tab-mYS2wg5e.js +1 -0
- codex/static_root/assets/flag-tab-mYS2wg5e.js.br +0 -0
- codex/static_root/assets/flag-tab-mYS2wg5e.js.gz +0 -0
- codex/static_root/assets/{group-tab-D3CyU-Il.fbf9ce5ef593.js → group-tab-MK1lcjUU.98406d5babdc.js} +1 -1
- codex/static_root/assets/group-tab-MK1lcjUU.98406d5babdc.js.br +0 -0
- codex/static_root/assets/group-tab-MK1lcjUU.98406d5babdc.js.gz +0 -0
- codex/static_root/assets/{group-tab-D3CyU-Il.js → group-tab-MK1lcjUU.js} +1 -1
- codex/static_root/assets/group-tab-MK1lcjUU.js.br +0 -0
- codex/static_root/assets/group-tab-MK1lcjUU.js.gz +0 -0
- codex/static_root/assets/{http-error-0ef6-Ajc.e2879bcd242f.js → http-error-HFeYnF0n.a3c578a0265e.js} +1 -1
- codex/static_root/assets/http-error-HFeYnF0n.a3c578a0265e.js.br +0 -0
- codex/static_root/assets/http-error-HFeYnF0n.a3c578a0265e.js.gz +0 -0
- codex/static_root/assets/{http-error-0ef6-Ajc.js → http-error-HFeYnF0n.js} +1 -1
- codex/static_root/assets/http-error-HFeYnF0n.js.br +0 -0
- codex/static_root/assets/http-error-HFeYnF0n.js.gz +0 -0
- codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css +1 -0
- codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.br +0 -0
- codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.gz +0 -0
- codex/static_root/assets/library-tab-BN0SfPcH.css +1 -0
- codex/static_root/assets/library-tab-BN0SfPcH.css.br +0 -0
- codex/static_root/assets/library-tab-BN0SfPcH.css.gz +0 -0
- codex/static_root/assets/library-tab-DYeEBYlT.a2a2ef088d1c.js +1 -0
- codex/static_root/assets/library-tab-DYeEBYlT.a2a2ef088d1c.js.br +0 -0
- codex/static_root/assets/library-tab-DYeEBYlT.a2a2ef088d1c.js.gz +0 -0
- codex/static_root/assets/library-tab-DYeEBYlT.js +1 -0
- codex/static_root/assets/library-tab-DYeEBYlT.js.br +0 -0
- codex/static_root/assets/library-tab-DYeEBYlT.js.gz +0 -0
- codex/static_root/assets/{main-CuzJev9T.js → main-gSW7TFDY.329223b148d4.js} +6 -6
- codex/static_root/assets/main-gSW7TFDY.329223b148d4.js.br +0 -0
- codex/static_root/assets/main-gSW7TFDY.329223b148d4.js.gz +0 -0
- codex/static_root/assets/{main-CuzJev9T.f58771cc37e2.js → main-gSW7TFDY.js} +6 -6
- codex/static_root/assets/main-gSW7TFDY.js.br +0 -0
- codex/static_root/assets/main-gSW7TFDY.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-B3wS4_7p.7695fafdefce.css → pagination-toolbar-ClZui9Zf.697d7ae11c21.css} +1 -1
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.697d7ae11c21.css.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-B3wS4_7p.css → pagination-toolbar-ClZui9Zf.css} +1 -1
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-ClZui9Zf.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dlm70Bhs.8f23f8bd9a05.js +1 -0
- codex/static_root/assets/pagination-toolbar-Dlm70Bhs.8f23f8bd9a05.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dlm70Bhs.8f23f8bd9a05.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-Dlm70Bhs.js +1 -0
- codex/static_root/assets/pagination-toolbar-Dlm70Bhs.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-Dlm70Bhs.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-BlU5mm5n.0431bcdf48d1.js → pdf-doc-BTdS9hUz.7c966524280a.js} +1 -1
- codex/static_root/assets/pdf-doc-BTdS9hUz.7c966524280a.js.br +0 -0
- codex/static_root/assets/pdf-doc-BTdS9hUz.7c966524280a.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-BlU5mm5n.js → pdf-doc-BTdS9hUz.js} +1 -1
- codex/static_root/assets/pdf-doc-BTdS9hUz.js.br +0 -0
- codex/static_root/assets/pdf-doc-BTdS9hUz.js.gz +0 -0
- codex/static_root/assets/{reader-s7jttB_F.f7b43b04961a.js → reader-BtSTIETq.f940f66c0e58.js} +2 -2
- codex/static_root/assets/reader-BtSTIETq.f940f66c0e58.js.br +0 -0
- codex/static_root/assets/reader-BtSTIETq.f940f66c0e58.js.gz +0 -0
- codex/static_root/assets/{reader-s7jttB_F.js → reader-BtSTIETq.js} +2 -2
- codex/static_root/assets/reader-BtSTIETq.js.br +0 -0
- codex/static_root/assets/reader-BtSTIETq.js.gz +0 -0
- codex/static_root/assets/{reader-BiKxuxj7.css → reader-CF3xt6JG.19fad7f62450.css} +1 -1
- codex/static_root/assets/reader-CF3xt6JG.19fad7f62450.css.br +0 -0
- codex/static_root/assets/reader-CF3xt6JG.19fad7f62450.css.gz +0 -0
- codex/static_root/assets/{reader-BiKxuxj7.dabe592f46f1.css → reader-CF3xt6JG.css} +1 -1
- codex/static_root/assets/reader-CF3xt6JG.css.br +0 -0
- codex/static_root/assets/reader-CF3xt6JG.css.gz +0 -0
- codex/static_root/assets/{relation-chips-D6T6FX7G.css → relation-chips-Bsc-gUxE.98e65384c3c9.css} +1 -1
- codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.br +0 -0
- codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.gz +0 -0
- codex/static_root/assets/{relation-chips-D6T6FX7G.db095b2497e4.css → relation-chips-Bsc-gUxE.css} +1 -1
- codex/static_root/assets/relation-chips-Bsc-gUxE.css.br +0 -0
- codex/static_root/assets/relation-chips-Bsc-gUxE.css.gz +0 -0
- codex/static_root/assets/relation-chips-C4Ob7ySi.95855a010f4a.js +1 -0
- codex/static_root/assets/relation-chips-C4Ob7ySi.95855a010f4a.js.br +0 -0
- codex/static_root/assets/relation-chips-C4Ob7ySi.95855a010f4a.js.gz +0 -0
- codex/static_root/assets/relation-chips-C4Ob7ySi.js +1 -0
- codex/static_root/assets/relation-chips-C4Ob7ySi.js.br +0 -0
- codex/static_root/assets/relation-chips-C4Ob7ySi.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-DbJuixzh.352aaaab5925.js → settings-drawer-xSctoxZn.4ce8afcb879a.js} +2 -2
- codex/static_root/assets/settings-drawer-xSctoxZn.4ce8afcb879a.js.br +0 -0
- codex/static_root/assets/settings-drawer-xSctoxZn.4ce8afcb879a.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-DbJuixzh.js → settings-drawer-xSctoxZn.js} +2 -2
- codex/static_root/assets/settings-drawer-xSctoxZn.js.br +0 -0
- codex/static_root/assets/settings-drawer-xSctoxZn.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BhRLh7XB.7be95b5021c3.js → stats-tab-C_uC_U7o.e6b014b6e8c6.js} +1 -1
- codex/static_root/assets/stats-tab-C_uC_U7o.e6b014b6e8c6.js.br +0 -0
- codex/static_root/assets/stats-tab-C_uC_U7o.e6b014b6e8c6.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BhRLh7XB.js → stats-tab-C_uC_U7o.js} +1 -1
- codex/static_root/assets/stats-tab-C_uC_U7o.js.br +0 -0
- codex/static_root/assets/stats-tab-C_uC_U7o.js.gz +0 -0
- codex/static_root/assets/task-tab-VIpy1Ula.c07877250c88.js +1 -0
- codex/static_root/assets/task-tab-VIpy1Ula.c07877250c88.js.br +0 -0
- codex/static_root/assets/task-tab-VIpy1Ula.c07877250c88.js.gz +0 -0
- codex/static_root/assets/task-tab-VIpy1Ula.js +1 -0
- codex/static_root/assets/task-tab-VIpy1Ula.js.br +0 -0
- codex/static_root/assets/task-tab-VIpy1Ula.js.gz +0 -0
- codex/static_root/assets/{unauthorized-BgXQnNpn.f63b36d526b5.js → unauthorized-kEuFL5br.475729603aeb.js} +1 -1
- codex/static_root/assets/unauthorized-kEuFL5br.475729603aeb.js.br +0 -0
- codex/static_root/assets/unauthorized-kEuFL5br.475729603aeb.js.gz +0 -0
- codex/static_root/assets/{unauthorized-BgXQnNpn.js → unauthorized-kEuFL5br.js} +1 -1
- codex/static_root/assets/unauthorized-kEuFL5br.js.br +0 -0
- codex/static_root/assets/unauthorized-kEuFL5br.js.gz +0 -0
- codex/static_root/assets/{user-tab-cZoJDlb-.2a497e8b2b24.js → user-tab-CZNFTTEI.f3940a75daae.js} +1 -1
- codex/static_root/assets/user-tab-CZNFTTEI.f3940a75daae.js.br +0 -0
- codex/static_root/assets/user-tab-CZNFTTEI.f3940a75daae.js.gz +0 -0
- codex/static_root/assets/{user-tab-cZoJDlb-.js → user-tab-CZNFTTEI.js} +1 -1
- codex/static_root/assets/user-tab-CZNFTTEI.js.br +0 -0
- codex/static_root/assets/user-tab-CZNFTTEI.js.gz +0 -0
- codex/static_root/js/choices-admin.ef1ff3a8b9da.json +1 -0
- 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-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.b60817ba0a93.json → choices.23fedac2b9ba.json} +1 -1
- codex/static_root/js/choices.23fedac2b9ba.json.br +0 -0
- codex/static_root/js/choices.23fedac2b9ba.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.6ef112683dae.json +642 -0
- codex/static_root/manifest.6ef112683dae.json.br +0 -0
- codex/static_root/manifest.6ef112683dae.json.gz +0 -0
- codex/static_root/manifest.json +254 -254
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/status_controller.py +11 -2
- codex/views/admin/library.py +47 -27
- codex/views/admin/stats.py +4 -1
- codex/views/admin/tasks.py +6 -1
- codex/views/browser/base.py +2 -2
- codex/views/browser/browser.py +1 -2
- codex/views/browser/browser_annotations.py +87 -17
- codex/views/browser/browser_breadcrumbs.py +2 -2
- codex/views/browser/browser_order_by.py +31 -20
- codex/views/browser/filters/search.py +1 -1
- codex/views/browser/metadata.py +0 -1
- codex/views/cover.py +3 -2
- codex/views/session.py +1 -0
- {codex-1.6.0a4.dist-info → codex-1.6.0a5.dist-info}/METADATA +3 -2
- {codex-1.6.0a4.dist-info → codex-1.6.0a5.dist-info}/RECORD +340 -339
- codex/static_root/assets/VCheckbox-CN6Sn_k7.9bf27129091c.js.br +0 -0
- codex/static_root/assets/VCheckbox-CN6Sn_k7.9bf27129091c.js.gz +0 -0
- codex/static_root/assets/VCheckbox-CN6Sn_k7.js.br +0 -0
- codex/static_root/assets/VCheckbox-CN6Sn_k7.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CN1RPZPQ.b763c6a7abaf.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CN1RPZPQ.b763c6a7abaf.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CN1RPZPQ.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CN1RPZPQ.js.gz +0 -0
- codex/static_root/assets/VCombobox-CtLUGYtD.6e49097cea2c.js +0 -1
- codex/static_root/assets/VCombobox-CtLUGYtD.6e49097cea2c.js.br +0 -0
- codex/static_root/assets/VCombobox-CtLUGYtD.6e49097cea2c.js.gz +0 -0
- codex/static_root/assets/VCombobox-CtLUGYtD.js +0 -1
- codex/static_root/assets/VCombobox-CtLUGYtD.js.br +0 -0
- codex/static_root/assets/VCombobox-CtLUGYtD.js.gz +0 -0
- codex/static_root/assets/VDialog-DC3KGsMT.71e2a460e44b.js.br +0 -0
- codex/static_root/assets/VDialog-DC3KGsMT.71e2a460e44b.js.gz +0 -0
- codex/static_root/assets/VDialog-DC3KGsMT.js.br +0 -0
- codex/static_root/assets/VDialog-DC3KGsMT.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DJQYXCn2.f0d471a1b80a.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DJQYXCn2.f0d471a1b80a.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DJQYXCn2.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DJQYXCn2.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-CgodTThy.b20290d57146.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CgodTThy.b20290d57146.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-CgodTThy.js.br +0 -0
- codex/static_root/assets/VRadioGroup-CgodTThy.js.gz +0 -0
- codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css +0 -1
- 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 +0 -1
- 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-B6s-x36h.de1030c82785.js +0 -1
- codex/static_root/assets/VSelect-B6s-x36h.de1030c82785.js.br +0 -0
- codex/static_root/assets/VSelect-B6s-x36h.de1030c82785.js.gz +0 -0
- codex/static_root/assets/VSelect-B6s-x36h.js +0 -1
- codex/static_root/assets/VSelect-B6s-x36h.js.br +0 -0
- codex/static_root/assets/VSelect-B6s-x36h.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-zPp4DXWq.635b7f5aa882.js.br +0 -0
- codex/static_root/assets/VSelectionControl-zPp4DXWq.635b7f5aa882.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-zPp4DXWq.js.br +0 -0
- codex/static_root/assets/VSelectionControl-zPp4DXWq.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-pK9Xompk.67014b86fc74.js.br +0 -0
- codex/static_root/assets/VSlideGroup-pK9Xompk.67014b86fc74.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-pK9Xompk.js.br +0 -0
- codex/static_root/assets/VSlideGroup-pK9Xompk.js.gz +0 -0
- codex/static_root/assets/VTable-CMi6sDtP.8445f91d9023.js.br +0 -0
- codex/static_root/assets/VTable-CMi6sDtP.8445f91d9023.js.gz +0 -0
- codex/static_root/assets/VTable-CMi6sDtP.js.br +0 -0
- codex/static_root/assets/VTable-CMi6sDtP.js.gz +0 -0
- codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css +0 -1
- codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.br +0 -0
- codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.gz +0 -0
- codex/static_root/assets/VTextField-DuIIp-VY.css +0 -1
- codex/static_root/assets/VTextField-DuIIp-VY.css.br +0 -0
- codex/static_root/assets/VTextField-DuIIp-VY.css.gz +0 -0
- codex/static_root/assets/VTextField-dMTizQEN.e93eefec0fdf.js +0 -1
- codex/static_root/assets/VTextField-dMTizQEN.e93eefec0fdf.js.br +0 -0
- codex/static_root/assets/VTextField-dMTizQEN.e93eefec0fdf.js.gz +0 -0
- codex/static_root/assets/VTextField-dMTizQEN.js +0 -1
- codex/static_root/assets/VTextField-dMTizQEN.js.br +0 -0
- codex/static_root/assets/VTextField-dMTizQEN.js.gz +0 -0
- codex/static_root/assets/VWindowItem-DNsRQx9l.c42f636c386e.js.br +0 -0
- codex/static_root/assets/VWindowItem-DNsRQx9l.c42f636c386e.js.gz +0 -0
- codex/static_root/assets/VWindowItem-DNsRQx9l.js.br +0 -0
- codex/static_root/assets/VWindowItem-DNsRQx9l.js.gz +0 -0
- codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.br +0 -0
- codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.gz +0 -0
- codex/static_root/assets/admin-BbrOU9Y9.css.br +0 -0
- codex/static_root/assets/admin-BbrOU9Y9.css.gz +0 -0
- codex/static_root/assets/admin-CApphpty.5a41cbf0eefc.js +0 -1
- codex/static_root/assets/admin-CApphpty.5a41cbf0eefc.js.br +0 -0
- codex/static_root/assets/admin-CApphpty.5a41cbf0eefc.js.gz +0 -0
- codex/static_root/assets/admin-CApphpty.js +0 -1
- codex/static_root/assets/admin-CApphpty.js.br +0 -0
- codex/static_root/assets/admin-CApphpty.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css +0 -1
- codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css +0 -1
- codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-Dp8KD9D7.a79eda3055a7.js +0 -30
- codex/static_root/assets/admin-drawer-panel-Dp8KD9D7.a79eda3055a7.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-Dp8KD9D7.a79eda3055a7.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-Dp8KD9D7.js +0 -30
- codex/static_root/assets/admin-drawer-panel-Dp8KD9D7.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-Dp8KD9D7.js.gz +0 -0
- codex/static_root/assets/browser-C_PHQbyN.bb065e2ce21a.js +0 -1
- codex/static_root/assets/browser-C_PHQbyN.bb065e2ce21a.js.br +0 -0
- codex/static_root/assets/browser-C_PHQbyN.bb065e2ce21a.js.gz +0 -0
- codex/static_root/assets/browser-C_PHQbyN.js +0 -1
- codex/static_root/assets/browser-C_PHQbyN.js.br +0 -0
- codex/static_root/assets/browser-C_PHQbyN.js.gz +0 -0
- codex/static_root/assets/browser-DVI4LUNv.css +0 -1
- codex/static_root/assets/browser-DVI4LUNv.css.br +0 -0
- codex/static_root/assets/browser-DVI4LUNv.css.gz +0 -0
- codex/static_root/assets/browser-DVI4LUNv.fef2b997145a.css +0 -1
- codex/static_root/assets/browser-DVI4LUNv.fef2b997145a.css.br +0 -0
- codex/static_root/assets/browser-DVI4LUNv.fef2b997145a.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-BHTkpC6Z.2d5d5dd57ad3.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BHTkpC6Z.2d5d5dd57ad3.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-BHTkpC6Z.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BHTkpC6Z.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DmXGDg4z.284812bd376d.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DmXGDg4z.284812bd376d.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DmXGDg4z.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DmXGDg4z.js.gz +0 -0
- codex/static_root/assets/datetime-column-DKaH5S3z.5c6042016200.js.br +0 -0
- codex/static_root/assets/datetime-column-DKaH5S3z.5c6042016200.js.gz +0 -0
- codex/static_root/assets/datetime-column-DKaH5S3z.js.br +0 -0
- codex/static_root/assets/datetime-column-DKaH5S3z.js.gz +0 -0
- codex/static_root/assets/filter-DUVATQW3.e1e7aa6d0b18.js.br +0 -0
- codex/static_root/assets/filter-DUVATQW3.e1e7aa6d0b18.js.gz +0 -0
- codex/static_root/assets/filter-DUVATQW3.js.br +0 -0
- codex/static_root/assets/filter-DUVATQW3.js.gz +0 -0
- codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css +0 -1
- codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.br +0 -0
- codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.gz +0 -0
- codex/static_root/assets/flag-tab-BacZLlVi.css +0 -1
- codex/static_root/assets/flag-tab-BacZLlVi.css.br +0 -0
- codex/static_root/assets/flag-tab-BacZLlVi.css.gz +0 -0
- codex/static_root/assets/flag-tab-CSKMJEn-.5d5c0604541b.js +0 -1
- codex/static_root/assets/flag-tab-CSKMJEn-.5d5c0604541b.js.br +0 -0
- codex/static_root/assets/flag-tab-CSKMJEn-.5d5c0604541b.js.gz +0 -0
- codex/static_root/assets/flag-tab-CSKMJEn-.js +0 -1
- codex/static_root/assets/flag-tab-CSKMJEn-.js.br +0 -0
- codex/static_root/assets/flag-tab-CSKMJEn-.js.gz +0 -0
- codex/static_root/assets/group-tab-D3CyU-Il.fbf9ce5ef593.js.br +0 -0
- codex/static_root/assets/group-tab-D3CyU-Il.fbf9ce5ef593.js.gz +0 -0
- codex/static_root/assets/group-tab-D3CyU-Il.js.br +0 -0
- codex/static_root/assets/group-tab-D3CyU-Il.js.gz +0 -0
- codex/static_root/assets/http-error-0ef6-Ajc.e2879bcd242f.js.br +0 -0
- codex/static_root/assets/http-error-0ef6-Ajc.e2879bcd242f.js.gz +0 -0
- codex/static_root/assets/http-error-0ef6-Ajc.js.br +0 -0
- codex/static_root/assets/http-error-0ef6-Ajc.js.gz +0 -0
- codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css +0 -1
- codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.br +0 -2
- codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.gz +0 -0
- codex/static_root/assets/library-tab-CXbkxNZt.css +0 -1
- codex/static_root/assets/library-tab-CXbkxNZt.css.br +0 -2
- codex/static_root/assets/library-tab-CXbkxNZt.css.gz +0 -0
- codex/static_root/assets/library-tab-IdDfLn4k.70b55460b8e1.js +0 -1
- codex/static_root/assets/library-tab-IdDfLn4k.70b55460b8e1.js.br +0 -0
- codex/static_root/assets/library-tab-IdDfLn4k.70b55460b8e1.js.gz +0 -0
- codex/static_root/assets/library-tab-IdDfLn4k.js +0 -1
- codex/static_root/assets/library-tab-IdDfLn4k.js.br +0 -0
- codex/static_root/assets/library-tab-IdDfLn4k.js.gz +0 -0
- codex/static_root/assets/main-CuzJev9T.f58771cc37e2.js.br +0 -0
- codex/static_root/assets/main-CuzJev9T.f58771cc37e2.js.gz +0 -0
- codex/static_root/assets/main-CuzJev9T.js.br +0 -0
- codex/static_root/assets/main-CuzJev9T.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CLr9RVHd.66d3b756d974.js +0 -1
- codex/static_root/assets/pagination-toolbar-CLr9RVHd.66d3b756d974.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CLr9RVHd.66d3b756d974.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CLr9RVHd.js +0 -1
- codex/static_root/assets/pagination-toolbar-CLr9RVHd.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CLr9RVHd.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BlU5mm5n.0431bcdf48d1.js.br +0 -0
- codex/static_root/assets/pdf-doc-BlU5mm5n.0431bcdf48d1.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BlU5mm5n.js.br +0 -0
- codex/static_root/assets/pdf-doc-BlU5mm5n.js.gz +0 -0
- codex/static_root/assets/reader-BiKxuxj7.css.br +0 -0
- codex/static_root/assets/reader-BiKxuxj7.css.gz +0 -0
- codex/static_root/assets/reader-BiKxuxj7.dabe592f46f1.css.br +0 -0
- codex/static_root/assets/reader-BiKxuxj7.dabe592f46f1.css.gz +0 -0
- codex/static_root/assets/reader-s7jttB_F.f7b43b04961a.js.br +0 -0
- codex/static_root/assets/reader-s7jttB_F.f7b43b04961a.js.gz +0 -0
- codex/static_root/assets/reader-s7jttB_F.js.br +0 -0
- codex/static_root/assets/reader-s7jttB_F.js.gz +0 -0
- codex/static_root/assets/relation-chips-BiVsYCd9.27eca8616ba4.js +0 -1
- codex/static_root/assets/relation-chips-BiVsYCd9.27eca8616ba4.js.br +0 -0
- codex/static_root/assets/relation-chips-BiVsYCd9.27eca8616ba4.js.gz +0 -0
- codex/static_root/assets/relation-chips-BiVsYCd9.js +0 -1
- codex/static_root/assets/relation-chips-BiVsYCd9.js.br +0 -0
- codex/static_root/assets/relation-chips-BiVsYCd9.js.gz +0 -0
- codex/static_root/assets/relation-chips-D6T6FX7G.css.br +0 -0
- codex/static_root/assets/relation-chips-D6T6FX7G.css.gz +0 -0
- codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.br +0 -0
- codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.gz +0 -0
- codex/static_root/assets/settings-drawer-DbJuixzh.352aaaab5925.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbJuixzh.352aaaab5925.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DbJuixzh.js.br +0 -0
- codex/static_root/assets/settings-drawer-DbJuixzh.js.gz +0 -0
- codex/static_root/assets/stats-tab-BhRLh7XB.7be95b5021c3.js.br +0 -0
- codex/static_root/assets/stats-tab-BhRLh7XB.7be95b5021c3.js.gz +0 -0
- codex/static_root/assets/stats-tab-BhRLh7XB.js.br +0 -0
- codex/static_root/assets/stats-tab-BhRLh7XB.js.gz +0 -0
- codex/static_root/assets/task-tab-DLrd54z2.c574111658b9.js +0 -1
- codex/static_root/assets/task-tab-DLrd54z2.c574111658b9.js.br +0 -0
- codex/static_root/assets/task-tab-DLrd54z2.c574111658b9.js.gz +0 -0
- codex/static_root/assets/task-tab-DLrd54z2.js +0 -1
- codex/static_root/assets/task-tab-DLrd54z2.js.br +0 -0
- codex/static_root/assets/task-tab-DLrd54z2.js.gz +0 -0
- codex/static_root/assets/unauthorized-BgXQnNpn.f63b36d526b5.js.br +0 -0
- codex/static_root/assets/unauthorized-BgXQnNpn.f63b36d526b5.js.gz +0 -0
- codex/static_root/assets/unauthorized-BgXQnNpn.js.br +0 -0
- codex/static_root/assets/unauthorized-BgXQnNpn.js.gz +0 -0
- codex/static_root/assets/user-tab-cZoJDlb-.2a497e8b2b24.js.br +0 -0
- codex/static_root/assets/user-tab-cZoJDlb-.2a497e8b2b24.js.gz +0 -0
- codex/static_root/assets/user-tab-cZoJDlb-.js.br +0 -0
- codex/static_root/assets/user-tab-cZoJDlb-.js.gz +0 -0
- codex/static_root/js/choices-admin.248384ece3f6.json +0 -1
- codex/static_root/js/choices-admin.248384ece3f6.json.br +0 -0
- codex/static_root/js/choices-admin.248384ece3f6.json.gz +0 -0
- codex/static_root/js/choices.b60817ba0a93.json.br +0 -0
- codex/static_root/js/choices.b60817ba0a93.json.gz +0 -0
- codex/static_root/manifest.3c2f342d5f5a.json +0 -642
- codex/static_root/manifest.3c2f342d5f5a.json.br +0 -0
- codex/static_root/manifest.3c2f342d5f5a.json.gz +0 -0
- {codex-1.6.0a4.dist-info → codex-1.6.0a5.dist-info}/LICENSE +0 -0
- {codex-1.6.0a4.dist-info → codex-1.6.0a5.dist-info}/WHEEL +0 -0
- {codex-1.6.0a4.dist-info → codex-1.6.0a5.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Query the missing foreign keys for comics and contributors."""
|
|
2
2
|
|
|
3
|
+
from itertools import chain
|
|
3
4
|
from logging import DEBUG, INFO
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from types import MappingProxyType
|
|
@@ -35,6 +36,7 @@ from codex.models import (
|
|
|
35
36
|
Volume,
|
|
36
37
|
)
|
|
37
38
|
from codex.models.named import Identifier
|
|
39
|
+
from codex.models.paths import CustomCover
|
|
38
40
|
from codex.settings.settings import FILTER_BATCH_SIZE
|
|
39
41
|
from codex.status import Status
|
|
40
42
|
from codex.threads import QueuedThread
|
|
@@ -566,6 +568,30 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
566
568
|
self.log.info(f"Prepared {count} new Folders.")
|
|
567
569
|
return count
|
|
568
570
|
|
|
571
|
+
@staticmethod
|
|
572
|
+
def _get_create_fks_totals(create_data):
|
|
573
|
+
(
|
|
574
|
+
create_groups,
|
|
575
|
+
update_groups,
|
|
576
|
+
create_folder_paths,
|
|
577
|
+
create_fks,
|
|
578
|
+
create_contributors,
|
|
579
|
+
create_story_arc_numbers,
|
|
580
|
+
create_identifiers,
|
|
581
|
+
) = create_data
|
|
582
|
+
total_fks = 0
|
|
583
|
+
for data_group in chain(
|
|
584
|
+
create_groups.values(), update_groups.values(), create_fks.values()
|
|
585
|
+
):
|
|
586
|
+
total_fks += len(data_group)
|
|
587
|
+
total_fks += (
|
|
588
|
+
len(create_folder_paths)
|
|
589
|
+
+ len(create_contributors)
|
|
590
|
+
+ len(create_story_arc_numbers)
|
|
591
|
+
+ len(create_identifiers)
|
|
592
|
+
)
|
|
593
|
+
return total_fks
|
|
594
|
+
|
|
569
595
|
def query_all_missing_fks(self, library_path, fks):
|
|
570
596
|
"""Get objects to create by querying existing objects for the proposed fks."""
|
|
571
597
|
create_contributors = set()
|
|
@@ -619,7 +645,7 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
619
645
|
finally:
|
|
620
646
|
self.status_controller.finish(status)
|
|
621
647
|
|
|
622
|
-
|
|
648
|
+
create_data = (
|
|
623
649
|
create_groups,
|
|
624
650
|
update_groups,
|
|
625
651
|
create_folder_paths,
|
|
@@ -628,3 +654,41 @@ class QueryForeignKeysMixin(QueuedThread):
|
|
|
628
654
|
create_story_arc_numbers,
|
|
629
655
|
create_identifiers,
|
|
630
656
|
)
|
|
657
|
+
|
|
658
|
+
total_fks = self._get_create_fks_totals(create_data)
|
|
659
|
+
status = Status(ImportStatusTypes.CREATE_FKS, 0, total_fks)
|
|
660
|
+
self.status_controller.update(status, notify=False)
|
|
661
|
+
return (*create_data, total_fks)
|
|
662
|
+
|
|
663
|
+
@status_notify(ImportStatusTypes.QUERY_MISSING_COVERS, updates=False)
|
|
664
|
+
def query_missing_custom_covers(
|
|
665
|
+
self, cover_paths: frozenset, library, query_data: list, status=None
|
|
666
|
+
):
|
|
667
|
+
"""Identify update & create covers."""
|
|
668
|
+
self.log.debug(f"Querying {len(cover_paths)} custom cover_paths")
|
|
669
|
+
if status:
|
|
670
|
+
status.total = len(cover_paths)
|
|
671
|
+
|
|
672
|
+
update_covers_qs = CustomCover.objects.filter(
|
|
673
|
+
library=library, path__in=cover_paths
|
|
674
|
+
)
|
|
675
|
+
query_data.append(update_covers_qs)
|
|
676
|
+
update_cover_paths = frozenset(update_covers_qs.values_list("path", flat=True))
|
|
677
|
+
update_count = len(update_cover_paths)
|
|
678
|
+
update_status = Status(ImportStatusTypes.COVERS_MODIFIED, 0, update_count)
|
|
679
|
+
self.status_controller.update(update_status, notify=False)
|
|
680
|
+
|
|
681
|
+
create_cover_paths = cover_paths - update_cover_paths
|
|
682
|
+
query_data.append(create_cover_paths)
|
|
683
|
+
create_count = len(create_cover_paths)
|
|
684
|
+
create_status = Status(ImportStatusTypes.COVERS_CREATED, 0, create_count)
|
|
685
|
+
self.status_controller.update(create_status, notify=False)
|
|
686
|
+
|
|
687
|
+
count = create_count + update_count
|
|
688
|
+
if count:
|
|
689
|
+
self.log.debug(
|
|
690
|
+
f"Discovered {update_count} custom covers to update and {create_count} to create."
|
|
691
|
+
)
|
|
692
|
+
if status:
|
|
693
|
+
status.add_complete(count)
|
|
694
|
+
return count
|
|
@@ -25,6 +25,12 @@ class ImportStatusTypes(Choices):
|
|
|
25
25
|
DIRS_DELETED = "IDD"
|
|
26
26
|
FILES_DELETED = "IFD"
|
|
27
27
|
FAILED_IMPORTS = "IFI"
|
|
28
|
+
QUERY_MISSING_COVERS = "ICQ"
|
|
29
|
+
COVERS_MOVED = "ICM"
|
|
30
|
+
COVERS_MODIFIED = "ICU"
|
|
31
|
+
COVERS_CREATED = "ICC"
|
|
32
|
+
COVERS_DELETED = "ICD"
|
|
33
|
+
COVERS_LINK = "ICL"
|
|
28
34
|
|
|
29
35
|
|
|
30
36
|
def status_notify(status_type: str | Enum = "", updates=True):
|
|
@@ -13,14 +13,22 @@ class ImportDBDiffTask(ImportTask):
|
|
|
13
13
|
"""For sending to the updater."""
|
|
14
14
|
|
|
15
15
|
library_id: int
|
|
16
|
+
|
|
16
17
|
dirs_moved: dict[str, str]
|
|
17
|
-
files_moved: dict[str, str]
|
|
18
18
|
dirs_modified: frozenset[str]
|
|
19
|
+
# dirs_created: frozenset[str]
|
|
20
|
+
dirs_deleted: frozenset[str]
|
|
21
|
+
|
|
22
|
+
files_moved: dict[str, str]
|
|
19
23
|
files_modified: frozenset[str]
|
|
20
|
-
# dirs_created
|
|
21
24
|
files_created: frozenset[str]
|
|
22
|
-
dirs_deleted: frozenset[str]
|
|
23
25
|
files_deleted: frozenset[str]
|
|
26
|
+
|
|
27
|
+
covers_moved: dict[str, str]
|
|
28
|
+
covers_modified: frozenset[str]
|
|
29
|
+
covers_created: frozenset[str]
|
|
30
|
+
covers_deleted: frozenset[str]
|
|
31
|
+
|
|
24
32
|
force_import_metadata: bool = False
|
|
25
33
|
|
|
26
34
|
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from django.db.models import NOT_PROVIDED
|
|
4
4
|
from django.db.models.functions import Now
|
|
5
5
|
|
|
6
|
-
from codex.librarian.covers.tasks import CoverRemoveTask
|
|
7
6
|
from codex.librarian.importer.const import (
|
|
8
7
|
BULK_UPDATE_COMIC_FIELDS,
|
|
9
8
|
BULK_UPDATE_COMIC_FIELDS_WITH_VALUES,
|
|
@@ -78,9 +77,8 @@ class UpdateComicsMixin(LinkComicsMixin):
|
|
|
78
77
|
Timestamp.touch(Timestamp.TimestampChoices.COVERS)
|
|
79
78
|
count = len(update_comics)
|
|
80
79
|
|
|
81
|
-
|
|
80
|
+
self._remove_covers(comic_pks, False) # type: ignore
|
|
82
81
|
self.log.debug(f"Purging covers for {len(comic_pks)} updated comics.")
|
|
83
|
-
self.librarian_queue.put(task)
|
|
84
82
|
if count:
|
|
85
83
|
self.log.info(f"Updated {count} comics.")
|
|
86
84
|
except Exception:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Clean up the database after moves or imports."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from time import time
|
|
5
6
|
from types import MappingProxyType
|
|
6
7
|
|
|
@@ -34,6 +35,7 @@ from codex.models import (
|
|
|
34
35
|
Team,
|
|
35
36
|
Volume,
|
|
36
37
|
)
|
|
38
|
+
from codex.models.paths import CustomCover
|
|
37
39
|
from codex.status import Status
|
|
38
40
|
from codex.worker_base import WorkerBaseMixin
|
|
39
41
|
|
|
@@ -107,6 +109,28 @@ class CleanupMixin(WorkerBaseMixin):
|
|
|
107
109
|
finally:
|
|
108
110
|
self.status_controller.finish(status)
|
|
109
111
|
|
|
112
|
+
def cleanup_custom_covers(self):
|
|
113
|
+
"""Clean up unused custom covers."""
|
|
114
|
+
start = time()
|
|
115
|
+
covers = CustomCover.objects.only("path")
|
|
116
|
+
status = Status(JanitorStatusTypes.CLEANUP_COVERS, 0, covers.count())
|
|
117
|
+
delete_pks = []
|
|
118
|
+
try:
|
|
119
|
+
self.status_controller.start(status)
|
|
120
|
+
self.log.debug("Cleaning up db custom covers with no source images...")
|
|
121
|
+
for cover in covers.iterator():
|
|
122
|
+
if not Path(cover.path).exists():
|
|
123
|
+
delete_pks.append(cover.pk)
|
|
124
|
+
status.increment_complete()
|
|
125
|
+
delete_qs = CustomCover.objects.filter(pk__in=delete_pks)
|
|
126
|
+
count = delete_qs.count()
|
|
127
|
+
delete_qs.delete()
|
|
128
|
+
level = logging.INFO if status.complete else logging.DEBUG
|
|
129
|
+
self.log.log(level, f"Deleted {count} CustomCovers without source images.")
|
|
130
|
+
finally:
|
|
131
|
+
until = start + 2
|
|
132
|
+
self.status_controller.finish(status, until=until)
|
|
133
|
+
|
|
110
134
|
def cleanup_sessions(self):
|
|
111
135
|
"""Delete corrupt sessions."""
|
|
112
136
|
start = time()
|
|
@@ -22,6 +22,6 @@ class UpdateFailedImportsMixin(WorkerBaseMixin):
|
|
|
22
22
|
|
|
23
23
|
def force_update_all_failed_imports(self):
|
|
24
24
|
"""Force update events for failed imports in every library."""
|
|
25
|
-
pks = Library.objects.values_list("pk", flat=True)
|
|
25
|
+
pks = Library.objects.filter(covers_only=False).values_list("pk", flat=True)
|
|
26
26
|
for pk in pks:
|
|
27
27
|
self._force_update_failed_imports(pk)
|
|
@@ -8,6 +8,7 @@ from codex.librarian.janitor.status import JanitorStatusTypes
|
|
|
8
8
|
from codex.librarian.janitor.tasks import (
|
|
9
9
|
ForceUpdateAllFailedImportsTask,
|
|
10
10
|
JanitorBackupTask,
|
|
11
|
+
JanitorCleanCoversTask,
|
|
11
12
|
JanitorCleanFKsTask,
|
|
12
13
|
JanitorCleanupSessionsTask,
|
|
13
14
|
JanitorClearStatusTask,
|
|
@@ -30,6 +31,7 @@ from codex.status import Status
|
|
|
30
31
|
|
|
31
32
|
_JANITOR_STATII = (
|
|
32
33
|
Status(JanitorStatusTypes.CLEANUP_FK, 0, TOTAL_NUM_FK_CLASSES),
|
|
34
|
+
Status(JanitorStatusTypes.CLEANUP_COVERS),
|
|
33
35
|
Status(JanitorStatusTypes.CLEANUP_SESSIONS),
|
|
34
36
|
Status(JanitorStatusTypes.DB_OPTIMIZE),
|
|
35
37
|
Status(JanitorStatusTypes.DB_BACKUP),
|
|
@@ -59,6 +61,7 @@ class Janitor(CleanupMixin, UpdateMixin, VacuumMixin, UpdateFailedImportsMixin):
|
|
|
59
61
|
tasks = (
|
|
60
62
|
SearchIndexAbortTask(),
|
|
61
63
|
JanitorCleanFKsTask(),
|
|
64
|
+
JanitorCleanCoversTask(),
|
|
62
65
|
JanitorCleanupSessionsTask(),
|
|
63
66
|
JanitorVacuumTask(),
|
|
64
67
|
JanitorBackupTask(),
|
|
@@ -89,6 +92,8 @@ class Janitor(CleanupMixin, UpdateMixin, VacuumMixin, UpdateFailedImportsMixin):
|
|
|
89
92
|
self.shutdown_codex()
|
|
90
93
|
case JanitorCleanFKsTask():
|
|
91
94
|
self.cleanup_fks()
|
|
95
|
+
case JanitorCleanCoversTask():
|
|
96
|
+
self.cleanup_custom_covers()
|
|
92
97
|
case JanitorCleanupSessionsTask():
|
|
93
98
|
self.cleanup_sessions()
|
|
94
99
|
case JanitorClearStatusTask():
|
codex/librarian/janitor/tasks.py
CHANGED
|
@@ -40,6 +40,11 @@ class JanitorCleanFKsTask(JanitorTask):
|
|
|
40
40
|
"""Clean unused foreign keys."""
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
@dataclass
|
|
44
|
+
class JanitorCleanCoversTask(JanitorTask):
|
|
45
|
+
"""Clean unused custom covers."""
|
|
46
|
+
|
|
47
|
+
|
|
43
48
|
@dataclass
|
|
44
49
|
class JanitorClearStatusTask(JanitorTask):
|
|
45
50
|
"""Clear all librarian statuses."""
|
codex/librarian/librariand.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import NamedTuple
|
|
|
7
7
|
|
|
8
8
|
from caseconverter import snakecase
|
|
9
9
|
|
|
10
|
-
from codex.librarian.covers.coverd import
|
|
10
|
+
from codex.librarian.covers.coverd import CoverThread
|
|
11
11
|
from codex.librarian.covers.tasks import CoverTask
|
|
12
12
|
from codex.librarian.delayed_taskd import DelayedTasksThread
|
|
13
13
|
from codex.librarian.importer.importerd import ComicImporterThread
|
|
@@ -43,7 +43,7 @@ class LibrarianDaemon(Process, LoggerBaseMixin):
|
|
|
43
43
|
_THREAD_CLASSES = (
|
|
44
44
|
NotifierThread,
|
|
45
45
|
DelayedTasksThread,
|
|
46
|
-
|
|
46
|
+
CoverThread,
|
|
47
47
|
SearchIndexerThread,
|
|
48
48
|
ComicImporterThread,
|
|
49
49
|
WatchdogEventBatcherThread,
|
|
@@ -81,7 +81,7 @@ class LibrarianDaemon(Process, LoggerBaseMixin):
|
|
|
81
81
|
"""Process an individual task popped off the queue."""
|
|
82
82
|
match task:
|
|
83
83
|
case CoverTask():
|
|
84
|
-
self._threads.
|
|
84
|
+
self._threads.cover_thread.queue.put(task)
|
|
85
85
|
case WatchdogEventTask():
|
|
86
86
|
self._threads.watchdog_event_batcher_thread.queue.put(task)
|
|
87
87
|
case ImportTask():
|
codex/librarian/search/update.py
CHANGED
|
@@ -319,7 +319,7 @@ class UpdateMixin(RemoveMixin):
|
|
|
319
319
|
self.abort_event.clear()
|
|
320
320
|
try:
|
|
321
321
|
any_update_in_progress = Library.objects.filter(
|
|
322
|
-
update_in_progress=True
|
|
322
|
+
covers_only=False, update_in_progress=True
|
|
323
323
|
).exists()
|
|
324
324
|
if any_update_in_progress:
|
|
325
325
|
self.log.debug(
|
|
@@ -7,19 +7,20 @@ from pathlib import Path
|
|
|
7
7
|
from watchdog.utils.dirsnapshot import DirectorySnapshot
|
|
8
8
|
|
|
9
9
|
from codex.logger_base import LoggerBaseMixin
|
|
10
|
-
from codex.models import Comic, FailedImport, Folder
|
|
10
|
+
from codex.models import Comic, CustomCover, FailedImport, Folder
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class CodexDatabaseSnapshot(DirectorySnapshot, LoggerBaseMixin):
|
|
14
14
|
"""Take snapshots from the Codex database."""
|
|
15
15
|
|
|
16
|
-
MODELS = (Folder, Comic, FailedImport)
|
|
16
|
+
MODELS = (Folder, Comic, FailedImport, CustomCover)
|
|
17
|
+
COVERS_ONLY_MODELS = (CustomCover,)
|
|
17
18
|
_STAT_LEN = 10
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
def _walk(cls, root):
|
|
20
|
+
def _walk(self, root):
|
|
21
21
|
"""Populate the DirectorySnapshot structures from the database."""
|
|
22
|
-
|
|
22
|
+
models = self.COVERS_ONLY_MODELS if self._covers_only else self.MODELS
|
|
23
|
+
for model in models:
|
|
23
24
|
yield (
|
|
24
25
|
model.objects.filter(library__path=root)
|
|
25
26
|
.order_by("path")
|
|
@@ -57,7 +58,7 @@ class CodexDatabaseSnapshot(DirectorySnapshot, LoggerBaseMixin):
|
|
|
57
58
|
i = (st.st_ino, st.st_dev)
|
|
58
59
|
self._inode_to_path[i] = path
|
|
59
60
|
|
|
60
|
-
def __init__(
|
|
61
|
+
def __init__( # noqa: PLR0913
|
|
61
62
|
self,
|
|
62
63
|
path,
|
|
63
64
|
_recursive=True, # unused, always recursive
|
|
@@ -65,8 +66,10 @@ class CodexDatabaseSnapshot(DirectorySnapshot, LoggerBaseMixin):
|
|
|
65
66
|
_listdir=os.listdir, # unused for database
|
|
66
67
|
force=False,
|
|
67
68
|
log_queue=None,
|
|
69
|
+
covers_only=False,
|
|
68
70
|
):
|
|
69
71
|
"""Initialize like DirectorySnapshot but use a database walk."""
|
|
72
|
+
self._covers_only = covers_only
|
|
70
73
|
self.init_logger(log_queue)
|
|
71
74
|
self._stat_info = {}
|
|
72
75
|
self._inode_to_path = {}
|
|
@@ -54,6 +54,7 @@ class DatabasePollingEmitter(EventEmitter, WorkerBaseMixin):
|
|
|
54
54
|
timeout=DEFAULT_EMITTER_TIMEOUT,
|
|
55
55
|
log_queue=None,
|
|
56
56
|
librarian_queue=None,
|
|
57
|
+
covers_only=False,
|
|
57
58
|
):
|
|
58
59
|
"""Initialize snapshot methods."""
|
|
59
60
|
self.init_worker(log_queue, librarian_queue)
|
|
@@ -61,6 +62,7 @@ class DatabasePollingEmitter(EventEmitter, WorkerBaseMixin):
|
|
|
61
62
|
self._force = False
|
|
62
63
|
self._watch_path = Path(watch.path)
|
|
63
64
|
self._watch_path_unmounted = self._watch_path / _DOCKER_UNMOUNTED_FN
|
|
65
|
+
self._covers_only = covers_only
|
|
64
66
|
super().__init__(
|
|
65
67
|
event_queue, watch, timeout=timeout, event_filter=_CODEX_EVENT_FILTER
|
|
66
68
|
)
|
|
@@ -84,6 +86,7 @@ class DatabasePollingEmitter(EventEmitter, WorkerBaseMixin):
|
|
|
84
86
|
self.watch.is_recursive,
|
|
85
87
|
force=self._force,
|
|
86
88
|
log_queue=self.log_queue,
|
|
89
|
+
covers_only=self._covers_only,
|
|
87
90
|
)
|
|
88
91
|
self._force = False
|
|
89
92
|
return db_snapshot
|
|
@@ -25,12 +25,16 @@ class WatchdogEventBatcherThread(AggregateMessageQueuedThread):
|
|
|
25
25
|
{
|
|
26
26
|
"library_id": None,
|
|
27
27
|
"dirs_moved": {},
|
|
28
|
+
"dirs_modified": set(),
|
|
29
|
+
"dirs_deleted": set(),
|
|
28
30
|
"files_moved": {},
|
|
29
31
|
"files_modified": set(),
|
|
30
32
|
"files_created": set(),
|
|
31
|
-
"dirs_deleted": set(),
|
|
32
|
-
"dirs_modified": set(),
|
|
33
33
|
"files_deleted": set(),
|
|
34
|
+
"covers_moved": {},
|
|
35
|
+
"covers_modified": set(),
|
|
36
|
+
"covers_created": set(),
|
|
37
|
+
"covers_deleted": set(),
|
|
34
38
|
}
|
|
35
39
|
)
|
|
36
40
|
MAX_DELAY = 60
|
|
@@ -54,7 +58,13 @@ class WatchdogEventBatcherThread(AggregateMessageQueuedThread):
|
|
|
54
58
|
"""Translate event class names into field names."""
|
|
55
59
|
self._ensure_library_args(library_id)
|
|
56
60
|
|
|
57
|
-
prefix =
|
|
61
|
+
prefix = (
|
|
62
|
+
"dir"
|
|
63
|
+
if event.is_directory
|
|
64
|
+
else "cover"
|
|
65
|
+
if getattr(event, "is_cover", False)
|
|
66
|
+
else "file"
|
|
67
|
+
)
|
|
58
68
|
field = f"{prefix}s_{event.event_type}"
|
|
59
69
|
|
|
60
70
|
return self.cache[library_id].get(field)
|
|
@@ -90,17 +100,23 @@ class WatchdogEventBatcherThread(AggregateMessageQueuedThread):
|
|
|
90
100
|
for src_path in args["files_deleted"]:
|
|
91
101
|
with suppress(KeyError):
|
|
92
102
|
del args["files_moved"][src_path]
|
|
103
|
+
|
|
93
104
|
# created
|
|
94
105
|
args["files_created"] -= args["files_deleted"]
|
|
95
106
|
files_dest_paths = set(args["files_moved"].values())
|
|
96
107
|
args["files_created"] -= files_dest_paths
|
|
108
|
+
|
|
97
109
|
# modified
|
|
98
110
|
args["dirs_modified"] -= args["dirs_deleted"]
|
|
99
111
|
args["dirs_modified"] -= set(args["dirs_moved"].values())
|
|
112
|
+
|
|
100
113
|
args["files_modified"] -= args["files_created"]
|
|
101
114
|
args["files_modified"] -= args["files_deleted"]
|
|
102
115
|
args["files_modified"] -= files_dest_paths
|
|
103
116
|
|
|
117
|
+
args["covers_modified"] -= args["covers_deleted"]
|
|
118
|
+
args["covers_modified"] -= args["covers_created"]
|
|
119
|
+
|
|
104
120
|
def _create_task(self, library_id):
|
|
105
121
|
"""Create a task from cached aggregated message data."""
|
|
106
122
|
self._deduplicate_events(library_id)
|