codex 1.5.12__py3-none-any.whl → 1.5.13a0__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 (414) hide show
  1. codex/librarian/importer/importerd.py +2 -1
  2. codex/librarian/importer/query_fks.py +1 -2
  3. codex/middleware.py +50 -1
  4. codex/serializers/browser/settings.py +1 -0
  5. codex/serializers/choices.py +11 -13
  6. codex/serializers/metadata.py +1 -1
  7. codex/settings/settings.py +16 -5
  8. codex/signals/django_signals.py +6 -0
  9. codex/static_root/assets/{VCheckbox-CC74mhfV.a196e804e50a.js → VCheckbox-BMRDCYNv.7f791d7f065f.js} +1 -1
  10. codex/static_root/assets/VCheckbox-BMRDCYNv.7f791d7f065f.js.br +0 -0
  11. codex/static_root/assets/VCheckbox-BMRDCYNv.7f791d7f065f.js.gz +0 -0
  12. codex/static_root/assets/{VCheckbox-CC74mhfV.js → VCheckbox-BMRDCYNv.js} +1 -1
  13. codex/static_root/assets/VCheckbox-BMRDCYNv.js.br +0 -0
  14. codex/static_root/assets/VCheckbox-BMRDCYNv.js.gz +0 -0
  15. codex/static_root/assets/{VCheckboxBtn-F27UKlAX.f74083aa5b9a.js → VCheckboxBtn-Dqp1u3GT.e80f145994b6.js} +1 -1
  16. codex/static_root/assets/VCheckboxBtn-Dqp1u3GT.e80f145994b6.js.br +0 -0
  17. codex/static_root/assets/VCheckboxBtn-Dqp1u3GT.e80f145994b6.js.gz +0 -0
  18. codex/static_root/assets/{VCheckboxBtn-F27UKlAX.js → VCheckboxBtn-Dqp1u3GT.js} +1 -1
  19. codex/static_root/assets/VCheckboxBtn-Dqp1u3GT.js.br +0 -0
  20. codex/static_root/assets/VCheckboxBtn-Dqp1u3GT.js.gz +0 -0
  21. codex/static_root/assets/VCombobox-DT52mZm3.309c77be4a55.js +1 -0
  22. codex/static_root/assets/VCombobox-DT52mZm3.309c77be4a55.js.br +0 -0
  23. codex/static_root/assets/VCombobox-DT52mZm3.309c77be4a55.js.gz +0 -0
  24. codex/static_root/assets/VCombobox-DT52mZm3.js +1 -0
  25. codex/static_root/assets/VCombobox-DT52mZm3.js.br +0 -0
  26. codex/static_root/assets/VCombobox-DT52mZm3.js.gz +0 -0
  27. codex/static_root/assets/{VDataTableVirtual-BgFOSn9_.969c17b4d50a.js → VDataTableVirtual-DhhCmPtf.0735a1ab4c2f.js} +1 -1
  28. codex/static_root/assets/VDataTableVirtual-DhhCmPtf.0735a1ab4c2f.js.br +0 -0
  29. codex/static_root/assets/VDataTableVirtual-DhhCmPtf.0735a1ab4c2f.js.gz +0 -0
  30. codex/static_root/assets/{VDataTableVirtual-BgFOSn9_.js → VDataTableVirtual-DhhCmPtf.js} +1 -1
  31. codex/static_root/assets/VDataTableVirtual-DhhCmPtf.js.br +0 -0
  32. codex/static_root/assets/VDataTableVirtual-DhhCmPtf.js.gz +0 -0
  33. codex/static_root/assets/{VExpansionPanel-B06inlZY.a77a3ad1cc7c.js → VExpansionPanel-C593uXqT.d3bdc6a21208.js} +1 -1
  34. codex/static_root/assets/VExpansionPanel-C593uXqT.d3bdc6a21208.js.br +0 -0
  35. codex/static_root/assets/VExpansionPanel-C593uXqT.d3bdc6a21208.js.gz +0 -0
  36. codex/static_root/assets/{VExpansionPanel-B06inlZY.js → VExpansionPanel-C593uXqT.js} +1 -1
  37. codex/static_root/assets/VExpansionPanel-C593uXqT.js.br +0 -0
  38. codex/static_root/assets/VExpansionPanel-C593uXqT.js.gz +0 -0
  39. codex/static_root/assets/{VMain-BR4DrMy3.977234e0db6a.js → VMain-DmQvRj_k.1e0480bed9a6.js} +1 -1
  40. codex/static_root/assets/VMain-DmQvRj_k.1e0480bed9a6.js.br +0 -0
  41. codex/static_root/assets/VMain-DmQvRj_k.1e0480bed9a6.js.gz +0 -0
  42. codex/static_root/assets/{VMain-BR4DrMy3.js → VMain-DmQvRj_k.js} +1 -1
  43. codex/static_root/assets/VMain-DmQvRj_k.js.br +0 -0
  44. codex/static_root/assets/VMain-DmQvRj_k.js.gz +0 -0
  45. codex/static_root/assets/{VRadioGroup-DE0KmC8d.75bdb9d16a32.js → VRadioGroup-Bi16yPEE.69086b77f9b1.js} +1 -1
  46. codex/static_root/assets/VRadioGroup-Bi16yPEE.69086b77f9b1.js.br +0 -0
  47. codex/static_root/assets/VRadioGroup-Bi16yPEE.69086b77f9b1.js.gz +0 -0
  48. codex/static_root/assets/{VRadioGroup-DE0KmC8d.js → VRadioGroup-Bi16yPEE.js} +1 -1
  49. codex/static_root/assets/VRadioGroup-Bi16yPEE.js.br +0 -0
  50. codex/static_root/assets/VRadioGroup-Bi16yPEE.js.gz +0 -0
  51. codex/static_root/assets/VSelect-BdaijxdJ.b969ab260593.js +1 -0
  52. codex/static_root/assets/VSelect-BdaijxdJ.b969ab260593.js.br +0 -0
  53. codex/static_root/assets/VSelect-BdaijxdJ.b969ab260593.js.gz +0 -0
  54. codex/static_root/assets/VSelect-BdaijxdJ.js +1 -0
  55. codex/static_root/assets/VSelect-BdaijxdJ.js.br +0 -0
  56. codex/static_root/assets/VSelect-BdaijxdJ.js.gz +0 -0
  57. codex/static_root/assets/{VSelectionControl-B1zPb_Yg.6112179d7a5d.js → VSelectionControl-CuM4okF6.0f246e35e86f.js} +1 -1
  58. codex/static_root/assets/VSelectionControl-CuM4okF6.0f246e35e86f.js.br +0 -0
  59. codex/static_root/assets/VSelectionControl-CuM4okF6.0f246e35e86f.js.gz +0 -0
  60. codex/static_root/assets/{VSelectionControl-B1zPb_Yg.js → VSelectionControl-CuM4okF6.js} +1 -1
  61. codex/static_root/assets/VSelectionControl-CuM4okF6.js.br +0 -0
  62. codex/static_root/assets/VSelectionControl-CuM4okF6.js.gz +0 -0
  63. codex/static_root/assets/VSlideGroup-ztBraz6g.02a0bc55b207.js +1 -0
  64. codex/static_root/assets/VSlideGroup-ztBraz6g.02a0bc55b207.js.br +0 -0
  65. codex/static_root/assets/VSlideGroup-ztBraz6g.02a0bc55b207.js.gz +0 -0
  66. codex/static_root/assets/VSlideGroup-ztBraz6g.js +1 -0
  67. codex/static_root/assets/VSlideGroup-ztBraz6g.js.br +0 -0
  68. codex/static_root/assets/VSlideGroup-ztBraz6g.js.gz +0 -0
  69. codex/static_root/assets/{VTable-Pq4fCfUx.e50f8ad539ed.js → VTable-CGuSv-Tv.eddaf5526d93.js} +1 -1
  70. codex/static_root/assets/VTable-CGuSv-Tv.eddaf5526d93.js.br +0 -0
  71. codex/static_root/assets/VTable-CGuSv-Tv.eddaf5526d93.js.gz +0 -0
  72. codex/static_root/assets/{VTable-Pq4fCfUx.js → VTable-CGuSv-Tv.js} +1 -1
  73. codex/static_root/assets/VTable-CGuSv-Tv.js.br +0 -0
  74. codex/static_root/assets/VTable-CGuSv-Tv.js.gz +0 -0
  75. codex/static_root/assets/{VToolbar-BFYiqJrS.js → VToolbar-CAUhD2BO.279f0b52347a.js} +2 -2
  76. codex/static_root/assets/VToolbar-CAUhD2BO.279f0b52347a.js.br +0 -0
  77. codex/static_root/assets/VToolbar-CAUhD2BO.279f0b52347a.js.gz +0 -0
  78. codex/static_root/assets/{VToolbar-BFYiqJrS.71a0cbf7eb5f.js → VToolbar-CAUhD2BO.js} +2 -2
  79. codex/static_root/assets/VToolbar-CAUhD2BO.js.br +0 -0
  80. codex/static_root/assets/VToolbar-CAUhD2BO.js.gz +0 -0
  81. codex/static_root/assets/{VToolbar-BfNszTMd.css → VToolbar-DqQLg1UA.614d6a4a8a09.css} +1 -1
  82. codex/static_root/assets/VToolbar-DqQLg1UA.614d6a4a8a09.css.br +0 -0
  83. codex/static_root/assets/{VToolbar-BfNszTMd.111f25cdd6d8.css.gz → VToolbar-DqQLg1UA.614d6a4a8a09.css.gz} +0 -0
  84. codex/static_root/assets/{VToolbar-BfNszTMd.111f25cdd6d8.css → VToolbar-DqQLg1UA.css} +1 -1
  85. codex/static_root/assets/VToolbar-DqQLg1UA.css.br +0 -0
  86. codex/static_root/assets/{VToolbar-BfNszTMd.css.gz → VToolbar-DqQLg1UA.css.gz} +0 -0
  87. codex/static_root/assets/{VWindowItem-g6ho7Hf4.b91f9a3277ff.js → VWindowItem-YvmNwCNb.20a7e3b303de.js} +1 -1
  88. codex/static_root/assets/VWindowItem-YvmNwCNb.20a7e3b303de.js.br +0 -0
  89. codex/static_root/assets/VWindowItem-YvmNwCNb.20a7e3b303de.js.gz +0 -0
  90. codex/static_root/assets/{VWindowItem-g6ho7Hf4.js → VWindowItem-YvmNwCNb.js} +1 -1
  91. codex/static_root/assets/VWindowItem-YvmNwCNb.js.br +0 -0
  92. codex/static_root/assets/VWindowItem-YvmNwCNb.js.gz +0 -0
  93. codex/static_root/assets/{admin-BVkY78tW.affa20285127.js → admin-Ch9WezG1.bdace86b7c25.js} +1 -1
  94. codex/static_root/assets/admin-Ch9WezG1.bdace86b7c25.js.br +0 -0
  95. codex/static_root/assets/admin-Ch9WezG1.bdace86b7c25.js.gz +0 -0
  96. codex/static_root/assets/{admin-BVkY78tW.js → admin-Ch9WezG1.js} +1 -1
  97. codex/static_root/assets/admin-Ch9WezG1.js.br +0 -0
  98. codex/static_root/assets/admin-Ch9WezG1.js.gz +0 -0
  99. codex/static_root/assets/{admin-drawer-panel-CEiEnUcn.9f94b93a422f.js → admin-drawer-panel-B4VvGE4s.2265b9de60ab.js} +4 -4
  100. codex/static_root/assets/admin-drawer-panel-B4VvGE4s.2265b9de60ab.js.br +0 -0
  101. codex/static_root/assets/admin-drawer-panel-B4VvGE4s.2265b9de60ab.js.gz +0 -0
  102. codex/static_root/assets/{admin-drawer-panel-CEiEnUcn.js → admin-drawer-panel-B4VvGE4s.js} +4 -4
  103. codex/static_root/assets/admin-drawer-panel-B4VvGE4s.js.br +0 -0
  104. codex/static_root/assets/admin-drawer-panel-B4VvGE4s.js.gz +0 -0
  105. codex/static_root/assets/{admin-drawer-panel-s72VfDNy.css → admin-drawer-panel-Bk7z8uTR.1531b747003f.css} +1 -1
  106. codex/static_root/assets/admin-drawer-panel-Bk7z8uTR.1531b747003f.css.br +0 -0
  107. codex/static_root/assets/admin-drawer-panel-Bk7z8uTR.1531b747003f.css.gz +0 -0
  108. codex/static_root/assets/{admin-drawer-panel-s72VfDNy.ef6cb7221a44.css → admin-drawer-panel-Bk7z8uTR.css} +1 -1
  109. codex/static_root/assets/admin-drawer-panel-Bk7z8uTR.css.br +0 -0
  110. codex/static_root/assets/admin-drawer-panel-Bk7z8uTR.css.gz +0 -0
  111. codex/static_root/assets/browser-BTel3sYS.8e1515bc039a.js +1 -0
  112. codex/static_root/assets/browser-BTel3sYS.8e1515bc039a.js.br +0 -0
  113. codex/static_root/assets/browser-BTel3sYS.8e1515bc039a.js.gz +0 -0
  114. codex/static_root/assets/browser-BTel3sYS.js +1 -0
  115. codex/static_root/assets/browser-BTel3sYS.js.br +0 -0
  116. codex/static_root/assets/browser-BTel3sYS.js.gz +0 -0
  117. codex/static_root/assets/{browser-2i0QA4La.587673ac534c.css → browser-CVvV08AM.7667051b18fa.css} +1 -1
  118. codex/static_root/assets/browser-CVvV08AM.7667051b18fa.css.br +0 -0
  119. codex/static_root/assets/browser-CVvV08AM.7667051b18fa.css.gz +0 -0
  120. codex/static_root/assets/{browser-2i0QA4La.css → browser-CVvV08AM.css} +1 -1
  121. codex/static_root/assets/browser-CVvV08AM.css.br +0 -0
  122. codex/static_root/assets/browser-CVvV08AM.css.gz +0 -0
  123. codex/static_root/assets/{change-password-dialog-Bh7raeqK.6d408dcd933e.js → change-password-dialog-Dq6GjT1T.01b56b4b3e87.js} +1 -1
  124. codex/static_root/assets/change-password-dialog-Dq6GjT1T.01b56b4b3e87.js.br +0 -0
  125. codex/static_root/assets/change-password-dialog-Dq6GjT1T.01b56b4b3e87.js.gz +0 -0
  126. codex/static_root/assets/{change-password-dialog-Bh7raeqK.js → change-password-dialog-Dq6GjT1T.js} +1 -1
  127. codex/static_root/assets/change-password-dialog-Dq6GjT1T.js.br +0 -0
  128. codex/static_root/assets/change-password-dialog-Dq6GjT1T.js.gz +0 -0
  129. codex/static_root/assets/{confirm-dialog-CvURjaTY.cadecd4cefa8.js → confirm-dialog-D-Fx-51m.54b7d1059106.js} +1 -1
  130. codex/static_root/assets/confirm-dialog-D-Fx-51m.54b7d1059106.js.br +0 -0
  131. codex/static_root/assets/confirm-dialog-D-Fx-51m.54b7d1059106.js.gz +0 -0
  132. codex/static_root/assets/{confirm-dialog-CvURjaTY.js → confirm-dialog-D-Fx-51m.js} +1 -1
  133. codex/static_root/assets/confirm-dialog-D-Fx-51m.js.br +0 -0
  134. codex/static_root/assets/confirm-dialog-D-Fx-51m.js.gz +0 -0
  135. codex/static_root/assets/{confirm-footer-C-VAfuKA.js → confirm-footer-Yn7T9Tns.75a17cd86ca9.js} +1 -1
  136. codex/static_root/assets/confirm-footer-Yn7T9Tns.75a17cd86ca9.js.br +0 -0
  137. codex/static_root/assets/confirm-footer-Yn7T9Tns.75a17cd86ca9.js.gz +0 -0
  138. codex/static_root/assets/{confirm-footer-C-VAfuKA.c93e5c6d41ca.js → confirm-footer-Yn7T9Tns.js} +1 -1
  139. codex/static_root/assets/confirm-footer-Yn7T9Tns.js.br +0 -0
  140. codex/static_root/assets/confirm-footer-Yn7T9Tns.js.gz +0 -0
  141. codex/static_root/assets/{datetime-column-CDcOr8sM.951343a94a28.js → datetime-column-DCeBthsr.22ed49a999cc.js} +1 -1
  142. codex/static_root/assets/datetime-column-DCeBthsr.22ed49a999cc.js.br +0 -0
  143. codex/static_root/assets/datetime-column-DCeBthsr.22ed49a999cc.js.gz +0 -0
  144. codex/static_root/assets/{datetime-column-CDcOr8sM.js → datetime-column-DCeBthsr.js} +1 -1
  145. codex/static_root/assets/datetime-column-DCeBthsr.js.br +0 -0
  146. codex/static_root/assets/datetime-column-DCeBthsr.js.gz +0 -0
  147. codex/static_root/assets/{filter-DT8MlNGw.c70bb7a7c265.js → filter-Dw0fjwZi.4d5f085435ab.js} +1 -1
  148. codex/static_root/assets/filter-Dw0fjwZi.4d5f085435ab.js.br +0 -0
  149. codex/static_root/assets/filter-Dw0fjwZi.4d5f085435ab.js.gz +0 -0
  150. codex/static_root/assets/{filter-DT8MlNGw.js → filter-Dw0fjwZi.js} +1 -1
  151. codex/static_root/assets/filter-Dw0fjwZi.js.br +0 -0
  152. codex/static_root/assets/filter-Dw0fjwZi.js.gz +0 -0
  153. codex/static_root/assets/{flag-tab-BVoz2gvN.591572581c12.js → flag-tab-D5RcLFbQ.1073708ea164.js} +1 -1
  154. codex/static_root/assets/flag-tab-D5RcLFbQ.1073708ea164.js.br +0 -0
  155. codex/static_root/assets/flag-tab-D5RcLFbQ.1073708ea164.js.gz +0 -0
  156. codex/static_root/assets/{flag-tab-BVoz2gvN.js → flag-tab-D5RcLFbQ.js} +1 -1
  157. codex/static_root/assets/flag-tab-D5RcLFbQ.js.br +0 -0
  158. codex/static_root/assets/flag-tab-D5RcLFbQ.js.gz +0 -0
  159. codex/static_root/assets/{group-tab-Bu1Hn4DR.8c9fb2cbc4d2.js → group-tab-BilDDNz5.cba5ca15d7cf.js} +1 -1
  160. codex/static_root/assets/group-tab-BilDDNz5.cba5ca15d7cf.js.br +0 -0
  161. codex/static_root/assets/group-tab-BilDDNz5.cba5ca15d7cf.js.gz +0 -0
  162. codex/static_root/assets/{group-tab-Bu1Hn4DR.js → group-tab-BilDDNz5.js} +1 -1
  163. codex/static_root/assets/group-tab-BilDDNz5.js.br +0 -0
  164. codex/static_root/assets/group-tab-BilDDNz5.js.gz +0 -0
  165. codex/static_root/assets/{http-error-BKXUvS3w.93b39ceed2f7.js → http-error-DHmC7qgT.bde1d32b55df.js} +1 -1
  166. codex/static_root/assets/http-error-DHmC7qgT.bde1d32b55df.js.br +0 -0
  167. codex/static_root/assets/http-error-DHmC7qgT.bde1d32b55df.js.gz +0 -0
  168. codex/static_root/assets/{http-error-BKXUvS3w.js → http-error-DHmC7qgT.js} +1 -1
  169. codex/static_root/assets/http-error-DHmC7qgT.js.br +0 -0
  170. codex/static_root/assets/http-error-DHmC7qgT.js.gz +0 -0
  171. codex/static_root/assets/{library-tab-AM2XWHOr.31f48701358e.js → library-tab-dbcbv0--.efa2d1d95b77.js} +1 -1
  172. codex/static_root/assets/library-tab-dbcbv0--.efa2d1d95b77.js.br +0 -0
  173. codex/static_root/assets/library-tab-dbcbv0--.efa2d1d95b77.js.gz +0 -0
  174. codex/static_root/assets/{library-tab-AM2XWHOr.js → library-tab-dbcbv0--.js} +1 -1
  175. codex/static_root/assets/library-tab-dbcbv0--.js.br +0 -0
  176. codex/static_root/assets/library-tab-dbcbv0--.js.gz +0 -0
  177. codex/static_root/assets/main-CCY5Ix0K.b067e1d16cf5.js +37 -0
  178. codex/static_root/assets/main-CCY5Ix0K.b067e1d16cf5.js.br +0 -0
  179. codex/static_root/assets/main-CCY5Ix0K.b067e1d16cf5.js.gz +0 -0
  180. codex/static_root/assets/main-CCY5Ix0K.js +37 -0
  181. codex/static_root/assets/main-CCY5Ix0K.js.br +0 -0
  182. codex/static_root/assets/main-CCY5Ix0K.js.gz +0 -0
  183. codex/static_root/assets/{metadata-dialog-BGJasBRy.0553851658b5.css → metadata-dialog-DIhQctD5.67830cc94cf8.css} +1 -1
  184. codex/static_root/assets/metadata-dialog-DIhQctD5.67830cc94cf8.css.br +0 -0
  185. codex/static_root/assets/metadata-dialog-DIhQctD5.67830cc94cf8.css.gz +0 -0
  186. codex/static_root/assets/{metadata-dialog-BGJasBRy.css → metadata-dialog-DIhQctD5.css} +1 -1
  187. codex/static_root/assets/metadata-dialog-DIhQctD5.css.br +0 -0
  188. codex/static_root/assets/metadata-dialog-DIhQctD5.css.gz +0 -0
  189. codex/static_root/assets/metadata-dialog-PkTw4uLp.ce5ee2377f27.js +1 -0
  190. codex/static_root/assets/metadata-dialog-PkTw4uLp.ce5ee2377f27.js.br +0 -0
  191. codex/static_root/assets/metadata-dialog-PkTw4uLp.ce5ee2377f27.js.gz +0 -0
  192. codex/static_root/assets/metadata-dialog-PkTw4uLp.js +1 -0
  193. codex/static_root/assets/metadata-dialog-PkTw4uLp.js.br +0 -0
  194. codex/static_root/assets/metadata-dialog-PkTw4uLp.js.gz +0 -0
  195. codex/static_root/assets/{pdf-doc-DSq1qfWx.50ab90d8b609.js → pdf-doc-CEOcuQZb.260e6671eb89.js} +1 -1
  196. codex/static_root/assets/pdf-doc-CEOcuQZb.260e6671eb89.js.br +0 -0
  197. codex/static_root/assets/pdf-doc-CEOcuQZb.260e6671eb89.js.gz +0 -0
  198. codex/static_root/assets/{pdf-doc-DSq1qfWx.js → pdf-doc-CEOcuQZb.js} +1 -1
  199. codex/static_root/assets/pdf-doc-CEOcuQZb.js.br +0 -0
  200. codex/static_root/assets/pdf-doc-CEOcuQZb.js.gz +0 -0
  201. codex/static_root/assets/{reader-Qan6W6n-.fc91835a9075.js → reader-DRsYPz-3.b8ee57f2aefc.js} +2 -2
  202. codex/static_root/assets/reader-DRsYPz-3.b8ee57f2aefc.js.br +0 -0
  203. codex/static_root/assets/reader-DRsYPz-3.b8ee57f2aefc.js.gz +0 -0
  204. codex/static_root/assets/{reader-Qan6W6n-.js → reader-DRsYPz-3.js} +2 -2
  205. codex/static_root/assets/reader-DRsYPz-3.js.br +0 -0
  206. codex/static_root/assets/reader-DRsYPz-3.js.gz +0 -0
  207. codex/static_root/assets/{stats-tab-Bv3OL9xU.949c9b8d7135.js → stats-tab-QTG23RuT.654f85e0b21d.js} +1 -1
  208. codex/static_root/assets/stats-tab-QTG23RuT.654f85e0b21d.js.br +0 -0
  209. codex/static_root/assets/stats-tab-QTG23RuT.654f85e0b21d.js.gz +0 -0
  210. codex/static_root/assets/{stats-tab-Bv3OL9xU.js → stats-tab-QTG23RuT.js} +1 -1
  211. codex/static_root/assets/stats-tab-QTG23RuT.js.br +0 -0
  212. codex/static_root/assets/stats-tab-QTG23RuT.js.gz +0 -0
  213. codex/static_root/assets/{task-tab-CgR8JqMw.54569b8df927.js → task-tab-Kff6fz1t.28380a665ed7.js} +1 -1
  214. codex/static_root/assets/task-tab-Kff6fz1t.28380a665ed7.js.br +0 -0
  215. codex/static_root/assets/task-tab-Kff6fz1t.28380a665ed7.js.gz +0 -0
  216. codex/static_root/assets/{task-tab-CgR8JqMw.js → task-tab-Kff6fz1t.js} +1 -1
  217. codex/static_root/assets/task-tab-Kff6fz1t.js.br +0 -0
  218. codex/static_root/assets/task-tab-Kff6fz1t.js.gz +0 -0
  219. codex/static_root/assets/{user-tab-Xzi_07Yi.d165773d55aa.js → user-tab-OAmZ6CQl.eed3361aefb7.js} +1 -1
  220. codex/static_root/assets/user-tab-OAmZ6CQl.eed3361aefb7.js.br +0 -0
  221. codex/static_root/assets/user-tab-OAmZ6CQl.eed3361aefb7.js.gz +0 -0
  222. codex/static_root/assets/{user-tab-Xzi_07Yi.js → user-tab-OAmZ6CQl.js} +1 -1
  223. codex/static_root/assets/user-tab-OAmZ6CQl.js.br +0 -0
  224. codex/static_root/assets/user-tab-OAmZ6CQl.js.gz +0 -0
  225. codex/static_root/js/choices.a4dcff295a04.json +1 -0
  226. codex/static_root/js/choices.a4dcff295a04.json.br +0 -0
  227. codex/static_root/js/choices.a4dcff295a04.json.gz +0 -0
  228. codex/static_root/js/choices.json +1 -1
  229. codex/static_root/js/choices.json.br +0 -0
  230. codex/static_root/js/choices.json.gz +0 -0
  231. codex/static_root/{manifest.0d2e5eed5ce7.json → manifest.13219ea92507.json} +217 -216
  232. codex/static_root/manifest.13219ea92507.json.br +0 -0
  233. codex/static_root/manifest.13219ea92507.json.gz +0 -0
  234. codex/static_root/manifest.json +217 -216
  235. codex/static_root/manifest.json.br +0 -0
  236. codex/static_root/manifest.json.gz +0 -0
  237. codex/static_root/staticfiles.json +1 -1
  238. codex/views/bookmark.py +12 -9
  239. codex/views/browser/base.py +21 -8
  240. codex/views/browser/browser.py +88 -68
  241. codex/views/browser/browser_annotations.py +19 -7
  242. codex/views/browser/choices.py +3 -5
  243. codex/views/browser/const.py +3 -0
  244. codex/views/browser/filters/search.py +114 -26
  245. codex/views/browser/metadata.py +4 -6
  246. codex/views/error.py +7 -3
  247. codex/views/opds/v1/feed.py +2 -1
  248. codex/views/opds/v2/feed.py +4 -6
  249. codex/views/opds/v2/publications.py +6 -3
  250. codex/views/session.py +1 -0
  251. {codex-1.5.12.dist-info → codex-1.5.13a0.dist-info}/METADATA +23 -12
  252. {codex-1.5.12.dist-info → codex-1.5.13a0.dist-info}/RECORD +255 -254
  253. codex/static_root/assets/VCheckbox-CC74mhfV.a196e804e50a.js.br +0 -0
  254. codex/static_root/assets/VCheckbox-CC74mhfV.a196e804e50a.js.gz +0 -0
  255. codex/static_root/assets/VCheckbox-CC74mhfV.js.br +0 -0
  256. codex/static_root/assets/VCheckbox-CC74mhfV.js.gz +0 -0
  257. codex/static_root/assets/VCheckboxBtn-F27UKlAX.f74083aa5b9a.js.br +0 -0
  258. codex/static_root/assets/VCheckboxBtn-F27UKlAX.f74083aa5b9a.js.gz +0 -0
  259. codex/static_root/assets/VCheckboxBtn-F27UKlAX.js.br +0 -0
  260. codex/static_root/assets/VCheckboxBtn-F27UKlAX.js.gz +0 -0
  261. codex/static_root/assets/VCombobox-Dw57vrly.b1184dfd61ec.js +0 -1
  262. codex/static_root/assets/VCombobox-Dw57vrly.b1184dfd61ec.js.br +0 -0
  263. codex/static_root/assets/VCombobox-Dw57vrly.b1184dfd61ec.js.gz +0 -0
  264. codex/static_root/assets/VCombobox-Dw57vrly.js +0 -1
  265. codex/static_root/assets/VCombobox-Dw57vrly.js.br +0 -0
  266. codex/static_root/assets/VCombobox-Dw57vrly.js.gz +0 -0
  267. codex/static_root/assets/VDataTableVirtual-BgFOSn9_.969c17b4d50a.js.br +0 -0
  268. codex/static_root/assets/VDataTableVirtual-BgFOSn9_.969c17b4d50a.js.gz +0 -0
  269. codex/static_root/assets/VDataTableVirtual-BgFOSn9_.js.br +0 -0
  270. codex/static_root/assets/VDataTableVirtual-BgFOSn9_.js.gz +0 -0
  271. codex/static_root/assets/VExpansionPanel-B06inlZY.a77a3ad1cc7c.js.br +0 -0
  272. codex/static_root/assets/VExpansionPanel-B06inlZY.a77a3ad1cc7c.js.gz +0 -0
  273. codex/static_root/assets/VExpansionPanel-B06inlZY.js.br +0 -0
  274. codex/static_root/assets/VExpansionPanel-B06inlZY.js.gz +0 -0
  275. codex/static_root/assets/VMain-BR4DrMy3.977234e0db6a.js.br +0 -0
  276. codex/static_root/assets/VMain-BR4DrMy3.977234e0db6a.js.gz +0 -0
  277. codex/static_root/assets/VMain-BR4DrMy3.js.br +0 -0
  278. codex/static_root/assets/VMain-BR4DrMy3.js.gz +0 -0
  279. codex/static_root/assets/VRadioGroup-DE0KmC8d.75bdb9d16a32.js.br +0 -0
  280. codex/static_root/assets/VRadioGroup-DE0KmC8d.75bdb9d16a32.js.gz +0 -0
  281. codex/static_root/assets/VRadioGroup-DE0KmC8d.js.br +0 -0
  282. codex/static_root/assets/VRadioGroup-DE0KmC8d.js.gz +0 -0
  283. codex/static_root/assets/VSelect-5wraBYHV.54a9a3184add.js +0 -1
  284. codex/static_root/assets/VSelect-5wraBYHV.54a9a3184add.js.br +0 -0
  285. codex/static_root/assets/VSelect-5wraBYHV.54a9a3184add.js.gz +0 -0
  286. codex/static_root/assets/VSelect-5wraBYHV.js +0 -1
  287. codex/static_root/assets/VSelect-5wraBYHV.js.br +0 -0
  288. codex/static_root/assets/VSelect-5wraBYHV.js.gz +0 -0
  289. codex/static_root/assets/VSelectionControl-B1zPb_Yg.6112179d7a5d.js.br +0 -0
  290. codex/static_root/assets/VSelectionControl-B1zPb_Yg.6112179d7a5d.js.gz +0 -0
  291. codex/static_root/assets/VSelectionControl-B1zPb_Yg.js.br +0 -0
  292. codex/static_root/assets/VSelectionControl-B1zPb_Yg.js.gz +0 -0
  293. codex/static_root/assets/VSlideGroup-F7Hpcms9.dce335daf8f2.js +0 -1
  294. codex/static_root/assets/VSlideGroup-F7Hpcms9.dce335daf8f2.js.br +0 -0
  295. codex/static_root/assets/VSlideGroup-F7Hpcms9.dce335daf8f2.js.gz +0 -0
  296. codex/static_root/assets/VSlideGroup-F7Hpcms9.js +0 -1
  297. codex/static_root/assets/VSlideGroup-F7Hpcms9.js.br +0 -0
  298. codex/static_root/assets/VSlideGroup-F7Hpcms9.js.gz +0 -0
  299. codex/static_root/assets/VTable-Pq4fCfUx.e50f8ad539ed.js.br +0 -0
  300. codex/static_root/assets/VTable-Pq4fCfUx.e50f8ad539ed.js.gz +0 -0
  301. codex/static_root/assets/VTable-Pq4fCfUx.js.br +0 -0
  302. codex/static_root/assets/VTable-Pq4fCfUx.js.gz +0 -0
  303. codex/static_root/assets/VToolbar-BFYiqJrS.71a0cbf7eb5f.js.br +0 -0
  304. codex/static_root/assets/VToolbar-BFYiqJrS.71a0cbf7eb5f.js.gz +0 -0
  305. codex/static_root/assets/VToolbar-BFYiqJrS.js.br +0 -0
  306. codex/static_root/assets/VToolbar-BFYiqJrS.js.gz +0 -0
  307. codex/static_root/assets/VToolbar-BfNszTMd.111f25cdd6d8.css.br +0 -0
  308. codex/static_root/assets/VToolbar-BfNszTMd.css.br +0 -0
  309. codex/static_root/assets/VWindowItem-g6ho7Hf4.b91f9a3277ff.js.br +0 -0
  310. codex/static_root/assets/VWindowItem-g6ho7Hf4.b91f9a3277ff.js.gz +0 -0
  311. codex/static_root/assets/VWindowItem-g6ho7Hf4.js.br +0 -0
  312. codex/static_root/assets/VWindowItem-g6ho7Hf4.js.gz +0 -0
  313. codex/static_root/assets/admin-BVkY78tW.affa20285127.js.br +0 -0
  314. codex/static_root/assets/admin-BVkY78tW.affa20285127.js.gz +0 -0
  315. codex/static_root/assets/admin-BVkY78tW.js.br +0 -0
  316. codex/static_root/assets/admin-BVkY78tW.js.gz +0 -0
  317. codex/static_root/assets/admin-drawer-panel-CEiEnUcn.9f94b93a422f.js.br +0 -0
  318. codex/static_root/assets/admin-drawer-panel-CEiEnUcn.9f94b93a422f.js.gz +0 -0
  319. codex/static_root/assets/admin-drawer-panel-CEiEnUcn.js.br +0 -0
  320. codex/static_root/assets/admin-drawer-panel-CEiEnUcn.js.gz +0 -0
  321. codex/static_root/assets/admin-drawer-panel-s72VfDNy.css.br +0 -0
  322. codex/static_root/assets/admin-drawer-panel-s72VfDNy.css.gz +0 -0
  323. codex/static_root/assets/admin-drawer-panel-s72VfDNy.ef6cb7221a44.css.br +0 -0
  324. codex/static_root/assets/admin-drawer-panel-s72VfDNy.ef6cb7221a44.css.gz +0 -0
  325. codex/static_root/assets/browser-2i0QA4La.587673ac534c.css.br +0 -0
  326. codex/static_root/assets/browser-2i0QA4La.587673ac534c.css.gz +0 -0
  327. codex/static_root/assets/browser-2i0QA4La.css.br +0 -0
  328. codex/static_root/assets/browser-2i0QA4La.css.gz +0 -0
  329. codex/static_root/assets/browser-BYquFWOA.3e5479490c40.js +0 -1
  330. codex/static_root/assets/browser-BYquFWOA.3e5479490c40.js.br +0 -0
  331. codex/static_root/assets/browser-BYquFWOA.3e5479490c40.js.gz +0 -0
  332. codex/static_root/assets/browser-BYquFWOA.js +0 -1
  333. codex/static_root/assets/browser-BYquFWOA.js.br +0 -0
  334. codex/static_root/assets/browser-BYquFWOA.js.gz +0 -0
  335. codex/static_root/assets/change-password-dialog-Bh7raeqK.6d408dcd933e.js.br +0 -0
  336. codex/static_root/assets/change-password-dialog-Bh7raeqK.6d408dcd933e.js.gz +0 -0
  337. codex/static_root/assets/change-password-dialog-Bh7raeqK.js.br +0 -0
  338. codex/static_root/assets/change-password-dialog-Bh7raeqK.js.gz +0 -0
  339. codex/static_root/assets/confirm-dialog-CvURjaTY.cadecd4cefa8.js.br +0 -0
  340. codex/static_root/assets/confirm-dialog-CvURjaTY.cadecd4cefa8.js.gz +0 -0
  341. codex/static_root/assets/confirm-dialog-CvURjaTY.js.br +0 -0
  342. codex/static_root/assets/confirm-dialog-CvURjaTY.js.gz +0 -0
  343. codex/static_root/assets/confirm-footer-C-VAfuKA.c93e5c6d41ca.js.br +0 -0
  344. codex/static_root/assets/confirm-footer-C-VAfuKA.c93e5c6d41ca.js.gz +0 -0
  345. codex/static_root/assets/confirm-footer-C-VAfuKA.js.br +0 -0
  346. codex/static_root/assets/confirm-footer-C-VAfuKA.js.gz +0 -0
  347. codex/static_root/assets/datetime-column-CDcOr8sM.951343a94a28.js.br +0 -0
  348. codex/static_root/assets/datetime-column-CDcOr8sM.951343a94a28.js.gz +0 -0
  349. codex/static_root/assets/datetime-column-CDcOr8sM.js.br +0 -0
  350. codex/static_root/assets/datetime-column-CDcOr8sM.js.gz +0 -0
  351. codex/static_root/assets/filter-DT8MlNGw.c70bb7a7c265.js.br +0 -0
  352. codex/static_root/assets/filter-DT8MlNGw.c70bb7a7c265.js.gz +0 -0
  353. codex/static_root/assets/filter-DT8MlNGw.js.br +0 -0
  354. codex/static_root/assets/filter-DT8MlNGw.js.gz +0 -0
  355. codex/static_root/assets/flag-tab-BVoz2gvN.591572581c12.js.br +0 -0
  356. codex/static_root/assets/flag-tab-BVoz2gvN.591572581c12.js.gz +0 -0
  357. codex/static_root/assets/flag-tab-BVoz2gvN.js.br +0 -0
  358. codex/static_root/assets/flag-tab-BVoz2gvN.js.gz +0 -0
  359. codex/static_root/assets/group-tab-Bu1Hn4DR.8c9fb2cbc4d2.js.br +0 -0
  360. codex/static_root/assets/group-tab-Bu1Hn4DR.8c9fb2cbc4d2.js.gz +0 -0
  361. codex/static_root/assets/group-tab-Bu1Hn4DR.js.br +0 -0
  362. codex/static_root/assets/group-tab-Bu1Hn4DR.js.gz +0 -0
  363. codex/static_root/assets/http-error-BKXUvS3w.93b39ceed2f7.js.br +0 -4
  364. codex/static_root/assets/http-error-BKXUvS3w.93b39ceed2f7.js.gz +0 -0
  365. codex/static_root/assets/http-error-BKXUvS3w.js.br +0 -4
  366. codex/static_root/assets/http-error-BKXUvS3w.js.gz +0 -0
  367. codex/static_root/assets/library-tab-AM2XWHOr.31f48701358e.js.br +0 -0
  368. codex/static_root/assets/library-tab-AM2XWHOr.31f48701358e.js.gz +0 -0
  369. codex/static_root/assets/library-tab-AM2XWHOr.js.br +0 -0
  370. codex/static_root/assets/library-tab-AM2XWHOr.js.gz +0 -0
  371. codex/static_root/assets/main-Dr7xEc75.ffae6222f1aa.js +0 -37
  372. codex/static_root/assets/main-Dr7xEc75.ffae6222f1aa.js.br +0 -0
  373. codex/static_root/assets/main-Dr7xEc75.ffae6222f1aa.js.gz +0 -0
  374. codex/static_root/assets/main-Dr7xEc75.js +0 -37
  375. codex/static_root/assets/main-Dr7xEc75.js.br +0 -0
  376. codex/static_root/assets/main-Dr7xEc75.js.gz +0 -0
  377. codex/static_root/assets/metadata-dialog-BGJasBRy.0553851658b5.css.br +0 -0
  378. codex/static_root/assets/metadata-dialog-BGJasBRy.0553851658b5.css.gz +0 -0
  379. codex/static_root/assets/metadata-dialog-BGJasBRy.css.br +0 -0
  380. codex/static_root/assets/metadata-dialog-BGJasBRy.css.gz +0 -0
  381. codex/static_root/assets/metadata-dialog-DFDQ4P3u.b959bb5a03a2.js +0 -1
  382. codex/static_root/assets/metadata-dialog-DFDQ4P3u.b959bb5a03a2.js.br +0 -0
  383. codex/static_root/assets/metadata-dialog-DFDQ4P3u.b959bb5a03a2.js.gz +0 -0
  384. codex/static_root/assets/metadata-dialog-DFDQ4P3u.js +0 -1
  385. codex/static_root/assets/metadata-dialog-DFDQ4P3u.js.br +0 -0
  386. codex/static_root/assets/metadata-dialog-DFDQ4P3u.js.gz +0 -0
  387. codex/static_root/assets/pdf-doc-DSq1qfWx.50ab90d8b609.js.br +0 -0
  388. codex/static_root/assets/pdf-doc-DSq1qfWx.50ab90d8b609.js.gz +0 -0
  389. codex/static_root/assets/pdf-doc-DSq1qfWx.js.br +0 -0
  390. codex/static_root/assets/pdf-doc-DSq1qfWx.js.gz +0 -0
  391. codex/static_root/assets/reader-Qan6W6n-.fc91835a9075.js.br +0 -0
  392. codex/static_root/assets/reader-Qan6W6n-.fc91835a9075.js.gz +0 -0
  393. codex/static_root/assets/reader-Qan6W6n-.js.br +0 -0
  394. codex/static_root/assets/reader-Qan6W6n-.js.gz +0 -0
  395. codex/static_root/assets/stats-tab-Bv3OL9xU.949c9b8d7135.js.br +0 -0
  396. codex/static_root/assets/stats-tab-Bv3OL9xU.949c9b8d7135.js.gz +0 -0
  397. codex/static_root/assets/stats-tab-Bv3OL9xU.js.br +0 -0
  398. codex/static_root/assets/stats-tab-Bv3OL9xU.js.gz +0 -0
  399. codex/static_root/assets/task-tab-CgR8JqMw.54569b8df927.js.br +0 -0
  400. codex/static_root/assets/task-tab-CgR8JqMw.54569b8df927.js.gz +0 -0
  401. codex/static_root/assets/task-tab-CgR8JqMw.js.br +0 -0
  402. codex/static_root/assets/task-tab-CgR8JqMw.js.gz +0 -0
  403. codex/static_root/assets/user-tab-Xzi_07Yi.d165773d55aa.js.br +0 -0
  404. codex/static_root/assets/user-tab-Xzi_07Yi.d165773d55aa.js.gz +0 -0
  405. codex/static_root/assets/user-tab-Xzi_07Yi.js.br +0 -0
  406. codex/static_root/assets/user-tab-Xzi_07Yi.js.gz +0 -0
  407. codex/static_root/js/choices.fedcbd1ec085.json +0 -1
  408. codex/static_root/js/choices.fedcbd1ec085.json.br +0 -0
  409. codex/static_root/js/choices.fedcbd1ec085.json.gz +0 -0
  410. codex/static_root/manifest.0d2e5eed5ce7.json.br +0 -0
  411. codex/static_root/manifest.0d2e5eed5ce7.json.gz +0 -0
  412. {codex-1.5.12.dist-info → codex-1.5.13a0.dist-info}/LICENSE +0 -0
  413. {codex-1.5.12.dist-info → codex-1.5.13a0.dist-info}/WHEEL +0 -0
  414. {codex-1.5.12.dist-info → codex-1.5.13a0.dist-info}/entry_points.txt +0 -0
@@ -1,56 +1,144 @@
1
1
  """Search Filters Methods."""
2
2
 
3
+ from dataclasses import dataclass
4
+ from time import time
5
+
3
6
  from django.db.models import Q
4
7
 
5
8
  from codex._vendor.haystack.query import SearchQuerySet
6
9
  from codex.logger.logging import get_logger
7
10
  from codex.models import Comic
11
+ from codex.settings.settings import DEBUG
12
+ from codex.views.browser.const import MAX_OBJ_PER_PAGE
8
13
 
9
14
  LOG = get_logger(__name__)
10
15
 
11
16
 
17
+ @dataclass
18
+ class SearchScores:
19
+ """Search Scores for annotation."""
20
+
21
+ scores: tuple[tuple[int, float], ...] = ()
22
+ scored_pks: tuple[int, ...] = ()
23
+ prev_pks: tuple[int, ...] = ()
24
+ next_pks: tuple[int, ...] = ()
25
+
26
+
12
27
  class SearchFilterMixin:
13
28
  """Search Filters Methods."""
14
29
 
15
- def get_search_scores(self) -> dict | None:
30
+ def _get_binary_search_scores(self, sqs):
31
+ """Get search scores for choices and metadata."""
32
+ sqs = sqs.values_list("pk", flat=True)
33
+ search_results_limit = self.params.get( # type: ignore
34
+ "search_results_limit",
35
+ MAX_OBJ_PER_PAGE, # type: ignore
36
+ )
37
+ if search_results_limit:
38
+ sqs = sqs[:search_results_limit] # type: ignore
39
+ return tuple(sqs)
40
+
41
+ def _get_browser_search_scores(self, sqs):
42
+ """Get search scores for the browser cards."""
43
+ page = self.kwargs.get("page", 1) # type: ignore
44
+ search_results_limit = self.params.get( # type: ignore
45
+ "search_results_limit",
46
+ MAX_OBJ_PER_PAGE, # type: ignore
47
+ )
48
+ if search_results_limit:
49
+ offset = 0
50
+ limit = search_results_limit
51
+ else:
52
+ offset = max(0, (page - 1) * MAX_OBJ_PER_PAGE) # type: ignore
53
+ limit = offset + MAX_OBJ_PER_PAGE # type: ignore
54
+
55
+ if DEBUG:
56
+ LOG.debug(
57
+ f"searching... {page=} page_{offset=} page_{limit=} {search_results_limit=}"
58
+ )
59
+
60
+ scores_pairs = []
61
+ prev_pks = []
62
+ next_pks = []
63
+
64
+ if DEBUG:
65
+ start_time = time()
66
+ scores_values = sqs.values_list("pk", "score")
67
+ if search_results_limit:
68
+ scores_values = scores_values[:limit]
69
+ for index, pair in enumerate(scores_values):
70
+ if index < offset:
71
+ prev_pks.append(pair[0])
72
+ elif index > limit:
73
+ next_pks.append(pair[0])
74
+ else:
75
+ scores_pairs.append(pair)
76
+
77
+ if DEBUG:
78
+ LOG.debug(
79
+ f"search {time() - start_time}s" # type: ignore
80
+ f" {len(scores_pairs)=} {len(prev_pks)=} {len(next_pks)=}"
81
+ )
82
+
83
+ return tuple(scores_pairs), tuple(prev_pks), tuple(next_pks)
84
+
85
+ def get_search_scores(self, binary=False) -> SearchScores | None:
16
86
  """Perform the search and return the scores as a dict."""
17
- search_scores = {}
18
87
  text = self.params.get("q", "") # type: ignore
19
88
  if not text:
20
- # for opds 2
21
- text = self.params.get("query", "") # type: ignore
22
- text = text.strip()
23
- if not text:
24
- return search_scores
89
+ return None
25
90
 
26
- sqs = SearchQuerySet().auto_query(text)
27
- comic_scores = sqs.values("pk", "score")
91
+ scores_pairs = ()
92
+ scored_pks = ()
93
+ prev_pks = ()
94
+ next_pks = ()
28
95
  try:
29
- for comic_score in comic_scores:
30
- search_scores[comic_score["pk"]] = comic_score["score"]
96
+ sqs = SearchQuerySet()
97
+ sqs = sqs.auto_query(text) # .filter(score__gt=0.0)
98
+ if binary:
99
+ scored_pks = self._get_binary_search_scores(sqs)
100
+ else:
101
+ scores_pairs, prev_pks, next_pks = self._get_browser_search_scores(sqs)
102
+
31
103
  except MemoryError:
32
104
  LOG.warning("Search engine needs more memory, results truncated.")
33
105
  except Exception:
34
- LOG.exception("While Searching")
35
- if not search_scores:
36
- return None
37
- return search_scores
106
+ LOG.exception("Getting Search Scores")
107
+ return SearchScores(scores_pairs, scored_pks, prev_pks, next_pks)
38
108
 
39
- def _get_search_query_filter(self, model, search_scores: dict):
109
+ def _get_search_query_filter(
110
+ self,
111
+ model,
112
+ search_scores: SearchScores,
113
+ ):
40
114
  """Get the search filter and scores."""
41
- prefix = "" if model == Comic else self.rel_prefix # type: ignore
42
- rel = prefix + "pk__in"
43
- query_dict = {rel: search_scores.keys()}
44
- return Q(**query_dict)
115
+ if search_scores.scores:
116
+ query = Q(search_score__gt=0.0)
117
+ else:
118
+ prefix = "" if model == Comic else self.rel_prefix # type: ignore
119
+ rel = prefix + "pk__in"
120
+ query_dict = {rel: search_scores.scored_pks}
121
+ query = Q(**query_dict)
122
+ return query
45
123
 
46
- def get_search_filter(self, model, search_scores: dict):
124
+ def apply_search_filter(
125
+ self,
126
+ qs,
127
+ model,
128
+ search_scores: SearchScores | None,
129
+ ):
47
130
  """Preparse search, search and return the filter and scores."""
48
- search_filter = Q()
49
131
  try:
50
132
  if search_scores:
51
- # Query haystack
52
133
  search_filter = self._get_search_query_filter(model, search_scores)
53
- except Exception as exc:
54
- LOG.warning(exc)
134
+ qs = qs.filter(search_filter)
135
+ except Exception:
136
+ LOG.exception("Creating the search filter")
137
+
138
+ return qs
55
139
 
56
- return search_filter
140
+ def apply_binary_search_filter(self, qs):
141
+ """Apply scoreless search filter for choices & metadata."""
142
+ search_scores = self.get_search_scores(binary=True)
143
+ model = self.model # type: ignore
144
+ return self.apply_search_filter(qs, model, search_scores)
@@ -97,7 +97,7 @@ class MetadataView(BrowserAnnotationsView):
97
97
  if not self.is_model_comic:
98
98
  size_func = self.get_aggregate_func(self.model, "size")
99
99
  qs = qs.annotate(size=size_func)
100
- return self.annotate_common_aggregates(qs, self.model, {})
100
+ return self.annotate_common_aggregates(qs, self.model, None)
101
101
 
102
102
  def _annotate_values_and_fks(self, qs, simple_qs):
103
103
  """Annotate comic values and comic foreign key values."""
@@ -242,13 +242,11 @@ class MetadataView(BrowserAnnotationsView):
242
242
  if self.model is None:
243
243
  raise NotFound(detail=f"Cannot get metadata for {self.group=}")
244
244
 
245
- search_scores: dict | None = self.get_search_scores()
246
- if search_scores is None:
247
- self._raise_not_found()
248
- object_filter = self.get_query_filters_without_group(self.model, search_scores) # type: ignore
245
+ object_filter = self.get_query_filters_without_group(self.model)
249
246
  pk = self.kwargs["pk"]
250
247
  qs = self.model.objects.filter(object_filter, pk=pk)
251
-
248
+ if self.model != Comic:
249
+ qs = self.apply_binary_search_filter(qs)
252
250
  qs = self._annotate_aggregates(qs)
253
251
  simple_qs = qs
254
252
 
codex/views/error.py CHANGED
@@ -7,15 +7,19 @@ from rest_framework.views import exception_handler
7
7
 
8
8
  from codex.exceptions import SeeOtherRedirectError
9
9
 
10
+ _OPDS_PREFIX = "opds/v"
11
+
10
12
 
11
13
  def codex_exception_handler(exc, context):
12
14
  """Assume OPDS clients want redirects instead of errors."""
13
15
  response = None
14
16
  request = context.get("request")
15
- opds_start = reverse("opds:start")
16
- if request.path.startswith(opds_start):
17
+ if _OPDS_PREFIX in request.path:
18
+ name = "opds:v2:feed" if _OPDS_PREFIX + "2" in request.path else "opds:v1:feed"
19
+ opds_start = reverse(name)
20
+
17
21
  if isinstance(exc, SeeOtherRedirectError):
18
- response = exc.get_response("opds:v1:browser")
22
+ response = exc.get_response(opds_start)
19
23
  elif hasattr(exc, "status_code") and exc.status_code in (
20
24
  status.HTTP_400_BAD_REQUEST,
21
25
  status.HTTP_404_NOT_FOUND,
@@ -12,6 +12,7 @@ from codex.serializers.opds.v1 import (
12
12
  OPDS1TemplateSerializer,
13
13
  )
14
14
  from codex.views.browser.browser import BrowserView
15
+ from codex.views.browser.const import MAX_OBJ_PER_PAGE
15
16
  from codex.views.const import FALSY
16
17
  from codex.views.opds.const import BLANK_TITLE, MimeType
17
18
  from codex.views.opds.v1.entry.data import OPDS1EntryData
@@ -107,7 +108,7 @@ class OPDS1FeedView(CodexXMLTemplateView, LinksMixin):
107
108
  """Return opensearch:itemsPerPage."""
108
109
  try:
109
110
  if self.params.get("q"):
110
- return self.MAX_OBJ_PER_PAGE
111
+ return MAX_OBJ_PER_PAGE
111
112
  except Exception:
112
113
  LOG.exception("Getting OPDS v1 items per page")
113
114
 
@@ -11,6 +11,7 @@ from codex.logger.logging import get_logger
11
11
  from codex.models import AdminFlag
12
12
  from codex.serializers.opds.v2 import OPDS2FeedSerializer
13
13
  from codex.views.browser.browser import BrowserView
14
+ from codex.views.browser.const import MAX_OBJ_PER_PAGE
14
15
  from codex.views.const import FALSY
15
16
  from codex.views.opds.const import BLANK_TITLE
16
17
  from codex.views.opds.v2.const import (
@@ -175,14 +176,11 @@ class OPDS2FeedView(PublicationMixin, TopLinksMixin):
175
176
  """Get the browser page and serialize it for this subclass."""
176
177
  group = self.kwargs.get("group")
177
178
  if group in ("f", "a"):
178
- self.acquisition_groups = frozenset()
179
- else:
180
- self.acquisition_groups = frozenset(self.valid_nav_groups[-2:])
181
- if group == "a":
182
179
  pk = self.kwargs["pk"]
183
180
  self.is_opds_2_acquisition = bool(pk)
184
181
  else:
185
- self.is_opds_2_acquisition = group in self.acquisition_groups
182
+ acquisition_groups = frozenset(self.valid_nav_groups[-2:])
183
+ self.is_opds_2_acquisition = group in acquisition_groups
186
184
  self.is_opds_metadata = (
187
185
  self.request.query_params.get("opdsMetadata", "").lower() not in FALSY
188
186
  )
@@ -202,7 +200,7 @@ class OPDS2FeedView(PublicationMixin, TopLinksMixin):
202
200
  "metadata": {
203
201
  "title": title,
204
202
  "number_of_items": number_of_items,
205
- "items_per_page": self.MAX_OBJ_PER_PAGE,
203
+ "items_per_page": MAX_OBJ_PER_PAGE,
206
204
  "current_page": self.kwargs.get("page"),
207
205
  },
208
206
  "links": self.get_links(browser_page["up_route"]),
@@ -144,8 +144,10 @@ class PublicationMixin(LinksMixin):
144
144
 
145
145
  download_mime_type = MimeType.FILE_TYPE_MAP.get(obj.file_type, MimeType.OCTET)
146
146
  self_kwargs = {"group": "c", "pk": obj.pk, "page": 1}
147
- self_href_data = HrefData(self_kwargs, absolute_query_params=True)
148
- self_link_data = LinkData(Rel.SELF, self_href_data, mime_type=MimeType.OPDS_PUB)
147
+
148
+ # This would be for comic streaming which is not supported by OPDS 2 yet?
149
+ # self_href_data = HrefData(self_kwargs, absolute_query_params=True)
150
+ # self_link_data = LinkData(Rel.SELF, self_href_data, mime_type=MimeType.OPDS_PUB)
149
151
 
150
152
  alt_kwargs = self_kwargs
151
153
  alt_href_data = HrefData(
@@ -168,7 +170,8 @@ class PublicationMixin(LinksMixin):
168
170
  mime_type=download_mime_type,
169
171
  )
170
172
  links = [
171
- self.link(self_link_data),
173
+ # Comic streaming link (unsupported)
174
+ # self.link(self_link_data),
172
175
  self.link(alt_link_data),
173
176
  self.link(acq_link_data),
174
177
  ]
codex/views/session.py CHANGED
@@ -105,6 +105,7 @@ class BrowserSessionViewBase(SessionViewBaseBase):
105
105
  "order_reverse": False,
106
106
  "q": DEFAULTS["q"],
107
107
  "route": DEFAULTS["route"],
108
+ "search_results_limit": DEFAULTS["searchResultsLimit"],
108
109
  "show": DEFAULTS["show"],
109
110
  "twenty_four_hour_time": False,
110
111
  "top_group": DEFAULTS["topGroup"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codex
3
- Version: 1.5.12
3
+ Version: 1.5.13a0
4
4
  Summary: A comic archive web server.
5
5
  Home-page: https://github.com/ajslater/codex
6
6
  License: GPL-3.0-only
@@ -30,6 +30,7 @@ Requires-Dist: case-converter (>=1.1.0,<2.0.0)
30
30
  Requires-Dist: channels (>=4.0.0,<5.0.0)
31
31
  Requires-Dist: comicbox[pdf] (>=1.1.4,<2.0.0)
32
32
  Requires-Dist: django (>=5.0.3,<6.0.0)
33
+ Requires-Dist: django-cachalot (>=2.6.2,<3.0.0)
33
34
  Requires-Dist: django-cors-headers (>=4.0,<5.0)
34
35
  Requires-Dist: django-rest-registration (>=0.8.0,<0.9.0)
35
36
  Requires-Dist: django-vite (>=3.0.1,<4.0.0)
@@ -267,15 +268,29 @@ remove users to groups.
267
268
  Codex can make groups for libraries that exclude groups of users or exclude
268
269
  everyone and include only certain groups of users.
269
270
 
270
- ### PDFs
271
+ ### PDF Metadata
271
272
 
272
- Codex only reads PDF metadata from the filename. If you decide to include PDFs
273
- in your comic library, I recommend taking time to rename your files so Codex can
274
- find some metadata. Codex recognizes several file naming schemes. This one has
275
- good results:
273
+ Codex reads PDF metadata from the filename, PDF metadata fields and also many
274
+ formats of common complex comic metadata if they are embedded in the PDF
275
+ `keywords` field.
276
+
277
+ If you decide to include PDFs in your comic library, I recommend taking time to
278
+ rename your files so Codex can find some metadata. Codex recognizes several file
279
+ naming schemes. This one has good results:
276
280
 
277
281
  `{series} v{volume} #{issue} {title} ({year}) {ignored}.pdf`
278
282
 
283
+ Complex comic metadata, such as ComicInfo.xml, can be also be embedded in the
284
+ keywords field by using the [comicbox](https://github.com/ajslater/comicbox)
285
+ command line tool. Codex will read this data because it relies on comicbox
286
+ internally. Not many people use comicbox or embedded metadata in PDFs in this
287
+ fashion, so you likely won't find it unless you've added it yourself.
288
+
289
+ ### 🗝️ API with Key Access
290
+
291
+ Codex has a limited number of API endpoints available with API Key Access. The
292
+ API Key is available on the admin/stats tab.
293
+
279
294
  ## <a name="configuration">🎛️ Configuration</a>
280
295
 
281
296
  ### Config Dir
@@ -384,7 +399,7 @@ If you must run Codex in an admin restricted memory environment you might want
384
399
  to temporarily give Codex a lot of memory to run a very large import job and
385
400
  then restrict it for normal operation.
386
401
 
387
- ## <a name="usage">📖 Usage</a>
402
+ ## <a name="use">📖 Use</a>
388
403
 
389
404
  ### 👤 Sessions & Accounts
390
405
 
@@ -395,11 +410,6 @@ To preserve these settings across browsers and after sessions expire, you may
395
410
  register an account with a username and password. You will have to contact your
396
411
  administrator to reset your password if you forget it.
397
412
 
398
- ### 🗝️ API with Key Access
399
-
400
- Codex has a limited number of API endpoints available with API Key Access. The
401
- API Key is available on the admin/stats tab.
402
-
403
413
  ### ᯤ OPDS
404
414
 
405
415
  Codex supports OPDS syndication and OPDS streaming. You may find the OPDS url in
@@ -438,6 +448,7 @@ authentication. In that case the OPDS url will look like:
438
448
  - [OPDS-PSE 1.2](https://github.com/anansi-project/opds-pse/blob/master/v1.2.md)
439
449
  - [OPDS Authentication 1.0](https://drafts.opds.io/authentication-for-opds-1.0.html)
440
450
  - [OpenSearch 1.1](https://github.com/dewitt/opensearch)
451
+ - [OPDS 2.0 (draft)](https://drafts.opds.io/opds-2.0.html)
441
452
 
442
453
  ## <a name="troubleshooting">🩺 Troubleshooting</a>
443
454