codex 1.6.2__py3-none-any.whl → 1.6.4__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 (513) hide show
  1. codex/exceptions.py +42 -16
  2. codex/librarian/importer/importer.py +1 -1
  3. codex/librarian/janitor/cleanup.py +2 -4
  4. codex/librarian/janitor/update.py +10 -9
  5. codex/librarian/search/merge.py +37 -40
  6. codex/librarian/search/remove.py +30 -26
  7. codex/librarian/search/update.py +47 -38
  8. codex/librarian/stats.py +177 -0
  9. codex/librarian/watchdog/events.py +2 -2
  10. codex/serializers/admin/__init__.py +1 -0
  11. codex/serializers/admin/flags.py +15 -0
  12. codex/serializers/admin/groups.py +38 -0
  13. codex/serializers/admin/libraries.py +90 -0
  14. codex/serializers/admin/stats.py +126 -0
  15. codex/serializers/admin/tasks.py +16 -0
  16. codex/serializers/admin/users.py +40 -0
  17. codex/serializers/fields.py +30 -0
  18. codex/serializers/reader.py +8 -3
  19. codex/settings/settings.py +3 -3
  20. codex/static_root/assets/VCheckbox-DtXDauZz.54986ad416a1.js +1 -0
  21. codex/static_root/assets/VCheckbox-DtXDauZz.54986ad416a1.js.br +0 -0
  22. codex/static_root/assets/VCheckbox-DtXDauZz.54986ad416a1.js.gz +0 -0
  23. codex/static_root/assets/VCheckbox-DtXDauZz.js +1 -0
  24. codex/static_root/assets/VCheckbox-DtXDauZz.js.br +0 -0
  25. codex/static_root/assets/VCheckbox-DtXDauZz.js.gz +0 -0
  26. codex/static_root/assets/VCheckboxBtn-B-iT1MnG.8505f6eed0fe.js +1 -0
  27. codex/static_root/assets/VCheckboxBtn-B-iT1MnG.8505f6eed0fe.js.br +0 -0
  28. codex/static_root/assets/VCheckboxBtn-B-iT1MnG.8505f6eed0fe.js.gz +0 -0
  29. codex/static_root/assets/VCheckboxBtn-B-iT1MnG.js +1 -0
  30. codex/static_root/assets/VCheckboxBtn-B-iT1MnG.js.br +0 -0
  31. codex/static_root/assets/VCheckboxBtn-B-iT1MnG.js.gz +0 -0
  32. codex/static_root/assets/{VCombobox-CGyBgdqr.2f85598cc1a4.js → VCombobox-DZmum3X-.330883d59742.js} +1 -1
  33. codex/static_root/assets/VCombobox-DZmum3X-.330883d59742.js.br +0 -0
  34. codex/static_root/assets/VCombobox-DZmum3X-.330883d59742.js.gz +0 -0
  35. codex/static_root/assets/{VCombobox-CGyBgdqr.js → VCombobox-DZmum3X-.js} +1 -1
  36. codex/static_root/assets/VCombobox-DZmum3X-.js.br +0 -0
  37. codex/static_root/assets/VCombobox-DZmum3X-.js.gz +0 -0
  38. codex/static_root/assets/VDialog-DUdNpXLj.6088d518d3af.js +1 -0
  39. codex/static_root/assets/VDialog-DUdNpXLj.6088d518d3af.js.br +0 -0
  40. codex/static_root/assets/VDialog-DUdNpXLj.6088d518d3af.js.gz +0 -0
  41. codex/static_root/assets/VDialog-DUdNpXLj.js +1 -0
  42. codex/static_root/assets/VDialog-DUdNpXLj.js.br +0 -0
  43. codex/static_root/assets/VDialog-DUdNpXLj.js.gz +0 -0
  44. codex/static_root/assets/VExpansionPanels-CurqcyFg.860017abf25d.js +1 -0
  45. codex/static_root/assets/VExpansionPanels-CurqcyFg.860017abf25d.js.br +0 -0
  46. codex/static_root/assets/VExpansionPanels-CurqcyFg.860017abf25d.js.gz +0 -0
  47. codex/static_root/assets/VExpansionPanels-CurqcyFg.js +1 -0
  48. codex/static_root/assets/VExpansionPanels-CurqcyFg.js.br +0 -0
  49. codex/static_root/assets/VExpansionPanels-CurqcyFg.js.gz +0 -0
  50. codex/static_root/assets/VRadioGroup-B7n5ReZ-.8acbc71ac411.js +1 -0
  51. codex/static_root/assets/VRadioGroup-B7n5ReZ-.8acbc71ac411.js.br +0 -0
  52. codex/static_root/assets/VRadioGroup-B7n5ReZ-.8acbc71ac411.js.gz +0 -0
  53. codex/static_root/assets/VRadioGroup-B7n5ReZ-.js +1 -0
  54. codex/static_root/assets/VRadioGroup-B7n5ReZ-.js.br +0 -0
  55. codex/static_root/assets/VRadioGroup-B7n5ReZ-.js.gz +0 -0
  56. codex/static_root/assets/VSelect-FYWbH55D.83e91b93fdd1.js +1 -0
  57. codex/static_root/assets/VSelect-FYWbH55D.83e91b93fdd1.js.br +0 -0
  58. codex/static_root/assets/VSelect-FYWbH55D.83e91b93fdd1.js.gz +0 -0
  59. codex/static_root/assets/VSelect-FYWbH55D.js +1 -0
  60. codex/static_root/assets/VSelect-FYWbH55D.js.br +0 -0
  61. codex/static_root/assets/VSelect-FYWbH55D.js.gz +0 -0
  62. codex/static_root/assets/{VSelectionControl-DXxRmssH.js → VSelectionControl-CUlT3cc_.63f60240eb49.js} +1 -1
  63. codex/static_root/assets/VSelectionControl-CUlT3cc_.63f60240eb49.js.br +0 -0
  64. codex/static_root/assets/VSelectionControl-CUlT3cc_.63f60240eb49.js.gz +0 -0
  65. codex/static_root/assets/{VSelectionControl-DXxRmssH.252890f79cc6.js → VSelectionControl-CUlT3cc_.js} +1 -1
  66. codex/static_root/assets/VSelectionControl-CUlT3cc_.js.br +0 -0
  67. codex/static_root/assets/VSelectionControl-CUlT3cc_.js.gz +0 -0
  68. codex/static_root/assets/{VSlideGroup-DYJ3EYZI.a2542c5f90c4.js → VSlideGroup-CRJazQeR.cb89b2222518.js} +1 -1
  69. codex/static_root/assets/VSlideGroup-CRJazQeR.cb89b2222518.js.br +0 -0
  70. codex/static_root/assets/VSlideGroup-CRJazQeR.cb89b2222518.js.gz +0 -0
  71. codex/static_root/assets/{VSlideGroup-DYJ3EYZI.js → VSlideGroup-CRJazQeR.js} +1 -1
  72. codex/static_root/assets/VSlideGroup-CRJazQeR.js.br +0 -0
  73. codex/static_root/assets/VSlideGroup-CRJazQeR.js.gz +0 -0
  74. codex/static_root/assets/{VTable-BveGtxei.7f76f4ef812b.js → VTable-DtyBEZ5i.6848f15ea03f.js} +1 -1
  75. codex/static_root/assets/VTable-DtyBEZ5i.6848f15ea03f.js.br +0 -0
  76. codex/static_root/assets/VTable-DtyBEZ5i.6848f15ea03f.js.gz +0 -0
  77. codex/static_root/assets/{VTable-BveGtxei.js → VTable-DtyBEZ5i.js} +1 -1
  78. codex/static_root/assets/VTable-DtyBEZ5i.js.br +0 -0
  79. codex/static_root/assets/VTable-DtyBEZ5i.js.gz +0 -0
  80. codex/static_root/assets/VTextField-DEiVah7O.fbf3130f2dea.js +1 -0
  81. codex/static_root/assets/VTextField-DEiVah7O.fbf3130f2dea.js.br +0 -0
  82. codex/static_root/assets/VTextField-DEiVah7O.fbf3130f2dea.js.gz +0 -0
  83. codex/static_root/assets/VTextField-DEiVah7O.js +1 -0
  84. codex/static_root/assets/VTextField-DEiVah7O.js.br +0 -0
  85. codex/static_root/assets/VTextField-DEiVah7O.js.gz +0 -0
  86. codex/static_root/assets/{VWindowItem-FBuIO_rT.8610c7e83905.js → VWindowItem-BVIaHO-S.419e4ecf523d.js} +1 -1
  87. codex/static_root/assets/VWindowItem-BVIaHO-S.419e4ecf523d.js.br +0 -0
  88. codex/static_root/assets/VWindowItem-BVIaHO-S.419e4ecf523d.js.gz +0 -0
  89. codex/static_root/assets/{VWindowItem-FBuIO_rT.js → VWindowItem-BVIaHO-S.js} +1 -1
  90. codex/static_root/assets/VWindowItem-BVIaHO-S.js.br +0 -0
  91. codex/static_root/assets/VWindowItem-BVIaHO-S.js.gz +0 -0
  92. codex/static_root/assets/{admin-B8Bp2Uih.82c98714bcf1.css → admin-D4sw3N4T.b590f88a62cf.css} +1 -1
  93. codex/static_root/assets/admin-D4sw3N4T.b590f88a62cf.css.br +0 -0
  94. codex/static_root/assets/admin-D4sw3N4T.b590f88a62cf.css.gz +0 -0
  95. codex/static_root/assets/{admin-B8Bp2Uih.css → admin-D4sw3N4T.css} +1 -1
  96. codex/static_root/assets/admin-D4sw3N4T.css.br +0 -0
  97. codex/static_root/assets/admin-D4sw3N4T.css.gz +0 -0
  98. codex/static_root/assets/admin-S53JleJt.f629d90f73a1.js +1 -0
  99. codex/static_root/assets/admin-S53JleJt.f629d90f73a1.js.br +0 -0
  100. codex/static_root/assets/admin-S53JleJt.f629d90f73a1.js.gz +0 -0
  101. codex/static_root/assets/admin-S53JleJt.js +1 -0
  102. codex/static_root/assets/admin-S53JleJt.js.br +0 -0
  103. codex/static_root/assets/admin-S53JleJt.js.gz +0 -0
  104. codex/static_root/assets/admin-drawer-panel-CnAnGx7w.1e4eb021cb21.js +56 -0
  105. codex/static_root/assets/admin-drawer-panel-CnAnGx7w.1e4eb021cb21.js.br +0 -0
  106. codex/static_root/assets/admin-drawer-panel-CnAnGx7w.1e4eb021cb21.js.gz +0 -0
  107. codex/static_root/assets/admin-drawer-panel-CnAnGx7w.js +56 -0
  108. codex/static_root/assets/admin-drawer-panel-CnAnGx7w.js.br +0 -0
  109. codex/static_root/assets/admin-drawer-panel-CnAnGx7w.js.gz +0 -0
  110. codex/static_root/assets/browser-BHHgqDP7.7ada4400d63f.js +1 -0
  111. codex/static_root/assets/browser-BHHgqDP7.7ada4400d63f.js.br +0 -0
  112. codex/static_root/assets/browser-BHHgqDP7.7ada4400d63f.js.gz +0 -0
  113. codex/static_root/assets/browser-BHHgqDP7.js +1 -0
  114. codex/static_root/assets/browser-BHHgqDP7.js.br +0 -0
  115. codex/static_root/assets/browser-BHHgqDP7.js.gz +0 -0
  116. codex/static_root/assets/{browser-DP9eEJ0M.css → browser-Cy0OgQJC.css} +1 -1
  117. codex/static_root/assets/browser-Cy0OgQJC.css.br +0 -0
  118. codex/static_root/assets/browser-Cy0OgQJC.css.gz +0 -0
  119. codex/static_root/assets/{browser-DP9eEJ0M.276e8636f8fc.css → browser-Cy0OgQJC.fabbd1aaffcf.css} +1 -1
  120. codex/static_root/assets/browser-Cy0OgQJC.fabbd1aaffcf.css.br +0 -0
  121. codex/static_root/assets/browser-Cy0OgQJC.fabbd1aaffcf.css.gz +0 -0
  122. codex/static_root/assets/change-password-dialog-Du1bwEt1.a4c0205c9bc4.js +1 -0
  123. codex/static_root/assets/change-password-dialog-Du1bwEt1.a4c0205c9bc4.js.br +0 -0
  124. codex/static_root/assets/change-password-dialog-Du1bwEt1.a4c0205c9bc4.js.gz +0 -0
  125. codex/static_root/assets/change-password-dialog-Du1bwEt1.js +1 -0
  126. codex/static_root/assets/change-password-dialog-Du1bwEt1.js.br +0 -0
  127. codex/static_root/assets/change-password-dialog-Du1bwEt1.js.gz +0 -0
  128. codex/static_root/assets/confirm-dialog-eKN71B8a.af6187dc12bd.js +1 -0
  129. codex/static_root/assets/confirm-dialog-eKN71B8a.af6187dc12bd.js.br +0 -0
  130. codex/static_root/assets/confirm-dialog-eKN71B8a.af6187dc12bd.js.gz +0 -0
  131. codex/static_root/assets/confirm-dialog-eKN71B8a.js +1 -0
  132. codex/static_root/assets/confirm-dialog-eKN71B8a.js.br +0 -0
  133. codex/static_root/assets/confirm-dialog-eKN71B8a.js.gz +0 -0
  134. codex/static_root/assets/{datetime-column-uaXWFgF_.29c6d50b483e.js → datetime-column-CWp600fz.e8a969126bf5.js} +1 -1
  135. codex/static_root/assets/datetime-column-CWp600fz.e8a969126bf5.js.br +0 -0
  136. codex/static_root/assets/datetime-column-CWp600fz.e8a969126bf5.js.gz +0 -0
  137. codex/static_root/assets/{datetime-column-uaXWFgF_.js → datetime-column-CWp600fz.js} +1 -1
  138. codex/static_root/assets/datetime-column-CWp600fz.js.br +0 -0
  139. codex/static_root/assets/datetime-column-CWp600fz.js.gz +0 -0
  140. codex/static_root/assets/{filter-DS84uTvk.4fbebd4832bc.js → filter-_XbKRiIR.2c7ac68a2d03.js} +1 -1
  141. codex/static_root/assets/filter-_XbKRiIR.2c7ac68a2d03.js.br +0 -0
  142. codex/static_root/assets/filter-_XbKRiIR.2c7ac68a2d03.js.gz +0 -0
  143. codex/static_root/assets/{filter-DS84uTvk.js → filter-_XbKRiIR.js} +1 -1
  144. codex/static_root/assets/filter-_XbKRiIR.js.br +0 -0
  145. codex/static_root/assets/filter-_XbKRiIR.js.gz +0 -0
  146. codex/static_root/assets/flag-tab-DBqpLKi7.css +1 -0
  147. codex/static_root/assets/flag-tab-DBqpLKi7.css.br +0 -0
  148. codex/static_root/assets/flag-tab-DBqpLKi7.css.gz +0 -0
  149. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css +1 -0
  150. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.br +0 -0
  151. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.gz +0 -0
  152. codex/static_root/assets/flag-tab-DR_nY0Jg.7323e386c6ed.js +1 -0
  153. codex/static_root/assets/flag-tab-DR_nY0Jg.7323e386c6ed.js.br +0 -0
  154. codex/static_root/assets/flag-tab-DR_nY0Jg.7323e386c6ed.js.gz +0 -0
  155. codex/static_root/assets/flag-tab-DR_nY0Jg.js +1 -0
  156. codex/static_root/assets/flag-tab-DR_nY0Jg.js.br +0 -0
  157. codex/static_root/assets/flag-tab-DR_nY0Jg.js.gz +0 -0
  158. codex/static_root/assets/group-tab-JKsMHOmK.d2c2f3fceec1.js +1 -0
  159. codex/static_root/assets/group-tab-JKsMHOmK.d2c2f3fceec1.js.br +0 -0
  160. codex/static_root/assets/group-tab-JKsMHOmK.d2c2f3fceec1.js.gz +0 -0
  161. codex/static_root/assets/group-tab-JKsMHOmK.js +1 -0
  162. codex/static_root/assets/group-tab-JKsMHOmK.js.br +0 -0
  163. codex/static_root/assets/group-tab-JKsMHOmK.js.gz +0 -0
  164. codex/static_root/assets/http-error-Bw1wUv3U.c8313a2fb129.js +1 -0
  165. codex/static_root/assets/http-error-Bw1wUv3U.c8313a2fb129.js.br +0 -0
  166. codex/static_root/assets/http-error-Bw1wUv3U.c8313a2fb129.js.gz +0 -0
  167. codex/static_root/assets/http-error-Bw1wUv3U.js +1 -0
  168. codex/static_root/assets/http-error-Bw1wUv3U.js.br +0 -0
  169. codex/static_root/assets/http-error-Bw1wUv3U.js.gz +0 -0
  170. codex/static_root/assets/{library-tab-BN0SfPcH.913e236f625e.css → library-tab-BygwYPnO.94e92aa60bf2.css} +1 -1
  171. codex/static_root/assets/library-tab-BygwYPnO.94e92aa60bf2.css.br +0 -0
  172. codex/static_root/assets/library-tab-BygwYPnO.94e92aa60bf2.css.gz +0 -0
  173. codex/static_root/assets/{library-tab-BN0SfPcH.css → library-tab-BygwYPnO.css} +1 -1
  174. codex/static_root/assets/library-tab-BygwYPnO.css.br +0 -0
  175. codex/static_root/assets/library-tab-BygwYPnO.css.gz +0 -0
  176. codex/static_root/assets/library-tab-D9GTugZ6.8e3e6ebd38b7.js +1 -0
  177. codex/static_root/assets/library-tab-D9GTugZ6.8e3e6ebd38b7.js.br +0 -0
  178. codex/static_root/assets/library-tab-D9GTugZ6.8e3e6ebd38b7.js.gz +0 -0
  179. codex/static_root/assets/library-tab-D9GTugZ6.js +1 -0
  180. codex/static_root/assets/library-tab-D9GTugZ6.js.br +0 -0
  181. codex/static_root/assets/library-tab-D9GTugZ6.js.gz +0 -0
  182. codex/static_root/assets/main-BJiV8IG3.9d708627091f.js +6 -0
  183. codex/static_root/assets/main-BJiV8IG3.9d708627091f.js.br +0 -0
  184. codex/static_root/assets/main-BJiV8IG3.9d708627091f.js.gz +0 -0
  185. codex/static_root/assets/main-BJiV8IG3.js +6 -0
  186. codex/static_root/assets/main-BJiV8IG3.js.br +0 -0
  187. codex/static_root/assets/main-BJiV8IG3.js.gz +0 -0
  188. codex/static_root/assets/pagination-toolbar-i2VoXaGH.c3dbb703af2e.js +1 -0
  189. codex/static_root/assets/pagination-toolbar-i2VoXaGH.c3dbb703af2e.js.br +0 -0
  190. codex/static_root/assets/pagination-toolbar-i2VoXaGH.c3dbb703af2e.js.gz +0 -0
  191. codex/static_root/assets/pagination-toolbar-i2VoXaGH.js +1 -0
  192. codex/static_root/assets/pagination-toolbar-i2VoXaGH.js.br +0 -0
  193. codex/static_root/assets/pagination-toolbar-i2VoXaGH.js.gz +0 -0
  194. codex/static_root/assets/{pdf-doc-C-4EM9-d.ce9cf66bd4c3.js → pdf-doc-BLxZLD38.4cf9622c535f.js} +1 -1
  195. codex/static_root/assets/pdf-doc-BLxZLD38.4cf9622c535f.js.br +0 -0
  196. codex/static_root/assets/pdf-doc-BLxZLD38.4cf9622c535f.js.gz +0 -0
  197. codex/static_root/assets/{pdf-doc-C-4EM9-d.js → pdf-doc-BLxZLD38.js} +1 -1
  198. codex/static_root/assets/pdf-doc-BLxZLD38.js.br +0 -0
  199. codex/static_root/assets/pdf-doc-BLxZLD38.js.gz +0 -0
  200. codex/static_root/assets/reader-D2O_yHTW.70d616ddc2cc.js +2 -0
  201. codex/static_root/assets/reader-D2O_yHTW.70d616ddc2cc.js.br +0 -0
  202. codex/static_root/assets/reader-D2O_yHTW.70d616ddc2cc.js.gz +0 -0
  203. codex/static_root/assets/reader-D2O_yHTW.js +2 -0
  204. codex/static_root/assets/reader-D2O_yHTW.js.br +0 -0
  205. codex/static_root/assets/reader-D2O_yHTW.js.gz +0 -0
  206. codex/static_root/assets/{reader-DOQuhDYO.css → reader-YbzUiD0T.css} +1 -1
  207. codex/static_root/assets/reader-YbzUiD0T.css.br +0 -0
  208. codex/static_root/assets/reader-YbzUiD0T.css.gz +0 -0
  209. codex/static_root/assets/{reader-DOQuhDYO.df559ad29ab3.css → reader-YbzUiD0T.efb15835b39d.css} +1 -1
  210. codex/static_root/assets/reader-YbzUiD0T.efb15835b39d.css.br +0 -0
  211. codex/static_root/assets/reader-YbzUiD0T.efb15835b39d.css.gz +0 -0
  212. codex/static_root/assets/{relation-chips-Bsc-gUxE.98e65384c3c9.css → relation-chips-BGitp3yx.b3e7d178a615.css} +1 -1
  213. codex/static_root/assets/relation-chips-BGitp3yx.b3e7d178a615.css.br +0 -0
  214. codex/static_root/assets/relation-chips-BGitp3yx.b3e7d178a615.css.gz +0 -0
  215. codex/static_root/assets/{relation-chips-Bsc-gUxE.css → relation-chips-BGitp3yx.css} +1 -1
  216. codex/static_root/assets/relation-chips-BGitp3yx.css.br +0 -0
  217. codex/static_root/assets/relation-chips-BGitp3yx.css.gz +0 -0
  218. codex/static_root/assets/relation-chips-CmeSIsRq.f169f7c3f48d.js +1 -0
  219. codex/static_root/assets/relation-chips-CmeSIsRq.f169f7c3f48d.js.br +0 -0
  220. codex/static_root/assets/relation-chips-CmeSIsRq.f169f7c3f48d.js.gz +0 -0
  221. codex/static_root/assets/relation-chips-CmeSIsRq.js +1 -0
  222. codex/static_root/assets/relation-chips-CmeSIsRq.js.br +0 -0
  223. codex/static_root/assets/relation-chips-CmeSIsRq.js.gz +0 -0
  224. codex/static_root/assets/settings-drawer-XH4sNDNT.98ee4b24901c.js +2 -0
  225. codex/static_root/assets/settings-drawer-XH4sNDNT.98ee4b24901c.js.br +0 -0
  226. codex/static_root/assets/settings-drawer-XH4sNDNT.98ee4b24901c.js.gz +0 -0
  227. codex/static_root/assets/settings-drawer-XH4sNDNT.js +2 -0
  228. codex/static_root/assets/settings-drawer-XH4sNDNT.js.br +0 -0
  229. codex/static_root/assets/settings-drawer-XH4sNDNT.js.gz +0 -0
  230. codex/static_root/assets/stats-tab-BGxkeKnY.44cf18ca895d.js +1 -0
  231. codex/static_root/assets/stats-tab-BGxkeKnY.44cf18ca895d.js.br +0 -0
  232. codex/static_root/assets/stats-tab-BGxkeKnY.44cf18ca895d.js.gz +0 -0
  233. codex/static_root/assets/stats-tab-BGxkeKnY.js +1 -0
  234. codex/static_root/assets/stats-tab-BGxkeKnY.js.br +0 -0
  235. codex/static_root/assets/stats-tab-BGxkeKnY.js.gz +0 -0
  236. codex/static_root/assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css +1 -0
  237. codex/static_root/assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css.br +0 -0
  238. codex/static_root/assets/stats-tab-CI0u-X7Y.2d1b6a0d4139.css.gz +0 -0
  239. codex/static_root/assets/stats-tab-CI0u-X7Y.css +1 -0
  240. codex/static_root/assets/stats-tab-CI0u-X7Y.css.br +0 -0
  241. codex/static_root/assets/stats-tab-CI0u-X7Y.css.gz +0 -0
  242. codex/static_root/assets/task-tab-B74Kah_b.58627993d3c6.js +1 -0
  243. codex/static_root/assets/task-tab-B74Kah_b.58627993d3c6.js.br +0 -0
  244. codex/static_root/assets/task-tab-B74Kah_b.58627993d3c6.js.gz +0 -0
  245. codex/static_root/assets/task-tab-B74Kah_b.js +1 -0
  246. codex/static_root/assets/task-tab-B74Kah_b.js.br +0 -0
  247. codex/static_root/assets/task-tab-B74Kah_b.js.gz +0 -0
  248. codex/static_root/assets/unauthorized-BF45der6.d34f8022124b.js +1 -0
  249. codex/static_root/assets/unauthorized-BF45der6.d34f8022124b.js.br +0 -0
  250. codex/static_root/assets/unauthorized-BF45der6.d34f8022124b.js.gz +0 -0
  251. codex/static_root/assets/unauthorized-BF45der6.js +1 -0
  252. codex/static_root/assets/unauthorized-BF45der6.js.br +0 -0
  253. codex/static_root/assets/unauthorized-BF45der6.js.gz +0 -0
  254. codex/static_root/assets/user-tab-BP2TTPg5.e63a5661a1a5.js +1 -0
  255. codex/static_root/assets/user-tab-BP2TTPg5.e63a5661a1a5.js.br +0 -0
  256. codex/static_root/assets/user-tab-BP2TTPg5.e63a5661a1a5.js.gz +0 -0
  257. codex/static_root/assets/user-tab-BP2TTPg5.js +1 -0
  258. codex/static_root/assets/user-tab-BP2TTPg5.js.br +0 -0
  259. codex/static_root/assets/user-tab-BP2TTPg5.js.gz +0 -0
  260. codex/static_root/{manifest.80e911824648.json → manifest.7033f9a22987.json} +230 -242
  261. codex/static_root/manifest.7033f9a22987.json.br +0 -0
  262. codex/static_root/manifest.7033f9a22987.json.gz +0 -0
  263. codex/static_root/manifest.json +230 -242
  264. codex/static_root/manifest.json.br +0 -0
  265. codex/static_root/manifest.json.gz +0 -0
  266. codex/static_root/staticfiles.json +1 -1
  267. codex/urls/root.py +12 -2
  268. codex/views/admin/api_key.py +1 -1
  269. codex/views/admin/flag.py +1 -1
  270. codex/views/admin/group.py +1 -1
  271. codex/views/admin/library.py +1 -1
  272. codex/views/admin/stats.py +41 -155
  273. codex/views/admin/tasks.py +1 -1
  274. codex/views/admin/user.py +1 -1
  275. codex/views/browser/browser.py +4 -1
  276. codex/views/browser/filters/field.py +15 -6
  277. codex/views/browser/paginate.py +61 -11
  278. codex/views/browser/validate.py +7 -5
  279. codex/views/opds/binary.py +1 -3
  280. codex/views/opds/const.py +10 -0
  281. codex/views/opds/util.py +10 -0
  282. codex/views/opds/v1/entry/entry.py +14 -18
  283. codex/views/opds/v1/feed.py +10 -24
  284. codex/views/opds/v1/links.py +1 -0
  285. codex/views/reader/arcs.py +65 -53
  286. codex/views/reader/books.py +38 -38
  287. codex/views/reader/init.py +7 -5
  288. codex/views/reader/reader.py +0 -2
  289. {codex-1.6.2.dist-info → codex-1.6.4.dist-info}/METADATA +18 -7
  290. {codex-1.6.2.dist-info → codex-1.6.4.dist-info}/RECORD +293 -289
  291. codex/serializers/admin.py +0 -268
  292. codex/settings/logging.py +0 -20
  293. codex/static_root/assets/VCheckbox-DUxuAZcY.46ab94043464.js +0 -1
  294. codex/static_root/assets/VCheckbox-DUxuAZcY.46ab94043464.js.br +0 -0
  295. codex/static_root/assets/VCheckbox-DUxuAZcY.46ab94043464.js.gz +0 -0
  296. codex/static_root/assets/VCheckbox-DUxuAZcY.js +0 -1
  297. codex/static_root/assets/VCheckbox-DUxuAZcY.js.br +0 -0
  298. codex/static_root/assets/VCheckbox-DUxuAZcY.js.gz +0 -0
  299. codex/static_root/assets/VCheckboxBtn-BTFFFGx3.0cbde4eb9a65.js +0 -1
  300. codex/static_root/assets/VCheckboxBtn-BTFFFGx3.0cbde4eb9a65.js.br +0 -0
  301. codex/static_root/assets/VCheckboxBtn-BTFFFGx3.0cbde4eb9a65.js.gz +0 -0
  302. codex/static_root/assets/VCheckboxBtn-BTFFFGx3.js +0 -1
  303. codex/static_root/assets/VCheckboxBtn-BTFFFGx3.js.br +0 -0
  304. codex/static_root/assets/VCheckboxBtn-BTFFFGx3.js.gz +0 -0
  305. codex/static_root/assets/VCombobox-CGyBgdqr.2f85598cc1a4.js.br +0 -0
  306. codex/static_root/assets/VCombobox-CGyBgdqr.2f85598cc1a4.js.gz +0 -0
  307. codex/static_root/assets/VCombobox-CGyBgdqr.js.br +0 -0
  308. codex/static_root/assets/VCombobox-CGyBgdqr.js.gz +0 -0
  309. codex/static_root/assets/VDialog-DTWAoZBU.b8c4c276e9b2.js +0 -1
  310. codex/static_root/assets/VDialog-DTWAoZBU.b8c4c276e9b2.js.br +0 -0
  311. codex/static_root/assets/VDialog-DTWAoZBU.b8c4c276e9b2.js.gz +0 -0
  312. codex/static_root/assets/VDialog-DTWAoZBU.js +0 -1
  313. codex/static_root/assets/VDialog-DTWAoZBU.js.br +0 -0
  314. codex/static_root/assets/VDialog-DTWAoZBU.js.gz +0 -0
  315. codex/static_root/assets/VExpansionPanels-D4psrz4h.b55b901da65f.js +0 -1
  316. codex/static_root/assets/VExpansionPanels-D4psrz4h.b55b901da65f.js.br +0 -0
  317. codex/static_root/assets/VExpansionPanels-D4psrz4h.b55b901da65f.js.gz +0 -0
  318. codex/static_root/assets/VExpansionPanels-D4psrz4h.js +0 -1
  319. codex/static_root/assets/VExpansionPanels-D4psrz4h.js.br +0 -0
  320. codex/static_root/assets/VExpansionPanels-D4psrz4h.js.gz +0 -0
  321. codex/static_root/assets/VRadioGroup-BY572TP-.6d47a94795de.js +0 -1
  322. codex/static_root/assets/VRadioGroup-BY572TP-.6d47a94795de.js.br +0 -2
  323. codex/static_root/assets/VRadioGroup-BY572TP-.6d47a94795de.js.gz +0 -0
  324. codex/static_root/assets/VRadioGroup-BY572TP-.js +0 -1
  325. codex/static_root/assets/VRadioGroup-BY572TP-.js.br +0 -2
  326. codex/static_root/assets/VRadioGroup-BY572TP-.js.gz +0 -0
  327. codex/static_root/assets/VSelect-Bnhj5kBc.fdcd87c9e253.js +0 -1
  328. codex/static_root/assets/VSelect-Bnhj5kBc.fdcd87c9e253.js.br +0 -0
  329. codex/static_root/assets/VSelect-Bnhj5kBc.fdcd87c9e253.js.gz +0 -0
  330. codex/static_root/assets/VSelect-Bnhj5kBc.js +0 -1
  331. codex/static_root/assets/VSelect-Bnhj5kBc.js.br +0 -0
  332. codex/static_root/assets/VSelect-Bnhj5kBc.js.gz +0 -0
  333. codex/static_root/assets/VSelectionControl-DXxRmssH.252890f79cc6.js.br +0 -0
  334. codex/static_root/assets/VSelectionControl-DXxRmssH.252890f79cc6.js.gz +0 -0
  335. codex/static_root/assets/VSelectionControl-DXxRmssH.js.br +0 -0
  336. codex/static_root/assets/VSelectionControl-DXxRmssH.js.gz +0 -0
  337. codex/static_root/assets/VSlideGroup-DYJ3EYZI.a2542c5f90c4.js.br +0 -0
  338. codex/static_root/assets/VSlideGroup-DYJ3EYZI.a2542c5f90c4.js.gz +0 -0
  339. codex/static_root/assets/VSlideGroup-DYJ3EYZI.js.br +0 -0
  340. codex/static_root/assets/VSlideGroup-DYJ3EYZI.js.gz +0 -0
  341. codex/static_root/assets/VTable-BveGtxei.7f76f4ef812b.js.br +0 -0
  342. codex/static_root/assets/VTable-BveGtxei.7f76f4ef812b.js.gz +0 -0
  343. codex/static_root/assets/VTable-BveGtxei.js.br +0 -0
  344. codex/static_root/assets/VTable-BveGtxei.js.gz +0 -0
  345. codex/static_root/assets/VTextField-BayL7C1D.6e53c61b3760.js +0 -1
  346. codex/static_root/assets/VTextField-BayL7C1D.6e53c61b3760.js.br +0 -0
  347. codex/static_root/assets/VTextField-BayL7C1D.6e53c61b3760.js.gz +0 -0
  348. codex/static_root/assets/VTextField-BayL7C1D.js +0 -1
  349. codex/static_root/assets/VTextField-BayL7C1D.js.br +0 -0
  350. codex/static_root/assets/VTextField-BayL7C1D.js.gz +0 -0
  351. codex/static_root/assets/VWindowItem-FBuIO_rT.8610c7e83905.js.br +0 -0
  352. codex/static_root/assets/VWindowItem-FBuIO_rT.8610c7e83905.js.gz +0 -0
  353. codex/static_root/assets/VWindowItem-FBuIO_rT.js.br +0 -0
  354. codex/static_root/assets/VWindowItem-FBuIO_rT.js.gz +0 -0
  355. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.br +0 -0
  356. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.gz +0 -0
  357. codex/static_root/assets/admin-B8Bp2Uih.css.br +0 -0
  358. codex/static_root/assets/admin-B8Bp2Uih.css.gz +0 -0
  359. codex/static_root/assets/admin-BH6uiYBb.d51c720fa05c.js +0 -1
  360. codex/static_root/assets/admin-BH6uiYBb.d51c720fa05c.js.br +0 -0
  361. codex/static_root/assets/admin-BH6uiYBb.d51c720fa05c.js.gz +0 -0
  362. codex/static_root/assets/admin-BH6uiYBb.js +0 -1
  363. codex/static_root/assets/admin-BH6uiYBb.js.br +0 -0
  364. codex/static_root/assets/admin-BH6uiYBb.js.gz +0 -0
  365. codex/static_root/assets/admin-drawer-panel-DsgLbfnD.7c409b430d79.js +0 -30
  366. codex/static_root/assets/admin-drawer-panel-DsgLbfnD.7c409b430d79.js.br +0 -0
  367. codex/static_root/assets/admin-drawer-panel-DsgLbfnD.7c409b430d79.js.gz +0 -0
  368. codex/static_root/assets/admin-drawer-panel-DsgLbfnD.js +0 -30
  369. codex/static_root/assets/admin-drawer-panel-DsgLbfnD.js.br +0 -0
  370. codex/static_root/assets/admin-drawer-panel-DsgLbfnD.js.gz +0 -0
  371. codex/static_root/assets/browser-BVciW8XB.ab1d75272aa7.js +0 -1
  372. codex/static_root/assets/browser-BVciW8XB.ab1d75272aa7.js.br +0 -0
  373. codex/static_root/assets/browser-BVciW8XB.ab1d75272aa7.js.gz +0 -0
  374. codex/static_root/assets/browser-BVciW8XB.js +0 -1
  375. codex/static_root/assets/browser-BVciW8XB.js.br +0 -0
  376. codex/static_root/assets/browser-BVciW8XB.js.gz +0 -0
  377. codex/static_root/assets/browser-DP9eEJ0M.276e8636f8fc.css.br +0 -0
  378. codex/static_root/assets/browser-DP9eEJ0M.276e8636f8fc.css.gz +0 -0
  379. codex/static_root/assets/browser-DP9eEJ0M.css.br +0 -0
  380. codex/static_root/assets/browser-DP9eEJ0M.css.gz +0 -0
  381. codex/static_root/assets/change-password-dialog-B-Sd5U5p.adf0a0f02866.js +0 -1
  382. codex/static_root/assets/change-password-dialog-B-Sd5U5p.adf0a0f02866.js.br +0 -0
  383. codex/static_root/assets/change-password-dialog-B-Sd5U5p.adf0a0f02866.js.gz +0 -0
  384. codex/static_root/assets/change-password-dialog-B-Sd5U5p.js +0 -1
  385. codex/static_root/assets/change-password-dialog-B-Sd5U5p.js.br +0 -0
  386. codex/static_root/assets/change-password-dialog-B-Sd5U5p.js.gz +0 -0
  387. codex/static_root/assets/confirm-dialog-CYEBgtj5.a5f142656c12.js +0 -1
  388. codex/static_root/assets/confirm-dialog-CYEBgtj5.a5f142656c12.js.br +0 -0
  389. codex/static_root/assets/confirm-dialog-CYEBgtj5.a5f142656c12.js.gz +0 -0
  390. codex/static_root/assets/confirm-dialog-CYEBgtj5.js +0 -1
  391. codex/static_root/assets/confirm-dialog-CYEBgtj5.js.br +0 -0
  392. codex/static_root/assets/confirm-dialog-CYEBgtj5.js.gz +0 -0
  393. codex/static_root/assets/datetime-column-uaXWFgF_.29c6d50b483e.js.br +0 -0
  394. codex/static_root/assets/datetime-column-uaXWFgF_.29c6d50b483e.js.gz +0 -0
  395. codex/static_root/assets/datetime-column-uaXWFgF_.js.br +0 -0
  396. codex/static_root/assets/datetime-column-uaXWFgF_.js.gz +0 -0
  397. codex/static_root/assets/filter-DS84uTvk.4fbebd4832bc.js.br +0 -0
  398. codex/static_root/assets/filter-DS84uTvk.4fbebd4832bc.js.gz +0 -0
  399. codex/static_root/assets/filter-DS84uTvk.js.br +0 -0
  400. codex/static_root/assets/filter-DS84uTvk.js.gz +0 -0
  401. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +0 -1
  402. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
  403. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
  404. codex/static_root/assets/flag-tab-BNwbLfrN.css +0 -1
  405. codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
  406. codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
  407. codex/static_root/assets/flag-tab-iJTJldQ1.213201f8e03b.js +0 -1
  408. codex/static_root/assets/flag-tab-iJTJldQ1.213201f8e03b.js.br +0 -0
  409. codex/static_root/assets/flag-tab-iJTJldQ1.213201f8e03b.js.gz +0 -0
  410. codex/static_root/assets/flag-tab-iJTJldQ1.js +0 -1
  411. codex/static_root/assets/flag-tab-iJTJldQ1.js.br +0 -0
  412. codex/static_root/assets/flag-tab-iJTJldQ1.js.gz +0 -0
  413. codex/static_root/assets/group-tab-DdmGE4gB.48ef83a4c7cd.js +0 -1
  414. codex/static_root/assets/group-tab-DdmGE4gB.48ef83a4c7cd.js.br +0 -0
  415. codex/static_root/assets/group-tab-DdmGE4gB.48ef83a4c7cd.js.gz +0 -0
  416. codex/static_root/assets/group-tab-DdmGE4gB.js +0 -1
  417. codex/static_root/assets/group-tab-DdmGE4gB.js.br +0 -0
  418. codex/static_root/assets/group-tab-DdmGE4gB.js.gz +0 -0
  419. codex/static_root/assets/http-error-HtOe8jPa.141ad665f81d.js +0 -1
  420. codex/static_root/assets/http-error-HtOe8jPa.141ad665f81d.js.br +0 -0
  421. codex/static_root/assets/http-error-HtOe8jPa.141ad665f81d.js.gz +0 -0
  422. codex/static_root/assets/http-error-HtOe8jPa.js +0 -1
  423. codex/static_root/assets/http-error-HtOe8jPa.js.br +0 -0
  424. codex/static_root/assets/http-error-HtOe8jPa.js.gz +0 -0
  425. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.br +0 -0
  426. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.gz +0 -0
  427. codex/static_root/assets/library-tab-BN0SfPcH.css.br +0 -0
  428. codex/static_root/assets/library-tab-BN0SfPcH.css.gz +0 -0
  429. codex/static_root/assets/library-tab-DLAJV6j2.dae6292bbf28.js +0 -1
  430. codex/static_root/assets/library-tab-DLAJV6j2.dae6292bbf28.js.br +0 -0
  431. codex/static_root/assets/library-tab-DLAJV6j2.dae6292bbf28.js.gz +0 -0
  432. codex/static_root/assets/library-tab-DLAJV6j2.js +0 -1
  433. codex/static_root/assets/library-tab-DLAJV6j2.js.br +0 -0
  434. codex/static_root/assets/library-tab-DLAJV6j2.js.gz +0 -0
  435. codex/static_root/assets/main-BjGE3kSi.22c1b19a9e19.js +0 -32
  436. codex/static_root/assets/main-BjGE3kSi.22c1b19a9e19.js.br +0 -0
  437. codex/static_root/assets/main-BjGE3kSi.22c1b19a9e19.js.gz +0 -0
  438. codex/static_root/assets/main-BjGE3kSi.js +0 -32
  439. codex/static_root/assets/main-BjGE3kSi.js.br +0 -0
  440. codex/static_root/assets/main-BjGE3kSi.js.gz +0 -0
  441. codex/static_root/assets/pagination-toolbar-C8CSryCU.9b61f95fd710.js +0 -1
  442. codex/static_root/assets/pagination-toolbar-C8CSryCU.9b61f95fd710.js.br +0 -0
  443. codex/static_root/assets/pagination-toolbar-C8CSryCU.9b61f95fd710.js.gz +0 -0
  444. codex/static_root/assets/pagination-toolbar-C8CSryCU.js +0 -1
  445. codex/static_root/assets/pagination-toolbar-C8CSryCU.js.br +0 -0
  446. codex/static_root/assets/pagination-toolbar-C8CSryCU.js.gz +0 -0
  447. codex/static_root/assets/pdf-doc-C-4EM9-d.ce9cf66bd4c3.js.br +0 -0
  448. codex/static_root/assets/pdf-doc-C-4EM9-d.ce9cf66bd4c3.js.gz +0 -0
  449. codex/static_root/assets/pdf-doc-C-4EM9-d.js.br +0 -0
  450. codex/static_root/assets/pdf-doc-C-4EM9-d.js.gz +0 -0
  451. codex/static_root/assets/reader-C5OTEQ7N.fae52c1fee51.js +0 -2
  452. codex/static_root/assets/reader-C5OTEQ7N.fae52c1fee51.js.br +0 -0
  453. codex/static_root/assets/reader-C5OTEQ7N.fae52c1fee51.js.gz +0 -0
  454. codex/static_root/assets/reader-C5OTEQ7N.js +0 -2
  455. codex/static_root/assets/reader-C5OTEQ7N.js.br +0 -0
  456. codex/static_root/assets/reader-C5OTEQ7N.js.gz +0 -0
  457. codex/static_root/assets/reader-DOQuhDYO.css.br +0 -0
  458. codex/static_root/assets/reader-DOQuhDYO.css.gz +0 -0
  459. codex/static_root/assets/reader-DOQuhDYO.df559ad29ab3.css.br +0 -0
  460. codex/static_root/assets/reader-DOQuhDYO.df559ad29ab3.css.gz +0 -0
  461. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.br +0 -0
  462. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.gz +0 -0
  463. codex/static_root/assets/relation-chips-Bsc-gUxE.css.br +0 -0
  464. codex/static_root/assets/relation-chips-Bsc-gUxE.css.gz +0 -0
  465. codex/static_root/assets/relation-chips-C4LQSHRc.3c85433df91c.js +0 -1
  466. codex/static_root/assets/relation-chips-C4LQSHRc.3c85433df91c.js.br +0 -0
  467. codex/static_root/assets/relation-chips-C4LQSHRc.3c85433df91c.js.gz +0 -0
  468. codex/static_root/assets/relation-chips-C4LQSHRc.js +0 -1
  469. codex/static_root/assets/relation-chips-C4LQSHRc.js.br +0 -0
  470. codex/static_root/assets/relation-chips-C4LQSHRc.js.gz +0 -0
  471. codex/static_root/assets/settings-drawer-aTAAoX2A.2f21008ade35.js +0 -2
  472. codex/static_root/assets/settings-drawer-aTAAoX2A.2f21008ade35.js.br +0 -0
  473. codex/static_root/assets/settings-drawer-aTAAoX2A.2f21008ade35.js.gz +0 -0
  474. codex/static_root/assets/settings-drawer-aTAAoX2A.js +0 -2
  475. codex/static_root/assets/settings-drawer-aTAAoX2A.js.br +0 -0
  476. codex/static_root/assets/settings-drawer-aTAAoX2A.js.gz +0 -0
  477. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +0 -1
  478. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  479. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  480. codex/static_root/assets/stats-tab-B4yKuY0c.css +0 -1
  481. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  482. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  483. codex/static_root/assets/stats-tab-DL4J3pvZ.b9056e70a70f.js +0 -1
  484. codex/static_root/assets/stats-tab-DL4J3pvZ.b9056e70a70f.js.br +0 -0
  485. codex/static_root/assets/stats-tab-DL4J3pvZ.b9056e70a70f.js.gz +0 -0
  486. codex/static_root/assets/stats-tab-DL4J3pvZ.js +0 -1
  487. codex/static_root/assets/stats-tab-DL4J3pvZ.js.br +0 -0
  488. codex/static_root/assets/stats-tab-DL4J3pvZ.js.gz +0 -0
  489. codex/static_root/assets/task-tab-0t7ZJlwL.1ff1cc14a6aa.js +0 -1
  490. codex/static_root/assets/task-tab-0t7ZJlwL.1ff1cc14a6aa.js.br +0 -0
  491. codex/static_root/assets/task-tab-0t7ZJlwL.1ff1cc14a6aa.js.gz +0 -0
  492. codex/static_root/assets/task-tab-0t7ZJlwL.js +0 -1
  493. codex/static_root/assets/task-tab-0t7ZJlwL.js.br +0 -0
  494. codex/static_root/assets/task-tab-0t7ZJlwL.js.gz +0 -0
  495. codex/static_root/assets/to-case-BCB751sX.4afb5ae1b77d.js +0 -1
  496. codex/static_root/assets/to-case-BCB751sX.js +0 -1
  497. codex/static_root/assets/unauthorized-Ovy_BO5R.598527e8e4fe.js +0 -1
  498. codex/static_root/assets/unauthorized-Ovy_BO5R.598527e8e4fe.js.br +0 -0
  499. codex/static_root/assets/unauthorized-Ovy_BO5R.598527e8e4fe.js.gz +0 -0
  500. codex/static_root/assets/unauthorized-Ovy_BO5R.js +0 -1
  501. codex/static_root/assets/unauthorized-Ovy_BO5R.js.br +0 -0
  502. codex/static_root/assets/unauthorized-Ovy_BO5R.js.gz +0 -0
  503. codex/static_root/assets/user-tab-Cdspo8ie.8e886a1a28e8.js +0 -1
  504. codex/static_root/assets/user-tab-Cdspo8ie.8e886a1a28e8.js.br +0 -0
  505. codex/static_root/assets/user-tab-Cdspo8ie.8e886a1a28e8.js.gz +0 -0
  506. codex/static_root/assets/user-tab-Cdspo8ie.js +0 -1
  507. codex/static_root/assets/user-tab-Cdspo8ie.js.br +0 -0
  508. codex/static_root/assets/user-tab-Cdspo8ie.js.gz +0 -0
  509. codex/static_root/manifest.80e911824648.json.br +0 -0
  510. codex/static_root/manifest.80e911824648.json.gz +0 -0
  511. {codex-1.6.2.dist-info → codex-1.6.4.dist-info}/LICENSE +0 -0
  512. {codex-1.6.2.dist-info → codex-1.6.4.dist-info}/WHEEL +0 -0
  513. {codex-1.6.2.dist-info → codex-1.6.4.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,11 @@
1
1
  """OPDS v1 Entry."""
2
2
 
3
3
  import json
4
+ from contextlib import suppress
4
5
  from datetime import datetime, timezone
5
6
  from urllib.parse import urlencode
6
7
 
8
+ from dateutil import parser
7
9
  from django.urls import reverse
8
10
 
9
11
  from codex.logger.logging import get_logger
@@ -24,11 +26,6 @@ LOG = get_logger(__name__)
24
26
  class OPDS1Entry(OPDS1EntryLinksMixin):
25
27
  """An OPDS entry object."""
26
28
 
27
- _DATE_FORMAT_BASE = "%Y-%m-%dT%H:%M:%S"
28
- _DATE_FORMAT_MS = _DATE_FORMAT_BASE + ".%f%z"
29
- _DATE_FORMAT = _DATE_FORMAT_BASE + "%z"
30
- _DATE_FORMATS = (_DATE_FORMAT_MS, _DATE_FORMAT)
31
-
32
29
  @property
33
30
  def id_tag(self):
34
31
  """GUID is a nav url."""
@@ -69,9 +66,12 @@ class OPDS1Entry(OPDS1EntryLinksMixin):
69
66
  @property
70
67
  def issued(self):
71
68
  """Return the published date."""
69
+ date = ""
72
70
  if self.obj.group == "c":
73
- return self.obj.date
74
- return None
71
+ with suppress(Exception):
72
+ date = self.obj.date.isoformat()
73
+
74
+ return date
75
75
 
76
76
  @property
77
77
  def publisher(self):
@@ -81,17 +81,13 @@ class OPDS1Entry(OPDS1EntryLinksMixin):
81
81
  def _get_datefield(self, key):
82
82
  result = None
83
83
  if not self.fake and (value := getattr(self.obj, key, None)):
84
- for date_format in self._DATE_FORMATS:
85
- try:
86
- if isinstance(value, str):
87
- result = datetime.strptime(value, date_format).astimezone(
88
- timezone.utc
89
- )
90
- if isinstance(value, datetime):
91
- result = value.astimezone(timezone.utc).strftime(date_format)
92
- break
93
- except ValueError:
94
- pass
84
+ try:
85
+ if isinstance(value, str):
86
+ result = parser.parse(value)
87
+ if isinstance(value, datetime):
88
+ result = value.astimezone(timezone.utc).isoformat()
89
+ except ValueError:
90
+ pass
95
91
  return result
96
92
 
97
93
  @property
@@ -17,7 +17,8 @@ from codex.serializers.opds.v1 import (
17
17
  )
18
18
  from codex.views.const import FALSY, MAX_OBJ_PER_PAGE
19
19
  from codex.views.opds.auth import OPDSTemplateView
20
- from codex.views.opds.const import BLANK_TITLE, MimeType
20
+ from codex.views.opds.const import BLANK_TITLE, MimeType, UserAgentNames
21
+ from codex.views.opds.util import get_user_agent_name
21
22
  from codex.views.opds.v1.entry.data import OPDS1EntryData
22
23
  from codex.views.opds.v1.entry.entry import OPDS1Entry
23
24
  from codex.views.opds.v1.links import (
@@ -41,16 +42,6 @@ class OpdsNs:
41
42
  ACQUISITION = "http://opds-spec.org/2010/acquisition"
42
43
 
43
44
 
44
- class UserAgentNames:
45
- """Control whether to hack in facets with nav links."""
46
-
47
- CLIENT_REORDERS = frozenset({"Chunky"})
48
- FACET_SUPPORT = frozenset({"yar"}) # kybooks
49
- SIMPLE_DOWNLOAD_MIME_TYPES = frozenset({"PocketBook Reader"})
50
- # Other known valid names:
51
- # "Panels", "Chunky"
52
-
53
-
54
45
  class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
55
46
  """OPDS 1 Feed."""
56
47
 
@@ -105,10 +96,14 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
105
96
  @property
106
97
  def updated(self):
107
98
  """Use mtime for updated."""
99
+ datestr = ""
108
100
  try:
109
- return self.obj.get("mtime", "")
101
+ mtime = self.obj.get("mtime")
102
+ if mtime:
103
+ datestr = mtime.isoformat() # type: ignore
110
104
  except Exception:
111
105
  LOG.exception("Getting OPDS v1 updated")
106
+ return datestr
112
107
 
113
108
  @property
114
109
  def items_per_page(self):
@@ -218,19 +213,10 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView):
218
213
 
219
214
  def _set_user_agent_variables(self):
220
215
  """Set User Agent variables."""
221
- user_agent = self.request.headers.get("User-Agent")
222
- if not user_agent:
223
- return
224
- user_agent_parts = user_agent.split("/", 1)
225
- if user_agent_parts:
226
- user_agent_name = user_agent_parts[0]
227
- else:
228
- return
216
+ user_agent_name = get_user_agent_name(self.request)
229
217
 
230
- if user_agent_name in UserAgentNames.FACET_SUPPORT:
231
- self.use_facets = True
232
- if user_agent_name in UserAgentNames.CLIENT_REORDERS:
233
- self.skip_order_facets = True
218
+ self.user_facets = user_agent_name in UserAgentNames.FACET_SUPPORT
219
+ self.skip_order_facets = user_agent_name in UserAgentNames.CLIENT_REORDERS
234
220
  if user_agent_name in UserAgentNames.SIMPLE_DOWNLOAD_MIME_TYPES:
235
221
  self.mime_type_map = MimeType.SIMPLE_FILE_TYPE_MAP
236
222
 
@@ -168,6 +168,7 @@ class OPDS1LinksView(OPDS1FacetsView):
168
168
  reverse("opds:authentication:v1"),
169
169
  MimeType.AUTHENTICATION,
170
170
  ),
171
+ OPDS1Link(Rel.START, reverse("opds:v1:start"), MimeType.NAV),
171
172
  OPDS1Link(
172
173
  "search", reverse("opds:v1:opensearch_v1"), MimeType.OPENSEARCH
173
174
  ),
@@ -4,7 +4,10 @@ from types import MappingProxyType
4
4
 
5
5
  from codex.models import AdminFlag
6
6
  from codex.util import max_none
7
- from codex.views.const import FOLDER_GROUP, STORY_ARC_GROUP
7
+ from codex.views.const import (
8
+ FOLDER_GROUP,
9
+ STORY_ARC_GROUP,
10
+ )
8
11
  from codex.views.reader.books import ReaderBooksView
9
12
 
10
13
 
@@ -16,77 +19,86 @@ class ReaderArcsView(ReaderBooksView):
16
19
  super().__init__(*args, **kwargs)
17
20
  self.params: MappingProxyType = MappingProxyType({})
18
21
 
19
- def _get_group_arc(self, book, attr):
20
- """Create the volume arc."""
22
+ def _get_group_arc(self, book, attr, browser_arc_group, arcs, max_mtime): # noqa: PLR0913
23
+ """Append the volume arc."""
24
+ if browser_arc_group == attr[0]:
25
+ return max_mtime
21
26
  group = getattr(book, attr, None)
22
27
  if not group:
23
- return None
28
+ return max_mtime
24
29
 
25
30
  _, arc_pks = self.get_group_pks_from_breadcrumbs([group])
26
31
  if group.pk not in arc_pks:
27
32
  arc_pks = (group.pk,)
28
- return {
29
- "group": attr[0],
30
- "pks": arc_pks,
31
- "name": group.name,
32
- "mtime": group.updated_at,
33
- }
33
+ arcs.append(
34
+ {
35
+ "group": attr[0],
36
+ "pks": arc_pks,
37
+ "name": group.name,
38
+ "mtime": group.updated_at,
39
+ }
40
+ )
41
+ return max_none(max_mtime, group.updated_at)
34
42
 
35
- def _get_folder_arc(self, book):
36
- """Create the folder arc."""
43
+ def _get_folder_arc(self, book, browser_arc_group, arcs, max_mtime):
44
+ """Append the folder arc."""
37
45
  efv_flag = (
38
46
  AdminFlag.objects.only("on")
39
47
  .get(key=AdminFlag.FlagChoices.FOLDER_VIEW.value)
40
48
  .on
41
49
  )
42
- if not efv_flag:
43
- return None
50
+ if not efv_flag or browser_arc_group == FOLDER_GROUP:
51
+ return max_mtime
44
52
 
45
53
  folder = book.parent_folder
46
- return {
47
- "group": FOLDER_GROUP,
48
- "pks": (folder.pk,),
49
- "name": folder.name,
50
- "mtime": folder.updated_at,
51
- }
54
+ arcs.append(
55
+ {
56
+ "group": FOLDER_GROUP,
57
+ "pks": (folder.pk,),
58
+ "name": folder.name,
59
+ "mtime": folder.updated_at,
60
+ }
61
+ )
62
+ return max_none(max_mtime, folder.updated_at)
63
+
64
+ def _get_story_arcs(self, book, browser_arc, arcs, max_mtime):
65
+ """Append the story arcs."""
66
+ if browser_arc.get("group") == STORY_ARC_GROUP:
67
+ browser_arc_pks = frozenset(browser_arc.get("pks", ()))
68
+ else:
69
+ browser_arc_pks = frozenset()
52
70
 
53
- def _get_story_arcs(self, book):
54
- """Create story arcs."""
55
- sas = []
56
- for san in book.story_arc_numbers.all():
71
+ for san in book.story_arc_numbers.all().order_by("story_arc__name"):
57
72
  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"])
73
+ if not browser_arc_pks or sa.pk not in browser_arc_pks:
74
+ arc = {
75
+ "group": "a",
76
+ "pks": (sa.pk,),
77
+ "name": sa.name,
78
+ "mtime": sa.updated_at,
79
+ }
80
+ arcs.append(arc)
81
+ max_mtime = max_none(max_mtime, sa.updated_at)
82
+ return max_mtime
66
83
 
67
84
  def get_arcs(self, book):
68
85
  """Get all series/folder/story arcs."""
69
- # create top arcs
70
86
  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
87
  max_mtime = None
90
- for arc in arcs:
91
- max_mtime = max_none(max_mtime, arc["mtime"])
88
+
89
+ if browser_arc := self.params.get("browser_arc", {}):
90
+ arcs.append(browser_arc)
91
+ browser_arc_mtime = browser_arc.get("mtime")
92
+ max_mtime = max_none(max_mtime, browser_arc_mtime)
93
+
94
+ browser_arc_group = browser_arc.get("group", "")
95
+ max_mtime = self._get_group_arc(
96
+ book, "series", browser_arc_group, arcs, max_mtime
97
+ )
98
+ max_mtime = self._get_group_arc(
99
+ book, "volume", browser_arc_group, arcs, max_mtime
100
+ )
101
+ max_mtime = self._get_folder_arc(book, browser_arc_group, arcs, max_mtime)
102
+ max_mtime = self._get_story_arcs(book, browser_arc, arcs, max_mtime)
103
+
92
104
  return arcs, max_mtime
@@ -6,7 +6,14 @@ from django.db.models import F
6
6
 
7
7
  from codex.models import Bookmark, Comic
8
8
  from codex.views.bookmark import BookmarkBaseView
9
- from codex.views.const import FOLDER_GROUP, NONE_INTEGERFIELD
9
+ from codex.views.browser.filters.field import ComicFieldFilterView
10
+ from codex.views.const import (
11
+ FOLDER_GROUP,
12
+ GROUP_MODEL_MAP,
13
+ GROUP_RELATION,
14
+ NONE_INTEGERFIELD,
15
+ STORY_ARC_GROUP,
16
+ )
10
17
  from codex.views.mixins import SharedAnnotationsMixin
11
18
  from codex.views.reader.init import ReaderInitView
12
19
 
@@ -57,45 +64,30 @@ class ReaderBooksView(BookmarkBaseView, ReaderInitView, SharedAnnotationsMixin):
57
64
 
58
65
  def _get_comics_list(self):
59
66
  """Get the reader naviation group filter."""
60
- select_related = ("series", "volume")
61
- prefetch_related = ()
62
-
63
67
  arc: Mapping = self.params.get("arc", {}) # type: ignore
64
68
 
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")
69
+ arc_group = arc.get("group", "")
70
+ if not GROUP_MODEL_MAP.get(arc_group):
71
+ arc_group = "s"
72
+
73
+ rel = GROUP_RELATION[arc_group]
74
+ fields = _COMIC_FIELDS
75
+ arc_pk_rel = rel + "__pk"
76
+ arc_index = NONE_INTEGERFIELD
77
+ ordering = ()
78
+ arc_pk_select_related = (rel,)
79
+ select_related = ()
80
+ prefetch_related = ()
81
+
82
+ if arc_group == STORY_ARC_GROUP:
83
+ prefetch_related = (*prefetch_related, rel)
72
84
  arc_index = F("story_arc_numbers__number")
73
85
  ordering = ("arc_index", "date", "pk")
74
86
  arc_pk_select_related = ()
75
87
  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
88
+ select_related = (rel,)
89
+ fields = (*_COMIC_FIELDS, rel)
81
90
  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
91
 
100
92
  arc_pks = self._get_reader_arc_pks(
101
93
  arc, arc_pk_select_related, prefetch_related, arc_pk_rel, arc_group
@@ -103,12 +95,20 @@ class ReaderBooksView(BookmarkBaseView, ReaderInitView, SharedAnnotationsMixin):
103
95
  nav_filter = {f"{rel}__in": arc_pks}
104
96
  group_acl_filter = self.get_group_acl_filter(Comic)
105
97
 
98
+ qs = Comic.objects.filter(group_acl_filter).filter(**nav_filter)
99
+ if browser_filters := arc.get("filters"):
100
+ # no search at this time.
101
+ field_filters = ComicFieldFilterView.get_all_comic_field_filters(
102
+ "", browser_filters
103
+ )
104
+ qs = qs.filter(field_filters)
105
+
106
+ if select_related:
107
+ qs = qs.select_related(*select_related)
108
+ if prefetch_related:
109
+ qs = qs.prefetch_related(*prefetch_related)
106
110
  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)
111
+ qs.only(*fields)
112
112
  .annotate(
113
113
  issue_count=F("volume__issue_count"),
114
114
  )
@@ -13,8 +13,8 @@ from codex.views.session import SessionView
13
13
  from codex.views.util import reparse_json_query_params
14
14
 
15
15
  LOG = get_logger(__name__)
16
- VALID_ARC_GROUPS = frozenset({"s", "v", "f", "a"})
17
- _JSON_KEYS = frozenset({"arc", "breadcrumbs", "show"})
16
+ VALID_ARC_GROUPS = "pisvfa"
17
+ _JSON_KEYS = frozenset({"arc", "breadcrumbs", "browser_arc", "show"})
18
18
  _BROWSER_SESSION_DEFAULTS = SessionView.SESSION_DEFAULTS[
19
19
  SessionView.BROWSER_SESSION_KEY
20
20
  ]
@@ -89,12 +89,14 @@ class ReaderInitView(SessionView):
89
89
  # Can't be in the serializer
90
90
  arc = params.get("arc", {})
91
91
 
92
- if arc.get("group") not in VALID_ARC_GROUPS:
92
+ arc_group = arc.get("group", "")
93
+ arc_pks = arc.get("pks", ())
94
+ if arc_group not in VALID_ARC_GROUPS or not arc_pks:
93
95
  top_group = params["top_group"]
94
- if top_group in (FOLDER_GROUP, STORY_ARC_GROUP):
96
+ if top_group in FOLDER_GROUP + STORY_ARC_GROUP:
95
97
  search_groups = (top_group,)
96
98
  else:
97
- search_groups = ("v", "s")
99
+ search_groups = "vsip"
98
100
 
99
101
  group, pks = self.get_group_pks_from_breadcrumbs(search_groups)
100
102
  if not group:
@@ -12,7 +12,6 @@ from codex.logger.logging import get_logger
12
12
  from codex.serializers.reader import ReaderComicsSerializer, ReaderViewInputSerializer
13
13
  from codex.serializers.redirect import ReaderRedirectSerializer
14
14
  from codex.views.reader.arcs import ReaderArcsView
15
- from codex.views.util import pop_name
16
15
 
17
16
  LOG = get_logger(__name__)
18
17
 
@@ -90,7 +89,6 @@ class ReaderView(ReaderArcsView):
90
89
  arc["count"] = current.arc_count # type: ignore
91
90
 
92
91
  close_route = self.get_last_route()
93
- close_route = pop_name(close_route)
94
92
 
95
93
  return {
96
94
  "books": books,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codex
3
- Version: 1.6.2
3
+ Version: 1.6.4
4
4
  Summary: A comic archive web server.
5
5
  Home-page: https://github.com/ajslater/codex
6
6
  License: GPL-3.0-only
@@ -29,7 +29,7 @@ Requires-Dist: ansicolors (>=1.1,<2.0)
29
29
  Requires-Dist: bidict (>=0.23.1,<0.24.0)
30
30
  Requires-Dist: case-converter (>=1.1.0,<2.0.0)
31
31
  Requires-Dist: channels (>=4.0.0,<5.0.0)
32
- Requires-Dist: comicbox[pdf] (>=1.1.8,<2.0.0)
32
+ Requires-Dist: comicbox[pdf] (>=1.1.10,<2.0.0)
33
33
  Requires-Dist: django (>=5.0.6,<6.0.0)
34
34
  Requires-Dist: django-cachalot (>=2.6.2,<3.0.0)
35
35
  Requires-Dist: django-cors-headers (>=4.0,<5.0)
@@ -42,7 +42,7 @@ Requires-Dist: fnvhash (>=0.1,<0.2)
42
42
  Requires-Dist: humanfriendly (>=10.0,<11.0)
43
43
  Requires-Dist: humanize (>=4.0.0,<5.0.0)
44
44
  Requires-Dist: hypercorn[h3] (>=0.17.3,<0.18.0)
45
- Requires-Dist: psutil (>=5.9.4,<6.0.0)
45
+ Requires-Dist: psutil (>=6.0.0,<7.0.0)
46
46
  Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
47
47
  Requires-Dist: requests (>=2.24,<3.0)
48
48
  Requires-Dist: setuptools (>=70.0.0,<71.0.0)
@@ -71,6 +71,7 @@ border-radius: 128px;
71
71
  ## <a name="features">✨ Features</a>
72
72
 
73
73
  - Codex is a web server.
74
+ - GPLv3 Licenced.
74
75
  - Full text search of metadata and bookmarks.
75
76
  - Filter and sort on all comic metadata and unread status per user.
76
77
  - Browse a tree of Publishers, Imprints, Series, Volumes, or your own folder
@@ -95,8 +96,8 @@ border-radius: 128px;
95
96
 
96
97
  ## <a name="demonstration">👀 Demonstration</a>
97
98
 
98
- You may browse a [live demo server](https://codex.sl8r.net/) to get a feel for
99
- Codex.
99
+ You may browse a [live demo server](https://demo.codex-reader.app/) to get a
100
+ feel for Codex.
100
101
 
101
102
  ## <a name="news">📜 News</a>
102
103
 
@@ -134,12 +135,22 @@ brew install jpeg libffi libyaml libzip openssl python unrar webp
134
135
 
135
136
  ###### <a href="#debian">Debian</a>
136
137
 
137
- ...and Ubuntu, Mint, MX and others.
138
+ ...and Ubuntu, Mint, MX and others (and WSL).
138
139
 
139
140
  <!-- eslint-skip -->
140
141
 
141
142
  ```sh
142
- apt install build-essential libimagequant0 libjpeg62-turbo libopenjp2-7 libssl3 libyaml-0-2 libtiff6 libwebp7 python3-dev python3-pip mupdf unrar zlib1g
143
+ apt install build-essential libimagequant0 libjpeg-turbo8 libopenjp2-7 libssl libyaml-0-2 libtiff6 libwebp7 python3-dev python3-pip mupdf unrar zlib1g
144
+ ```
145
+
146
+ Versions of packages like libjpeg, libssl, libtiff may differ between flavors
147
+ and versions of Debian. If the version above is not available, try searching for
148
+ one that is with apt-cache or aptitude.
149
+
150
+ <!-- eslint-skip -->
151
+
152
+ ```sh
153
+ apt-cache search libjpeg-turbo
143
154
  ```
144
155
 
145
156
  ###### Alpine