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.

Files changed (557) hide show
  1. codex/integrity.py +1 -2
  2. codex/librarian/importer/cache.py +46 -133
  3. codex/librarian/importer/create_comics.py +3 -4
  4. codex/librarian/importer/create_covers.py +1 -3
  5. codex/librarian/importer/create_fks.py +3 -1
  6. codex/librarian/importer/failed_imports.py +1 -2
  7. codex/librarian/importer/importer.py +1 -1
  8. codex/librarian/importer/importerd.py +7 -7
  9. codex/librarian/importer/moved.py +4 -8
  10. codex/librarian/importer/tasks.py +2 -2
  11. codex/librarian/janitor/janitor.py +0 -3
  12. codex/librarian/librariand.py +0 -2
  13. codex/librarian/notifier/notifierd.py +1 -1
  14. codex/librarian/notifier/tasks.py +4 -4
  15. codex/middleware.py +1 -2
  16. codex/migrations/0027_import_order_and_covers.py +1 -66
  17. codex/models/comic.py +0 -1
  18. codex/models/groups.py +0 -3
  19. codex/serializers/admin.py +41 -40
  20. codex/serializers/browser/choices.py +22 -6
  21. codex/serializers/browser/metadata.py +45 -1
  22. codex/serializers/browser/mtime.py +21 -0
  23. codex/serializers/browser/page.py +2 -4
  24. codex/serializers/browser/settings.py +34 -14
  25. codex/serializers/fields.py +27 -10
  26. codex/serializers/reader.py +16 -6
  27. codex/serializers/route.py +9 -4
  28. codex/serializers/settings.py +12 -0
  29. codex/settings/settings.py +10 -1
  30. codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js +1 -0
  31. codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js.br +0 -0
  32. codex/static_root/assets/VCheckbox-CY3rcqlS.de5154294920.js.gz +0 -0
  33. codex/static_root/assets/VCheckbox-CY3rcqlS.js +1 -0
  34. codex/static_root/assets/VCheckbox-CY3rcqlS.js.br +0 -0
  35. codex/static_root/assets/VCheckbox-CY3rcqlS.js.gz +0 -0
  36. codex/static_root/assets/{VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js → VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js} +1 -1
  37. codex/static_root/assets/VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js.br +0 -0
  38. codex/static_root/assets/VCheckboxBtn-D2tPTt6P.9a90d6818bf6.js.gz +0 -0
  39. codex/static_root/assets/{VCheckboxBtn-B8Z4NA-t.js → VCheckboxBtn-D2tPTt6P.js} +1 -1
  40. codex/static_root/assets/VCheckboxBtn-D2tPTt6P.js.br +0 -0
  41. codex/static_root/assets/VCheckboxBtn-D2tPTt6P.js.gz +0 -0
  42. codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js +1 -0
  43. codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js.br +0 -0
  44. codex/static_root/assets/VCombobox-aJr--Ou7.f290ccf2ce25.js.gz +0 -0
  45. codex/static_root/assets/VCombobox-aJr--Ou7.js +1 -0
  46. codex/static_root/assets/VCombobox-aJr--Ou7.js.br +0 -0
  47. codex/static_root/assets/VCombobox-aJr--Ou7.js.gz +0 -0
  48. codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js +1 -0
  49. codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js.br +0 -0
  50. codex/static_root/assets/VDialog-61pzfUB2.33f73beb5224.js.gz +0 -0
  51. codex/static_root/assets/VDialog-61pzfUB2.js +1 -0
  52. codex/static_root/assets/VDialog-61pzfUB2.js.br +0 -0
  53. codex/static_root/assets/VDialog-61pzfUB2.js.gz +0 -0
  54. codex/static_root/assets/{VDialog-C5Nxd_zP.css → VDialog-lQ13FnRR.1c801ad756b2.css} +1 -1
  55. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
  56. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
  57. codex/static_root/assets/{VDialog-C5Nxd_zP.d327f505ef0e.css → VDialog-lQ13FnRR.css} +1 -1
  58. codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
  59. codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
  60. codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js +1 -0
  61. codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js.br +0 -0
  62. codex/static_root/assets/VExpansionPanels-rewm0P4z.5c7680f815b6.js.gz +0 -0
  63. codex/static_root/assets/VExpansionPanels-rewm0P4z.js +1 -0
  64. codex/static_root/assets/VExpansionPanels-rewm0P4z.js.br +0 -0
  65. codex/static_root/assets/VExpansionPanels-rewm0P4z.js.gz +0 -0
  66. codex/static_root/assets/{VRadioGroup-BGa6_q5a.d1a3ad7266bd.js → VRadioGroup-QFQbK1qo.750a42b1b814.js} +1 -1
  67. codex/static_root/assets/VRadioGroup-QFQbK1qo.750a42b1b814.js.br +0 -0
  68. codex/static_root/assets/VRadioGroup-QFQbK1qo.750a42b1b814.js.gz +0 -0
  69. codex/static_root/assets/{VRadioGroup-BGa6_q5a.js → VRadioGroup-QFQbK1qo.js} +1 -1
  70. codex/static_root/assets/VRadioGroup-QFQbK1qo.js.br +0 -0
  71. codex/static_root/assets/VRadioGroup-QFQbK1qo.js.gz +0 -0
  72. codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js +1 -0
  73. codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js.br +0 -0
  74. codex/static_root/assets/VSelect-Dixy6okt.5d53830daa8a.js.gz +0 -0
  75. codex/static_root/assets/VSelect-Dixy6okt.js +1 -0
  76. codex/static_root/assets/VSelect-Dixy6okt.js.br +0 -0
  77. codex/static_root/assets/VSelect-Dixy6okt.js.gz +0 -0
  78. codex/static_root/assets/{VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js → VSelectionControl-MNmxKc3J.08055d00917e.js} +1 -1
  79. codex/static_root/assets/VSelectionControl-MNmxKc3J.08055d00917e.js.br +0 -0
  80. codex/static_root/assets/VSelectionControl-MNmxKc3J.08055d00917e.js.gz +0 -0
  81. codex/static_root/assets/{VSelectionControl-C8DP9rgp.js → VSelectionControl-MNmxKc3J.js} +1 -1
  82. codex/static_root/assets/VSelectionControl-MNmxKc3J.js.br +0 -0
  83. codex/static_root/assets/VSelectionControl-MNmxKc3J.js.gz +0 -0
  84. codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js +1 -0
  85. codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js.br +0 -0
  86. codex/static_root/assets/VSlideGroup-DZEV0FoV.5f996daf0e98.js.gz +0 -0
  87. codex/static_root/assets/VSlideGroup-DZEV0FoV.js +1 -0
  88. codex/static_root/assets/VSlideGroup-DZEV0FoV.js.br +0 -0
  89. codex/static_root/assets/VSlideGroup-DZEV0FoV.js.gz +0 -0
  90. codex/static_root/assets/{VTable-D1esKtlw.52165930e3b9.js → VTable-lcnYg9Ee.d72927b13c2e.js} +1 -1
  91. codex/static_root/assets/VTable-lcnYg9Ee.d72927b13c2e.js.br +0 -0
  92. codex/static_root/assets/VTable-lcnYg9Ee.d72927b13c2e.js.gz +0 -0
  93. codex/static_root/assets/{VTable-D1esKtlw.js → VTable-lcnYg9Ee.js} +1 -1
  94. codex/static_root/assets/VTable-lcnYg9Ee.js.br +0 -0
  95. codex/static_root/assets/VTable-lcnYg9Ee.js.gz +0 -0
  96. codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js +1 -0
  97. codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js.br +0 -0
  98. codex/static_root/assets/VTextField-BkFrjhdV.b02653a9b3b7.js.gz +0 -0
  99. codex/static_root/assets/VTextField-BkFrjhdV.js +1 -0
  100. codex/static_root/assets/VTextField-BkFrjhdV.js.br +0 -0
  101. codex/static_root/assets/VTextField-BkFrjhdV.js.gz +0 -0
  102. codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js +1 -0
  103. codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js.br +0 -0
  104. codex/static_root/assets/VWindowItem-C__tAqdc.9791c128c3b7.js.gz +0 -0
  105. codex/static_root/assets/VWindowItem-C__tAqdc.js +1 -0
  106. codex/static_root/assets/VWindowItem-C__tAqdc.js.br +0 -0
  107. codex/static_root/assets/VWindowItem-C__tAqdc.js.gz +0 -0
  108. codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js +1 -0
  109. codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js.br +0 -0
  110. codex/static_root/assets/admin-CXES2HXe.9e48a9bf84e0.js.gz +0 -0
  111. codex/static_root/assets/admin-CXES2HXe.js +1 -0
  112. codex/static_root/assets/admin-CXES2HXe.js.br +0 -0
  113. codex/static_root/assets/admin-CXES2HXe.js.gz +0 -0
  114. codex/static_root/assets/{admin-drawer-panel-o87BwD38.ce39427c8201.css → admin-drawer-panel-mne3FIj6.561b3f75fe65.css} +1 -1
  115. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
  116. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
  117. codex/static_root/assets/{admin-drawer-panel-o87BwD38.css → admin-drawer-panel-mne3FIj6.css} +1 -1
  118. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
  119. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
  120. codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js +30 -0
  121. codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js.br +0 -0
  122. codex/static_root/assets/admin-drawer-panel-rrNKi_GE.e2b034db7934.js.gz +0 -0
  123. codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js +30 -0
  124. codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js.br +0 -0
  125. codex/static_root/assets/admin-drawer-panel-rrNKi_GE.js.gz +0 -0
  126. codex/static_root/assets/browser-BuDeXGEe.css +1 -0
  127. codex/static_root/assets/browser-BuDeXGEe.css.br +0 -0
  128. codex/static_root/assets/browser-BuDeXGEe.css.gz +0 -0
  129. codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css +1 -0
  130. codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css.br +0 -0
  131. codex/static_root/assets/browser-BuDeXGEe.f60854183b45.css.gz +0 -0
  132. codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js +1 -0
  133. codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js.br +0 -0
  134. codex/static_root/assets/browser-s6mFzrK9.0d2200b451af.js.gz +0 -0
  135. codex/static_root/assets/browser-s6mFzrK9.js +1 -0
  136. codex/static_root/assets/browser-s6mFzrK9.js.br +0 -0
  137. codex/static_root/assets/browser-s6mFzrK9.js.gz +0 -0
  138. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +1 -0
  139. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
  140. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
  141. codex/static_root/assets/change-password-dialog-0u6IJA87.css +1 -0
  142. codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
  143. codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
  144. codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js +1 -0
  145. codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js.br +0 -0
  146. codex/static_root/assets/change-password-dialog-Bn20jYzD.593c5af1732b.js.gz +0 -0
  147. codex/static_root/assets/change-password-dialog-Bn20jYzD.js +1 -0
  148. codex/static_root/assets/change-password-dialog-Bn20jYzD.js.br +0 -0
  149. codex/static_root/assets/change-password-dialog-Bn20jYzD.js.gz +0 -0
  150. codex/static_root/assets/{confirm-dialog-DkU0twE6.a20006aa5ba6.js → confirm-dialog-CWszioQE.859051c35dd9.js} +1 -1
  151. codex/static_root/assets/confirm-dialog-CWszioQE.859051c35dd9.js.br +0 -0
  152. codex/static_root/assets/confirm-dialog-CWszioQE.859051c35dd9.js.gz +0 -0
  153. codex/static_root/assets/{confirm-dialog-DkU0twE6.js → confirm-dialog-CWszioQE.js} +1 -1
  154. codex/static_root/assets/confirm-dialog-CWszioQE.js.br +0 -0
  155. codex/static_root/assets/confirm-dialog-CWszioQE.js.gz +0 -0
  156. codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js +1 -0
  157. codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js.br +0 -0
  158. codex/static_root/assets/datetime-column-BSdlLt-4.27ec2df67a0b.js.gz +0 -0
  159. codex/static_root/assets/datetime-column-BSdlLt-4.js +1 -0
  160. codex/static_root/assets/datetime-column-BSdlLt-4.js.br +0 -0
  161. codex/static_root/assets/datetime-column-BSdlLt-4.js.gz +0 -0
  162. codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js +1 -0
  163. codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js.br +0 -0
  164. codex/static_root/assets/filter-D3gaGf87.1f14dbfd9929.js.gz +0 -0
  165. codex/static_root/assets/filter-D3gaGf87.js +1 -0
  166. codex/static_root/assets/filter-D3gaGf87.js.br +0 -0
  167. codex/static_root/assets/filter-D3gaGf87.js.gz +0 -0
  168. codex/static_root/assets/{flag-tab-D4ZNSbMR.e763a9937701.js → flag-tab-8vzpdySX.a982c7f0776a.js} +1 -1
  169. codex/static_root/assets/flag-tab-8vzpdySX.a982c7f0776a.js.br +0 -0
  170. codex/static_root/assets/flag-tab-8vzpdySX.a982c7f0776a.js.gz +0 -0
  171. codex/static_root/assets/{flag-tab-D4ZNSbMR.js → flag-tab-8vzpdySX.js} +1 -1
  172. codex/static_root/assets/flag-tab-8vzpdySX.js.br +0 -0
  173. codex/static_root/assets/flag-tab-8vzpdySX.js.gz +0 -0
  174. codex/static_root/assets/{group-tab-DucpNoBs.a6f37ae940c0.js → group-tab-Cz9t_ECi.a9e8aea79254.js} +1 -1
  175. codex/static_root/assets/group-tab-Cz9t_ECi.a9e8aea79254.js.br +0 -0
  176. codex/static_root/assets/group-tab-Cz9t_ECi.a9e8aea79254.js.gz +0 -0
  177. codex/static_root/assets/{group-tab-DucpNoBs.js → group-tab-Cz9t_ECi.js} +1 -1
  178. codex/static_root/assets/group-tab-Cz9t_ECi.js.br +0 -0
  179. codex/static_root/assets/group-tab-Cz9t_ECi.js.gz +0 -0
  180. codex/static_root/assets/{http-error-Cj0hTq-c.062a88ddd4dc.js → http-error-Cqtszzf1.b31df3d9c29f.js} +1 -1
  181. codex/static_root/assets/http-error-Cqtszzf1.b31df3d9c29f.js.br +0 -0
  182. codex/static_root/assets/http-error-Cqtszzf1.b31df3d9c29f.js.gz +0 -0
  183. codex/static_root/assets/{http-error-Cj0hTq-c.js → http-error-Cqtszzf1.js} +1 -1
  184. codex/static_root/assets/http-error-Cqtszzf1.js.br +0 -0
  185. codex/static_root/assets/http-error-Cqtszzf1.js.gz +0 -0
  186. codex/static_root/assets/{library-tab-CzksdS3Q.566acdb45dec.js → library-tab-DMlnswUU.30f454e84184.js} +1 -1
  187. codex/static_root/assets/library-tab-DMlnswUU.30f454e84184.js.br +0 -0
  188. codex/static_root/assets/library-tab-DMlnswUU.30f454e84184.js.gz +0 -0
  189. codex/static_root/assets/{library-tab-CzksdS3Q.js → library-tab-DMlnswUU.js} +1 -1
  190. codex/static_root/assets/library-tab-DMlnswUU.js.br +0 -0
  191. codex/static_root/assets/library-tab-DMlnswUU.js.gz +0 -0
  192. codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js +32 -0
  193. codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js.br +0 -0
  194. codex/static_root/assets/main-vjXu_QYL.548bd4c38799.js.gz +0 -0
  195. codex/static_root/assets/main-vjXu_QYL.js +32 -0
  196. codex/static_root/assets/main-vjXu_QYL.js.br +0 -0
  197. codex/static_root/assets/main-vjXu_QYL.js.gz +0 -0
  198. codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css +1 -0
  199. codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css.br +0 -0
  200. codex/static_root/assets/pagination-toolbar-DGdMiBRs.5829b01b8a2f.css.gz +0 -0
  201. codex/static_root/assets/pagination-toolbar-DGdMiBRs.css +1 -0
  202. codex/static_root/assets/pagination-toolbar-DGdMiBRs.css.br +0 -0
  203. codex/static_root/assets/pagination-toolbar-DGdMiBRs.css.gz +0 -0
  204. codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js +1 -0
  205. codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js.br +0 -0
  206. codex/static_root/assets/pagination-toolbar-JW78pa0q.91024effdab9.js.gz +0 -0
  207. codex/static_root/assets/pagination-toolbar-JW78pa0q.js +1 -0
  208. codex/static_root/assets/pagination-toolbar-JW78pa0q.js.br +0 -0
  209. codex/static_root/assets/pagination-toolbar-JW78pa0q.js.gz +0 -0
  210. codex/static_root/assets/{pdf-doc-GkMk4o5L.ef24c859a7a4.js → pdf-doc-BiamrjRZ.4c9be1ade43c.js} +1 -1
  211. codex/static_root/assets/pdf-doc-BiamrjRZ.4c9be1ade43c.js.br +0 -0
  212. codex/static_root/assets/pdf-doc-BiamrjRZ.4c9be1ade43c.js.gz +0 -0
  213. codex/static_root/assets/{pdf-doc-GkMk4o5L.js → pdf-doc-BiamrjRZ.js} +1 -1
  214. codex/static_root/assets/pdf-doc-BiamrjRZ.js.br +0 -0
  215. codex/static_root/assets/pdf-doc-BiamrjRZ.js.gz +0 -0
  216. codex/static_root/assets/{reader-CCCfpM3x.1553e45bd775.css → reader-BpsctRsY.5d72e393911a.css} +1 -1
  217. codex/static_root/assets/reader-BpsctRsY.5d72e393911a.css.br +0 -0
  218. codex/static_root/assets/reader-BpsctRsY.5d72e393911a.css.gz +0 -0
  219. codex/static_root/assets/{reader-CCCfpM3x.css → reader-BpsctRsY.css} +1 -1
  220. codex/static_root/assets/reader-BpsctRsY.css.br +0 -0
  221. codex/static_root/assets/reader-BpsctRsY.css.gz +0 -0
  222. codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js +2 -0
  223. codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js.br +0 -0
  224. codex/static_root/assets/reader-CDk8oZzB.ad62eebda920.js.gz +0 -0
  225. codex/static_root/assets/reader-CDk8oZzB.js +2 -0
  226. codex/static_root/assets/reader-CDk8oZzB.js.br +0 -0
  227. codex/static_root/assets/reader-CDk8oZzB.js.gz +0 -0
  228. codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js +1 -0
  229. codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js.br +0 -0
  230. codex/static_root/assets/relation-chips-C5acBjpy.dc67d4528868.js.gz +0 -0
  231. codex/static_root/assets/relation-chips-C5acBjpy.js +1 -0
  232. codex/static_root/assets/relation-chips-C5acBjpy.js.br +0 -0
  233. codex/static_root/assets/relation-chips-C5acBjpy.js.gz +0 -0
  234. codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js +2 -0
  235. codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js.br +0 -0
  236. codex/static_root/assets/settings-drawer-D_JuRi7F.f02f3f981f8f.js.gz +0 -0
  237. codex/static_root/assets/settings-drawer-D_JuRi7F.js +2 -0
  238. codex/static_root/assets/settings-drawer-D_JuRi7F.js.br +0 -0
  239. codex/static_root/assets/settings-drawer-D_JuRi7F.js.gz +0 -0
  240. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +1 -0
  241. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  242. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  243. codex/static_root/assets/stats-tab-B4yKuY0c.css +1 -0
  244. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  245. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  246. codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js +1 -0
  247. codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js.br +0 -0
  248. codex/static_root/assets/stats-tab-ClqRTk1z.c759ace65a87.js.gz +0 -0
  249. codex/static_root/assets/stats-tab-ClqRTk1z.js +1 -0
  250. codex/static_root/assets/stats-tab-ClqRTk1z.js.br +0 -0
  251. codex/static_root/assets/stats-tab-ClqRTk1z.js.gz +0 -0
  252. codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js +1 -0
  253. codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js.br +0 -0
  254. codex/static_root/assets/task-tab-DF9qa6LO.0b32cafde4ad.js.gz +0 -0
  255. codex/static_root/assets/task-tab-DF9qa6LO.js +1 -0
  256. codex/static_root/assets/task-tab-DF9qa6LO.js.br +0 -0
  257. codex/static_root/assets/task-tab-DF9qa6LO.js.gz +0 -0
  258. codex/static_root/assets/to-case-CGbULRaE.4c80644f460d.js +1 -0
  259. codex/static_root/assets/to-case-CGbULRaE.4c80644f460d.js.br +0 -0
  260. codex/static_root/assets/to-case-CGbULRaE.js +1 -0
  261. codex/static_root/assets/to-case-CGbULRaE.js.br +0 -0
  262. codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js +1 -0
  263. codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js.br +0 -0
  264. codex/static_root/assets/unauthorized-BjKuLH6k.2ae00ddd79fb.js.gz +0 -0
  265. codex/static_root/assets/unauthorized-BjKuLH6k.js +1 -0
  266. codex/static_root/assets/unauthorized-BjKuLH6k.js.br +0 -0
  267. codex/static_root/assets/unauthorized-BjKuLH6k.js.gz +0 -0
  268. codex/static_root/assets/{unauthorized-DHV6Q1n-.b7847b2872a1.css → unauthorized-CibJYD8o.4c2de98c2b53.css} +1 -1
  269. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
  270. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
  271. codex/static_root/assets/{unauthorized-DHV6Q1n-.css → unauthorized-CibJYD8o.css} +1 -1
  272. codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
  273. codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
  274. codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js +1 -0
  275. codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js.br +0 -0
  276. codex/static_root/assets/user-tab-Dpxe3ygA.7d90174631f0.js.gz +0 -0
  277. codex/static_root/assets/user-tab-Dpxe3ygA.js +1 -0
  278. codex/static_root/assets/user-tab-Dpxe3ygA.js.br +0 -0
  279. codex/static_root/assets/user-tab-Dpxe3ygA.js.gz +0 -0
  280. codex/static_root/js/choices-admin.3521e2a863df.json +1 -0
  281. codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
  282. codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
  283. codex/static_root/js/choices-admin.json +1 -1
  284. codex/static_root/js/choices-admin.json.br +0 -0
  285. codex/static_root/js/choices-admin.json.gz +0 -0
  286. codex/static_root/manifest.35e46a3ec8fa.json +622 -0
  287. codex/static_root/manifest.35e46a3ec8fa.json.br +0 -0
  288. codex/static_root/manifest.35e46a3ec8fa.json.gz +0 -0
  289. codex/static_root/manifest.json +245 -252
  290. codex/static_root/manifest.json.br +0 -0
  291. codex/static_root/manifest.json.gz +0 -0
  292. codex/static_root/staticfiles.json +1 -1
  293. codex/urls/api/v3.py +1 -1
  294. codex/views/admin/api_key.py +5 -2
  295. codex/views/admin/stats.py +13 -20
  296. codex/views/admin/tasks.py +3 -7
  297. codex/views/auth.py +1 -1
  298. codex/views/bookmark.py +69 -51
  299. codex/views/browser/annotations.py +32 -45
  300. codex/views/browser/base.py +25 -8
  301. codex/views/browser/breadcrumbs.py +5 -5
  302. codex/views/browser/browser.py +20 -32
  303. codex/views/browser/choices.py +18 -15
  304. codex/views/browser/cover.py +30 -66
  305. codex/views/browser/filters/annotations.py +66 -14
  306. codex/views/browser/filters/bookmark.py +21 -5
  307. codex/views/browser/filters/group.py +29 -17
  308. codex/views/browser/filters/search.py +3 -4
  309. codex/views/browser/metadata.py +86 -47
  310. codex/views/browser/mtime.py +61 -0
  311. codex/views/browser/order_by.py +1 -6
  312. codex/views/browser/settings.py +53 -0
  313. codex/views/browser/validate.py +3 -0
  314. codex/views/const.py +32 -1
  315. codex/views/opds/v1/feed.py +3 -5
  316. codex/views/opds/v2/feed.py +3 -3
  317. codex/views/reader/arcs.py +42 -51
  318. codex/views/reader/books.py +48 -66
  319. codex/views/reader/init.py +121 -0
  320. codex/views/reader/reader.py +8 -66
  321. codex/views/session.py +15 -11
  322. codex/views/settings.py +23 -10
  323. codex/views/util.py +2 -1
  324. codex/websockets/consumers.py +13 -9
  325. {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/METADATA +1 -1
  326. {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/RECORD +329 -325
  327. codex/serializers/mtime.py +0 -25
  328. codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js +0 -1
  329. codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js.br +0 -0
  330. codex/static_root/assets/VCheckbox-DI-DgMb4.8eeb1bd3e18b.js.gz +0 -0
  331. codex/static_root/assets/VCheckbox-DI-DgMb4.js +0 -1
  332. codex/static_root/assets/VCheckbox-DI-DgMb4.js.br +0 -0
  333. codex/static_root/assets/VCheckbox-DI-DgMb4.js.gz +0 -0
  334. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js.br +0 -0
  335. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.3d8921f98ad9.js.gz +0 -0
  336. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.js.br +0 -0
  337. codex/static_root/assets/VCheckboxBtn-B8Z4NA-t.js.gz +0 -0
  338. codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js +0 -1
  339. codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js.br +0 -0
  340. codex/static_root/assets/VCombobox-D1_0lCri.6ef85a29c2dc.js.gz +0 -0
  341. codex/static_root/assets/VCombobox-D1_0lCri.js +0 -1
  342. codex/static_root/assets/VCombobox-D1_0lCri.js.br +0 -0
  343. codex/static_root/assets/VCombobox-D1_0lCri.js.gz +0 -0
  344. codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
  345. codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
  346. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
  347. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
  348. codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js +0 -1
  349. codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js.br +0 -0
  350. codex/static_root/assets/VDialog-opmV0YZz.d77216e97599.js.gz +0 -0
  351. codex/static_root/assets/VDialog-opmV0YZz.js +0 -1
  352. codex/static_root/assets/VDialog-opmV0YZz.js.br +0 -0
  353. codex/static_root/assets/VDialog-opmV0YZz.js.gz +0 -0
  354. codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js +0 -1
  355. codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js.br +0 -0
  356. codex/static_root/assets/VExpansionPanels-DX2dhUf5.ecc2ebfa62ec.js.gz +0 -0
  357. codex/static_root/assets/VExpansionPanels-DX2dhUf5.js +0 -1
  358. codex/static_root/assets/VExpansionPanels-DX2dhUf5.js.br +0 -0
  359. codex/static_root/assets/VExpansionPanels-DX2dhUf5.js.gz +0 -0
  360. codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js.br +0 -0
  361. codex/static_root/assets/VRadioGroup-BGa6_q5a.d1a3ad7266bd.js.gz +0 -0
  362. codex/static_root/assets/VRadioGroup-BGa6_q5a.js.br +0 -0
  363. codex/static_root/assets/VRadioGroup-BGa6_q5a.js.gz +0 -0
  364. codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js +0 -1
  365. codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js.br +0 -0
  366. codex/static_root/assets/VSelect-sIYW_-ud.7d40da0ec3ff.js.gz +0 -0
  367. codex/static_root/assets/VSelect-sIYW_-ud.js +0 -1
  368. codex/static_root/assets/VSelect-sIYW_-ud.js.br +0 -0
  369. codex/static_root/assets/VSelect-sIYW_-ud.js.gz +0 -0
  370. codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js.br +0 -0
  371. codex/static_root/assets/VSelectionControl-C8DP9rgp.ef80e8e3dfc1.js.gz +0 -0
  372. codex/static_root/assets/VSelectionControl-C8DP9rgp.js.br +0 -0
  373. codex/static_root/assets/VSelectionControl-C8DP9rgp.js.gz +0 -0
  374. codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js +0 -1
  375. codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js.br +0 -0
  376. codex/static_root/assets/VSlideGroup-BRYhkLH8.3534ec94b2f1.js.gz +0 -0
  377. codex/static_root/assets/VSlideGroup-BRYhkLH8.js +0 -1
  378. codex/static_root/assets/VSlideGroup-BRYhkLH8.js.br +0 -0
  379. codex/static_root/assets/VSlideGroup-BRYhkLH8.js.gz +0 -0
  380. codex/static_root/assets/VTable-D1esKtlw.52165930e3b9.js.br +0 -0
  381. codex/static_root/assets/VTable-D1esKtlw.52165930e3b9.js.gz +0 -0
  382. codex/static_root/assets/VTable-D1esKtlw.js.br +0 -0
  383. codex/static_root/assets/VTable-D1esKtlw.js.gz +0 -0
  384. codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js +0 -1
  385. codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js.br +0 -0
  386. codex/static_root/assets/VTextField-BnGscKcY.54032adf3a4b.js.gz +0 -0
  387. codex/static_root/assets/VTextField-BnGscKcY.js +0 -1
  388. codex/static_root/assets/VTextField-BnGscKcY.js.br +0 -0
  389. codex/static_root/assets/VTextField-BnGscKcY.js.gz +0 -0
  390. codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js +0 -1
  391. codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js.br +0 -0
  392. codex/static_root/assets/VWindowItem-B0KokcAk.ea94224aecb9.js.gz +0 -0
  393. codex/static_root/assets/VWindowItem-B0KokcAk.js +0 -1
  394. codex/static_root/assets/VWindowItem-B0KokcAk.js.br +0 -0
  395. codex/static_root/assets/VWindowItem-B0KokcAk.js.gz +0 -0
  396. codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js +0 -1
  397. codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js.br +0 -0
  398. codex/static_root/assets/admin-Y0bL21AB.42d4f0d68163.js.gz +0 -0
  399. codex/static_root/assets/admin-Y0bL21AB.js +0 -1
  400. codex/static_root/assets/admin-Y0bL21AB.js.br +0 -0
  401. codex/static_root/assets/admin-Y0bL21AB.js.gz +0 -0
  402. codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js +0 -30
  403. codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js.br +0 -0
  404. codex/static_root/assets/admin-drawer-panel-DNngWUEM.4e992e3fe86e.js.gz +0 -0
  405. codex/static_root/assets/admin-drawer-panel-DNngWUEM.js +0 -30
  406. codex/static_root/assets/admin-drawer-panel-DNngWUEM.js.br +0 -0
  407. codex/static_root/assets/admin-drawer-panel-DNngWUEM.js.gz +0 -0
  408. codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
  409. codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.gz +0 -0
  410. codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
  411. codex/static_root/assets/admin-drawer-panel-o87BwD38.css.gz +0 -0
  412. codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css +0 -1
  413. codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css.br +0 -0
  414. codex/static_root/assets/browser-CMAtBCLx.17a277ce43a9.css.gz +0 -0
  415. codex/static_root/assets/browser-CMAtBCLx.css +0 -1
  416. codex/static_root/assets/browser-CMAtBCLx.css.br +0 -0
  417. codex/static_root/assets/browser-CMAtBCLx.css.gz +0 -0
  418. codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js +0 -1
  419. codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js.br +0 -0
  420. codex/static_root/assets/browser-DoJk8uvb.2c97a3858932.js.gz +0 -0
  421. codex/static_root/assets/browser-DoJk8uvb.js +0 -1
  422. codex/static_root/assets/browser-DoJk8uvb.js.br +0 -0
  423. codex/static_root/assets/browser-DoJk8uvb.js.gz +0 -0
  424. codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js +0 -1
  425. codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js.br +0 -0
  426. codex/static_root/assets/change-password-dialog-CH4xbjJa.b749aa6ea07e.js.gz +0 -0
  427. codex/static_root/assets/change-password-dialog-CH4xbjJa.js +0 -1
  428. codex/static_root/assets/change-password-dialog-CH4xbjJa.js.br +0 -0
  429. codex/static_root/assets/change-password-dialog-CH4xbjJa.js.gz +0 -0
  430. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +0 -1
  431. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
  432. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
  433. codex/static_root/assets/change-password-dialog-HvIvmmIE.css +0 -1
  434. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
  435. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
  436. codex/static_root/assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js.br +0 -0
  437. codex/static_root/assets/confirm-dialog-DkU0twE6.a20006aa5ba6.js.gz +0 -0
  438. codex/static_root/assets/confirm-dialog-DkU0twE6.js.br +0 -0
  439. codex/static_root/assets/confirm-dialog-DkU0twE6.js.gz +0 -0
  440. codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js +0 -1
  441. codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js.br +0 -0
  442. codex/static_root/assets/datetime-column-BfW_j_3Q.6a614321a435.js.gz +0 -0
  443. codex/static_root/assets/datetime-column-BfW_j_3Q.js +0 -1
  444. codex/static_root/assets/datetime-column-BfW_j_3Q.js.br +0 -0
  445. codex/static_root/assets/datetime-column-BfW_j_3Q.js.gz +0 -0
  446. codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js +0 -1
  447. codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js.br +0 -0
  448. codex/static_root/assets/filter-DjxN78cK.35673f6e49b1.js.gz +0 -0
  449. codex/static_root/assets/filter-DjxN78cK.js +0 -1
  450. codex/static_root/assets/filter-DjxN78cK.js.br +0 -0
  451. codex/static_root/assets/filter-DjxN78cK.js.gz +0 -0
  452. codex/static_root/assets/flag-tab-D4ZNSbMR.e763a9937701.js.br +0 -0
  453. codex/static_root/assets/flag-tab-D4ZNSbMR.e763a9937701.js.gz +0 -0
  454. codex/static_root/assets/flag-tab-D4ZNSbMR.js.br +0 -0
  455. codex/static_root/assets/flag-tab-D4ZNSbMR.js.gz +0 -0
  456. codex/static_root/assets/group-tab-DucpNoBs.a6f37ae940c0.js.br +0 -0
  457. codex/static_root/assets/group-tab-DucpNoBs.a6f37ae940c0.js.gz +0 -0
  458. codex/static_root/assets/group-tab-DucpNoBs.js.br +0 -0
  459. codex/static_root/assets/group-tab-DucpNoBs.js.gz +0 -0
  460. codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js.br +0 -0
  461. codex/static_root/assets/http-error-Cj0hTq-c.062a88ddd4dc.js.gz +0 -0
  462. codex/static_root/assets/http-error-Cj0hTq-c.js.br +0 -0
  463. codex/static_root/assets/http-error-Cj0hTq-c.js.gz +0 -0
  464. codex/static_root/assets/library-tab-CzksdS3Q.566acdb45dec.js.br +0 -0
  465. codex/static_root/assets/library-tab-CzksdS3Q.566acdb45dec.js.gz +0 -0
  466. codex/static_root/assets/library-tab-CzksdS3Q.js.br +0 -0
  467. codex/static_root/assets/library-tab-CzksdS3Q.js.gz +0 -0
  468. codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js +0 -32
  469. codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js.br +0 -0
  470. codex/static_root/assets/main-DX-k2724.f73d08e9ad64.js.gz +0 -0
  471. codex/static_root/assets/main-DX-k2724.js +0 -32
  472. codex/static_root/assets/main-DX-k2724.js.br +0 -0
  473. codex/static_root/assets/main-DX-k2724.js.gz +0 -0
  474. codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js +0 -1
  475. codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js.br +0 -0
  476. codex/static_root/assets/pagination-toolbar-CQcR0a3T.7a2d33ed8c39.js.gz +0 -0
  477. codex/static_root/assets/pagination-toolbar-CQcR0a3T.js +0 -1
  478. codex/static_root/assets/pagination-toolbar-CQcR0a3T.js.br +0 -0
  479. codex/static_root/assets/pagination-toolbar-CQcR0a3T.js.gz +0 -0
  480. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css +0 -1
  481. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.br +0 -0
  482. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.gz +0 -0
  483. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css +0 -1
  484. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.br +0 -0
  485. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.gz +0 -0
  486. codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js.br +0 -0
  487. codex/static_root/assets/pdf-doc-GkMk4o5L.ef24c859a7a4.js.gz +0 -0
  488. codex/static_root/assets/pdf-doc-GkMk4o5L.js.br +0 -0
  489. codex/static_root/assets/pdf-doc-GkMk4o5L.js.gz +0 -0
  490. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.br +0 -0
  491. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.gz +0 -0
  492. codex/static_root/assets/reader-CCCfpM3x.css.br +0 -0
  493. codex/static_root/assets/reader-CCCfpM3x.css.gz +0 -0
  494. codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js +0 -2
  495. codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js.br +0 -0
  496. codex/static_root/assets/reader-Cl6mmQB_.7b9e7591954f.js.gz +0 -0
  497. codex/static_root/assets/reader-Cl6mmQB_.js +0 -2
  498. codex/static_root/assets/reader-Cl6mmQB_.js.br +0 -0
  499. codex/static_root/assets/reader-Cl6mmQB_.js.gz +0 -0
  500. codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js +0 -1
  501. codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js.br +0 -0
  502. codex/static_root/assets/relation-chips-CZ8VvR4y.d4232f3c2518.js.gz +0 -0
  503. codex/static_root/assets/relation-chips-CZ8VvR4y.js +0 -1
  504. codex/static_root/assets/relation-chips-CZ8VvR4y.js.br +0 -0
  505. codex/static_root/assets/relation-chips-CZ8VvR4y.js.gz +0 -0
  506. codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js +0 -2
  507. codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js.br +0 -0
  508. codex/static_root/assets/settings-drawer-DyS0A2pN.17a98928589f.js.gz +0 -0
  509. codex/static_root/assets/settings-drawer-DyS0A2pN.js +0 -2
  510. codex/static_root/assets/settings-drawer-DyS0A2pN.js.br +0 -0
  511. codex/static_root/assets/settings-drawer-DyS0A2pN.js.gz +0 -0
  512. codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js +0 -1
  513. codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js.br +0 -0
  514. codex/static_root/assets/stats-tab-R3Ekobfm.70fa09a67518.js.gz +0 -0
  515. codex/static_root/assets/stats-tab-R3Ekobfm.js +0 -1
  516. codex/static_root/assets/stats-tab-R3Ekobfm.js.br +0 -0
  517. codex/static_root/assets/stats-tab-R3Ekobfm.js.gz +0 -0
  518. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +0 -1
  519. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +0 -2
  520. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
  521. codex/static_root/assets/stats-tab-TsyG3wH_.css +0 -1
  522. codex/static_root/assets/stats-tab-TsyG3wH_.css.br +0 -2
  523. codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
  524. codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js +0 -1
  525. codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js.br +0 -0
  526. codex/static_root/assets/task-tab-BhLDK_7Q.28ff51b3ed01.js.gz +0 -0
  527. codex/static_root/assets/task-tab-BhLDK_7Q.js +0 -1
  528. codex/static_root/assets/task-tab-BhLDK_7Q.js.br +0 -0
  529. codex/static_root/assets/task-tab-BhLDK_7Q.js.gz +0 -0
  530. codex/static_root/assets/to-case-BR2frjFx.87de5d7a0503.js +0 -1
  531. codex/static_root/assets/to-case-BR2frjFx.js +0 -1
  532. codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js +0 -1
  533. codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js.br +0 -0
  534. codex/static_root/assets/unauthorized-BbXjAe5l.d48912d34a68.js.gz +0 -0
  535. codex/static_root/assets/unauthorized-BbXjAe5l.js +0 -1
  536. codex/static_root/assets/unauthorized-BbXjAe5l.js.br +0 -0
  537. codex/static_root/assets/unauthorized-BbXjAe5l.js.gz +0 -0
  538. codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.br +0 -0
  539. codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.gz +0 -0
  540. codex/static_root/assets/unauthorized-DHV6Q1n-.css.br +0 -0
  541. codex/static_root/assets/unauthorized-DHV6Q1n-.css.gz +0 -0
  542. codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js +0 -1
  543. codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js.br +0 -0
  544. codex/static_root/assets/user-tab-DxITIl2d.d79d7f062930.js.gz +0 -0
  545. codex/static_root/assets/user-tab-DxITIl2d.js +0 -1
  546. codex/static_root/assets/user-tab-DxITIl2d.js.br +0 -0
  547. codex/static_root/assets/user-tab-DxITIl2d.js.gz +0 -0
  548. codex/static_root/js/choices-admin.d790df01c20a.json +0 -1
  549. codex/static_root/js/choices-admin.d790df01c20a.json.br +0 -0
  550. codex/static_root/js/choices-admin.d790df01c20a.json.gz +0 -0
  551. codex/static_root/manifest.16d52597ef50.json +0 -629
  552. codex/static_root/manifest.16d52597ef50.json.br +0 -0
  553. codex/static_root/manifest.16d52597ef50.json.gz +0 -0
  554. codex/views/mtime.py +0 -72
  555. {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/LICENSE +0 -0
  556. {codex-1.6.0a8.dist-info → codex-1.6.0a10.dist-info}/WHEEL +0 -0
  557. {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 = now
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 Comic, Folder, Imprint, Publisher, Series, StoryArc, Volume
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
- _FIRST_COVER_MODEL_UPDATE_ORDER = (Volume, Series, Imprint, Publisher, Folder, StoryArc)
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 _get_folder_batches(model_qs):
23
- """Create batches of folders by folder depth level."""
24
- # Collect all related folders
25
- folder_pks = model_qs.values_list("pk", flat=True)
26
- all_folders = (
27
- Folder.objects.filter(Q(folder__pk__in=folder_pks) | Q(pk__in=folder_pks))
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
- @staticmethod
48
- def _update_first_cover_volume(obj):
49
- qs = Comic.objects.filter(volume=obj)
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
- @staticmethod
54
- def _update_first_cover_group(obj, model, field):
55
- qs = model.objects.filter(**{field: obj})
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
- @staticmethod
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 _update_first_cover_folder(obj):
68
- first_comic = (
69
- Comic.objects.filter(parent_folder=obj)
70
- .order_by("path")
71
- .only("path")
72
- .first()
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 _update_group_first_comic(
108
- cls, force_update_group_map, model, start_time, log_list
109
- ):
110
- rel = "storyarcnumber__" if model == StoryArc else ""
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
- if model != Volume:
119
- filter_query |= Q(custom_cover__updated_at__gt=start_time)
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
- # only update those with comics
126
- rel_prefix = "storyarcnumber__" if model == StoryArc else ""
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
- total_count = 0
138
- for model_qs in batches:
139
- updated = []
140
- for obj in model_qs:
141
- cls._update_first_cover(model, obj)
142
- obj.updated_at = Now()
143
- updated.append(obj)
144
-
145
- count = len(updated)
146
- if count:
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 update_all_groups_first_comics(self, force_update_group_map, start_time):
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 _FIRST_COVER_MODEL_UPDATE_ORDER:
161
- # self.log.debug(f"Updating first covers for {model.__name__}s...")
162
- count = self._update_group_first_comic(
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 first covers for {groups_log}."
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, now, comic, results):
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 = now
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(now, comic, results)
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 = now
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 paths in sorted(folder_path_dict.values()):
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 = now
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.update_all_groups_first_comics(deleted_comic_groups, self.start_time)
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.timezone import datetime
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
- UpdateGroupsFirstComic,
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 _update_groups_first_comic(self, task):
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 datetime.now()
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.update_all_groups_first_comics({}, start_time)
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, UpdateGroupsFirstComic):
111
- self._update_groups_first_comic(task)
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 = now
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 = now
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 = now # type: ignore
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 = now
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 UpdateGroupsFirstComic(ImportTask):
51
- """Force the update of the first comics."""
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),
@@ -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
  )
@@ -22,7 +22,7 @@ class NotifierThread(AggregateMessageQueuedThread):
22
22
  and do a group_send with it's message.
23
23
  """
24
24
  item = {
25
- "group": task.group.name,
25
+ "group": task.group,
26
26
  "message": {
27
27
  "type": "send_text",
28
28
  "text": task.text,
@@ -10,9 +10,9 @@ class NotifierTask:
10
10
  """Handle with the Notifier."""
11
11
 
12
12
  text: str
13
- group: ChannelGroups
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 = request.session.get("django_timezone")
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
@@ -176,7 +176,6 @@ class Comic(WatchedPathBrowserGroup):
176
176
 
177
177
  # Not useful
178
178
  custom_cover = None
179
- first_comic = None
180
179
 
181
180
  class Meta(WatchedPathBrowserGroup.Meta):
182
181
  """Constraints."""
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."""