codex 1.7.1__py3-none-any.whl → 1.7.3__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 (916) hide show
  1. codex/asgi.py +2 -1
  2. codex/choices.py +10 -21
  3. codex/choices_to_json.py +8 -8
  4. codex/db.py +2 -2
  5. codex/exceptions.py +5 -6
  6. codex/librarian/bookmark/bookmarkd.py +9 -6
  7. codex/librarian/bookmark/tasks.py +1 -1
  8. codex/librarian/bookmark/update.py +17 -31
  9. codex/librarian/covers/create.py +10 -8
  10. codex/librarian/covers/path.py +6 -5
  11. codex/librarian/covers/purge.py +2 -2
  12. codex/librarian/cron/crond.py +1 -1
  13. codex/librarian/importer/aggregate.py +2 -2
  14. codex/librarian/importer/cache.py +1 -4
  15. codex/librarian/importer/create_comics.py +2 -2
  16. codex/librarian/importer/create_covers.py +1 -1
  17. codex/librarian/importer/create_fks.py +4 -3
  18. codex/librarian/importer/deleted.py +3 -3
  19. codex/librarian/importer/extract.py +2 -2
  20. codex/librarian/importer/failed_imports.py +1 -1
  21. codex/librarian/importer/importer.py +3 -1
  22. codex/librarian/importer/importerd.py +3 -3
  23. codex/librarian/importer/link_comics.py +2 -1
  24. codex/librarian/importer/moved.py +2 -7
  25. codex/librarian/importer/query_fks.py +3 -6
  26. codex/librarian/importer/tasks.py +1 -1
  27. codex/librarian/janitor/integrity.py +27 -20
  28. codex/librarian/janitor/janitor.py +5 -2
  29. codex/librarian/janitor/latest_version.py +1 -1
  30. codex/librarian/janitor/update.py +2 -2
  31. codex/librarian/janitor/vacuum.py +1 -1
  32. codex/librarian/librariand.py +16 -15
  33. codex/librarian/notifier/notifierd.py +2 -1
  34. codex/librarian/search/optimize.py +1 -1
  35. codex/librarian/search/remove.py +1 -1
  36. codex/librarian/search/update.py +11 -7
  37. codex/librarian/telemeter/stats.py +7 -6
  38. codex/librarian/telemeter/telemeter.py +0 -1
  39. codex/librarian/watchdog/db_snapshot.py +3 -3
  40. codex/librarian/watchdog/dir_snapshot_diff.py +3 -4
  41. codex/librarian/watchdog/emitter.py +4 -4
  42. codex/librarian/watchdog/event_batcherd.py +2 -1
  43. codex/librarian/watchdog/events.py +1 -2
  44. codex/librarian/watchdog/observers.py +15 -10
  45. codex/logger/loggerd.py +40 -17
  46. codex/logger/logging.py +1 -1
  47. codex/memory.py +3 -2
  48. codex/migrations/0001_init.py +1 -2
  49. codex/migrations/0014_pdf_issue_suffix_remove_cover_image_sort_name.py +1 -2
  50. codex/migrations/0018_rename_userbookmark_bookmark.py +1 -2
  51. codex/migrations/0028_telemeter.py +1 -5
  52. codex/migrations/0031_adminflag_banner.py +50 -0
  53. codex/models/admin.py +4 -3
  54. codex/models/base.py +3 -1
  55. codex/models/bookmark.py +4 -7
  56. codex/models/comic.py +2 -2
  57. codex/models/functions.py +12 -5
  58. codex/models/groups.py +1 -1
  59. codex/models/library.py +1 -1
  60. codex/models/paths.py +4 -4
  61. codex/models/query.py +8 -4
  62. codex/models/util.py +1 -1
  63. codex/permissions.py +1 -1
  64. codex/run.py +1 -1
  65. codex/serializers/admin/flags.py +1 -1
  66. codex/serializers/admin/libraries.py +1 -3
  67. codex/serializers/auth.py +1 -0
  68. codex/serializers/browser/choices.py +9 -11
  69. codex/serializers/browser/metadata.py +1 -1
  70. codex/serializers/browser/mixins.py +5 -1
  71. codex/serializers/browser/settings.py +2 -2
  72. codex/serializers/fields.py +7 -7
  73. codex/serializers/models/base.py +1 -1
  74. codex/serializers/models/comic.py +2 -2
  75. codex/serializers/models/groups.py +0 -2
  76. codex/serializers/opds/authentication.py +2 -1
  77. codex/serializers/opds/v2/__init__.py +1 -0
  78. codex/serializers/opds/v2/facet.py +13 -0
  79. codex/serializers/opds/v2/feed.py +36 -0
  80. codex/serializers/opds/v2/links.py +75 -0
  81. codex/serializers/opds/v2/metadata.py +23 -0
  82. codex/serializers/opds/v2/progression.py +65 -0
  83. codex/serializers/opds/v2/publication.py +81 -0
  84. codex/serializers/opds/{v2_unused.py → v2/unused.py} +16 -9
  85. codex/serializers/route.py +2 -2
  86. codex/settings/settings.py +4 -3
  87. codex/signals/django_signals.py +1 -1
  88. codex/static_root/assets/VCheckbox-Dv6fwaDb.56abbfb00c8a.js +1 -0
  89. codex/static_root/assets/VCheckbox-Dv6fwaDb.56abbfb00c8a.js.br +0 -0
  90. codex/static_root/assets/VCheckbox-Dv6fwaDb.56abbfb00c8a.js.gz +0 -0
  91. codex/static_root/assets/VCheckbox-Dv6fwaDb.js +1 -0
  92. codex/static_root/assets/VCheckbox-Dv6fwaDb.js.br +0 -0
  93. codex/static_root/assets/VCheckbox-Dv6fwaDb.js.gz +0 -0
  94. codex/static_root/assets/VCheckboxBtn-CNMFahfF.4ee9778a562e.js +1 -0
  95. codex/static_root/assets/VCheckboxBtn-CNMFahfF.4ee9778a562e.js.br +0 -0
  96. codex/static_root/assets/VCheckboxBtn-CNMFahfF.4ee9778a562e.js.gz +0 -0
  97. codex/static_root/assets/VCheckboxBtn-CNMFahfF.js +1 -0
  98. codex/static_root/assets/VCheckboxBtn-CNMFahfF.js.br +0 -0
  99. codex/static_root/assets/VCheckboxBtn-CNMFahfF.js.gz +0 -0
  100. codex/static_root/assets/VCombobox-DqBFki-9.2806f95c938d.js +1 -0
  101. codex/static_root/assets/VCombobox-DqBFki-9.2806f95c938d.js.br +0 -0
  102. codex/static_root/assets/VCombobox-DqBFki-9.2806f95c938d.js.gz +0 -0
  103. codex/static_root/assets/VCombobox-DqBFki-9.js +1 -0
  104. codex/static_root/assets/VCombobox-DqBFki-9.js.br +0 -0
  105. codex/static_root/assets/VCombobox-DqBFki-9.js.gz +0 -0
  106. codex/static_root/assets/VDialog-CQXjBvDZ.1a576c5e472f.js +1 -0
  107. codex/static_root/assets/VDialog-CQXjBvDZ.1a576c5e472f.js.br +0 -0
  108. codex/static_root/assets/VDialog-CQXjBvDZ.1a576c5e472f.js.gz +0 -0
  109. codex/static_root/assets/VDialog-CQXjBvDZ.js +1 -0
  110. codex/static_root/assets/VDialog-CQXjBvDZ.js.br +0 -0
  111. codex/static_root/assets/VDialog-CQXjBvDZ.js.gz +0 -0
  112. codex/static_root/assets/VDialog-DWos4S54.b07aca713774.css +1 -0
  113. codex/static_root/assets/VDialog-DWos4S54.b07aca713774.css.br +0 -0
  114. codex/static_root/assets/VDialog-DWos4S54.b07aca713774.css.gz +0 -0
  115. codex/static_root/assets/VDialog-DWos4S54.css +1 -0
  116. codex/static_root/assets/VDialog-DWos4S54.css.br +0 -0
  117. codex/static_root/assets/VDialog-DWos4S54.css.gz +0 -0
  118. codex/static_root/assets/VDivider-DU47sRrT.3d2e17799e5c.css +1 -0
  119. codex/static_root/assets/VDivider-DU47sRrT.3d2e17799e5c.css.br +0 -0
  120. codex/static_root/assets/VDivider-DU47sRrT.3d2e17799e5c.css.gz +0 -0
  121. codex/static_root/assets/VDivider-DU47sRrT.css +1 -0
  122. codex/static_root/assets/VDivider-DU47sRrT.css.br +0 -0
  123. codex/static_root/assets/VDivider-DU47sRrT.css.gz +0 -0
  124. codex/static_root/assets/VDivider-DUxQu-IZ.73d92ae2a07e.js +1 -0
  125. codex/static_root/assets/VDivider-DUxQu-IZ.73d92ae2a07e.js.br +0 -0
  126. codex/static_root/assets/VDivider-DUxQu-IZ.73d92ae2a07e.js.gz +0 -0
  127. codex/static_root/assets/VDivider-DUxQu-IZ.js +1 -0
  128. codex/static_root/assets/VDivider-DUxQu-IZ.js.br +0 -0
  129. codex/static_root/assets/VDivider-DUxQu-IZ.js.gz +0 -0
  130. codex/static_root/assets/VExpansionPanels-BaYzHUJp.5346826103eb.js +1 -0
  131. codex/static_root/assets/VExpansionPanels-BaYzHUJp.5346826103eb.js.br +0 -0
  132. codex/static_root/assets/VExpansionPanels-BaYzHUJp.5346826103eb.js.gz +0 -0
  133. codex/static_root/assets/VExpansionPanels-BaYzHUJp.js +1 -0
  134. codex/static_root/assets/VExpansionPanels-BaYzHUJp.js.br +0 -0
  135. codex/static_root/assets/VExpansionPanels-BaYzHUJp.js.gz +0 -0
  136. codex/static_root/assets/VForm-DxBt30-N.138c0b89b6fc.css +1 -0
  137. codex/static_root/assets/VForm-DxBt30-N.138c0b89b6fc.css.br +0 -0
  138. codex/static_root/assets/VForm-DxBt30-N.138c0b89b6fc.css.gz +0 -0
  139. codex/static_root/assets/VForm-DxBt30-N.css +1 -0
  140. codex/static_root/assets/VForm-DxBt30-N.css.br +0 -0
  141. codex/static_root/assets/VForm-DxBt30-N.css.gz +0 -0
  142. codex/static_root/assets/VForm-hB4C5jVd.a2b90ddcd8ee.js +1 -0
  143. codex/static_root/assets/VForm-hB4C5jVd.a2b90ddcd8ee.js.br +0 -0
  144. codex/static_root/assets/VForm-hB4C5jVd.a2b90ddcd8ee.js.gz +0 -0
  145. codex/static_root/assets/VForm-hB4C5jVd.js +1 -0
  146. codex/static_root/assets/VForm-hB4C5jVd.js.br +0 -0
  147. codex/static_root/assets/VForm-hB4C5jVd.js.gz +0 -0
  148. codex/static_root/assets/VRadioGroup-DOjw38qB.cbf2922d05af.js +1 -0
  149. codex/static_root/assets/VRadioGroup-DOjw38qB.cbf2922d05af.js.br +0 -0
  150. codex/static_root/assets/VRadioGroup-DOjw38qB.cbf2922d05af.js.gz +0 -0
  151. codex/static_root/assets/VRadioGroup-DOjw38qB.js +1 -0
  152. codex/static_root/assets/VRadioGroup-DOjw38qB.js.br +0 -0
  153. codex/static_root/assets/VRadioGroup-DOjw38qB.js.gz +0 -0
  154. codex/static_root/assets/VSelect-CP_CVb8s.6309f7bf17bb.css +1 -0
  155. codex/static_root/assets/VSelect-CP_CVb8s.6309f7bf17bb.css.br +0 -0
  156. codex/static_root/assets/VSelect-CP_CVb8s.6309f7bf17bb.css.gz +0 -0
  157. codex/static_root/assets/VSelect-CP_CVb8s.css +1 -0
  158. codex/static_root/assets/VSelect-CP_CVb8s.css.br +0 -0
  159. codex/static_root/assets/VSelect-CP_CVb8s.css.gz +0 -0
  160. codex/static_root/assets/VSelect-L4v_m3ag.db9fb8348617.js +1 -0
  161. codex/static_root/assets/VSelect-L4v_m3ag.db9fb8348617.js.br +0 -0
  162. codex/static_root/assets/VSelect-L4v_m3ag.db9fb8348617.js.gz +0 -0
  163. codex/static_root/assets/VSelect-L4v_m3ag.js +1 -0
  164. codex/static_root/assets/VSelect-L4v_m3ag.js.br +0 -0
  165. codex/static_root/assets/VSelect-L4v_m3ag.js.gz +0 -0
  166. codex/static_root/assets/VSelectionControl-BqB1JeKa.2fb68a673402.js +1 -0
  167. codex/static_root/assets/VSelectionControl-BqB1JeKa.2fb68a673402.js.br +0 -0
  168. codex/static_root/assets/VSelectionControl-BqB1JeKa.2fb68a673402.js.gz +0 -0
  169. codex/static_root/assets/VSelectionControl-BqB1JeKa.js +1 -0
  170. codex/static_root/assets/VSelectionControl-BqB1JeKa.js.br +0 -0
  171. codex/static_root/assets/VSelectionControl-BqB1JeKa.js.gz +0 -0
  172. codex/static_root/assets/VSelectionControl-DPpfgCW2.cc18de4e83f6.css +1 -0
  173. codex/static_root/assets/VSelectionControl-DPpfgCW2.cc18de4e83f6.css.br +0 -0
  174. codex/static_root/assets/VSelectionControl-DPpfgCW2.cc18de4e83f6.css.gz +0 -0
  175. codex/static_root/assets/VSelectionControl-DPpfgCW2.css +1 -0
  176. codex/static_root/assets/VSelectionControl-DPpfgCW2.css.br +0 -0
  177. codex/static_root/assets/VSelectionControl-DPpfgCW2.css.gz +0 -0
  178. codex/static_root/assets/VTable-CtorAbOx.bbda450cbd73.js +1 -0
  179. codex/static_root/assets/VTable-CtorAbOx.bbda450cbd73.js.br +0 -0
  180. codex/static_root/assets/VTable-CtorAbOx.bbda450cbd73.js.gz +0 -0
  181. codex/static_root/assets/VTable-CtorAbOx.js +1 -0
  182. codex/static_root/assets/VTable-CtorAbOx.js.br +0 -0
  183. codex/static_root/assets/VTable-CtorAbOx.js.gz +0 -0
  184. codex/static_root/assets/VWindowItem-Bl-fa3ss.334e6b813775.js +1 -0
  185. codex/static_root/assets/VWindowItem-Bl-fa3ss.334e6b813775.js.br +0 -0
  186. codex/static_root/assets/VWindowItem-Bl-fa3ss.334e6b813775.js.gz +0 -0
  187. codex/static_root/assets/VWindowItem-Bl-fa3ss.js +1 -0
  188. codex/static_root/assets/VWindowItem-Bl-fa3ss.js.br +0 -0
  189. codex/static_root/assets/VWindowItem-Bl-fa3ss.js.gz +0 -0
  190. codex/static_root/assets/admin-BAVKNREt.23c0966bd683.js +1 -0
  191. codex/static_root/assets/admin-BAVKNREt.23c0966bd683.js.br +0 -0
  192. codex/static_root/assets/admin-BAVKNREt.23c0966bd683.js.gz +0 -0
  193. codex/static_root/assets/admin-BAVKNREt.js +1 -0
  194. codex/static_root/assets/admin-BAVKNREt.js.br +0 -0
  195. codex/static_root/assets/admin-BAVKNREt.js.gz +0 -0
  196. codex/static_root/assets/admin-C3iCIUnm.06cb213f624d.css +1 -0
  197. codex/static_root/assets/admin-C3iCIUnm.06cb213f624d.css.br +0 -0
  198. codex/static_root/assets/admin-C3iCIUnm.06cb213f624d.css.gz +0 -0
  199. codex/static_root/assets/admin-C3iCIUnm.css +1 -0
  200. codex/static_root/assets/admin-C3iCIUnm.css.br +0 -0
  201. codex/static_root/assets/admin-C3iCIUnm.css.gz +0 -0
  202. codex/static_root/assets/admin-CHuFhx_t.a54700f97fc8.js +1 -0
  203. codex/static_root/assets/admin-CHuFhx_t.a54700f97fc8.js.br +0 -0
  204. codex/static_root/assets/admin-CHuFhx_t.a54700f97fc8.js.gz +0 -0
  205. codex/static_root/assets/admin-CHuFhx_t.js +1 -0
  206. codex/static_root/assets/admin-CHuFhx_t.js.br +0 -0
  207. codex/static_root/assets/admin-CHuFhx_t.js.gz +0 -0
  208. codex/static_root/assets/admin-menu-T8WJ_x0C.4f011540bb4c.js +1 -0
  209. codex/static_root/assets/admin-menu-T8WJ_x0C.4f011540bb4c.js.br +0 -0
  210. codex/static_root/assets/admin-menu-T8WJ_x0C.4f011540bb4c.js.gz +0 -0
  211. codex/static_root/assets/admin-menu-T8WJ_x0C.js +1 -0
  212. codex/static_root/assets/admin-menu-T8WJ_x0C.js.br +0 -0
  213. codex/static_root/assets/admin-menu-T8WJ_x0C.js.gz +0 -0
  214. codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.7b36216f68b5.js +1 -0
  215. codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.7b36216f68b5.js.br +0 -0
  216. codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.7b36216f68b5.js.gz +0 -0
  217. codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.js +1 -0
  218. codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.js.br +0 -0
  219. codex/static_root/assets/admin-settings-button-progress-w_CqTSMl.js.gz +0 -0
  220. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css +1 -0
  221. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.br +0 -0
  222. codex/static_root/assets/browser-DNzQvgkY.aea8b7d7ca40.css.gz +0 -0
  223. codex/static_root/assets/browser-DNzQvgkY.css +1 -0
  224. codex/static_root/assets/browser-DNzQvgkY.css.br +0 -0
  225. codex/static_root/assets/browser-DNzQvgkY.css.gz +0 -0
  226. codex/static_root/assets/browser-DdLCtUlr.380b79bea4a7.js +1 -0
  227. codex/static_root/assets/browser-DdLCtUlr.380b79bea4a7.js.br +0 -0
  228. codex/static_root/assets/browser-DdLCtUlr.380b79bea4a7.js.gz +0 -0
  229. codex/static_root/assets/browser-DdLCtUlr.js +1 -0
  230. codex/static_root/assets/browser-DdLCtUlr.js.br +0 -0
  231. codex/static_root/assets/browser-DdLCtUlr.js.gz +0 -0
  232. codex/static_root/assets/change-password-dialog-Cy1tU-tj.416ef5bdfd46.js +1 -0
  233. codex/static_root/assets/change-password-dialog-Cy1tU-tj.416ef5bdfd46.js.br +0 -0
  234. codex/static_root/assets/change-password-dialog-Cy1tU-tj.416ef5bdfd46.js.gz +0 -0
  235. codex/static_root/assets/change-password-dialog-Cy1tU-tj.js +1 -0
  236. codex/static_root/assets/change-password-dialog-Cy1tU-tj.js.br +0 -0
  237. codex/static_root/assets/change-password-dialog-Cy1tU-tj.js.gz +0 -0
  238. codex/static_root/assets/change-password-dialog-D0ymWcl_.a30e68c6e303.css +1 -0
  239. codex/static_root/assets/change-password-dialog-D0ymWcl_.a30e68c6e303.css.br +0 -0
  240. codex/static_root/assets/change-password-dialog-D0ymWcl_.a30e68c6e303.css.gz +0 -0
  241. codex/static_root/assets/change-password-dialog-D0ymWcl_.css +1 -0
  242. codex/static_root/assets/change-password-dialog-D0ymWcl_.css.br +0 -0
  243. codex/static_root/assets/change-password-dialog-D0ymWcl_.css.gz +0 -0
  244. codex/static_root/assets/confirm-dialog-B1ABbGMU.9b5915b112c0.css +1 -0
  245. codex/static_root/assets/confirm-dialog-B1ABbGMU.9b5915b112c0.css.br +0 -0
  246. codex/static_root/assets/confirm-dialog-B1ABbGMU.css +1 -0
  247. codex/static_root/assets/confirm-dialog-B1ABbGMU.css.br +0 -0
  248. codex/static_root/assets/confirm-dialog-B_Y3KKiL.1070d18f6b2d.js +1 -0
  249. codex/static_root/assets/confirm-dialog-B_Y3KKiL.1070d18f6b2d.js.br +0 -0
  250. codex/static_root/assets/confirm-dialog-B_Y3KKiL.1070d18f6b2d.js.gz +0 -0
  251. codex/static_root/assets/confirm-dialog-B_Y3KKiL.js +1 -0
  252. codex/static_root/assets/confirm-dialog-B_Y3KKiL.js.br +0 -0
  253. codex/static_root/assets/confirm-dialog-B_Y3KKiL.js.gz +0 -0
  254. codex/static_root/assets/datetime-column-DVC0YqHC.03bb52c198e9.js +1 -0
  255. codex/static_root/assets/datetime-column-DVC0YqHC.03bb52c198e9.js.br +0 -0
  256. codex/static_root/assets/datetime-column-DVC0YqHC.03bb52c198e9.js.gz +0 -0
  257. codex/static_root/assets/datetime-column-DVC0YqHC.js +1 -0
  258. codex/static_root/assets/datetime-column-DVC0YqHC.js.br +0 -0
  259. codex/static_root/assets/datetime-column-DVC0YqHC.js.gz +0 -0
  260. codex/static_root/assets/{filter-CnO_WiBE.4044b9091aae.js → filter-xcEcgcIx.be1bb4725c89.js} +1 -1
  261. codex/static_root/assets/filter-xcEcgcIx.be1bb4725c89.js.br +0 -0
  262. codex/static_root/assets/filter-xcEcgcIx.be1bb4725c89.js.gz +0 -0
  263. codex/static_root/assets/{filter-CnO_WiBE.js → filter-xcEcgcIx.js} +1 -1
  264. codex/static_root/assets/filter-xcEcgcIx.js.br +0 -0
  265. codex/static_root/assets/filter-xcEcgcIx.js.gz +0 -0
  266. codex/static_root/assets/flag-tab-BOyQb0kr.842fca93f19c.js +1 -0
  267. codex/static_root/assets/flag-tab-BOyQb0kr.842fca93f19c.js.br +0 -0
  268. codex/static_root/assets/flag-tab-BOyQb0kr.842fca93f19c.js.gz +0 -0
  269. codex/static_root/assets/flag-tab-BOyQb0kr.js +1 -0
  270. codex/static_root/assets/flag-tab-BOyQb0kr.js.br +0 -0
  271. codex/static_root/assets/flag-tab-BOyQb0kr.js.gz +0 -0
  272. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css +1 -0
  273. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.br +0 -0
  274. codex/static_root/assets/flag-tab-D2MYXCHk.0f57e109c01b.css.gz +0 -0
  275. codex/static_root/assets/flag-tab-D2MYXCHk.css +1 -0
  276. codex/static_root/assets/flag-tab-D2MYXCHk.css.br +0 -0
  277. codex/static_root/assets/flag-tab-D2MYXCHk.css.gz +0 -0
  278. codex/static_root/assets/{VDialog-CSvrKKb2.css → forwardRefs-CFNX6kJ2.9b56b4459240.css} +1 -1
  279. codex/static_root/assets/forwardRefs-CFNX6kJ2.9b56b4459240.css.br +0 -0
  280. codex/static_root/assets/forwardRefs-CFNX6kJ2.9b56b4459240.css.gz +0 -0
  281. codex/static_root/assets/{VDialog-CSvrKKb2.fd4d50904b17.css → forwardRefs-CFNX6kJ2.css} +1 -1
  282. codex/static_root/assets/forwardRefs-CFNX6kJ2.css.br +0 -0
  283. codex/static_root/assets/forwardRefs-CFNX6kJ2.css.gz +0 -0
  284. codex/static_root/assets/forwardRefs-D1ZDjzWx.96fccf773093.js +1 -0
  285. codex/static_root/assets/forwardRefs-D1ZDjzWx.96fccf773093.js.br +0 -0
  286. codex/static_root/assets/forwardRefs-D1ZDjzWx.96fccf773093.js.gz +0 -0
  287. codex/static_root/assets/forwardRefs-D1ZDjzWx.js +1 -0
  288. codex/static_root/assets/forwardRefs-D1ZDjzWx.js.br +0 -0
  289. codex/static_root/assets/forwardRefs-D1ZDjzWx.js.gz +0 -0
  290. codex/static_root/assets/group-tab-DkAIGL8z.527cad03c21d.js +1 -0
  291. codex/static_root/assets/group-tab-DkAIGL8z.527cad03c21d.js.br +0 -0
  292. codex/static_root/assets/group-tab-DkAIGL8z.527cad03c21d.js.gz +0 -0
  293. codex/static_root/assets/group-tab-DkAIGL8z.js +1 -0
  294. codex/static_root/assets/group-tab-DkAIGL8z.js.br +0 -0
  295. codex/static_root/assets/group-tab-DkAIGL8z.js.gz +0 -0
  296. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css +1 -0
  297. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.br +0 -0
  298. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.gz +0 -0
  299. codex/static_root/assets/http-error-CODU7jcH.css +1 -0
  300. codex/static_root/assets/http-error-CODU7jcH.css.br +0 -0
  301. codex/static_root/assets/http-error-CODU7jcH.css.gz +0 -0
  302. codex/static_root/assets/http-error-CjSb8orc.ad6fc5733ed8.js +1 -0
  303. codex/static_root/assets/http-error-CjSb8orc.ad6fc5733ed8.js.br +0 -0
  304. codex/static_root/assets/http-error-CjSb8orc.ad6fc5733ed8.js.gz +0 -0
  305. codex/static_root/assets/http-error-CjSb8orc.js +1 -0
  306. codex/static_root/assets/http-error-CjSb8orc.js.br +0 -0
  307. codex/static_root/assets/http-error-CjSb8orc.js.gz +0 -0
  308. codex/static_root/assets/index-CoFXW6I0.27f397e1425e.js +1 -0
  309. codex/static_root/assets/index-CoFXW6I0.27f397e1425e.js.br +0 -0
  310. codex/static_root/assets/index-CoFXW6I0.27f397e1425e.js.gz +0 -0
  311. codex/static_root/assets/index-CoFXW6I0.js +1 -0
  312. codex/static_root/assets/index-CoFXW6I0.js.br +0 -0
  313. codex/static_root/assets/index-CoFXW6I0.js.gz +0 -0
  314. codex/static_root/assets/library-tab-CgsXOX_r.75baedb7e976.css +1 -0
  315. codex/static_root/assets/library-tab-CgsXOX_r.75baedb7e976.css.br +0 -0
  316. codex/static_root/assets/library-tab-CgsXOX_r.75baedb7e976.css.gz +0 -0
  317. codex/static_root/assets/library-tab-CgsXOX_r.css +1 -0
  318. codex/static_root/assets/library-tab-CgsXOX_r.css.br +0 -0
  319. codex/static_root/assets/library-tab-CgsXOX_r.css.gz +0 -0
  320. codex/static_root/assets/library-tab-hkMMBz1x.02270491d822.js +1 -0
  321. codex/static_root/assets/library-tab-hkMMBz1x.02270491d822.js.br +0 -0
  322. codex/static_root/assets/library-tab-hkMMBz1x.02270491d822.js.gz +0 -0
  323. codex/static_root/assets/library-tab-hkMMBz1x.js +1 -0
  324. codex/static_root/assets/library-tab-hkMMBz1x.js.br +0 -0
  325. codex/static_root/assets/library-tab-hkMMBz1x.js.gz +0 -0
  326. codex/static_root/assets/main-DCaPxp2h.076707ddd123.js +35 -0
  327. codex/static_root/assets/main-DCaPxp2h.076707ddd123.js.br +0 -0
  328. codex/static_root/assets/main-DCaPxp2h.076707ddd123.js.gz +0 -0
  329. codex/static_root/assets/main-DCaPxp2h.js +35 -0
  330. codex/static_root/assets/main-DCaPxp2h.js.br +0 -0
  331. codex/static_root/assets/main-DCaPxp2h.js.gz +0 -0
  332. codex/static_root/assets/pager-full-pdf-CwmA9y3l.e7dfdd2a6937.js +1 -0
  333. codex/static_root/assets/pager-full-pdf-CwmA9y3l.e7dfdd2a6937.js.br +0 -0
  334. codex/static_root/assets/pager-full-pdf-CwmA9y3l.e7dfdd2a6937.js.gz +0 -0
  335. codex/static_root/assets/pager-full-pdf-CwmA9y3l.js +1 -0
  336. codex/static_root/assets/pager-full-pdf-CwmA9y3l.js.br +0 -0
  337. codex/static_root/assets/pager-full-pdf-CwmA9y3l.js.gz +0 -0
  338. codex/static_root/assets/pagination-toolbar-D5VQREy5.css +1 -0
  339. codex/static_root/assets/pagination-toolbar-D5VQREy5.css.br +0 -0
  340. codex/static_root/assets/pagination-toolbar-D5VQREy5.css.gz +0 -0
  341. codex/static_root/assets/pagination-toolbar-D5VQREy5.dcb0eba65827.css +1 -0
  342. codex/static_root/assets/pagination-toolbar-D5VQREy5.dcb0eba65827.css.br +0 -0
  343. codex/static_root/assets/pagination-toolbar-D5VQREy5.dcb0eba65827.css.gz +0 -0
  344. codex/static_root/assets/pagination-toolbar-DoqxSygU.f985bc705fe5.js +1 -0
  345. codex/static_root/assets/pagination-toolbar-DoqxSygU.f985bc705fe5.js.br +0 -0
  346. codex/static_root/assets/pagination-toolbar-DoqxSygU.f985bc705fe5.js.gz +0 -0
  347. codex/static_root/assets/pagination-toolbar-DoqxSygU.js +1 -0
  348. codex/static_root/assets/pagination-toolbar-DoqxSygU.js.br +0 -0
  349. codex/static_root/assets/pagination-toolbar-DoqxSygU.js.gz +0 -0
  350. codex/static_root/assets/pdf-doc-BwxvAx1z.96cbc39c321d.js +348 -0
  351. codex/static_root/assets/pdf-doc-BwxvAx1z.96cbc39c321d.js.br +0 -0
  352. codex/static_root/assets/pdf-doc-BwxvAx1z.96cbc39c321d.js.gz +0 -0
  353. codex/static_root/assets/pdf-doc-BwxvAx1z.js +348 -0
  354. codex/static_root/assets/pdf-doc-BwxvAx1z.js.br +0 -0
  355. codex/static_root/assets/pdf-doc-BwxvAx1z.js.gz +0 -0
  356. codex/static_root/assets/reader-D_3ruSqa.2ed32f08e906.css +1 -0
  357. codex/static_root/assets/reader-D_3ruSqa.2ed32f08e906.css.br +0 -0
  358. codex/static_root/assets/reader-D_3ruSqa.2ed32f08e906.css.gz +0 -0
  359. codex/static_root/assets/reader-D_3ruSqa.css +1 -0
  360. codex/static_root/assets/reader-D_3ruSqa.css.br +0 -0
  361. codex/static_root/assets/reader-D_3ruSqa.css.gz +0 -0
  362. codex/static_root/assets/reader-hHIonVbA.4c12219242a9.js +2 -0
  363. codex/static_root/assets/reader-hHIonVbA.4c12219242a9.js.br +0 -0
  364. codex/static_root/assets/reader-hHIonVbA.4c12219242a9.js.gz +0 -0
  365. codex/static_root/assets/reader-hHIonVbA.js +2 -0
  366. codex/static_root/assets/reader-hHIonVbA.js.br +0 -0
  367. codex/static_root/assets/reader-hHIonVbA.js.gz +0 -0
  368. codex/static_root/assets/relation-chips-D7-5kPem.4443b085aca2.js +1 -0
  369. codex/static_root/assets/relation-chips-D7-5kPem.4443b085aca2.js.br +0 -0
  370. codex/static_root/assets/relation-chips-D7-5kPem.4443b085aca2.js.gz +0 -0
  371. codex/static_root/assets/relation-chips-D7-5kPem.js +1 -0
  372. codex/static_root/assets/relation-chips-D7-5kPem.js.br +0 -0
  373. codex/static_root/assets/relation-chips-D7-5kPem.js.gz +0 -0
  374. codex/static_root/assets/settings-drawer-CdFmOhnd.f7dcd12b3ebc.js +2 -0
  375. codex/static_root/assets/settings-drawer-CdFmOhnd.f7dcd12b3ebc.js.br +0 -0
  376. codex/static_root/assets/settings-drawer-CdFmOhnd.f7dcd12b3ebc.js.gz +0 -0
  377. codex/static_root/assets/settings-drawer-CdFmOhnd.js +2 -0
  378. codex/static_root/assets/settings-drawer-CdFmOhnd.js.br +0 -0
  379. codex/static_root/assets/settings-drawer-CdFmOhnd.js.gz +0 -0
  380. codex/static_root/assets/settings-drawer-DMSsWF8c.75a6ea969e71.css +1 -0
  381. codex/static_root/assets/settings-drawer-DMSsWF8c.75a6ea969e71.css.br +0 -0
  382. codex/static_root/assets/settings-drawer-DMSsWF8c.75a6ea969e71.css.gz +0 -0
  383. codex/static_root/assets/settings-drawer-DMSsWF8c.css +1 -0
  384. codex/static_root/assets/settings-drawer-DMSsWF8c.css.br +0 -0
  385. codex/static_root/assets/settings-drawer-DMSsWF8c.css.gz +0 -0
  386. codex/static_root/assets/stats-tab-BzaipD0m.b6bf627ea860.js +1 -0
  387. codex/static_root/assets/stats-tab-BzaipD0m.b6bf627ea860.js.br +0 -0
  388. codex/static_root/assets/stats-tab-BzaipD0m.b6bf627ea860.js.gz +0 -0
  389. codex/static_root/assets/stats-tab-BzaipD0m.js +1 -0
  390. codex/static_root/assets/stats-tab-BzaipD0m.js.br +0 -0
  391. codex/static_root/assets/stats-tab-BzaipD0m.js.gz +0 -0
  392. codex/static_root/assets/{stats-tab-BAYTqQNg.5f715428c394.css → stats-tab-WvF2acoZ.9fdb0106124d.css} +1 -1
  393. codex/static_root/assets/stats-tab-WvF2acoZ.9fdb0106124d.css.br +0 -0
  394. codex/static_root/assets/stats-tab-WvF2acoZ.9fdb0106124d.css.gz +0 -0
  395. codex/static_root/assets/{stats-tab-BAYTqQNg.css → stats-tab-WvF2acoZ.css} +1 -1
  396. codex/static_root/assets/stats-tab-WvF2acoZ.css.br +0 -0
  397. codex/static_root/assets/stats-tab-WvF2acoZ.css.gz +0 -0
  398. codex/static_root/assets/task-tab-DCnS1sM9.44d8435b4989.js +1 -0
  399. codex/static_root/assets/task-tab-DCnS1sM9.44d8435b4989.js.br +0 -0
  400. codex/static_root/assets/task-tab-DCnS1sM9.44d8435b4989.js.gz +0 -0
  401. codex/static_root/assets/task-tab-DCnS1sM9.js +1 -0
  402. codex/static_root/assets/task-tab-DCnS1sM9.js.br +0 -0
  403. codex/static_root/assets/task-tab-DCnS1sM9.js.gz +0 -0
  404. codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css +1 -0
  405. codex/static_root/assets/{task-tab--cXi48kg.5dfd6890a1c2.css.br → task-tab-DfdUY9Rc.478e74041f80.css.br} +1 -1
  406. codex/static_root/assets/task-tab-DfdUY9Rc.478e74041f80.css.gz +0 -0
  407. codex/static_root/assets/task-tab-DfdUY9Rc.css +1 -0
  408. codex/static_root/assets/{task-tab--cXi48kg.css.br → task-tab-DfdUY9Rc.css.br} +1 -1
  409. codex/static_root/assets/task-tab-DfdUY9Rc.css.gz +0 -0
  410. codex/static_root/assets/unauthorized-CsSak07X.c5536d9dae75.css +1 -0
  411. codex/static_root/assets/unauthorized-CsSak07X.c5536d9dae75.css.br +0 -0
  412. codex/static_root/assets/unauthorized-CsSak07X.c5536d9dae75.css.gz +0 -0
  413. codex/static_root/assets/unauthorized-CsSak07X.css +1 -0
  414. codex/static_root/assets/unauthorized-CsSak07X.css.br +0 -0
  415. codex/static_root/assets/unauthorized-CsSak07X.css.gz +0 -0
  416. codex/static_root/assets/unauthorized-DJSr03Dw.7555cbcf1064.js +1 -0
  417. codex/static_root/assets/unauthorized-DJSr03Dw.7555cbcf1064.js.br +0 -0
  418. codex/static_root/assets/unauthorized-DJSr03Dw.7555cbcf1064.js.gz +0 -0
  419. codex/static_root/assets/unauthorized-DJSr03Dw.js +1 -0
  420. codex/static_root/assets/unauthorized-DJSr03Dw.js.br +0 -0
  421. codex/static_root/assets/unauthorized-DJSr03Dw.js.gz +0 -0
  422. codex/static_root/assets/user-tab-DAK_Deoh.1832877d449a.js +1 -0
  423. codex/static_root/assets/user-tab-DAK_Deoh.1832877d449a.js.br +0 -0
  424. codex/static_root/assets/user-tab-DAK_Deoh.1832877d449a.js.gz +0 -0
  425. codex/static_root/assets/user-tab-DAK_Deoh.js +1 -0
  426. codex/static_root/assets/user-tab-DAK_Deoh.js.br +0 -0
  427. codex/static_root/assets/user-tab-DAK_Deoh.js.gz +0 -0
  428. codex/static_root/manifest.cbc39bca88fc.json +735 -0
  429. codex/static_root/manifest.cbc39bca88fc.json.br +0 -0
  430. codex/static_root/manifest.cbc39bca88fc.json.gz +0 -0
  431. codex/static_root/manifest.json +389 -366
  432. codex/static_root/manifest.json.br +0 -0
  433. codex/static_root/manifest.json.gz +0 -0
  434. codex/static_root/staticfiles.json +1 -1
  435. codex/status_controller.py +9 -12
  436. codex/templates/index.html +1 -1
  437. codex/threads.py +3 -3
  438. codex/urls/api/admin.py +4 -3
  439. codex/urls/api/browser.py +10 -1
  440. codex/urls/api/reader.py +8 -4
  441. codex/urls/opds/v2.py +6 -0
  442. codex/urls/root.py +4 -3
  443. codex/util.py +11 -0
  444. codex/views/admin/api_key.py +1 -4
  445. codex/views/admin/flag.py +5 -1
  446. codex/views/admin/library.py +4 -4
  447. codex/views/admin/stats.py +10 -10
  448. codex/views/admin/tasks.py +9 -9
  449. codex/views/auth.py +3 -8
  450. codex/views/bookmark.py +53 -41
  451. codex/views/browser/annotate/bookmark.py +6 -4
  452. codex/views/browser/annotate/card.py +4 -21
  453. codex/views/browser/annotate/order.py +51 -25
  454. codex/views/browser/bookmark.py +53 -0
  455. codex/views/browser/breadcrumbs.py +6 -5
  456. codex/views/browser/browser.py +2 -2
  457. codex/views/browser/choices.py +6 -5
  458. codex/views/browser/cover.py +6 -3
  459. codex/views/browser/download.py +67 -0
  460. codex/views/browser/filters/bookmark.py +5 -33
  461. codex/views/browser/filters/field.py +1 -1
  462. codex/views/browser/filters/filter.py +6 -8
  463. codex/views/browser/filters/group.py +7 -4
  464. codex/views/browser/filters/search/field/expression.py +1 -2
  465. codex/views/browser/filters/search/field/optimize.py +1 -1
  466. codex/views/browser/filters/search/field/parse.py +2 -2
  467. codex/views/browser/filters/search/parse.py +4 -19
  468. codex/views/browser/group_mtime.py +3 -3
  469. codex/views/browser/metadata/annotate.py +1 -1
  470. codex/views/browser/metadata/copy_intersections.py +1 -1
  471. codex/views/browser/metadata/metadata.py +2 -2
  472. codex/views/browser/mtime.py +1 -1
  473. codex/views/browser/order_by.py +9 -6
  474. codex/views/browser/params.py +1 -1
  475. codex/views/browser/settings.py +1 -1
  476. codex/views/browser/validate.py +14 -7
  477. codex/views/const.py +0 -3
  478. codex/views/download.py +5 -5
  479. codex/views/frontend.py +20 -5
  480. codex/views/mixins.py +19 -30
  481. codex/views/opds/authentication_v1.py +1 -1
  482. codex/views/opds/const.py +6 -4
  483. codex/views/opds/util.py +5 -5
  484. codex/views/opds/v1/entry/entry.py +4 -2
  485. codex/views/opds/v1/entry/links.py +5 -7
  486. codex/views/opds/v1/facets.py +8 -4
  487. codex/views/opds/v1/feed.py +5 -5
  488. codex/views/opds/v1/links.py +11 -6
  489. codex/views/opds/v2/const.py +5 -2
  490. codex/views/opds/v2/feed.py +6 -5
  491. codex/views/opds/v2/href.py +60 -0
  492. codex/views/opds/v2/links.py +13 -47
  493. codex/views/opds/v2/progression.py +136 -0
  494. codex/views/opds/v2/publications.py +31 -21
  495. codex/views/opds/v2/top_links.py +2 -1
  496. codex/views/public.py +12 -5
  497. codex/views/reader/books.py +22 -10
  498. codex/views/reader/page.py +19 -14
  499. codex/views/reader/params.py +3 -3
  500. codex/views/reader/reader.py +6 -6
  501. codex/views/reader/settings.py +1 -1
  502. codex/views/session.py +10 -3
  503. codex/views/settings.py +2 -2
  504. codex/views/timezone.py +2 -2
  505. codex/views/util.py +10 -9
  506. codex/views/version.py +1 -1
  507. {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/METADATA +23 -27
  508. codex-1.7.3.dist-info/RECORD +1031 -0
  509. {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/WHEEL +1 -1
  510. codex/serializers/opds/v2.py +0 -178
  511. codex/static_root/assets/VCheckbox-Cf74Jfrq.2fbb5106ef5a.js +0 -1
  512. codex/static_root/assets/VCheckbox-Cf74Jfrq.2fbb5106ef5a.js.br +0 -0
  513. codex/static_root/assets/VCheckbox-Cf74Jfrq.2fbb5106ef5a.js.gz +0 -0
  514. codex/static_root/assets/VCheckbox-Cf74Jfrq.js +0 -1
  515. codex/static_root/assets/VCheckbox-Cf74Jfrq.js.br +0 -0
  516. codex/static_root/assets/VCheckbox-Cf74Jfrq.js.gz +0 -0
  517. codex/static_root/assets/VCheckboxBtn-D5jbIiqO.921713d268ba.js +0 -1
  518. codex/static_root/assets/VCheckboxBtn-D5jbIiqO.921713d268ba.js.br +0 -0
  519. codex/static_root/assets/VCheckboxBtn-D5jbIiqO.921713d268ba.js.gz +0 -0
  520. codex/static_root/assets/VCheckboxBtn-D5jbIiqO.js +0 -1
  521. codex/static_root/assets/VCheckboxBtn-D5jbIiqO.js.br +0 -0
  522. codex/static_root/assets/VCheckboxBtn-D5jbIiqO.js.gz +0 -0
  523. codex/static_root/assets/VCombobox-Dq3Y5j2w.8f4884677e5a.js +0 -1
  524. codex/static_root/assets/VCombobox-Dq3Y5j2w.8f4884677e5a.js.br +0 -0
  525. codex/static_root/assets/VCombobox-Dq3Y5j2w.8f4884677e5a.js.gz +0 -0
  526. codex/static_root/assets/VCombobox-Dq3Y5j2w.js +0 -1
  527. codex/static_root/assets/VCombobox-Dq3Y5j2w.js.br +0 -0
  528. codex/static_root/assets/VCombobox-Dq3Y5j2w.js.gz +0 -0
  529. codex/static_root/assets/VDialog-BVHV10WD.993b98f2be7f.js +0 -1
  530. codex/static_root/assets/VDialog-BVHV10WD.993b98f2be7f.js.br +0 -0
  531. codex/static_root/assets/VDialog-BVHV10WD.993b98f2be7f.js.gz +0 -0
  532. codex/static_root/assets/VDialog-BVHV10WD.js +0 -1
  533. codex/static_root/assets/VDialog-BVHV10WD.js.br +0 -0
  534. codex/static_root/assets/VDialog-BVHV10WD.js.gz +0 -0
  535. codex/static_root/assets/VDialog-CSvrKKb2.css.br +0 -0
  536. codex/static_root/assets/VDialog-CSvrKKb2.css.gz +0 -0
  537. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.br +0 -0
  538. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.gz +0 -0
  539. codex/static_root/assets/VExpansionPanels-BLAGU-dj.e244f3902cf9.js +0 -1
  540. codex/static_root/assets/VExpansionPanels-BLAGU-dj.e244f3902cf9.js.br +0 -0
  541. codex/static_root/assets/VExpansionPanels-BLAGU-dj.e244f3902cf9.js.gz +0 -0
  542. codex/static_root/assets/VExpansionPanels-BLAGU-dj.js +0 -1
  543. codex/static_root/assets/VExpansionPanels-BLAGU-dj.js.br +0 -0
  544. codex/static_root/assets/VExpansionPanels-BLAGU-dj.js.gz +0 -0
  545. codex/static_root/assets/VRadioGroup-Bnt5BbmK.826e1c2d9134.js +0 -1
  546. codex/static_root/assets/VRadioGroup-Bnt5BbmK.826e1c2d9134.js.br +0 -0
  547. codex/static_root/assets/VRadioGroup-Bnt5BbmK.826e1c2d9134.js.gz +0 -0
  548. codex/static_root/assets/VRadioGroup-Bnt5BbmK.js +0 -1
  549. codex/static_root/assets/VRadioGroup-Bnt5BbmK.js.br +0 -0
  550. codex/static_root/assets/VRadioGroup-Bnt5BbmK.js.gz +0 -0
  551. codex/static_root/assets/VSelect-BTo1ZM8U.ea4a7a7bbce9.js +0 -1
  552. codex/static_root/assets/VSelect-BTo1ZM8U.ea4a7a7bbce9.js.br +0 -0
  553. codex/static_root/assets/VSelect-BTo1ZM8U.ea4a7a7bbce9.js.gz +0 -0
  554. codex/static_root/assets/VSelect-BTo1ZM8U.js +0 -1
  555. codex/static_root/assets/VSelect-BTo1ZM8U.js.br +0 -0
  556. codex/static_root/assets/VSelect-BTo1ZM8U.js.gz +0 -0
  557. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css +0 -1
  558. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.br +0 -0
  559. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.gz +0 -0
  560. codex/static_root/assets/VSelect-DLu8bpcs.css +0 -1
  561. codex/static_root/assets/VSelect-DLu8bpcs.css.br +0 -0
  562. codex/static_root/assets/VSelect-DLu8bpcs.css.gz +0 -0
  563. codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css +0 -1
  564. codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css.br +0 -0
  565. codex/static_root/assets/VSelectionControl-CiViEYoC.c77bb19a4a06.css.gz +0 -0
  566. codex/static_root/assets/VSelectionControl-CiViEYoC.css +0 -1
  567. codex/static_root/assets/VSelectionControl-CiViEYoC.css.br +0 -0
  568. codex/static_root/assets/VSelectionControl-CiViEYoC.css.gz +0 -0
  569. codex/static_root/assets/VSelectionControl-CrzLF2bD.965af5336c62.js +0 -1
  570. codex/static_root/assets/VSelectionControl-CrzLF2bD.965af5336c62.js.br +0 -0
  571. codex/static_root/assets/VSelectionControl-CrzLF2bD.965af5336c62.js.gz +0 -0
  572. codex/static_root/assets/VSelectionControl-CrzLF2bD.js +0 -1
  573. codex/static_root/assets/VSelectionControl-CrzLF2bD.js.br +0 -0
  574. codex/static_root/assets/VSelectionControl-CrzLF2bD.js.gz +0 -0
  575. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css +0 -1
  576. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.br +0 -0
  577. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.gz +0 -0
  578. codex/static_root/assets/VSlideGroup-BtXPhMOT.css +0 -1
  579. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.br +0 -0
  580. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.gz +0 -0
  581. codex/static_root/assets/VSlideGroup-ZRALPG67.9807cdc6b330.js +0 -1
  582. codex/static_root/assets/VSlideGroup-ZRALPG67.9807cdc6b330.js.br +0 -0
  583. codex/static_root/assets/VSlideGroup-ZRALPG67.9807cdc6b330.js.gz +0 -0
  584. codex/static_root/assets/VSlideGroup-ZRALPG67.js +0 -1
  585. codex/static_root/assets/VSlideGroup-ZRALPG67.js.br +0 -0
  586. codex/static_root/assets/VSlideGroup-ZRALPG67.js.gz +0 -0
  587. codex/static_root/assets/VTable-Ci8_04Au.1382ab272e40.js +0 -1
  588. codex/static_root/assets/VTable-Ci8_04Au.1382ab272e40.js.br +0 -0
  589. codex/static_root/assets/VTable-Ci8_04Au.1382ab272e40.js.gz +0 -0
  590. codex/static_root/assets/VTable-Ci8_04Au.js +0 -1
  591. codex/static_root/assets/VTable-Ci8_04Au.js.br +0 -0
  592. codex/static_root/assets/VTable-Ci8_04Au.js.gz +0 -0
  593. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css +0 -1
  594. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.br +0 -0
  595. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.gz +0 -0
  596. codex/static_root/assets/VTextField-BnCEPZIq.css +0 -1
  597. codex/static_root/assets/VTextField-BnCEPZIq.css.br +0 -0
  598. codex/static_root/assets/VTextField-BnCEPZIq.css.gz +0 -0
  599. codex/static_root/assets/VTextField-D7pt5iJ3.c020691495b7.js +0 -1
  600. codex/static_root/assets/VTextField-D7pt5iJ3.c020691495b7.js.br +0 -0
  601. codex/static_root/assets/VTextField-D7pt5iJ3.c020691495b7.js.gz +0 -0
  602. codex/static_root/assets/VTextField-D7pt5iJ3.js +0 -1
  603. codex/static_root/assets/VTextField-D7pt5iJ3.js.br +0 -0
  604. codex/static_root/assets/VTextField-D7pt5iJ3.js.gz +0 -0
  605. codex/static_root/assets/VWindowItem-CGBsUHpV.7c57d79cf74a.js +0 -1
  606. codex/static_root/assets/VWindowItem-CGBsUHpV.7c57d79cf74a.js.br +0 -0
  607. codex/static_root/assets/VWindowItem-CGBsUHpV.7c57d79cf74a.js.gz +0 -0
  608. codex/static_root/assets/VWindowItem-CGBsUHpV.js +0 -1
  609. codex/static_root/assets/VWindowItem-CGBsUHpV.js.br +0 -0
  610. codex/static_root/assets/VWindowItem-CGBsUHpV.js.gz +0 -0
  611. codex/static_root/assets/admin-BTXUbxw5.23e0d3602f29.js +0 -1
  612. codex/static_root/assets/admin-BTXUbxw5.23e0d3602f29.js.br +0 -0
  613. codex/static_root/assets/admin-BTXUbxw5.23e0d3602f29.js.gz +0 -0
  614. codex/static_root/assets/admin-BTXUbxw5.js +0 -1
  615. codex/static_root/assets/admin-BTXUbxw5.js.br +0 -0
  616. codex/static_root/assets/admin-BTXUbxw5.js.gz +0 -0
  617. codex/static_root/assets/admin-DJ7pIXDQ.css +0 -1
  618. codex/static_root/assets/admin-DJ7pIXDQ.css.br +0 -0
  619. codex/static_root/assets/admin-DJ7pIXDQ.css.gz +0 -0
  620. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css +0 -1
  621. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.br +0 -0
  622. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
  623. codex/static_root/assets/admin-menu-Dbt1Rajw.043fb778ba6c.js +0 -1
  624. codex/static_root/assets/admin-menu-Dbt1Rajw.043fb778ba6c.js.br +0 -0
  625. codex/static_root/assets/admin-menu-Dbt1Rajw.043fb778ba6c.js.gz +0 -0
  626. codex/static_root/assets/admin-menu-Dbt1Rajw.js +0 -1
  627. codex/static_root/assets/admin-menu-Dbt1Rajw.js.br +0 -0
  628. codex/static_root/assets/admin-menu-Dbt1Rajw.js.gz +0 -0
  629. codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.fad596375b9b.js +0 -1
  630. codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.fad596375b9b.js.br +0 -0
  631. codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.fad596375b9b.js.gz +0 -0
  632. codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.js +0 -1
  633. codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.js.br +0 -0
  634. codex/static_root/assets/admin-settings-button-progress-DSOZWzf1.js.gz +0 -0
  635. codex/static_root/assets/browser-3Sm5qvA_.188da1350ec3.css +0 -1
  636. codex/static_root/assets/browser-3Sm5qvA_.188da1350ec3.css.br +0 -0
  637. codex/static_root/assets/browser-3Sm5qvA_.188da1350ec3.css.gz +0 -0
  638. codex/static_root/assets/browser-3Sm5qvA_.css +0 -1
  639. codex/static_root/assets/browser-3Sm5qvA_.css.br +0 -0
  640. codex/static_root/assets/browser-3Sm5qvA_.css.gz +0 -0
  641. codex/static_root/assets/browser-Dq-fQLJF.2e88354a9574.js +0 -1
  642. codex/static_root/assets/browser-Dq-fQLJF.2e88354a9574.js.br +0 -0
  643. codex/static_root/assets/browser-Dq-fQLJF.2e88354a9574.js.gz +0 -0
  644. codex/static_root/assets/browser-Dq-fQLJF.js +0 -1
  645. codex/static_root/assets/browser-Dq-fQLJF.js.br +0 -0
  646. codex/static_root/assets/browser-Dq-fQLJF.js.gz +0 -0
  647. codex/static_root/assets/change-password-dialog-BaGA_bnX.af8ea11b1579.js +0 -1
  648. codex/static_root/assets/change-password-dialog-BaGA_bnX.af8ea11b1579.js.br +0 -0
  649. codex/static_root/assets/change-password-dialog-BaGA_bnX.af8ea11b1579.js.gz +0 -0
  650. codex/static_root/assets/change-password-dialog-BaGA_bnX.js +0 -1
  651. codex/static_root/assets/change-password-dialog-BaGA_bnX.js.br +0 -0
  652. codex/static_root/assets/change-password-dialog-BaGA_bnX.js.gz +0 -0
  653. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css +0 -1
  654. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.br +0 -0
  655. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.gz +0 -0
  656. codex/static_root/assets/change-password-dialog-DrIXdKUC.css +0 -1
  657. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.br +0 -0
  658. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.gz +0 -0
  659. codex/static_root/assets/confirm-dialog-B7w6z2rf.472011c06253.css +0 -1
  660. codex/static_root/assets/confirm-dialog-B7w6z2rf.css +0 -1
  661. codex/static_root/assets/confirm-dialog-X14gSw1w.21504f7c1db4.js +0 -1
  662. codex/static_root/assets/confirm-dialog-X14gSw1w.21504f7c1db4.js.br +0 -0
  663. codex/static_root/assets/confirm-dialog-X14gSw1w.21504f7c1db4.js.gz +0 -0
  664. codex/static_root/assets/confirm-dialog-X14gSw1w.js +0 -1
  665. codex/static_root/assets/confirm-dialog-X14gSw1w.js.br +0 -0
  666. codex/static_root/assets/confirm-dialog-X14gSw1w.js.gz +0 -0
  667. codex/static_root/assets/datetime-column-BN2Ulei5.a31061d3729c.js +0 -1
  668. codex/static_root/assets/datetime-column-BN2Ulei5.a31061d3729c.js.br +0 -0
  669. codex/static_root/assets/datetime-column-BN2Ulei5.a31061d3729c.js.gz +0 -0
  670. codex/static_root/assets/datetime-column-BN2Ulei5.js +0 -1
  671. codex/static_root/assets/datetime-column-BN2Ulei5.js.br +0 -0
  672. codex/static_root/assets/datetime-column-BN2Ulei5.js.gz +0 -0
  673. codex/static_root/assets/filter-CnO_WiBE.4044b9091aae.js.br +0 -0
  674. codex/static_root/assets/filter-CnO_WiBE.4044b9091aae.js.gz +0 -0
  675. codex/static_root/assets/filter-CnO_WiBE.js.br +0 -0
  676. codex/static_root/assets/filter-CnO_WiBE.js.gz +0 -0
  677. codex/static_root/assets/flag-tab-C5NP3j6O.1c692a00884d.js +0 -1
  678. codex/static_root/assets/flag-tab-C5NP3j6O.1c692a00884d.js.br +0 -0
  679. codex/static_root/assets/flag-tab-C5NP3j6O.1c692a00884d.js.gz +0 -0
  680. codex/static_root/assets/flag-tab-C5NP3j6O.js +0 -1
  681. codex/static_root/assets/flag-tab-C5NP3j6O.js.br +0 -0
  682. codex/static_root/assets/flag-tab-C5NP3j6O.js.gz +0 -0
  683. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css +0 -1
  684. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.br +0 -0
  685. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.gz +0 -0
  686. codex/static_root/assets/flag-tab-CqWovuBu.css +0 -1
  687. codex/static_root/assets/flag-tab-CqWovuBu.css.br +0 -0
  688. codex/static_root/assets/flag-tab-CqWovuBu.css.gz +0 -0
  689. codex/static_root/assets/group-tab-Cq4QjmHS.a9d15dac0289.js +0 -1
  690. codex/static_root/assets/group-tab-Cq4QjmHS.a9d15dac0289.js.br +0 -0
  691. codex/static_root/assets/group-tab-Cq4QjmHS.a9d15dac0289.js.gz +0 -0
  692. codex/static_root/assets/group-tab-Cq4QjmHS.js +0 -1
  693. codex/static_root/assets/group-tab-Cq4QjmHS.js.br +0 -0
  694. codex/static_root/assets/group-tab-Cq4QjmHS.js.gz +0 -0
  695. codex/static_root/assets/http-error-DGFbgQC5.da17e7b6d980.js +0 -1
  696. codex/static_root/assets/http-error-DGFbgQC5.da17e7b6d980.js.br +0 -0
  697. codex/static_root/assets/http-error-DGFbgQC5.da17e7b6d980.js.gz +0 -0
  698. codex/static_root/assets/http-error-DGFbgQC5.js +0 -1
  699. codex/static_root/assets/http-error-DGFbgQC5.js.br +0 -0
  700. codex/static_root/assets/http-error-DGFbgQC5.js.gz +0 -0
  701. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css +0 -1
  702. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.br +0 -0
  703. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.gz +0 -0
  704. codex/static_root/assets/http-error-DKulXuTl.css +0 -1
  705. codex/static_root/assets/http-error-DKulXuTl.css.br +0 -0
  706. codex/static_root/assets/http-error-DKulXuTl.css.gz +0 -0
  707. codex/static_root/assets/index-BI-1EK3Q.51e5dd220639.js +0 -1
  708. codex/static_root/assets/index-BI-1EK3Q.51e5dd220639.js.br +0 -0
  709. codex/static_root/assets/index-BI-1EK3Q.51e5dd220639.js.gz +0 -0
  710. codex/static_root/assets/index-BI-1EK3Q.js +0 -1
  711. codex/static_root/assets/index-BI-1EK3Q.js.br +0 -0
  712. codex/static_root/assets/index-BI-1EK3Q.js.gz +0 -0
  713. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css +0 -1
  714. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.br +0 -0
  715. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.gz +0 -0
  716. codex/static_root/assets/library-tab-Wew8YOLv.css +0 -1
  717. codex/static_root/assets/library-tab-Wew8YOLv.css.br +0 -0
  718. codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
  719. codex/static_root/assets/library-tab-woA1HyfN.acfc4f327913.js +0 -1
  720. codex/static_root/assets/library-tab-woA1HyfN.acfc4f327913.js.br +0 -0
  721. codex/static_root/assets/library-tab-woA1HyfN.acfc4f327913.js.gz +0 -0
  722. codex/static_root/assets/library-tab-woA1HyfN.js +0 -1
  723. codex/static_root/assets/library-tab-woA1HyfN.js.br +0 -0
  724. codex/static_root/assets/library-tab-woA1HyfN.js.gz +0 -0
  725. codex/static_root/assets/main-Ed96tESk.7777498eb960.js +0 -35
  726. codex/static_root/assets/main-Ed96tESk.7777498eb960.js.br +0 -0
  727. codex/static_root/assets/main-Ed96tESk.7777498eb960.js.gz +0 -0
  728. codex/static_root/assets/main-Ed96tESk.js +0 -35
  729. codex/static_root/assets/main-Ed96tESk.js.br +0 -0
  730. codex/static_root/assets/main-Ed96tESk.js.gz +0 -0
  731. codex/static_root/assets/pager-full-pdf-DpxPZAZR.ec23b0e50b95.js +0 -1
  732. codex/static_root/assets/pager-full-pdf-DpxPZAZR.ec23b0e50b95.js.br +0 -0
  733. codex/static_root/assets/pager-full-pdf-DpxPZAZR.ec23b0e50b95.js.gz +0 -0
  734. codex/static_root/assets/pager-full-pdf-DpxPZAZR.js +0 -1
  735. codex/static_root/assets/pager-full-pdf-DpxPZAZR.js.br +0 -0
  736. codex/static_root/assets/pager-full-pdf-DpxPZAZR.js.gz +0 -0
  737. codex/static_root/assets/pagination-toolbar-Bz5nEUwa.d01b9cf3ab5e.js +0 -1
  738. codex/static_root/assets/pagination-toolbar-Bz5nEUwa.d01b9cf3ab5e.js.br +0 -0
  739. codex/static_root/assets/pagination-toolbar-Bz5nEUwa.d01b9cf3ab5e.js.gz +0 -0
  740. codex/static_root/assets/pagination-toolbar-Bz5nEUwa.js +0 -1
  741. codex/static_root/assets/pagination-toolbar-Bz5nEUwa.js.br +0 -0
  742. codex/static_root/assets/pagination-toolbar-Bz5nEUwa.js.gz +0 -0
  743. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css +0 -1
  744. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.br +0 -0
  745. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.gz +0 -0
  746. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css +0 -1
  747. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.br +0 -0
  748. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.gz +0 -0
  749. codex/static_root/assets/pdf-doc-6j4uJzw7.59963079f1ec.js +0 -305
  750. codex/static_root/assets/pdf-doc-6j4uJzw7.59963079f1ec.js.br +0 -0
  751. codex/static_root/assets/pdf-doc-6j4uJzw7.59963079f1ec.js.gz +0 -0
  752. codex/static_root/assets/pdf-doc-6j4uJzw7.js +0 -305
  753. codex/static_root/assets/pdf-doc-6j4uJzw7.js.br +0 -0
  754. codex/static_root/assets/pdf-doc-6j4uJzw7.js.gz +0 -0
  755. codex/static_root/assets/reader-DAyPkkSs.0f54806aed4b.js +0 -2
  756. codex/static_root/assets/reader-DAyPkkSs.0f54806aed4b.js.br +0 -0
  757. codex/static_root/assets/reader-DAyPkkSs.0f54806aed4b.js.gz +0 -0
  758. codex/static_root/assets/reader-DAyPkkSs.js +0 -2
  759. codex/static_root/assets/reader-DAyPkkSs.js.br +0 -0
  760. codex/static_root/assets/reader-DAyPkkSs.js.gz +0 -0
  761. codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css +0 -1
  762. codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css.br +0 -0
  763. codex/static_root/assets/reader-nD70BeEz.06e85e73c391.css.gz +0 -0
  764. codex/static_root/assets/reader-nD70BeEz.css +0 -1
  765. codex/static_root/assets/reader-nD70BeEz.css.br +0 -0
  766. codex/static_root/assets/reader-nD70BeEz.css.gz +0 -0
  767. codex/static_root/assets/relation-chips-DUOduJmS.8b39d35f8503.js +0 -1
  768. codex/static_root/assets/relation-chips-DUOduJmS.8b39d35f8503.js.br +0 -0
  769. codex/static_root/assets/relation-chips-DUOduJmS.8b39d35f8503.js.gz +0 -0
  770. codex/static_root/assets/relation-chips-DUOduJmS.js +0 -1
  771. codex/static_root/assets/relation-chips-DUOduJmS.js.br +0 -0
  772. codex/static_root/assets/relation-chips-DUOduJmS.js.gz +0 -0
  773. codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css +0 -1
  774. codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css.br +0 -0
  775. codex/static_root/assets/settings-drawer-DKncO_vX.0a2cd24cd904.css.gz +0 -0
  776. codex/static_root/assets/settings-drawer-DKncO_vX.css +0 -1
  777. codex/static_root/assets/settings-drawer-DKncO_vX.css.br +0 -0
  778. codex/static_root/assets/settings-drawer-DKncO_vX.css.gz +0 -0
  779. codex/static_root/assets/settings-drawer-lRimDTyf.054f1f057cee.js +0 -2
  780. codex/static_root/assets/settings-drawer-lRimDTyf.054f1f057cee.js.br +0 -0
  781. codex/static_root/assets/settings-drawer-lRimDTyf.054f1f057cee.js.gz +0 -0
  782. codex/static_root/assets/settings-drawer-lRimDTyf.js +0 -2
  783. codex/static_root/assets/settings-drawer-lRimDTyf.js.br +0 -0
  784. codex/static_root/assets/settings-drawer-lRimDTyf.js.gz +0 -0
  785. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.br +0 -0
  786. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.gz +0 -0
  787. codex/static_root/assets/stats-tab-BAYTqQNg.css.br +0 -0
  788. codex/static_root/assets/stats-tab-BAYTqQNg.css.gz +0 -0
  789. codex/static_root/assets/stats-tab-Cyli0TxY.f9af7d3387d9.js +0 -1
  790. codex/static_root/assets/stats-tab-Cyli0TxY.f9af7d3387d9.js.br +0 -0
  791. codex/static_root/assets/stats-tab-Cyli0TxY.f9af7d3387d9.js.gz +0 -0
  792. codex/static_root/assets/stats-tab-Cyli0TxY.js +0 -1
  793. codex/static_root/assets/stats-tab-Cyli0TxY.js.br +0 -0
  794. codex/static_root/assets/stats-tab-Cyli0TxY.js.gz +0 -0
  795. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css +0 -1
  796. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css.gz +0 -0
  797. codex/static_root/assets/task-tab--cXi48kg.css +0 -1
  798. codex/static_root/assets/task-tab--cXi48kg.css.gz +0 -0
  799. codex/static_root/assets/task-tab-CrRRKMNo.52cc73a5889d.js +0 -1
  800. codex/static_root/assets/task-tab-CrRRKMNo.52cc73a5889d.js.br +0 -0
  801. codex/static_root/assets/task-tab-CrRRKMNo.52cc73a5889d.js.gz +0 -0
  802. codex/static_root/assets/task-tab-CrRRKMNo.js +0 -1
  803. codex/static_root/assets/task-tab-CrRRKMNo.js.br +0 -0
  804. codex/static_root/assets/task-tab-CrRRKMNo.js.gz +0 -0
  805. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css +0 -1
  806. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.br +0 -4
  807. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.gz +0 -0
  808. codex/static_root/assets/transition-5LRFTPo5.css +0 -1
  809. codex/static_root/assets/transition-5LRFTPo5.css.br +0 -4
  810. codex/static_root/assets/transition-5LRFTPo5.css.gz +0 -0
  811. codex/static_root/assets/transition-CyIqQdeu.7496bae455dc.js +0 -1
  812. codex/static_root/assets/transition-CyIqQdeu.7496bae455dc.js.br +0 -0
  813. codex/static_root/assets/transition-CyIqQdeu.7496bae455dc.js.gz +0 -0
  814. codex/static_root/assets/transition-CyIqQdeu.js +0 -1
  815. codex/static_root/assets/transition-CyIqQdeu.js.br +0 -0
  816. codex/static_root/assets/transition-CyIqQdeu.js.gz +0 -0
  817. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css +0 -1
  818. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.br +0 -0
  819. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.gz +0 -0
  820. codex/static_root/assets/unauthorized-BjhIc97q.css +0 -1
  821. codex/static_root/assets/unauthorized-BjhIc97q.css.br +0 -0
  822. codex/static_root/assets/unauthorized-BjhIc97q.css.gz +0 -0
  823. codex/static_root/assets/unauthorized-IWC3QdqX.1d5d2dafa046.js +0 -1
  824. codex/static_root/assets/unauthorized-IWC3QdqX.1d5d2dafa046.js.br +0 -0
  825. codex/static_root/assets/unauthorized-IWC3QdqX.1d5d2dafa046.js.gz +0 -0
  826. codex/static_root/assets/unauthorized-IWC3QdqX.js +0 -1
  827. codex/static_root/assets/unauthorized-IWC3QdqX.js.br +0 -0
  828. codex/static_root/assets/unauthorized-IWC3QdqX.js.gz +0 -0
  829. codex/static_root/assets/user-tab-Bt7BG8Ih.8f797a19b7ae.js +0 -1
  830. codex/static_root/assets/user-tab-Bt7BG8Ih.8f797a19b7ae.js.br +0 -0
  831. codex/static_root/assets/user-tab-Bt7BG8Ih.8f797a19b7ae.js.gz +0 -0
  832. codex/static_root/assets/user-tab-Bt7BG8Ih.js +0 -1
  833. codex/static_root/assets/user-tab-Bt7BG8Ih.js.br +0 -0
  834. codex/static_root/assets/user-tab-Bt7BG8Ih.js.gz +0 -0
  835. codex/static_root/manifest.dbf5ed7a4b40.json +0 -712
  836. codex/static_root/manifest.dbf5ed7a4b40.json.br +0 -0
  837. codex/static_root/manifest.dbf5ed7a4b40.json.gz +0 -0
  838. codex-1.7.1.dist-info/RECORD +0 -1012
  839. /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css → VCheckbox-CvH8ekHL.016ed8d222c4.css} +0 -0
  840. /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css.br → VCheckbox-CvH8ekHL.016ed8d222c4.css.br} +0 -0
  841. /codex/static_root/assets/{VCheckbox-CMKdyl0R.016ed8d222c4.css.gz → VCheckbox-CvH8ekHL.016ed8d222c4.css.gz} +0 -0
  842. /codex/static_root/assets/{VCheckbox-CMKdyl0R.css → VCheckbox-CvH8ekHL.css} +0 -0
  843. /codex/static_root/assets/{VCheckbox-CMKdyl0R.css.br → VCheckbox-CvH8ekHL.css.br} +0 -0
  844. /codex/static_root/assets/{VCheckbox-CMKdyl0R.css.gz → VCheckbox-CvH8ekHL.css.gz} +0 -0
  845. /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css → VCombobox-BQHELb_o.9f25a34994e2.css} +0 -0
  846. /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css.br → VCombobox-BQHELb_o.9f25a34994e2.css.br} +0 -0
  847. /codex/static_root/assets/{VCombobox-bwEYrXCg.9f25a34994e2.css.gz → VCombobox-BQHELb_o.9f25a34994e2.css.gz} +0 -0
  848. /codex/static_root/assets/{VCombobox-bwEYrXCg.css → VCombobox-BQHELb_o.css} +0 -0
  849. /codex/static_root/assets/{VCombobox-bwEYrXCg.css.br → VCombobox-BQHELb_o.css.br} +0 -0
  850. /codex/static_root/assets/{VCombobox-bwEYrXCg.css.gz → VCombobox-BQHELb_o.css.gz} +0 -0
  851. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css → VExpansionPanels-RsCANmDP.5b17872981df.css} +0 -0
  852. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css.br → VExpansionPanels-RsCANmDP.5b17872981df.css.br} +0 -0
  853. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.5b17872981df.css.gz → VExpansionPanels-RsCANmDP.5b17872981df.css.gz} +0 -0
  854. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css → VExpansionPanels-RsCANmDP.css} +0 -0
  855. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css.br → VExpansionPanels-RsCANmDP.css.br} +0 -0
  856. /codex/static_root/assets/{VExpansionPanels-6G1AUajL.css.gz → VExpansionPanels-RsCANmDP.css.gz} +0 -0
  857. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css → VRadioGroup-Cp9mZ7cb.8e3741381961.css} +0 -0
  858. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css.br → VRadioGroup-Cp9mZ7cb.8e3741381961.css.br} +0 -0
  859. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.8e3741381961.css.gz → VRadioGroup-Cp9mZ7cb.8e3741381961.css.gz} +0 -0
  860. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css → VRadioGroup-Cp9mZ7cb.css} +0 -0
  861. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css.br → VRadioGroup-Cp9mZ7cb.css.br} +0 -0
  862. /codex/static_root/assets/{VRadioGroup-i2qP9Wu9.css.gz → VRadioGroup-Cp9mZ7cb.css.gz} +0 -0
  863. /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css → VTable-BnxSZ_W5.c36f0a6a30cf.css} +0 -0
  864. /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css.br → VTable-BnxSZ_W5.c36f0a6a30cf.css.br} +0 -0
  865. /codex/static_root/assets/{VTable-Y5Sc3hJd.c36f0a6a30cf.css.gz → VTable-BnxSZ_W5.c36f0a6a30cf.css.gz} +0 -0
  866. /codex/static_root/assets/{VTable-Y5Sc3hJd.css → VTable-BnxSZ_W5.css} +0 -0
  867. /codex/static_root/assets/{VTable-Y5Sc3hJd.css.br → VTable-BnxSZ_W5.css.br} +0 -0
  868. /codex/static_root/assets/{VTable-Y5Sc3hJd.css.gz → VTable-BnxSZ_W5.css.gz} +0 -0
  869. /codex/static_root/assets/{VWindowItem-ByIod57Y.css → VWindowItem-CWBhiE_Y.css} +0 -0
  870. /codex/static_root/assets/{VWindowItem-ByIod57Y.css.br → VWindowItem-CWBhiE_Y.css.br} +0 -0
  871. /codex/static_root/assets/{VWindowItem-ByIod57Y.css.gz → VWindowItem-CWBhiE_Y.css.gz} +0 -0
  872. /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css → VWindowItem-CWBhiE_Y.f7fb19752bf3.css} +0 -0
  873. /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css.br → VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br} +0 -0
  874. /codex/static_root/assets/{VWindowItem-ByIod57Y.f7fb19752bf3.css.gz → VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz} +0 -0
  875. /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css → admin-menu-B3iXsOyy.c13b7df2ff57.css} +0 -0
  876. /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css.br → admin-menu-B3iXsOyy.c13b7df2ff57.css.br} +0 -0
  877. /codex/static_root/assets/{admin-menu-B9bzD6hV.c13b7df2ff57.css.gz → admin-menu-B3iXsOyy.c13b7df2ff57.css.gz} +0 -0
  878. /codex/static_root/assets/{admin-menu-B9bzD6hV.css → admin-menu-B3iXsOyy.css} +0 -0
  879. /codex/static_root/assets/{admin-menu-B9bzD6hV.css.br → admin-menu-B3iXsOyy.css.br} +0 -0
  880. /codex/static_root/assets/{admin-menu-B9bzD6hV.css.gz → admin-menu-B3iXsOyy.css.gz} +0 -0
  881. /codex/static_root/assets/{admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css → admin-settings-button-progress-BGB22oTD.2548c49a853e.css} +0 -0
  882. /codex/static_root/assets/{admin-settings-button-progress-DUUQfVsZ.css → admin-settings-button-progress-BGB22oTD.css} +0 -0
  883. /codex/static_root/assets/{datetime-column-DeCthByU.1f3bf499e063.css → datetime-column-BavtvLnf.1f3bf499e063.css} +0 -0
  884. /codex/static_root/assets/{datetime-column-DeCthByU.css → datetime-column-BavtvLnf.css} +0 -0
  885. /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css → group-tab-_vKWzoyd.948e907b1e6b.css} +0 -0
  886. /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css.br → group-tab-_vKWzoyd.948e907b1e6b.css.br} +0 -0
  887. /codex/static_root/assets/{group-tab-DkIN1Heu.948e907b1e6b.css.gz → group-tab-_vKWzoyd.948e907b1e6b.css.gz} +0 -0
  888. /codex/static_root/assets/{group-tab-DkIN1Heu.css → group-tab-_vKWzoyd.css} +0 -0
  889. /codex/static_root/assets/{group-tab-DkIN1Heu.css.br → group-tab-_vKWzoyd.css.br} +0 -0
  890. /codex/static_root/assets/{group-tab-DkIN1Heu.css.gz → group-tab-_vKWzoyd.css.gz} +0 -0
  891. /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css → index-BHXJTQ4V.523d7b3d350f.css} +0 -0
  892. /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css.br → index-BHXJTQ4V.523d7b3d350f.css.br} +0 -0
  893. /codex/static_root/assets/{index-CL_6g4tJ.523d7b3d350f.css.gz → index-BHXJTQ4V.523d7b3d350f.css.gz} +0 -0
  894. /codex/static_root/assets/{index-CL_6g4tJ.css → index-BHXJTQ4V.css} +0 -0
  895. /codex/static_root/assets/{index-CL_6g4tJ.css.br → index-BHXJTQ4V.css.br} +0 -0
  896. /codex/static_root/assets/{index-CL_6g4tJ.css.gz → index-BHXJTQ4V.css.gz} +0 -0
  897. /codex/static_root/assets/{main-BZ73p_WW.css → main-K8cER0IH.css} +0 -0
  898. /codex/static_root/assets/{main-BZ73p_WW.css.br → main-K8cER0IH.css.br} +0 -0
  899. /codex/static_root/assets/{main-BZ73p_WW.css.gz → main-K8cER0IH.css.gz} +0 -0
  900. /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css → main-K8cER0IH.d529e8b3f52a.css} +0 -0
  901. /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css.br → main-K8cER0IH.d529e8b3f52a.css.br} +0 -0
  902. /codex/static_root/assets/{main-BZ73p_WW.d529e8b3f52a.css.gz → main-K8cER0IH.d529e8b3f52a.css.gz} +0 -0
  903. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css → pdf-doc-B4cGW_Hl.b94aac7e3313.css} +0 -0
  904. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css.br → pdf-doc-B4cGW_Hl.b94aac7e3313.css.br} +0 -0
  905. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.b94aac7e3313.css.gz → pdf-doc-B4cGW_Hl.b94aac7e3313.css.gz} +0 -0
  906. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css → pdf-doc-B4cGW_Hl.css} +0 -0
  907. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css.br → pdf-doc-B4cGW_Hl.css.br} +0 -0
  908. /codex/static_root/assets/{pdf-doc-CG5-AZ2M.css.gz → pdf-doc-B4cGW_Hl.css.gz} +0 -0
  909. /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css → relation-chips-DpbzrZxT.01269a188e01.css} +0 -0
  910. /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css.br → relation-chips-DpbzrZxT.01269a188e01.css.br} +0 -0
  911. /codex/static_root/assets/{relation-chips-ByfWwuQc.01269a188e01.css.gz → relation-chips-DpbzrZxT.01269a188e01.css.gz} +0 -0
  912. /codex/static_root/assets/{relation-chips-ByfWwuQc.css → relation-chips-DpbzrZxT.css} +0 -0
  913. /codex/static_root/assets/{relation-chips-ByfWwuQc.css.br → relation-chips-DpbzrZxT.css.br} +0 -0
  914. /codex/static_root/assets/{relation-chips-ByfWwuQc.css.gz → relation-chips-DpbzrZxT.css.gz} +0 -0
  915. {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/LICENSE +0 -0
  916. {codex-1.7.1.dist-info → codex-1.7.3.dist-info}/entry_points.txt +0 -0
@@ -6,7 +6,6 @@ from django.db.models import (
6
6
  F,
7
7
  Value,
8
8
  )
9
- from django.db.models.aggregates import Count
10
9
  from django.db.models.fields import CharField
11
10
 
12
11
  from codex.logger.logging import get_logger
@@ -14,7 +13,6 @@ from codex.models.comic import Comic
14
13
  from codex.models.functions import JsonGroupArray
15
14
  from codex.models.groups import BrowserGroupModel, Imprint, Publisher, Series, Volume
16
15
  from codex.views.browser.annotate.bookmark import BrowserAnnotateBookmarkView
17
- from codex.views.const import FOLDER_GROUP
18
16
 
19
17
  _GROUP_BY: MappingProxyType[type[BrowserGroupModel], str] = MappingProxyType(
20
18
  {Publisher: "sort_name", Imprint: "sort_name", Series: "sort_name", Volume: "name"}
@@ -27,33 +25,18 @@ class BrowserAnnotateCardView(BrowserAnnotateBookmarkView):
27
25
 
28
26
  def add_group_by(self, qs):
29
27
  """Get the group by for the model."""
30
- if group_by := _GROUP_BY.get(qs.model): # type: ignore
28
+ if group_by := _GROUP_BY.get(qs.model):
31
29
  qs = qs.group_by(group_by)
32
30
  return qs
33
31
 
34
- def _annotate_child_count(self, qs):
35
- """Annotate child chount for card."""
36
- if qs.model is Comic:
37
- return qs
38
- rel = self.rel_prefix + "pk"
39
- count_func = Count(rel, distinct=True)
40
- ann = {"child_count": count_func}
41
- if self.TARGET == "opds2":
42
- if qs.model is not Comic:
43
- qs = qs.alias(**ann)
44
- else:
45
- qs = qs.annotate(**ann)
46
- return qs
47
-
48
32
  def _annotate_group(self, qs):
49
33
  """Annotate Group."""
50
- value = "c" if qs.model is Comic else self.model_group # type: ignore
34
+ value = "c" if qs.model is Comic else self.model_group
51
35
  return qs.annotate(group=Value(value, CharField(max_length=1)))
52
36
 
53
37
  def _annotate_file_name(self, qs):
54
38
  """Annotate the file name for folder view."""
55
- group = self.kwargs.get("group")
56
- if group != FOLDER_GROUP or qs.model is not Comic:
39
+ if qs.model is not Comic:
57
40
  return qs
58
41
  if self.order_key == "filename":
59
42
  file_name = F("filename")
@@ -69,7 +52,7 @@ class BrowserAnnotateCardView(BrowserAnnotateBookmarkView):
69
52
  qs = self._annotate_group(qs)
70
53
  qs = self.annotate_group_names(qs)
71
54
  qs = self._annotate_file_name(qs)
72
- qs = self._annotate_child_count(qs)
55
+ qs = self.annotate_child_count(qs)
73
56
  qs = self.annotate_bookmarks(qs)
74
57
  qs = self.annotate_progress(qs)
75
58
  return qs.annotate(updated_ats=JsonGroupArray("updated_at", distinct=True))
@@ -9,7 +9,7 @@ from django.db.models import (
9
9
  Q,
10
10
  Value,
11
11
  )
12
- from django.db.models.aggregates import Avg, Max, Min, Sum
12
+ from django.db.models.aggregates import Avg, Count, Max, Min, Sum
13
13
  from django.db.models.fields import CharField
14
14
  from django.db.models.functions import Reverse, Right, StrIndex
15
15
 
@@ -33,6 +33,7 @@ _ORDER_AGGREGATE_FUNCS = MappingProxyType(
33
33
  # These are annotated to order_value because they're simple relations
34
34
  {
35
35
  "age_rating": Avg,
36
+ "child_count": Min,
36
37
  "community_rating": Avg,
37
38
  "created_at": Min,
38
39
  "critical_rating": Avg,
@@ -45,10 +46,11 @@ _ORDER_AGGREGATE_FUNCS = MappingProxyType(
45
46
  _ANNOTATED_ORDER_FIELDS = frozenset(
46
47
  # These are annotated with their own functions
47
48
  {
49
+ "bookmark_updated_at",
50
+ "child_count",
48
51
  "filename",
49
- "sort_name",
50
52
  "search_score",
51
- "bookmark_updated_at",
53
+ "sort_name",
52
54
  "story_arc_number",
53
55
  }
54
56
  )
@@ -71,6 +73,7 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
71
73
  self._is_opds_acquisition: bool | None = None
72
74
  self._opds_acquisition_groups: frozenset[str] | None = None
73
75
  self.bmua_is_max = False
76
+ self._child_count_annotated = False
74
77
 
75
78
  @property
76
79
  def opds_acquisition_groups(self):
@@ -109,13 +112,11 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
109
112
  qs.model is StoryArc and self.order_key == "story_arc_number"
110
113
  ):
111
114
  return qs
115
+ group = self.kwargs.get("group")
112
116
  pks = self.kwargs.get("pks")
113
- show = MappingProxyType(self.params["show"]) # type: ignore
114
- # TODO too many annotations for order?
115
- # Move other annotations to card.
116
- # eager publisher for imprint of course
117
+ show = MappingProxyType(self.params["show"])
117
118
  sort_name_annotations = self.get_sort_name_annotations(
118
- qs.model, self.model_group, pks, show
119
+ qs.model, group, pks, show
119
120
  )
120
121
  if sort_name_annotations:
121
122
  qs = qs.alias(**sort_name_annotations)
@@ -130,7 +131,11 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
130
131
 
131
132
  return Right(
132
133
  path_rel,
133
- StrIndex(Reverse(F(path_rel)), Value(sep)) - 1, # type: ignore
134
+ StrIndex(
135
+ Reverse(F(path_rel)), # type: ignore[reportArgumentType]
136
+ Value(sep),
137
+ )
138
+ - 1,
134
139
  output_field=CharField(),
135
140
  )
136
141
 
@@ -155,9 +160,7 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
155
160
  if group == STORY_ARC_GROUP and pks:
156
161
  story_arc_pks = pks
157
162
  else:
158
- story_arc_pks = self.params.get("filters", {}).get( # type: ignore
159
- "story_arcs", ()
160
- )
163
+ story_arc_pks = self.params.get("filters", {}).get("story_arcs", ())
161
164
 
162
165
  # If we have one annotate it.
163
166
  if story_arc_pks:
@@ -202,6 +205,35 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
202
205
  # This is used by the serializer to compute mtime
203
206
  return qs.annotate(bmua_is_max=Value(self.bmua_is_max))
204
207
 
208
+ def _annotate_search_scores(self, qs):
209
+ """Annotate Search Scores."""
210
+ if (
211
+ self.TARGET not in self._COVER_AND_CARD_TARGETS
212
+ or self.order_key != "search_score"
213
+ ):
214
+ return qs
215
+
216
+ # Rank is always the max of the relations, cannot aggregate?
217
+ # group by here fixes duplicates with story_arc, probably because it's a long relation
218
+ return qs.annotate(search_score=ComicFTSRank()).group_by("id")
219
+
220
+ def annotate_child_count(self, qs):
221
+ """Annotate child count."""
222
+ if qs.model is Comic or self._child_count_annotated:
223
+ return qs
224
+ rel = self.rel_prefix + "pk"
225
+ count_func = Count(rel, distinct=True)
226
+ ann = {"child_count": count_func}
227
+ qs = qs.alias(**ann) if self.TARGET == "opds2" else qs.annotate(**ann)
228
+ self._child_count_annotated = True
229
+ return qs
230
+
231
+ def _annotate_order_child_count(self, qs):
232
+ """Annotate child count for order."""
233
+ if self.order_key != "child_count":
234
+ return qs
235
+ return self.annotate_child_count(qs)
236
+
205
237
  def annotate_order_value(self, qs):
206
238
  """Annotate a main key for sorting and browser card display."""
207
239
  # Determine order func
@@ -209,7 +241,12 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
209
241
  return qs
210
242
  if qs.model is Folder and self.order_key == "filename":
211
243
  order_value = F("name")
212
- elif qs.model is Comic or self.order_key in _ANNOTATED_ORDER_FIELDS:
244
+ elif qs.model is Comic:
245
+ order_key = (
246
+ "sort_name" if self.order_key == "child_count" else self.order_key
247
+ )
248
+ order_value = F(order_key)
249
+ elif self.order_key in _ANNOTATED_ORDER_FIELDS:
213
250
  # These are annotated in browser_annotaions
214
251
  order_value = F(self.order_key)
215
252
  else:
@@ -224,18 +261,6 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
224
261
  qs = qs.alias(order_value=order_value)
225
262
  return qs
226
263
 
227
- def _annotate_search_scores(self, qs):
228
- """Annotate Search Scores."""
229
- if (
230
- self.TARGET not in self._COVER_AND_CARD_TARGETS
231
- or self.order_key != "search_score"
232
- ):
233
- return qs
234
-
235
- # Rank is always the max of the relations, cannot aggregate?
236
- # group by here fixes duplicates with story_arc, probably because it's a long relation
237
- return qs.annotate(search_score=ComicFTSRank()).group_by("id")
238
-
239
264
  def annotate_order_aggregates(self, qs):
240
265
  """Annotate common aggregates between browser and metadata."""
241
266
  qs = qs.annotate(ids=JsonGroupArray("id", distinct=True))
@@ -245,6 +270,7 @@ class BrowserAnnotateOrderView(BrowserOrderByView, SharedAnnotationsMixin):
245
270
  qs = self._alias_story_arc_number(qs)
246
271
  qs = self._annotate_page_count(qs)
247
272
  qs = self._annotate_bookmark_updated_at(qs)
273
+ qs = self._annotate_order_child_count(qs)
248
274
  if qs.model is not Comic:
249
275
  # comic orders on indexed fields when it can
250
276
  qs = self.annotate_order_value(qs)
@@ -0,0 +1,53 @@
1
+ """Bookmark view."""
2
+
3
+ from drf_spectacular.utils import extend_schema
4
+ from rest_framework.response import Response
5
+
6
+ from codex.librarian.bookmark.update import BookmarkUpdate
7
+ from codex.logger.logging import get_logger
8
+ from codex.models.comic import Comic
9
+ from codex.serializers.models.bookmark import (
10
+ BookmarkFinishedSerializer,
11
+ BookmarkSerializer,
12
+ )
13
+ from codex.views.bookmark import BookmarkAuthMixin
14
+ from codex.views.browser.filters.filter import BrowserFilterView
15
+
16
+ LOG = get_logger(__name__)
17
+
18
+
19
+ class BookmarkView(BookmarkUpdate, BookmarkAuthMixin, BrowserFilterView):
20
+ """User Bookmark View."""
21
+
22
+ serializer_class = BookmarkSerializer
23
+
24
+ def _parse_params(self):
25
+ """Validate and translate the submitted data."""
26
+ group = self.kwargs.get("group")
27
+ # If the target is recursive, strip everything but finished state data.
28
+ serializer_class = None if group == "c" else BookmarkFinishedSerializer
29
+
30
+ data = self.request.data
31
+ if serializer_class:
32
+ serializer = serializer_class(data=data, partial=True)
33
+ else:
34
+ serializer = self.get_serializer(data=data, partial=True)
35
+ serializer.is_valid(raise_exception=True)
36
+ return serializer.validated_data
37
+
38
+ def _get_comic_query(self):
39
+ """Get comic pks for group."""
40
+ group = self.kwargs.get("group")
41
+ pks = self.kwargs.get("pks")
42
+ return self.get_filtered_queryset(Comic, group=group, pks=pks).only("pk")
43
+
44
+ @extend_schema(request=serializer_class, responses=None)
45
+ def patch(self, *_args, **_kwargs):
46
+ """Update bookmarks recursively."""
47
+ updates = self._parse_params()
48
+
49
+ auth_filter = self.get_bookmark_auth_filter()
50
+ comic_qs = self._get_comic_query()
51
+
52
+ self.update_bookmarks(auth_filter, comic_qs, updates, LOG)
53
+ return Response()
@@ -87,8 +87,9 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
87
87
  if not model:
88
88
  model = Publisher
89
89
  group_query = model.objects.none()
90
- self._group_instance = group_query.first()
91
- return self._group_instance # type: ignore
90
+ group_instance: BrowserGroupModel | None = group_query.first()
91
+ self._group_instance = group_instance
92
+ return self._group_instance # type: ignore[reportReturnType]
92
93
 
93
94
  def _init_breadcrumbs(self, valid_groups):
94
95
  """Load breadcrumbs and determine if they should be searched for a graft."""
@@ -103,7 +104,7 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
103
104
  """Save the breadcrumbs to params."""
104
105
  params = dict(self.params)
105
106
  params["breadcrumbs"] = tuple(crumb.dict() for crumb in breadcrumbs)
106
- # HACK rewriting params
107
+ # The only place I rewrite params
107
108
  self._params = MappingProxyType(params)
108
109
 
109
110
  def _breadcrumbs_graft_or_create_story_arc(self) -> tuple[tuple[Route, ...], bool]:
@@ -146,7 +147,7 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
146
147
 
147
148
  pks = self.kwargs["pks"]
148
149
  page = self.kwargs["page"]
149
- folder: Folder | None = self.group_instance # type: ignore
150
+ folder: Folder | None = self.group_instance # type: ignore[reportAssignmentType]
150
151
  name = folder.name if folder and pks else ""
151
152
  group_crumb = Route(FOLDER_GROUP, pks, page, name)
152
153
  new_breadcrumbs = []
@@ -230,7 +231,7 @@ class BrowserBreadcrumbsView(BrowserPaginateView):
230
231
  """Graft or create browse group breadcrumbs."""
231
232
  old_breadcrumbs, changed = self._init_breadcrumbs(GROUP_ORDER)
232
233
 
233
- vng = self.valid_nav_groups # type: ignore
234
+ vng = self.valid_nav_groups
234
235
  test_groups = tuple(reversed(vng[:-1]))
235
236
  new_breadcrumbs = []
236
237
  level = done = False
@@ -173,13 +173,13 @@ class BrowserView(BrowserTitleView):
173
173
  else:
174
174
  zero_pad = 1
175
175
 
176
- # self._debug_queries(page_group_count, page_book_count, group_qs, book_qs)
176
+ # self._debug_queries(page_group_count, page_book_count, group_qs, book_qs) # noqa: ERA001
177
177
 
178
178
  total_page_count = page_group_count + page_book_count
179
179
  mtime = self._get_page_mtime()
180
180
  return group_qs, book_qs, num_pages, total_page_count, zero_pad, mtime
181
181
 
182
- def get_object(self): # type: ignore
182
+ def get_object(self):
183
183
  """Validate settings and get the querysets."""
184
184
  group_qs, book_qs, num_pages, total_count, zero_pad, mtime = (
185
185
  self._get_group_and_books()
@@ -98,7 +98,7 @@ class BrowserChoicesViewBase(BrowserFilterView):
98
98
 
99
99
  return rel, model
100
100
 
101
- def get_object(self) -> QuerySet: # type: ignore
101
+ def get_object(self) -> QuerySet:
102
102
  """Get the comic subquery use for the choices."""
103
103
  return self.get_filtered_queryset(Comic)
104
104
 
@@ -136,12 +136,13 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
136
136
 
137
137
  return count
138
138
 
139
- def get_object(self) -> dict[str, Any]: # type: ignore
139
+ def get_object(self) -> dict[str, Any]: # type: ignore[reportIncompatibleMethodOverride]
140
140
  """Get choice counts."""
141
141
  qs = super().get_object()
142
142
  filters = self.params.get("filters", {})
143
143
  data = {}
144
- for field_name in self.serializer_class().get_fields(): # type: ignore
144
+ serializer: BrowserFilterChoicesSerializer = self.serializer_class() # type: ignore[reportOptionalCall, reportAssignmentType]
145
+ for field_name in serializer.get_fields():
145
146
  if field_name == "story_arcs" and qs.model is StoryArc:
146
147
  # don't allow filtering on story arc in story arc view.
147
148
  continue
@@ -154,7 +155,7 @@ class BrowserChoicesAvailableView(BrowserChoicesViewBase):
154
155
 
155
156
  try:
156
157
  is_filter_set = bool(filters.get(field_name))
157
- flag = is_filter_set or count > 1 # type: ignore
158
+ flag = is_filter_set or count > 1
158
159
  except TypeError:
159
160
  flag = False
160
161
  data[field_name] = flag
@@ -185,7 +186,7 @@ class BrowserChoicesView(BrowserChoicesViewBase):
185
186
  field_name = self.kwargs.get("field_name", "")
186
187
  return snakecase(field_name)
187
188
 
188
- def get_object(self) -> dict[str, Any]: # type: ignore
189
+ def get_object(self) -> dict[str, Any]: # type: ignore[reportIncompatibleMethodOverride]
189
190
  """Return choices with more than one choice."""
190
191
  qs = super().get_object()
191
192
  field_name = self._get_field_name()
@@ -52,7 +52,7 @@ class CoverView(BrowserAnnotateOrderView):
52
52
  BrowserAnnotateOrderView.REPARSE_JSON_FIELDS | {"parent"}
53
53
  )
54
54
 
55
- def get_group_filter(self, group=None, pks=None, page_mtime=False):
55
+ def get_group_filter(self, group=None, pks=None, page_mtime=False): # noqa: FBT002
56
56
  """Get group filter for First Cover View."""
57
57
  if self.params.get("dynamic_covers") or self.model in (Volume, Folder):
58
58
  return super().get_group_filter(group=group, pks=pks, page_mtime=page_mtime)
@@ -60,7 +60,10 @@ class CoverView(BrowserAnnotateOrderView):
60
60
  # First cover group filter relies on sort names to look outside the browser supplied pks
61
61
  # For multi_groups not in the browser query.
62
62
  pks = self.kwargs["pks"]
63
- qs = self.model.objects.filter(pk__in=pks) # type: ignore
63
+ if not self.model:
64
+ qs = Comic.objects.none()
65
+ else:
66
+ qs = self.model.objects.filter(pk__in=pks)
64
67
  sort_names = qs.values_list("sort_name", flat=True).distinct()
65
68
  model_rel = GROUP_RELATION[self.model_group]
66
69
  group_filter = {f"{model_rel}__sort_name__in": sort_names}
@@ -142,7 +145,7 @@ class CoverView(BrowserAnnotateOrderView):
142
145
  parameters=[BrowserAnnotateOrderView.input_serializer_class],
143
146
  responses={(200, content_type): OpenApiTypes.BINARY},
144
147
  )
145
- def get(self, *args, **kwargs): # type: ignore
148
+ def get(self, *args, **kwargs):
146
149
  """Get comic cover."""
147
150
  try:
148
151
  try:
@@ -0,0 +1,67 @@
1
+ """Download a group of comics in a zipfile."""
2
+
3
+ from django.http import HttpResponseBadRequest
4
+ from django.http.response import FileResponse, Http404
5
+ from drf_spectacular.types import OpenApiTypes
6
+ from drf_spectacular.utils import extend_schema
7
+ from zipstream import ZipStream
8
+
9
+ from codex.logger.logging import get_logger
10
+ from codex.views.browser.filters.filter import BrowserFilterView
11
+
12
+ LOG = get_logger()
13
+
14
+
15
+ class GroupDownloadView(BrowserFilterView):
16
+ """Return a group of comic archives as a streaming zipfile."""
17
+
18
+ content_type = "application/zip"
19
+ AS_ATTACHMENT = True
20
+ TARGET = "download"
21
+
22
+ def get_object(self):
23
+ """Get comic paths for a browse group."""
24
+ group = self.kwargs.get("group")
25
+ pks = self.kwargs.get("pks")
26
+ if not self.model:
27
+ reason = f"Could not find model for group {group}"
28
+ return HttpResponseBadRequest(reason)
29
+
30
+ try:
31
+ qs = self.get_filtered_queryset(self.model, group=group, pks=pks)
32
+ path_rel = self.rel_prefix + "path"
33
+ paths = qs.values_list(path_rel, flat=True)
34
+ except Exception as exc:
35
+ LOG.warning(f"Error with download query for {group}:{pks} {exc}")
36
+ raise
37
+
38
+ if not paths:
39
+ reason = f"Comics from {group}:{pks} not not found."
40
+ raise Http404(reason)
41
+
42
+ return sorted(set(paths))
43
+
44
+ @extend_schema(responses={(200, content_type): OpenApiTypes.BINARY})
45
+ def get(self, *_args, **kwargs):
46
+ """Stream a zip archive of many comics."""
47
+ paths = self.get_object()
48
+
49
+ zs = ZipStream(sized=True)
50
+ for path in paths:
51
+ zs.add_path(path)
52
+ download_file = zs
53
+
54
+ filename = kwargs.get("filename")
55
+ if not filename:
56
+ pks = self.kwargs.get("pks")
57
+ name = self.model.__name__ if self.model else "No Model"
58
+ filename = f"{name} {pks} Comics.zip"
59
+
60
+ headers = {"Content-Length": len(zs), "Last-Modified": zs.last_modified}
61
+ return FileResponse(
62
+ download_file,
63
+ as_attachment=self.AS_ATTACHMENT,
64
+ content_type=self.content_type,
65
+ filename=filename,
66
+ headers=headers,
67
+ )
@@ -1,48 +1,20 @@
1
1
  """Bookmark filter view methods."""
2
2
 
3
- from typing import TYPE_CHECKING
4
-
5
3
  from django.db.models import Q
6
4
 
5
+ from codex.views.bookmark import BookmarkFilterMixin
7
6
  from codex.views.browser.validate import BrowserValidateView
8
7
 
9
- if TYPE_CHECKING:
10
- from codex.models import BrowserGroupModel
11
-
12
8
 
13
- class BrowserFilterBookmarkView(BrowserValidateView):
9
+ class BrowserFilterBookmarkView(BookmarkFilterMixin, BrowserValidateView):
14
10
  """BookmarkFilter view methods."""
15
11
 
16
- def __init__(self, *args, **kwargs):
17
- """Initialize the bm_annotation_data."""
18
- super().__init__(*args, **kwargs)
19
- self._bm_rels: dict[BrowserGroupModel, str] = {}
20
- self._bm_filters: dict[BrowserGroupModel, Q] = {}
21
-
22
- def _get_bm_rel(self, model):
23
- """Create bookmark relation."""
24
- if model not in self._bm_rels:
25
- rel_prefix = self.get_rel_prefix(model) # type: ignore
26
- self._bm_rels[model] = rel_prefix + "bookmark"
27
- return self._bm_rels[model]
28
-
29
- def _get_my_bookmark_filter(self, bm_rel):
30
- """Get a filter for my session or user defined bookmarks."""
31
- if self.request.user and self.request.user.is_authenticated:
32
- key = f"{bm_rel}__user"
33
- value = self.request.user
34
- else:
35
- key = f"{bm_rel}__session__session_key"
36
- value = self.request.session.session_key
37
- my_bookmarks_kwargs = {key: value}
38
- return Q(**my_bookmarks_kwargs)
39
-
40
12
  def get_bookmark_filter(self, model):
41
13
  """Build bookmark query."""
42
- choice: str = self.params.get("filters", {}).get("bookmark", "") # type: ignore
14
+ choice: str = self.params.get("filters", {}).get("bookmark", "")
43
15
  if choice:
44
- bm_rel = self._get_bm_rel(model)
45
- my_bookmark_filter = self._get_my_bookmark_filter(bm_rel)
16
+ bm_rel = self.get_bm_rel(model)
17
+ my_bookmark_filter = self.get_my_bookmark_filter(bm_rel)
46
18
  if choice == "READ":
47
19
  bookmark_filter = my_bookmark_filter & Q(
48
20
  **{f"{bm_rel}__finished": True}
@@ -55,5 +55,5 @@ class ComicFieldFilterView(GroupFilterView):
55
55
  def get_comic_field_filter(self, model):
56
56
  """Filter the comics based on the form filters."""
57
57
  rel_prefix = self.get_rel_prefix(model)
58
- filters = self.params["filters"] # type: ignore
58
+ filters = self.params["filters"]
59
59
  return self.get_all_comic_field_filters(rel_prefix, filters)
@@ -13,8 +13,6 @@ LOG = get_logger(__name__)
13
13
  class BrowserFilterView(BrowserFilterBookmarkView):
14
14
  """Browser Filters."""
15
15
 
16
- TARGET = ""
17
-
18
16
  def force_inner_joins(self, qs):
19
17
  """Force INNER JOINS to filter empty groups."""
20
18
  demote_tables = {"codex_library"}
@@ -28,10 +26,10 @@ class BrowserFilterView(BrowserFilterBookmarkView):
28
26
  def _get_query_filters(
29
27
  self,
30
28
  model,
29
+ page_mtime,
30
+ bookmark_filter,
31
31
  group=None,
32
32
  pks=None,
33
- page_mtime=False,
34
- bookmark_filter=True,
35
33
  ) -> Q:
36
34
  """Return all the filters except the group filter."""
37
35
  big_include_filter = Q()
@@ -54,16 +52,16 @@ class BrowserFilterView(BrowserFilterBookmarkView):
54
52
  model,
55
53
  group=None,
56
54
  pks=None,
57
- page_mtime=False,
58
- bookmark_filter=True,
55
+ page_mtime=False, # noqa: FBT002
56
+ bookmark_filter=True, # noqa: FBT002
59
57
  ) -> QuerySet:
60
58
  """Get a filtered queryset for the model."""
61
59
  query_filters = self._get_query_filters(
62
60
  model,
63
- group=group,
64
- pks=pks,
65
61
  page_mtime=page_mtime,
66
62
  bookmark_filter=bookmark_filter,
63
+ group=group,
64
+ pks=pks,
67
65
  )
68
66
  # Distinct necissary for folder view with search
69
67
  return model.objects.filter(query_filters).distinct()
@@ -18,15 +18,18 @@ class GroupFilterView(BrowserParamsView):
18
18
 
19
19
  SESSION_KEY = BrowserParamsView.BROWSER_SESSION_KEY
20
20
 
21
- def _get_rel_for_pks(self, group, page_mtime=False):
21
+ TARGET = ""
22
+
23
+ def _get_rel_for_pks(self, group, page_mtime: bool):
22
24
  """Get the relation from the model to the pks."""
23
- # XXX these TARGET refs might be better as subclass get rel methods.
24
- target: str = self.TARGET # type: ignore
25
+ target: str = self.TARGET
25
26
  if target in _GROUP_REL_TARGETS:
26
27
  rel = FILTER_ONLY_GROUP_RELATION[group]
27
28
  elif target in _PK_REL_TARGETS or page_mtime:
28
29
  # metadata, mtime, browser.page_mtime
29
30
  rel = "pk"
31
+ elif target == "download":
32
+ rel = "comic__folders" if group == "f" else "pk"
30
33
  else:
31
34
  # browser.group, opds
32
35
  rel = GROUP_RELATION[group]
@@ -34,7 +37,7 @@ class GroupFilterView(BrowserParamsView):
34
37
  rel += "__in"
35
38
  return rel
36
39
 
37
- def get_group_filter(self, group=None, pks=None, page_mtime=False):
40
+ def get_group_filter(self, group=None, pks=None, page_mtime=False): # noqa: FBT002
38
41
  """Get filter for the displayed group."""
39
42
  if group is None:
40
43
  group = self.kwargs["group"]
@@ -79,8 +79,7 @@ def _cast_value(rel, rel_class, value):
79
79
  value = parse(value)
80
80
  if rel_class == DateField and value:
81
81
  value = value.date()
82
- # elif rel_class in (CharField, TextField):
83
- # value = value
82
+ # (CharField, TextField):
84
83
  return value
85
84
 
86
85
 
@@ -1,5 +1,5 @@
1
1
  """Optimize Text Lookups."""
2
- # XXX Unused XXX multiple like queries test better
2
+ # UNUSED CODE multiple like queries test better
3
3
 
4
4
  import re
5
5
 
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
22
22
  from pyparsing.helpers import InfixNotationOperatorSpec
23
23
 
24
24
  _QUOTES_REXP = r"(?:\".*?\")"
25
- _OPERATORS_REXP = "|".join(("and not", "or not", "and", "or"))
25
+ _OPERATORS_REXP = "and not|or not|and|or"
26
26
  _BEGIN_NOT_REXP = r"^\s*\(?\s*(?P<not>not)"
27
27
  _IMPLICIT_AND_REXP = (
28
28
  rf"{_QUOTES_REXP}|\ (?P<ok>{_OPERATORS_REXP})\ |(?P<bare>(?:\ not)?\ )\S"
@@ -183,5 +183,5 @@ def get_field_query(rel, rel_class, exp, model, many_to_many):
183
183
  bool_expr = _create_context_expression(context)
184
184
 
185
185
  parsed_result = bool_expr.parse_string(exp)
186
- root_bool_operand: BoolOperand = parsed_result[0] # type:ignore
186
+ root_bool_operand: BoolOperand = parsed_result[0] # type:ignore[reportAssignmentType]
187
187
  return root_bool_operand.to_query()