codex 1.6.0__py3-none-any.whl → 1.6.0a0__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 (769) hide show
  1. codex/exceptions.py +18 -22
  2. codex/integrity.py +3 -66
  3. codex/librarian/covers/coverd.py +2 -2
  4. codex/librarian/covers/create.py +29 -50
  5. codex/librarian/covers/path.py +6 -8
  6. codex/librarian/covers/purge.py +18 -28
  7. codex/librarian/covers/tasks.py +2 -3
  8. codex/librarian/importer/{aggregate.py → aggregate_metadata.py} +88 -58
  9. codex/librarian/importer/{extract.py → clean_metadata.py} +4 -33
  10. codex/librarian/importer/const.py +13 -46
  11. codex/librarian/importer/create_comics.py +17 -101
  12. codex/librarian/importer/create_fks.py +134 -99
  13. codex/librarian/importer/deleted.py +28 -103
  14. codex/librarian/importer/failed_imports.py +64 -42
  15. codex/librarian/importer/importerd.py +290 -71
  16. codex/librarian/importer/link_comics.py +26 -26
  17. codex/librarian/importer/moved.py +81 -128
  18. codex/librarian/importer/query_fks.py +122 -142
  19. codex/librarian/importer/status.py +39 -8
  20. codex/librarian/importer/tasks.py +9 -26
  21. codex/librarian/importer/update_comics.py +89 -0
  22. codex/librarian/janitor/cleanup.py +2 -26
  23. codex/librarian/janitor/failed_imports.py +1 -1
  24. codex/librarian/janitor/janitor.py +1 -13
  25. codex/librarian/janitor/janitord.py +1 -1
  26. codex/librarian/janitor/status.py +0 -1
  27. codex/librarian/janitor/tasks.py +0 -5
  28. codex/librarian/librariand.py +5 -9
  29. codex/librarian/notifier/notifierd.py +1 -1
  30. codex/librarian/notifier/tasks.py +4 -4
  31. codex/librarian/search/update.py +1 -1
  32. codex/librarian/watchdog/db_snapshot.py +6 -9
  33. codex/librarian/watchdog/emitter.py +0 -3
  34. codex/librarian/watchdog/event_batcherd.py +3 -19
  35. codex/librarian/watchdog/events.py +36 -176
  36. codex/librarian/watchdog/observers.py +3 -13
  37. codex/middleware.py +2 -1
  38. codex/migrations/0027_sort_name.py +149 -0
  39. codex/models/admin.py +2 -0
  40. codex/models/base.py +0 -3
  41. codex/models/comic.py +9 -13
  42. codex/models/{util.py → const.py} +2 -15
  43. codex/models/groups.py +14 -28
  44. codex/models/library.py +3 -11
  45. codex/models/paths.py +14 -61
  46. codex/permissions.py +1 -1
  47. codex/search/backend_search.py +8 -5
  48. codex/search/query.py +2 -25
  49. codex/search/writing.py +1 -1
  50. codex/serializers/admin.py +44 -53
  51. codex/serializers/browser/choices.py +42 -37
  52. codex/serializers/browser/filters.py +131 -32
  53. codex/serializers/browser/metadata.py +1 -45
  54. codex/serializers/browser/mixins.py +4 -37
  55. codex/serializers/browser/page.py +6 -3
  56. codex/serializers/browser/settings.py +11 -42
  57. codex/serializers/choices.py +1 -14
  58. codex/serializers/models/pycountry.py +51 -11
  59. codex/serializers/opds/v2.py +16 -10
  60. codex/serializers/opds/v2_unused.py +3 -5
  61. codex/serializers/reader.py +7 -21
  62. codex/serializers/redirect.py +2 -3
  63. codex/serializers/route.py +7 -16
  64. codex/settings/settings.py +8 -23
  65. codex/startup.py +3 -77
  66. codex/static_root/assets/VCheckbox-Aq_ImMNC.da711f8b6a15.js +1 -0
  67. codex/static_root/assets/VCheckbox-Aq_ImMNC.da711f8b6a15.js.br +0 -0
  68. codex/static_root/assets/VCheckbox-Aq_ImMNC.da711f8b6a15.js.gz +0 -0
  69. codex/static_root/assets/VCheckbox-Aq_ImMNC.js +1 -0
  70. codex/static_root/assets/VCheckbox-Aq_ImMNC.js.br +0 -0
  71. codex/static_root/assets/VCheckbox-Aq_ImMNC.js.gz +0 -0
  72. codex/static_root/assets/{VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js → VCheckboxBtn-D3izCBa7.54f4d7f48bbf.js} +1 -1
  73. codex/static_root/assets/VCheckboxBtn-D3izCBa7.54f4d7f48bbf.js.br +0 -0
  74. codex/static_root/assets/VCheckboxBtn-D3izCBa7.54f4d7f48bbf.js.gz +0 -0
  75. codex/static_root/assets/{VCheckboxBtn-DxNOKONG.js → VCheckboxBtn-D3izCBa7.js} +1 -1
  76. codex/static_root/assets/VCheckboxBtn-D3izCBa7.js.br +0 -0
  77. codex/static_root/assets/VCheckboxBtn-D3izCBa7.js.gz +0 -0
  78. codex/static_root/assets/VCombobox-DLL1EsSN.55622a0cd4ab.js +1 -0
  79. codex/static_root/assets/VCombobox-DLL1EsSN.55622a0cd4ab.js.br +0 -0
  80. codex/static_root/assets/VCombobox-DLL1EsSN.55622a0cd4ab.js.gz +0 -0
  81. codex/static_root/assets/VCombobox-DLL1EsSN.js +1 -0
  82. codex/static_root/assets/VCombobox-DLL1EsSN.js.br +0 -0
  83. codex/static_root/assets/VCombobox-DLL1EsSN.js.gz +0 -0
  84. codex/static_root/assets/{VDialog-lQ13FnRR.1c801ad756b2.css → VDialog-C5Nxd_zP.css} +1 -1
  85. codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
  86. codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
  87. codex/static_root/assets/{VDialog-lQ13FnRR.css → VDialog-C5Nxd_zP.d327f505ef0e.css} +1 -1
  88. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
  89. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
  90. codex/static_root/assets/VDialog-yDKzaGEj.e8dba78ac8db.js +1 -0
  91. codex/static_root/assets/VDialog-yDKzaGEj.e8dba78ac8db.js.br +0 -0
  92. codex/static_root/assets/VDialog-yDKzaGEj.e8dba78ac8db.js.gz +0 -0
  93. codex/static_root/assets/VDialog-yDKzaGEj.js +1 -0
  94. codex/static_root/assets/VDialog-yDKzaGEj.js.br +0 -0
  95. codex/static_root/assets/VDialog-yDKzaGEj.js.gz +0 -0
  96. codex/static_root/assets/VExpansionPanels-Cpo8QLLq.d733b7906e00.js +1 -0
  97. codex/static_root/assets/VExpansionPanels-Cpo8QLLq.d733b7906e00.js.br +0 -0
  98. codex/static_root/assets/VExpansionPanels-Cpo8QLLq.d733b7906e00.js.gz +0 -0
  99. codex/static_root/assets/VExpansionPanels-Cpo8QLLq.js +1 -0
  100. codex/static_root/assets/VExpansionPanels-Cpo8QLLq.js.br +0 -0
  101. codex/static_root/assets/VExpansionPanels-Cpo8QLLq.js.gz +0 -0
  102. codex/static_root/assets/VRadioGroup-DEezv8bL.4a609e74e507.js +1 -0
  103. codex/static_root/assets/VRadioGroup-DEezv8bL.4a609e74e507.js.br +0 -0
  104. codex/static_root/assets/VRadioGroup-DEezv8bL.4a609e74e507.js.gz +0 -0
  105. codex/static_root/assets/VRadioGroup-DEezv8bL.js +1 -0
  106. codex/static_root/assets/VRadioGroup-DEezv8bL.js.br +0 -0
  107. codex/static_root/assets/VRadioGroup-DEezv8bL.js.gz +0 -0
  108. codex/static_root/assets/VSelect-BKXcujPy.8871035f5634.js +1 -0
  109. codex/static_root/assets/VSelect-BKXcujPy.8871035f5634.js.br +0 -0
  110. codex/static_root/assets/VSelect-BKXcujPy.8871035f5634.js.gz +0 -0
  111. codex/static_root/assets/VSelect-BKXcujPy.js +1 -0
  112. codex/static_root/assets/VSelect-BKXcujPy.js.br +0 -0
  113. codex/static_root/assets/VSelect-BKXcujPy.js.gz +0 -0
  114. codex/static_root/assets/VSelectionControl-DJAPiluk.402a7ad84a8e.js +1 -0
  115. codex/static_root/assets/VSelectionControl-DJAPiluk.402a7ad84a8e.js.br +0 -0
  116. codex/static_root/assets/VSelectionControl-DJAPiluk.402a7ad84a8e.js.gz +0 -0
  117. codex/static_root/assets/VSelectionControl-DJAPiluk.js +1 -0
  118. codex/static_root/assets/VSelectionControl-DJAPiluk.js.br +0 -0
  119. codex/static_root/assets/VSelectionControl-DJAPiluk.js.gz +0 -0
  120. codex/static_root/assets/VSlideGroup-C-kO93Va.8c9e31362dc5.js +1 -0
  121. codex/static_root/assets/VSlideGroup-C-kO93Va.8c9e31362dc5.js.br +0 -0
  122. codex/static_root/assets/VSlideGroup-C-kO93Va.8c9e31362dc5.js.gz +0 -0
  123. codex/static_root/assets/VSlideGroup-C-kO93Va.js +1 -0
  124. codex/static_root/assets/VSlideGroup-C-kO93Va.js.br +0 -0
  125. codex/static_root/assets/VSlideGroup-C-kO93Va.js.gz +0 -0
  126. codex/static_root/assets/{VTable-2RHFqfg6.f0f2106b158b.js → VTable-9vsIQObs.0a135029e924.js} +1 -1
  127. codex/static_root/assets/VTable-9vsIQObs.0a135029e924.js.br +0 -0
  128. codex/static_root/assets/VTable-9vsIQObs.0a135029e924.js.gz +0 -0
  129. codex/static_root/assets/{VTable-2RHFqfg6.js → VTable-9vsIQObs.js} +1 -1
  130. codex/static_root/assets/VTable-9vsIQObs.js.br +0 -0
  131. codex/static_root/assets/VTable-9vsIQObs.js.gz +0 -0
  132. codex/static_root/assets/VTextField-DI9HAmWh.0de01739bbf9.js +1 -0
  133. codex/static_root/assets/VTextField-DI9HAmWh.0de01739bbf9.js.br +0 -0
  134. codex/static_root/assets/VTextField-DI9HAmWh.0de01739bbf9.js.gz +0 -0
  135. codex/static_root/assets/VTextField-DI9HAmWh.js +1 -0
  136. codex/static_root/assets/VTextField-DI9HAmWh.js.br +0 -0
  137. codex/static_root/assets/VTextField-DI9HAmWh.js.gz +0 -0
  138. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css +1 -0
  139. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.br +0 -0
  140. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.gz +0 -0
  141. codex/static_root/assets/VTextField-DuIIp-VY.css +1 -0
  142. codex/static_root/assets/VTextField-DuIIp-VY.css.br +0 -0
  143. codex/static_root/assets/VTextField-DuIIp-VY.css.gz +0 -0
  144. codex/static_root/assets/VWindowItem-DpnYkF3y.017d99c27b7b.js +1 -0
  145. codex/static_root/assets/VWindowItem-DpnYkF3y.017d99c27b7b.js.br +0 -0
  146. codex/static_root/assets/VWindowItem-DpnYkF3y.017d99c27b7b.js.gz +0 -0
  147. codex/static_root/assets/VWindowItem-DpnYkF3y.js +1 -0
  148. codex/static_root/assets/VWindowItem-DpnYkF3y.js.br +0 -0
  149. codex/static_root/assets/VWindowItem-DpnYkF3y.js.gz +0 -0
  150. codex/static_root/assets/admin-2BTkfSQA.e7ef29cb106d.js +1 -0
  151. codex/static_root/assets/admin-2BTkfSQA.e7ef29cb106d.js.br +0 -0
  152. codex/static_root/assets/admin-2BTkfSQA.e7ef29cb106d.js.gz +0 -0
  153. codex/static_root/assets/admin-2BTkfSQA.js +1 -0
  154. codex/static_root/assets/admin-2BTkfSQA.js.br +0 -0
  155. codex/static_root/assets/admin-2BTkfSQA.js.gz +0 -0
  156. codex/static_root/assets/{admin-B8Bp2Uih.82c98714bcf1.css → admin-BbrOU9Y9.29936748af9e.css} +1 -1
  157. codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.br +0 -0
  158. codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.gz +0 -0
  159. codex/static_root/assets/{admin-B8Bp2Uih.css → admin-BbrOU9Y9.css} +1 -1
  160. codex/static_root/assets/admin-BbrOU9Y9.css.br +0 -0
  161. codex/static_root/assets/admin-BbrOU9Y9.css.gz +0 -0
  162. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css +1 -0
  163. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.br +0 -0
  164. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.gz +0 -0
  165. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css +1 -0
  166. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.br +0 -0
  167. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.gz +0 -0
  168. codex/static_root/assets/admin-drawer-panel-mtdde7vY.c172dbae9463.js +30 -0
  169. codex/static_root/assets/admin-drawer-panel-mtdde7vY.c172dbae9463.js.br +0 -0
  170. codex/static_root/assets/admin-drawer-panel-mtdde7vY.c172dbae9463.js.gz +0 -0
  171. codex/static_root/assets/admin-drawer-panel-mtdde7vY.js +30 -0
  172. codex/static_root/assets/admin-drawer-panel-mtdde7vY.js.br +0 -0
  173. codex/static_root/assets/admin-drawer-panel-mtdde7vY.js.gz +0 -0
  174. codex/static_root/assets/browser-BA-AwUn-.23bb4b2f6a29.js +1 -0
  175. codex/static_root/assets/browser-BA-AwUn-.23bb4b2f6a29.js.br +0 -0
  176. codex/static_root/assets/browser-BA-AwUn-.23bb4b2f6a29.js.gz +0 -0
  177. codex/static_root/assets/browser-BA-AwUn-.js +1 -0
  178. codex/static_root/assets/browser-BA-AwUn-.js.br +0 -0
  179. codex/static_root/assets/browser-BA-AwUn-.js.gz +0 -0
  180. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css +1 -0
  181. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css.br +0 -0
  182. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css.gz +0 -0
  183. codex/static_root/assets/browser-CZeVqRNy.css +1 -0
  184. codex/static_root/assets/browser-CZeVqRNy.css.br +0 -0
  185. codex/static_root/assets/browser-CZeVqRNy.css.gz +0 -0
  186. codex/static_root/assets/change-password-dialog-C8YONrId.49aa6df6a91d.js +1 -0
  187. codex/static_root/assets/change-password-dialog-C8YONrId.49aa6df6a91d.js.br +0 -0
  188. codex/static_root/assets/change-password-dialog-C8YONrId.49aa6df6a91d.js.gz +0 -0
  189. codex/static_root/assets/change-password-dialog-C8YONrId.js +1 -0
  190. codex/static_root/assets/change-password-dialog-C8YONrId.js.br +0 -0
  191. codex/static_root/assets/change-password-dialog-C8YONrId.js.gz +0 -0
  192. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +1 -0
  193. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
  194. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
  195. codex/static_root/assets/change-password-dialog-HvIvmmIE.css +1 -0
  196. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
  197. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
  198. codex/static_root/assets/confirm-dialog-Clg-o2G-.e11d8efef3fb.js +1 -0
  199. codex/static_root/assets/confirm-dialog-Clg-o2G-.e11d8efef3fb.js.br +0 -0
  200. codex/static_root/assets/confirm-dialog-Clg-o2G-.e11d8efef3fb.js.gz +0 -0
  201. codex/static_root/assets/confirm-dialog-Clg-o2G-.js +1 -0
  202. codex/static_root/assets/confirm-dialog-Clg-o2G-.js.br +0 -0
  203. codex/static_root/assets/confirm-dialog-Clg-o2G-.js.gz +0 -0
  204. codex/static_root/assets/datetime-column-DejrPZxl.9fd36bef6fdd.js +1 -0
  205. codex/static_root/assets/datetime-column-DejrPZxl.9fd36bef6fdd.js.br +0 -0
  206. codex/static_root/assets/datetime-column-DejrPZxl.9fd36bef6fdd.js.gz +0 -0
  207. codex/static_root/assets/datetime-column-DejrPZxl.js +1 -0
  208. codex/static_root/assets/datetime-column-DejrPZxl.js.br +0 -0
  209. codex/static_root/assets/datetime-column-DejrPZxl.js.gz +0 -0
  210. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css +1 -0
  211. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css.br +0 -0
  212. codex/static_root/assets/datetime-column-Dg_RxTVM.css +1 -0
  213. codex/static_root/assets/datetime-column-Dg_RxTVM.css.br +0 -0
  214. codex/static_root/assets/filter-DHo57nTp.4d79a276d806.js +1 -0
  215. codex/static_root/assets/filter-DHo57nTp.4d79a276d806.js.br +0 -0
  216. codex/static_root/assets/filter-DHo57nTp.4d79a276d806.js.gz +0 -0
  217. codex/static_root/assets/filter-DHo57nTp.js +1 -0
  218. codex/static_root/assets/filter-DHo57nTp.js.br +0 -0
  219. codex/static_root/assets/filter-DHo57nTp.js.gz +0 -0
  220. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css +1 -0
  221. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.br +0 -0
  222. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.gz +0 -0
  223. codex/static_root/assets/flag-tab-BacZLlVi.css +1 -0
  224. codex/static_root/assets/flag-tab-BacZLlVi.css.br +0 -0
  225. codex/static_root/assets/flag-tab-BacZLlVi.css.gz +0 -0
  226. codex/static_root/assets/flag-tab-CagMLGSE.125739911c45.js +1 -0
  227. codex/static_root/assets/flag-tab-CagMLGSE.125739911c45.js.br +0 -0
  228. codex/static_root/assets/flag-tab-CagMLGSE.125739911c45.js.gz +0 -0
  229. codex/static_root/assets/flag-tab-CagMLGSE.js +1 -0
  230. codex/static_root/assets/flag-tab-CagMLGSE.js.br +0 -0
  231. codex/static_root/assets/flag-tab-CagMLGSE.js.gz +0 -0
  232. codex/static_root/assets/{group-tab-D5vWrihT.js → group-tab-BTAjhv32.ac196780d0a9.js} +1 -1
  233. codex/static_root/assets/group-tab-BTAjhv32.ac196780d0a9.js.br +0 -0
  234. codex/static_root/assets/group-tab-BTAjhv32.ac196780d0a9.js.gz +0 -0
  235. codex/static_root/assets/{group-tab-D5vWrihT.1afb2ce453ff.js → group-tab-BTAjhv32.js} +1 -1
  236. codex/static_root/assets/group-tab-BTAjhv32.js.br +0 -0
  237. codex/static_root/assets/group-tab-BTAjhv32.js.gz +0 -0
  238. codex/static_root/assets/http-error-DaHEsKbT.55d56ce2b9b4.js +1 -0
  239. codex/static_root/assets/http-error-DaHEsKbT.55d56ce2b9b4.js.br +0 -0
  240. codex/static_root/assets/http-error-DaHEsKbT.55d56ce2b9b4.js.gz +0 -0
  241. codex/static_root/assets/http-error-DaHEsKbT.js +1 -0
  242. codex/static_root/assets/http-error-DaHEsKbT.js.br +0 -0
  243. codex/static_root/assets/http-error-DaHEsKbT.js.gz +0 -0
  244. codex/static_root/assets/http-error-_wlDqEcp.5b78d3e332c9.css +1 -0
  245. codex/static_root/assets/{http-error-DKulXuTl.95e42988d5d5.css.br → http-error-_wlDqEcp.5b78d3e332c9.css.br} +0 -0
  246. codex/static_root/assets/http-error-_wlDqEcp.5b78d3e332c9.css.gz +0 -0
  247. codex/static_root/assets/http-error-_wlDqEcp.css +1 -0
  248. codex/static_root/assets/{http-error-DKulXuTl.css.br → http-error-_wlDqEcp.css.br} +0 -0
  249. codex/static_root/assets/http-error-_wlDqEcp.css.gz +0 -0
  250. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +1 -0
  251. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
  252. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
  253. codex/static_root/assets/index-DUjeNg4x.js +1 -0
  254. codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
  255. codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
  256. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css +1 -0
  257. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.br +2 -0
  258. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.gz +0 -0
  259. codex/static_root/assets/library-tab-CXbkxNZt.css +1 -0
  260. codex/static_root/assets/library-tab-CXbkxNZt.css.br +2 -0
  261. codex/static_root/assets/library-tab-CXbkxNZt.css.gz +0 -0
  262. codex/static_root/assets/library-tab-Cud4639b.7f5a50aaabe8.js +1 -0
  263. codex/static_root/assets/library-tab-Cud4639b.7f5a50aaabe8.js.br +0 -0
  264. codex/static_root/assets/library-tab-Cud4639b.7f5a50aaabe8.js.gz +0 -0
  265. codex/static_root/assets/library-tab-Cud4639b.js +1 -0
  266. codex/static_root/assets/library-tab-Cud4639b.js.br +0 -0
  267. codex/static_root/assets/library-tab-Cud4639b.js.gz +0 -0
  268. codex/static_root/assets/main-BnzL_Byv.22f98ee91990.js +32 -0
  269. codex/static_root/assets/main-BnzL_Byv.22f98ee91990.js.br +0 -0
  270. codex/static_root/assets/main-BnzL_Byv.22f98ee91990.js.gz +0 -0
  271. codex/static_root/assets/main-BnzL_Byv.js +32 -0
  272. codex/static_root/assets/main-BnzL_Byv.js.br +0 -0
  273. codex/static_root/assets/main-BnzL_Byv.js.gz +0 -0
  274. codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css → main-sK7HC5h4.6f04ddfc5f1a.css} +1 -1
  275. codex/static_root/assets/main-sK7HC5h4.6f04ddfc5f1a.css.br +0 -0
  276. codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css.gz → main-sK7HC5h4.6f04ddfc5f1a.css.gz} +0 -0
  277. codex/static_root/assets/{main-Ztp855PW.css → main-sK7HC5h4.css} +1 -1
  278. codex/static_root/assets/main-sK7HC5h4.css.br +0 -0
  279. codex/static_root/assets/{main-Ztp855PW.css.gz → main-sK7HC5h4.css.gz} +0 -0
  280. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css +1 -0
  281. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.br +0 -0
  282. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.gz +0 -0
  283. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css +1 -0
  284. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.br +0 -0
  285. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.gz +0 -0
  286. codex/static_root/assets/pagination-toolbar-Covpd-k8.b71277bd7a2d.js +1 -0
  287. codex/static_root/assets/pagination-toolbar-Covpd-k8.b71277bd7a2d.js.br +0 -0
  288. codex/static_root/assets/pagination-toolbar-Covpd-k8.b71277bd7a2d.js.gz +0 -0
  289. codex/static_root/assets/pagination-toolbar-Covpd-k8.js +1 -0
  290. codex/static_root/assets/pagination-toolbar-Covpd-k8.js.br +0 -0
  291. codex/static_root/assets/pagination-toolbar-Covpd-k8.js.gz +0 -0
  292. codex/static_root/assets/pdf-doc-CD2lnB32.1cef3bf498be.js +35 -0
  293. codex/static_root/assets/pdf-doc-CD2lnB32.1cef3bf498be.js.br +0 -0
  294. codex/static_root/assets/pdf-doc-CD2lnB32.1cef3bf498be.js.gz +0 -0
  295. codex/static_root/assets/pdf-doc-CD2lnB32.js +35 -0
  296. codex/static_root/assets/pdf-doc-CD2lnB32.js.br +0 -0
  297. codex/static_root/assets/pdf-doc-CD2lnB32.js.gz +0 -0
  298. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css +1 -0
  299. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css.br +0 -0
  300. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css.gz +0 -0
  301. codex/static_root/assets/reader-Dspy46e8.css +1 -0
  302. codex/static_root/assets/reader-Dspy46e8.css.br +0 -0
  303. codex/static_root/assets/reader-Dspy46e8.css.gz +0 -0
  304. codex/static_root/assets/reader-L85y7IXD.6de58f450421.js +2 -0
  305. codex/static_root/assets/reader-L85y7IXD.6de58f450421.js.br +0 -0
  306. codex/static_root/assets/reader-L85y7IXD.6de58f450421.js.gz +0 -0
  307. codex/static_root/assets/reader-L85y7IXD.js +2 -0
  308. codex/static_root/assets/reader-L85y7IXD.js.br +0 -0
  309. codex/static_root/assets/reader-L85y7IXD.js.gz +0 -0
  310. codex/static_root/assets/relation-chips-BpuqEeqM.1372d8a3e6cf.js +1 -0
  311. codex/static_root/assets/relation-chips-BpuqEeqM.1372d8a3e6cf.js.br +0 -0
  312. codex/static_root/assets/relation-chips-BpuqEeqM.1372d8a3e6cf.js.gz +0 -0
  313. codex/static_root/assets/relation-chips-BpuqEeqM.js +1 -0
  314. codex/static_root/assets/relation-chips-BpuqEeqM.js.br +0 -0
  315. codex/static_root/assets/relation-chips-BpuqEeqM.js.gz +0 -0
  316. codex/static_root/assets/{relation-chips-Bsc-gUxE.98e65384c3c9.css → relation-chips-D6T6FX7G.css} +1 -1
  317. codex/static_root/assets/relation-chips-D6T6FX7G.css.br +0 -0
  318. codex/static_root/assets/relation-chips-D6T6FX7G.css.gz +0 -0
  319. codex/static_root/assets/{relation-chips-Bsc-gUxE.css → relation-chips-D6T6FX7G.db095b2497e4.css} +1 -1
  320. codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.br +0 -0
  321. codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.gz +0 -0
  322. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css +1 -0
  323. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css.br +0 -0
  324. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css.gz +0 -0
  325. codex/static_root/assets/settings-drawer-BgUazs7O.css +1 -0
  326. codex/static_root/assets/settings-drawer-BgUazs7O.css.br +0 -0
  327. codex/static_root/assets/settings-drawer-BgUazs7O.css.gz +0 -0
  328. codex/static_root/assets/settings-drawer-CLMcxfVd.b9619341ad48.js +2 -0
  329. codex/static_root/assets/settings-drawer-CLMcxfVd.b9619341ad48.js.br +0 -0
  330. codex/static_root/assets/settings-drawer-CLMcxfVd.b9619341ad48.js.gz +0 -0
  331. codex/static_root/assets/settings-drawer-CLMcxfVd.js +2 -0
  332. codex/static_root/assets/settings-drawer-CLMcxfVd.js.br +0 -0
  333. codex/static_root/assets/settings-drawer-CLMcxfVd.js.gz +0 -0
  334. codex/static_root/assets/stats-tab-CQa3-W05.3d7c61418528.js +1 -0
  335. codex/static_root/assets/stats-tab-CQa3-W05.3d7c61418528.js.br +0 -0
  336. codex/static_root/assets/stats-tab-CQa3-W05.3d7c61418528.js.gz +0 -0
  337. codex/static_root/assets/stats-tab-CQa3-W05.js +1 -0
  338. codex/static_root/assets/stats-tab-CQa3-W05.js.br +0 -0
  339. codex/static_root/assets/stats-tab-CQa3-W05.js.gz +0 -0
  340. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +1 -0
  341. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +2 -0
  342. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
  343. codex/static_root/assets/stats-tab-TsyG3wH_.css +1 -0
  344. codex/static_root/assets/stats-tab-TsyG3wH_.css.br +2 -0
  345. codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
  346. codex/static_root/assets/task-tab-OPhBm-O2.8f31f4215114.js +1 -0
  347. codex/static_root/assets/task-tab-OPhBm-O2.8f31f4215114.js.br +0 -0
  348. codex/static_root/assets/task-tab-OPhBm-O2.8f31f4215114.js.gz +0 -0
  349. codex/static_root/assets/task-tab-OPhBm-O2.js +1 -0
  350. codex/static_root/assets/task-tab-OPhBm-O2.js.br +0 -0
  351. codex/static_root/assets/task-tab-OPhBm-O2.js.gz +0 -0
  352. codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +1 -0
  353. codex/static_root/assets/to-case-kUm8NPpW.js +1 -0
  354. codex/static_root/assets/unauthorized-ClQNhRb5.32a8a84d1781.js +1 -0
  355. codex/static_root/assets/unauthorized-ClQNhRb5.32a8a84d1781.js.br +0 -0
  356. codex/static_root/assets/unauthorized-ClQNhRb5.32a8a84d1781.js.gz +0 -0
  357. codex/static_root/assets/unauthorized-ClQNhRb5.js +1 -0
  358. codex/static_root/assets/unauthorized-ClQNhRb5.js.br +0 -0
  359. codex/static_root/assets/unauthorized-ClQNhRb5.js.gz +0 -0
  360. codex/static_root/assets/{unauthorized-CibJYD8o.4c2de98c2b53.css → unauthorized-DWgytUow.ca2f13dbdbf5.css} +1 -1
  361. codex/static_root/assets/unauthorized-DWgytUow.ca2f13dbdbf5.css.br +0 -0
  362. codex/static_root/assets/unauthorized-DWgytUow.ca2f13dbdbf5.css.gz +0 -0
  363. codex/static_root/assets/{unauthorized-CibJYD8o.css → unauthorized-DWgytUow.css} +1 -1
  364. codex/static_root/assets/unauthorized-DWgytUow.css.br +0 -0
  365. codex/static_root/assets/unauthorized-DWgytUow.css.gz +0 -0
  366. codex/static_root/assets/user-tab-BKkxa2WL.50d83951c09f.js +1 -0
  367. codex/static_root/assets/user-tab-BKkxa2WL.50d83951c09f.js.br +0 -0
  368. codex/static_root/assets/user-tab-BKkxa2WL.50d83951c09f.js.gz +0 -0
  369. codex/static_root/assets/user-tab-BKkxa2WL.js +1 -0
  370. codex/static_root/assets/user-tab-BKkxa2WL.js.br +0 -0
  371. codex/static_root/assets/user-tab-BKkxa2WL.js.gz +0 -0
  372. codex/static_root/js/choices-admin.248384ece3f6.json +1 -0
  373. codex/static_root/js/choices-admin.248384ece3f6.json.br +0 -0
  374. codex/static_root/js/choices-admin.248384ece3f6.json.gz +0 -0
  375. codex/static_root/js/choices-admin.json +1 -1
  376. codex/static_root/js/choices-admin.json.br +0 -0
  377. codex/static_root/js/choices-admin.json.gz +0 -0
  378. codex/static_root/js/choices.b60817ba0a93.json +1 -0
  379. codex/static_root/js/choices.b60817ba0a93.json.br +0 -0
  380. codex/static_root/js/choices.b60817ba0a93.json.gz +0 -0
  381. codex/static_root/js/choices.json +1 -1
  382. codex/static_root/js/choices.json.br +0 -0
  383. codex/static_root/js/choices.json.gz +0 -0
  384. codex/static_root/manifest.c5fa10a7dfdc.json +641 -0
  385. codex/static_root/manifest.c5fa10a7dfdc.json.br +0 -0
  386. codex/static_root/manifest.c5fa10a7dfdc.json.gz +0 -0
  387. codex/static_root/manifest.json +298 -279
  388. codex/static_root/manifest.json.br +0 -0
  389. codex/static_root/manifest.json.gz +0 -0
  390. codex/static_root/staticfiles.json +1 -1
  391. codex/status_controller.py +2 -11
  392. codex/urls/api/auth.py +1 -2
  393. codex/urls/api/browser.py +4 -13
  394. codex/urls/api/reader.py +9 -3
  395. codex/urls/api/v3.py +0 -2
  396. codex/urls/opds/binary.py +1 -1
  397. codex/views/admin/api_key.py +8 -7
  398. codex/views/admin/flag.py +7 -2
  399. codex/views/admin/group.py +6 -2
  400. codex/views/admin/library.py +37 -44
  401. codex/views/admin/stats.py +83 -20
  402. codex/views/admin/tasks.py +12 -26
  403. codex/views/admin/user.py +9 -3
  404. codex/views/auth.py +54 -31
  405. codex/views/bookmark.py +72 -92
  406. codex/views/browser/base.py +90 -42
  407. codex/views/browser/browser.py +371 -92
  408. codex/views/browser/{annotations.py → browser_annotations.py} +121 -67
  409. codex/views/browser/browser_breadcrumbs.py +175 -0
  410. codex/views/browser/browser_order_by.py +63 -0
  411. codex/views/browser/choices.py +85 -38
  412. codex/views/browser/const.py +3 -0
  413. codex/views/browser/filters/annotations.py +19 -87
  414. codex/views/browser/filters/bookmark.py +12 -24
  415. codex/views/browser/filters/field.py +6 -8
  416. codex/views/browser/filters/group.py +14 -35
  417. codex/views/browser/filters/search.py +20 -31
  418. codex/views/browser/metadata.py +73 -112
  419. codex/views/browser/session.py +12 -0
  420. codex/views/const.py +0 -140
  421. codex/views/cover.py +77 -0
  422. codex/views/download.py +8 -5
  423. codex/views/frontend.py +2 -4
  424. codex/views/opds/authentication_v1.py +45 -46
  425. codex/views/opds/binary.py +10 -5
  426. codex/views/opds/const.py +0 -13
  427. codex/views/opds/urls.py +4 -6
  428. codex/views/opds/util.py +12 -4
  429. codex/views/opds/v1/entry/links.py +33 -18
  430. codex/views/opds/v1/facets.py +7 -7
  431. codex/views/opds/v1/feed.py +45 -55
  432. codex/views/opds/v1/links.py +5 -7
  433. codex/views/opds/v1/opensearch_v1.py +6 -2
  434. codex/views/opds/v2/feed.py +26 -25
  435. codex/views/opds/v2/links.py +2 -4
  436. codex/views/opds/v2/publications.py +54 -34
  437. codex/views/opds/v2/top_links.py +2 -2
  438. codex/views/reader/page.py +8 -15
  439. codex/views/reader/reader.py +322 -19
  440. codex/views/reader/{settings.py → session.py} +2 -4
  441. codex/views/session.py +102 -83
  442. codex/views/template.py +3 -3
  443. codex/views/version.py +2 -2
  444. codex/websockets/consumers.py +10 -14
  445. {codex-1.6.0.dist-info → codex-1.6.0a0.dist-info}/METADATA +15 -22
  446. {codex-1.6.0.dist-info → codex-1.6.0a0.dist-info}/RECORD +449 -467
  447. codex/librarian/importer/cache.py +0 -93
  448. codex/librarian/importer/create_covers.py +0 -96
  449. codex/librarian/importer/importer.py +0 -96
  450. codex/librarian/importer/init.py +0 -265
  451. codex/librarian/importer/link_covers.py +0 -73
  452. codex/librarian/importer/query_covers.py +0 -52
  453. codex/migrations/0027_import_order_and_covers.py +0 -280
  454. codex/serializers/browser/mtime.py +0 -21
  455. codex/serializers/fields.py +0 -149
  456. codex/serializers/settings.py +0 -12
  457. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js +0 -1
  458. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.br +0 -0
  459. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.gz +0 -0
  460. codex/static_root/assets/VCheckbox-DanrzdHo.js +0 -1
  461. codex/static_root/assets/VCheckbox-DanrzdHo.js.br +0 -0
  462. codex/static_root/assets/VCheckbox-DanrzdHo.js.gz +0 -0
  463. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.br +0 -0
  464. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.gz +0 -0
  465. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.br +0 -0
  466. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.gz +0 -0
  467. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js +0 -1
  468. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.br +0 -0
  469. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.gz +0 -0
  470. codex/static_root/assets/VCombobox-DDvdoPTG.js +0 -1
  471. codex/static_root/assets/VCombobox-DDvdoPTG.js.br +0 -0
  472. codex/static_root/assets/VCombobox-DDvdoPTG.js.gz +0 -0
  473. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js +0 -1
  474. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.br +0 -0
  475. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.gz +0 -0
  476. codex/static_root/assets/VDialog-Bd5dN_E1.js +0 -1
  477. codex/static_root/assets/VDialog-Bd5dN_E1.js.br +0 -0
  478. codex/static_root/assets/VDialog-Bd5dN_E1.js.gz +0 -0
  479. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
  480. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
  481. codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
  482. codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
  483. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js +0 -1
  484. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.br +0 -0
  485. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.gz +0 -0
  486. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js +0 -1
  487. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.br +0 -0
  488. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.gz +0 -0
  489. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js +0 -1
  490. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.br +0 -0
  491. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.gz +0 -0
  492. codex/static_root/assets/VRadioGroup-DKb8XPr-.js +0 -1
  493. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.br +0 -0
  494. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.gz +0 -0
  495. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js +0 -1
  496. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.br +0 -0
  497. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.gz +0 -0
  498. codex/static_root/assets/VSelect-C_yPbyCG.js +0 -1
  499. codex/static_root/assets/VSelect-C_yPbyCG.js.br +0 -0
  500. codex/static_root/assets/VSelect-C_yPbyCG.js.gz +0 -0
  501. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js +0 -1
  502. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.br +0 -0
  503. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.gz +0 -0
  504. codex/static_root/assets/VSelectionControl-CmFPvGMS.js +0 -1
  505. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.br +0 -0
  506. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.gz +0 -0
  507. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js +0 -1
  508. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.br +0 -0
  509. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.gz +0 -0
  510. codex/static_root/assets/VSlideGroup-D5FZWsM1.js +0 -1
  511. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.br +0 -0
  512. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.gz +0 -0
  513. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.br +0 -0
  514. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.gz +0 -0
  515. codex/static_root/assets/VTable-2RHFqfg6.js.br +0 -0
  516. codex/static_root/assets/VTable-2RHFqfg6.js.gz +0 -0
  517. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css +0 -1
  518. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.br +0 -0
  519. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.gz +0 -0
  520. codex/static_root/assets/VTextField-BssVoDhB.css +0 -1
  521. codex/static_root/assets/VTextField-BssVoDhB.css.br +0 -0
  522. codex/static_root/assets/VTextField-BssVoDhB.css.gz +0 -0
  523. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js +0 -1
  524. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.br +0 -0
  525. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.gz +0 -0
  526. codex/static_root/assets/VTextField-o1N9ylIb.js +0 -1
  527. codex/static_root/assets/VTextField-o1N9ylIb.js.br +0 -0
  528. codex/static_root/assets/VTextField-o1N9ylIb.js.gz +0 -0
  529. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js +0 -1
  530. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.br +0 -0
  531. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.gz +0 -0
  532. codex/static_root/assets/VWindowItem-C_zvuz9C.js +0 -1
  533. codex/static_root/assets/VWindowItem-C_zvuz9C.js.br +0 -0
  534. codex/static_root/assets/VWindowItem-C_zvuz9C.js.gz +0 -0
  535. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.br +0 -0
  536. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.gz +0 -0
  537. codex/static_root/assets/admin-B8Bp2Uih.css.br +0 -0
  538. codex/static_root/assets/admin-B8Bp2Uih.css.gz +0 -0
  539. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js +0 -1
  540. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.br +0 -0
  541. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.gz +0 -0
  542. codex/static_root/assets/admin-DHyHEWZ3.js +0 -1
  543. codex/static_root/assets/admin-DHyHEWZ3.js.br +0 -0
  544. codex/static_root/assets/admin-DHyHEWZ3.js.gz +0 -0
  545. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js +0 -30
  546. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.br +0 -0
  547. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.gz +0 -0
  548. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js +0 -30
  549. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.br +0 -0
  550. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.gz +0 -0
  551. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css +0 -1
  552. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
  553. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
  554. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css +0 -1
  555. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
  556. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
  557. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js +0 -1
  558. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.br +0 -0
  559. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.gz +0 -0
  560. codex/static_root/assets/browser-D0Vjmmp_.js +0 -1
  561. codex/static_root/assets/browser-D0Vjmmp_.js.br +0 -0
  562. codex/static_root/assets/browser-D0Vjmmp_.js.gz +0 -0
  563. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css +0 -1
  564. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.br +0 -0
  565. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.gz +0 -0
  566. codex/static_root/assets/browser-D7QQDneO.css +0 -1
  567. codex/static_root/assets/browser-D7QQDneO.css.br +0 -0
  568. codex/static_root/assets/browser-D7QQDneO.css.gz +0 -0
  569. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +0 -1
  570. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
  571. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
  572. codex/static_root/assets/change-password-dialog-0u6IJA87.css +0 -1
  573. codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
  574. codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
  575. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js +0 -1
  576. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.br +0 -0
  577. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.gz +0 -0
  578. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js +0 -1
  579. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.br +0 -0
  580. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.gz +0 -0
  581. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js +0 -1
  582. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.br +0 -0
  583. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.gz +0 -0
  584. codex/static_root/assets/confirm-dialog-DCKvg3ai.js +0 -1
  585. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.br +0 -0
  586. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.gz +0 -0
  587. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +0 -1
  588. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
  589. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +0 -1
  590. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
  591. codex/static_root/assets/datetime-column-DeCthByU.1f3bf499e063.css +0 -1
  592. codex/static_root/assets/datetime-column-DeCthByU.css +0 -1
  593. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js +0 -1
  594. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.br +0 -0
  595. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.gz +0 -0
  596. codex/static_root/assets/datetime-column-jHKA_uNm.js +0 -1
  597. codex/static_root/assets/datetime-column-jHKA_uNm.js.br +0 -0
  598. codex/static_root/assets/datetime-column-jHKA_uNm.js.gz +0 -0
  599. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js +0 -1
  600. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.br +0 -0
  601. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.gz +0 -0
  602. codex/static_root/assets/filter-DgPg2ts9.js +0 -1
  603. codex/static_root/assets/filter-DgPg2ts9.js.br +0 -0
  604. codex/static_root/assets/filter-DgPg2ts9.js.gz +0 -0
  605. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js +0 -1
  606. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.br +0 -0
  607. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.gz +0 -0
  608. codex/static_root/assets/flag-tab-9qxOALxP.js +0 -1
  609. codex/static_root/assets/flag-tab-9qxOALxP.js.br +0 -0
  610. codex/static_root/assets/flag-tab-9qxOALxP.js.gz +0 -0
  611. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +0 -1
  612. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
  613. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
  614. codex/static_root/assets/flag-tab-BNwbLfrN.css +0 -1
  615. codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
  616. codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
  617. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.br +0 -0
  618. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.gz +0 -0
  619. codex/static_root/assets/group-tab-D5vWrihT.js.br +0 -0
  620. codex/static_root/assets/group-tab-D5vWrihT.js.gz +0 -0
  621. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js +0 -1
  622. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.br +0 -0
  623. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.gz +0 -0
  624. codex/static_root/assets/http-error-B4FHoKfs.js +0 -1
  625. codex/static_root/assets/http-error-B4FHoKfs.js.br +0 -0
  626. codex/static_root/assets/http-error-B4FHoKfs.js.gz +0 -0
  627. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css +0 -1
  628. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.gz +0 -0
  629. codex/static_root/assets/http-error-DKulXuTl.css +0 -1
  630. codex/static_root/assets/http-error-DKulXuTl.css.gz +0 -0
  631. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css +0 -1
  632. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.br +0 -0
  633. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.gz +0 -0
  634. codex/static_root/assets/library-tab-BN0SfPcH.css +0 -1
  635. codex/static_root/assets/library-tab-BN0SfPcH.css.br +0 -0
  636. codex/static_root/assets/library-tab-BN0SfPcH.css.gz +0 -0
  637. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js +0 -1
  638. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.br +0 -0
  639. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.gz +0 -0
  640. codex/static_root/assets/library-tab-BWo0cmzk.js +0 -1
  641. codex/static_root/assets/library-tab-BWo0cmzk.js.br +0 -0
  642. codex/static_root/assets/library-tab-BWo0cmzk.js.gz +0 -0
  643. codex/static_root/assets/main-Ztp855PW.css.br +0 -0
  644. codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
  645. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js +0 -32
  646. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.br +0 -0
  647. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.gz +0 -0
  648. codex/static_root/assets/main-ipmlipkF.js +0 -32
  649. codex/static_root/assets/main-ipmlipkF.js.br +0 -0
  650. codex/static_root/assets/main-ipmlipkF.js.gz +0 -0
  651. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css +0 -1
  652. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.br +0 -0
  653. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.gz +0 -0
  654. codex/static_root/assets/pagination-toolbar-BA9ifTed.css +0 -1
  655. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.br +0 -0
  656. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.gz +0 -0
  657. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js +0 -1
  658. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.br +0 -0
  659. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.gz +0 -0
  660. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js +0 -1
  661. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.br +0 -0
  662. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.gz +0 -0
  663. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js +0 -305
  664. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.br +0 -0
  665. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.gz +0 -0
  666. codex/static_root/assets/pdf-doc-C2StaYUz.js +0 -305
  667. codex/static_root/assets/pdf-doc-C2StaYUz.js.br +0 -0
  668. codex/static_root/assets/pdf-doc-C2StaYUz.js.gz +0 -0
  669. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js +0 -2
  670. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.br +0 -0
  671. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.gz +0 -0
  672. codex/static_root/assets/reader-CCnq3j1-.js +0 -2
  673. codex/static_root/assets/reader-CCnq3j1-.js.br +0 -0
  674. codex/static_root/assets/reader-CCnq3j1-.js.gz +0 -0
  675. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css +0 -1
  676. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.br +0 -0
  677. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.gz +0 -0
  678. codex/static_root/assets/reader-CqXFa_gE.css +0 -1
  679. codex/static_root/assets/reader-CqXFa_gE.css.br +0 -0
  680. codex/static_root/assets/reader-CqXFa_gE.css.gz +0 -0
  681. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.br +0 -0
  682. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.gz +0 -0
  683. codex/static_root/assets/relation-chips-Bsc-gUxE.css.br +0 -0
  684. codex/static_root/assets/relation-chips-Bsc-gUxE.css.gz +0 -0
  685. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js +0 -1
  686. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.br +0 -0
  687. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.gz +0 -0
  688. codex/static_root/assets/relation-chips-C9ysW0tU.js +0 -1
  689. codex/static_root/assets/relation-chips-C9ysW0tU.js.br +0 -0
  690. codex/static_root/assets/relation-chips-C9ysW0tU.js.gz +0 -0
  691. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js +0 -2
  692. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.br +0 -0
  693. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.gz +0 -0
  694. codex/static_root/assets/settings-drawer-C0ofzAhW.js +0 -2
  695. codex/static_root/assets/settings-drawer-C0ofzAhW.js.br +0 -0
  696. codex/static_root/assets/settings-drawer-C0ofzAhW.js.gz +0 -0
  697. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css +0 -1
  698. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.br +0 -0
  699. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.gz +0 -0
  700. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css +0 -1
  701. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.br +0 -0
  702. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.gz +0 -0
  703. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +0 -1
  704. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  705. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  706. codex/static_root/assets/stats-tab-B4yKuY0c.css +0 -1
  707. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  708. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  709. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js +0 -1
  710. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.br +0 -0
  711. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.gz +0 -0
  712. codex/static_root/assets/stats-tab-BqJj7j1w.js +0 -1
  713. codex/static_root/assets/stats-tab-BqJj7j1w.js.br +0 -0
  714. codex/static_root/assets/stats-tab-BqJj7j1w.js.gz +0 -0
  715. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js +0 -1
  716. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.br +0 -0
  717. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.gz +0 -0
  718. codex/static_root/assets/task-tab-BsPzNk8S.js +0 -1
  719. codex/static_root/assets/task-tab-BsPzNk8S.js.br +0 -0
  720. codex/static_root/assets/task-tab-BsPzNk8S.js.gz +0 -0
  721. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js +0 -1
  722. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js.br +0 -0
  723. codex/static_root/assets/to-case-KvqtSug2.js +0 -1
  724. codex/static_root/assets/to-case-KvqtSug2.js.br +0 -0
  725. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
  726. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
  727. codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
  728. codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
  729. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js +0 -1
  730. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.br +0 -0
  731. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.gz +0 -0
  732. codex/static_root/assets/unauthorized-DwSdNzX2.js +0 -1
  733. codex/static_root/assets/unauthorized-DwSdNzX2.js.br +0 -0
  734. codex/static_root/assets/unauthorized-DwSdNzX2.js.gz +0 -0
  735. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js +0 -1
  736. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.br +0 -0
  737. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.gz +0 -0
  738. codex/static_root/assets/user-tab-DrJOb9Ys.js +0 -1
  739. codex/static_root/assets/user-tab-DrJOb9Ys.js.br +0 -0
  740. codex/static_root/assets/user-tab-DrJOb9Ys.js.gz +0 -0
  741. codex/static_root/js/choices-admin.3521e2a863df.json +0 -1
  742. codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
  743. codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
  744. codex/static_root/js/choices.2f6b0359e1ef.json +0 -1
  745. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  746. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  747. codex/static_root/manifest.1c84116d9a0a.json +0 -622
  748. codex/static_root/manifest.1c84116d9a0a.json.br +0 -0
  749. codex/static_root/manifest.1c84116d9a0a.json.gz +0 -0
  750. codex/util.py +0 -12
  751. codex/views/admin/auth.py +0 -28
  752. codex/views/browser/breadcrumbs.py +0 -202
  753. codex/views/browser/cover.py +0 -165
  754. codex/views/browser/mtime.py +0 -61
  755. codex/views/browser/order_by.py +0 -65
  756. codex/views/browser/paginate.py +0 -106
  757. codex/views/browser/settings.py +0 -66
  758. codex/views/browser/title.py +0 -48
  759. codex/views/browser/validate.py +0 -161
  760. codex/views/opds/auth.py +0 -17
  761. codex/views/public.py +0 -36
  762. codex/views/reader/arcs.py +0 -92
  763. codex/views/reader/books.py +0 -181
  764. codex/views/reader/init.py +0 -125
  765. codex/views/settings.py +0 -47
  766. codex/views/util.py +0 -77
  767. {codex-1.6.0.dist-info → codex-1.6.0a0.dist-info}/LICENSE +0 -0
  768. {codex-1.6.0.dist-info → codex-1.6.0a0.dist-info}/WHEEL +0 -0
  769. {codex-1.6.0.dist-info → codex-1.6.0a0.dist-info}/entry_points.txt +0 -0
@@ -1,48 +0,0 @@
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
- }
@@ -1,161 +0,0 @@
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/opds/auth.py DELETED
@@ -1,17 +0,0 @@
1
- """OPDS Authentican mixin."""
2
-
3
- from rest_framework.authentication import BasicAuthentication, SessionAuthentication
4
-
5
- from codex.views.auth import IsAuthenticatedOrEnabledNonUsers
6
- from codex.views.template import CodexXMLTemplateView
7
-
8
-
9
- class OPDSAuthMixin:
10
- """Add Basic Auth."""
11
-
12
- authentication_classes = (SessionAuthentication, BasicAuthentication)
13
- permission_classes = (IsAuthenticatedOrEnabledNonUsers,)
14
-
15
-
16
- class OPDSTemplateView(OPDSAuthMixin, CodexXMLTemplateView):
17
- """XML Template view with OPDSAuth."""
codex/views/public.py DELETED
@@ -1,36 +0,0 @@
1
- """Public non-authenticated views."""
2
-
3
- from rest_framework.generics import GenericAPIView
4
- from rest_framework.mixins import RetrieveModelMixin
5
-
6
- from codex.logger.logging import get_logger
7
- from codex.models import AdminFlag
8
- from codex.serializers.auth import AuthAdminFlagsSerializer
9
- from codex.serializers.choices import CHOICES
10
-
11
- LOG = get_logger(__name__)
12
- _ADMIN_FLAG_KEYS = frozenset(
13
- {
14
- AdminFlag.FlagChoices.NON_USERS.value,
15
- AdminFlag.FlagChoices.REGISTRATION.value,
16
- }
17
- )
18
-
19
-
20
- class AdminFlagsView(GenericAPIView, RetrieveModelMixin):
21
- """Get admin flags relevant to auth."""
22
-
23
- serializer_class = AuthAdminFlagsSerializer
24
- queryset = AdminFlag.objects.filter(key__in=_ADMIN_FLAG_KEYS).only("key", "on")
25
-
26
- def get_object(self):
27
- """Get admin flags."""
28
- flags = {}
29
- for obj in self.get_queryset(): # type: ignore
30
- name = CHOICES["admin"]["adminFlags"][obj.key].lower().replace(" ", "_")
31
- flags[name] = obj.on
32
- return flags
33
-
34
- def get(self, request, *args, **kwargs):
35
- """Get admin flags relevant to auth."""
36
- return self.retrieve(request, *args, **kwargs)
@@ -1,92 +0,0 @@
1
- """Reader get Arcs methods."""
2
-
3
- from types import MappingProxyType
4
-
5
- from codex.models import AdminFlag
6
- from codex.util import max_none
7
- from codex.views.const import FOLDER_GROUP, STORY_ARC_GROUP
8
- from codex.views.reader.books import ReaderBooksView
9
-
10
-
11
- class ReaderArcsView(ReaderBooksView):
12
- """Reader get Arcs methods."""
13
-
14
- def __init__(self, *args, **kwargs):
15
- """Initialize instance vars."""
16
- super().__init__(*args, **kwargs)
17
- self.params: MappingProxyType = MappingProxyType({})
18
-
19
- def _get_group_arc(self, book, attr):
20
- """Create the volume arc."""
21
- group = getattr(book, attr, None)
22
- if not group:
23
- return None
24
-
25
- _, arc_pks = self.get_group_pks_from_breadcrumbs([group])
26
- if group.pk not in arc_pks:
27
- arc_pks = (group.pk,)
28
- return {
29
- "group": attr[0],
30
- "pks": arc_pks,
31
- "name": group.name,
32
- "mtime": group.updated_at,
33
- }
34
-
35
- def _get_folder_arc(self, book):
36
- """Create the folder arc."""
37
- efv_flag = (
38
- AdminFlag.objects.only("on")
39
- .get(key=AdminFlag.FlagChoices.FOLDER_VIEW.value)
40
- .on
41
- )
42
- if not efv_flag:
43
- return None
44
-
45
- folder = book.parent_folder
46
- return {
47
- "group": FOLDER_GROUP,
48
- "pks": (folder.pk,),
49
- "name": folder.name,
50
- "mtime": folder.updated_at,
51
- }
52
-
53
- def _get_story_arcs(self, book):
54
- """Create story arcs."""
55
- sas = []
56
- for san in book.story_arc_numbers.all():
57
- sa = san.story_arc
58
- arc = {
59
- "group": "a",
60
- "pks": (sa.pk,),
61
- "name": sa.name,
62
- "mtime": sa.updated_at,
63
- }
64
- sas.append(arc)
65
- return sorted(sas, key=lambda x: x["name"])
66
-
67
- def get_arcs(self, book):
68
- """Get all series/folder/story arcs."""
69
- # create top arcs
70
- arcs = []
71
- top_group = self.params.get("top_group")
72
- arc = None
73
- if series_arc := self._get_group_arc(book, "series"):
74
- arcs.append(series_arc)
75
- arc = series_arc
76
- if volume_arc := self._get_group_arc(book, "volume"):
77
- arcs.append(volume_arc)
78
- if not arc:
79
- arc = volume_arc
80
- if folder_arc := self._get_folder_arc(book):
81
- arcs.append(folder_arc)
82
- if top_group == FOLDER_GROUP:
83
- arc = folder_arc
84
- if story_arcs := self._get_story_arcs(book):
85
- arcs = [*arcs, *story_arcs]
86
- if top_group == STORY_ARC_GROUP:
87
- arc = story_arcs[0]
88
-
89
- max_mtime = None
90
- for arc in arcs:
91
- max_mtime = max_none(max_mtime, arc["mtime"])
92
- return arcs, max_mtime
@@ -1,181 +0,0 @@
1
- """Get Books methods."""
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- from django.db.models import F
6
-
7
- from codex.models import Bookmark, Comic
8
- from codex.views.bookmark import BookmarkBaseView
9
- from codex.views.const import FOLDER_GROUP, NONE_INTEGERFIELD
10
- from codex.views.mixins import SharedAnnotationsMixin
11
- from codex.views.reader.init import ReaderInitView
12
-
13
- if TYPE_CHECKING:
14
- from collections.abc import Mapping
15
-
16
- _SETTINGS_ATTRS = ("fit_to", "two_pages", "reading_direction")
17
- _COMIC_FIELDS = (
18
- "file_type",
19
- "issue_number",
20
- "issue_suffix",
21
- "page_count",
22
- "series",
23
- "volume",
24
- "reading_direction",
25
- "updated_at",
26
- )
27
-
28
-
29
- class ReaderBooksView(BookmarkBaseView, ReaderInitView, SharedAnnotationsMixin):
30
- """Get Books methods."""
31
-
32
- def _get_reader_arc_pks( # noqa: PLR0913
33
- self, arc, arc_pk_select_related, prefetch_related, arc_pk_rel, arc_group
34
- ):
35
- """Get the nav filter."""
36
- if arc_pks := arc.get("pks", ()):
37
- return arc_pks
38
-
39
- comic_pk = self.kwargs["pk"]
40
- try:
41
- arc_pk_qs = Comic.objects.filter(pk=comic_pk)
42
- arc_pk_qs = arc_pk_qs.select_related(*arc_pk_select_related)
43
- arc_pk_qs = arc_pk_qs.prefetch_related(*prefetch_related)
44
- arc_pk_qs = arc_pk_qs.values_list(arc_pk_rel, flat=True)
45
- arc_pk = arc_pk_qs.first()
46
- except IndexError:
47
- arc_pk = 0
48
-
49
- _, multi_arc_pks = self.get_group_pks_from_breadcrumbs([arc_group])
50
- if not arc_pk or arc_pk in multi_arc_pks:
51
- arc_pks = multi_arc_pks
52
-
53
- if not arc_pks:
54
- arc_pks = (arc_pk,)
55
-
56
- return arc_pks
57
-
58
- def _get_comics_list(self):
59
- """Get the reader naviation group filter."""
60
- select_related = ("series", "volume")
61
- prefetch_related = ()
62
-
63
- arc: Mapping = self.params.get("arc", {}) # type: ignore
64
-
65
- arc_group = arc.get("group", "s")
66
- if arc_group == "a":
67
- # for story arcs
68
- rel = "story_arc_numbers__story_arc"
69
- fields = _COMIC_FIELDS
70
- arc_pk_rel = "story_arc_numbers__story_arc__pk"
71
- prefetch_related = (*prefetch_related, "story_arc_numbers__story_arc")
72
- arc_index = F("story_arc_numbers__number")
73
- ordering = ("arc_index", "date", "pk")
74
- arc_pk_select_related = ()
75
- elif arc_group == FOLDER_GROUP:
76
- # folder mode
77
- rel = "parent_folder"
78
- fields = (*_COMIC_FIELDS, "parent_folder")
79
- arc_pk_rel = "parent_folder__pk"
80
- arc_index = NONE_INTEGERFIELD
81
- ordering = ("path", "pk")
82
- arc_pk_select_related = ("parent_folder",)
83
- elif arc_group == "v":
84
- # volume
85
- rel = "volume"
86
- fields = _COMIC_FIELDS
87
- arc_pk_rel = "volume__pk"
88
- arc_index = NONE_INTEGERFIELD
89
- ordering = ()
90
- arc_pk_select_related = ("volume",)
91
- else:
92
- # series
93
- rel = "series"
94
- fields = _COMIC_FIELDS
95
- arc_pk_rel = "series__pk"
96
- arc_index = NONE_INTEGERFIELD
97
- ordering = ()
98
- arc_pk_select_related = ("series",)
99
-
100
- arc_pks = self._get_reader_arc_pks(
101
- arc, arc_pk_select_related, prefetch_related, arc_pk_rel, arc_group
102
- )
103
- nav_filter = {f"{rel}__in": arc_pks}
104
- group_acl_filter = self.get_group_acl_filter(Comic)
105
-
106
- qs = (
107
- Comic.objects.filter(group_acl_filter)
108
- .filter(**nav_filter)
109
- .select_related(*select_related)
110
- .prefetch_related(*prefetch_related)
111
- .only(*fields)
112
- .annotate(
113
- issue_count=F("volume__issue_count"),
114
- )
115
- .annotate(
116
- arc_pk=F(arc_pk_rel),
117
- arc_index=arc_index,
118
- )
119
- .annotate(mtime=F("updated_at"))
120
- )
121
- qs = self.annotate_group_names(qs, Comic)
122
- if arc_group in ("v", "s"):
123
- show = self.params["show"]
124
- model_group = "i" if arc_group == "s" else "s"
125
- qs, comic_sort_names = self.alias_sort_names(
126
- qs, Comic, pks=arc_pks, model_group=model_group, show=show
127
- )
128
- ordering = (
129
- *comic_sort_names,
130
- "issue_number",
131
- "issue_suffix",
132
- "sort_name",
133
- )
134
- qs = qs.order_by(*ordering)
135
- return qs, arc_group
136
-
137
- def _append_with_settings(self, book, bookmark_filter):
138
- """Append bookmark to book list."""
139
- book.settings = (
140
- Bookmark.objects.filter(**bookmark_filter, comic=book)
141
- .only(*_SETTINGS_ATTRS)
142
- .first()
143
- )
144
- return book
145
-
146
- def get_book_collection(self):
147
- """Get the -1, +1 window around the current issue.
148
-
149
- Uses iteration in python. There are some complicated ways of
150
- doing this with __gt[0] & __lt[0] in the db, but I think they
151
- might be even more expensive.
152
-
153
- Yields 1 to 3 books
154
- """
155
- comics, arc_group = self._get_comics_list()
156
- bookmark_filter = self.get_bookmark_search_kwargs()
157
- books = {}
158
- prev_book = None
159
- pk = self.kwargs.get("pk")
160
- for index, book in enumerate(comics):
161
- if books:
162
- # after match set next comic and break
163
- books["next"] = self._append_with_settings(book, bookmark_filter)
164
- break
165
- if book.pk == pk:
166
- # first match. set previous and current comic
167
- if prev_book:
168
- books["prev"] = self._append_with_settings(
169
- prev_book, bookmark_filter
170
- )
171
- # create extra current book attrs:
172
- if book.arc_index is None:
173
- book.arc_index = index + 1
174
- book.filename = book.get_filename()
175
- book.arc_group = arc_group
176
- book.arc_count = comics.count()
177
- books["current"] = self._append_with_settings(book, bookmark_filter)
178
- else:
179
- # Haven't matched yet, so set the previous comic
180
- prev_book = book
181
- return books
@@ -1,125 +0,0 @@
1
- """Views for reading comic books."""
2
-
3
- from copy import deepcopy
4
- from types import MappingProxyType
5
-
6
- from codex.logger.logging import get_logger
7
- from codex.models import Comic
8
- from codex.serializers.reader import (
9
- ReaderViewInputSerializer,
10
- )
11
- from codex.views.const import FOLDER_GROUP, GROUP_RELATION, STORY_ARC_GROUP
12
- from codex.views.session import SessionView
13
- from codex.views.util import reparse_json_query_params
14
-
15
- LOG = get_logger(__name__)
16
- VALID_ARC_GROUPS = frozenset({"s", "v", "f", "a"})
17
- _JSON_KEYS = frozenset({"arc", "breadcrumbs", "show"})
18
- _BROWSER_SESSION_DEFAULTS = SessionView.SESSION_DEFAULTS[
19
- SessionView.BROWSER_SESSION_KEY
20
- ]
21
- _DEFAULT_PARAMS = {
22
- "breadcrumbs": _BROWSER_SESSION_DEFAULTS["breadcrumbs"],
23
- "show": _BROWSER_SESSION_DEFAULTS["show"],
24
- "top_group": _BROWSER_SESSION_DEFAULTS["top_group"],
25
- }
26
-
27
-
28
- class ReaderInitView(SessionView):
29
- """Reader initialization."""
30
-
31
- input_serializer_class = ReaderViewInputSerializer
32
-
33
- def __init__(self, *args, **kwargs):
34
- """Initialize instance vars."""
35
- super().__init__(*args, **kwargs)
36
- self.group_pks: dict[str, tuple[int, ...]] = {}
37
-
38
- def _set_group_pks_from_breadcrumbs(self, groups, breadcrumbs):
39
- """Set Multi-Group pks from breadcrumbs to the cache."""
40
- index = len(breadcrumbs) - 1
41
- min_index = max(index - 1, 0) if FOLDER_GROUP in groups else 0
42
- while index > min_index:
43
- crumb = breadcrumbs[index]
44
- crumb_group = crumb.get("group")
45
- if crumb_group in groups:
46
- pks = crumb.get("pks", ())
47
- self.group_pks[crumb_group] = pks
48
- break
49
- index -= 1
50
- else:
51
- crumb_group = ""
52
- pks = ()
53
- for group in groups:
54
- self.group_pks[group] = pks
55
- return crumb_group, pks
56
-
57
- def get_group_pks_from_breadcrumbs(self, groups):
58
- """Get Multi-Group pks from the breadcrumbs."""
59
- # Return cached values
60
- for group in groups:
61
- if pks := self.group_pks.get(group):
62
- return group, pks
63
-
64
- # Validate input
65
- breadcrumbs: tuple = self.params.get("breadcrumbs") # type: ignore
66
- if not breadcrumbs:
67
- return "", ()
68
-
69
- return self._set_group_pks_from_breadcrumbs(groups, breadcrumbs)
70
-
71
- def _ensure_arc_contains_comic(self, params):
72
- """Arc sanity check."""
73
- arc = params.get("arc")
74
- if not arc:
75
- return
76
- pk = self.kwargs["pk"]
77
- arc_group = arc.get("group")
78
- arc_pks = arc.get("pks")
79
- valid = False
80
- if rel := GROUP_RELATION.get(arc_group):
81
- arc_filter = {rel: arc_pks}
82
- valid = Comic.objects.filter(pk=pk, **arc_filter).exists()
83
- if not valid:
84
- LOG.warning(f"Invalid arc {arc} submitted to reader for comic {pk}.")
85
- params.pop("arc", None)
86
-
87
- def _ensure_arc(self, params):
88
- """arc.group validation."""
89
- # Can't be in the serializer
90
- arc = params.get("arc", {})
91
-
92
- if arc.get("group") not in VALID_ARC_GROUPS:
93
- top_group = params["top_group"]
94
- if top_group in (FOLDER_GROUP, STORY_ARC_GROUP):
95
- search_groups = (top_group,)
96
- else:
97
- search_groups = ("v", "s")
98
-
99
- group, pks = self.get_group_pks_from_breadcrumbs(search_groups)
100
- if not group:
101
- group = "s"
102
-
103
- arc["group"] = group
104
- if pks:
105
- arc["pks"] = pks
106
-
107
- params["arc"] = arc
108
-
109
- def _parse_params(self):
110
- try:
111
- data = self.request.GET
112
- data = reparse_json_query_params(self.request.GET, _JSON_KEYS)
113
- serializer = self.input_serializer_class(data=data)
114
- serializer.is_valid(raise_exception=True)
115
-
116
- params = deepcopy(_DEFAULT_PARAMS)
117
- if serializer.validated_data:
118
- params.update(serializer.validated_data) # type: ignore
119
- self._ensure_arc_contains_comic(params)
120
- self._ensure_arc(params)
121
-
122
- self.params = MappingProxyType(params)
123
- except Exception:
124
- LOG.exception("validate")
125
- raise