codex 1.6.0a8__py3-none-any.whl → 1.6.0a10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codex might be problematic. Click here for more details.
- codex/integrity.py +1 -2
- codex/librarian/importer/cache.py +46 -133
- codex/librarian/importer/create_comics.py +3 -4
- codex/librarian/importer/create_covers.py +1 -3
- codex/librarian/importer/create_fks.py +3 -1
- codex/librarian/importer/failed_imports.py +1 -2
- codex/librarian/importer/importer.py +1 -1
- codex/librarian/importer/importerd.py +7 -7
- codex/librarian/importer/moved.py +4 -8
- codex/librarian/importer/tasks.py +2 -2
- codex/librarian/janitor/janitor.py +0 -3
- codex/librarian/librariand.py +0 -2
- codex/librarian/notifier/notifierd.py +1 -1
- codex/librarian/notifier/tasks.py +4 -4
- codex/middleware.py +1 -2
- codex/migrations/0027_import_order_and_covers.py +1 -66
- codex/models/comic.py +0 -1
- codex/models/groups.py +0 -3
- codex/serializers/admin.py +41 -40
- codex/serializers/browser/choices.py +22 -6
- codex/serializers/browser/metadata.py +45 -1
- codex/serializers/browser/mtime.py +21 -0
- codex/serializers/browser/page.py +2 -4
- codex/serializers/browser/settings.py +34 -14
- codex/serializers/fields.py +27 -10
- codex/serializers/reader.py +16 -6
- codex/serializers/route.py +9 -4
- codex/serializers/settings.py +12 -0
- codex/settings/settings.py +10 -1
- codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js +1 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js.br +0 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js.gz +0 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.js +1 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.js.br +0 -0
- codex/static_root/assets/VCheckbox-CY3rcqlS.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js → VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-B8Z4NA-t.js → VCheckboxBtn-D2tPTt6P.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-D2tPTt6P.js.gz +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js +1 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js.br +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js.gz +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.js +1 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.js.br +0 -0
- codex/static_root/assets/VCombobox-aJr--Ou7.js.gz +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js +1 -0
- codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js.br +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js.gz +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.js +1 -0
- codex/static_root/assets/VDialog-61pzfUB2.js.br +0 -0
- codex/static_root/assets/VDialog-61pzfUB2.js.gz +0 -0
- codex/static_root/assets/{VDialog-C5Nxd_zP.css → VDialog-lQ13FnRR.1c801ad756b2.css} +1 -1
- codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
- codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
- codex/static_root/assets/{VDialog-C5Nxd_zP.d327f505ef0e.css → VDialog-lQ13FnRR.css} +1 -1
- codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
- codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js +1 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.js +1 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-rewm0P4z.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-BGa6_q5a.d1a3ad7266bd.js → VRadioGroup-QFQbK1qo.750a42b1b814.js} +1 -1
- codex/static_root/assets/VRadioGroup-QFQbK1qo.750a42b1b814.js.br +0 -0
- codex/static_root/assets/VRadioGroup-QFQbK1qo.750a42b1b814.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-BGa6_q5a.js → VRadioGroup-QFQbK1qo.js} +1 -1
- codex/static_root/assets/VRadioGroup-QFQbK1qo.js.br +0 -0
- codex/static_root/assets/VRadioGroup-QFQbK1qo.js.gz +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js +1 -0
- codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js.br +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js.gz +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.js +1 -0
- codex/static_root/assets/VSelect-Dixy6okt.js.br +0 -0
- codex/static_root/assets/VSelect-Dixy6okt.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js → VSelectionControl-MNmxKc3J.08055d00917e.js} +1 -1
- codex/static_root/assets/VSelectionControl-MNmxKc3J.08055d00917e.js.br +0 -0
- codex/static_root/assets/VSelectionControl-MNmxKc3J.08055d00917e.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-C8DP9rgp.js → VSelectionControl-MNmxKc3J.js} +1 -1
- codex/static_root/assets/VSelectionControl-MNmxKc3J.js.br +0 -0
- codex/static_root/assets/VSelectionControl-MNmxKc3J.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js +1 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.js +1 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DZEV0FoV.js.gz +0 -0
- codex/static_root/assets/{VTable-D1esKtlw.52165930e3b9.js → VTable-lcnYg9Ee.d72927b13c2e.js} +1 -1
- codex/static_root/assets/VTable-lcnYg9Ee.d72927b13c2e.js.br +0 -0
- codex/static_root/assets/VTable-lcnYg9Ee.d72927b13c2e.js.gz +0 -0
- codex/static_root/assets/{VTable-D1esKtlw.js → VTable-lcnYg9Ee.js} +1 -1
- codex/static_root/assets/VTable-lcnYg9Ee.js.br +0 -0
- codex/static_root/assets/VTable-lcnYg9Ee.js.gz +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js +1 -0
- codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js.br +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js.gz +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.js +1 -0
- codex/static_root/assets/VTextField-BkFrjhdV.js.br +0 -0
- codex/static_root/assets/VTextField-BkFrjhdV.js.gz +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js +1 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js.br +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js.gz +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.js +1 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.js.br +0 -0
- codex/static_root/assets/VWindowItem-C__tAqdc.js.gz +0 -0
- codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js +1 -0
- codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js.br +0 -0
- codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js.gz +0 -0
- codex/static_root/assets/admin-CXES2HXe.js +1 -0
- codex/static_root/assets/admin-CXES2HXe.js.br +0 -0
- codex/static_root/assets/admin-CXES2HXe.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-o87BwD38.ce39427c8201.css → admin-drawer-panel-mne3FIj6.561b3f75fe65.css} +1 -1
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-o87BwD38.css → admin-drawer-panel-mne3FIj6.css} +1 -1
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js +30 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js +30 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js.gz +0 -0
- codex/static_root/assets/browser-BuDeXGEe.css +1 -0
- codex/static_root/assets/browser-BuDeXGEe.css.br +0 -0
- codex/static_root/assets/browser-BuDeXGEe.css.gz +0 -0
- codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css +1 -0
- codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css.br +0 -0
- codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css.gz +0 -0
- codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js +1 -0
- codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js.br +0 -0
- codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js.gz +0 -0
- codex/static_root/assets/browser-s6mFzrK9.js +1 -0
- codex/static_root/assets/browser-s6mFzrK9.js.br +0 -0
- codex/static_root/assets/browser-s6mFzrK9.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +1 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.css +1 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
- codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js +1 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js.br +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.js +1 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.js.br +0 -0
- codex/static_root/assets/change-password-dialog-Bn20jYzD.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DkU0twE6.a20006aa5ba6.js → confirm-dialog-CWszioQE.859051c35dd9.js} +1 -1
- codex/static_root/assets/confirm-dialog-CWszioQE.859051c35dd9.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CWszioQE.859051c35dd9.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-DkU0twE6.js → confirm-dialog-CWszioQE.js} +1 -1
- codex/static_root/assets/confirm-dialog-CWszioQE.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CWszioQE.js.gz +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js +1 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js.br +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js.gz +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.js +1 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.js.br +0 -0
- codex/static_root/assets/datetime-column-BSdlLt-4.js.gz +0 -0
- codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js +1 -0
- codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js.br +0 -0
- codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js.gz +0 -0
- codex/static_root/assets/filter-D3gaGf87.js +1 -0
- codex/static_root/assets/filter-D3gaGf87.js.br +0 -0
- codex/static_root/assets/filter-D3gaGf87.js.gz +0 -0
- codex/static_root/assets/{flag-tab-D4ZNSbMR.e763a9937701.js → flag-tab-8vzpdySX.a982c7f0776a.js} +1 -1
- codex/static_root/assets/flag-tab-8vzpdySX.a982c7f0776a.js.br +0 -0
- codex/static_root/assets/flag-tab-8vzpdySX.a982c7f0776a.js.gz +0 -0
- codex/static_root/assets/{flag-tab-D4ZNSbMR.js → flag-tab-8vzpdySX.js} +1 -1
- codex/static_root/assets/flag-tab-8vzpdySX.js.br +0 -0
- codex/static_root/assets/flag-tab-8vzpdySX.js.gz +0 -0
- codex/static_root/assets/{group-tab-DucpNoBs.a6f37ae940c0.js → group-tab-Cz9t_ECi.a9e8aea79254.js} +1 -1
- codex/static_root/assets/group-tab-Cz9t_ECi.a9e8aea79254.js.br +0 -0
- codex/static_root/assets/group-tab-Cz9t_ECi.a9e8aea79254.js.gz +0 -0
- codex/static_root/assets/{group-tab-DucpNoBs.js → group-tab-Cz9t_ECi.js} +1 -1
- codex/static_root/assets/group-tab-Cz9t_ECi.js.br +0 -0
- codex/static_root/assets/group-tab-Cz9t_ECi.js.gz +0 -0
- codex/static_root/assets/{http-error-Cj0hTq-c.062a88ddd4dc.js → http-error-Cqtszzf1.b31df3d9c29f.js} +1 -1
- codex/static_root/assets/http-error-Cqtszzf1.b31df3d9c29f.js.br +0 -0
- codex/static_root/assets/http-error-Cqtszzf1.b31df3d9c29f.js.gz +0 -0
- codex/static_root/assets/{http-error-Cj0hTq-c.js → http-error-Cqtszzf1.js} +1 -1
- codex/static_root/assets/http-error-Cqtszzf1.js.br +0 -0
- codex/static_root/assets/http-error-Cqtszzf1.js.gz +0 -0
- codex/static_root/assets/{library-tab-CzksdS3Q.566acdb45dec.js → library-tab-DMlnswUU.30f454e84184.js} +1 -1
- codex/static_root/assets/library-tab-DMlnswUU.30f454e84184.js.br +0 -0
- codex/static_root/assets/library-tab-DMlnswUU.30f454e84184.js.gz +0 -0
- codex/static_root/assets/{library-tab-CzksdS3Q.js → library-tab-DMlnswUU.js} +1 -1
- codex/static_root/assets/library-tab-DMlnswUU.js.br +0 -0
- codex/static_root/assets/library-tab-DMlnswUU.js.gz +0 -0
- codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js +32 -0
- codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js.br +0 -0
- codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js.gz +0 -0
- codex/static_root/assets/main-vjXu_QYL.js +32 -0
- codex/static_root/assets/main-vjXu_QYL.js.br +0 -0
- codex/static_root/assets/main-vjXu_QYL.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css +1 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.css +1 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGdMiBRs.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js +1 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.js +1 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JW78pa0q.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-GkMk4o5L.ef24c859a7a4.js → pdf-doc-BiamrjRZ.4c9be1ade43c.js} +1 -1
- codex/static_root/assets/pdf-doc-BiamrjRZ.4c9be1ade43c.js.br +0 -0
- codex/static_root/assets/pdf-doc-BiamrjRZ.4c9be1ade43c.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-GkMk4o5L.js → pdf-doc-BiamrjRZ.js} +1 -1
- codex/static_root/assets/pdf-doc-BiamrjRZ.js.br +0 -0
- codex/static_root/assets/pdf-doc-BiamrjRZ.js.gz +0 -0
- codex/static_root/assets/{reader-CCCfpM3x.1553e45bd775.css → reader-BpsctRsY.5d72e393911a.css} +1 -1
- codex/static_root/assets/reader-BpsctRsY.5d72e393911a.css.br +0 -0
- codex/static_root/assets/reader-BpsctRsY.5d72e393911a.css.gz +0 -0
- codex/static_root/assets/{reader-CCCfpM3x.css → reader-BpsctRsY.css} +1 -1
- codex/static_root/assets/reader-BpsctRsY.css.br +0 -0
- codex/static_root/assets/reader-BpsctRsY.css.gz +0 -0
- codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js +2 -0
- codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js.br +0 -0
- codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js.gz +0 -0
- codex/static_root/assets/reader-CDk8oZzB.js +2 -0
- codex/static_root/assets/reader-CDk8oZzB.js.br +0 -0
- codex/static_root/assets/reader-CDk8oZzB.js.gz +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js +1 -0
- codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js.br +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js.gz +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.js +1 -0
- codex/static_root/assets/relation-chips-C5acBjpy.js.br +0 -0
- codex/static_root/assets/relation-chips-C5acBjpy.js.gz +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js +2 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js.br +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js.gz +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.js +2 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.js.br +0 -0
- codex/static_root/assets/settings-drawer-D_JuRi7F.js.gz +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +1 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.css +1 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
- codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js +1 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js.br +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js.gz +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.js +1 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.js.br +0 -0
- codex/static_root/assets/stats-tab-ClqRTk1z.js.gz +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js +1 -0
- codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js.br +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js.gz +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.js +1 -0
- codex/static_root/assets/task-tab-DF9qa6LO.js.br +0 -0
- codex/static_root/assets/task-tab-DF9qa6LO.js.gz +0 -0
- codex/static_root/assets/to-case-CGbULRaE.4c80644f460d.js +1 -0
- codex/static_root/assets/to-case-CGbULRaE.4c80644f460d.js.br +0 -0
- codex/static_root/assets/to-case-CGbULRaE.js +1 -0
- codex/static_root/assets/to-case-CGbULRaE.js.br +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js +1 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js.br +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js.gz +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.js +1 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.js.br +0 -0
- codex/static_root/assets/unauthorized-BjKuLH6k.js.gz +0 -0
- codex/static_root/assets/{unauthorized-DHV6Q1n-.b7847b2872a1.css → unauthorized-CibJYD8o.4c2de98c2b53.css} +1 -1
- codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
- codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
- codex/static_root/assets/{unauthorized-DHV6Q1n-.css → unauthorized-CibJYD8o.css} +1 -1
- codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
- codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js +1 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js.br +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js.gz +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.js +1 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.js.br +0 -0
- codex/static_root/assets/user-tab-Dpxe3ygA.js.gz +0 -0
- codex/static_root/js/choices-admin.3521e2a863df.json +1 -0
- codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
- codex/static_root/js/choices-admin.3521e2a863df.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/manifest.35e46a3ec8fa.json +622 -0
- codex/static_root/manifest.35e46a3ec8fa.json.br +0 -0
- codex/static_root/manifest.35e46a3ec8fa.json.gz +0 -0
- codex/static_root/manifest.json +245 -252
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/urls/api/v3.py +1 -1
- codex/views/admin/api_key.py +5 -2
- codex/views/admin/stats.py +13 -20
- codex/views/admin/tasks.py +3 -7
- codex/views/auth.py +1 -1
- codex/views/bookmark.py +69 -51
- codex/views/browser/annotations.py +32 -45
- codex/views/browser/base.py +25 -8
- codex/views/browser/breadcrumbs.py +5 -5
- codex/views/browser/browser.py +20 -32
- codex/views/browser/choices.py +18 -15
- codex/views/browser/cover.py +30 -66
- codex/views/browser/filters/annotations.py +66 -14
- codex/views/browser/filters/bookmark.py +21 -5
- codex/views/browser/filters/group.py +29 -17
- codex/views/browser/filters/search.py +3 -4
- codex/views/browser/metadata.py +86 -47
- codex/views/browser/mtime.py +61 -0
- codex/views/browser/order_by.py +1 -6
- codex/views/browser/settings.py +53 -0
- codex/views/browser/validate.py +3 -0
- codex/views/const.py +32 -1
- codex/views/opds/v1/feed.py +3 -5
- codex/views/opds/v2/feed.py +3 -3
- codex/views/reader/arcs.py +42 -51
- codex/views/reader/books.py +48 -66
- codex/views/reader/init.py +121 -0
- codex/views/reader/reader.py +8 -66
- codex/views/session.py +15 -11
- codex/views/settings.py +23 -10
- codex/views/util.py +2 -1
- codex/websockets/consumers.py +13 -9
- {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/METADATA +1 -1
- {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/RECORD +329 -325
- codex/serializers/mtime.py +0 -25
- codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js +0 -1
- codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js.br +0 -0
- codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js.gz +0 -0
- codex/static_root/assets/VCheckbox-DI-DgMb4.js +0 -1
- codex/static_root/assets/VCheckbox-DI-DgMb4.js.br +0 -0
- codex/static_root/assets/VCheckbox-DI-DgMb4.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.js.gz +0 -0
- codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js +0 -1
- codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js.br +0 -0
- codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js.gz +0 -0
- codex/static_root/assets/VCombobox-D1_0lCri.js +0 -1
- codex/static_root/assets/VCombobox-D1_0lCri.js.br +0 -0
- codex/static_root/assets/VCombobox-D1_0lCri.js.gz +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
- codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
- codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js +0 -1
- codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js.br +0 -0
- codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js.gz +0 -0
- codex/static_root/assets/VDialog-opmV0YZz.js +0 -1
- codex/static_root/assets/VDialog-opmV0YZz.js.br +0 -0
- codex/static_root/assets/VDialog-opmV0YZz.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js +0 -1
- codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-DX2dhUf5.js +0 -1
- codex/static_root/assets/VExpansionPanels-DX2dhUf5.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-DX2dhUf5.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-BGa6_q5a.js.br +0 -0
- codex/static_root/assets/VRadioGroup-BGa6_q5a.js.gz +0 -0
- codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js +0 -1
- codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js.br +0 -0
- codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js.gz +0 -0
- codex/static_root/assets/VSelect-sIYW_-ud.js +0 -1
- codex/static_root/assets/VSelect-sIYW_-ud.js.br +0 -0
- codex/static_root/assets/VSelect-sIYW_-ud.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js.br +0 -0
- codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-C8DP9rgp.js.br +0 -0
- codex/static_root/assets/VSelectionControl-C8DP9rgp.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js +0 -1
- codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js.br +0 -0
- codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-BRYhkLH8.js +0 -1
- codex/static_root/assets/VSlideGroup-BRYhkLH8.js.br +0 -0
- codex/static_root/assets/VSlideGroup-BRYhkLH8.js.gz +0 -0
- codex/static_root/assets/VTable-D1esKtlw.52165930e3b9.js.br +0 -0
- codex/static_root/assets/VTable-D1esKtlw.52165930e3b9.js.gz +0 -0
- codex/static_root/assets/VTable-D1esKtlw.js.br +0 -0
- codex/static_root/assets/VTable-D1esKtlw.js.gz +0 -0
- codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js +0 -1
- codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js.br +0 -0
- codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js.gz +0 -0
- codex/static_root/assets/VTextField-BnGscKcY.js +0 -1
- codex/static_root/assets/VTextField-BnGscKcY.js.br +0 -0
- codex/static_root/assets/VTextField-BnGscKcY.js.gz +0 -0
- codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js +0 -1
- codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js.br +0 -0
- codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js.gz +0 -0
- codex/static_root/assets/VWindowItem-B0KokcAk.js +0 -1
- codex/static_root/assets/VWindowItem-B0KokcAk.js.br +0 -0
- codex/static_root/assets/VWindowItem-B0KokcAk.js.gz +0 -0
- codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js +0 -1
- codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js.br +0 -0
- codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js.gz +0 -0
- codex/static_root/assets/admin-Y0bL21AB.js +0 -1
- codex/static_root/assets/admin-Y0bL21AB.js.br +0 -0
- codex/static_root/assets/admin-Y0bL21AB.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js +0 -30
- codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-DNngWUEM.js +0 -30
- codex/static_root/assets/admin-drawer-panel-DNngWUEM.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-DNngWUEM.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-o87BwD38.css.gz +0 -0
- codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css +0 -1
- codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css.br +0 -0
- codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css.gz +0 -0
- codex/static_root/assets/browser-CMAtBCLx.css +0 -1
- codex/static_root/assets/browser-CMAtBCLx.css.br +0 -0
- codex/static_root/assets/browser-CMAtBCLx.css.gz +0 -0
- codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js +0 -1
- codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js.br +0 -0
- codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js.gz +0 -0
- codex/static_root/assets/browser-DoJk8uvb.js +0 -1
- codex/static_root/assets/browser-DoJk8uvb.js.br +0 -0
- codex/static_root/assets/browser-DoJk8uvb.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js +0 -1
- codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js.br +0 -0
- codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-CH4xbjJa.js +0 -1
- codex/static_root/assets/change-password-dialog-CH4xbjJa.js.br +0 -0
- codex/static_root/assets/change-password-dialog-CH4xbjJa.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +0 -1
- codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.css +0 -1
- codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
- codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
- codex/static_root/assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-DkU0twE6.js.br +0 -0
- codex/static_root/assets/confirm-dialog-DkU0twE6.js.gz +0 -0
- codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js +0 -1
- codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js.br +0 -0
- codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js.gz +0 -0
- codex/static_root/assets/datetime-column-BfW_j_3Q.js +0 -1
- codex/static_root/assets/datetime-column-BfW_j_3Q.js.br +0 -0
- codex/static_root/assets/datetime-column-BfW_j_3Q.js.gz +0 -0
- codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js +0 -1
- codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js.br +0 -0
- codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js.gz +0 -0
- codex/static_root/assets/filter-DjxN78cK.js +0 -1
- codex/static_root/assets/filter-DjxN78cK.js.br +0 -0
- codex/static_root/assets/filter-DjxN78cK.js.gz +0 -0
- codex/static_root/assets/flag-tab-D4ZNSbMR.e763a9937701.js.br +0 -0
- codex/static_root/assets/flag-tab-D4ZNSbMR.e763a9937701.js.gz +0 -0
- codex/static_root/assets/flag-tab-D4ZNSbMR.js.br +0 -0
- codex/static_root/assets/flag-tab-D4ZNSbMR.js.gz +0 -0
- codex/static_root/assets/group-tab-DucpNoBs.a6f37ae940c0.js.br +0 -0
- codex/static_root/assets/group-tab-DucpNoBs.a6f37ae940c0.js.gz +0 -0
- codex/static_root/assets/group-tab-DucpNoBs.js.br +0 -0
- codex/static_root/assets/group-tab-DucpNoBs.js.gz +0 -0
- codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js.br +0 -0
- codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js.gz +0 -0
- codex/static_root/assets/http-error-Cj0hTq-c.js.br +0 -0
- codex/static_root/assets/http-error-Cj0hTq-c.js.gz +0 -0
- codex/static_root/assets/library-tab-CzksdS3Q.566acdb45dec.js.br +0 -0
- codex/static_root/assets/library-tab-CzksdS3Q.566acdb45dec.js.gz +0 -0
- codex/static_root/assets/library-tab-CzksdS3Q.js.br +0 -0
- codex/static_root/assets/library-tab-CzksdS3Q.js.gz +0 -0
- codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js +0 -32
- codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js.br +0 -0
- codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js.gz +0 -0
- codex/static_root/assets/main-DX-k2724.js +0 -32
- codex/static_root/assets/main-DX-k2724.js.br +0 -0
- codex/static_root/assets/main-DX-k2724.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js +0 -1
- codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CQcR0a3T.js +0 -1
- codex/static_root/assets/pagination-toolbar-CQcR0a3T.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CQcR0a3T.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css +0 -1
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css +0 -1
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.gz +0 -0
- codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js.br +0 -0
- codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js.gz +0 -0
- codex/static_root/assets/pdf-doc-GkMk4o5L.js.br +0 -0
- codex/static_root/assets/pdf-doc-GkMk4o5L.js.gz +0 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.br +0 -0
- codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.gz +0 -0
- codex/static_root/assets/reader-CCCfpM3x.css.br +0 -0
- codex/static_root/assets/reader-CCCfpM3x.css.gz +0 -0
- codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js +0 -2
- codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js.br +0 -0
- codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js.gz +0 -0
- codex/static_root/assets/reader-Cl6mmQB_.js +0 -2
- codex/static_root/assets/reader-Cl6mmQB_.js.br +0 -0
- codex/static_root/assets/reader-Cl6mmQB_.js.gz +0 -0
- codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js +0 -1
- codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js.br +0 -0
- codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js.gz +0 -0
- codex/static_root/assets/relation-chips-CZ8VvR4y.js +0 -1
- codex/static_root/assets/relation-chips-CZ8VvR4y.js.br +0 -0
- codex/static_root/assets/relation-chips-CZ8VvR4y.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js +0 -2
- codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js.br +0 -0
- codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js.gz +0 -0
- codex/static_root/assets/settings-drawer-DyS0A2pN.js +0 -2
- codex/static_root/assets/settings-drawer-DyS0A2pN.js.br +0 -0
- codex/static_root/assets/settings-drawer-DyS0A2pN.js.gz +0 -0
- codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js +0 -1
- codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js.br +0 -0
- codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js.gz +0 -0
- codex/static_root/assets/stats-tab-R3Ekobfm.js +0 -1
- codex/static_root/assets/stats-tab-R3Ekobfm.js.br +0 -0
- codex/static_root/assets/stats-tab-R3Ekobfm.js.gz +0 -0
- codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +0 -1
- codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +0 -2
- codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
- codex/static_root/assets/stats-tab-TsyG3wH_.css +0 -1
- codex/static_root/assets/stats-tab-TsyG3wH_.css.br +0 -2
- codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
- codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js +0 -1
- codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js.br +0 -0
- codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js.gz +0 -0
- codex/static_root/assets/task-tab-BhLDK_7Q.js +0 -1
- codex/static_root/assets/task-tab-BhLDK_7Q.js.br +0 -0
- codex/static_root/assets/task-tab-BhLDK_7Q.js.gz +0 -0
- codex/static_root/assets/to-case-BR2frjFx.87de5d7a0503.js +0 -1
- codex/static_root/assets/to-case-BR2frjFx.js +0 -1
- codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js +0 -1
- codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js.br +0 -0
- codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js.gz +0 -0
- codex/static_root/assets/unauthorized-BbXjAe5l.js +0 -1
- codex/static_root/assets/unauthorized-BbXjAe5l.js.br +0 -0
- codex/static_root/assets/unauthorized-BbXjAe5l.js.gz +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.br +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.gz +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.css.br +0 -0
- codex/static_root/assets/unauthorized-DHV6Q1n-.css.gz +0 -0
- codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js +0 -1
- codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js.br +0 -0
- codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js.gz +0 -0
- codex/static_root/assets/user-tab-DxITIl2d.js +0 -1
- codex/static_root/assets/user-tab-DxITIl2d.js.br +0 -0
- codex/static_root/assets/user-tab-DxITIl2d.js.gz +0 -0
- codex/static_root/js/choices-admin.d790df01c20a.json +0 -1
- codex/static_root/js/choices-admin.d790df01c20a.json.br +0 -0
- codex/static_root/js/choices-admin.d790df01c20a.json.gz +0 -0
- codex/static_root/manifest.16d52597ef50.json +0 -629
- codex/static_root/manifest.16d52597ef50.json.br +0 -0
- codex/static_root/manifest.16d52597ef50.json.gz +0 -0
- codex/views/mtime.py +0 -72
- {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/LICENSE +0 -0
- {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/WHEEL +0 -0
- {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/entry_points.txt +0 -0
codex/integrity.py
CHANGED
|
@@ -342,7 +342,6 @@ def _repair_groups_with_custom_covers(apps):
|
|
|
342
342
|
if not has_applied_migration(MIGRATION_0027):
|
|
343
343
|
return
|
|
344
344
|
custom_cover_model = apps.get_model("codex", "customcover")
|
|
345
|
-
now = Now()
|
|
346
345
|
for model_name, group_letter in CUSTOM_COVER_MODEL_NAMES.items():
|
|
347
346
|
valid_covers = custom_cover_model.objects.filter(group=group_letter)
|
|
348
347
|
group_model = apps.get_model("codex", model_name)
|
|
@@ -352,7 +351,7 @@ def _repair_groups_with_custom_covers(apps):
|
|
|
352
351
|
update_groups = []
|
|
353
352
|
for group in objs:
|
|
354
353
|
group.custom_cover = None
|
|
355
|
-
group.updated_at =
|
|
354
|
+
group.updated_at = Now()
|
|
356
355
|
update_groups.append(group)
|
|
357
356
|
group_model.objects.bulk_update(update_groups, ["custom_cover"])
|
|
358
357
|
count = len(update_groups)
|
|
@@ -1,171 +1,84 @@
|
|
|
1
1
|
"""Update Groups timestamp for cover cache busting."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
3
|
from django.db.models.aggregates import Count
|
|
6
4
|
from django.db.models.functions.datetime import Now
|
|
7
5
|
from django.db.models.query import Q
|
|
8
6
|
|
|
9
7
|
from codex.librarian.importer.init import InitImporter
|
|
10
8
|
from codex.librarian.importer.status import ImportStatusTypes
|
|
11
|
-
from codex.models import
|
|
9
|
+
from codex.models import StoryArc, Volume
|
|
12
10
|
from codex.status import Status
|
|
11
|
+
from codex.views.const import GROUP_MODELS
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
_UPDATE_FIELDS = ("first_comic", "updated_at")
|
|
13
|
+
_UPDATE_FIELDS = ("updated_at",)
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
class CacheUpdateImporter(InitImporter):
|
|
19
17
|
"""Update Groups timestamp for cover cache busting."""
|
|
20
18
|
|
|
21
19
|
@staticmethod
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.select_related("first_comic")
|
|
29
|
-
.only("path", *_UPDATE_FIELDS)
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
# Create a map of each folder by path depth level
|
|
33
|
-
batch_map = {}
|
|
34
|
-
for folder in all_folders:
|
|
35
|
-
depth = folder.path.count(os.sep)
|
|
36
|
-
if depth not in batch_map:
|
|
37
|
-
batch_map[depth] = set()
|
|
38
|
-
batch_map[depth].add(folder)
|
|
39
|
-
|
|
40
|
-
# Order batches by reverse depth level to update bottom up.
|
|
41
|
-
batches = []
|
|
42
|
-
for _, folders in sorted(batch_map.items(), reverse=True):
|
|
43
|
-
batches.append(folders)
|
|
44
|
-
|
|
45
|
-
return tuple(batches)
|
|
20
|
+
def _get_update_filter(model, start_time, force_update_group_map):
|
|
21
|
+
# Get groups with comics updated during this import
|
|
22
|
+
rel = "storyarcnumber__" if model == StoryArc else ""
|
|
23
|
+
updated_at_rel = rel + "comic__updated_at__gt"
|
|
24
|
+
updated_filter = {updated_at_rel: start_time}
|
|
25
|
+
update_filter = Q(**updated_filter)
|
|
46
26
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
qs = qs.order_by("issue_number", "issue_suffix", "sort_name").only("pk")
|
|
51
|
-
obj.first_comic = qs.first()
|
|
27
|
+
# Get groups with custom covers updated during this import
|
|
28
|
+
if model != Volume:
|
|
29
|
+
update_filter |= Q(custom_cover__updated_at__gt=start_time)
|
|
52
30
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
order_by = "name" if model == Volume else "sort_name"
|
|
57
|
-
qs = qs.select_related("first_comic").order_by(order_by).only("first_comic")
|
|
58
|
-
obj.first_comic = qs.first().first_comic
|
|
31
|
+
# Get groups to be force updated (usually those with deleted children)
|
|
32
|
+
if pks := force_update_group_map.get(model):
|
|
33
|
+
update_filter |= Q(pk__in=pks)
|
|
59
34
|
|
|
60
|
-
|
|
61
|
-
def _update_first_cover_story_arc(obj):
|
|
62
|
-
qs = Comic.objects.filter(story_arc_numbers__story_arc=obj)
|
|
63
|
-
qs = qs.order_by("story_arc_numbers__number", "date").only("pk")
|
|
64
|
-
obj.first_comic = qs.first()
|
|
35
|
+
return update_filter
|
|
65
36
|
|
|
66
37
|
@staticmethod
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
first_folder = (
|
|
75
|
-
Folder.objects.filter(parent_folder=obj)
|
|
76
|
-
.select_related("first_comic")
|
|
77
|
-
.order_by("path")
|
|
78
|
-
.only("first_comic", "path")
|
|
79
|
-
.first()
|
|
80
|
-
)
|
|
81
|
-
if first_comic and not first_folder:
|
|
82
|
-
obj.first_comic = first_comic
|
|
83
|
-
elif first_folder and not first_comic:
|
|
84
|
-
obj.first_comic = first_folder.first_comic
|
|
85
|
-
elif first_folder and first_comic:
|
|
86
|
-
if first_comic and first_comic.path < first_folder.path:
|
|
87
|
-
obj.first_comic = first_comic
|
|
88
|
-
else:
|
|
89
|
-
obj.first_comic = first_folder.first_comic
|
|
90
|
-
|
|
91
|
-
@classmethod
|
|
92
|
-
def _update_first_cover(cls, model, obj):
|
|
93
|
-
if model == Volume:
|
|
94
|
-
cls._update_first_cover_volume(obj)
|
|
95
|
-
elif model == Series:
|
|
96
|
-
cls._update_first_cover_group(obj, Volume, "series")
|
|
97
|
-
elif model == Imprint:
|
|
98
|
-
cls._update_first_cover_group(obj, Series, "imprint")
|
|
99
|
-
elif model == Publisher:
|
|
100
|
-
cls._update_first_cover_group(obj, Imprint, "publisher")
|
|
101
|
-
elif model == StoryArc:
|
|
102
|
-
cls._update_first_cover_story_arc(obj)
|
|
103
|
-
elif model == Folder:
|
|
104
|
-
cls._update_first_cover_folder(obj)
|
|
38
|
+
def _add_child_count_filter(qs, model):
|
|
39
|
+
"""Filter out groups with no comics."""
|
|
40
|
+
rel_prefix = "storyarcnumber__" if model == StoryArc else ""
|
|
41
|
+
rel_prefix += "comic"
|
|
42
|
+
qs = qs.alias(child_count=Count(f"{rel_prefix}__pk", distinct=True))
|
|
43
|
+
return qs.filter(child_count__gt=0)
|
|
105
44
|
|
|
106
45
|
@classmethod
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
updated_at_rel = rel + "comic__updated_at__gt"
|
|
112
|
-
updated_filter = {updated_at_rel: start_time}
|
|
113
|
-
filter_query = (
|
|
114
|
-
Q(**updated_filter)
|
|
115
|
-
| Q(first_comic__isnull=True)
|
|
116
|
-
| Q(updated_at__gt=start_time)
|
|
46
|
+
def _update_group_model(cls, force_update_group_map, model, start_time, log_list):
|
|
47
|
+
"""Update a single group model."""
|
|
48
|
+
update_filter = cls._get_update_filter(
|
|
49
|
+
model, start_time, force_update_group_map
|
|
117
50
|
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
pks = force_update_group_map.get(model)
|
|
121
|
-
if pks:
|
|
122
|
-
filter_query |= Q(pk__in=pks)
|
|
123
|
-
model_qs = model.objects.filter(filter_query)
|
|
51
|
+
qs = model.objects.filter(update_filter)
|
|
52
|
+
qs = cls._add_child_count_filter(qs, model)
|
|
124
53
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
rel_prefix += "comic"
|
|
128
|
-
model_qs = model_qs.alias(child_count=Count(f"{rel_prefix}__pk", distinct=True))
|
|
129
|
-
model_qs = model_qs.filter(child_count__gt=0)
|
|
130
|
-
model_qs = model_qs.distinct()
|
|
131
|
-
if model == Folder:
|
|
132
|
-
batches = cls._get_folder_batches(model_qs)
|
|
133
|
-
else:
|
|
134
|
-
model_qs.select_related("first_comic").only(*_UPDATE_FIELDS)
|
|
135
|
-
batches = (model_qs,)
|
|
54
|
+
qs = qs.distinct()
|
|
55
|
+
qs = qs.only(*_UPDATE_FIELDS)
|
|
136
56
|
|
|
137
|
-
|
|
138
|
-
for
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
count
|
|
146
|
-
|
|
147
|
-
model.objects.bulk_update(updated, _UPDATE_FIELDS)
|
|
148
|
-
total_count += count
|
|
149
|
-
if total_count:
|
|
150
|
-
log_list.append(f"{total_count} {model.__name__}s")
|
|
151
|
-
return total_count
|
|
57
|
+
updated = []
|
|
58
|
+
for obj in qs:
|
|
59
|
+
obj.updated_at = Now()
|
|
60
|
+
updated.append(obj)
|
|
61
|
+
|
|
62
|
+
count = len(updated)
|
|
63
|
+
if count:
|
|
64
|
+
model.objects.bulk_update(updated, _UPDATE_FIELDS)
|
|
65
|
+
log_list.append(f"{count} {model.__name__}s")
|
|
66
|
+
return count
|
|
152
67
|
|
|
153
|
-
def
|
|
68
|
+
def update_all_groups(self, force_update_group_map, start_time):
|
|
154
69
|
"""Update timestamps for each group for cover cache busting."""
|
|
155
70
|
total_count = 0
|
|
156
71
|
status = Status(ImportStatusTypes.GROUP_UPDATE)
|
|
157
72
|
self.status_controller.start(status)
|
|
158
73
|
try:
|
|
159
74
|
log_list = []
|
|
160
|
-
for model in
|
|
161
|
-
# self.log.debug(f"Updating
|
|
162
|
-
count = self.
|
|
75
|
+
for model in GROUP_MODELS:
|
|
76
|
+
# self.log.debug(f"Updating timestamps for {model.__name__}s...")
|
|
77
|
+
count = self._update_group_model(
|
|
163
78
|
force_update_group_map, model, start_time, log_list
|
|
164
79
|
)
|
|
165
80
|
if count:
|
|
166
|
-
self.log.debug(
|
|
167
|
-
f"Updated {count} first covers for {model.__name__}s"
|
|
168
|
-
)
|
|
81
|
+
self.log.debug(f"Updated {count} {model.__name__}s timestamps.")
|
|
169
82
|
status.add_complete(count)
|
|
170
83
|
self.status_controller.update(status, notify=False)
|
|
171
84
|
total_count += count
|
|
@@ -173,7 +86,7 @@ class CacheUpdateImporter(InitImporter):
|
|
|
173
86
|
if total_count:
|
|
174
87
|
groups_log = ", ".join(log_list)
|
|
175
88
|
self.log.info( # type: ignore
|
|
176
|
-
f"Updated
|
|
89
|
+
f"Updated timestamps for {groups_log}."
|
|
177
90
|
)
|
|
178
91
|
self.changed += total_count
|
|
179
92
|
finally:
|
|
@@ -20,7 +20,7 @@ from codex.status import Status
|
|
|
20
20
|
class CreateComicsImporter(LinkComicsImporter):
|
|
21
21
|
"""Create comics methods."""
|
|
22
22
|
|
|
23
|
-
def _bulk_update_comics_add_comic(self,
|
|
23
|
+
def _bulk_update_comics_add_comic(self, comic, results):
|
|
24
24
|
"""Add one comic and stats to the bulk update list."""
|
|
25
25
|
try:
|
|
26
26
|
md = self.metadata[MDS].pop(comic.path)
|
|
@@ -33,7 +33,7 @@ class CreateComicsImporter(LinkComicsImporter):
|
|
|
33
33
|
value = default_value
|
|
34
34
|
setattr(comic, field_name, value)
|
|
35
35
|
comic.presave()
|
|
36
|
-
comic.updated_at =
|
|
36
|
+
comic.updated_at = Now()
|
|
37
37
|
update_comics, comic_pks, comic_update_paths = results
|
|
38
38
|
update_comics.append(comic)
|
|
39
39
|
comic_pks.append(comic.pk)
|
|
@@ -59,12 +59,11 @@ class CreateComicsImporter(LinkComicsImporter):
|
|
|
59
59
|
|
|
60
60
|
# set attributes for each comic
|
|
61
61
|
update_comics = []
|
|
62
|
-
now = Now()
|
|
63
62
|
comic_pks = []
|
|
64
63
|
comic_update_paths = set()
|
|
65
64
|
results = update_comics, comic_pks, comic_update_paths
|
|
66
65
|
for comic in comics.iterator():
|
|
67
|
-
self._bulk_update_comics_add_comic(
|
|
66
|
+
self._bulk_update_comics_add_comic(comic, results)
|
|
68
67
|
|
|
69
68
|
converted_create_paths = frozenset(
|
|
70
69
|
set(self.task.files_modified) - comic_update_paths
|
|
@@ -30,11 +30,9 @@ class CreateCoversImporter(CreateComicsImporter):
|
|
|
30
30
|
status = Status(ImportStatusTypes.COVERS_MODIFIED, 0, update_covers_count)
|
|
31
31
|
self.status_controller.start(status)
|
|
32
32
|
|
|
33
|
-
now = Now()
|
|
34
|
-
|
|
35
33
|
update_covers = []
|
|
36
34
|
for cover in update_covers_qs.only(*CUSTOM_COVER_UPDATE_FIELDS):
|
|
37
|
-
cover.updated_at =
|
|
35
|
+
cover.updated_at = Now()
|
|
38
36
|
cover.presave()
|
|
39
37
|
update_covers.append(cover)
|
|
40
38
|
|
|
@@ -211,8 +211,10 @@ class CreateForeignKeysImporter(CreateCoversImporter):
|
|
|
211
211
|
folder_path_dict[path_length].add(path)
|
|
212
212
|
|
|
213
213
|
# create each depth level first to ensure we can assign parents
|
|
214
|
-
for
|
|
214
|
+
for depth_level in sorted(folder_path_dict):
|
|
215
|
+
paths = sorted(folder_path_dict[depth_level])
|
|
215
216
|
count += self._bulk_folders_create_depth_level(paths, status)
|
|
217
|
+
self.log.debug(f"Created {count} Folders at depth level {depth_level}")
|
|
216
218
|
|
|
217
219
|
if count:
|
|
218
220
|
self.log.info(f"Created {count} Folders.")
|
|
@@ -84,13 +84,12 @@ class FailedImportsImporter(DeletedImporter):
|
|
|
84
84
|
).only(*_BULK_UPDATE_FAILED_IMPORT_FIELDS)
|
|
85
85
|
if not update_failed_import_objs:
|
|
86
86
|
return
|
|
87
|
-
now = Now()
|
|
88
87
|
for fi in update_failed_import_objs:
|
|
89
88
|
try:
|
|
90
89
|
exc = update_failed_imports.pop(fi.path)
|
|
91
90
|
fi.set_reason(exc)
|
|
92
91
|
fi.presave()
|
|
93
|
-
fi.updated_at =
|
|
92
|
+
fi.updated_at = Now()
|
|
94
93
|
except Exception as exc:
|
|
95
94
|
self.log.exception(
|
|
96
95
|
f"Error preparing failed import update for {fi.path}"
|
|
@@ -88,7 +88,7 @@ class ComicImporter(MovedImporter):
|
|
|
88
88
|
|
|
89
89
|
deleted_comic_groups = self.delete()
|
|
90
90
|
|
|
91
|
-
self.
|
|
91
|
+
self.update_all_groups(deleted_comic_groups, self.start_time)
|
|
92
92
|
|
|
93
93
|
finally:
|
|
94
94
|
self._finish_apply_status()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Bulk import and move comics and folders."""
|
|
2
2
|
|
|
3
|
-
from django.utils
|
|
3
|
+
from django.utils import timezone
|
|
4
4
|
|
|
5
5
|
from codex.librarian.importer.importer import ComicImporter
|
|
6
6
|
from codex.librarian.importer.status import ImportStatusTypes
|
|
@@ -8,7 +8,7 @@ from codex.librarian.importer.tasks import (
|
|
|
8
8
|
AdoptOrphanFoldersTask,
|
|
9
9
|
ImportDBDiffTask,
|
|
10
10
|
LazyImportComicsTask,
|
|
11
|
-
|
|
11
|
+
UpdateGroupsTask,
|
|
12
12
|
)
|
|
13
13
|
from codex.librarian.notifier.tasks import LIBRARY_CHANGED_TASK
|
|
14
14
|
from codex.models import Comic, Folder, Library
|
|
@@ -89,13 +89,13 @@ class ComicImporterThread(QueuedThread):
|
|
|
89
89
|
|
|
90
90
|
self.status_controller.finish_many((moved_status, status))
|
|
91
91
|
|
|
92
|
-
def
|
|
92
|
+
def _update_groups(self, task):
|
|
93
93
|
pks = Library.objects.filter(covers_only=False).values_list("pk", flat=True)
|
|
94
|
-
start_time = task.start_time if task.start_time else
|
|
94
|
+
start_time = task.start_time if task.start_time else timezone.now()
|
|
95
95
|
for pk in pks:
|
|
96
96
|
task = ImportDBDiffTask(library_id=pk)
|
|
97
97
|
importer = self._create_importer(task)
|
|
98
|
-
importer.
|
|
98
|
+
importer.update_all_groups({}, start_time)
|
|
99
99
|
self.librarian_queue.put(LIBRARY_CHANGED_TASK)
|
|
100
100
|
|
|
101
101
|
def process_item(self, item):
|
|
@@ -107,7 +107,7 @@ class ComicImporterThread(QueuedThread):
|
|
|
107
107
|
self._lazy_import_metadata(task)
|
|
108
108
|
elif isinstance(task, AdoptOrphanFoldersTask):
|
|
109
109
|
self._adopt_orphan_folders()
|
|
110
|
-
elif isinstance(task,
|
|
111
|
-
self.
|
|
110
|
+
elif isinstance(task, UpdateGroupsTask):
|
|
111
|
+
self._update_groups(task)
|
|
112
112
|
else:
|
|
113
113
|
self.log.warning(f"Bad task sent to library updater {task}")
|
|
@@ -42,7 +42,6 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
42
42
|
).only("pk", "path", PARENT_FOLDER, FOLDERS_FIELD)
|
|
43
43
|
|
|
44
44
|
folder_m2m_links = {}
|
|
45
|
-
now = Now()
|
|
46
45
|
updated_comics = []
|
|
47
46
|
for comic in comics.iterator():
|
|
48
47
|
try:
|
|
@@ -52,7 +51,7 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
52
51
|
comic.parent_folder = Folder.objects.get( # type: ignore
|
|
53
52
|
path=new_path.parent
|
|
54
53
|
)
|
|
55
|
-
comic.updated_at =
|
|
54
|
+
comic.updated_at = Now()
|
|
56
55
|
comic.presave()
|
|
57
56
|
folder_m2m_links[comic.pk] = Folder.objects.filter(
|
|
58
57
|
path__in=new_path.parents
|
|
@@ -83,7 +82,6 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
83
82
|
if status:
|
|
84
83
|
status.total = covers.count()
|
|
85
84
|
|
|
86
|
-
now = Now()
|
|
87
85
|
moved_covers = []
|
|
88
86
|
unlink_pks = set()
|
|
89
87
|
for cover in covers.iterator():
|
|
@@ -91,7 +89,7 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
91
89
|
new_path = self.task.covers_moved[cover.path]
|
|
92
90
|
cover.path = new_path
|
|
93
91
|
new_path = Path(new_path)
|
|
94
|
-
cover.updated_at =
|
|
92
|
+
cover.updated_at = Now()
|
|
95
93
|
cover.presave()
|
|
96
94
|
moved_covers.append(cover)
|
|
97
95
|
unlink_pks.add(cover.pk)
|
|
@@ -186,7 +184,6 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
186
184
|
).order_by("path")
|
|
187
185
|
|
|
188
186
|
update_folders = []
|
|
189
|
-
now = Now()
|
|
190
187
|
for folder in folders_to_move.iterator():
|
|
191
188
|
new_path = self.task.dirs_moved[folder.path]
|
|
192
189
|
folder.name = Path(new_path).name
|
|
@@ -194,7 +191,7 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
194
191
|
parent_path_str = str(Path(new_path).parent)
|
|
195
192
|
folder.parent_folder = dest_parent_folders.get(parent_path_str)
|
|
196
193
|
folder.presave()
|
|
197
|
-
folder.updated_at =
|
|
194
|
+
folder.updated_at = Now()
|
|
198
195
|
update_folders.append(folder)
|
|
199
196
|
self.task.dirs_moved = {}
|
|
200
197
|
|
|
@@ -220,10 +217,9 @@ class MovedImporter(AggregateMetadataImporter):
|
|
|
220
217
|
).only("stat", "updated_at")
|
|
221
218
|
self.task.dirs_modified = frozenset()
|
|
222
219
|
update_folders = []
|
|
223
|
-
now = Now()
|
|
224
220
|
for folder in folders.iterator():
|
|
225
221
|
if Path(folder.path).exists():
|
|
226
|
-
folder.updated_at =
|
|
222
|
+
folder.updated_at = Now()
|
|
227
223
|
folder.presave()
|
|
228
224
|
update_folders.append(folder)
|
|
229
225
|
Folder.objects.bulk_update(
|
|
@@ -47,7 +47,7 @@ class AdoptOrphanFoldersTask(ImportTask):
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
@dataclass
|
|
50
|
-
class
|
|
51
|
-
"""Force the update of
|
|
50
|
+
class UpdateGroupsTask(ImportTask):
|
|
51
|
+
"""Force the update of group timestamp."""
|
|
52
52
|
|
|
53
53
|
start_time: datetime | None = None
|
|
@@ -5,7 +5,6 @@ from codex.librarian.covers.tasks import CoverRemoveOrphansTask
|
|
|
5
5
|
from codex.librarian.importer.status import ImportStatusTypes
|
|
6
6
|
from codex.librarian.importer.tasks import (
|
|
7
7
|
AdoptOrphanFoldersTask,
|
|
8
|
-
UpdateGroupsFirstComic,
|
|
9
8
|
)
|
|
10
9
|
from codex.librarian.janitor.cleanup import TOTAL_NUM_FK_CLASSES, CleanupMixin
|
|
11
10
|
from codex.librarian.janitor.failed_imports import UpdateFailedImportsMixin
|
|
@@ -41,7 +40,6 @@ _JANITOR_STATII = (
|
|
|
41
40
|
Status(JanitorStatusTypes.DB_OPTIMIZE),
|
|
42
41
|
Status(JanitorStatusTypes.DB_BACKUP),
|
|
43
42
|
Status(JanitorStatusTypes.CODEX_UPDATE),
|
|
44
|
-
Status(ImportStatusTypes.GROUP_UPDATE),
|
|
45
43
|
Status(CoverStatusTypes.FIND_ORPHAN),
|
|
46
44
|
Status(CoverStatusTypes.PURGE_COVERS),
|
|
47
45
|
Status(ImportStatusTypes.ADOPT_FOLDERS),
|
|
@@ -75,7 +73,6 @@ class Janitor(CleanupMixin, UpdateMixin, VacuumMixin, UpdateFailedImportsMixin):
|
|
|
75
73
|
JanitorBackupTask(),
|
|
76
74
|
JanitorUpdateTask(force=False),
|
|
77
75
|
AdoptOrphanFoldersTask(),
|
|
78
|
-
UpdateGroupsFirstComic(),
|
|
79
76
|
CoverRemoveOrphansTask(),
|
|
80
77
|
SearchIndexUpdateTask(False),
|
|
81
78
|
SearchIndexMergeTask(optimize),
|
codex/librarian/librariand.py
CHANGED
|
@@ -14,7 +14,6 @@ from codex.librarian.importer.importerd import ComicImporterThread
|
|
|
14
14
|
from codex.librarian.importer.tasks import (
|
|
15
15
|
AdoptOrphanFoldersTask,
|
|
16
16
|
ImportTask,
|
|
17
|
-
UpdateGroupsFirstComic,
|
|
18
17
|
)
|
|
19
18
|
from codex.librarian.janitor.janitor import Janitor
|
|
20
19
|
from codex.librarian.janitor.janitord import JanitorThread
|
|
@@ -74,7 +73,6 @@ class LibrarianDaemon(Process, LoggerBaseMixin):
|
|
|
74
73
|
self.broadcast_queue = broadcast_queue
|
|
75
74
|
startup_tasks = (
|
|
76
75
|
AdoptOrphanFoldersTask(),
|
|
77
|
-
UpdateGroupsFirstComic(),
|
|
78
76
|
WatchdogSyncTask(),
|
|
79
77
|
SearchIndexRebuildIfDBChangedTask(),
|
|
80
78
|
)
|
|
@@ -10,9 +10,9 @@ class NotifierTask:
|
|
|
10
10
|
"""Handle with the Notifier."""
|
|
11
11
|
|
|
12
12
|
text: str
|
|
13
|
-
group:
|
|
13
|
+
group: str
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
LIBRARY_CHANGED_TASK = NotifierTask("LIBRARY_CHANGED", ChannelGroups.ALL)
|
|
17
|
-
LIBRARIAN_STATUS_TASK = NotifierTask("LIBRARIAN_STATUS", ChannelGroups.ADMIN)
|
|
18
|
-
FAILED_IMPORTS_TASK = NotifierTask("FAILED_IMPORTS", ChannelGroups.ADMIN)
|
|
16
|
+
LIBRARY_CHANGED_TASK = NotifierTask("LIBRARY_CHANGED", ChannelGroups.ALL.name)
|
|
17
|
+
LIBRARIAN_STATUS_TASK = NotifierTask("LIBRARIAN_STATUS", ChannelGroups.ADMIN.name)
|
|
18
|
+
FAILED_IMPORTS_TASK = NotifierTask("FAILED_IMPORTS", ChannelGroups.ADMIN.name)
|
codex/middleware.py
CHANGED
|
@@ -22,8 +22,7 @@ class TimezoneMiddleware:
|
|
|
22
22
|
|
|
23
23
|
def __call__(self, request):
|
|
24
24
|
"""Fix timeszone from the django session."""
|
|
25
|
-
tzname
|
|
26
|
-
if tzname:
|
|
25
|
+
if tzname := request.session.get("django_timezone"):
|
|
27
26
|
timezone.activate(tzname)
|
|
28
27
|
else:
|
|
29
28
|
timezone.deactivate()
|
|
@@ -71,33 +71,11 @@ class Migration(migrations.Migration):
|
|
|
71
71
|
name="sort_name",
|
|
72
72
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
73
73
|
),
|
|
74
|
-
migrations.AddField(
|
|
75
|
-
model_name="folder",
|
|
76
|
-
name="first_comic",
|
|
77
|
-
field=models.ForeignKey(
|
|
78
|
-
default=None,
|
|
79
|
-
null=True,
|
|
80
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
81
|
-
related_name="+",
|
|
82
|
-
to="codex.comic",
|
|
83
|
-
),
|
|
84
|
-
),
|
|
85
74
|
migrations.AddField(
|
|
86
75
|
model_name="folder",
|
|
87
76
|
name="sort_name",
|
|
88
77
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
89
78
|
),
|
|
90
|
-
migrations.AddField(
|
|
91
|
-
model_name="imprint",
|
|
92
|
-
name="first_comic",
|
|
93
|
-
field=models.ForeignKey(
|
|
94
|
-
default=None,
|
|
95
|
-
null=True,
|
|
96
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
97
|
-
related_name="+",
|
|
98
|
-
to="codex.comic",
|
|
99
|
-
),
|
|
100
|
-
),
|
|
101
79
|
migrations.AddField(
|
|
102
80
|
model_name="imprint",
|
|
103
81
|
name="sort_name",
|
|
@@ -108,65 +86,21 @@ class Migration(migrations.Migration):
|
|
|
108
86
|
name="covers_only",
|
|
109
87
|
field=models.BooleanField(db_index=True, default=False),
|
|
110
88
|
),
|
|
111
|
-
migrations.AddField(
|
|
112
|
-
model_name="publisher",
|
|
113
|
-
name="first_comic",
|
|
114
|
-
field=models.ForeignKey(
|
|
115
|
-
default=None,
|
|
116
|
-
null=True,
|
|
117
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
118
|
-
related_name="+",
|
|
119
|
-
to="codex.comic",
|
|
120
|
-
),
|
|
121
|
-
),
|
|
122
89
|
migrations.AddField(
|
|
123
90
|
model_name="publisher",
|
|
124
91
|
name="sort_name",
|
|
125
92
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
126
93
|
),
|
|
127
|
-
migrations.AddField(
|
|
128
|
-
model_name="series",
|
|
129
|
-
name="first_comic",
|
|
130
|
-
field=models.ForeignKey(
|
|
131
|
-
default=None,
|
|
132
|
-
null=True,
|
|
133
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
134
|
-
related_name="+",
|
|
135
|
-
to="codex.comic",
|
|
136
|
-
),
|
|
137
|
-
),
|
|
138
94
|
migrations.AddField(
|
|
139
95
|
model_name="series",
|
|
140
96
|
name="sort_name",
|
|
141
97
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
142
98
|
),
|
|
143
|
-
migrations.AddField(
|
|
144
|
-
model_name="storyarc",
|
|
145
|
-
name="first_comic",
|
|
146
|
-
field=models.ForeignKey(
|
|
147
|
-
default=None,
|
|
148
|
-
null=True,
|
|
149
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
150
|
-
related_name="+",
|
|
151
|
-
to="codex.comic",
|
|
152
|
-
),
|
|
153
|
-
),
|
|
154
99
|
migrations.AddField(
|
|
155
100
|
model_name="storyarc",
|
|
156
101
|
name="sort_name",
|
|
157
102
|
field=models.CharField(db_index=True, default="", max_length=128),
|
|
158
103
|
),
|
|
159
|
-
migrations.AddField(
|
|
160
|
-
model_name="volume",
|
|
161
|
-
name="first_comic",
|
|
162
|
-
field=models.ForeignKey(
|
|
163
|
-
default=None,
|
|
164
|
-
null=True,
|
|
165
|
-
on_delete=django.db.models.deletion.SET_DEFAULT,
|
|
166
|
-
related_name="+",
|
|
167
|
-
to="codex.comic",
|
|
168
|
-
),
|
|
169
|
-
),
|
|
170
104
|
migrations.AlterField(
|
|
171
105
|
model_name="adminflag",
|
|
172
106
|
name="key",
|
|
@@ -211,6 +145,7 @@ class Migration(migrations.Migration):
|
|
|
211
145
|
("ICD", "Covers Deleted"),
|
|
212
146
|
("ICL", "Covers Link"),
|
|
213
147
|
("IGU", "Group Update"),
|
|
148
|
+
("IAF", "Adopt Folders"),
|
|
214
149
|
("JTD", "Cleanup Fk"),
|
|
215
150
|
("JCU", "Codex Update"),
|
|
216
151
|
("JCR", "Codex Restart"),
|
codex/models/comic.py
CHANGED
codex/models/groups.py
CHANGED
|
@@ -25,9 +25,6 @@ class BrowserGroupModel(BaseModel):
|
|
|
25
25
|
custom_cover = ForeignKey(
|
|
26
26
|
CustomCover, on_delete=SET_DEFAULT, null=True, default=None
|
|
27
27
|
)
|
|
28
|
-
first_comic = ForeignKey(
|
|
29
|
-
"Comic", on_delete=SET_DEFAULT, null=True, default=None, related_name="+"
|
|
30
|
-
)
|
|
31
28
|
|
|
32
29
|
def set_sort_name(self):
|
|
33
30
|
"""Create sort_name for model."""
|