codex 1.6.0__py3-none-any.whl → 1.6.0a1__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 (768) 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/query.py +2 -25
  48. codex/search/writing.py +1 -1
  49. codex/serializers/admin.py +44 -53
  50. codex/serializers/browser/choices.py +42 -37
  51. codex/serializers/browser/filters.py +131 -32
  52. codex/serializers/browser/metadata.py +1 -45
  53. codex/serializers/browser/mixins.py +4 -37
  54. codex/serializers/browser/page.py +6 -3
  55. codex/serializers/browser/settings.py +11 -42
  56. codex/serializers/choices.py +1 -14
  57. codex/serializers/models/pycountry.py +51 -11
  58. codex/serializers/opds/v2.py +16 -10
  59. codex/serializers/opds/v2_unused.py +3 -5
  60. codex/serializers/reader.py +7 -21
  61. codex/serializers/redirect.py +2 -3
  62. codex/serializers/route.py +7 -16
  63. codex/settings/settings.py +8 -23
  64. codex/startup.py +3 -77
  65. codex/static_root/assets/VCheckbox-u_aWQJA7.a0db8a7bd681.js +1 -0
  66. codex/static_root/assets/VCheckbox-u_aWQJA7.a0db8a7bd681.js.br +0 -0
  67. codex/static_root/assets/VCheckbox-u_aWQJA7.a0db8a7bd681.js.gz +0 -0
  68. codex/static_root/assets/VCheckbox-u_aWQJA7.js +1 -0
  69. codex/static_root/assets/VCheckbox-u_aWQJA7.js.br +0 -0
  70. codex/static_root/assets/VCheckbox-u_aWQJA7.js.gz +0 -0
  71. codex/static_root/assets/{VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js → VCheckboxBtn-yCN3TB6A.29d48d14ab3b.js} +1 -1
  72. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.29d48d14ab3b.js.br +0 -0
  73. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.29d48d14ab3b.js.gz +0 -0
  74. codex/static_root/assets/{VCheckboxBtn-DxNOKONG.js → VCheckboxBtn-yCN3TB6A.js} +1 -1
  75. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.js.br +0 -0
  76. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.js.gz +0 -0
  77. codex/static_root/assets/VCombobox-dsIKbjps.d3c8da1d75b3.js +1 -0
  78. codex/static_root/assets/VCombobox-dsIKbjps.d3c8da1d75b3.js.br +0 -0
  79. codex/static_root/assets/VCombobox-dsIKbjps.d3c8da1d75b3.js.gz +0 -0
  80. codex/static_root/assets/VCombobox-dsIKbjps.js +1 -0
  81. codex/static_root/assets/VCombobox-dsIKbjps.js.br +0 -0
  82. codex/static_root/assets/VCombobox-dsIKbjps.js.gz +0 -0
  83. codex/static_root/assets/VDialog-BNHg8txZ.21bed7754d3a.js +1 -0
  84. codex/static_root/assets/VDialog-BNHg8txZ.21bed7754d3a.js.br +0 -0
  85. codex/static_root/assets/VDialog-BNHg8txZ.21bed7754d3a.js.gz +0 -0
  86. codex/static_root/assets/VDialog-BNHg8txZ.js +1 -0
  87. codex/static_root/assets/VDialog-BNHg8txZ.js.br +0 -0
  88. codex/static_root/assets/VDialog-BNHg8txZ.js.gz +0 -0
  89. codex/static_root/assets/{VDialog-lQ13FnRR.1c801ad756b2.css → VDialog-C5Nxd_zP.css} +1 -1
  90. codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
  91. codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
  92. codex/static_root/assets/{VDialog-lQ13FnRR.css → VDialog-C5Nxd_zP.d327f505ef0e.css} +1 -1
  93. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
  94. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
  95. codex/static_root/assets/VExpansionPanels-CX4W4vZK.8e90fe0b34f4.js +1 -0
  96. codex/static_root/assets/VExpansionPanels-CX4W4vZK.8e90fe0b34f4.js.br +0 -0
  97. codex/static_root/assets/VExpansionPanels-CX4W4vZK.8e90fe0b34f4.js.gz +0 -0
  98. codex/static_root/assets/VExpansionPanels-CX4W4vZK.js +1 -0
  99. codex/static_root/assets/VExpansionPanels-CX4W4vZK.js.br +0 -0
  100. codex/static_root/assets/VExpansionPanels-CX4W4vZK.js.gz +0 -0
  101. codex/static_root/assets/VRadioGroup-jCr3CAsk.685daccd04d8.js +1 -0
  102. codex/static_root/assets/VRadioGroup-jCr3CAsk.685daccd04d8.js.br +0 -0
  103. codex/static_root/assets/VRadioGroup-jCr3CAsk.685daccd04d8.js.gz +0 -0
  104. codex/static_root/assets/VRadioGroup-jCr3CAsk.js +1 -0
  105. codex/static_root/assets/VRadioGroup-jCr3CAsk.js.br +0 -0
  106. codex/static_root/assets/VRadioGroup-jCr3CAsk.js.gz +0 -0
  107. codex/static_root/assets/VSelect--XHNpxvB.ff050ef0d6de.js +1 -0
  108. codex/static_root/assets/VSelect--XHNpxvB.ff050ef0d6de.js.br +0 -0
  109. codex/static_root/assets/VSelect--XHNpxvB.ff050ef0d6de.js.gz +0 -0
  110. codex/static_root/assets/VSelect--XHNpxvB.js +1 -0
  111. codex/static_root/assets/VSelect--XHNpxvB.js.br +0 -0
  112. codex/static_root/assets/VSelect--XHNpxvB.js.gz +0 -0
  113. codex/static_root/assets/VSelectionControl-CVIKc_ra.0b2cc426e8b8.js +1 -0
  114. codex/static_root/assets/VSelectionControl-CVIKc_ra.0b2cc426e8b8.js.br +0 -0
  115. codex/static_root/assets/VSelectionControl-CVIKc_ra.0b2cc426e8b8.js.gz +0 -0
  116. codex/static_root/assets/VSelectionControl-CVIKc_ra.js +1 -0
  117. codex/static_root/assets/VSelectionControl-CVIKc_ra.js.br +0 -0
  118. codex/static_root/assets/VSelectionControl-CVIKc_ra.js.gz +0 -0
  119. codex/static_root/assets/VSlideGroup-CZw5_eNv.7ae5182e5988.js +1 -0
  120. codex/static_root/assets/VSlideGroup-CZw5_eNv.7ae5182e5988.js.br +0 -0
  121. codex/static_root/assets/VSlideGroup-CZw5_eNv.7ae5182e5988.js.gz +0 -0
  122. codex/static_root/assets/VSlideGroup-CZw5_eNv.js +1 -0
  123. codex/static_root/assets/VSlideGroup-CZw5_eNv.js.br +0 -0
  124. codex/static_root/assets/VSlideGroup-CZw5_eNv.js.gz +0 -0
  125. codex/static_root/assets/{VTable-2RHFqfg6.f0f2106b158b.js → VTable-hGJDFK5t.d2f84d68747b.js} +1 -1
  126. codex/static_root/assets/VTable-hGJDFK5t.d2f84d68747b.js.br +0 -0
  127. codex/static_root/assets/VTable-hGJDFK5t.d2f84d68747b.js.gz +0 -0
  128. codex/static_root/assets/{VTable-2RHFqfg6.js → VTable-hGJDFK5t.js} +1 -1
  129. codex/static_root/assets/VTable-hGJDFK5t.js.br +0 -0
  130. codex/static_root/assets/VTable-hGJDFK5t.js.gz +0 -0
  131. codex/static_root/assets/VTextField-C8y3lyz9.eb58405614ad.js +1 -0
  132. codex/static_root/assets/VTextField-C8y3lyz9.eb58405614ad.js.br +0 -0
  133. codex/static_root/assets/VTextField-C8y3lyz9.eb58405614ad.js.gz +0 -0
  134. codex/static_root/assets/VTextField-C8y3lyz9.js +1 -0
  135. codex/static_root/assets/VTextField-C8y3lyz9.js.br +0 -0
  136. codex/static_root/assets/VTextField-C8y3lyz9.js.gz +0 -0
  137. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css +1 -0
  138. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.br +0 -0
  139. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.gz +0 -0
  140. codex/static_root/assets/VTextField-DuIIp-VY.css +1 -0
  141. codex/static_root/assets/VTextField-DuIIp-VY.css.br +0 -0
  142. codex/static_root/assets/VTextField-DuIIp-VY.css.gz +0 -0
  143. codex/static_root/assets/VWindowItem-BHpZIa_r.2b3c5f9594e6.js +1 -0
  144. codex/static_root/assets/VWindowItem-BHpZIa_r.2b3c5f9594e6.js.br +0 -0
  145. codex/static_root/assets/VWindowItem-BHpZIa_r.2b3c5f9594e6.js.gz +0 -0
  146. codex/static_root/assets/VWindowItem-BHpZIa_r.js +1 -0
  147. codex/static_root/assets/VWindowItem-BHpZIa_r.js.br +0 -0
  148. codex/static_root/assets/VWindowItem-BHpZIa_r.js.gz +0 -0
  149. codex/static_root/assets/{admin-B8Bp2Uih.82c98714bcf1.css → admin-BbrOU9Y9.29936748af9e.css} +1 -1
  150. codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.br +0 -0
  151. codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.gz +0 -0
  152. codex/static_root/assets/{admin-B8Bp2Uih.css → admin-BbrOU9Y9.css} +1 -1
  153. codex/static_root/assets/admin-BbrOU9Y9.css.br +0 -0
  154. codex/static_root/assets/admin-BbrOU9Y9.css.gz +0 -0
  155. codex/static_root/assets/admin-Bvd-SvGS.412e5b1b7ed1.js +1 -0
  156. codex/static_root/assets/admin-Bvd-SvGS.412e5b1b7ed1.js.br +0 -0
  157. codex/static_root/assets/admin-Bvd-SvGS.412e5b1b7ed1.js.gz +0 -0
  158. codex/static_root/assets/admin-Bvd-SvGS.js +1 -0
  159. codex/static_root/assets/admin-Bvd-SvGS.js.br +0 -0
  160. codex/static_root/assets/admin-Bvd-SvGS.js.gz +0 -0
  161. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css +1 -0
  162. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.br +0 -0
  163. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.gz +0 -0
  164. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css +1 -0
  165. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.br +0 -0
  166. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.gz +0 -0
  167. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.059e3bde9568.js +30 -0
  168. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.059e3bde9568.js.br +0 -0
  169. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.059e3bde9568.js.gz +0 -0
  170. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.js +30 -0
  171. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.js.br +0 -0
  172. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.js.gz +0 -0
  173. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css +1 -0
  174. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css.br +0 -0
  175. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css.gz +0 -0
  176. codex/static_root/assets/browser-CZeVqRNy.css +1 -0
  177. codex/static_root/assets/browser-CZeVqRNy.css.br +0 -0
  178. codex/static_root/assets/browser-CZeVqRNy.css.gz +0 -0
  179. codex/static_root/assets/browser-rc5ObkeN.0c1f38d229ac.js +1 -0
  180. codex/static_root/assets/browser-rc5ObkeN.0c1f38d229ac.js.br +0 -0
  181. codex/static_root/assets/browser-rc5ObkeN.0c1f38d229ac.js.gz +0 -0
  182. codex/static_root/assets/browser-rc5ObkeN.js +1 -0
  183. codex/static_root/assets/browser-rc5ObkeN.js.br +0 -0
  184. codex/static_root/assets/browser-rc5ObkeN.js.gz +0 -0
  185. codex/static_root/assets/change-password-dialog-CRHk2tjq.d4d4b5945cd4.js +1 -0
  186. codex/static_root/assets/change-password-dialog-CRHk2tjq.d4d4b5945cd4.js.br +0 -0
  187. codex/static_root/assets/change-password-dialog-CRHk2tjq.d4d4b5945cd4.js.gz +0 -0
  188. codex/static_root/assets/change-password-dialog-CRHk2tjq.js +1 -0
  189. codex/static_root/assets/change-password-dialog-CRHk2tjq.js.br +0 -0
  190. codex/static_root/assets/change-password-dialog-CRHk2tjq.js.gz +0 -0
  191. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +1 -0
  192. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
  193. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
  194. codex/static_root/assets/change-password-dialog-HvIvmmIE.css +1 -0
  195. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
  196. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
  197. codex/static_root/assets/confirm-dialog-DnHKM44R.d57a0196ac5a.js +1 -0
  198. codex/static_root/assets/confirm-dialog-DnHKM44R.d57a0196ac5a.js.br +0 -0
  199. codex/static_root/assets/confirm-dialog-DnHKM44R.d57a0196ac5a.js.gz +0 -0
  200. codex/static_root/assets/confirm-dialog-DnHKM44R.js +1 -0
  201. codex/static_root/assets/confirm-dialog-DnHKM44R.js.br +0 -0
  202. codex/static_root/assets/confirm-dialog-DnHKM44R.js.gz +0 -0
  203. codex/static_root/assets/datetime-column-BEqDvdeI.44b65455a2c3.js +1 -0
  204. codex/static_root/assets/datetime-column-BEqDvdeI.44b65455a2c3.js.br +0 -0
  205. codex/static_root/assets/datetime-column-BEqDvdeI.44b65455a2c3.js.gz +0 -0
  206. codex/static_root/assets/datetime-column-BEqDvdeI.js +1 -0
  207. codex/static_root/assets/datetime-column-BEqDvdeI.js.br +0 -0
  208. codex/static_root/assets/datetime-column-BEqDvdeI.js.gz +0 -0
  209. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css +1 -0
  210. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css.br +0 -0
  211. codex/static_root/assets/datetime-column-Dg_RxTVM.css +1 -0
  212. codex/static_root/assets/datetime-column-Dg_RxTVM.css.br +0 -0
  213. codex/static_root/assets/filter-_wYL6jQC.dbc7d7e7b855.js +1 -0
  214. codex/static_root/assets/filter-_wYL6jQC.dbc7d7e7b855.js.br +0 -0
  215. codex/static_root/assets/filter-_wYL6jQC.dbc7d7e7b855.js.gz +0 -0
  216. codex/static_root/assets/filter-_wYL6jQC.js +1 -0
  217. codex/static_root/assets/filter-_wYL6jQC.js.br +0 -0
  218. codex/static_root/assets/filter-_wYL6jQC.js.gz +0 -0
  219. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css +1 -0
  220. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.br +0 -0
  221. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.gz +0 -0
  222. codex/static_root/assets/flag-tab-BacZLlVi.css +1 -0
  223. codex/static_root/assets/flag-tab-BacZLlVi.css.br +0 -0
  224. codex/static_root/assets/flag-tab-BacZLlVi.css.gz +0 -0
  225. codex/static_root/assets/flag-tab-Dpyvhwb_.2812bd46db2d.js +1 -0
  226. codex/static_root/assets/flag-tab-Dpyvhwb_.2812bd46db2d.js.br +0 -0
  227. codex/static_root/assets/flag-tab-Dpyvhwb_.2812bd46db2d.js.gz +0 -0
  228. codex/static_root/assets/flag-tab-Dpyvhwb_.js +1 -0
  229. codex/static_root/assets/flag-tab-Dpyvhwb_.js.br +0 -0
  230. codex/static_root/assets/flag-tab-Dpyvhwb_.js.gz +0 -0
  231. codex/static_root/assets/{group-tab-D5vWrihT.1afb2ce453ff.js → group-tab-DAjvuSUO.4494d4846fa6.js} +1 -1
  232. codex/static_root/assets/group-tab-DAjvuSUO.4494d4846fa6.js.br +0 -0
  233. codex/static_root/assets/group-tab-DAjvuSUO.4494d4846fa6.js.gz +0 -0
  234. codex/static_root/assets/{group-tab-D5vWrihT.js → group-tab-DAjvuSUO.js} +1 -1
  235. codex/static_root/assets/group-tab-DAjvuSUO.js.br +0 -0
  236. codex/static_root/assets/group-tab-DAjvuSUO.js.gz +0 -0
  237. codex/static_root/assets/http-error-CDQ-296a.6ea61686beb8.js +1 -0
  238. codex/static_root/assets/http-error-CDQ-296a.6ea61686beb8.js.br +0 -0
  239. codex/static_root/assets/http-error-CDQ-296a.6ea61686beb8.js.gz +0 -0
  240. codex/static_root/assets/http-error-CDQ-296a.js +1 -0
  241. codex/static_root/assets/http-error-CDQ-296a.js.br +0 -0
  242. codex/static_root/assets/http-error-CDQ-296a.js.gz +0 -0
  243. codex/static_root/assets/http-error-_wlDqEcp.5b78d3e332c9.css +1 -0
  244. codex/static_root/assets/{http-error-DKulXuTl.95e42988d5d5.css.br → http-error-_wlDqEcp.5b78d3e332c9.css.br} +0 -0
  245. codex/static_root/assets/http-error-_wlDqEcp.5b78d3e332c9.css.gz +0 -0
  246. codex/static_root/assets/http-error-_wlDqEcp.css +1 -0
  247. codex/static_root/assets/{http-error-DKulXuTl.css.br → http-error-_wlDqEcp.css.br} +0 -0
  248. codex/static_root/assets/http-error-_wlDqEcp.css.gz +0 -0
  249. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +1 -0
  250. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
  251. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
  252. codex/static_root/assets/index-DUjeNg4x.js +1 -0
  253. codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
  254. codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
  255. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css +1 -0
  256. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.br +2 -0
  257. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.gz +0 -0
  258. codex/static_root/assets/library-tab-CXbkxNZt.css +1 -0
  259. codex/static_root/assets/library-tab-CXbkxNZt.css.br +2 -0
  260. codex/static_root/assets/library-tab-CXbkxNZt.css.gz +0 -0
  261. codex/static_root/assets/library-tab-LsexSRi2.34b88bbbfcdc.js +1 -0
  262. codex/static_root/assets/library-tab-LsexSRi2.34b88bbbfcdc.js.br +0 -0
  263. codex/static_root/assets/library-tab-LsexSRi2.34b88bbbfcdc.js.gz +0 -0
  264. codex/static_root/assets/library-tab-LsexSRi2.js +1 -0
  265. codex/static_root/assets/library-tab-LsexSRi2.js.br +0 -0
  266. codex/static_root/assets/library-tab-LsexSRi2.js.gz +0 -0
  267. codex/static_root/assets/main-CjPnwTfF.0f333ec81a42.js +32 -0
  268. codex/static_root/assets/main-CjPnwTfF.0f333ec81a42.js.br +0 -0
  269. codex/static_root/assets/main-CjPnwTfF.0f333ec81a42.js.gz +0 -0
  270. codex/static_root/assets/main-CjPnwTfF.js +32 -0
  271. codex/static_root/assets/main-CjPnwTfF.js.br +0 -0
  272. codex/static_root/assets/main-CjPnwTfF.js.gz +0 -0
  273. codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css → main-sK7HC5h4.6f04ddfc5f1a.css} +1 -1
  274. codex/static_root/assets/main-sK7HC5h4.6f04ddfc5f1a.css.br +0 -0
  275. codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css.gz → main-sK7HC5h4.6f04ddfc5f1a.css.gz} +0 -0
  276. codex/static_root/assets/{main-Ztp855PW.css → main-sK7HC5h4.css} +1 -1
  277. codex/static_root/assets/main-sK7HC5h4.css.br +0 -0
  278. codex/static_root/assets/{main-Ztp855PW.css.gz → main-sK7HC5h4.css.gz} +0 -0
  279. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css +1 -0
  280. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.br +0 -0
  281. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.gz +0 -0
  282. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css +1 -0
  283. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.br +0 -0
  284. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.gz +0 -0
  285. codex/static_root/assets/pagination-toolbar-B955aa-d.3fd9249f7342.js +1 -0
  286. codex/static_root/assets/pagination-toolbar-B955aa-d.3fd9249f7342.js.br +0 -0
  287. codex/static_root/assets/pagination-toolbar-B955aa-d.3fd9249f7342.js.gz +0 -0
  288. codex/static_root/assets/pagination-toolbar-B955aa-d.js +1 -0
  289. codex/static_root/assets/pagination-toolbar-B955aa-d.js.br +0 -0
  290. codex/static_root/assets/pagination-toolbar-B955aa-d.js.gz +0 -0
  291. codex/static_root/assets/pdf-doc-DPDmmEEp.74cab27a76e1.js +35 -0
  292. codex/static_root/assets/pdf-doc-DPDmmEEp.74cab27a76e1.js.br +0 -0
  293. codex/static_root/assets/pdf-doc-DPDmmEEp.74cab27a76e1.js.gz +0 -0
  294. codex/static_root/assets/pdf-doc-DPDmmEEp.js +35 -0
  295. codex/static_root/assets/pdf-doc-DPDmmEEp.js.br +0 -0
  296. codex/static_root/assets/pdf-doc-DPDmmEEp.js.gz +0 -0
  297. codex/static_root/assets/reader-BuMh4x3f.f4d7f1c97387.js +2 -0
  298. codex/static_root/assets/reader-BuMh4x3f.f4d7f1c97387.js.br +0 -0
  299. codex/static_root/assets/reader-BuMh4x3f.f4d7f1c97387.js.gz +0 -0
  300. codex/static_root/assets/reader-BuMh4x3f.js +2 -0
  301. codex/static_root/assets/reader-BuMh4x3f.js.br +0 -0
  302. codex/static_root/assets/reader-BuMh4x3f.js.gz +0 -0
  303. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css +1 -0
  304. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css.br +0 -0
  305. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css.gz +0 -0
  306. codex/static_root/assets/reader-Dspy46e8.css +1 -0
  307. codex/static_root/assets/reader-Dspy46e8.css.br +0 -0
  308. codex/static_root/assets/reader-Dspy46e8.css.gz +0 -0
  309. codex/static_root/assets/{relation-chips-Bsc-gUxE.98e65384c3c9.css → relation-chips-D6T6FX7G.css} +1 -1
  310. codex/static_root/assets/relation-chips-D6T6FX7G.css.br +0 -0
  311. codex/static_root/assets/relation-chips-D6T6FX7G.css.gz +0 -0
  312. codex/static_root/assets/{relation-chips-Bsc-gUxE.css → relation-chips-D6T6FX7G.db095b2497e4.css} +1 -1
  313. codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.br +0 -0
  314. codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.gz +0 -0
  315. codex/static_root/assets/relation-chips-DN_pPmnS.684c4eae4bdb.js +1 -0
  316. codex/static_root/assets/relation-chips-DN_pPmnS.684c4eae4bdb.js.br +0 -0
  317. codex/static_root/assets/relation-chips-DN_pPmnS.684c4eae4bdb.js.gz +0 -0
  318. codex/static_root/assets/relation-chips-DN_pPmnS.js +1 -0
  319. codex/static_root/assets/relation-chips-DN_pPmnS.js.br +0 -0
  320. codex/static_root/assets/relation-chips-DN_pPmnS.js.gz +0 -0
  321. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css +1 -0
  322. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css.br +0 -0
  323. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css.gz +0 -0
  324. codex/static_root/assets/settings-drawer-BgUazs7O.css +1 -0
  325. codex/static_root/assets/settings-drawer-BgUazs7O.css.br +0 -0
  326. codex/static_root/assets/settings-drawer-BgUazs7O.css.gz +0 -0
  327. codex/static_root/assets/settings-drawer-D4FgDG4z.de28fd4ce82a.js +2 -0
  328. codex/static_root/assets/settings-drawer-D4FgDG4z.de28fd4ce82a.js.br +0 -0
  329. codex/static_root/assets/settings-drawer-D4FgDG4z.de28fd4ce82a.js.gz +0 -0
  330. codex/static_root/assets/settings-drawer-D4FgDG4z.js +2 -0
  331. codex/static_root/assets/settings-drawer-D4FgDG4z.js.br +0 -0
  332. codex/static_root/assets/settings-drawer-D4FgDG4z.js.gz +0 -0
  333. codex/static_root/assets/stats-tab-AwbCeW63.a95f7d9b2059.js +1 -0
  334. codex/static_root/assets/stats-tab-AwbCeW63.a95f7d9b2059.js.br +0 -0
  335. codex/static_root/assets/stats-tab-AwbCeW63.a95f7d9b2059.js.gz +0 -0
  336. codex/static_root/assets/stats-tab-AwbCeW63.js +1 -0
  337. codex/static_root/assets/stats-tab-AwbCeW63.js.br +0 -0
  338. codex/static_root/assets/stats-tab-AwbCeW63.js.gz +0 -0
  339. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +1 -0
  340. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +2 -0
  341. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
  342. codex/static_root/assets/stats-tab-TsyG3wH_.css +1 -0
  343. codex/static_root/assets/stats-tab-TsyG3wH_.css.br +2 -0
  344. codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
  345. codex/static_root/assets/task-tab-DeHQTHuz.5f967defca9f.js +1 -0
  346. codex/static_root/assets/task-tab-DeHQTHuz.5f967defca9f.js.br +0 -0
  347. codex/static_root/assets/task-tab-DeHQTHuz.5f967defca9f.js.gz +0 -0
  348. codex/static_root/assets/task-tab-DeHQTHuz.js +1 -0
  349. codex/static_root/assets/task-tab-DeHQTHuz.js.br +0 -0
  350. codex/static_root/assets/task-tab-DeHQTHuz.js.gz +0 -0
  351. codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +1 -0
  352. codex/static_root/assets/to-case-kUm8NPpW.js +1 -0
  353. codex/static_root/assets/unauthorized-BXCbvRsL.bc44d7ba68b3.js +1 -0
  354. codex/static_root/assets/unauthorized-BXCbvRsL.bc44d7ba68b3.js.br +0 -0
  355. codex/static_root/assets/unauthorized-BXCbvRsL.bc44d7ba68b3.js.gz +0 -0
  356. codex/static_root/assets/unauthorized-BXCbvRsL.js +1 -0
  357. codex/static_root/assets/unauthorized-BXCbvRsL.js.br +0 -0
  358. codex/static_root/assets/unauthorized-BXCbvRsL.js.gz +0 -0
  359. codex/static_root/assets/{unauthorized-CibJYD8o.4c2de98c2b53.css → unauthorized-DWgytUow.ca2f13dbdbf5.css} +1 -1
  360. codex/static_root/assets/unauthorized-DWgytUow.ca2f13dbdbf5.css.br +0 -0
  361. codex/static_root/assets/unauthorized-DWgytUow.ca2f13dbdbf5.css.gz +0 -0
  362. codex/static_root/assets/{unauthorized-CibJYD8o.css → unauthorized-DWgytUow.css} +1 -1
  363. codex/static_root/assets/unauthorized-DWgytUow.css.br +0 -0
  364. codex/static_root/assets/unauthorized-DWgytUow.css.gz +0 -0
  365. codex/static_root/assets/user-tab-Dq4qYzgp.5d1b6c07edd0.js +1 -0
  366. codex/static_root/assets/user-tab-Dq4qYzgp.5d1b6c07edd0.js.br +0 -0
  367. codex/static_root/assets/user-tab-Dq4qYzgp.5d1b6c07edd0.js.gz +0 -0
  368. codex/static_root/assets/user-tab-Dq4qYzgp.js +1 -0
  369. codex/static_root/assets/user-tab-Dq4qYzgp.js.br +0 -0
  370. codex/static_root/assets/user-tab-Dq4qYzgp.js.gz +0 -0
  371. codex/static_root/js/choices-admin.248384ece3f6.json +1 -0
  372. codex/static_root/js/choices-admin.248384ece3f6.json.br +0 -0
  373. codex/static_root/js/choices-admin.248384ece3f6.json.gz +0 -0
  374. codex/static_root/js/choices-admin.json +1 -1
  375. codex/static_root/js/choices-admin.json.br +0 -0
  376. codex/static_root/js/choices-admin.json.gz +0 -0
  377. codex/static_root/js/choices.b60817ba0a93.json +1 -0
  378. codex/static_root/js/choices.b60817ba0a93.json.br +0 -0
  379. codex/static_root/js/choices.b60817ba0a93.json.gz +0 -0
  380. codex/static_root/js/choices.json +1 -1
  381. codex/static_root/js/choices.json.br +0 -0
  382. codex/static_root/js/choices.json.gz +0 -0
  383. codex/static_root/manifest.b5fe5d7ef44e.json +641 -0
  384. codex/static_root/manifest.b5fe5d7ef44e.json.br +0 -0
  385. codex/static_root/manifest.b5fe5d7ef44e.json.gz +0 -0
  386. codex/static_root/manifest.json +298 -279
  387. codex/static_root/manifest.json.br +0 -0
  388. codex/static_root/manifest.json.gz +0 -0
  389. codex/static_root/staticfiles.json +1 -1
  390. codex/status_controller.py +2 -11
  391. codex/urls/api/auth.py +1 -2
  392. codex/urls/api/browser.py +4 -13
  393. codex/urls/api/reader.py +9 -3
  394. codex/urls/api/v3.py +0 -2
  395. codex/urls/opds/binary.py +1 -1
  396. codex/views/admin/api_key.py +8 -7
  397. codex/views/admin/flag.py +7 -2
  398. codex/views/admin/group.py +6 -2
  399. codex/views/admin/library.py +37 -44
  400. codex/views/admin/stats.py +83 -20
  401. codex/views/admin/tasks.py +12 -26
  402. codex/views/admin/user.py +9 -3
  403. codex/views/auth.py +54 -31
  404. codex/views/bookmark.py +72 -92
  405. codex/views/browser/base.py +90 -42
  406. codex/views/browser/browser.py +371 -92
  407. codex/views/browser/{annotations.py → browser_annotations.py} +121 -67
  408. codex/views/browser/browser_breadcrumbs.py +175 -0
  409. codex/views/browser/browser_order_by.py +63 -0
  410. codex/views/browser/choices.py +85 -38
  411. codex/views/browser/const.py +3 -0
  412. codex/views/browser/filters/annotations.py +19 -87
  413. codex/views/browser/filters/bookmark.py +12 -24
  414. codex/views/browser/filters/field.py +6 -8
  415. codex/views/browser/filters/group.py +14 -35
  416. codex/views/browser/filters/search.py +20 -31
  417. codex/views/browser/metadata.py +73 -112
  418. codex/views/browser/session.py +12 -0
  419. codex/views/const.py +0 -140
  420. codex/views/cover.py +77 -0
  421. codex/views/download.py +8 -5
  422. codex/views/frontend.py +2 -4
  423. codex/views/opds/authentication_v1.py +45 -46
  424. codex/views/opds/binary.py +10 -5
  425. codex/views/opds/const.py +0 -13
  426. codex/views/opds/urls.py +4 -6
  427. codex/views/opds/util.py +12 -4
  428. codex/views/opds/v1/entry/links.py +33 -18
  429. codex/views/opds/v1/facets.py +7 -7
  430. codex/views/opds/v1/feed.py +45 -55
  431. codex/views/opds/v1/links.py +5 -7
  432. codex/views/opds/v1/opensearch_v1.py +6 -2
  433. codex/views/opds/v2/feed.py +26 -25
  434. codex/views/opds/v2/links.py +2 -4
  435. codex/views/opds/v2/publications.py +54 -34
  436. codex/views/opds/v2/top_links.py +2 -2
  437. codex/views/reader/page.py +8 -15
  438. codex/views/reader/reader.py +322 -19
  439. codex/views/reader/{settings.py → session.py} +2 -4
  440. codex/views/session.py +102 -83
  441. codex/views/template.py +3 -3
  442. codex/views/version.py +2 -2
  443. codex/websockets/consumers.py +10 -14
  444. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/METADATA +15 -22
  445. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/RECORD +448 -466
  446. codex/librarian/importer/cache.py +0 -93
  447. codex/librarian/importer/create_covers.py +0 -96
  448. codex/librarian/importer/importer.py +0 -96
  449. codex/librarian/importer/init.py +0 -265
  450. codex/librarian/importer/link_covers.py +0 -73
  451. codex/librarian/importer/query_covers.py +0 -52
  452. codex/migrations/0027_import_order_and_covers.py +0 -280
  453. codex/serializers/browser/mtime.py +0 -21
  454. codex/serializers/fields.py +0 -149
  455. codex/serializers/settings.py +0 -12
  456. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js +0 -1
  457. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.br +0 -0
  458. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.gz +0 -0
  459. codex/static_root/assets/VCheckbox-DanrzdHo.js +0 -1
  460. codex/static_root/assets/VCheckbox-DanrzdHo.js.br +0 -0
  461. codex/static_root/assets/VCheckbox-DanrzdHo.js.gz +0 -0
  462. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.br +0 -0
  463. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.gz +0 -0
  464. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.br +0 -0
  465. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.gz +0 -0
  466. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js +0 -1
  467. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.br +0 -0
  468. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.gz +0 -0
  469. codex/static_root/assets/VCombobox-DDvdoPTG.js +0 -1
  470. codex/static_root/assets/VCombobox-DDvdoPTG.js.br +0 -0
  471. codex/static_root/assets/VCombobox-DDvdoPTG.js.gz +0 -0
  472. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js +0 -1
  473. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.br +0 -0
  474. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.gz +0 -0
  475. codex/static_root/assets/VDialog-Bd5dN_E1.js +0 -1
  476. codex/static_root/assets/VDialog-Bd5dN_E1.js.br +0 -0
  477. codex/static_root/assets/VDialog-Bd5dN_E1.js.gz +0 -0
  478. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
  479. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
  480. codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
  481. codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
  482. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js +0 -1
  483. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.br +0 -0
  484. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.gz +0 -0
  485. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js +0 -1
  486. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.br +0 -0
  487. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.gz +0 -0
  488. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js +0 -1
  489. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.br +0 -0
  490. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.gz +0 -0
  491. codex/static_root/assets/VRadioGroup-DKb8XPr-.js +0 -1
  492. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.br +0 -0
  493. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.gz +0 -0
  494. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js +0 -1
  495. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.br +0 -0
  496. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.gz +0 -0
  497. codex/static_root/assets/VSelect-C_yPbyCG.js +0 -1
  498. codex/static_root/assets/VSelect-C_yPbyCG.js.br +0 -0
  499. codex/static_root/assets/VSelect-C_yPbyCG.js.gz +0 -0
  500. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js +0 -1
  501. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.br +0 -0
  502. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.gz +0 -0
  503. codex/static_root/assets/VSelectionControl-CmFPvGMS.js +0 -1
  504. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.br +0 -0
  505. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.gz +0 -0
  506. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js +0 -1
  507. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.br +0 -0
  508. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.gz +0 -0
  509. codex/static_root/assets/VSlideGroup-D5FZWsM1.js +0 -1
  510. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.br +0 -0
  511. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.gz +0 -0
  512. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.br +0 -0
  513. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.gz +0 -0
  514. codex/static_root/assets/VTable-2RHFqfg6.js.br +0 -0
  515. codex/static_root/assets/VTable-2RHFqfg6.js.gz +0 -0
  516. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css +0 -1
  517. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.br +0 -0
  518. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.gz +0 -0
  519. codex/static_root/assets/VTextField-BssVoDhB.css +0 -1
  520. codex/static_root/assets/VTextField-BssVoDhB.css.br +0 -0
  521. codex/static_root/assets/VTextField-BssVoDhB.css.gz +0 -0
  522. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js +0 -1
  523. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.br +0 -0
  524. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.gz +0 -0
  525. codex/static_root/assets/VTextField-o1N9ylIb.js +0 -1
  526. codex/static_root/assets/VTextField-o1N9ylIb.js.br +0 -0
  527. codex/static_root/assets/VTextField-o1N9ylIb.js.gz +0 -0
  528. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js +0 -1
  529. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.br +0 -0
  530. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.gz +0 -0
  531. codex/static_root/assets/VWindowItem-C_zvuz9C.js +0 -1
  532. codex/static_root/assets/VWindowItem-C_zvuz9C.js.br +0 -0
  533. codex/static_root/assets/VWindowItem-C_zvuz9C.js.gz +0 -0
  534. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.br +0 -0
  535. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.gz +0 -0
  536. codex/static_root/assets/admin-B8Bp2Uih.css.br +0 -0
  537. codex/static_root/assets/admin-B8Bp2Uih.css.gz +0 -0
  538. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js +0 -1
  539. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.br +0 -0
  540. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.gz +0 -0
  541. codex/static_root/assets/admin-DHyHEWZ3.js +0 -1
  542. codex/static_root/assets/admin-DHyHEWZ3.js.br +0 -0
  543. codex/static_root/assets/admin-DHyHEWZ3.js.gz +0 -0
  544. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js +0 -30
  545. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.br +0 -0
  546. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.gz +0 -0
  547. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js +0 -30
  548. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.br +0 -0
  549. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.gz +0 -0
  550. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css +0 -1
  551. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
  552. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
  553. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css +0 -1
  554. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
  555. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
  556. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js +0 -1
  557. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.br +0 -0
  558. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.gz +0 -0
  559. codex/static_root/assets/browser-D0Vjmmp_.js +0 -1
  560. codex/static_root/assets/browser-D0Vjmmp_.js.br +0 -0
  561. codex/static_root/assets/browser-D0Vjmmp_.js.gz +0 -0
  562. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css +0 -1
  563. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.br +0 -0
  564. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.gz +0 -0
  565. codex/static_root/assets/browser-D7QQDneO.css +0 -1
  566. codex/static_root/assets/browser-D7QQDneO.css.br +0 -0
  567. codex/static_root/assets/browser-D7QQDneO.css.gz +0 -0
  568. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +0 -1
  569. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
  570. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
  571. codex/static_root/assets/change-password-dialog-0u6IJA87.css +0 -1
  572. codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
  573. codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
  574. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js +0 -1
  575. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.br +0 -0
  576. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.gz +0 -0
  577. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js +0 -1
  578. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.br +0 -0
  579. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.gz +0 -0
  580. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js +0 -1
  581. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.br +0 -0
  582. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.gz +0 -0
  583. codex/static_root/assets/confirm-dialog-DCKvg3ai.js +0 -1
  584. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.br +0 -0
  585. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.gz +0 -0
  586. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +0 -1
  587. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
  588. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +0 -1
  589. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
  590. codex/static_root/assets/datetime-column-DeCthByU.1f3bf499e063.css +0 -1
  591. codex/static_root/assets/datetime-column-DeCthByU.css +0 -1
  592. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js +0 -1
  593. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.br +0 -0
  594. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.gz +0 -0
  595. codex/static_root/assets/datetime-column-jHKA_uNm.js +0 -1
  596. codex/static_root/assets/datetime-column-jHKA_uNm.js.br +0 -0
  597. codex/static_root/assets/datetime-column-jHKA_uNm.js.gz +0 -0
  598. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js +0 -1
  599. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.br +0 -0
  600. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.gz +0 -0
  601. codex/static_root/assets/filter-DgPg2ts9.js +0 -1
  602. codex/static_root/assets/filter-DgPg2ts9.js.br +0 -0
  603. codex/static_root/assets/filter-DgPg2ts9.js.gz +0 -0
  604. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js +0 -1
  605. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.br +0 -0
  606. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.gz +0 -0
  607. codex/static_root/assets/flag-tab-9qxOALxP.js +0 -1
  608. codex/static_root/assets/flag-tab-9qxOALxP.js.br +0 -0
  609. codex/static_root/assets/flag-tab-9qxOALxP.js.gz +0 -0
  610. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +0 -1
  611. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
  612. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
  613. codex/static_root/assets/flag-tab-BNwbLfrN.css +0 -1
  614. codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
  615. codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
  616. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.br +0 -0
  617. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.gz +0 -0
  618. codex/static_root/assets/group-tab-D5vWrihT.js.br +0 -0
  619. codex/static_root/assets/group-tab-D5vWrihT.js.gz +0 -0
  620. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js +0 -1
  621. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.br +0 -0
  622. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.gz +0 -0
  623. codex/static_root/assets/http-error-B4FHoKfs.js +0 -1
  624. codex/static_root/assets/http-error-B4FHoKfs.js.br +0 -0
  625. codex/static_root/assets/http-error-B4FHoKfs.js.gz +0 -0
  626. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css +0 -1
  627. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.gz +0 -0
  628. codex/static_root/assets/http-error-DKulXuTl.css +0 -1
  629. codex/static_root/assets/http-error-DKulXuTl.css.gz +0 -0
  630. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css +0 -1
  631. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.br +0 -0
  632. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.gz +0 -0
  633. codex/static_root/assets/library-tab-BN0SfPcH.css +0 -1
  634. codex/static_root/assets/library-tab-BN0SfPcH.css.br +0 -0
  635. codex/static_root/assets/library-tab-BN0SfPcH.css.gz +0 -0
  636. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js +0 -1
  637. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.br +0 -0
  638. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.gz +0 -0
  639. codex/static_root/assets/library-tab-BWo0cmzk.js +0 -1
  640. codex/static_root/assets/library-tab-BWo0cmzk.js.br +0 -0
  641. codex/static_root/assets/library-tab-BWo0cmzk.js.gz +0 -0
  642. codex/static_root/assets/main-Ztp855PW.css.br +0 -0
  643. codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
  644. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js +0 -32
  645. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.br +0 -0
  646. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.gz +0 -0
  647. codex/static_root/assets/main-ipmlipkF.js +0 -32
  648. codex/static_root/assets/main-ipmlipkF.js.br +0 -0
  649. codex/static_root/assets/main-ipmlipkF.js.gz +0 -0
  650. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css +0 -1
  651. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.br +0 -0
  652. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.gz +0 -0
  653. codex/static_root/assets/pagination-toolbar-BA9ifTed.css +0 -1
  654. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.br +0 -0
  655. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.gz +0 -0
  656. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js +0 -1
  657. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.br +0 -0
  658. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.gz +0 -0
  659. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js +0 -1
  660. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.br +0 -0
  661. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.gz +0 -0
  662. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js +0 -305
  663. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.br +0 -0
  664. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.gz +0 -0
  665. codex/static_root/assets/pdf-doc-C2StaYUz.js +0 -305
  666. codex/static_root/assets/pdf-doc-C2StaYUz.js.br +0 -0
  667. codex/static_root/assets/pdf-doc-C2StaYUz.js.gz +0 -0
  668. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js +0 -2
  669. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.br +0 -0
  670. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.gz +0 -0
  671. codex/static_root/assets/reader-CCnq3j1-.js +0 -2
  672. codex/static_root/assets/reader-CCnq3j1-.js.br +0 -0
  673. codex/static_root/assets/reader-CCnq3j1-.js.gz +0 -0
  674. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css +0 -1
  675. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.br +0 -0
  676. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.gz +0 -0
  677. codex/static_root/assets/reader-CqXFa_gE.css +0 -1
  678. codex/static_root/assets/reader-CqXFa_gE.css.br +0 -0
  679. codex/static_root/assets/reader-CqXFa_gE.css.gz +0 -0
  680. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.br +0 -0
  681. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.gz +0 -0
  682. codex/static_root/assets/relation-chips-Bsc-gUxE.css.br +0 -0
  683. codex/static_root/assets/relation-chips-Bsc-gUxE.css.gz +0 -0
  684. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js +0 -1
  685. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.br +0 -0
  686. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.gz +0 -0
  687. codex/static_root/assets/relation-chips-C9ysW0tU.js +0 -1
  688. codex/static_root/assets/relation-chips-C9ysW0tU.js.br +0 -0
  689. codex/static_root/assets/relation-chips-C9ysW0tU.js.gz +0 -0
  690. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js +0 -2
  691. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.br +0 -0
  692. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.gz +0 -0
  693. codex/static_root/assets/settings-drawer-C0ofzAhW.js +0 -2
  694. codex/static_root/assets/settings-drawer-C0ofzAhW.js.br +0 -0
  695. codex/static_root/assets/settings-drawer-C0ofzAhW.js.gz +0 -0
  696. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css +0 -1
  697. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.br +0 -0
  698. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.gz +0 -0
  699. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css +0 -1
  700. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.br +0 -0
  701. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.gz +0 -0
  702. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +0 -1
  703. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  704. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  705. codex/static_root/assets/stats-tab-B4yKuY0c.css +0 -1
  706. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  707. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  708. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js +0 -1
  709. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.br +0 -0
  710. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.gz +0 -0
  711. codex/static_root/assets/stats-tab-BqJj7j1w.js +0 -1
  712. codex/static_root/assets/stats-tab-BqJj7j1w.js.br +0 -0
  713. codex/static_root/assets/stats-tab-BqJj7j1w.js.gz +0 -0
  714. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js +0 -1
  715. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.br +0 -0
  716. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.gz +0 -0
  717. codex/static_root/assets/task-tab-BsPzNk8S.js +0 -1
  718. codex/static_root/assets/task-tab-BsPzNk8S.js.br +0 -0
  719. codex/static_root/assets/task-tab-BsPzNk8S.js.gz +0 -0
  720. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js +0 -1
  721. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js.br +0 -0
  722. codex/static_root/assets/to-case-KvqtSug2.js +0 -1
  723. codex/static_root/assets/to-case-KvqtSug2.js.br +0 -0
  724. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
  725. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
  726. codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
  727. codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
  728. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js +0 -1
  729. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.br +0 -0
  730. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.gz +0 -0
  731. codex/static_root/assets/unauthorized-DwSdNzX2.js +0 -1
  732. codex/static_root/assets/unauthorized-DwSdNzX2.js.br +0 -0
  733. codex/static_root/assets/unauthorized-DwSdNzX2.js.gz +0 -0
  734. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js +0 -1
  735. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.br +0 -0
  736. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.gz +0 -0
  737. codex/static_root/assets/user-tab-DrJOb9Ys.js +0 -1
  738. codex/static_root/assets/user-tab-DrJOb9Ys.js.br +0 -0
  739. codex/static_root/assets/user-tab-DrJOb9Ys.js.gz +0 -0
  740. codex/static_root/js/choices-admin.3521e2a863df.json +0 -1
  741. codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
  742. codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
  743. codex/static_root/js/choices.2f6b0359e1ef.json +0 -1
  744. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  745. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  746. codex/static_root/manifest.1c84116d9a0a.json +0 -622
  747. codex/static_root/manifest.1c84116d9a0a.json.br +0 -0
  748. codex/static_root/manifest.1c84116d9a0a.json.gz +0 -0
  749. codex/util.py +0 -12
  750. codex/views/admin/auth.py +0 -28
  751. codex/views/browser/breadcrumbs.py +0 -202
  752. codex/views/browser/cover.py +0 -165
  753. codex/views/browser/mtime.py +0 -61
  754. codex/views/browser/order_by.py +0 -65
  755. codex/views/browser/paginate.py +0 -106
  756. codex/views/browser/settings.py +0 -66
  757. codex/views/browser/title.py +0 -48
  758. codex/views/browser/validate.py +0 -161
  759. codex/views/opds/auth.py +0 -17
  760. codex/views/public.py +0 -36
  761. codex/views/reader/arcs.py +0 -92
  762. codex/views/reader/books.py +0 -181
  763. codex/views/reader/init.py +0 -125
  764. codex/views/settings.py +0 -47
  765. codex/views/util.py +0 -77
  766. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/LICENSE +0 -0
  767. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/WHEEL +0 -0
  768. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/entry_points.txt +0 -0
@@ -1,23 +1,9 @@
1
1
  """Codex Serializers for the metadata box."""
2
2
 
3
- from rest_framework.serializers import CharField, IntegerField, ListField, Serializer
3
+ from rest_framework.serializers import CharField, IntegerField
4
4
 
5
5
  from codex.serializers.browser.mixins import BrowserAggregateSerializerMixin
6
6
  from codex.serializers.models.comic import ComicSerializer
7
- from codex.serializers.models.named import (
8
- ContributorSerializer,
9
- IdentifierSeralizer,
10
- StoryArcNumberSerializer,
11
- )
12
-
13
- PREFETCH_PREFIX = "attached_"
14
-
15
-
16
- class GroupSerializer(Serializer):
17
- """Serialize a group pk and name."""
18
-
19
- ids = ListField(child=IntegerField(), read_only=True)
20
- name = CharField(read_only=True)
21
7
 
22
8
 
23
9
  class MetadataSerializer(BrowserAggregateSerializerMixin, ComicSerializer):
@@ -27,33 +13,3 @@ class MetadataSerializer(BrowserAggregateSerializerMixin, ComicSerializer):
27
13
  parent_folder_id = IntegerField(read_only=True, required=False)
28
14
  series_volume_count = IntegerField(read_only=True)
29
15
  volume_issue_count = IntegerField(read_only=True)
30
-
31
- publisher_list = GroupSerializer(many=True, required=False)
32
- imprint_list = GroupSerializer(many=True, required=False)
33
- series_list = GroupSerializer(many=True, required=False)
34
- volume_list = GroupSerializer(many=True, required=False)
35
- publisher = None
36
- imprint = None
37
- series = None
38
- volume = None
39
-
40
- identifiers = IdentifierSeralizer(
41
- source=f"{PREFETCH_PREFIX}identifiers", many=True, allow_null=True
42
- )
43
- contributors = ContributorSerializer(
44
- source=f"{PREFETCH_PREFIX}contributors", many=True, allow_null=True
45
- )
46
- stroy_arc_numbers = StoryArcNumberSerializer(
47
- source=f"{PREFETCH_PREFIX}story_arc_numbers", many=True, allow_null=True
48
- )
49
-
50
- class Meta(ComicSerializer.Meta):
51
- """Configure the model."""
52
-
53
- exclude = (
54
- *ComicSerializer.Meta.exclude,
55
- "publisher",
56
- "imprint",
57
- "series",
58
- "volume",
59
- )
@@ -1,33 +1,27 @@
1
1
  """Serializer mixins."""
2
2
 
3
- from datetime import datetime, timezone
4
-
5
3
  from rest_framework.serializers import (
6
4
  BooleanField,
7
5
  CharField,
8
6
  DateTimeField,
9
7
  DecimalField,
10
8
  IntegerField,
11
- ListField,
12
9
  Serializer,
13
- SerializerMethodField,
14
10
  )
15
11
 
16
- from codex.logger.logging import get_logger
17
- from codex.views.const import COMIC_GROUP, EPOCH_START
18
-
19
- LOG = get_logger(__name__)
12
+ from codex.serializers.browser.filters import IntListField
20
13
 
21
14
 
22
15
  class BrowserAggregateSerializerMixin(Serializer):
23
16
  """Mixin for browser, opds & metadata serializers."""
24
17
 
25
18
  group = CharField(read_only=True, max_length=1)
26
- ids = ListField(child=IntegerField(), read_only=True)
19
+ ids = IntListField(read_only=True)
27
20
 
28
21
  # Aggregate Annotations
29
22
  child_count = IntegerField(read_only=True)
30
- mtime = SerializerMethodField(read_only=True)
23
+ cover_pk = IntegerField(read_only=True)
24
+ cover_mtime = DateTimeField(format="%s", read_only=True)
31
25
 
32
26
  # Bookmark annotations
33
27
  page = IntegerField(read_only=True)
@@ -36,30 +30,3 @@ class BrowserAggregateSerializerMixin(Serializer):
36
30
  progress = DecimalField(
37
31
  max_digits=5, decimal_places=2, read_only=True, coerce_to_string=False
38
32
  )
39
-
40
- def get_mtime(self, obj) -> int:
41
- """Compute mtime from json array aggregates."""
42
- mtime = EPOCH_START
43
- for dt_str in obj.updated_ats:
44
- if not dt_str:
45
- continue
46
- try:
47
- dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S.%f").replace(
48
- tzinfo=timezone.utc
49
- )
50
- except ValueError:
51
- LOG.warning(
52
- f"computing group mtime: {dt_str} is not a valid datetime string."
53
- )
54
- continue
55
-
56
- if dt > mtime:
57
- mtime = dt
58
-
59
- if obj.group != COMIC_GROUP and (
60
- mbua := getattr(obj, "max_bookmark_updated_at", None)
61
- ):
62
- mtime = max(mtime, mbua)
63
-
64
- # print(obj.group, obj.pk, obj.name, obj.updated_ats, obj.max_bookmark_updated_at, "max:", mtime)
65
- return int(mtime.timestamp() * 1000)
@@ -3,15 +3,17 @@
3
3
  from rest_framework.serializers import (
4
4
  BooleanField,
5
5
  CharField,
6
+ DateTimeField,
6
7
  DecimalField,
7
8
  IntegerField,
9
+ ListSerializer,
8
10
  Serializer,
9
11
  )
10
12
 
11
13
  from codex.serializers.browser.mixins import (
12
14
  BrowserAggregateSerializerMixin,
13
15
  )
14
- from codex.serializers.fields import BreadcrumbsField, TimestampField
16
+ from codex.serializers.route import RouteSerializer
15
17
 
16
18
 
17
19
  class BrowserCardSerializer(BrowserAggregateSerializerMixin):
@@ -32,6 +34,7 @@ class BrowserCardSerializer(BrowserAggregateSerializerMixin):
32
34
  order_value = CharField(read_only=True)
33
35
  page_count = IntegerField(read_only=True)
34
36
  reading_direction = CharField(read_only=True)
37
+ mtime = DateTimeField(format="%s", read_only=True)
35
38
 
36
39
 
37
40
  class BrowserAdminFlagsSerializer(Serializer):
@@ -52,12 +55,12 @@ class BrowserPageSerializer(Serializer):
52
55
  """The main browse list."""
53
56
 
54
57
  admin_flags = BrowserAdminFlagsSerializer(read_only=True)
55
- breadcrumbs = BreadcrumbsField(read_only=True)
58
+ breadcrumbs = ListSerializer(child=RouteSerializer())
56
59
  title = BrowserTitleSerializer(read_only=True)
60
+ covers_timestamp = IntegerField(read_only=True)
57
61
  zero_pad = IntegerField(read_only=True)
58
62
  libraries_exist = BooleanField(read_only=True)
59
63
  model_group = CharField(read_only=True)
60
64
  num_pages = IntegerField(read_only=True)
61
65
  groups = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
62
66
  books = BrowserCardSerializer(allow_empty=True, read_only=True, many=True)
63
- mtime = TimestampField(read_only=True)
@@ -10,8 +10,6 @@ from rest_framework.serializers import (
10
10
 
11
11
  from codex.serializers.browser.filters import BrowserSettingsFilterSerializer
12
12
  from codex.serializers.choices import CHOICES, VUETIFY_NULL_CODE
13
- from codex.serializers.fields import BreadcrumbsField, TimestampField, TopGroupField
14
- from codex.serializers.route import SimpleRouteSerializer
15
13
 
16
14
  VUETIFY_NULL_CODE_STR = str(VUETIFY_NULL_CODE)
17
15
 
@@ -25,50 +23,21 @@ class BrowserSettingsShowGroupFlagsSerializer(Serializer):
25
23
  v = BooleanField()
26
24
 
27
25
 
28
- class BrowserFilterChoicesInputSerilalizer(Serializer):
29
- """Browser Settings for the filter choices response."""
30
-
31
- filters = BrowserSettingsFilterSerializer(required=False)
32
- q = CharField(allow_blank=True, required=False)
33
-
26
+ class BrowserSettingsSerializer(Serializer):
27
+ """Browser Settings that the user can change.
34
28
 
35
- class BrowserCoverInputSerializerBase(BrowserFilterChoicesInputSerilalizer):
36
- """Base Serializer for Cover and Settings."""
29
+ This is the only browse serializer that's submitted.
30
+ It is also sent to the browser as part of BrowserOpenedSerializer.
31
+ """
37
32
 
38
- custom_covers = BooleanField(required=False)
39
- dynamic_covers = BooleanField(required=False)
33
+ filters = BrowserSettingsFilterSerializer(required=False)
40
34
  order_by = ChoiceField(choices=tuple(CHOICES["orderBy"].keys()), required=False)
41
35
  order_reverse = BooleanField(required=False)
36
+ q = CharField(allow_blank=True, required=False)
37
+ query = CharField(allow_blank=True, required=False) # OPDS 2.0
42
38
  show = BrowserSettingsShowGroupFlagsSerializer(required=False)
43
-
44
-
45
- class BrowserCoverInputSerializer(BrowserCoverInputSerializerBase):
46
- """Browser Settings for the cover response."""
47
-
48
- parent = SimpleRouteSerializer(required=False)
49
-
50
-
51
- class BrowserSettingsSerializerBase(BrowserCoverInputSerializerBase):
52
- """Base Serializer for Browser & OPDS Settings."""
53
-
54
39
  # search_results_limit = IntegerField(required=False)
55
- top_group = TopGroupField(required=False)
56
-
57
-
58
- class OPDSSettingsSerializer(BrowserSettingsSerializerBase):
59
- """Browser Settings for the OPDS."""
60
-
61
- limit = IntegerField(required=False)
62
- opds_metadata = BooleanField(required=False)
63
- query = CharField(allow_blank=True, required=False) # OPDS 2.0
64
-
65
-
66
- class BrowserSettingsSerializer(BrowserSettingsSerializerBase):
67
- """Browser Settings that the user can change.
68
-
69
- This is the only browse serializer that's submitted.
70
- """
71
-
72
- breadcrumbs = BreadcrumbsField(required=False)
73
- mtime = TimestampField(read_only=True)
74
40
  twenty_four_hour_time = BooleanField(required=False)
41
+ top_group = ChoiceField(choices=tuple(CHOICES["topGroup"].keys()), required=False)
42
+ opds_metadata = BooleanField(required=False)
43
+ limit = IntegerField(required=False)
@@ -49,26 +49,13 @@ _CHOICES_FN_RE = {
49
49
  _CHOICES_MODULE_NAME: create_choices_fn_regexes(_CHOICES_MODULE_NAME),
50
50
  _ADMIN_CHOICES_MODULE_NAME: create_choices_fn_regexes(_ADMIN_CHOICES_MODULE_NAME),
51
51
  }
52
- _SINGLE_VALUE_KEYS = frozenset(
53
- {
54
- "customCovers",
55
- "dynamicCovers",
56
- "finishOnLastPage",
57
- "orderReverse",
58
- "q",
59
- "readRtlInReverse",
60
- "searchResultsLimit",
61
- "twentyFourHourTime",
62
- "twoPages",
63
- }
64
- )
52
+ _SINGLE_VALUE_KEYS = frozenset({"orderReverse", "q", "searchResultsLimit"})
65
53
 
66
54
  # Exports
67
55
  CHOICES = {}
68
56
  DEFAULTS = {}
69
57
  WEBSOCKET_MESSAGES = {}
70
58
  VUETIFY_NULL_CODE = -1
71
- DUMMY_NULL_NAME = "_none_"
72
59
 
73
60
 
74
61
  def _find_filename_regex(js_root, module_name):
@@ -1,33 +1,73 @@
1
1
  """Pycountry Model Serializers."""
2
2
 
3
- from codex.logger.logging import get_logger
3
+ import pycountry
4
+ from drf_spectacular.types import OpenApiTypes
5
+ from drf_spectacular.utils import extend_schema_field
6
+ from rest_framework.serializers import (
7
+ SerializerMethodField,
8
+ )
9
+
4
10
  from codex.models import (
5
11
  Country,
6
12
  Language,
7
13
  )
8
- from codex.serializers.fields import CountryField, LanguageField
9
14
  from codex.serializers.models.named import NamedModelSerializer
10
15
 
11
- LOG = get_logger(__name__)
12
16
 
17
+ class PyCountrySerializer(NamedModelSerializer):
18
+ """PyCountry tag serializer to include long names.
13
19
 
14
- class CountrySerializer(NamedModelSerializer):
15
- """Pycountry serializer for country field."""
20
+ Takes a single string value and serializes the value to
21
+ a pk attribute and a pycountry long name lookup of that value to
22
+ the name.
23
+ """
24
+
25
+ LOOKUP_MODULE = pycountry.countries
26
+ _ALPHA_2_LEN = 2
16
27
 
17
- name = CountryField(read_only=True)
28
+ name = SerializerMethodField()
18
29
 
19
30
  class Meta(NamedModelSerializer.Meta):
20
- """Configure model."""
31
+ """Abstract class."""
21
32
 
22
- model = Country
33
+ abstract = True
34
+
35
+ @classmethod
36
+ def lookup_name(cls, lookup_module, obj):
37
+ """Lookup the name with pycountry, just copy the key on fail."""
38
+ name = obj.name
39
+ if not name:
40
+ return ""
41
+ # fix for https://github.com/flyingcircusio/pycountry/issues/41
42
+ lookup_obj = (
43
+ lookup_module.get(alpha_2=name)
44
+ if len(name) == cls._ALPHA_2_LEN
45
+ else lookup_module.lookup(name)
46
+ )
47
+ # If lookup fails, return the key as the name
48
+ return lookup_obj.name if lookup_obj else name
49
+
50
+ @extend_schema_field(OpenApiTypes.STR)
51
+ def get_name(self, obj):
52
+ """Lookup the name with pycountry, just copy the key on fail."""
53
+ return self.lookup_name(self.LOOKUP_MODULE, obj)
23
54
 
24
55
 
25
- class LanguageSerializer(NamedModelSerializer):
56
+ class LanguageSerializer(PyCountrySerializer):
26
57
  """Pycountry serializer for language field."""
27
58
 
28
- name = LanguageField(read_only=True)
59
+ LOOKUP_MODULE = pycountry.languages
29
60
 
30
- class Meta(NamedModelSerializer.Meta):
61
+ class Meta(PyCountrySerializer.Meta):
31
62
  """Configure model."""
32
63
 
33
64
  model = Language
65
+
66
+
67
+ class CountrySerializer(PyCountrySerializer):
68
+ """Pycountry serializer for country field."""
69
+
70
+ class Meta(PyCountrySerializer.Meta):
71
+ """Configure model."""
72
+
73
+ model = Country
@@ -12,6 +12,12 @@ from rest_framework.fields import (
12
12
  from rest_framework.serializers import Serializer
13
13
 
14
14
 
15
+ class CharListField(ListField):
16
+ """List of CharFields."""
17
+
18
+ child = CharField()
19
+
20
+
15
21
  class OPDS2LinkPropertiesSerializer(Serializer):
16
22
  """Link Properties.
17
23
 
@@ -49,9 +55,9 @@ class OPDS2LinkSerializer(Serializer):
49
55
  width = IntegerField(read_only=True, required=False)
50
56
  # bitrate = IntegerField(read_only=True, required=False)
51
57
  # duration = IntegerField(read_only=True, required=False)
52
- # language = CharField(many=True, read_only=True, required=False)
53
- alternate = ListField(child=CharField(), read_only=True, required=False)
54
- children = ListField(child=CharField(), read_only=True, required=False)
58
+ # language = CharListField(read_only=True, required=False)
59
+ alternate = CharListField(read_only=True, required=False)
60
+ children = CharListField(read_only=True, required=False)
55
61
  properties = OPDS2LinkPropertiesSerializer(read_only=True, required=False)
56
62
 
57
63
  def get_rel(self, obj) -> str | None:
@@ -63,7 +69,7 @@ class OPDS2LinkSerializer(Serializer):
63
69
  return obj.get("rel")
64
70
 
65
71
 
66
- class OPDS2LinkListField(ListField):
72
+ class LinkListField(ListField):
67
73
  """Link List."""
68
74
 
69
75
  child = OPDS2LinkSerializer()
@@ -125,7 +131,7 @@ class OPDS2PublicationMetadataSerializer(OPDS2MetadataSerializer):
125
131
  #####################
126
132
  # Extended metadata #
127
133
  #####################
128
- subject = ListField(child=CharField(), read_only=True, required=False)
134
+ subject = CharListField(read_only=True, required=False)
129
135
  author = OPDS2ContributorObjectSerializer(many=True, required=False)
130
136
  # translator = OPDS2ContributorObjectSerializer(many=True, required=False)
131
137
  editor = OPDS2ContributorObjectSerializer(many=True, required=False)
@@ -142,7 +148,7 @@ class OPDS2FacetSerializer(Serializer):
142
148
  """Facets."""
143
149
 
144
150
  metadata = OPDS2MetadataSerializer(read_only=True)
145
- links = OPDS2LinkListField(read_only=True)
151
+ links = LinkListField(read_only=True)
146
152
 
147
153
 
148
154
  class OPDS2PublicationSerializer(OPDS2FacetSerializer):
@@ -152,19 +158,19 @@ class OPDS2PublicationSerializer(OPDS2FacetSerializer):
152
158
  """
153
159
 
154
160
  metadata = OPDS2PublicationMetadataSerializer(read_only=True)
155
- links = OPDS2LinkListField(read_only=True)
156
- images = OPDS2LinkListField(read_only=True, required=False)
161
+ links = LinkListField(read_only=True)
162
+ images = LinkListField(read_only=True, required=False)
157
163
 
158
164
 
159
165
  class OPDS2GroupSerializer(Serializer):
160
166
  """Group."""
161
167
 
162
168
  metadata = OPDS2MetadataSerializer(read_only=True)
163
- links = OPDS2LinkListField(read_only=True, required=False)
169
+ links = LinkListField(read_only=True, required=False)
164
170
  publications = ListField(
165
171
  child=OPDS2PublicationSerializer(), read_only=True, required=False
166
172
  )
167
- navigation = OPDS2LinkListField(read_only=True, required=False)
173
+ navigation = LinkListField(read_only=True, required=False)
168
174
 
169
175
 
170
176
  class OPDS2FeedSerializer(OPDS2GroupSerializer):
@@ -3,7 +3,7 @@
3
3
  from rest_framework.fields import CharField, DateTimeField, DecimalField, IntegerField
4
4
  from rest_framework.serializers import ChoiceField, Serializer
5
5
 
6
- from codex.serializers.opds.v2 import OPDS2LinkListField
6
+ from codex.serializers.opds.v2 import LinkListField
7
7
 
8
8
 
9
9
  class RecursiveField(Serializer):
@@ -15,9 +15,7 @@ class RecursiveField(Serializer):
15
15
 
16
16
  def to_representation(self, instance):
17
17
  """Represent with own class."""
18
- parent = self.parent
19
- # Should not be ignored but is currently unused
20
- serializer = parent.parent.__class__(instance, context=self.context) # type: ignore
18
+ serializer = self.parent.parent.__class__(instance, context=self.context)
21
19
  return serializer.data
22
20
 
23
21
 
@@ -70,7 +68,7 @@ class OPDS2ProfileSerializer(Serializer):
70
68
 
71
69
  name = CharField(read_only=True)
72
70
  email = CharField(read_only=True)
73
- links = OPDS2LinkListField(read_only=True, required=False)
71
+ links = LinkListField(read_only=True, required=False)
74
72
  loans = OPDS2CopiesSerializer(read_only=True)
75
73
  holds = OPDS2HoldsSerializer(read_only=True)
76
74
 
@@ -4,15 +4,14 @@ from rest_framework.serializers import (
4
4
  BooleanField,
5
5
  CharField,
6
6
  ChoiceField,
7
+ DateTimeField,
7
8
  DecimalField,
8
9
  IntegerField,
9
10
  Serializer,
10
11
  )
11
12
 
12
13
  from codex.models import Bookmark
13
- from codex.serializers.browser.settings import BrowserSettingsShowGroupFlagsSerializer
14
- from codex.serializers.fields import BreadcrumbsField, TimestampField, TopGroupField
15
- from codex.serializers.route import RouteSerializer, SimpleRouteSerializer
14
+ from codex.serializers.route import RouteSerializer
16
15
 
17
16
 
18
17
  class ReaderSettingsSerializer(Serializer):
@@ -26,8 +25,6 @@ class ReaderSettingsSerializer(Serializer):
26
25
  two_pages = BooleanField(allow_null=True, required=False)
27
26
  reading_direction = CharField(allow_null=True, required=False)
28
27
  read_rtl_in_reverse = BooleanField(allow_null=True, required=False)
29
- finish_on_last_page = BooleanField(allow_null=True, required=False)
30
- mtime = TimestampField(read_only=True)
31
28
 
32
29
 
33
30
  class ReaderComicSerializer(Serializer):
@@ -37,25 +34,15 @@ class ReaderComicSerializer(Serializer):
37
34
  settings = ReaderSettingsSerializer(read_only=True)
38
35
  max_page = IntegerField(read_only=True)
39
36
  reading_direction = CharField(read_only=True)
40
- mtime = TimestampField(read_only=True)
37
+ mtime = DateTimeField(format="%s", read_only=True)
41
38
 
42
39
 
43
- class ReaderArcSerializer(SimpleRouteSerializer):
40
+ class ReaderArcSerializer(RouteSerializer):
44
41
  """Information about the current Arc."""
45
42
 
46
- name = CharField(required=False)
47
- index = IntegerField(required=False)
48
- count = IntegerField(required=False)
49
- mtime = TimestampField(read_only=True)
50
-
51
-
52
- class ReaderViewInputSerializer(Serializer):
53
- """Input for the reader serailizer."""
54
-
55
- arc = ReaderArcSerializer(required=False)
56
- breadcrumbs = BreadcrumbsField(required=False)
57
- show = BrowserSettingsShowGroupFlagsSerializer(required=False)
58
- top_group = TopGroupField(required=False)
43
+ page = None
44
+ index = IntegerField(read_only=True, required=False)
45
+ count = IntegerField(read_only=True, required=False)
59
46
 
60
47
 
61
48
  class ReaderCurrentComicSerializer(ReaderComicSerializer):
@@ -97,4 +84,3 @@ class ReaderComicsSerializer(Serializer):
97
84
  arcs = ReaderArcSerializer(many=True, read_only=True)
98
85
  arc = ReaderArcSerializer(read_only=True)
99
86
  close_route = RouteSerializer(read_only=True)
100
- mtime = TimestampField(read_only=True)
@@ -1,16 +1,15 @@
1
1
  """Notification serializers."""
2
2
 
3
- from rest_framework.serializers import CharField, Serializer
3
+ from rest_framework.serializers import CharField, JSONField, Serializer
4
4
 
5
5
  from codex.serializers.browser.settings import BrowserSettingsSerializer
6
- from codex.serializers.route import RouteSerializer
7
6
 
8
7
 
9
8
  class ReaderRedirectSerializer(Serializer):
10
9
  """Reader 404 message."""
11
10
 
12
11
  reason = CharField(read_only=True)
13
- route = RouteSerializer(read_only=True)
12
+ route = JSONField(read_only=True)
14
13
 
15
14
 
16
15
  class BrowserRedirectSerializer(ReaderRedirectSerializer):
@@ -3,20 +3,18 @@
3
3
  from rest_framework.fields import CharField, IntegerField
4
4
  from rest_framework.serializers import Serializer
5
5
 
6
- from codex.views.util import Route
7
6
 
8
-
9
- class SimpleRouteSerializer(Serializer):
10
- """A an abbreviated vue route for the browser."""
7
+ class RouteSerializer(Serializer):
8
+ """A vue route for the browser."""
11
9
 
12
10
  group = CharField()
13
11
  pks = CharField()
12
+ page = IntegerField()
13
+ name = CharField(required=False)
14
14
 
15
15
  def to_representation(self, instance):
16
16
  """Allow submission of sequences instead of strings for pks."""
17
- if isinstance(instance, Route):
18
- instance = instance.dict()
19
- pks = instance["pks"]
17
+ pks = instance.get("pks")
20
18
  if not pks:
21
19
  instance["pks"] = "0"
22
20
  elif not isinstance(pks, str):
@@ -30,16 +28,9 @@ class SimpleRouteSerializer(Serializer):
30
28
  pks = instance.get("pks")
31
29
  if isinstance(pks, str):
32
30
  pks = tuple(sorted(int(pk) for pk in pks.split(",")))
33
- if 0 in pks: # type: ignore
31
+ if 0 in pks:
34
32
  pks = ()
35
- instance["pks"] = tuple(pks) # type: ignore
33
+ instance["pks"] = tuple(pks)
36
34
  except ValueError:
37
35
  instance["pks"] = ()
38
36
  return instance
39
-
40
-
41
- class RouteSerializer(SimpleRouteSerializer):
42
- """A vue route for the browser."""
43
-
44
- page = IntegerField()
45
- name = CharField(allow_blank=True, required=False)
@@ -37,11 +37,10 @@ WRITER_MEMORY_PERCENT = float(environ.get("CODEX_WRITER_MEMORY_PERCENT", 0.6))
37
37
  CPU_MULTIPLIER = float(environ.get("CODEX_CPU_MULTIPLIER", 1.25))
38
38
  CHUNK_PER_GB = int(environ.get("CODEX_CHUNK_PER_GB", 250))
39
39
  MAX_CHUNK_SIZE = int(environ.get("CODEX_MAX_CHUNK_SIZE", 1000))
40
- # sqlite parser breaks with more than 1000 variables in a query and
41
- # django only fixes this in the bulk_create & bulk_update functions.
42
- # So for complicated queries I gotta batch them myself. Filter arg
43
- # count is a proxy, but it works. 990 errors sometimes.
44
- FILTER_BATCH_SIZE = int(environ.get("CODEX_FILTER_BATCH_SIZE", 900))
40
+ # sqlite parser breaks with more than 1000 variables in a query and django only
41
+ # fixes this in the bulk_create & bulk_update functions. So for complicated
42
+ # queries I gotta batch them myself. Filter arg count is a proxy, but it works.
43
+ FILTER_BATCH_SIZE = int(environ.get("CODEX_FILTER_BATCH_SIZE", 990))
45
44
  VITE_HOST = environ.get("VITE_HOST")
46
45
 
47
46
  ####################################
@@ -63,12 +62,7 @@ THROTTLE_OPENSEARCH = int(environ.get("CODEX_THROTTLE_OPENSEARCH", 0))
63
62
  # Base paths
64
63
  BASE_DIR = Path(__file__).resolve().parent.parent.parent
65
64
  CODEX_PATH = BASE_DIR / "codex"
66
- CUSTOM_COVERS_SUBDIR = "custom-covers"
67
- CUSTOM_COVERS_DIR = CONFIG_PATH / CUSTOM_COVERS_SUBDIR
68
- CUSTOM_COVERS_GROUP_DIRS = ("publishers", "imprints", "series", "volumes", "story-arcs")
69
- for group_dir in CUSTOM_COVERS_GROUP_DIRS:
70
- custom_cover_group_dir = CUSTOM_COVERS_DIR / group_dir
71
- custom_cover_group_dir.mkdir(exist_ok=True, parents=True)
65
+ CONFIG_PATH.mkdir(exist_ok=True, parents=True)
72
66
 
73
67
  # SECURITY WARNING: keep the secret key used in production secret!
74
68
  SECRET_KEY = get_secret_key(CONFIG_PATH)
@@ -291,9 +285,9 @@ REST_FRAMEWORK = {
291
285
  "djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer",
292
286
  ),
293
287
  "DEFAULT_PARSER_CLASSES": (
288
+ "djangorestframework_camel_case.parser.CamelCaseFormParser",
289
+ "djangorestframework_camel_case.parser.CamelCaseMultiPartParser",
294
290
  "djangorestframework_camel_case.parser.CamelCaseJSONParser",
295
- # "djangorestframework_camel_case.parser.CamelCaseFormParser",
296
- # "djangorestframework_camel_case.parser.CamelCaseMultiPartParser",
297
291
  ),
298
292
  "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
299
293
  "EXCEPTION_HANDLER": "codex.views.error.codex_exception_handler",
@@ -325,18 +319,9 @@ REST_REGISTRATION = {
325
319
  SPECTACULAR_SETTINGS = {
326
320
  "TITLE": "Codex API",
327
321
  "DESCRIPTION": "Comic Library Browser and Reader",
328
- "OAS_VERSION": "3.1.0",
329
322
  "VERSION": "3.0.0",
330
- "CONTACT": {
331
- "name": "Support",
332
- "url": "https://github.com/ajslater/codex?tab=readme-ov-file#-support",
333
- },
323
+ "CONTACT": {"name": "Repository", "url": "https://github.com/ajslater/codex/"},
334
324
  "PREPROCESSING_HOOKS": ["codex.urls.spectacular.allow_list"],
335
- "SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
336
- "EXTERNAL_DOCS": {
337
- "url": "https://github.com/ajslater/codex/",
338
- "description": "Codex Docs",
339
- },
340
325
  }
341
326
 
342
327
  CORS_ALLOW_CREDENTIALS = True