codex 1.5.17__py3-none-any.whl → 1.6.0__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 (921) hide show
  1. codex/exceptions.py +25 -12
  2. codex/integrity.py +66 -3
  3. codex/librarian/covers/coverd.py +2 -2
  4. codex/librarian/covers/create.py +52 -30
  5. codex/librarian/covers/path.py +9 -8
  6. codex/librarian/covers/purge.py +28 -18
  7. codex/librarian/covers/tasks.py +3 -2
  8. codex/librarian/importer/{aggregate_metadata.py → aggregate.py} +58 -88
  9. codex/librarian/importer/cache.py +93 -0
  10. codex/librarian/importer/const.py +77 -23
  11. codex/librarian/importer/create_comics.py +101 -18
  12. codex/librarian/importer/create_covers.py +96 -0
  13. codex/librarian/importer/create_fks.py +129 -150
  14. codex/librarian/importer/deleted.py +103 -28
  15. codex/librarian/importer/{clean_metadata.py → extract.py} +33 -4
  16. codex/librarian/importer/failed_imports.py +44 -66
  17. codex/librarian/importer/importer.py +96 -0
  18. codex/librarian/importer/importerd.py +71 -290
  19. codex/librarian/importer/init.py +265 -0
  20. codex/librarian/importer/link_comics.py +26 -26
  21. codex/librarian/importer/link_covers.py +73 -0
  22. codex/librarian/importer/moved.py +138 -89
  23. codex/librarian/importer/query_covers.py +52 -0
  24. codex/librarian/importer/query_fks.py +255 -189
  25. codex/librarian/importer/status.py +8 -39
  26. codex/librarian/importer/tasks.py +26 -9
  27. codex/librarian/janitor/cleanup.py +61 -16
  28. codex/librarian/janitor/failed_imports.py +1 -1
  29. codex/librarian/janitor/janitor.py +13 -1
  30. codex/librarian/janitor/janitord.py +1 -1
  31. codex/librarian/janitor/status.py +1 -0
  32. codex/librarian/janitor/tasks.py +5 -0
  33. codex/librarian/librariand.py +9 -5
  34. codex/librarian/notifier/notifierd.py +1 -1
  35. codex/librarian/notifier/tasks.py +4 -4
  36. codex/librarian/search/update.py +1 -1
  37. codex/librarian/watchdog/db_snapshot.py +9 -6
  38. codex/librarian/watchdog/emitter.py +3 -0
  39. codex/librarian/watchdog/event_batcherd.py +19 -3
  40. codex/librarian/watchdog/events.py +176 -36
  41. codex/librarian/watchdog/observers.py +13 -3
  42. codex/middleware.py +1 -2
  43. codex/migrations/0027_import_order_and_covers.py +280 -0
  44. codex/models/admin.py +0 -1
  45. codex/models/base.py +6 -0
  46. codex/models/comic.py +41 -44
  47. codex/models/functions.py +12 -0
  48. codex/models/groups.py +58 -12
  49. codex/models/library.py +11 -3
  50. codex/models/paths.py +65 -13
  51. codex/models/query.py +91 -0
  52. codex/models/util.py +31 -0
  53. codex/permissions.py +1 -1
  54. codex/search/backend.py +2 -2
  55. codex/search/backend_search.py +229 -0
  56. codex/search/engine.py +1 -9
  57. codex/search/query.py +67 -0
  58. codex/search/writing.py +1 -1
  59. codex/serializers/admin.py +56 -45
  60. codex/serializers/browser/choices.py +37 -42
  61. codex/serializers/browser/filters.py +32 -136
  62. codex/serializers/browser/metadata.py +59 -0
  63. codex/serializers/browser/mixins.py +65 -0
  64. codex/serializers/browser/mtime.py +21 -0
  65. codex/serializers/browser/page.py +6 -21
  66. codex/serializers/browser/settings.py +43 -11
  67. codex/serializers/choices.py +35 -12
  68. codex/serializers/fields.py +149 -0
  69. codex/serializers/mixins.py +0 -22
  70. codex/serializers/models/pycountry.py +11 -51
  71. codex/serializers/opds/urls.py +10 -0
  72. codex/serializers/opds/v2.py +10 -16
  73. codex/serializers/opds/v2_unused.py +5 -3
  74. codex/serializers/reader.py +24 -16
  75. codex/serializers/redirect.py +3 -2
  76. codex/serializers/route.py +45 -0
  77. codex/serializers/settings.py +12 -0
  78. codex/settings/settings.py +79 -32
  79. codex/signals/django_signals.py +6 -0
  80. codex/startup.py +77 -3
  81. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js +1 -0
  82. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.br +0 -0
  83. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.gz +0 -0
  84. codex/static_root/assets/VCheckbox-DanrzdHo.js +1 -0
  85. codex/static_root/assets/VCheckbox-DanrzdHo.js.br +0 -0
  86. codex/static_root/assets/VCheckbox-DanrzdHo.js.gz +0 -0
  87. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js +1 -0
  88. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.br +0 -0
  89. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.gz +0 -0
  90. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js +1 -0
  91. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.br +0 -0
  92. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.gz +0 -0
  93. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js +1 -0
  94. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.br +0 -0
  95. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.gz +0 -0
  96. codex/static_root/assets/VCombobox-DDvdoPTG.js +1 -0
  97. codex/static_root/assets/VCombobox-DDvdoPTG.js.br +0 -0
  98. codex/static_root/assets/VCombobox-DDvdoPTG.js.gz +0 -0
  99. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js +1 -0
  100. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.br +0 -0
  101. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.gz +0 -0
  102. codex/static_root/assets/VDialog-Bd5dN_E1.js +1 -0
  103. codex/static_root/assets/VDialog-Bd5dN_E1.js.br +0 -0
  104. codex/static_root/assets/VDialog-Bd5dN_E1.js.gz +0 -0
  105. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css +1 -0
  106. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
  107. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
  108. codex/static_root/assets/VDialog-lQ13FnRR.css +1 -0
  109. codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
  110. codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
  111. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js +1 -0
  112. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.br +0 -0
  113. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.gz +0 -0
  114. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js +1 -0
  115. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.br +0 -0
  116. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.gz +0 -0
  117. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js +1 -0
  118. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.br +0 -0
  119. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.gz +0 -0
  120. codex/static_root/assets/VRadioGroup-DKb8XPr-.js +1 -0
  121. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.br +0 -0
  122. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.gz +0 -0
  123. codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css +1 -0
  124. codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.br +0 -0
  125. codex/static_root/assets/VSelect-ARDhJiQK.372c098fb475.css.gz +0 -0
  126. codex/static_root/assets/VSelect-ARDhJiQK.css +1 -0
  127. codex/static_root/assets/VSelect-ARDhJiQK.css.br +0 -0
  128. codex/static_root/assets/VSelect-ARDhJiQK.css.gz +0 -0
  129. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js +1 -0
  130. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.br +0 -0
  131. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.gz +0 -0
  132. codex/static_root/assets/VSelect-C_yPbyCG.js +1 -0
  133. codex/static_root/assets/VSelect-C_yPbyCG.js.br +0 -0
  134. codex/static_root/assets/VSelect-C_yPbyCG.js.gz +0 -0
  135. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js +1 -0
  136. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.br +0 -0
  137. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.gz +0 -0
  138. codex/static_root/assets/VSelectionControl-CmFPvGMS.js +1 -0
  139. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.br +0 -0
  140. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.gz +0 -0
  141. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js +1 -0
  142. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.br +0 -0
  143. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.gz +0 -0
  144. codex/static_root/assets/VSlideGroup-D5FZWsM1.js +1 -0
  145. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.br +0 -0
  146. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.gz +0 -0
  147. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css +1 -0
  148. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.br +0 -0
  149. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.gz +0 -0
  150. codex/static_root/assets/VSlideGroup-Dk_1upHt.css +1 -0
  151. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.br +0 -0
  152. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.gz +0 -0
  153. codex/static_root/assets/{VTable-XNBBnB2q.b2784736062a.js → VTable-2RHFqfg6.f0f2106b158b.js} +1 -1
  154. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.br +0 -0
  155. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.gz +0 -0
  156. codex/static_root/assets/{VTable-XNBBnB2q.js → VTable-2RHFqfg6.js} +1 -1
  157. codex/static_root/assets/VTable-2RHFqfg6.js.br +0 -0
  158. codex/static_root/assets/VTable-2RHFqfg6.js.gz +0 -0
  159. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css +1 -0
  160. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.br +0 -0
  161. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.gz +0 -0
  162. codex/static_root/assets/VTextField-BssVoDhB.css +1 -0
  163. codex/static_root/assets/VTextField-BssVoDhB.css.br +0 -0
  164. codex/static_root/assets/VTextField-BssVoDhB.css.gz +0 -0
  165. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js +1 -0
  166. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.br +0 -0
  167. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.gz +0 -0
  168. codex/static_root/assets/VTextField-o1N9ylIb.js +1 -0
  169. codex/static_root/assets/VTextField-o1N9ylIb.js.br +0 -0
  170. codex/static_root/assets/VTextField-o1N9ylIb.js.gz +0 -0
  171. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js +1 -0
  172. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.br +0 -0
  173. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.gz +0 -0
  174. codex/static_root/assets/VWindowItem-C_zvuz9C.js +1 -0
  175. codex/static_root/assets/VWindowItem-C_zvuz9C.js.br +0 -0
  176. codex/static_root/assets/VWindowItem-C_zvuz9C.js.gz +0 -0
  177. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css +1 -0
  178. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.br +0 -0
  179. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.gz +0 -0
  180. codex/static_root/assets/admin-B8Bp2Uih.css +1 -0
  181. codex/static_root/assets/admin-B8Bp2Uih.css.br +0 -0
  182. codex/static_root/assets/admin-B8Bp2Uih.css.gz +0 -0
  183. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js +1 -0
  184. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.br +0 -0
  185. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.gz +0 -0
  186. codex/static_root/assets/admin-DHyHEWZ3.js +1 -0
  187. codex/static_root/assets/admin-DHyHEWZ3.js.br +0 -0
  188. codex/static_root/assets/admin-DHyHEWZ3.js.gz +0 -0
  189. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js +30 -0
  190. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.br +0 -0
  191. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.gz +0 -0
  192. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js +30 -0
  193. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.br +0 -0
  194. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.gz +0 -0
  195. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css +1 -0
  196. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
  197. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
  198. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css +1 -0
  199. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
  200. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
  201. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js +1 -0
  202. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.br +0 -0
  203. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.gz +0 -0
  204. codex/static_root/assets/browser-D0Vjmmp_.js +1 -0
  205. codex/static_root/assets/browser-D0Vjmmp_.js.br +0 -0
  206. codex/static_root/assets/browser-D0Vjmmp_.js.gz +0 -0
  207. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css +1 -0
  208. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.br +0 -0
  209. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.gz +0 -0
  210. codex/static_root/assets/browser-D7QQDneO.css +1 -0
  211. codex/static_root/assets/browser-D7QQDneO.css.br +0 -0
  212. codex/static_root/assets/browser-D7QQDneO.css.gz +0 -0
  213. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +1 -0
  214. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
  215. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
  216. codex/static_root/assets/change-password-dialog-0u6IJA87.css +1 -0
  217. codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
  218. codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
  219. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js +1 -0
  220. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.br +0 -0
  221. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.gz +0 -0
  222. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js +1 -0
  223. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.br +0 -0
  224. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.gz +0 -0
  225. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js +1 -0
  226. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.br +0 -0
  227. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.gz +0 -0
  228. codex/static_root/assets/confirm-dialog-DCKvg3ai.js +1 -0
  229. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.br +0 -0
  230. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.gz +0 -0
  231. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +1 -0
  232. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
  233. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +1 -0
  234. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
  235. codex/static_root/assets/datetime-column-DeCthByU.1f3bf499e063.css +1 -0
  236. codex/static_root/assets/datetime-column-DeCthByU.css +1 -0
  237. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js +1 -0
  238. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.br +0 -0
  239. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.gz +0 -0
  240. codex/static_root/assets/datetime-column-jHKA_uNm.js +1 -0
  241. codex/static_root/assets/datetime-column-jHKA_uNm.js.br +0 -0
  242. codex/static_root/assets/datetime-column-jHKA_uNm.js.gz +0 -0
  243. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js +1 -0
  244. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.br +0 -0
  245. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.gz +0 -0
  246. codex/static_root/assets/filter-DgPg2ts9.js +1 -0
  247. codex/static_root/assets/filter-DgPg2ts9.js.br +0 -0
  248. codex/static_root/assets/filter-DgPg2ts9.js.gz +0 -0
  249. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js +1 -0
  250. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.br +0 -0
  251. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.gz +0 -0
  252. codex/static_root/assets/flag-tab-9qxOALxP.js +1 -0
  253. codex/static_root/assets/flag-tab-9qxOALxP.js.br +0 -0
  254. codex/static_root/assets/flag-tab-9qxOALxP.js.gz +0 -0
  255. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +1 -0
  256. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
  257. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
  258. codex/static_root/assets/flag-tab-BNwbLfrN.css +1 -0
  259. codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
  260. codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
  261. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css +1 -0
  262. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.br +0 -0
  263. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.gz +0 -0
  264. codex/static_root/assets/group-tab-CBKuS3Iv.css +1 -0
  265. codex/static_root/assets/group-tab-CBKuS3Iv.css.br +0 -0
  266. codex/static_root/assets/group-tab-CBKuS3Iv.css.gz +0 -0
  267. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js +1 -0
  268. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.br +0 -0
  269. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.gz +0 -0
  270. codex/static_root/assets/group-tab-D5vWrihT.js +1 -0
  271. codex/static_root/assets/group-tab-D5vWrihT.js.br +0 -0
  272. codex/static_root/assets/group-tab-D5vWrihT.js.gz +0 -0
  273. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js +1 -0
  274. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.br +0 -0
  275. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.gz +0 -0
  276. codex/static_root/assets/http-error-B4FHoKfs.js +1 -0
  277. codex/static_root/assets/http-error-B4FHoKfs.js.br +0 -0
  278. codex/static_root/assets/http-error-B4FHoKfs.js.gz +0 -0
  279. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css +1 -0
  280. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.br +0 -0
  281. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.gz +0 -0
  282. codex/static_root/assets/http-error-DKulXuTl.css +1 -0
  283. codex/static_root/assets/http-error-DKulXuTl.css.br +0 -0
  284. codex/static_root/assets/http-error-DKulXuTl.css.gz +0 -0
  285. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css +1 -0
  286. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.br +0 -0
  287. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.gz +0 -0
  288. codex/static_root/assets/library-tab-BN0SfPcH.css +1 -0
  289. codex/static_root/assets/library-tab-BN0SfPcH.css.br +0 -0
  290. codex/static_root/assets/library-tab-BN0SfPcH.css.gz +0 -0
  291. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js +1 -0
  292. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.br +0 -0
  293. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.gz +0 -0
  294. codex/static_root/assets/library-tab-BWo0cmzk.js +1 -0
  295. codex/static_root/assets/library-tab-BWo0cmzk.js.br +0 -0
  296. codex/static_root/assets/library-tab-BWo0cmzk.js.gz +0 -0
  297. codex/static_root/assets/{main-ClKzvaJK.css → main-Ztp855PW.css} +1 -1
  298. codex/static_root/assets/main-Ztp855PW.css.br +0 -0
  299. codex/static_root/assets/{main-ClKzvaJK.css.gz → main-Ztp855PW.css.gz} +0 -0
  300. codex/static_root/assets/{main-ClKzvaJK.04ea1888c6b4.css → main-Ztp855PW.d46d718fac45.css} +1 -1
  301. codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
  302. codex/static_root/assets/{main-ClKzvaJK.04ea1888c6b4.css.gz → main-Ztp855PW.d46d718fac45.css.gz} +0 -0
  303. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js +32 -0
  304. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.br +0 -0
  305. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.gz +0 -0
  306. codex/static_root/assets/main-ipmlipkF.js +32 -0
  307. codex/static_root/assets/main-ipmlipkF.js.br +0 -0
  308. codex/static_root/assets/main-ipmlipkF.js.gz +0 -0
  309. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css +1 -0
  310. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.br +0 -0
  311. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.gz +0 -0
  312. codex/static_root/assets/pagination-toolbar-BA9ifTed.css +1 -0
  313. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.br +0 -0
  314. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.gz +0 -0
  315. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js +1 -0
  316. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.br +0 -0
  317. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.gz +0 -0
  318. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js +1 -0
  319. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.br +0 -0
  320. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.gz +0 -0
  321. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js +305 -0
  322. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.br +0 -0
  323. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.gz +0 -0
  324. codex/static_root/assets/pdf-doc-C2StaYUz.js +305 -0
  325. codex/static_root/assets/pdf-doc-C2StaYUz.js.br +0 -0
  326. codex/static_root/assets/pdf-doc-C2StaYUz.js.gz +0 -0
  327. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js +2 -0
  328. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.br +0 -0
  329. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.gz +0 -0
  330. codex/static_root/assets/reader-CCnq3j1-.js +2 -0
  331. codex/static_root/assets/reader-CCnq3j1-.js.br +0 -0
  332. codex/static_root/assets/reader-CCnq3j1-.js.gz +0 -0
  333. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css +1 -0
  334. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.br +0 -0
  335. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.gz +0 -0
  336. codex/static_root/assets/reader-CqXFa_gE.css +1 -0
  337. codex/static_root/assets/reader-CqXFa_gE.css.br +0 -0
  338. codex/static_root/assets/reader-CqXFa_gE.css.gz +0 -0
  339. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css +1 -0
  340. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.br +0 -0
  341. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.gz +0 -0
  342. codex/static_root/assets/relation-chips-Bsc-gUxE.css +1 -0
  343. codex/static_root/assets/relation-chips-Bsc-gUxE.css.br +0 -0
  344. codex/static_root/assets/relation-chips-Bsc-gUxE.css.gz +0 -0
  345. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js +1 -0
  346. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.br +0 -0
  347. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.gz +0 -0
  348. codex/static_root/assets/relation-chips-C9ysW0tU.js +1 -0
  349. codex/static_root/assets/relation-chips-C9ysW0tU.js.br +0 -0
  350. codex/static_root/assets/relation-chips-C9ysW0tU.js.gz +0 -0
  351. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js +2 -0
  352. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.br +0 -0
  353. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.gz +0 -0
  354. codex/static_root/assets/settings-drawer-C0ofzAhW.js +2 -0
  355. codex/static_root/assets/settings-drawer-C0ofzAhW.js.br +0 -0
  356. codex/static_root/assets/settings-drawer-C0ofzAhW.js.gz +0 -0
  357. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css +1 -0
  358. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.br +0 -0
  359. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.gz +0 -0
  360. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css +1 -0
  361. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.br +0 -0
  362. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.gz +0 -0
  363. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +1 -0
  364. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  365. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  366. codex/static_root/assets/stats-tab-B4yKuY0c.css +1 -0
  367. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  368. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  369. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js +1 -0
  370. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.br +0 -0
  371. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.gz +0 -0
  372. codex/static_root/assets/stats-tab-BqJj7j1w.js +1 -0
  373. codex/static_root/assets/stats-tab-BqJj7j1w.js.br +0 -0
  374. codex/static_root/assets/stats-tab-BqJj7j1w.js.gz +0 -0
  375. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css +1 -0
  376. codex/static_root/assets/{task-tab-DoX9OA37.9bb355f36dbf.css.br → task-tab-1XiWn9xP.06cb8e1b794d.css.br} +1 -1
  377. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css.gz +0 -0
  378. codex/static_root/assets/task-tab-1XiWn9xP.css +1 -0
  379. codex/static_root/assets/{task-tab-DoX9OA37.css.br → task-tab-1XiWn9xP.css.br} +1 -1
  380. codex/static_root/assets/task-tab-1XiWn9xP.css.gz +0 -0
  381. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js +1 -0
  382. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.br +0 -0
  383. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.gz +0 -0
  384. codex/static_root/assets/task-tab-BsPzNk8S.js +1 -0
  385. codex/static_root/assets/task-tab-BsPzNk8S.js.br +0 -0
  386. codex/static_root/assets/task-tab-BsPzNk8S.js.gz +0 -0
  387. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js +1 -0
  388. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js.br +0 -0
  389. codex/static_root/assets/to-case-KvqtSug2.js +1 -0
  390. codex/static_root/assets/to-case-KvqtSug2.js.br +0 -0
  391. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css +1 -0
  392. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
  393. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
  394. codex/static_root/assets/unauthorized-CibJYD8o.css +1 -0
  395. codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
  396. codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
  397. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js +1 -0
  398. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.br +0 -0
  399. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.gz +0 -0
  400. codex/static_root/assets/unauthorized-DwSdNzX2.js +1 -0
  401. codex/static_root/assets/unauthorized-DwSdNzX2.js.br +0 -0
  402. codex/static_root/assets/unauthorized-DwSdNzX2.js.gz +0 -0
  403. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js +1 -0
  404. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.br +0 -0
  405. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.gz +0 -0
  406. codex/static_root/assets/user-tab-DrJOb9Ys.js +1 -0
  407. codex/static_root/assets/user-tab-DrJOb9Ys.js.br +0 -0
  408. codex/static_root/assets/user-tab-DrJOb9Ys.js.gz +0 -0
  409. codex/static_root/img/folder.f28936a3701d.svg +1 -0
  410. codex/static_root/img/folder.f28936a3701d.svg.br +0 -0
  411. codex/static_root/img/folder.f28936a3701d.svg.gz +0 -0
  412. codex/static_root/img/folder.svg +1 -0
  413. codex/static_root/img/folder.svg.br +0 -0
  414. codex/static_root/img/folder.svg.gz +0 -0
  415. codex/static_root/img/imprint.7c2adebb76d6.svg +1 -0
  416. codex/static_root/img/imprint.7c2adebb76d6.svg.br +0 -0
  417. codex/static_root/img/imprint.7c2adebb76d6.svg.gz +0 -0
  418. codex/static_root/img/imprint.svg +1 -0
  419. codex/static_root/img/imprint.svg.br +0 -0
  420. codex/static_root/img/imprint.svg.gz +0 -0
  421. codex/static_root/img/logo-32.5688944495bf.webp +0 -0
  422. codex/static_root/img/logo-32.webp +0 -0
  423. codex/static_root/img/logo-maskable-180.c58d966aa64e.webp +0 -0
  424. codex/static_root/img/logo-maskable-180.webp +0 -0
  425. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg +1 -0
  426. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.br +0 -0
  427. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.gz +0 -0
  428. codex/static_root/img/logo-maskable.svg +1 -83
  429. codex/static_root/img/logo-maskable.svg.br +0 -0
  430. codex/static_root/img/logo-maskable.svg.gz +0 -0
  431. codex/static_root/img/logo.0f5344a028ca.svg +1 -0
  432. codex/static_root/img/logo.0f5344a028ca.svg.br +0 -0
  433. codex/static_root/img/logo.0f5344a028ca.svg.gz +0 -0
  434. codex/static_root/img/logo.svg +1 -80
  435. codex/static_root/img/logo.svg.br +0 -0
  436. codex/static_root/img/logo.svg.gz +0 -0
  437. codex/static_root/img/missing-cover-165.0743171f2148.webp +0 -0
  438. codex/static_root/img/missing-cover-165.webp +0 -0
  439. codex/static_root/img/missing-cover.ddb038cc2c56.svg +1 -0
  440. codex/static_root/img/missing-cover.ddb038cc2c56.svg.br +0 -0
  441. codex/static_root/img/missing-cover.ddb038cc2c56.svg.gz +0 -0
  442. codex/static_root/img/missing-cover.svg +1 -0
  443. codex/static_root/img/missing-cover.svg.br +0 -0
  444. codex/static_root/img/missing-cover.svg.gz +0 -0
  445. codex/static_root/img/publisher.82d378fcd601.svg +1 -0
  446. codex/static_root/img/publisher.82d378fcd601.svg.br +0 -0
  447. codex/static_root/img/publisher.82d378fcd601.svg.gz +0 -0
  448. codex/static_root/img/publisher.svg +1 -0
  449. codex/static_root/img/publisher.svg.br +0 -0
  450. codex/static_root/img/publisher.svg.gz +0 -0
  451. codex/static_root/img/series.ec8a889b8f95.svg +1 -0
  452. codex/static_root/img/series.ec8a889b8f95.svg.br +0 -0
  453. codex/static_root/img/series.ec8a889b8f95.svg.gz +0 -0
  454. codex/static_root/img/series.svg +1 -0
  455. codex/static_root/img/series.svg.br +0 -0
  456. codex/static_root/img/series.svg.gz +0 -0
  457. codex/static_root/img/story-arc.ca10014355ef.svg +1 -0
  458. codex/static_root/img/story-arc.ca10014355ef.svg.br +1 -0
  459. codex/static_root/img/story-arc.ca10014355ef.svg.gz +0 -0
  460. codex/static_root/img/story-arc.svg +1 -0
  461. codex/static_root/img/story-arc.svg.br +1 -0
  462. codex/static_root/img/story-arc.svg.gz +0 -0
  463. codex/static_root/img/volume.814e4c79461a.svg +1 -0
  464. codex/static_root/img/volume.814e4c79461a.svg.br +0 -0
  465. codex/static_root/img/volume.814e4c79461a.svg.gz +0 -0
  466. codex/static_root/img/volume.svg +1 -0
  467. codex/static_root/img/volume.svg.br +0 -0
  468. codex/static_root/img/volume.svg.gz +0 -0
  469. codex/static_root/js/choices-admin.3521e2a863df.json +1 -0
  470. codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
  471. codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
  472. codex/static_root/js/choices-admin.json +1 -1
  473. codex/static_root/js/choices-admin.json.br +0 -0
  474. codex/static_root/js/choices-admin.json.gz +0 -0
  475. codex/static_root/js/choices.2f6b0359e1ef.json +1 -0
  476. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  477. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  478. codex/static_root/js/choices.json +1 -1
  479. codex/static_root/js/choices.json.br +0 -0
  480. codex/static_root/js/choices.json.gz +0 -0
  481. codex/static_root/manifest.1c84116d9a0a.json +622 -0
  482. codex/static_root/manifest.1c84116d9a0a.json.br +0 -0
  483. codex/static_root/manifest.1c84116d9a0a.json.gz +0 -0
  484. codex/static_root/manifest.json +342 -327
  485. codex/static_root/manifest.json.br +0 -0
  486. codex/static_root/manifest.json.gz +0 -0
  487. codex/static_root/staticfiles.json +1 -1
  488. codex/status_controller.py +11 -2
  489. codex/templates/headers-script-globals.html +1 -4
  490. codex/urls/api/admin.py +5 -7
  491. codex/urls/api/auth.py +2 -1
  492. codex/urls/api/browser.py +18 -9
  493. codex/urls/api/reader.py +5 -11
  494. codex/urls/api/v3.py +4 -0
  495. codex/urls/app.py +8 -3
  496. codex/urls/converters.py +39 -0
  497. codex/urls/opds/binary.py +1 -1
  498. codex/urls/opds/root.py +3 -4
  499. codex/urls/opds/v1.py +1 -1
  500. codex/urls/opds/v2.py +6 -1
  501. codex/urls/root.py +2 -1
  502. codex/util.py +12 -0
  503. codex/views/admin/api_key.py +7 -8
  504. codex/views/admin/auth.py +28 -0
  505. codex/views/admin/flag.py +2 -7
  506. codex/views/admin/group.py +2 -6
  507. codex/views/admin/library.py +44 -37
  508. codex/views/admin/stats.py +20 -83
  509. codex/views/admin/tasks.py +26 -12
  510. codex/views/admin/user.py +3 -14
  511. codex/views/auth.py +39 -64
  512. codex/views/bookmark.py +93 -72
  513. codex/views/browser/annotations.py +293 -0
  514. codex/views/browser/base.py +101 -87
  515. codex/views/browser/breadcrumbs.py +202 -0
  516. codex/views/browser/browser.py +165 -518
  517. codex/views/browser/choices.py +67 -120
  518. codex/views/browser/cover.py +165 -0
  519. codex/views/browser/filters/annotations.py +102 -0
  520. codex/views/browser/filters/bookmark.py +24 -12
  521. codex/views/browser/filters/field.py +8 -6
  522. codex/views/browser/filters/group.py +38 -16
  523. codex/views/browser/filters/search.py +169 -25
  524. codex/views/browser/metadata.py +169 -136
  525. codex/views/browser/mtime.py +61 -0
  526. codex/views/browser/order_by.py +65 -0
  527. codex/views/browser/paginate.py +106 -0
  528. codex/views/browser/settings.py +66 -0
  529. codex/views/browser/title.py +48 -0
  530. codex/views/browser/validate.py +161 -0
  531. codex/views/const.py +157 -0
  532. codex/views/download.py +8 -20
  533. codex/views/error.py +2 -2
  534. codex/views/frontend.py +8 -3
  535. codex/views/mixins.py +76 -0
  536. codex/views/opds/auth.py +17 -0
  537. codex/views/opds/authentication_v1.py +46 -45
  538. codex/views/opds/binary.py +5 -10
  539. codex/views/opds/const.py +13 -0
  540. codex/views/opds/urls.py +30 -0
  541. codex/views/opds/util.py +11 -19
  542. codex/views/opds/v1/entry/data.py +2 -2
  543. codex/views/opds/v1/entry/entry.py +5 -5
  544. codex/views/opds/v1/entry/links.py +68 -58
  545. codex/views/opds/v1/facets.py +11 -11
  546. codex/views/opds/v1/feed.py +84 -63
  547. codex/views/opds/v1/links.py +21 -19
  548. codex/views/opds/v1/opensearch_v1.py +5 -6
  549. codex/views/opds/v2/feed.py +69 -53
  550. codex/views/opds/v2/links.py +4 -2
  551. codex/views/opds/v2/publications.py +50 -68
  552. codex/views/opds/v2/top_links.py +4 -4
  553. codex/views/public.py +36 -0
  554. codex/views/reader/arcs.py +92 -0
  555. codex/views/reader/books.py +181 -0
  556. codex/views/reader/init.py +125 -0
  557. codex/views/reader/page.py +16 -5
  558. codex/views/reader/reader.py +22 -236
  559. codex/views/reader/{session.py → settings.py} +4 -2
  560. codex/views/session.py +92 -102
  561. codex/views/settings.py +47 -0
  562. codex/views/template.py +3 -3
  563. codex/views/util.py +77 -0
  564. codex/views/version.py +2 -2
  565. codex/websockets/consumers.py +14 -10
  566. {codex-1.5.17.dist-info → codex-1.6.0.dist-info}/METADATA +36 -18
  567. codex-1.6.0.dist-info/RECORD +1013 -0
  568. codex/db_functions.py +0 -25
  569. codex/img/missing-cover.webp +0 -0
  570. codex/librarian/importer/update_comics.py +0 -90
  571. codex/serializers/metadata.py +0 -15
  572. codex/static_root/assets/VCheckbox-CFqm2IhY.60c7775eda9e.js +0 -1
  573. codex/static_root/assets/VCheckbox-CFqm2IhY.60c7775eda9e.js.br +0 -0
  574. codex/static_root/assets/VCheckbox-CFqm2IhY.60c7775eda9e.js.gz +0 -0
  575. codex/static_root/assets/VCheckbox-CFqm2IhY.js +0 -1
  576. codex/static_root/assets/VCheckbox-CFqm2IhY.js.br +0 -0
  577. codex/static_root/assets/VCheckbox-CFqm2IhY.js.gz +0 -0
  578. codex/static_root/assets/VCheckboxBtn-BjWW08N8.bee4c9c1c3b4.js +0 -1
  579. codex/static_root/assets/VCheckboxBtn-BjWW08N8.bee4c9c1c3b4.js.br +0 -0
  580. codex/static_root/assets/VCheckboxBtn-BjWW08N8.bee4c9c1c3b4.js.gz +0 -0
  581. codex/static_root/assets/VCheckboxBtn-BjWW08N8.js +0 -1
  582. codex/static_root/assets/VCheckboxBtn-BjWW08N8.js.br +0 -0
  583. codex/static_root/assets/VCheckboxBtn-BjWW08N8.js.gz +0 -0
  584. codex/static_root/assets/VCombobox-BiHR4LaF.7487536b173b.js +0 -1
  585. codex/static_root/assets/VCombobox-BiHR4LaF.7487536b173b.js.br +0 -0
  586. codex/static_root/assets/VCombobox-BiHR4LaF.7487536b173b.js.gz +0 -0
  587. codex/static_root/assets/VCombobox-BiHR4LaF.js +0 -1
  588. codex/static_root/assets/VCombobox-BiHR4LaF.js.br +0 -0
  589. codex/static_root/assets/VCombobox-BiHR4LaF.js.gz +0 -0
  590. codex/static_root/assets/VDataTableVirtual--XFLD9jr.ecfcb691279b.js +0 -1
  591. codex/static_root/assets/VDataTableVirtual--XFLD9jr.ecfcb691279b.js.br +0 -0
  592. codex/static_root/assets/VDataTableVirtual--XFLD9jr.ecfcb691279b.js.gz +0 -0
  593. codex/static_root/assets/VDataTableVirtual--XFLD9jr.js +0 -1
  594. codex/static_root/assets/VDataTableVirtual--XFLD9jr.js.br +0 -0
  595. codex/static_root/assets/VDataTableVirtual--XFLD9jr.js.gz +0 -0
  596. codex/static_root/assets/VDataTableVirtual-CSBxS0yr.825a0ca38f9d.css +0 -1
  597. codex/static_root/assets/VDataTableVirtual-CSBxS0yr.825a0ca38f9d.css.br +0 -0
  598. codex/static_root/assets/VDataTableVirtual-CSBxS0yr.825a0ca38f9d.css.gz +0 -0
  599. codex/static_root/assets/VDataTableVirtual-CSBxS0yr.css +0 -1
  600. codex/static_root/assets/VDataTableVirtual-CSBxS0yr.css.br +0 -0
  601. codex/static_root/assets/VDataTableVirtual-CSBxS0yr.css.gz +0 -0
  602. codex/static_root/assets/VExpansionPanel-CSSnZFhG.bb54c6635f82.js +0 -1
  603. codex/static_root/assets/VExpansionPanel-CSSnZFhG.bb54c6635f82.js.br +0 -0
  604. codex/static_root/assets/VExpansionPanel-CSSnZFhG.bb54c6635f82.js.gz +0 -0
  605. codex/static_root/assets/VExpansionPanel-CSSnZFhG.js +0 -1
  606. codex/static_root/assets/VExpansionPanel-CSSnZFhG.js.br +0 -0
  607. codex/static_root/assets/VExpansionPanel-CSSnZFhG.js.gz +0 -0
  608. codex/static_root/assets/VMain-BJLquw4_.0d36762696df.js +0 -1
  609. codex/static_root/assets/VMain-BJLquw4_.0d36762696df.js.br +0 -0
  610. codex/static_root/assets/VMain-BJLquw4_.0d36762696df.js.gz +0 -0
  611. codex/static_root/assets/VMain-BJLquw4_.js +0 -1
  612. codex/static_root/assets/VMain-BJLquw4_.js.br +0 -0
  613. codex/static_root/assets/VMain-BJLquw4_.js.gz +0 -0
  614. codex/static_root/assets/VMain-Byt37V4c.a00e206f3cfa.css +0 -1
  615. codex/static_root/assets/VMain-Byt37V4c.a00e206f3cfa.css.br +0 -0
  616. codex/static_root/assets/VMain-Byt37V4c.a00e206f3cfa.css.gz +0 -0
  617. codex/static_root/assets/VMain-Byt37V4c.css +0 -1
  618. codex/static_root/assets/VMain-Byt37V4c.css.br +0 -0
  619. codex/static_root/assets/VMain-Byt37V4c.css.gz +0 -0
  620. codex/static_root/assets/VRadioGroup-BrO5lLMK.60b07cdd1b52.js +0 -1
  621. codex/static_root/assets/VRadioGroup-BrO5lLMK.60b07cdd1b52.js.br +0 -0
  622. codex/static_root/assets/VRadioGroup-BrO5lLMK.60b07cdd1b52.js.gz +0 -0
  623. codex/static_root/assets/VRadioGroup-BrO5lLMK.js +0 -1
  624. codex/static_root/assets/VRadioGroup-BrO5lLMK.js.br +0 -0
  625. codex/static_root/assets/VRadioGroup-BrO5lLMK.js.gz +0 -0
  626. codex/static_root/assets/VSelect-BdGop3V2.604c1785fbff.css +0 -1
  627. codex/static_root/assets/VSelect-BdGop3V2.604c1785fbff.css.br +0 -0
  628. codex/static_root/assets/VSelect-BdGop3V2.604c1785fbff.css.gz +0 -0
  629. codex/static_root/assets/VSelect-BdGop3V2.css +0 -1
  630. codex/static_root/assets/VSelect-BdGop3V2.css.br +0 -0
  631. codex/static_root/assets/VSelect-BdGop3V2.css.gz +0 -0
  632. codex/static_root/assets/VSelect-CAEbdtAK.6d93a3800567.js +0 -1
  633. codex/static_root/assets/VSelect-CAEbdtAK.6d93a3800567.js.br +0 -0
  634. codex/static_root/assets/VSelect-CAEbdtAK.6d93a3800567.js.gz +0 -0
  635. codex/static_root/assets/VSelect-CAEbdtAK.js +0 -1
  636. codex/static_root/assets/VSelect-CAEbdtAK.js.br +0 -0
  637. codex/static_root/assets/VSelect-CAEbdtAK.js.gz +0 -0
  638. codex/static_root/assets/VSelectionControl-BoyRbIct.7cfcfa9ae20b.js +0 -1
  639. codex/static_root/assets/VSelectionControl-BoyRbIct.7cfcfa9ae20b.js.br +0 -0
  640. codex/static_root/assets/VSelectionControl-BoyRbIct.7cfcfa9ae20b.js.gz +0 -0
  641. codex/static_root/assets/VSelectionControl-BoyRbIct.js +0 -1
  642. codex/static_root/assets/VSelectionControl-BoyRbIct.js.br +0 -0
  643. codex/static_root/assets/VSelectionControl-BoyRbIct.js.gz +0 -0
  644. codex/static_root/assets/VSlideGroup-C3lY91uv.css +0 -1
  645. codex/static_root/assets/VSlideGroup-C3lY91uv.css.br +0 -0
  646. codex/static_root/assets/VSlideGroup-C3lY91uv.css.gz +0 -0
  647. codex/static_root/assets/VSlideGroup-C3lY91uv.d268067bd078.css +0 -1
  648. codex/static_root/assets/VSlideGroup-C3lY91uv.d268067bd078.css.br +0 -0
  649. codex/static_root/assets/VSlideGroup-C3lY91uv.d268067bd078.css.gz +0 -0
  650. codex/static_root/assets/VSlideGroup-IIebYuJm.d50fd68270e6.js +0 -1
  651. codex/static_root/assets/VSlideGroup-IIebYuJm.d50fd68270e6.js.br +0 -0
  652. codex/static_root/assets/VSlideGroup-IIebYuJm.d50fd68270e6.js.gz +0 -0
  653. codex/static_root/assets/VSlideGroup-IIebYuJm.js +0 -1
  654. codex/static_root/assets/VSlideGroup-IIebYuJm.js.br +0 -0
  655. codex/static_root/assets/VSlideGroup-IIebYuJm.js.gz +0 -0
  656. codex/static_root/assets/VTable-XNBBnB2q.b2784736062a.js.br +0 -0
  657. codex/static_root/assets/VTable-XNBBnB2q.b2784736062a.js.gz +0 -0
  658. codex/static_root/assets/VTable-XNBBnB2q.js.br +0 -0
  659. codex/static_root/assets/VTable-XNBBnB2q.js.gz +0 -0
  660. codex/static_root/assets/VToolbar-CLYsoOKq.acca0b6c0684.js +0 -2
  661. codex/static_root/assets/VToolbar-CLYsoOKq.acca0b6c0684.js.br +0 -0
  662. codex/static_root/assets/VToolbar-CLYsoOKq.acca0b6c0684.js.gz +0 -0
  663. codex/static_root/assets/VToolbar-CLYsoOKq.js +0 -2
  664. codex/static_root/assets/VToolbar-CLYsoOKq.js.br +0 -0
  665. codex/static_root/assets/VToolbar-CLYsoOKq.js.gz +0 -0
  666. codex/static_root/assets/VToolbar-DqQLg1UA.614d6a4a8a09.css +0 -1
  667. codex/static_root/assets/VToolbar-DqQLg1UA.614d6a4a8a09.css.br +0 -0
  668. codex/static_root/assets/VToolbar-DqQLg1UA.614d6a4a8a09.css.gz +0 -0
  669. codex/static_root/assets/VToolbar-DqQLg1UA.css +0 -1
  670. codex/static_root/assets/VToolbar-DqQLg1UA.css.br +0 -0
  671. codex/static_root/assets/VToolbar-DqQLg1UA.css.gz +0 -0
  672. codex/static_root/assets/VWindowItem-CPevuSn_.27817d5bd8e4.js +0 -1
  673. codex/static_root/assets/VWindowItem-CPevuSn_.27817d5bd8e4.js.br +0 -0
  674. codex/static_root/assets/VWindowItem-CPevuSn_.27817d5bd8e4.js.gz +0 -0
  675. codex/static_root/assets/VWindowItem-CPevuSn_.js +0 -1
  676. codex/static_root/assets/VWindowItem-CPevuSn_.js.br +0 -0
  677. codex/static_root/assets/VWindowItem-CPevuSn_.js.gz +0 -0
  678. codex/static_root/assets/admin-CzWbM7Nl.95cf937f31ff.js +0 -1
  679. codex/static_root/assets/admin-CzWbM7Nl.95cf937f31ff.js.br +0 -0
  680. codex/static_root/assets/admin-CzWbM7Nl.95cf937f31ff.js.gz +0 -0
  681. codex/static_root/assets/admin-CzWbM7Nl.js +0 -1
  682. codex/static_root/assets/admin-CzWbM7Nl.js.br +0 -0
  683. codex/static_root/assets/admin-CzWbM7Nl.js.gz +0 -0
  684. codex/static_root/assets/admin-Df82-Qcj.4c3f0406ee54.css +0 -1
  685. codex/static_root/assets/admin-Df82-Qcj.4c3f0406ee54.css.br +0 -0
  686. codex/static_root/assets/admin-Df82-Qcj.4c3f0406ee54.css.gz +0 -0
  687. codex/static_root/assets/admin-Df82-Qcj.css +0 -1
  688. codex/static_root/assets/admin-Df82-Qcj.css.br +0 -0
  689. codex/static_root/assets/admin-Df82-Qcj.css.gz +0 -0
  690. codex/static_root/assets/admin-drawer-panel-B4-04ET4.ff74b52952d0.js +0 -30
  691. codex/static_root/assets/admin-drawer-panel-B4-04ET4.ff74b52952d0.js.br +0 -0
  692. codex/static_root/assets/admin-drawer-panel-B4-04ET4.ff74b52952d0.js.gz +0 -0
  693. codex/static_root/assets/admin-drawer-panel-B4-04ET4.js +0 -30
  694. codex/static_root/assets/admin-drawer-panel-B4-04ET4.js.br +0 -0
  695. codex/static_root/assets/admin-drawer-panel-B4-04ET4.js.gz +0 -0
  696. codex/static_root/assets/admin-drawer-panel-Cr-0BCQv.b519336cb005.css +0 -1
  697. codex/static_root/assets/admin-drawer-panel-Cr-0BCQv.b519336cb005.css.br +0 -0
  698. codex/static_root/assets/admin-drawer-panel-Cr-0BCQv.b519336cb005.css.gz +0 -0
  699. codex/static_root/assets/admin-drawer-panel-Cr-0BCQv.css +0 -1
  700. codex/static_root/assets/admin-drawer-panel-Cr-0BCQv.css.br +0 -0
  701. codex/static_root/assets/admin-drawer-panel-Cr-0BCQv.css.gz +0 -0
  702. codex/static_root/assets/browser-BldK4CGS.ce8c71552de0.js +0 -1
  703. codex/static_root/assets/browser-BldK4CGS.ce8c71552de0.js.br +0 -0
  704. codex/static_root/assets/browser-BldK4CGS.ce8c71552de0.js.gz +0 -0
  705. codex/static_root/assets/browser-BldK4CGS.js +0 -1
  706. codex/static_root/assets/browser-BldK4CGS.js.br +0 -0
  707. codex/static_root/assets/browser-BldK4CGS.js.gz +0 -0
  708. codex/static_root/assets/browser-HtKThxA9.69be059a55f4.css +0 -1
  709. codex/static_root/assets/browser-HtKThxA9.69be059a55f4.css.br +0 -0
  710. codex/static_root/assets/browser-HtKThxA9.69be059a55f4.css.gz +0 -0
  711. codex/static_root/assets/browser-HtKThxA9.css +0 -1
  712. codex/static_root/assets/browser-HtKThxA9.css.br +0 -0
  713. codex/static_root/assets/browser-HtKThxA9.css.gz +0 -0
  714. codex/static_root/assets/change-password-dialog-BRmvkNir.2fead58a78c7.css +0 -1
  715. codex/static_root/assets/change-password-dialog-BRmvkNir.2fead58a78c7.css.br +0 -0
  716. codex/static_root/assets/change-password-dialog-BRmvkNir.2fead58a78c7.css.gz +0 -0
  717. codex/static_root/assets/change-password-dialog-BRmvkNir.css +0 -1
  718. codex/static_root/assets/change-password-dialog-BRmvkNir.css.br +0 -0
  719. codex/static_root/assets/change-password-dialog-BRmvkNir.css.gz +0 -0
  720. codex/static_root/assets/change-password-dialog-DAvSz_BT.89752c597186.js +0 -1
  721. codex/static_root/assets/change-password-dialog-DAvSz_BT.89752c597186.js.br +0 -0
  722. codex/static_root/assets/change-password-dialog-DAvSz_BT.89752c597186.js.gz +0 -0
  723. codex/static_root/assets/change-password-dialog-DAvSz_BT.js +0 -1
  724. codex/static_root/assets/change-password-dialog-DAvSz_BT.js.br +0 -0
  725. codex/static_root/assets/change-password-dialog-DAvSz_BT.js.gz +0 -0
  726. codex/static_root/assets/confirm-dialog-0mqMQack.a2b39e1d65f7.js +0 -1
  727. codex/static_root/assets/confirm-dialog-0mqMQack.a2b39e1d65f7.js.br +0 -0
  728. codex/static_root/assets/confirm-dialog-0mqMQack.a2b39e1d65f7.js.gz +0 -0
  729. codex/static_root/assets/confirm-dialog-0mqMQack.js +0 -1
  730. codex/static_root/assets/confirm-dialog-0mqMQack.js.br +0 -0
  731. codex/static_root/assets/confirm-dialog-0mqMQack.js.gz +0 -0
  732. codex/static_root/assets/confirm-footer-VFepxcJs.4150131304bd.css +0 -1
  733. codex/static_root/assets/confirm-footer-VFepxcJs.4150131304bd.css.br +0 -0
  734. codex/static_root/assets/confirm-footer-VFepxcJs.4150131304bd.css.gz +0 -0
  735. codex/static_root/assets/confirm-footer-VFepxcJs.css +0 -1
  736. codex/static_root/assets/confirm-footer-VFepxcJs.css.br +0 -0
  737. codex/static_root/assets/confirm-footer-VFepxcJs.css.gz +0 -0
  738. codex/static_root/assets/confirm-footer-oTUv06_v.99f172061491.js +0 -1
  739. codex/static_root/assets/confirm-footer-oTUv06_v.99f172061491.js.br +0 -0
  740. codex/static_root/assets/confirm-footer-oTUv06_v.99f172061491.js.gz +0 -0
  741. codex/static_root/assets/confirm-footer-oTUv06_v.js +0 -1
  742. codex/static_root/assets/confirm-footer-oTUv06_v.js.br +0 -0
  743. codex/static_root/assets/confirm-footer-oTUv06_v.js.gz +0 -0
  744. codex/static_root/assets/datetime-column-BWWfvyhn.a4a94ba57c73.css +0 -1
  745. codex/static_root/assets/datetime-column-BWWfvyhn.a4a94ba57c73.css.br +0 -0
  746. codex/static_root/assets/datetime-column-BWWfvyhn.css +0 -1
  747. codex/static_root/assets/datetime-column-BWWfvyhn.css.br +0 -0
  748. codex/static_root/assets/datetime-column-D3I95kw3.26791f31ac02.js +0 -1
  749. codex/static_root/assets/datetime-column-D3I95kw3.26791f31ac02.js.br +0 -0
  750. codex/static_root/assets/datetime-column-D3I95kw3.26791f31ac02.js.gz +0 -0
  751. codex/static_root/assets/datetime-column-D3I95kw3.js +0 -1
  752. codex/static_root/assets/datetime-column-D3I95kw3.js.br +0 -0
  753. codex/static_root/assets/datetime-column-D3I95kw3.js.gz +0 -0
  754. codex/static_root/assets/filter-D95Y3XYa.b69f5d543997.js +0 -1
  755. codex/static_root/assets/filter-D95Y3XYa.b69f5d543997.js.br +0 -0
  756. codex/static_root/assets/filter-D95Y3XYa.b69f5d543997.js.gz +0 -0
  757. codex/static_root/assets/filter-D95Y3XYa.js +0 -1
  758. codex/static_root/assets/filter-D95Y3XYa.js.br +0 -0
  759. codex/static_root/assets/filter-D95Y3XYa.js.gz +0 -0
  760. codex/static_root/assets/flag-tab-C9vu256Y.bd43f22c727b.js +0 -1
  761. codex/static_root/assets/flag-tab-C9vu256Y.bd43f22c727b.js.br +0 -0
  762. codex/static_root/assets/flag-tab-C9vu256Y.bd43f22c727b.js.gz +0 -0
  763. codex/static_root/assets/flag-tab-C9vu256Y.js +0 -1
  764. codex/static_root/assets/flag-tab-C9vu256Y.js.br +0 -0
  765. codex/static_root/assets/flag-tab-C9vu256Y.js.gz +0 -0
  766. codex/static_root/assets/flag-tab-D_HjkAta.203bedf35ce7.css +0 -1
  767. codex/static_root/assets/flag-tab-D_HjkAta.203bedf35ce7.css.br +0 -0
  768. codex/static_root/assets/flag-tab-D_HjkAta.203bedf35ce7.css.gz +0 -0
  769. codex/static_root/assets/flag-tab-D_HjkAta.css +0 -1
  770. codex/static_root/assets/flag-tab-D_HjkAta.css.br +0 -0
  771. codex/static_root/assets/flag-tab-D_HjkAta.css.gz +0 -0
  772. codex/static_root/assets/group-tab-DKqBg4yc.22ea16c1e331.js +0 -1
  773. codex/static_root/assets/group-tab-DKqBg4yc.22ea16c1e331.js.br +0 -0
  774. codex/static_root/assets/group-tab-DKqBg4yc.22ea16c1e331.js.gz +0 -0
  775. codex/static_root/assets/group-tab-DKqBg4yc.js +0 -1
  776. codex/static_root/assets/group-tab-DKqBg4yc.js.br +0 -0
  777. codex/static_root/assets/group-tab-DKqBg4yc.js.gz +0 -0
  778. codex/static_root/assets/group-tab-GFacGljN.98df9e04f2a7.css +0 -1
  779. codex/static_root/assets/group-tab-GFacGljN.98df9e04f2a7.css.br +0 -0
  780. codex/static_root/assets/group-tab-GFacGljN.98df9e04f2a7.css.gz +0 -0
  781. codex/static_root/assets/group-tab-GFacGljN.css +0 -1
  782. codex/static_root/assets/group-tab-GFacGljN.css.br +0 -0
  783. codex/static_root/assets/group-tab-GFacGljN.css.gz +0 -0
  784. codex/static_root/assets/http-error-C25WdjWC.1c7337ad6e1d.css +0 -1
  785. codex/static_root/assets/http-error-C25WdjWC.1c7337ad6e1d.css.br +0 -0
  786. codex/static_root/assets/http-error-C25WdjWC.1c7337ad6e1d.css.gz +0 -0
  787. codex/static_root/assets/http-error-C25WdjWC.css +0 -1
  788. codex/static_root/assets/http-error-C25WdjWC.css.br +0 -0
  789. codex/static_root/assets/http-error-C25WdjWC.css.gz +0 -0
  790. codex/static_root/assets/http-error-F_AIFiVP.1d3b95f22256.js +0 -1
  791. codex/static_root/assets/http-error-F_AIFiVP.1d3b95f22256.js.br +0 -0
  792. codex/static_root/assets/http-error-F_AIFiVP.1d3b95f22256.js.gz +0 -0
  793. codex/static_root/assets/http-error-F_AIFiVP.js +0 -1
  794. codex/static_root/assets/http-error-F_AIFiVP.js.br +0 -0
  795. codex/static_root/assets/http-error-F_AIFiVP.js.gz +0 -0
  796. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +0 -1
  797. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
  798. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
  799. codex/static_root/assets/index-DUjeNg4x.js +0 -1
  800. codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
  801. codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
  802. codex/static_root/assets/library-tab-CKYjhIWV.a1119d2cb417.js +0 -1
  803. codex/static_root/assets/library-tab-CKYjhIWV.a1119d2cb417.js.br +0 -0
  804. codex/static_root/assets/library-tab-CKYjhIWV.a1119d2cb417.js.gz +0 -0
  805. codex/static_root/assets/library-tab-CKYjhIWV.js +0 -1
  806. codex/static_root/assets/library-tab-CKYjhIWV.js.br +0 -0
  807. codex/static_root/assets/library-tab-CKYjhIWV.js.gz +0 -0
  808. codex/static_root/assets/library-tab-DZKDtQ5v.c8123e4bc5a4.css +0 -1
  809. codex/static_root/assets/library-tab-DZKDtQ5v.c8123e4bc5a4.css.br +0 -3
  810. codex/static_root/assets/library-tab-DZKDtQ5v.c8123e4bc5a4.css.gz +0 -0
  811. codex/static_root/assets/library-tab-DZKDtQ5v.css +0 -1
  812. codex/static_root/assets/library-tab-DZKDtQ5v.css.br +0 -3
  813. codex/static_root/assets/library-tab-DZKDtQ5v.css.gz +0 -0
  814. codex/static_root/assets/main-BJxn-WA7.a04c671bd796.js +0 -32
  815. codex/static_root/assets/main-BJxn-WA7.a04c671bd796.js.br +0 -0
  816. codex/static_root/assets/main-BJxn-WA7.a04c671bd796.js.gz +0 -0
  817. codex/static_root/assets/main-BJxn-WA7.js +0 -32
  818. codex/static_root/assets/main-BJxn-WA7.js.br +0 -0
  819. codex/static_root/assets/main-BJxn-WA7.js.gz +0 -0
  820. codex/static_root/assets/main-ClKzvaJK.04ea1888c6b4.css.br +0 -0
  821. codex/static_root/assets/main-ClKzvaJK.css.br +0 -0
  822. codex/static_root/assets/metadata-dialog-DNdhw8Y2.21df0d7eff56.js +0 -1
  823. codex/static_root/assets/metadata-dialog-DNdhw8Y2.21df0d7eff56.js.br +0 -0
  824. codex/static_root/assets/metadata-dialog-DNdhw8Y2.21df0d7eff56.js.gz +0 -0
  825. codex/static_root/assets/metadata-dialog-DNdhw8Y2.js +0 -1
  826. codex/static_root/assets/metadata-dialog-DNdhw8Y2.js.br +0 -0
  827. codex/static_root/assets/metadata-dialog-DNdhw8Y2.js.gz +0 -0
  828. codex/static_root/assets/metadata-dialog-DqTRiI3h.ac34b1bcab82.css +0 -1
  829. codex/static_root/assets/metadata-dialog-DqTRiI3h.ac34b1bcab82.css.br +0 -0
  830. codex/static_root/assets/metadata-dialog-DqTRiI3h.ac34b1bcab82.css.gz +0 -0
  831. codex/static_root/assets/metadata-dialog-DqTRiI3h.css +0 -1
  832. codex/static_root/assets/metadata-dialog-DqTRiI3h.css.br +0 -0
  833. codex/static_root/assets/metadata-dialog-DqTRiI3h.css.gz +0 -0
  834. codex/static_root/assets/pdf-doc-DQV6XqAo.38b6ebeec5bc.js +0 -35
  835. codex/static_root/assets/pdf-doc-DQV6XqAo.38b6ebeec5bc.js.br +0 -0
  836. codex/static_root/assets/pdf-doc-DQV6XqAo.38b6ebeec5bc.js.gz +0 -0
  837. codex/static_root/assets/pdf-doc-DQV6XqAo.js +0 -35
  838. codex/static_root/assets/pdf-doc-DQV6XqAo.js.br +0 -0
  839. codex/static_root/assets/pdf-doc-DQV6XqAo.js.gz +0 -0
  840. codex/static_root/assets/reader-BuAYRwBN.3f834951f509.js +0 -2
  841. codex/static_root/assets/reader-BuAYRwBN.3f834951f509.js.br +0 -0
  842. codex/static_root/assets/reader-BuAYRwBN.3f834951f509.js.gz +0 -0
  843. codex/static_root/assets/reader-BuAYRwBN.js +0 -2
  844. codex/static_root/assets/reader-BuAYRwBN.js.br +0 -0
  845. codex/static_root/assets/reader-BuAYRwBN.js.gz +0 -0
  846. codex/static_root/assets/reader-CG6zrLXl.css +0 -1
  847. codex/static_root/assets/reader-CG6zrLXl.css.br +0 -0
  848. codex/static_root/assets/reader-CG6zrLXl.css.gz +0 -0
  849. codex/static_root/assets/reader-CG6zrLXl.ed017042cd53.css +0 -1
  850. codex/static_root/assets/reader-CG6zrLXl.ed017042cd53.css.br +0 -0
  851. codex/static_root/assets/reader-CG6zrLXl.ed017042cd53.css.gz +0 -0
  852. codex/static_root/assets/stats-tab-BTZLMBCU.7e0a9547c12e.css +0 -1
  853. codex/static_root/assets/stats-tab-BTZLMBCU.7e0a9547c12e.css.br +0 -0
  854. codex/static_root/assets/stats-tab-BTZLMBCU.7e0a9547c12e.css.gz +0 -0
  855. codex/static_root/assets/stats-tab-BTZLMBCU.css +0 -1
  856. codex/static_root/assets/stats-tab-BTZLMBCU.css.br +0 -0
  857. codex/static_root/assets/stats-tab-BTZLMBCU.css.gz +0 -0
  858. codex/static_root/assets/stats-tab-wzOFMrgw.ffc62bf814ce.js +0 -1
  859. codex/static_root/assets/stats-tab-wzOFMrgw.ffc62bf814ce.js.br +0 -0
  860. codex/static_root/assets/stats-tab-wzOFMrgw.ffc62bf814ce.js.gz +0 -0
  861. codex/static_root/assets/stats-tab-wzOFMrgw.js +0 -1
  862. codex/static_root/assets/stats-tab-wzOFMrgw.js.br +0 -0
  863. codex/static_root/assets/stats-tab-wzOFMrgw.js.gz +0 -0
  864. codex/static_root/assets/task-tab-DoX9OA37.9bb355f36dbf.css +0 -1
  865. codex/static_root/assets/task-tab-DoX9OA37.9bb355f36dbf.css.gz +0 -0
  866. codex/static_root/assets/task-tab-DoX9OA37.css +0 -1
  867. codex/static_root/assets/task-tab-DoX9OA37.css.gz +0 -0
  868. codex/static_root/assets/task-tab-UYMTSKl-.c37096a07f51.js +0 -1
  869. codex/static_root/assets/task-tab-UYMTSKl-.c37096a07f51.js.br +0 -0
  870. codex/static_root/assets/task-tab-UYMTSKl-.c37096a07f51.js.gz +0 -0
  871. codex/static_root/assets/task-tab-UYMTSKl-.js +0 -1
  872. codex/static_root/assets/task-tab-UYMTSKl-.js.br +0 -0
  873. codex/static_root/assets/task-tab-UYMTSKl-.js.gz +0 -0
  874. codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +0 -1
  875. codex/static_root/assets/to-case-kUm8NPpW.js +0 -1
  876. codex/static_root/assets/user-tab-ByP2OwxN.255023553b2e.js +0 -1
  877. codex/static_root/assets/user-tab-ByP2OwxN.255023553b2e.js.br +0 -0
  878. codex/static_root/assets/user-tab-ByP2OwxN.255023553b2e.js.gz +0 -0
  879. codex/static_root/assets/user-tab-ByP2OwxN.js +0 -1
  880. codex/static_root/assets/user-tab-ByP2OwxN.js.br +0 -0
  881. codex/static_root/assets/user-tab-ByP2OwxN.js.gz +0 -0
  882. codex/static_root/img/logo-32.dbb98f6dfde4.webp +0 -0
  883. codex/static_root/img/logo-maskable-180.201cbde62d55.webp +0 -0
  884. codex/static_root/img/logo-maskable.d618c2d7943f.svg +0 -83
  885. codex/static_root/img/logo-maskable.d618c2d7943f.svg.br +0 -0
  886. codex/static_root/img/logo-maskable.d618c2d7943f.svg.gz +0 -0
  887. codex/static_root/img/logo.3fb129bfbd92.svg +0 -80
  888. codex/static_root/img/logo.3fb129bfbd92.svg.br +0 -0
  889. codex/static_root/img/logo.3fb129bfbd92.svg.gz +0 -0
  890. codex/static_root/img/missing-cover.8c8c1d4f6782.webp +0 -0
  891. codex/static_root/img/missing-cover.webp +0 -0
  892. codex/static_root/img/missing-page.71bb10f7c72a.svg +0 -13
  893. codex/static_root/img/missing-page.71bb10f7c72a.svg.br +0 -0
  894. codex/static_root/img/missing-page.71bb10f7c72a.svg.gz +0 -0
  895. codex/static_root/img/missing-page.svg +0 -13
  896. codex/static_root/img/missing-page.svg.br +0 -0
  897. codex/static_root/img/missing-page.svg.gz +0 -0
  898. codex/static_root/js/choices-admin.bb730e4f26ac.json +0 -1
  899. codex/static_root/js/choices-admin.bb730e4f26ac.json.br +0 -0
  900. codex/static_root/js/choices-admin.bb730e4f26ac.json.gz +0 -0
  901. codex/static_root/js/choices.fedcbd1ec085.json +0 -1
  902. codex/static_root/js/choices.fedcbd1ec085.json.br +0 -0
  903. codex/static_root/js/choices.fedcbd1ec085.json.gz +0 -0
  904. codex/static_root/manifest.d2fc837c9c53.json +0 -607
  905. codex/static_root/manifest.d2fc837c9c53.json.br +0 -0
  906. codex/static_root/manifest.d2fc837c9c53.json.gz +0 -0
  907. codex/views/browser/browser_annotations.py +0 -298
  908. codex/views/browser/browser_order_by.py +0 -108
  909. codex/views/browser/const.py +0 -3
  910. codex/views/browser/session.py +0 -12
  911. codex/views/cover.py +0 -59
  912. codex-1.5.17.dist-info/RECORD +0 -936
  913. /codex/static_root/assets/{VExpansionPanel-DsEXVcCv.20b475255e66.css → VExpansionPanels-DsEXVcCv.20b475255e66.css} +0 -0
  914. /codex/static_root/assets/{VExpansionPanel-DsEXVcCv.20b475255e66.css.br → VExpansionPanels-DsEXVcCv.20b475255e66.css.br} +0 -0
  915. /codex/static_root/assets/{VExpansionPanel-DsEXVcCv.20b475255e66.css.gz → VExpansionPanels-DsEXVcCv.20b475255e66.css.gz} +0 -0
  916. /codex/static_root/assets/{VExpansionPanel-DsEXVcCv.css → VExpansionPanels-DsEXVcCv.css} +0 -0
  917. /codex/static_root/assets/{VExpansionPanel-DsEXVcCv.css.br → VExpansionPanels-DsEXVcCv.css.br} +0 -0
  918. /codex/static_root/assets/{VExpansionPanel-DsEXVcCv.css.gz → VExpansionPanels-DsEXVcCv.css.gz} +0 -0
  919. {codex-1.5.17.dist-info → codex-1.6.0.dist-info}/LICENSE +0 -0
  920. {codex-1.5.17.dist-info → codex-1.6.0.dist-info}/WHEEL +0 -0
  921. {codex-1.5.17.dist-info → codex-1.6.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,106 @@
1
+ """Browser pagination."""
2
+
3
+ from math import ceil
4
+
5
+ from django.core.paginator import EmptyPage, Paginator
6
+
7
+ from codex.logger.logging import get_logger
8
+ from codex.models import (
9
+ Comic,
10
+ Folder,
11
+ )
12
+ from codex.views.browser.annotations import BrowserAnnotationsView
13
+ from codex.views.const import (
14
+ MAX_OBJ_PER_PAGE,
15
+ )
16
+
17
+ LOG = get_logger(__name__)
18
+
19
+
20
+ class BrowserPaginateView(BrowserAnnotationsView):
21
+ """Browser pagination."""
22
+
23
+ def _check_page_in_bounds(self, total_count):
24
+ """Redirect page out of bounds."""
25
+ pks = self.kwargs.get("pks")
26
+ page = self.kwargs.get("page", 1)
27
+ num_pages = ceil(total_count / MAX_OBJ_PER_PAGE)
28
+ if (not pks and page == 1) or (page >= 1 and page <= num_pages):
29
+ # Don't redirect if on the root page for the group.
30
+ # Or page within valid range.
31
+ return num_pages
32
+
33
+ # Adjust route mask for redirect
34
+ group = self.kwargs.get("group")
35
+ if num_pages and page > 1:
36
+ # Try page 1 first.
37
+ new_page = num_pages if num_pages and page > num_pages else 1
38
+ pks = pks if pks else "0"
39
+ else:
40
+ # Redirect to root for the group.
41
+ pks = "0"
42
+ new_page = 1
43
+
44
+ reason = f"{page=} does not exist!"
45
+ route_changes = {"group": group, "pks": pks, "page": new_page}
46
+ return self.raise_redirect(reason, route_mask=route_changes)
47
+
48
+ def _paginate_section(self, model, qs, page):
49
+ """Paginate a group or Comic section."""
50
+ orphans = 0 if self.model_group == "f" or self.params.get("q") else 5
51
+ paginator = Paginator(qs, MAX_OBJ_PER_PAGE, orphans=orphans)
52
+ try:
53
+ qs = paginator.page(page).object_list
54
+ except EmptyPage:
55
+ if model != Folder:
56
+ model_name = self.model.__name__ if self.model else "NO_MODEL"
57
+ LOG.warning(f"No {model_name}s on page {page}")
58
+ qs = model.objects.none()
59
+
60
+ return qs
61
+
62
+ def _paginate_groups(self, group_qs, total_group_count):
63
+ """Paginate the group object list before books."""
64
+ if total_group_count:
65
+ page = self.kwargs.get("page", 1)
66
+ page_group_qs = self._paginate_section(self.model, group_qs, page)
67
+ else:
68
+ page_group_qs = self.model.objects.none() # type: ignore
69
+ return page_group_qs
70
+
71
+ def _paginate_books(self, book_qs, total_group_count, page_obj_count):
72
+ """Paginate the book object list based on how many group/folders are showing."""
73
+ if page_obj_count >= MAX_OBJ_PER_PAGE:
74
+ # No books for this page
75
+ page_book_qs = Comic.objects.none()
76
+ else:
77
+ group_remainder = total_group_count % MAX_OBJ_PER_PAGE
78
+ if page_obj_count:
79
+ # There are books after the groups on the same page
80
+ # Manually add books without the paginator
81
+ book_limit = MAX_OBJ_PER_PAGE - group_remainder
82
+ page_book_qs = book_qs[:book_limit]
83
+ else:
84
+ # There are books after the groups on a new page
85
+ if group_remainder:
86
+ book_offset = MAX_OBJ_PER_PAGE - group_remainder
87
+ page_book_qs = book_qs[book_offset:]
88
+ else:
89
+ page_book_qs = book_qs
90
+
91
+ num_group_and_mixed_pages = ceil(total_group_count / MAX_OBJ_PER_PAGE)
92
+ book_only_page = self.kwargs.get("page", 1) - num_group_and_mixed_pages
93
+ page_book_qs = self._paginate_section(
94
+ Comic, page_book_qs, book_only_page
95
+ )
96
+ return page_book_qs
97
+
98
+ def paginate(self, group_qs, book_qs, group_count, book_count):
99
+ """Paginate the queryset into a group and book object lists."""
100
+ num_pages = self._check_page_in_bounds(group_count + book_count)
101
+ page_group_qs = self._paginate_groups(group_qs, group_count)
102
+ page_group_count = page_group_qs.count()
103
+ page_book_qs = self._paginate_books(book_qs, group_count, page_group_count)
104
+ page_book_count = page_book_qs.count()
105
+
106
+ return page_group_qs, page_book_qs, num_pages, page_group_count, page_book_count
@@ -0,0 +1,66 @@
1
+ """Browser session view."""
2
+
3
+ from codex.serializers.browser.settings import BrowserSettingsSerializer
4
+ from codex.views.const import GROUP_ORDER
5
+ from codex.views.settings import SettingsView
6
+
7
+
8
+ class BrowserSettingsView(SettingsView):
9
+ """Get Browser Settings."""
10
+
11
+ # Put Browser Settings is normally done through BrowserView.get()
12
+ serializer_class = BrowserSettingsSerializer # type: ignore
13
+
14
+ SESSION_KEY = SettingsView.BROWSER_SESSION_KEY
15
+
16
+ @staticmethod
17
+ def _strip_breadcrumb_names(params):
18
+ """Remove names from breadcrumbs."""
19
+ breadcrumbs = params.get("breadcrumbs")
20
+ if not breadcrumbs:
21
+ return params
22
+ nameless_breadcrumbs = []
23
+ for crumb in breadcrumbs:
24
+ crumb.pop("name", None)
25
+ nameless_breadcrumbs.append(crumb)
26
+ params["breadcrumbs"] = nameless_breadcrumbs
27
+ return params
28
+
29
+ @staticmethod
30
+ def _validate_browse_top_group(params, group, top_group):
31
+ """Validate top group for browse groups."""
32
+ show = params["show"]
33
+ if group == "r" or (
34
+ show.get(top_group)
35
+ and GROUP_ORDER.index(top_group) < GROUP_ORDER.index(group)
36
+ ):
37
+ return
38
+
39
+ for show_group, on in show.items():
40
+ if on:
41
+ params["top_group"] = show_group
42
+ break
43
+ else:
44
+ params["top_group"] = "c"
45
+
46
+ @classmethod
47
+ def _validate_top_group(cls, params, group, top_group):
48
+ """Validate top group."""
49
+ if group == top_group:
50
+ return
51
+
52
+ if group in ("f", "a"):
53
+ params["top_group"] = group
54
+ else:
55
+ cls._validate_browse_top_group(params, group, top_group)
56
+
57
+ def validate_settings_get(self, validated_data, params):
58
+ """Change bad settings."""
59
+ top_group = params["top_group"]
60
+ group = validated_data.get("group", "r") if validated_data else "r"
61
+ self._validate_top_group(params, group, top_group)
62
+
63
+ if not validated_data.get("breadcrumb_names", True):
64
+ params = self._strip_breadcrumb_names(params)
65
+
66
+ return params
@@ -0,0 +1,48 @@
1
+ """Browser title."""
2
+
3
+ from codex.models import BrowserGroupModel, Comic, Volume
4
+ from codex.views.browser.breadcrumbs import BrowserBreadcrumbsView
5
+
6
+
7
+ class BrowserTitleView(BrowserBreadcrumbsView):
8
+ """Browser title methods."""
9
+
10
+ def __init__(self, *args, **kwargs):
11
+ """Set params for the type checker."""
12
+ super().__init__(*args, **kwargs)
13
+ self.group_instance: BrowserGroupModel | None = None
14
+
15
+ def _get_root_group_name(self):
16
+ if not self.model:
17
+ reason = "No model set in browser"
18
+ raise ValueError(reason)
19
+ plural = self.model._meta.verbose_name_plural
20
+ if not plural:
21
+ reason = f"No plural name for {self.model}"
22
+ raise ValueError(reason)
23
+ return plural.capitalize(), 0
24
+
25
+ def _get_group_name(self):
26
+ group_count = 0
27
+ if gi := self.group_instance:
28
+ if isinstance(gi, Volume):
29
+ group_count = gi.series.volume_count
30
+ elif isinstance(gi, Comic):
31
+ group_count = gi.volume.issue_count
32
+ group_name = gi.name
33
+ else:
34
+ group_name = ""
35
+ return group_name, group_count
36
+
37
+ def get_browser_page_title(self):
38
+ """Get the proper title for this browse level."""
39
+ pks = self.kwargs.get("pks")
40
+ if not pks:
41
+ group_name, group_count = self._get_root_group_name()
42
+ else:
43
+ group_name, group_count = self._get_group_name()
44
+
45
+ return {
46
+ "group_name": group_name,
47
+ "group_count": group_count,
48
+ }
@@ -0,0 +1,161 @@
1
+ """Browser Settings and URL Validation."""
2
+
3
+ from copy import deepcopy
4
+ from types import MappingProxyType
5
+
6
+ from codex.exceptions import SeeOtherRedirectError
7
+ from codex.logger.logging import get_logger
8
+ from codex.serializers.choices import DEFAULTS
9
+ from codex.views.browser.base import BrowserBaseView
10
+ from codex.views.const import (
11
+ COMIC_GROUP,
12
+ FOLDER_GROUP,
13
+ ROOT_GROUP,
14
+ STORY_ARC_GROUP,
15
+ )
16
+
17
+ LOG = get_logger(__name__)
18
+ _NO_TOP_GROUP_VALIDATE = frozenset({"metadata"})
19
+
20
+
21
+ class BrowserValidateView(BrowserBaseView):
22
+ """Browser Settings and URL Validation."""
23
+
24
+ DEFAULT_ROUTE = MappingProxyType(
25
+ {
26
+ "name": "browser",
27
+ "params": deepcopy(DEFAULTS["breadcrumbs"][0]),
28
+ }
29
+ )
30
+
31
+ def raise_redirect(self, reason, route_mask=None, settings_mask=None):
32
+ """Redirect the client to a valid group url."""
33
+ route = deepcopy(dict(self.DEFAULT_ROUTE))
34
+ if route_mask:
35
+ route["params"].update(route_mask) # type: ignore
36
+ settings = deepcopy(dict(self.params))
37
+ if settings_mask:
38
+ settings.update(settings_mask)
39
+ detail = {"route": route, "settings": settings, "reason": reason}
40
+ raise SeeOtherRedirectError(detail=detail)
41
+
42
+ def _get_valid_browse_top_groups(self):
43
+ """Get valid top groups for the current settings.
44
+
45
+ Valid top groups are determined by the Browser Settings.
46
+ """
47
+ valid_top_groups = []
48
+
49
+ show = self.params["show"]
50
+ for nav_group, allowed in show.items():
51
+ if allowed:
52
+ valid_top_groups.append(nav_group)
53
+ # Issues is always a valid top group
54
+ valid_top_groups += [COMIC_GROUP]
55
+
56
+ return valid_top_groups
57
+
58
+ def _validate_top_group(self, valid_top_groups):
59
+ # if self.TARGET in _NO_TOP_GROUP_VALIDATE:
60
+ # return
61
+ nav_group = self.kwargs.get("group")
62
+ top_group = self.params.get("top_group")
63
+ if top_group not in valid_top_groups:
64
+ reason = f"top_group {top_group} not in valid nav groups, changed to "
65
+ if nav_group in valid_top_groups:
66
+ valid_top_group = nav_group
67
+ reason += "nav group: "
68
+ else:
69
+ valid_top_group = valid_top_groups[0]
70
+ reason += "first valid top group "
71
+ reason += valid_top_group
72
+ pks = self.kwargs.get("pks", ())
73
+ page = self.kwargs["page"]
74
+ route = {"group": nav_group, "pks": pks, "page": page}
75
+ settings_mask = {"top_group": valid_top_group}
76
+ self.raise_redirect(reason, route, settings_mask)
77
+
78
+ def set_valid_browse_nav_groups(self, valid_top_groups):
79
+ """Get valid nav groups for the current settings.
80
+
81
+ Valid nav groups are the top group and below that are also
82
+ enabled in browser settings.
83
+
84
+ May always navigate to root 'r' nav group.
85
+ """
86
+ top_group = self.params["top_group"]
87
+ nav_group = self.kwargs["group"]
88
+ valid_nav_groups = [ROOT_GROUP]
89
+
90
+ for possible_index, possible_nav_group in enumerate(valid_top_groups):
91
+ if top_group == possible_nav_group:
92
+ # all the nav groups past this point,
93
+ # 'c' is obscured by the web reader url, but valid for opds
94
+ tail_top_groups = valid_top_groups[possible_index:]
95
+ valid_nav_groups += tail_top_groups
96
+
97
+ if nav_group not in valid_nav_groups:
98
+ reason = (
99
+ f"Nav group {nav_group} unavailable, "
100
+ f"redirect to {ROOT_GROUP}"
101
+ )
102
+ self.raise_redirect(reason)
103
+ break
104
+ self.valid_nav_groups = tuple(valid_nav_groups)
105
+
106
+ def _validate_folder_settings(self):
107
+ """Check that all the view variables for folder mode are set right."""
108
+ # Check folder view admin flag
109
+ if not self.admin_flags["folder_view"]:
110
+ reason = "folder view disabled"
111
+ valid_top_groups = self._get_valid_browse_top_groups()
112
+ settings_mask = {"top_group": valid_top_groups[0]}
113
+ self.raise_redirect(reason, settings_mask=settings_mask)
114
+
115
+ valid_top_groups = (FOLDER_GROUP,)
116
+ self._validate_top_group(valid_top_groups)
117
+ self.valid_nav_groups = valid_top_groups
118
+
119
+ def _validate_browser_group_settings(self):
120
+ """Check that all the view variables for browser mode are set right."""
121
+ # Validate Browser top_group
122
+ # Change top_group if its not in the valid top groups
123
+ valid_top_groups = self._get_valid_browse_top_groups()
124
+ self._validate_top_group(valid_top_groups)
125
+
126
+ # Validate pks
127
+ nav_group = self.kwargs["group"]
128
+ pks = self.kwargs["pks"]
129
+ if nav_group == ROOT_GROUP and (pks and 0 not in pks):
130
+ # r never has pks
131
+ reason = f"Redirect r with {pks=} to pks 0"
132
+ self.raise_redirect(reason)
133
+
134
+ # Validate Browser nav_group
135
+ # Redirect if nav group is wrong
136
+ self.set_valid_browse_nav_groups(valid_top_groups)
137
+
138
+ def _validate_story_arc_settings(self):
139
+ """Validate story arc settings."""
140
+ valid_top_groups = (STORY_ARC_GROUP,)
141
+ self._validate_top_group(valid_top_groups)
142
+ self.valid_nav_groups = valid_top_groups
143
+
144
+ def validate_settings(self):
145
+ """Validate group and top group settings."""
146
+ group = self.kwargs["group"]
147
+ if group == FOLDER_GROUP:
148
+ self._validate_folder_settings()
149
+ elif group == STORY_ARC_GROUP:
150
+ self._validate_story_arc_settings()
151
+ else:
152
+ self._validate_browser_group_settings()
153
+
154
+ # Validate order
155
+ if self.order_key == "filename" and not self.admin_flags["folder_view"]:
156
+ pks = self.kwargs["pks"]
157
+ page = self.kwargs["page"]
158
+ route_changes = {"group": group, "pks": pks, "page": page}
159
+ reason = "order by filename not allowed by admin flag."
160
+ settings_mask = {"order_by": "sort_name"}
161
+ self.raise_redirect(reason, route_changes, settings_mask)
codex/views/const.py CHANGED
@@ -1,3 +1,160 @@
1
1
  """Common view constants."""
2
2
 
3
+ from datetime import datetime, timezone
4
+ from types import MappingProxyType
5
+
6
+ from django.contrib.auth.models import Group, User
7
+ from django.contrib.sessions.models import Session
8
+ from django.db.models.expressions import Value
9
+ from django.db.models.fields import DateTimeField, PositiveSmallIntegerField
10
+
11
+ from codex.models import (
12
+ AgeRating,
13
+ BrowserGroupModel,
14
+ Character,
15
+ Comic,
16
+ Contributor,
17
+ ContributorPerson,
18
+ ContributorRole,
19
+ Country,
20
+ Folder,
21
+ Genre,
22
+ Identifier,
23
+ IdentifierType,
24
+ Imprint,
25
+ Language,
26
+ Library,
27
+ Location,
28
+ OriginalFormat,
29
+ Publisher,
30
+ ScanInfo,
31
+ Series,
32
+ SeriesGroup,
33
+ StoryArc,
34
+ StoryArcNumber,
35
+ Tag,
36
+ Tagger,
37
+ Team,
38
+ Volume,
39
+ )
40
+ from codex.settings.settings import CODEX_PATH
41
+
3
42
  FALSY = {None, "", "false", "0", False}
43
+ GROUP_NAME_MAP = MappingProxyType(
44
+ {"p": "publisher", "i": "imprint", "s": "series", "v": "volume"}
45
+ )
46
+ STATIC_IMG_PATH = CODEX_PATH / "static_root/img"
47
+ MISSING_COVER_NAME_MAP = MappingProxyType(
48
+ {
49
+ **GROUP_NAME_MAP,
50
+ "f": "folder",
51
+ "a": "story-arc",
52
+ }
53
+ )
54
+ MISSING_COVER_FN = "missing-cover-165.webp"
55
+ MISSING_COVER_PATH = STATIC_IMG_PATH / MISSING_COVER_FN
56
+
57
+
58
+ ROOT_GROUP = "r"
59
+ FOLDER_GROUP = "f"
60
+ STORY_ARC_GROUP = "a"
61
+ COMIC_GROUP = "c"
62
+ GROUP_RELATION = MappingProxyType(
63
+ {
64
+ **GROUP_NAME_MAP,
65
+ COMIC_GROUP: "pk",
66
+ FOLDER_GROUP: "parent_folder",
67
+ STORY_ARC_GROUP: "story_arc_numbers__story_arc",
68
+ }
69
+ )
70
+ FILTER_ONLY_GROUP_RELATION = MappingProxyType(
71
+ {
72
+ **GROUP_NAME_MAP,
73
+ FOLDER_GROUP: "folders",
74
+ STORY_ARC_GROUP: "story_arc_numbers__story_arc",
75
+ }
76
+ )
77
+ METADATA_GROUP_RELATION = MappingProxyType(
78
+ {
79
+ **GROUP_NAME_MAP,
80
+ COMIC_GROUP: "pk",
81
+ # Possible to list all groups in a non group view, but could get crazy.
82
+ # FOLDER_GROUP: "comic__folder",
83
+ # STORY_ARC_GROUP: "comic__story_arc_number__story_arc"
84
+ }
85
+ )
86
+ CUSTOM_COVER_GROUP_RELATION = MappingProxyType(
87
+ {**GROUP_NAME_MAP, FOLDER_GROUP: "folder", STORY_ARC_GROUP: "storyarc"}
88
+ )
89
+ GROUP_ORDER = "rpisv"
90
+ MODEL_REL_MAP = MappingProxyType(
91
+ {
92
+ Publisher: "publisher",
93
+ Imprint: "imprint",
94
+ Series: "series",
95
+ Volume: "volume",
96
+ Folder: "parent_folder",
97
+ StoryArc: "story_arc_numbers__story_arc",
98
+ Comic: "pk",
99
+ }
100
+ )
101
+ GROUP_MODEL_MAP: MappingProxyType[str, type[BrowserGroupModel] | None] = (
102
+ MappingProxyType(
103
+ {
104
+ ROOT_GROUP: None,
105
+ "p": Publisher,
106
+ "i": Imprint,
107
+ "s": Series,
108
+ "v": Volume,
109
+ COMIC_GROUP: Comic,
110
+ FOLDER_GROUP: Folder,
111
+ STORY_ARC_GROUP: StoryArc,
112
+ }
113
+ )
114
+ )
115
+ GROUP_MODELS = (
116
+ Publisher,
117
+ Imprint,
118
+ Series,
119
+ Volume,
120
+ Folder,
121
+ StoryArc,
122
+ )
123
+ STATS_GROUP_MODELS = (
124
+ *GROUP_MODELS,
125
+ Comic,
126
+ )
127
+ METADATA_MODELS = (
128
+ AgeRating,
129
+ Character,
130
+ Country,
131
+ Genre,
132
+ Identifier,
133
+ IdentifierType,
134
+ Language,
135
+ Location,
136
+ OriginalFormat,
137
+ SeriesGroup,
138
+ ScanInfo,
139
+ StoryArc,
140
+ StoryArcNumber,
141
+ Team,
142
+ Tag,
143
+ Tagger,
144
+ Contributor,
145
+ ContributorPerson,
146
+ ContributorRole,
147
+ )
148
+ CONFIG_MODELS = (
149
+ Library,
150
+ User,
151
+ Group,
152
+ Session,
153
+ )
154
+ MAX_OBJ_PER_PAGE = 100
155
+ GROUP_MTIME_MODEL_MAP = MappingProxyType({"r": Publisher, "a": StoryArc, "f": Folder})
156
+ EPOCH_START = datetime.fromtimestamp(0, tz=timezone.utc)
157
+ ONE_INTEGERFIELD = Value(1, PositiveSmallIntegerField())
158
+ NONE_INTEGERFIELD = Value(None, PositiveSmallIntegerField())
159
+ NONE_DATETIMEFIELD = Value(None, DateTimeField())
160
+ EPOCH_START_DATETIMEFIELD = Value(EPOCH_START)
codex/views/download.py CHANGED
@@ -1,33 +1,21 @@
1
1
  """Download a comic archive."""
2
2
 
3
3
  from pathlib import Path
4
- from typing import ClassVar
5
4
 
6
5
  from django.http import FileResponse, Http404
7
6
  from drf_spectacular.types import OpenApiTypes
8
7
  from drf_spectacular.utils import extend_schema
9
- from rest_framework.views import APIView
10
8
 
11
9
  from codex.models import Comic
12
- from codex.views.auth import GroupACLMixin, IsAuthenticatedOrEnabledNonUsers
10
+ from codex.views.auth import AuthFilterAPIView
13
11
 
14
12
 
15
- class DownloadView(APIView, GroupACLMixin):
13
+ class DownloadView(AuthFilterAPIView):
16
14
  """Return the comic archive file as an attachment."""
17
15
 
18
- permission_classes: ClassVar[list] = [IsAuthenticatedOrEnabledNonUsers] # type: ignore
19
16
  content_type = "application/vnd.comicbook+zip"
20
17
 
21
- _DOWNLOAD_SELECT_RELATED = ("series", "volume")
22
- _DOWNLOAD_FIELDS = (
23
- "path",
24
- "series",
25
- "volume",
26
- "issue_number",
27
- "issue_suffix",
28
- "name",
29
- )
30
- AS_ATTACHMENT = True
18
+ _AS_ATTACHMENT = True
31
19
 
32
20
  @extend_schema(responses={(200, content_type): OpenApiTypes.BINARY})
33
21
  def get(self, *_args, **kwargs):
@@ -37,8 +25,7 @@ class DownloadView(APIView, GroupACLMixin):
37
25
  group_acl_filter = self.get_group_acl_filter(Comic)
38
26
  comic = (
39
27
  Comic.objects.filter(group_acl_filter)
40
- .select_related(*self._DOWNLOAD_SELECT_RELATED)
41
- .only(*self._DOWNLOAD_FIELDS)
28
+ .only("path", "file_type")
42
29
  .get(pk=pk)
43
30
  )
44
31
  except Comic.DoesNotExist as err:
@@ -55,15 +42,16 @@ class DownloadView(APIView, GroupACLMixin):
55
42
  else:
56
43
  content_type += "octet-stream"
57
44
 
45
+ filename = comic.get_filename()
58
46
  return FileResponse(
59
47
  comic_file,
60
- as_attachment=self.AS_ATTACHMENT,
48
+ as_attachment=self._AS_ATTACHMENT,
61
49
  content_type=content_type,
62
- filename=comic.filename(),
50
+ filename=filename,
63
51
  )
64
52
 
65
53
 
66
54
  class FileView(DownloadView):
67
55
  """View a comic in the browser."""
68
56
 
69
- AS_ATTACHMENT = False
57
+ _AS_ATTACHMENT = False
codex/views/error.py CHANGED
@@ -22,8 +22,8 @@ def codex_exception_handler(exc, context):
22
22
  status.HTTP_400_BAD_REQUEST,
23
23
  status.HTTP_404_NOT_FOUND,
24
24
  ):
25
- opds_start = reverse(name)
26
- response = redirect(opds_start, permanent=False)
25
+ url = reverse(name)
26
+ response = redirect(url, permanent=False)
27
27
 
28
28
  if not response:
29
29
  response = exception_handler(exc, context)
codex/views/frontend.py CHANGED
@@ -5,17 +5,22 @@ from typing import ClassVar
5
5
  from rest_framework.renderers import TemplateHTMLRenderer
6
6
  from rest_framework.response import Response
7
7
 
8
- from codex.views.session import BrowserSessionViewBase
8
+ from codex.serializers.route import RouteSerializer
9
+ from codex.views.session import SessionView
9
10
 
10
11
 
11
- class IndexView(BrowserSessionViewBase):
12
+ class IndexView(SessionView):
12
13
  """The main app."""
13
14
 
15
+ SESSION_KEY = SessionView.BROWSER_SESSION_KEY
16
+
14
17
  renderer_classes: ClassVar[list] = [TemplateHTMLRenderer] # type: ignore
15
18
  template_name = "index.html"
16
19
 
17
20
  def get(self, *_args, **_kwargs):
18
21
  """Get the app index page."""
19
- last_route = self.get_from_session("route")
22
+ last_route = self.get_last_route(name=False)
23
+ serializer = RouteSerializer(last_route)
24
+ last_route = serializer.data
20
25
  extra_context = {"last_route": last_route}
21
26
  return Response(extra_context)