codex 1.6.0a9__py3-none-any.whl → 1.6.0a11__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 (560) hide show
  1. codex/librarian/importer/cache.py +46 -133
  2. codex/librarian/importer/create_fks.py +3 -1
  3. codex/librarian/importer/importer.py +1 -1
  4. codex/librarian/importer/importerd.py +5 -5
  5. codex/librarian/importer/tasks.py +2 -2
  6. codex/librarian/janitor/janitor.py +0 -3
  7. codex/librarian/librariand.py +0 -2
  8. codex/librarian/notifier/notifierd.py +1 -1
  9. codex/librarian/notifier/tasks.py +4 -4
  10. codex/middleware.py +1 -2
  11. codex/migrations/0027_import_order_and_covers.py +1 -66
  12. codex/models/comic.py +0 -1
  13. codex/models/groups.py +0 -3
  14. codex/serializers/admin.py +41 -40
  15. codex/serializers/browser/choices.py +38 -10
  16. codex/serializers/browser/filters.py +2 -2
  17. codex/serializers/browser/metadata.py +45 -1
  18. codex/serializers/browser/mixins.py +35 -2
  19. codex/serializers/browser/page.py +2 -4
  20. codex/serializers/browser/settings.py +41 -14
  21. codex/serializers/choices.py +4 -0
  22. codex/serializers/fields.py +61 -1
  23. codex/serializers/models/pycountry.py +11 -51
  24. codex/serializers/reader.py +12 -1
  25. codex/serializers/route.py +1 -1
  26. codex/serializers/settings.py +12 -0
  27. codex/settings/settings.py +10 -1
  28. codex/static_root/assets/VCheckbox-BwDyxhU7.831b00df198a.js +1 -0
  29. codex/static_root/assets/VCheckbox-BwDyxhU7.831b00df198a.js.br +0 -0
  30. codex/static_root/assets/VCheckbox-BwDyxhU7.831b00df198a.js.gz +0 -0
  31. codex/static_root/assets/VCheckbox-BwDyxhU7.js +1 -0
  32. codex/static_root/assets/VCheckbox-BwDyxhU7.js.br +0 -0
  33. codex/static_root/assets/VCheckbox-BwDyxhU7.js.gz +0 -0
  34. codex/static_root/assets/{VCheckboxBtn-DLzF_WHB.9a47873b8548.js → VCheckboxBtn-DVq5lDK4.5e6464c8d80a.js} +1 -1
  35. codex/static_root/assets/VCheckboxBtn-DVq5lDK4.5e6464c8d80a.js.br +0 -0
  36. codex/static_root/assets/VCheckboxBtn-DVq5lDK4.5e6464c8d80a.js.gz +0 -0
  37. codex/static_root/assets/{VCheckboxBtn-DLzF_WHB.js → VCheckboxBtn-DVq5lDK4.js} +1 -1
  38. codex/static_root/assets/VCheckboxBtn-DVq5lDK4.js.br +0 -0
  39. codex/static_root/assets/VCheckboxBtn-DVq5lDK4.js.gz +0 -0
  40. codex/static_root/assets/VCombobox-BASCOy0n.7801caa5e192.js +1 -0
  41. codex/static_root/assets/VCombobox-BASCOy0n.7801caa5e192.js.br +0 -0
  42. codex/static_root/assets/VCombobox-BASCOy0n.7801caa5e192.js.gz +0 -0
  43. codex/static_root/assets/VCombobox-BASCOy0n.js +1 -0
  44. codex/static_root/assets/VCombobox-BASCOy0n.js.br +0 -0
  45. codex/static_root/assets/VCombobox-BASCOy0n.js.gz +0 -0
  46. codex/static_root/assets/VDialog-DnbL_v_u.0bd289bda8e6.js +1 -0
  47. codex/static_root/assets/VDialog-DnbL_v_u.0bd289bda8e6.js.br +0 -0
  48. codex/static_root/assets/VDialog-DnbL_v_u.0bd289bda8e6.js.gz +0 -0
  49. codex/static_root/assets/VDialog-DnbL_v_u.js +1 -0
  50. codex/static_root/assets/VDialog-DnbL_v_u.js.br +0 -0
  51. codex/static_root/assets/VDialog-DnbL_v_u.js.gz +0 -0
  52. codex/static_root/assets/{VDialog-C5Nxd_zP.css → VDialog-lQ13FnRR.1c801ad756b2.css} +1 -1
  53. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
  54. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
  55. codex/static_root/assets/{VDialog-C5Nxd_zP.d327f505ef0e.css → VDialog-lQ13FnRR.css} +1 -1
  56. codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
  57. codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
  58. codex/static_root/assets/VExpansionPanels-B8nz8lN5.56e5adec4f62.js +1 -0
  59. codex/static_root/assets/VExpansionPanels-B8nz8lN5.56e5adec4f62.js.br +0 -0
  60. codex/static_root/assets/VExpansionPanels-B8nz8lN5.56e5adec4f62.js.gz +0 -0
  61. codex/static_root/assets/VExpansionPanels-B8nz8lN5.js +1 -0
  62. codex/static_root/assets/VExpansionPanels-B8nz8lN5.js.br +0 -0
  63. codex/static_root/assets/VExpansionPanels-B8nz8lN5.js.gz +0 -0
  64. codex/static_root/assets/{VRadioGroup-B--7K_v5.4a4e9c2d6c42.js → VRadioGroup-BgwJ_b94.55f84f3429b9.js} +1 -1
  65. codex/static_root/assets/VRadioGroup-BgwJ_b94.55f84f3429b9.js.br +0 -0
  66. codex/static_root/assets/VRadioGroup-BgwJ_b94.55f84f3429b9.js.gz +0 -0
  67. codex/static_root/assets/{VRadioGroup-B--7K_v5.js → VRadioGroup-BgwJ_b94.js} +1 -1
  68. codex/static_root/assets/VRadioGroup-BgwJ_b94.js.br +0 -0
  69. codex/static_root/assets/VRadioGroup-BgwJ_b94.js.gz +0 -0
  70. codex/static_root/assets/VSelect-BoKpXxwe.a88f065dfe3b.js +1 -0
  71. codex/static_root/assets/VSelect-BoKpXxwe.a88f065dfe3b.js.br +0 -0
  72. codex/static_root/assets/VSelect-BoKpXxwe.a88f065dfe3b.js.gz +0 -0
  73. codex/static_root/assets/VSelect-BoKpXxwe.js +1 -0
  74. codex/static_root/assets/VSelect-BoKpXxwe.js.br +0 -0
  75. codex/static_root/assets/VSelect-BoKpXxwe.js.gz +0 -0
  76. codex/static_root/assets/{VSelectionControl-CVQ9wkE2.c02186cceba6.js → VSelectionControl-BXJGg8No.0cb36d941d2a.js} +1 -1
  77. codex/static_root/assets/VSelectionControl-BXJGg8No.0cb36d941d2a.js.br +0 -0
  78. codex/static_root/assets/VSelectionControl-BXJGg8No.0cb36d941d2a.js.gz +0 -0
  79. codex/static_root/assets/{VSelectionControl-CVQ9wkE2.js → VSelectionControl-BXJGg8No.js} +1 -1
  80. codex/static_root/assets/VSelectionControl-BXJGg8No.js.br +0 -0
  81. codex/static_root/assets/VSelectionControl-BXJGg8No.js.gz +0 -0
  82. codex/static_root/assets/VSlideGroup-C2TL5E34.775adeb5a973.js +1 -0
  83. codex/static_root/assets/VSlideGroup-C2TL5E34.775adeb5a973.js.br +0 -0
  84. codex/static_root/assets/VSlideGroup-C2TL5E34.775adeb5a973.js.gz +0 -0
  85. codex/static_root/assets/VSlideGroup-C2TL5E34.js +1 -0
  86. codex/static_root/assets/VSlideGroup-C2TL5E34.js.br +0 -0
  87. codex/static_root/assets/VSlideGroup-C2TL5E34.js.gz +0 -0
  88. codex/static_root/assets/{VTable-CrWkhkiP.6d530eea0c09.js → VTable-C0FptljX.e4840b635c6e.js} +1 -1
  89. codex/static_root/assets/VTable-C0FptljX.e4840b635c6e.js.br +0 -0
  90. codex/static_root/assets/VTable-C0FptljX.e4840b635c6e.js.gz +0 -0
  91. codex/static_root/assets/{VTable-CrWkhkiP.js → VTable-C0FptljX.js} +1 -1
  92. codex/static_root/assets/VTable-C0FptljX.js.br +0 -0
  93. codex/static_root/assets/VTable-C0FptljX.js.gz +0 -0
  94. codex/static_root/assets/VTextField-Aw8nKhY6.428732ac22d7.js +1 -0
  95. codex/static_root/assets/VTextField-Aw8nKhY6.428732ac22d7.js.br +0 -0
  96. codex/static_root/assets/VTextField-Aw8nKhY6.428732ac22d7.js.gz +0 -0
  97. codex/static_root/assets/VTextField-Aw8nKhY6.js +1 -0
  98. codex/static_root/assets/VTextField-Aw8nKhY6.js.br +0 -0
  99. codex/static_root/assets/VTextField-Aw8nKhY6.js.gz +0 -0
  100. codex/static_root/assets/VWindowItem-D9j_u9MX.828acf3dee55.js +1 -0
  101. codex/static_root/assets/VWindowItem-D9j_u9MX.828acf3dee55.js.br +0 -0
  102. codex/static_root/assets/VWindowItem-D9j_u9MX.828acf3dee55.js.gz +0 -0
  103. codex/static_root/assets/VWindowItem-D9j_u9MX.js +1 -0
  104. codex/static_root/assets/VWindowItem-D9j_u9MX.js.br +0 -0
  105. codex/static_root/assets/VWindowItem-D9j_u9MX.js.gz +0 -0
  106. codex/static_root/assets/admin-drawer-panel-Dmn4wEY3.af7e8490f0e3.js +30 -0
  107. codex/static_root/assets/admin-drawer-panel-Dmn4wEY3.af7e8490f0e3.js.br +0 -0
  108. codex/static_root/assets/admin-drawer-panel-Dmn4wEY3.af7e8490f0e3.js.gz +0 -0
  109. codex/static_root/assets/admin-drawer-panel-Dmn4wEY3.js +30 -0
  110. codex/static_root/assets/admin-drawer-panel-Dmn4wEY3.js.br +0 -0
  111. codex/static_root/assets/admin-drawer-panel-Dmn4wEY3.js.gz +0 -0
  112. codex/static_root/assets/{admin-drawer-panel-o87BwD38.ce39427c8201.css → admin-drawer-panel-mne3FIj6.561b3f75fe65.css} +1 -1
  113. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
  114. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
  115. codex/static_root/assets/{admin-drawer-panel-o87BwD38.css → admin-drawer-panel-mne3FIj6.css} +1 -1
  116. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
  117. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
  118. codex/static_root/assets/admin-jf7zR2p_.4741813376d2.js +1 -0
  119. codex/static_root/assets/admin-jf7zR2p_.4741813376d2.js.br +0 -0
  120. codex/static_root/assets/admin-jf7zR2p_.4741813376d2.js.gz +0 -0
  121. codex/static_root/assets/admin-jf7zR2p_.js +1 -0
  122. codex/static_root/assets/admin-jf7zR2p_.js.br +0 -0
  123. codex/static_root/assets/admin-jf7zR2p_.js.gz +0 -0
  124. codex/static_root/assets/browser-BKZuypzF.86e5333bd7d6.js +1 -0
  125. codex/static_root/assets/browser-BKZuypzF.86e5333bd7d6.js.br +0 -0
  126. codex/static_root/assets/browser-BKZuypzF.86e5333bd7d6.js.gz +0 -0
  127. codex/static_root/assets/browser-BKZuypzF.js +1 -0
  128. codex/static_root/assets/browser-BKZuypzF.js.br +0 -0
  129. codex/static_root/assets/browser-BKZuypzF.js.gz +0 -0
  130. codex/static_root/assets/browser-D7xci5SY.css +1 -0
  131. codex/static_root/assets/browser-D7xci5SY.css.br +0 -0
  132. codex/static_root/assets/browser-D7xci5SY.css.gz +0 -0
  133. codex/static_root/assets/browser-D7xci5SY.fa305e14005c.css +1 -0
  134. codex/static_root/assets/browser-D7xci5SY.fa305e14005c.css.br +0 -0
  135. codex/static_root/assets/browser-D7xci5SY.fa305e14005c.css.gz +0 -0
  136. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +1 -0
  137. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
  138. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
  139. codex/static_root/assets/change-password-dialog-0u6IJA87.css +1 -0
  140. codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
  141. codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
  142. codex/static_root/assets/change-password-dialog-Cc1e755p.b29d200537bf.js +1 -0
  143. codex/static_root/assets/change-password-dialog-Cc1e755p.b29d200537bf.js.br +0 -0
  144. codex/static_root/assets/change-password-dialog-Cc1e755p.b29d200537bf.js.gz +0 -0
  145. codex/static_root/assets/change-password-dialog-Cc1e755p.js +1 -0
  146. codex/static_root/assets/change-password-dialog-Cc1e755p.js.br +0 -0
  147. codex/static_root/assets/change-password-dialog-Cc1e755p.js.gz +0 -0
  148. codex/static_root/assets/{confirm-dialog-jwL7B98r.1cfd579cbcfe.js → confirm-dialog-Cyr7HAAz.8ab1d8b6241a.js} +1 -1
  149. codex/static_root/assets/confirm-dialog-Cyr7HAAz.8ab1d8b6241a.js.br +0 -0
  150. codex/static_root/assets/confirm-dialog-Cyr7HAAz.8ab1d8b6241a.js.gz +0 -0
  151. codex/static_root/assets/{confirm-dialog-jwL7B98r.js → confirm-dialog-Cyr7HAAz.js} +1 -1
  152. codex/static_root/assets/confirm-dialog-Cyr7HAAz.js.br +0 -0
  153. codex/static_root/assets/confirm-dialog-Cyr7HAAz.js.gz +0 -0
  154. codex/static_root/assets/datetime-column-Cqi99Ze-.49d0ce340183.js +1 -0
  155. codex/static_root/assets/datetime-column-Cqi99Ze-.49d0ce340183.js.br +0 -0
  156. codex/static_root/assets/datetime-column-Cqi99Ze-.49d0ce340183.js.gz +0 -0
  157. codex/static_root/assets/datetime-column-Cqi99Ze-.js +1 -0
  158. codex/static_root/assets/datetime-column-Cqi99Ze-.js.br +0 -0
  159. codex/static_root/assets/datetime-column-Cqi99Ze-.js.gz +0 -0
  160. codex/static_root/assets/filter-CuocBoS2.885d1b8d44cc.js +1 -0
  161. codex/static_root/assets/filter-CuocBoS2.885d1b8d44cc.js.br +0 -0
  162. codex/static_root/assets/filter-CuocBoS2.885d1b8d44cc.js.gz +0 -0
  163. codex/static_root/assets/filter-CuocBoS2.js +1 -0
  164. codex/static_root/assets/filter-CuocBoS2.js.br +0 -0
  165. codex/static_root/assets/filter-CuocBoS2.js.gz +0 -0
  166. codex/static_root/assets/{flag-tab-Da2DBNyz.ffbe5ca37e1c.js → flag-tab-B5dRCBAt.e858f7ec9f55.js} +1 -1
  167. codex/static_root/assets/flag-tab-B5dRCBAt.e858f7ec9f55.js.br +0 -0
  168. codex/static_root/assets/flag-tab-B5dRCBAt.e858f7ec9f55.js.gz +0 -0
  169. codex/static_root/assets/{flag-tab-Da2DBNyz.js → flag-tab-B5dRCBAt.js} +1 -1
  170. codex/static_root/assets/flag-tab-B5dRCBAt.js.br +0 -0
  171. codex/static_root/assets/flag-tab-B5dRCBAt.js.gz +0 -0
  172. codex/static_root/assets/{group-tab-BONYWOc1.6ddf321a4a56.js → group-tab-_nT2o04v.c06032b254dc.js} +1 -1
  173. codex/static_root/assets/group-tab-_nT2o04v.c06032b254dc.js.br +0 -0
  174. codex/static_root/assets/group-tab-_nT2o04v.c06032b254dc.js.gz +0 -0
  175. codex/static_root/assets/{group-tab-BONYWOc1.js → group-tab-_nT2o04v.js} +1 -1
  176. codex/static_root/assets/group-tab-_nT2o04v.js.br +0 -0
  177. codex/static_root/assets/group-tab-_nT2o04v.js.gz +0 -0
  178. codex/static_root/assets/{http-error-D2Jnc20C.32846bc3a43d.js → http-error-CXo9qLiW.d5a337f399c9.js} +1 -1
  179. codex/static_root/assets/http-error-CXo9qLiW.d5a337f399c9.js.br +0 -0
  180. codex/static_root/assets/http-error-CXo9qLiW.d5a337f399c9.js.gz +0 -0
  181. codex/static_root/assets/{http-error-D2Jnc20C.js → http-error-CXo9qLiW.js} +1 -1
  182. codex/static_root/assets/http-error-CXo9qLiW.js.br +0 -0
  183. codex/static_root/assets/http-error-CXo9qLiW.js.gz +0 -0
  184. codex/static_root/assets/{library-tab-B419agXA.js → library-tab-lz5QMD4i.2f04b226ebe8.js} +1 -1
  185. codex/static_root/assets/library-tab-lz5QMD4i.2f04b226ebe8.js.br +0 -0
  186. codex/static_root/assets/library-tab-lz5QMD4i.2f04b226ebe8.js.gz +0 -0
  187. codex/static_root/assets/{library-tab-B419agXA.d4b778172aaa.js → library-tab-lz5QMD4i.js} +1 -1
  188. codex/static_root/assets/library-tab-lz5QMD4i.js.br +0 -0
  189. codex/static_root/assets/library-tab-lz5QMD4i.js.gz +0 -0
  190. codex/static_root/assets/main-17i0EBCp.7093c3f755f1.js +32 -0
  191. codex/static_root/assets/main-17i0EBCp.7093c3f755f1.js.br +0 -0
  192. codex/static_root/assets/main-17i0EBCp.7093c3f755f1.js.gz +0 -0
  193. codex/static_root/assets/main-17i0EBCp.js +32 -0
  194. codex/static_root/assets/main-17i0EBCp.js.br +0 -0
  195. codex/static_root/assets/main-17i0EBCp.js.gz +0 -0
  196. codex/static_root/assets/pagination-toolbar-BBvsIXTd.ad891da6617a.js +1 -0
  197. codex/static_root/assets/pagination-toolbar-BBvsIXTd.ad891da6617a.js.br +0 -0
  198. codex/static_root/assets/pagination-toolbar-BBvsIXTd.ad891da6617a.js.gz +0 -0
  199. codex/static_root/assets/pagination-toolbar-BBvsIXTd.js +1 -0
  200. codex/static_root/assets/pagination-toolbar-BBvsIXTd.js.br +0 -0
  201. codex/static_root/assets/pagination-toolbar-BBvsIXTd.js.gz +0 -0
  202. codex/static_root/assets/pagination-toolbar-B_zL7BQQ.css +1 -0
  203. codex/static_root/assets/pagination-toolbar-B_zL7BQQ.css.br +0 -0
  204. codex/static_root/assets/pagination-toolbar-B_zL7BQQ.css.gz +0 -0
  205. codex/static_root/assets/pagination-toolbar-B_zL7BQQ.d1311bd41edc.css +1 -0
  206. codex/static_root/assets/pagination-toolbar-B_zL7BQQ.d1311bd41edc.css.br +0 -0
  207. codex/static_root/assets/pagination-toolbar-B_zL7BQQ.d1311bd41edc.css.gz +0 -0
  208. codex/static_root/assets/{pdf-doc-8RVZqILx.2e7166dd26fb.js → pdf-doc-BpZdmj2g.93e86d9c7927.js} +1 -1
  209. codex/static_root/assets/pdf-doc-BpZdmj2g.93e86d9c7927.js.br +0 -0
  210. codex/static_root/assets/pdf-doc-BpZdmj2g.93e86d9c7927.js.gz +0 -0
  211. codex/static_root/assets/{pdf-doc-8RVZqILx.js → pdf-doc-BpZdmj2g.js} +1 -1
  212. codex/static_root/assets/pdf-doc-BpZdmj2g.js.br +0 -0
  213. codex/static_root/assets/pdf-doc-BpZdmj2g.js.gz +0 -0
  214. codex/static_root/assets/reader-CRJUR2qj.55d626f0f9fa.js +2 -0
  215. codex/static_root/assets/reader-CRJUR2qj.55d626f0f9fa.js.br +0 -0
  216. codex/static_root/assets/reader-CRJUR2qj.55d626f0f9fa.js.gz +0 -0
  217. codex/static_root/assets/reader-CRJUR2qj.js +2 -0
  218. codex/static_root/assets/reader-CRJUR2qj.js.br +0 -0
  219. codex/static_root/assets/reader-CRJUR2qj.js.gz +0 -0
  220. codex/static_root/assets/{reader-CCCfpM3x.1553e45bd775.css → reader-CqXFa_gE.78267e9de0c2.css} +1 -1
  221. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.br +0 -0
  222. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.gz +0 -0
  223. codex/static_root/assets/{reader-CCCfpM3x.css → reader-CqXFa_gE.css} +1 -1
  224. codex/static_root/assets/reader-CqXFa_gE.css.br +0 -0
  225. codex/static_root/assets/reader-CqXFa_gE.css.gz +0 -0
  226. codex/static_root/assets/relation-chips-NgDnInw_.3b5ba16f68f0.js +1 -0
  227. codex/static_root/assets/relation-chips-NgDnInw_.3b5ba16f68f0.js.br +0 -0
  228. codex/static_root/assets/relation-chips-NgDnInw_.3b5ba16f68f0.js.gz +0 -0
  229. codex/static_root/assets/relation-chips-NgDnInw_.js +1 -0
  230. codex/static_root/assets/relation-chips-NgDnInw_.js.br +0 -0
  231. codex/static_root/assets/relation-chips-NgDnInw_.js.gz +0 -0
  232. codex/static_root/assets/settings-drawer-BaQT27kc.e43fc1527b66.js +2 -0
  233. codex/static_root/assets/settings-drawer-BaQT27kc.e43fc1527b66.js.br +0 -0
  234. codex/static_root/assets/settings-drawer-BaQT27kc.e43fc1527b66.js.gz +0 -0
  235. codex/static_root/assets/settings-drawer-BaQT27kc.js +2 -0
  236. codex/static_root/assets/settings-drawer-BaQT27kc.js.br +0 -0
  237. codex/static_root/assets/settings-drawer-BaQT27kc.js.gz +0 -0
  238. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +1 -0
  239. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  240. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  241. codex/static_root/assets/stats-tab-B4yKuY0c.css +1 -0
  242. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  243. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  244. codex/static_root/assets/stats-tab-DoHb54IU.30d7deea7b9f.js +1 -0
  245. codex/static_root/assets/stats-tab-DoHb54IU.30d7deea7b9f.js.br +0 -0
  246. codex/static_root/assets/stats-tab-DoHb54IU.30d7deea7b9f.js.gz +0 -0
  247. codex/static_root/assets/stats-tab-DoHb54IU.js +1 -0
  248. codex/static_root/assets/stats-tab-DoHb54IU.js.br +0 -0
  249. codex/static_root/assets/stats-tab-DoHb54IU.js.gz +0 -0
  250. codex/static_root/assets/task-tab-B88ucu1U.4f240e3d82c4.js +1 -0
  251. codex/static_root/assets/task-tab-B88ucu1U.4f240e3d82c4.js.br +0 -0
  252. codex/static_root/assets/task-tab-B88ucu1U.4f240e3d82c4.js.gz +0 -0
  253. codex/static_root/assets/task-tab-B88ucu1U.js +1 -0
  254. codex/static_root/assets/task-tab-B88ucu1U.js.br +0 -0
  255. codex/static_root/assets/task-tab-B88ucu1U.js.gz +0 -0
  256. codex/static_root/assets/to-case-B7MjLIw-.08fc8412de69.js +1 -0
  257. codex/static_root/assets/to-case-B7MjLIw-.08fc8412de69.js.br +0 -0
  258. codex/static_root/assets/to-case-B7MjLIw-.js +1 -0
  259. codex/static_root/assets/to-case-B7MjLIw-.js.br +0 -0
  260. codex/static_root/assets/unauthorized-AnKtlgGy.62ee74d4373c.js +1 -0
  261. codex/static_root/assets/unauthorized-AnKtlgGy.62ee74d4373c.js.br +0 -0
  262. codex/static_root/assets/unauthorized-AnKtlgGy.62ee74d4373c.js.gz +0 -0
  263. codex/static_root/assets/unauthorized-AnKtlgGy.js +1 -0
  264. codex/static_root/assets/unauthorized-AnKtlgGy.js.br +0 -0
  265. codex/static_root/assets/unauthorized-AnKtlgGy.js.gz +0 -0
  266. codex/static_root/assets/{unauthorized-DHV6Q1n-.b7847b2872a1.css → unauthorized-CibJYD8o.4c2de98c2b53.css} +1 -1
  267. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
  268. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
  269. codex/static_root/assets/{unauthorized-DHV6Q1n-.css → unauthorized-CibJYD8o.css} +1 -1
  270. codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
  271. codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
  272. codex/static_root/assets/user-tab-BxtZ2u7W.161cc8f0dcce.js +1 -0
  273. codex/static_root/assets/user-tab-BxtZ2u7W.161cc8f0dcce.js.br +0 -0
  274. codex/static_root/assets/user-tab-BxtZ2u7W.161cc8f0dcce.js.gz +0 -0
  275. codex/static_root/assets/user-tab-BxtZ2u7W.js +1 -0
  276. codex/static_root/assets/user-tab-BxtZ2u7W.js.br +0 -0
  277. codex/static_root/assets/user-tab-BxtZ2u7W.js.gz +0 -0
  278. codex/static_root/js/choices-admin.3521e2a863df.json +1 -0
  279. codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
  280. codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
  281. codex/static_root/js/choices-admin.json +1 -1
  282. codex/static_root/js/choices-admin.json.br +0 -0
  283. codex/static_root/js/choices-admin.json.gz +0 -0
  284. codex/static_root/js/{choices.a0aaaa6c7ef7.json → choices.2f6b0359e1ef.json} +1 -1
  285. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  286. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  287. codex/static_root/js/choices.json +1 -1
  288. codex/static_root/js/choices.json.br +0 -0
  289. codex/static_root/js/choices.json.gz +0 -0
  290. codex/static_root/manifest.3851c028b0cb.json +622 -0
  291. codex/static_root/manifest.3851c028b0cb.json.br +0 -0
  292. codex/static_root/manifest.3851c028b0cb.json.gz +0 -0
  293. codex/static_root/manifest.json +245 -252
  294. codex/static_root/manifest.json.br +0 -0
  295. codex/static_root/manifest.json.gz +0 -0
  296. codex/static_root/staticfiles.json +1 -1
  297. codex/util.py +8 -6
  298. codex/views/admin/api_key.py +5 -2
  299. codex/views/admin/stats.py +13 -20
  300. codex/views/admin/tasks.py +2 -3
  301. codex/views/auth.py +1 -1
  302. codex/views/bookmark.py +49 -29
  303. codex/views/browser/annotations.py +11 -45
  304. codex/views/browser/base.py +22 -6
  305. codex/views/browser/breadcrumbs.py +5 -5
  306. codex/views/browser/browser.py +39 -27
  307. codex/views/browser/choices.py +22 -37
  308. codex/views/browser/cover.py +55 -65
  309. codex/views/browser/filters/annotations.py +33 -10
  310. codex/views/browser/filters/group.py +24 -15
  311. codex/views/browser/filters/search.py +3 -4
  312. codex/views/browser/metadata.py +98 -49
  313. codex/views/browser/mtime.py +3 -14
  314. codex/views/browser/order_by.py +1 -6
  315. codex/views/browser/settings.py +53 -0
  316. codex/views/browser/validate.py +3 -0
  317. codex/views/const.py +25 -2
  318. codex/views/opds/v1/feed.py +3 -5
  319. codex/views/opds/v2/feed.py +3 -3
  320. codex/views/reader/arcs.py +42 -51
  321. codex/views/reader/books.py +47 -63
  322. codex/views/reader/init.py +125 -0
  323. codex/views/reader/reader.py +9 -70
  324. codex/views/session.py +18 -12
  325. codex/views/settings.py +23 -10
  326. codex/views/util.py +2 -1
  327. codex/websockets/consumers.py +14 -10
  328. {codex-1.6.0a9.dist-info → codex-1.6.0a11.dist-info}/METADATA +1 -1
  329. {codex-1.6.0a9.dist-info → codex-1.6.0a11.dist-info}/RECORD +332 -328
  330. codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js +0 -1
  331. codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js.br +0 -0
  332. codex/static_root/assets/VCheckbox-eNspVUje.da8282a08876.js.gz +0 -0
  333. codex/static_root/assets/VCheckbox-eNspVUje.js +0 -1
  334. codex/static_root/assets/VCheckbox-eNspVUje.js.br +0 -0
  335. codex/static_root/assets/VCheckbox-eNspVUje.js.gz +0 -0
  336. codex/static_root/assets/VCheckboxBtn-DLzF_WHB.9a47873b8548.js.br +0 -0
  337. codex/static_root/assets/VCheckboxBtn-DLzF_WHB.9a47873b8548.js.gz +0 -0
  338. codex/static_root/assets/VCheckboxBtn-DLzF_WHB.js.br +0 -0
  339. codex/static_root/assets/VCheckboxBtn-DLzF_WHB.js.gz +0 -0
  340. codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js +0 -1
  341. codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js.br +0 -0
  342. codex/static_root/assets/VCombobox-BIO7lU_B.d607ada71b06.js.gz +0 -0
  343. codex/static_root/assets/VCombobox-BIO7lU_B.js +0 -1
  344. codex/static_root/assets/VCombobox-BIO7lU_B.js.br +0 -0
  345. codex/static_root/assets/VCombobox-BIO7lU_B.js.gz +0 -0
  346. codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js +0 -1
  347. codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js.br +0 -0
  348. codex/static_root/assets/VDialog-87AymJC5.4a46716358c0.js.gz +0 -0
  349. codex/static_root/assets/VDialog-87AymJC5.js +0 -1
  350. codex/static_root/assets/VDialog-87AymJC5.js.br +0 -0
  351. codex/static_root/assets/VDialog-87AymJC5.js.gz +0 -0
  352. codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
  353. codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
  354. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
  355. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
  356. codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js +0 -1
  357. codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js.br +0 -0
  358. codex/static_root/assets/VExpansionPanels-CgA3shsd.9e524c73726a.js.gz +0 -0
  359. codex/static_root/assets/VExpansionPanels-CgA3shsd.js +0 -1
  360. codex/static_root/assets/VExpansionPanels-CgA3shsd.js.br +0 -0
  361. codex/static_root/assets/VExpansionPanels-CgA3shsd.js.gz +0 -0
  362. codex/static_root/assets/VRadioGroup-B--7K_v5.4a4e9c2d6c42.js.br +0 -0
  363. codex/static_root/assets/VRadioGroup-B--7K_v5.4a4e9c2d6c42.js.gz +0 -0
  364. codex/static_root/assets/VRadioGroup-B--7K_v5.js.br +0 -0
  365. codex/static_root/assets/VRadioGroup-B--7K_v5.js.gz +0 -0
  366. codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js +0 -1
  367. codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js.br +0 -0
  368. codex/static_root/assets/VSelect-BoJq222l.fc714657e214.js.gz +0 -0
  369. codex/static_root/assets/VSelect-BoJq222l.js +0 -1
  370. codex/static_root/assets/VSelect-BoJq222l.js.br +0 -0
  371. codex/static_root/assets/VSelect-BoJq222l.js.gz +0 -0
  372. codex/static_root/assets/VSelectionControl-CVQ9wkE2.c02186cceba6.js.br +0 -0
  373. codex/static_root/assets/VSelectionControl-CVQ9wkE2.c02186cceba6.js.gz +0 -0
  374. codex/static_root/assets/VSelectionControl-CVQ9wkE2.js.br +0 -0
  375. codex/static_root/assets/VSelectionControl-CVQ9wkE2.js.gz +0 -0
  376. codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js +0 -1
  377. codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js.br +0 -0
  378. codex/static_root/assets/VSlideGroup-Ce0j2BKK.85e64443a928.js.gz +0 -0
  379. codex/static_root/assets/VSlideGroup-Ce0j2BKK.js +0 -1
  380. codex/static_root/assets/VSlideGroup-Ce0j2BKK.js.br +0 -0
  381. codex/static_root/assets/VSlideGroup-Ce0j2BKK.js.gz +0 -0
  382. codex/static_root/assets/VTable-CrWkhkiP.6d530eea0c09.js.br +0 -0
  383. codex/static_root/assets/VTable-CrWkhkiP.6d530eea0c09.js.gz +0 -0
  384. codex/static_root/assets/VTable-CrWkhkiP.js.br +0 -0
  385. codex/static_root/assets/VTable-CrWkhkiP.js.gz +0 -0
  386. codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js +0 -1
  387. codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js.br +0 -0
  388. codex/static_root/assets/VTextField-CkWbil3K.2cac13161dfe.js.gz +0 -0
  389. codex/static_root/assets/VTextField-CkWbil3K.js +0 -1
  390. codex/static_root/assets/VTextField-CkWbil3K.js.br +0 -0
  391. codex/static_root/assets/VTextField-CkWbil3K.js.gz +0 -0
  392. codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js +0 -1
  393. codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js.br +0 -0
  394. codex/static_root/assets/VWindowItem-7z55Y4lK.98eb7487e039.js.gz +0 -0
  395. codex/static_root/assets/VWindowItem-7z55Y4lK.js +0 -1
  396. codex/static_root/assets/VWindowItem-7z55Y4lK.js.br +0 -0
  397. codex/static_root/assets/VWindowItem-7z55Y4lK.js.gz +0 -0
  398. codex/static_root/assets/admin-D3OK784R.f69891726ec5.js +0 -1
  399. codex/static_root/assets/admin-D3OK784R.f69891726ec5.js.br +0 -0
  400. codex/static_root/assets/admin-D3OK784R.f69891726ec5.js.gz +0 -0
  401. codex/static_root/assets/admin-D3OK784R.js +0 -1
  402. codex/static_root/assets/admin-D3OK784R.js.br +0 -0
  403. codex/static_root/assets/admin-D3OK784R.js.gz +0 -0
  404. codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js +0 -30
  405. codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js.br +0 -0
  406. codex/static_root/assets/admin-drawer-panel-1pnfvY8O.5438f252970e.js.gz +0 -0
  407. codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js +0 -30
  408. codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js.br +0 -0
  409. codex/static_root/assets/admin-drawer-panel-1pnfvY8O.js.gz +0 -0
  410. codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.br +0 -0
  411. codex/static_root/assets/admin-drawer-panel-o87BwD38.ce39427c8201.css.gz +0 -0
  412. codex/static_root/assets/admin-drawer-panel-o87BwD38.css.br +0 -0
  413. codex/static_root/assets/admin-drawer-panel-o87BwD38.css.gz +0 -0
  414. codex/static_root/assets/browser-BuU2x9y7.css +0 -1
  415. codex/static_root/assets/browser-BuU2x9y7.css.br +0 -0
  416. codex/static_root/assets/browser-BuU2x9y7.css.gz +0 -0
  417. codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css +0 -1
  418. codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css.br +0 -0
  419. codex/static_root/assets/browser-BuU2x9y7.f67595d24664.css.gz +0 -0
  420. codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js +0 -1
  421. codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js.br +0 -0
  422. codex/static_root/assets/browser-CO9EYHIr.be49367c6a75.js.gz +0 -0
  423. codex/static_root/assets/browser-CO9EYHIr.js +0 -1
  424. codex/static_root/assets/browser-CO9EYHIr.js.br +0 -0
  425. codex/static_root/assets/browser-CO9EYHIr.js.gz +0 -0
  426. codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js +0 -1
  427. codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js.br +0 -0
  428. codex/static_root/assets/change-password-dialog-CjZdzaIk.188c765431ab.js.gz +0 -0
  429. codex/static_root/assets/change-password-dialog-CjZdzaIk.js +0 -1
  430. codex/static_root/assets/change-password-dialog-CjZdzaIk.js.br +0 -0
  431. codex/static_root/assets/change-password-dialog-CjZdzaIk.js.gz +0 -0
  432. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +0 -1
  433. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
  434. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
  435. codex/static_root/assets/change-password-dialog-HvIvmmIE.css +0 -1
  436. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
  437. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
  438. codex/static_root/assets/confirm-dialog-jwL7B98r.1cfd579cbcfe.js.br +0 -0
  439. codex/static_root/assets/confirm-dialog-jwL7B98r.1cfd579cbcfe.js.gz +0 -0
  440. codex/static_root/assets/confirm-dialog-jwL7B98r.js.br +0 -0
  441. codex/static_root/assets/confirm-dialog-jwL7B98r.js.gz +0 -0
  442. codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js +0 -1
  443. codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js.br +0 -0
  444. codex/static_root/assets/datetime-column-9w3GcKvo.f9172256f091.js.gz +0 -0
  445. codex/static_root/assets/datetime-column-9w3GcKvo.js +0 -1
  446. codex/static_root/assets/datetime-column-9w3GcKvo.js.br +0 -0
  447. codex/static_root/assets/datetime-column-9w3GcKvo.js.gz +0 -0
  448. codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js +0 -1
  449. codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js.br +0 -0
  450. codex/static_root/assets/filter-C-pghOri.eeb7c2ecf398.js.gz +0 -0
  451. codex/static_root/assets/filter-C-pghOri.js +0 -1
  452. codex/static_root/assets/filter-C-pghOri.js.br +0 -0
  453. codex/static_root/assets/filter-C-pghOri.js.gz +0 -0
  454. codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js.br +0 -0
  455. codex/static_root/assets/flag-tab-Da2DBNyz.ffbe5ca37e1c.js.gz +0 -0
  456. codex/static_root/assets/flag-tab-Da2DBNyz.js.br +0 -0
  457. codex/static_root/assets/flag-tab-Da2DBNyz.js.gz +0 -0
  458. codex/static_root/assets/group-tab-BONYWOc1.6ddf321a4a56.js.br +0 -0
  459. codex/static_root/assets/group-tab-BONYWOc1.6ddf321a4a56.js.gz +0 -0
  460. codex/static_root/assets/group-tab-BONYWOc1.js.br +0 -0
  461. codex/static_root/assets/group-tab-BONYWOc1.js.gz +0 -0
  462. codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js.br +0 -0
  463. codex/static_root/assets/http-error-D2Jnc20C.32846bc3a43d.js.gz +0 -0
  464. codex/static_root/assets/http-error-D2Jnc20C.js.br +0 -0
  465. codex/static_root/assets/http-error-D2Jnc20C.js.gz +0 -0
  466. codex/static_root/assets/library-tab-B419agXA.d4b778172aaa.js.br +0 -0
  467. codex/static_root/assets/library-tab-B419agXA.d4b778172aaa.js.gz +0 -0
  468. codex/static_root/assets/library-tab-B419agXA.js.br +0 -0
  469. codex/static_root/assets/library-tab-B419agXA.js.gz +0 -0
  470. codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js +0 -32
  471. codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js.br +0 -0
  472. codex/static_root/assets/main-CMQwJ9aG.9836fe81c80a.js.gz +0 -0
  473. codex/static_root/assets/main-CMQwJ9aG.js +0 -32
  474. codex/static_root/assets/main-CMQwJ9aG.js.br +0 -0
  475. codex/static_root/assets/main-CMQwJ9aG.js.gz +0 -0
  476. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css +0 -1
  477. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.br +0 -0
  478. codex/static_root/assets/pagination-toolbar-DWdp_kmz.css.gz +0 -0
  479. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css +0 -1
  480. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.br +0 -0
  481. codex/static_root/assets/pagination-toolbar-DWdp_kmz.f98f47e87612.css.gz +0 -0
  482. codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js +0 -1
  483. codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js.br +0 -0
  484. codex/static_root/assets/pagination-toolbar-LTuj5U-G.a295defbcd2f.js.gz +0 -0
  485. codex/static_root/assets/pagination-toolbar-LTuj5U-G.js +0 -1
  486. codex/static_root/assets/pagination-toolbar-LTuj5U-G.js.br +0 -0
  487. codex/static_root/assets/pagination-toolbar-LTuj5U-G.js.gz +0 -0
  488. codex/static_root/assets/pdf-doc-8RVZqILx.2e7166dd26fb.js.br +0 -0
  489. codex/static_root/assets/pdf-doc-8RVZqILx.2e7166dd26fb.js.gz +0 -0
  490. codex/static_root/assets/pdf-doc-8RVZqILx.js.br +0 -0
  491. codex/static_root/assets/pdf-doc-8RVZqILx.js.gz +0 -0
  492. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.br +0 -0
  493. codex/static_root/assets/reader-CCCfpM3x.1553e45bd775.css.gz +0 -0
  494. codex/static_root/assets/reader-CCCfpM3x.css.br +0 -0
  495. codex/static_root/assets/reader-CCCfpM3x.css.gz +0 -0
  496. codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js +0 -2
  497. codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js.br +0 -0
  498. codex/static_root/assets/reader-DNnK_Chr.114d0e321547.js.gz +0 -0
  499. codex/static_root/assets/reader-DNnK_Chr.js +0 -2
  500. codex/static_root/assets/reader-DNnK_Chr.js.br +0 -0
  501. codex/static_root/assets/reader-DNnK_Chr.js.gz +0 -0
  502. codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js +0 -1
  503. codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js.br +0 -0
  504. codex/static_root/assets/relation-chips-PYua7aXv.428ba0b5861e.js.gz +0 -0
  505. codex/static_root/assets/relation-chips-PYua7aXv.js +0 -1
  506. codex/static_root/assets/relation-chips-PYua7aXv.js.br +0 -0
  507. codex/static_root/assets/relation-chips-PYua7aXv.js.gz +0 -0
  508. codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js +0 -2
  509. codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js.br +0 -0
  510. codex/static_root/assets/settings-drawer-DbN6ISRH.d14f525d8eee.js.gz +0 -0
  511. codex/static_root/assets/settings-drawer-DbN6ISRH.js +0 -2
  512. codex/static_root/assets/settings-drawer-DbN6ISRH.js.br +0 -0
  513. codex/static_root/assets/settings-drawer-DbN6ISRH.js.gz +0 -0
  514. codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js +0 -1
  515. codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js.br +0 -0
  516. codex/static_root/assets/stats-tab-DImNhH8O.d5026283841a.js.gz +0 -0
  517. codex/static_root/assets/stats-tab-DImNhH8O.js +0 -1
  518. codex/static_root/assets/stats-tab-DImNhH8O.js.br +0 -0
  519. codex/static_root/assets/stats-tab-DImNhH8O.js.gz +0 -0
  520. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +0 -1
  521. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +0 -2
  522. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
  523. codex/static_root/assets/stats-tab-TsyG3wH_.css +0 -1
  524. codex/static_root/assets/stats-tab-TsyG3wH_.css.br +0 -2
  525. codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
  526. codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js +0 -1
  527. codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js.br +0 -0
  528. codex/static_root/assets/task-tab-DPD53kjv.e56a35ff1691.js.gz +0 -0
  529. codex/static_root/assets/task-tab-DPD53kjv.js +0 -1
  530. codex/static_root/assets/task-tab-DPD53kjv.js.br +0 -0
  531. codex/static_root/assets/task-tab-DPD53kjv.js.gz +0 -0
  532. codex/static_root/assets/to-case-ehC9Ccyj.a7b8e25b391f.js +0 -1
  533. codex/static_root/assets/to-case-ehC9Ccyj.js +0 -1
  534. codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js +0 -1
  535. codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js.br +0 -0
  536. codex/static_root/assets/unauthorized-BOIx7Y18.ee3961abfccb.js.gz +0 -0
  537. codex/static_root/assets/unauthorized-BOIx7Y18.js +0 -1
  538. codex/static_root/assets/unauthorized-BOIx7Y18.js.br +0 -0
  539. codex/static_root/assets/unauthorized-BOIx7Y18.js.gz +0 -0
  540. codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.br +0 -0
  541. codex/static_root/assets/unauthorized-DHV6Q1n-.b7847b2872a1.css.gz +0 -0
  542. codex/static_root/assets/unauthorized-DHV6Q1n-.css.br +0 -0
  543. codex/static_root/assets/unauthorized-DHV6Q1n-.css.gz +0 -0
  544. codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js +0 -1
  545. codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js.br +0 -0
  546. codex/static_root/assets/user-tab-BABwfxLO.37dd0440fbdd.js.gz +0 -0
  547. codex/static_root/assets/user-tab-BABwfxLO.js +0 -1
  548. codex/static_root/assets/user-tab-BABwfxLO.js.br +0 -0
  549. codex/static_root/assets/user-tab-BABwfxLO.js.gz +0 -0
  550. codex/static_root/js/choices-admin.d790df01c20a.json +0 -1
  551. codex/static_root/js/choices-admin.d790df01c20a.json.br +0 -0
  552. codex/static_root/js/choices-admin.d790df01c20a.json.gz +0 -0
  553. codex/static_root/js/choices.a0aaaa6c7ef7.json.br +0 -0
  554. codex/static_root/js/choices.a0aaaa6c7ef7.json.gz +0 -0
  555. codex/static_root/manifest.cbea5663003a.json +0 -629
  556. codex/static_root/manifest.cbea5663003a.json.br +0 -0
  557. codex/static_root/manifest.cbea5663003a.json.gz +0 -0
  558. {codex-1.6.0a9.dist-info → codex-1.6.0a11.dist-info}/LICENSE +0 -0
  559. {codex-1.6.0a9.dist-info → codex-1.6.0a11.dist-info}/WHEEL +0 -0
  560. {codex-1.6.0a9.dist-info → codex-1.6.0a11.dist-info}/entry_points.txt +0 -0
@@ -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:
@@ -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.")
@@ -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()
@@ -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
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}")
@@ -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."""
@@ -181,67 +181,68 @@ class AdminGroupSerializer(Serializer):
181
181
  """Group Counts."""
182
182
 
183
183
  publishers_count = IntegerField(required=False, read_only=True)
184
- imprints_count = IntegerField(required=False)
185
- series_count = IntegerField(required=False)
186
- volumes_count = IntegerField(required=False)
187
- issues_count = IntegerField(required=False)
188
- folders_count = IntegerField(required=False)
184
+ imprints_count = IntegerField(required=False, read_only=True)
185
+ series_count = IntegerField(required=False, read_only=True)
186
+ volumes_count = IntegerField(required=False, read_only=True)
187
+ issues_count = IntegerField(required=False, read_only=True)
188
+ folders_count = IntegerField(required=False, read_only=True)
189
+ story_arcs_count = IntegerField(required=False, read_only=True)
189
190
 
190
191
 
191
192
  class AdminFileTypeSerializer(Serializer):
192
193
  """File Type Counts."""
193
194
 
194
- pdf_count = IntegerField(required=False)
195
- cbz_count = IntegerField(required=False)
196
- cbr_count = IntegerField(required=False)
197
- cbt_count = IntegerField(required=False)
198
- unknown_count = IntegerField(required=False)
195
+ pdf_count = IntegerField(required=False, read_only=True)
196
+ cbz_count = IntegerField(required=False, read_only=True)
197
+ cbr_count = IntegerField(required=False, read_only=True)
198
+ cbt_count = IntegerField(required=False, read_only=True)
199
+ unknown_count = IntegerField(required=False, read_only=True)
199
200
 
200
201
 
201
202
  class AdminComicMetadataSerializer(Serializer):
202
203
  """Metadata Counts."""
203
204
 
204
- age_ratings_count = IntegerField(required=False)
205
- characters_count = IntegerField(required=False)
206
- contributors_count = IntegerField(required=False)
207
- contributor_persons_count = IntegerField(required=False)
208
- contributor_roles_count = IntegerField(required=False)
209
- countries_count = IntegerField(required=False)
210
- genres_count = IntegerField(required=False)
211
- identifiers_count = IntegerField(required=False)
212
- identifier_types_count = IntegerField(required=False)
213
- languages_count = IntegerField(required=False)
214
- locations_count = IntegerField(required=False)
215
- original_formats_count = IntegerField(required=False)
216
- series_groups_count = IntegerField(required=False)
217
- scan_infos_count = IntegerField(required=False)
205
+ age_ratings_count = IntegerField(required=False, read_only=True)
206
+ characters_count = IntegerField(required=False, read_only=True)
207
+ contributors_count = IntegerField(required=False, read_only=True)
208
+ contributor_persons_count = IntegerField(required=False, read_only=True)
209
+ contributor_roles_count = IntegerField(required=False, read_only=True)
210
+ countries_count = IntegerField(required=False, read_only=True)
211
+ genres_count = IntegerField(required=False, read_only=True)
212
+ identifiers_count = IntegerField(required=False, read_only=True)
213
+ identifier_types_count = IntegerField(required=False, read_only=True)
214
+ languages_count = IntegerField(required=False, read_only=True)
215
+ locations_count = IntegerField(required=False, read_only=True)
216
+ original_formats_count = IntegerField(required=False, read_only=True)
217
+ series_groups_count = IntegerField(required=False, read_only=True)
218
+ scan_infos_count = IntegerField(required=False, read_only=True)
218
219
  story_arcs_count = IntegerField(required=False)
219
- story_arc_numbers_count = IntegerField(required=False)
220
- tags_count = IntegerField(required=False)
221
- taggers_count = IntegerField(required=False)
222
- teams_count = IntegerField(required=False)
220
+ story_arc_numbers_count = IntegerField(required=False, read_only=True)
221
+ tags_count = IntegerField(required=False, read_only=True)
222
+ taggers_count = IntegerField(required=False, read_only=True)
223
+ teams_count = IntegerField(required=False, read_only=True)
223
224
 
224
225
 
225
226
  class AdminConfigSerializer(Serializer):
226
227
  """Config Information."""
227
228
 
228
- api_key = CharField(required=False)
229
- groups_count = IntegerField(required=False)
230
- libraries_count = IntegerField(required=False)
231
- sessions_anon_count = IntegerField(required=False)
232
- sessions_count = IntegerField(required=False)
233
- users_count = IntegerField(required=False)
229
+ api_key = CharField(required=False, read_only=True)
230
+ groups_count = IntegerField(required=False, read_only=True)
231
+ libraries_count = IntegerField(required=False, read_only=True)
232
+ sessions_anon_count = IntegerField(required=False, read_only=True)
233
+ sessions_count = IntegerField(required=False, read_only=True)
234
+ users_count = IntegerField(required=False, read_only=True)
234
235
 
235
236
 
236
237
  class AdminPlatformSerializer(Serializer):
237
238
  """Platform Information."""
238
239
 
239
- docker = BooleanField()
240
- machine = CharField()
241
- system = CharField()
242
- system_release = CharField()
243
- python = CharField()
244
- codex = CharField()
240
+ docker = BooleanField(read_only=True)
241
+ machine = CharField(read_only=True)
242
+ system = CharField(read_only=True)
243
+ system_release = CharField(read_only=True)
244
+ python = CharField(read_only=True)
245
+ codex = CharField(read_only=True)
245
246
 
246
247
 
247
248
  class AdminStatsSerializer(Serializer):