codex 1.7.0a0__py3-none-any.whl → 1.7.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of codex might be problematic. Click here for more details.

Files changed (715) hide show
  1. codex/choices.py +404 -0
  2. codex/choices_to_json.py +122 -0
  3. codex/db.py +31 -15
  4. codex/exceptions.py +2 -3
  5. codex/librarian/bookmark/__init__.py +1 -0
  6. codex/librarian/bookmark/bookmarkd.py +38 -0
  7. codex/librarian/bookmark/tasks.py +19 -0
  8. codex/librarian/bookmark/update.py +154 -0
  9. codex/librarian/covers/coverd.py +3 -4
  10. codex/librarian/covers/create.py +8 -7
  11. codex/librarian/covers/path.py +1 -2
  12. codex/librarian/covers/purge.py +2 -2
  13. codex/librarian/janitor/integrity.py +1 -0
  14. codex/librarian/librariand.py +5 -0
  15. codex/librarian/watchdog/emitter.py +21 -19
  16. codex/librarian/watchdog/event_batcherd.py +0 -1
  17. codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +4 -0
  18. codex/models/admin.py +0 -5
  19. codex/models/functions.py +6 -5
  20. codex/models/query.py +6 -0
  21. codex/run.py +11 -9
  22. codex/serializers/admin/tasks.py +2 -2
  23. codex/serializers/browser/mixins.py +18 -14
  24. codex/serializers/browser/settings.py +4 -4
  25. codex/serializers/fields.py +9 -5
  26. codex/startup.py +6 -4
  27. codex/static_root/assets/VCheckbox-B38iL9f_.81d9c00753e7.js +1 -0
  28. codex/static_root/assets/VCheckbox-B38iL9f_.81d9c00753e7.js.br +0 -0
  29. codex/static_root/assets/VCheckbox-B38iL9f_.81d9c00753e7.js.gz +0 -0
  30. codex/static_root/assets/VCheckbox-B38iL9f_.js +1 -0
  31. codex/static_root/assets/VCheckbox-B38iL9f_.js.br +0 -0
  32. codex/static_root/assets/VCheckbox-B38iL9f_.js.gz +0 -0
  33. codex/static_root/assets/VCheckboxBtn-BbNnqvzj.aa7fa886f86a.js +1 -0
  34. codex/static_root/assets/VCheckboxBtn-BbNnqvzj.aa7fa886f86a.js.br +0 -0
  35. codex/static_root/assets/VCheckboxBtn-BbNnqvzj.aa7fa886f86a.js.gz +0 -0
  36. codex/static_root/assets/VCheckboxBtn-BbNnqvzj.js +1 -0
  37. codex/static_root/assets/VCheckboxBtn-BbNnqvzj.js.br +0 -0
  38. codex/static_root/assets/VCheckboxBtn-BbNnqvzj.js.gz +0 -0
  39. codex/static_root/assets/VCombobox-BaV3XhIr.bf0c945d80a9.js +1 -0
  40. codex/static_root/assets/VCombobox-BaV3XhIr.bf0c945d80a9.js.br +0 -0
  41. codex/static_root/assets/VCombobox-BaV3XhIr.bf0c945d80a9.js.gz +0 -0
  42. codex/static_root/assets/VCombobox-BaV3XhIr.js +1 -0
  43. codex/static_root/assets/VCombobox-BaV3XhIr.js.br +0 -0
  44. codex/static_root/assets/VCombobox-BaV3XhIr.js.gz +0 -0
  45. codex/static_root/assets/VDialog-CSvrKKb2.css +1 -0
  46. codex/static_root/assets/VDialog-CSvrKKb2.css.br +0 -0
  47. codex/static_root/assets/VDialog-CSvrKKb2.css.gz +0 -0
  48. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css +1 -0
  49. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.br +0 -0
  50. codex/static_root/assets/VDialog-CSvrKKb2.fd4d50904b17.css.gz +0 -0
  51. codex/static_root/assets/VDialog-DJR54d5g.9d6a52f62db3.js +1 -0
  52. codex/static_root/assets/VDialog-DJR54d5g.9d6a52f62db3.js.br +0 -0
  53. codex/static_root/assets/VDialog-DJR54d5g.9d6a52f62db3.js.gz +0 -0
  54. codex/static_root/assets/VDialog-DJR54d5g.js +1 -0
  55. codex/static_root/assets/VDialog-DJR54d5g.js.br +0 -0
  56. codex/static_root/assets/VDialog-DJR54d5g.js.gz +0 -0
  57. codex/static_root/assets/VExpansionPanels-CJWqDA9d.acf5acdb3a81.js +1 -0
  58. codex/static_root/assets/VExpansionPanels-CJWqDA9d.acf5acdb3a81.js.br +0 -0
  59. codex/static_root/assets/VExpansionPanels-CJWqDA9d.acf5acdb3a81.js.gz +0 -0
  60. codex/static_root/assets/VExpansionPanels-CJWqDA9d.js +1 -0
  61. codex/static_root/assets/VExpansionPanels-CJWqDA9d.js.br +0 -0
  62. codex/static_root/assets/VExpansionPanels-CJWqDA9d.js.gz +0 -0
  63. codex/static_root/assets/VRadioGroup-BFLE3yCT.8b78cefe4206.js +1 -0
  64. codex/static_root/assets/VRadioGroup-BFLE3yCT.8b78cefe4206.js.br +0 -0
  65. codex/static_root/assets/VRadioGroup-BFLE3yCT.8b78cefe4206.js.gz +0 -0
  66. codex/static_root/assets/VRadioGroup-BFLE3yCT.js +1 -0
  67. codex/static_root/assets/VRadioGroup-BFLE3yCT.js.br +0 -0
  68. codex/static_root/assets/VRadioGroup-BFLE3yCT.js.gz +0 -0
  69. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css +1 -0
  70. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.br +0 -0
  71. codex/static_root/assets/VSelect-DLu8bpcs.98bdcf35411c.css.gz +0 -0
  72. codex/static_root/assets/VSelect-DLu8bpcs.css +1 -0
  73. codex/static_root/assets/VSelect-DLu8bpcs.css.br +0 -0
  74. codex/static_root/assets/VSelect-DLu8bpcs.css.gz +0 -0
  75. codex/static_root/assets/VSelect-Dvsi19pi.6d38dc99e0a8.js +1 -0
  76. codex/static_root/assets/VSelect-Dvsi19pi.6d38dc99e0a8.js.br +0 -0
  77. codex/static_root/assets/VSelect-Dvsi19pi.6d38dc99e0a8.js.gz +0 -0
  78. codex/static_root/assets/VSelect-Dvsi19pi.js +1 -0
  79. codex/static_root/assets/VSelect-Dvsi19pi.js.br +0 -0
  80. codex/static_root/assets/VSelect-Dvsi19pi.js.gz +0 -0
  81. codex/static_root/assets/VSelectionControl-BioGLzkQ.106c3be4b6d4.js +1 -0
  82. codex/static_root/assets/VSelectionControl-BioGLzkQ.106c3be4b6d4.js.br +0 -0
  83. codex/static_root/assets/VSelectionControl-BioGLzkQ.106c3be4b6d4.js.gz +0 -0
  84. codex/static_root/assets/VSelectionControl-BioGLzkQ.js +1 -0
  85. codex/static_root/assets/VSelectionControl-BioGLzkQ.js.br +0 -0
  86. codex/static_root/assets/VSelectionControl-BioGLzkQ.js.gz +0 -0
  87. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css +1 -0
  88. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.br +0 -0
  89. codex/static_root/assets/VSlideGroup-BtXPhMOT.830f136ffd41.css.gz +0 -0
  90. codex/static_root/assets/VSlideGroup-BtXPhMOT.css +1 -0
  91. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.br +0 -0
  92. codex/static_root/assets/VSlideGroup-BtXPhMOT.css.gz +0 -0
  93. codex/static_root/assets/VSlideGroup-CFkaPBuS.1d168fc87687.js +1 -0
  94. codex/static_root/assets/VSlideGroup-CFkaPBuS.1d168fc87687.js.br +0 -0
  95. codex/static_root/assets/VSlideGroup-CFkaPBuS.1d168fc87687.js.gz +0 -0
  96. codex/static_root/assets/VSlideGroup-CFkaPBuS.js +1 -0
  97. codex/static_root/assets/VSlideGroup-CFkaPBuS.js.br +0 -0
  98. codex/static_root/assets/VSlideGroup-CFkaPBuS.js.gz +0 -0
  99. codex/static_root/assets/VTable-B7x3Oih2.d0010dab39ce.js +1 -0
  100. codex/static_root/assets/VTable-B7x3Oih2.d0010dab39ce.js.br +0 -0
  101. codex/static_root/assets/VTable-B7x3Oih2.d0010dab39ce.js.gz +0 -0
  102. codex/static_root/assets/VTable-B7x3Oih2.js +1 -0
  103. codex/static_root/assets/VTable-B7x3Oih2.js.br +0 -0
  104. codex/static_root/assets/VTable-B7x3Oih2.js.gz +0 -0
  105. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css +1 -0
  106. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.br +0 -0
  107. codex/static_root/assets/VTextField-BnCEPZIq.b0c32b2c0b14.css.gz +0 -0
  108. codex/static_root/assets/VTextField-BnCEPZIq.css +1 -0
  109. codex/static_root/assets/VTextField-BnCEPZIq.css.br +0 -0
  110. codex/static_root/assets/VTextField-BnCEPZIq.css.gz +0 -0
  111. codex/static_root/assets/VTextField-rsRdtAxl.488a06f530fe.js +1 -0
  112. codex/static_root/assets/VTextField-rsRdtAxl.488a06f530fe.js.br +0 -0
  113. codex/static_root/assets/VTextField-rsRdtAxl.488a06f530fe.js.gz +0 -0
  114. codex/static_root/assets/VTextField-rsRdtAxl.js +1 -0
  115. codex/static_root/assets/VTextField-rsRdtAxl.js.br +0 -0
  116. codex/static_root/assets/VTextField-rsRdtAxl.js.gz +0 -0
  117. codex/static_root/assets/VWindowItem-CibnlNHs.75a48ded87d5.js +1 -0
  118. codex/static_root/assets/VWindowItem-CibnlNHs.75a48ded87d5.js.br +0 -0
  119. codex/static_root/assets/VWindowItem-CibnlNHs.75a48ded87d5.js.gz +0 -0
  120. codex/static_root/assets/VWindowItem-CibnlNHs.js +1 -0
  121. codex/static_root/assets/VWindowItem-CibnlNHs.js.br +0 -0
  122. codex/static_root/assets/VWindowItem-CibnlNHs.js.gz +0 -0
  123. codex/static_root/assets/admin-CaVmJ-fa.251f5d3cc755.js +1 -0
  124. codex/static_root/assets/admin-CaVmJ-fa.251f5d3cc755.js.br +0 -0
  125. codex/static_root/assets/admin-CaVmJ-fa.251f5d3cc755.js.gz +0 -0
  126. codex/static_root/assets/admin-CaVmJ-fa.js +1 -0
  127. codex/static_root/assets/admin-CaVmJ-fa.js.br +0 -0
  128. codex/static_root/assets/admin-CaVmJ-fa.js.gz +0 -0
  129. codex/static_root/assets/{admin-CWEjaFr5.7d4523387384.css → admin-DJ7pIXDQ.css} +1 -1
  130. codex/static_root/assets/admin-DJ7pIXDQ.css.br +0 -0
  131. codex/static_root/assets/admin-DJ7pIXDQ.css.gz +0 -0
  132. codex/static_root/assets/{admin-CWEjaFr5.css → admin-DJ7pIXDQ.e2a77af73ef2.css} +1 -1
  133. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.br +0 -0
  134. codex/static_root/assets/admin-DJ7pIXDQ.e2a77af73ef2.css.gz +0 -0
  135. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css +1 -0
  136. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.br +0 -0
  137. codex/static_root/assets/admin-menu-B9bzD6hV.c13b7df2ff57.css.gz +0 -0
  138. codex/static_root/assets/admin-menu-B9bzD6hV.css +1 -0
  139. codex/static_root/assets/admin-menu-B9bzD6hV.css.br +0 -0
  140. codex/static_root/assets/admin-menu-B9bzD6hV.css.gz +0 -0
  141. codex/static_root/assets/admin-menu-Cb7A0Ilo.ddf1e9339257.js +1 -0
  142. codex/static_root/assets/admin-menu-Cb7A0Ilo.ddf1e9339257.js.br +0 -0
  143. codex/static_root/assets/admin-menu-Cb7A0Ilo.ddf1e9339257.js.gz +0 -0
  144. codex/static_root/assets/admin-menu-Cb7A0Ilo.js +1 -0
  145. codex/static_root/assets/admin-menu-Cb7A0Ilo.js.br +0 -0
  146. codex/static_root/assets/admin-menu-Cb7A0Ilo.js.gz +0 -0
  147. codex/static_root/assets/admin-settings-button-progress-DID-drll.979420762aea.js +1 -0
  148. codex/static_root/assets/admin-settings-button-progress-DID-drll.979420762aea.js.br +0 -0
  149. codex/static_root/assets/admin-settings-button-progress-DID-drll.979420762aea.js.gz +0 -0
  150. codex/static_root/assets/admin-settings-button-progress-DID-drll.js +1 -0
  151. codex/static_root/assets/admin-settings-button-progress-DID-drll.js.br +0 -0
  152. codex/static_root/assets/admin-settings-button-progress-DID-drll.js.gz +0 -0
  153. codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.2548c49a853e.css +1 -0
  154. codex/static_root/assets/admin-settings-button-progress-DUUQfVsZ.css +1 -0
  155. codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css +1 -0
  156. codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css.br +0 -0
  157. codex/static_root/assets/browser-Br5CorL4.6e2a416309d5.css.gz +0 -0
  158. codex/static_root/assets/browser-Br5CorL4.css +1 -0
  159. codex/static_root/assets/browser-Br5CorL4.css.br +0 -0
  160. codex/static_root/assets/browser-Br5CorL4.css.gz +0 -0
  161. codex/static_root/assets/browser-xxQTUEuu.1686c20dc492.js +1 -0
  162. codex/static_root/assets/browser-xxQTUEuu.1686c20dc492.js.br +0 -0
  163. codex/static_root/assets/browser-xxQTUEuu.1686c20dc492.js.gz +0 -0
  164. codex/static_root/assets/browser-xxQTUEuu.js +1 -0
  165. codex/static_root/assets/browser-xxQTUEuu.js.br +0 -0
  166. codex/static_root/assets/browser-xxQTUEuu.js.gz +0 -0
  167. codex/static_root/assets/change-password-dialog-DXY2Xg9k.4a7ca6108810.js +1 -0
  168. codex/static_root/assets/change-password-dialog-DXY2Xg9k.4a7ca6108810.js.br +0 -0
  169. codex/static_root/assets/change-password-dialog-DXY2Xg9k.4a7ca6108810.js.gz +0 -0
  170. codex/static_root/assets/change-password-dialog-DXY2Xg9k.js +1 -0
  171. codex/static_root/assets/change-password-dialog-DXY2Xg9k.js.br +0 -0
  172. codex/static_root/assets/change-password-dialog-DXY2Xg9k.js.gz +0 -0
  173. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css +1 -0
  174. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.br +0 -0
  175. codex/static_root/assets/change-password-dialog-DrIXdKUC.217574b45b02.css.gz +0 -0
  176. codex/static_root/assets/change-password-dialog-DrIXdKUC.css +1 -0
  177. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.br +0 -0
  178. codex/static_root/assets/change-password-dialog-DrIXdKUC.css.gz +0 -0
  179. codex/static_root/assets/confirm-dialog-B7w6z2rf.472011c06253.css +1 -0
  180. codex/static_root/assets/confirm-dialog-B7w6z2rf.css +1 -0
  181. codex/static_root/assets/confirm-dialog-BEVEU-kA.281b6e877fb5.js +1 -0
  182. codex/static_root/assets/confirm-dialog-BEVEU-kA.281b6e877fb5.js.br +0 -0
  183. codex/static_root/assets/confirm-dialog-BEVEU-kA.281b6e877fb5.js.gz +0 -0
  184. codex/static_root/assets/confirm-dialog-BEVEU-kA.js +1 -0
  185. codex/static_root/assets/confirm-dialog-BEVEU-kA.js.br +0 -0
  186. codex/static_root/assets/confirm-dialog-BEVEU-kA.js.gz +0 -0
  187. codex/static_root/assets/datetime-column-DhrZEHwa.80e95aef7bdb.js +1 -0
  188. codex/static_root/assets/datetime-column-DhrZEHwa.80e95aef7bdb.js.br +1 -0
  189. codex/static_root/assets/datetime-column-DhrZEHwa.80e95aef7bdb.js.gz +0 -0
  190. codex/static_root/assets/datetime-column-DhrZEHwa.js +1 -0
  191. codex/static_root/assets/datetime-column-DhrZEHwa.js.br +1 -0
  192. codex/static_root/assets/datetime-column-DhrZEHwa.js.gz +0 -0
  193. codex/static_root/assets/filter-BJ7TmFiU.3cefe2d609c7.js +1 -0
  194. codex/static_root/assets/filter-BJ7TmFiU.3cefe2d609c7.js.br +0 -0
  195. codex/static_root/assets/filter-BJ7TmFiU.3cefe2d609c7.js.gz +0 -0
  196. codex/static_root/assets/filter-BJ7TmFiU.js +1 -0
  197. codex/static_root/assets/filter-BJ7TmFiU.js.br +0 -0
  198. codex/static_root/assets/filter-BJ7TmFiU.js.gz +0 -0
  199. codex/static_root/assets/flag-tab-AJj0sesB.2ab1be15d10f.js +1 -0
  200. codex/static_root/assets/flag-tab-AJj0sesB.2ab1be15d10f.js.br +0 -0
  201. codex/static_root/assets/flag-tab-AJj0sesB.2ab1be15d10f.js.gz +0 -0
  202. codex/static_root/assets/flag-tab-AJj0sesB.js +1 -0
  203. codex/static_root/assets/flag-tab-AJj0sesB.js.br +0 -0
  204. codex/static_root/assets/flag-tab-AJj0sesB.js.gz +0 -0
  205. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css +1 -0
  206. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.br +0 -0
  207. codex/static_root/assets/flag-tab-CqWovuBu.4dfc6b251e85.css.gz +0 -0
  208. codex/static_root/assets/flag-tab-CqWovuBu.css +1 -0
  209. codex/static_root/assets/flag-tab-CqWovuBu.css.br +0 -0
  210. codex/static_root/assets/flag-tab-CqWovuBu.css.gz +0 -0
  211. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css +1 -0
  212. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.br +0 -0
  213. codex/static_root/assets/group-tab-DkIN1Heu.948e907b1e6b.css.gz +0 -0
  214. codex/static_root/assets/group-tab-DkIN1Heu.css +1 -0
  215. codex/static_root/assets/group-tab-DkIN1Heu.css.br +0 -0
  216. codex/static_root/assets/group-tab-DkIN1Heu.css.gz +0 -0
  217. codex/static_root/assets/group-tab-DuxOH4Hn.8ac96cfe7c43.js +1 -0
  218. codex/static_root/assets/group-tab-DuxOH4Hn.8ac96cfe7c43.js.br +0 -0
  219. codex/static_root/assets/group-tab-DuxOH4Hn.8ac96cfe7c43.js.gz +0 -0
  220. codex/static_root/assets/group-tab-DuxOH4Hn.js +1 -0
  221. codex/static_root/assets/group-tab-DuxOH4Hn.js.br +0 -0
  222. codex/static_root/assets/group-tab-DuxOH4Hn.js.gz +0 -0
  223. codex/static_root/assets/http-error-DIeFpbQV.086e1dd09555.js +1 -0
  224. codex/static_root/assets/http-error-DIeFpbQV.086e1dd09555.js.br +0 -0
  225. codex/static_root/assets/http-error-DIeFpbQV.086e1dd09555.js.gz +0 -0
  226. codex/static_root/assets/http-error-DIeFpbQV.js +1 -0
  227. codex/static_root/assets/http-error-DIeFpbQV.js.br +0 -0
  228. codex/static_root/assets/http-error-DIeFpbQV.js.gz +0 -0
  229. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css +1 -0
  230. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.br +0 -0
  231. codex/static_root/assets/index-CL_6g4tJ.523d7b3d350f.css.gz +0 -0
  232. codex/static_root/assets/index-CL_6g4tJ.css +1 -0
  233. codex/static_root/assets/index-CL_6g4tJ.css.br +0 -0
  234. codex/static_root/assets/index-CL_6g4tJ.css.gz +0 -0
  235. codex/static_root/assets/index-MN9BB_He.201e30aa00ef.js +1 -0
  236. codex/static_root/assets/index-MN9BB_He.201e30aa00ef.js.br +0 -0
  237. codex/static_root/assets/index-MN9BB_He.201e30aa00ef.js.gz +0 -0
  238. codex/static_root/assets/index-MN9BB_He.js +1 -0
  239. codex/static_root/assets/index-MN9BB_He.js.br +0 -0
  240. codex/static_root/assets/index-MN9BB_He.js.gz +0 -0
  241. codex/static_root/assets/{library-tab-Bh7ErAk7.7c44200ee727.css → library-tab-Wew8YOLv.0c1780a6b68e.css} +1 -1
  242. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.br +0 -0
  243. codex/static_root/assets/library-tab-Wew8YOLv.0c1780a6b68e.css.gz +0 -0
  244. codex/static_root/assets/{library-tab-Bh7ErAk7.css → library-tab-Wew8YOLv.css} +1 -1
  245. codex/static_root/assets/library-tab-Wew8YOLv.css.br +0 -0
  246. codex/static_root/assets/library-tab-Wew8YOLv.css.gz +0 -0
  247. codex/static_root/assets/library-tab-jpeUUWzV.70dae13f6dab.js +1 -0
  248. codex/static_root/assets/library-tab-jpeUUWzV.70dae13f6dab.js.br +0 -0
  249. codex/static_root/assets/library-tab-jpeUUWzV.70dae13f6dab.js.gz +0 -0
  250. codex/static_root/assets/library-tab-jpeUUWzV.js +1 -0
  251. codex/static_root/assets/library-tab-jpeUUWzV.js.br +0 -0
  252. codex/static_root/assets/library-tab-jpeUUWzV.js.gz +0 -0
  253. codex/static_root/assets/main-Cs7q8tob.86ef2567544d.js +35 -0
  254. codex/static_root/assets/main-Cs7q8tob.86ef2567544d.js.br +0 -0
  255. codex/static_root/assets/main-Cs7q8tob.86ef2567544d.js.gz +0 -0
  256. codex/static_root/assets/main-Cs7q8tob.js +35 -0
  257. codex/static_root/assets/main-Cs7q8tob.js.br +0 -0
  258. codex/static_root/assets/main-Cs7q8tob.js.gz +0 -0
  259. codex/static_root/assets/pager-full-pdf-D_ecZhu-.ff93ca6c55e0.js +1 -0
  260. codex/static_root/assets/pager-full-pdf-D_ecZhu-.ff93ca6c55e0.js.br +0 -0
  261. codex/static_root/assets/pager-full-pdf-D_ecZhu-.ff93ca6c55e0.js.gz +0 -0
  262. codex/static_root/assets/pager-full-pdf-D_ecZhu-.js +1 -0
  263. codex/static_root/assets/pager-full-pdf-D_ecZhu-.js.br +0 -0
  264. codex/static_root/assets/pager-full-pdf-D_ecZhu-.js.gz +0 -0
  265. codex/static_root/assets/pagination-toolbar-yeU7sPiY.ce0751d6009d.js +1 -0
  266. codex/static_root/assets/pagination-toolbar-yeU7sPiY.ce0751d6009d.js.br +0 -0
  267. codex/static_root/assets/pagination-toolbar-yeU7sPiY.ce0751d6009d.js.gz +0 -0
  268. codex/static_root/assets/pagination-toolbar-yeU7sPiY.js +1 -0
  269. codex/static_root/assets/pagination-toolbar-yeU7sPiY.js.br +0 -0
  270. codex/static_root/assets/pagination-toolbar-yeU7sPiY.js.gz +0 -0
  271. codex/static_root/assets/{pdf-doc-BcRNpoaW.882f6e967869.js → pdf-doc-Czi9tnhD.4d4b8b7ff5d7.js} +3 -3
  272. codex/static_root/assets/pdf-doc-Czi9tnhD.4d4b8b7ff5d7.js.br +0 -0
  273. codex/static_root/assets/pdf-doc-Czi9tnhD.4d4b8b7ff5d7.js.gz +0 -0
  274. codex/static_root/assets/{pdf-doc-BcRNpoaW.js → pdf-doc-Czi9tnhD.js} +3 -3
  275. codex/static_root/assets/pdf-doc-Czi9tnhD.js.br +0 -0
  276. codex/static_root/assets/pdf-doc-Czi9tnhD.js.gz +0 -0
  277. codex/static_root/assets/reader-DQKMY8MS.d9d3451f2cff.js +2 -0
  278. codex/static_root/assets/reader-DQKMY8MS.d9d3451f2cff.js.br +0 -0
  279. codex/static_root/assets/reader-DQKMY8MS.d9d3451f2cff.js.gz +0 -0
  280. codex/static_root/assets/reader-DQKMY8MS.js +2 -0
  281. codex/static_root/assets/reader-DQKMY8MS.js.br +0 -0
  282. codex/static_root/assets/reader-DQKMY8MS.js.gz +0 -0
  283. codex/static_root/assets/{reader-DveZZr9x.7b21b9f8f628.css → reader-OpKdTZ_B.css} +1 -1
  284. codex/static_root/assets/reader-OpKdTZ_B.css.br +0 -0
  285. codex/static_root/assets/reader-OpKdTZ_B.css.gz +0 -0
  286. codex/static_root/assets/{reader-DveZZr9x.css → reader-OpKdTZ_B.ebd1512b7014.css} +1 -1
  287. codex/static_root/assets/reader-OpKdTZ_B.ebd1512b7014.css.br +0 -0
  288. codex/static_root/assets/reader-OpKdTZ_B.ebd1512b7014.css.gz +0 -0
  289. codex/static_root/assets/relation-chips-CFH0Xf78.62ded2739a22.js +1 -0
  290. codex/static_root/assets/relation-chips-CFH0Xf78.62ded2739a22.js.br +0 -0
  291. codex/static_root/assets/relation-chips-CFH0Xf78.62ded2739a22.js.gz +0 -0
  292. codex/static_root/assets/relation-chips-CFH0Xf78.js +1 -0
  293. codex/static_root/assets/relation-chips-CFH0Xf78.js.br +0 -0
  294. codex/static_root/assets/relation-chips-CFH0Xf78.js.gz +0 -0
  295. codex/static_root/assets/settings-drawer-DbOztp2R.b6f981108782.js +2 -0
  296. codex/static_root/assets/settings-drawer-DbOztp2R.b6f981108782.js.br +0 -0
  297. codex/static_root/assets/settings-drawer-DbOztp2R.b6f981108782.js.gz +0 -0
  298. codex/static_root/assets/settings-drawer-DbOztp2R.js +2 -0
  299. codex/static_root/assets/settings-drawer-DbOztp2R.js.br +0 -0
  300. codex/static_root/assets/settings-drawer-DbOztp2R.js.gz +0 -0
  301. codex/static_root/assets/{stats-tab-DpfGsVX3.1cb66f2649a9.css → stats-tab-BAYTqQNg.5f715428c394.css} +1 -1
  302. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.br +0 -0
  303. codex/static_root/assets/stats-tab-BAYTqQNg.5f715428c394.css.gz +0 -0
  304. codex/static_root/assets/{stats-tab-DpfGsVX3.css → stats-tab-BAYTqQNg.css} +1 -1
  305. codex/static_root/assets/stats-tab-BAYTqQNg.css.br +0 -0
  306. codex/static_root/assets/stats-tab-BAYTqQNg.css.gz +0 -0
  307. codex/static_root/assets/stats-tab-DWktIwEj.42666baa0d93.js +1 -0
  308. codex/static_root/assets/stats-tab-DWktIwEj.42666baa0d93.js.br +0 -0
  309. codex/static_root/assets/stats-tab-DWktIwEj.42666baa0d93.js.gz +0 -0
  310. codex/static_root/assets/stats-tab-DWktIwEj.js +1 -0
  311. codex/static_root/assets/stats-tab-DWktIwEj.js.br +0 -0
  312. codex/static_root/assets/stats-tab-DWktIwEj.js.gz +0 -0
  313. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css +1 -0
  314. codex/static_root/assets/{task-tab-1XiWn9xP.06cb8e1b794d.css.br → task-tab--cXi48kg.5dfd6890a1c2.css.br} +1 -1
  315. codex/static_root/assets/task-tab--cXi48kg.5dfd6890a1c2.css.gz +0 -0
  316. codex/static_root/assets/task-tab--cXi48kg.css +1 -0
  317. codex/static_root/assets/{task-tab-1XiWn9xP.css.br → task-tab--cXi48kg.css.br} +1 -1
  318. codex/static_root/assets/task-tab--cXi48kg.css.gz +0 -0
  319. codex/static_root/assets/task-tab-BtTtKJP6.421692e51e82.js +1 -0
  320. codex/static_root/assets/task-tab-BtTtKJP6.421692e51e82.js.br +0 -0
  321. codex/static_root/assets/task-tab-BtTtKJP6.421692e51e82.js.gz +0 -0
  322. codex/static_root/assets/task-tab-BtTtKJP6.js +1 -0
  323. codex/static_root/assets/task-tab-BtTtKJP6.js.br +0 -0
  324. codex/static_root/assets/task-tab-BtTtKJP6.js.gz +0 -0
  325. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css +1 -0
  326. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.br +4 -0
  327. codex/static_root/assets/transition-5LRFTPo5.3d726f9bbcb0.css.gz +0 -0
  328. codex/static_root/assets/transition-5LRFTPo5.css +1 -0
  329. codex/static_root/assets/transition-5LRFTPo5.css.br +4 -0
  330. codex/static_root/assets/transition-5LRFTPo5.css.gz +0 -0
  331. codex/static_root/assets/transition-A__CJ90w.970355913cb9.js +1 -0
  332. codex/static_root/assets/transition-A__CJ90w.970355913cb9.js.br +0 -0
  333. codex/static_root/assets/transition-A__CJ90w.970355913cb9.js.gz +0 -0
  334. codex/static_root/assets/transition-A__CJ90w.js +1 -0
  335. codex/static_root/assets/transition-A__CJ90w.js.br +0 -0
  336. codex/static_root/assets/transition-A__CJ90w.js.gz +0 -0
  337. codex/static_root/assets/unauthorized-FF1nwDKt.b3d6255ddb7f.js +1 -0
  338. codex/static_root/assets/unauthorized-FF1nwDKt.b3d6255ddb7f.js.br +0 -0
  339. codex/static_root/assets/unauthorized-FF1nwDKt.b3d6255ddb7f.js.gz +0 -0
  340. codex/static_root/assets/unauthorized-FF1nwDKt.js +1 -0
  341. codex/static_root/assets/unauthorized-FF1nwDKt.js.br +0 -0
  342. codex/static_root/assets/unauthorized-FF1nwDKt.js.gz +0 -0
  343. codex/static_root/assets/user-tab-RwMqZeSN.d4ed24177855.js +1 -0
  344. codex/static_root/assets/user-tab-RwMqZeSN.d4ed24177855.js.br +0 -0
  345. codex/static_root/assets/user-tab-RwMqZeSN.d4ed24177855.js.gz +0 -0
  346. codex/static_root/assets/user-tab-RwMqZeSN.js +1 -0
  347. codex/static_root/assets/user-tab-RwMqZeSN.js.br +0 -0
  348. codex/static_root/assets/user-tab-RwMqZeSN.js.gz +0 -0
  349. codex/static_root/manifest.8dff5f2fb15e.json +712 -0
  350. codex/static_root/manifest.8dff5f2fb15e.json.br +0 -0
  351. codex/static_root/manifest.8dff5f2fb15e.json.gz +0 -0
  352. codex/static_root/manifest.json +377 -300
  353. codex/static_root/manifest.json.br +0 -0
  354. codex/static_root/manifest.json.gz +0 -0
  355. codex/static_root/staticfiles.json +1 -1
  356. codex/status_controller.py +5 -6
  357. codex/threads.py +1 -1
  358. codex/urls/api/auth.py +1 -1
  359. codex/urls/api/browser.py +1 -1
  360. codex/views/admin/library.py +18 -13
  361. codex/views/admin/stats.py +23 -16
  362. codex/views/auth.py +42 -77
  363. codex/views/bookmark.py +16 -153
  364. codex/views/browser/annotate/__init__.py +1 -0
  365. codex/views/browser/annotate/bookmark.py +112 -0
  366. codex/views/browser/annotate/card.py +61 -0
  367. codex/views/browser/annotate/order.py +247 -0
  368. codex/views/browser/breadcrumbs.py +90 -11
  369. codex/views/browser/browser.py +44 -110
  370. codex/views/browser/choices.py +15 -18
  371. codex/views/browser/cover.py +10 -20
  372. codex/views/browser/filters/bookmark.py +18 -19
  373. codex/views/browser/filters/field.py +8 -3
  374. codex/views/browser/filters/filter.py +69 -0
  375. codex/views/browser/filters/group.py +9 -6
  376. codex/views/browser/filters/search/fts.py +5 -19
  377. codex/views/browser/filters/search/parse.py +54 -24
  378. codex/views/browser/group_mtime.py +83 -0
  379. codex/views/browser/metadata/__init__.py +1 -0
  380. codex/views/browser/metadata/annotate.py +109 -0
  381. codex/views/browser/metadata/copy_intersections.py +90 -0
  382. codex/views/browser/metadata/metadata.py +83 -0
  383. codex/views/browser/metadata/query_intersections.py +114 -0
  384. codex/views/browser/mtime.py +2 -10
  385. codex/views/browser/order_by.py +22 -22
  386. codex/views/browser/page_in_bounds.py +2 -2
  387. codex/views/browser/paginate.py +9 -15
  388. codex/views/browser/params.py +64 -0
  389. codex/views/browser/title.py +1 -6
  390. codex/views/browser/validate.py +68 -33
  391. codex/views/download.py +1 -1
  392. codex/views/mixins.py +27 -15
  393. codex/views/opds/const.py +2 -3
  394. codex/views/opds/urls.py +2 -2
  395. codex/views/opds/util.py +2 -3
  396. codex/views/opds/v1/entry/links.py +3 -1
  397. codex/views/opds/v1/facets.py +65 -12
  398. codex/views/opds/v1/feed.py +5 -64
  399. codex/views/opds/v1/links.py +5 -4
  400. codex/views/opds/v2/feed.py +1 -28
  401. codex/views/opds/v2/links.py +26 -1
  402. codex/views/opds/v2/publications.py +5 -6
  403. codex/views/opds/v2/top_links.py +3 -6
  404. codex/views/public.py +2 -2
  405. codex/views/reader/arcs.py +0 -3
  406. codex/views/reader/books.py +57 -41
  407. codex/views/reader/page.py +10 -4
  408. codex/views/reader/{init.py → params.py} +37 -31
  409. codex/views/reader/reader.py +1 -2
  410. codex/views/session.py +43 -54
  411. codex/views/timezone.py +54 -0
  412. codex/views/version.py +1 -1
  413. {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/METADATA +1 -1
  414. {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/RECORD +417 -383
  415. codex/serializers/choices.py +0 -196
  416. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js +0 -1
  417. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.br +0 -0
  418. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.gz +0 -0
  419. codex/static_root/assets/VCheckbox-CWiqcZ7a.js +0 -1
  420. codex/static_root/assets/VCheckbox-CWiqcZ7a.js.br +0 -0
  421. codex/static_root/assets/VCheckbox-CWiqcZ7a.js.gz +0 -0
  422. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js +0 -1
  423. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.br +0 -0
  424. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.gz +0 -0
  425. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js +0 -1
  426. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.br +0 -0
  427. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.gz +0 -0
  428. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js +0 -1
  429. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.br +0 -0
  430. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.gz +0 -0
  431. codex/static_root/assets/VCombobox-D1_KU27A.js +0 -1
  432. codex/static_root/assets/VCombobox-D1_KU27A.js.br +0 -0
  433. codex/static_root/assets/VCombobox-D1_KU27A.js.gz +0 -0
  434. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css +0 -1
  435. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.br +0 -0
  436. codex/static_root/assets/VDialog-38np3TSA.5a0cb7a9e56d.css.gz +0 -0
  437. codex/static_root/assets/VDialog-38np3TSA.css +0 -1
  438. codex/static_root/assets/VDialog-38np3TSA.css.br +0 -0
  439. codex/static_root/assets/VDialog-38np3TSA.css.gz +0 -0
  440. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js +0 -1
  441. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.br +0 -0
  442. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.gz +0 -0
  443. codex/static_root/assets/VDialog-GbxvFMMN.js +0 -1
  444. codex/static_root/assets/VDialog-GbxvFMMN.js.br +0 -0
  445. codex/static_root/assets/VDialog-GbxvFMMN.js.gz +0 -0
  446. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js +0 -1
  447. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.br +0 -0
  448. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.gz +0 -0
  449. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js +0 -1
  450. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.br +0 -0
  451. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.gz +0 -0
  452. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js +0 -1
  453. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.br +0 -0
  454. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.gz +0 -0
  455. codex/static_root/assets/VRadioGroup-C0etmxpZ.js +0 -1
  456. codex/static_root/assets/VRadioGroup-C0etmxpZ.js.br +0 -0
  457. codex/static_root/assets/VRadioGroup-C0etmxpZ.js.gz +0 -0
  458. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css +0 -1
  459. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.br +0 -0
  460. codex/static_root/assets/VSelect-Ca2bIOso.6613989e4c45.css.gz +0 -0
  461. codex/static_root/assets/VSelect-Ca2bIOso.css +0 -1
  462. codex/static_root/assets/VSelect-Ca2bIOso.css.br +0 -0
  463. codex/static_root/assets/VSelect-Ca2bIOso.css.gz +0 -0
  464. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js +0 -1
  465. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.br +0 -0
  466. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.gz +0 -0
  467. codex/static_root/assets/VSelect-txrnRiNJ.js +0 -1
  468. codex/static_root/assets/VSelect-txrnRiNJ.js.br +0 -0
  469. codex/static_root/assets/VSelect-txrnRiNJ.js.gz +0 -0
  470. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js +0 -1
  471. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.br +0 -0
  472. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.gz +0 -0
  473. codex/static_root/assets/VSelectionControl-CY6RmcvW.js +0 -1
  474. codex/static_root/assets/VSelectionControl-CY6RmcvW.js.br +0 -0
  475. codex/static_root/assets/VSelectionControl-CY6RmcvW.js.gz +0 -0
  476. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css +0 -1
  477. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.br +0 -0
  478. codex/static_root/assets/VSlideGroup-Dk_1upHt.2c836070ec75.css.gz +0 -0
  479. codex/static_root/assets/VSlideGroup-Dk_1upHt.css +0 -1
  480. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.br +0 -0
  481. codex/static_root/assets/VSlideGroup-Dk_1upHt.css.gz +0 -0
  482. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js +0 -1
  483. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.br +0 -0
  484. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.gz +0 -0
  485. codex/static_root/assets/VSlideGroup-DtEQMwY1.js +0 -1
  486. codex/static_root/assets/VSlideGroup-DtEQMwY1.js.br +0 -0
  487. codex/static_root/assets/VSlideGroup-DtEQMwY1.js.gz +0 -0
  488. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js +0 -1
  489. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.br +0 -0
  490. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.gz +0 -0
  491. codex/static_root/assets/VTable-2af995xo.js +0 -1
  492. codex/static_root/assets/VTable-2af995xo.js.br +0 -0
  493. codex/static_root/assets/VTable-2af995xo.js.gz +0 -0
  494. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css +0 -1
  495. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.br +0 -0
  496. codex/static_root/assets/VTextField-Crc3gdNh.39995ccf4d52.css.gz +0 -0
  497. codex/static_root/assets/VTextField-Crc3gdNh.css +0 -1
  498. codex/static_root/assets/VTextField-Crc3gdNh.css.br +0 -0
  499. codex/static_root/assets/VTextField-Crc3gdNh.css.gz +0 -0
  500. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js +0 -1
  501. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.br +0 -0
  502. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.gz +0 -0
  503. codex/static_root/assets/VTextField-G6CMj7yO.js +0 -1
  504. codex/static_root/assets/VTextField-G6CMj7yO.js.br +0 -0
  505. codex/static_root/assets/VTextField-G6CMj7yO.js.gz +0 -0
  506. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js +0 -1
  507. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.br +0 -0
  508. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.gz +0 -0
  509. codex/static_root/assets/VWindowItem-CzoGd6Ul.js +0 -1
  510. codex/static_root/assets/VWindowItem-CzoGd6Ul.js.br +0 -0
  511. codex/static_root/assets/VWindowItem-CzoGd6Ul.js.gz +0 -0
  512. codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.br +0 -0
  513. codex/static_root/assets/admin-CWEjaFr5.7d4523387384.css.gz +0 -0
  514. codex/static_root/assets/admin-CWEjaFr5.css.br +0 -0
  515. codex/static_root/assets/admin-CWEjaFr5.css.gz +0 -0
  516. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js +0 -1
  517. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.br +0 -0
  518. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.gz +0 -0
  519. codex/static_root/assets/admin-CsPAIQeG.js +0 -1
  520. codex/static_root/assets/admin-CsPAIQeG.js.br +0 -0
  521. codex/static_root/assets/admin-CsPAIQeG.js.gz +0 -0
  522. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js +0 -30
  523. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.br +0 -0
  524. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.gz +0 -0
  525. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js +0 -30
  526. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.br +0 -0
  527. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.gz +0 -0
  528. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css +0 -1
  529. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.br +0 -0
  530. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.3cb33056e994.css.gz +0 -0
  531. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css +0 -1
  532. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.br +0 -0
  533. codex/static_root/assets/admin-drawer-panel-Bs2wgKj3.css.gz +0 -0
  534. codex/static_root/assets/browser-C18l93yc.923860009ef4.js +0 -1
  535. codex/static_root/assets/browser-C18l93yc.923860009ef4.js.br +0 -0
  536. codex/static_root/assets/browser-C18l93yc.923860009ef4.js.gz +0 -0
  537. codex/static_root/assets/browser-C18l93yc.js +0 -1
  538. codex/static_root/assets/browser-C18l93yc.js.br +0 -0
  539. codex/static_root/assets/browser-C18l93yc.js.gz +0 -0
  540. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css +0 -1
  541. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.br +0 -0
  542. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.gz +0 -0
  543. codex/static_root/assets/browser-DaAqlBYO.css +0 -1
  544. codex/static_root/assets/browser-DaAqlBYO.css.br +0 -0
  545. codex/static_root/assets/browser-DaAqlBYO.css.gz +0 -0
  546. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js +0 -1
  547. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.br +0 -0
  548. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.gz +0 -0
  549. codex/static_root/assets/change-password-dialog-BazJdNs9.js +0 -1
  550. codex/static_root/assets/change-password-dialog-BazJdNs9.js.br +0 -0
  551. codex/static_root/assets/change-password-dialog-BazJdNs9.js.gz +0 -0
  552. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css +0 -1
  553. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.br +0 -0
  554. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.gz +0 -0
  555. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css +0 -1
  556. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.br +0 -0
  557. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.gz +0 -0
  558. codex/static_root/assets/confirm-dialog-BmhedLCx.7c2103d319d4.css +0 -1
  559. codex/static_root/assets/confirm-dialog-BmhedLCx.css +0 -1
  560. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js +0 -1
  561. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.br +0 -0
  562. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.gz +0 -0
  563. codex/static_root/assets/confirm-dialog-CbW3hlOp.js +0 -1
  564. codex/static_root/assets/confirm-dialog-CbW3hlOp.js.br +0 -0
  565. codex/static_root/assets/confirm-dialog-CbW3hlOp.js.gz +0 -0
  566. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js +0 -1
  567. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.br +0 -0
  568. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.gz +0 -0
  569. codex/static_root/assets/datetime-column-uSqKZU37.js +0 -1
  570. codex/static_root/assets/datetime-column-uSqKZU37.js.br +0 -0
  571. codex/static_root/assets/datetime-column-uSqKZU37.js.gz +0 -0
  572. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js +0 -1
  573. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.br +0 -0
  574. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.gz +0 -0
  575. codex/static_root/assets/filter-CBl5KEsB.js +0 -1
  576. codex/static_root/assets/filter-CBl5KEsB.js.br +0 -0
  577. codex/static_root/assets/filter-CBl5KEsB.js.gz +0 -0
  578. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js +0 -1
  579. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.br +0 -0
  580. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.gz +0 -0
  581. codex/static_root/assets/flag-tab-CT8pqM4r.js +0 -1
  582. codex/static_root/assets/flag-tab-CT8pqM4r.js.br +0 -0
  583. codex/static_root/assets/flag-tab-CT8pqM4r.js.gz +0 -0
  584. codex/static_root/assets/flag-tab-DBqpLKi7.css +0 -1
  585. codex/static_root/assets/flag-tab-DBqpLKi7.css.br +0 -0
  586. codex/static_root/assets/flag-tab-DBqpLKi7.css.gz +0 -0
  587. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css +0 -1
  588. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.br +0 -0
  589. codex/static_root/assets/flag-tab-DBqpLKi7.dcfef39f541e.css.gz +0 -0
  590. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js +0 -1
  591. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.br +0 -0
  592. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.gz +0 -0
  593. codex/static_root/assets/group-tab-BOW9kigw.js +0 -1
  594. codex/static_root/assets/group-tab-BOW9kigw.js.br +0 -0
  595. codex/static_root/assets/group-tab-BOW9kigw.js.gz +0 -0
  596. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css +0 -1
  597. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.br +0 -0
  598. codex/static_root/assets/group-tab-CBKuS3Iv.7e4746634782.css.gz +0 -0
  599. codex/static_root/assets/group-tab-CBKuS3Iv.css +0 -1
  600. codex/static_root/assets/group-tab-CBKuS3Iv.css.br +0 -0
  601. codex/static_root/assets/group-tab-CBKuS3Iv.css.gz +0 -0
  602. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js +0 -1
  603. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.br +0 -4
  604. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.gz +0 -0
  605. codex/static_root/assets/http-error-C6yuLApo.js +0 -1
  606. codex/static_root/assets/http-error-C6yuLApo.js.br +0 -4
  607. codex/static_root/assets/http-error-C6yuLApo.js.gz +0 -0
  608. codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.br +0 -2
  609. codex/static_root/assets/library-tab-Bh7ErAk7.7c44200ee727.css.gz +0 -0
  610. codex/static_root/assets/library-tab-Bh7ErAk7.css.br +0 -2
  611. codex/static_root/assets/library-tab-Bh7ErAk7.css.gz +0 -0
  612. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js +0 -1
  613. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.br +0 -0
  614. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.gz +0 -0
  615. codex/static_root/assets/library-tab-D3WOtpE0.js +0 -1
  616. codex/static_root/assets/library-tab-D3WOtpE0.js.br +0 -0
  617. codex/static_root/assets/library-tab-D3WOtpE0.js.gz +0 -0
  618. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js +0 -6
  619. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.br +0 -0
  620. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.gz +0 -0
  621. codex/static_root/assets/main-CmjU2oTp.js +0 -6
  622. codex/static_root/assets/main-CmjU2oTp.js.br +0 -0
  623. codex/static_root/assets/main-CmjU2oTp.js.gz +0 -0
  624. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js +0 -1
  625. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.br +0 -0
  626. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.gz +0 -0
  627. codex/static_root/assets/pager-full-pdf-BH54_5f6.js +0 -1
  628. codex/static_root/assets/pager-full-pdf-BH54_5f6.js.br +0 -0
  629. codex/static_root/assets/pager-full-pdf-BH54_5f6.js.gz +0 -0
  630. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js +0 -1
  631. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.br +0 -0
  632. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.gz +0 -0
  633. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js +0 -1
  634. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.br +0 -0
  635. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.gz +0 -0
  636. codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.br +0 -0
  637. codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.gz +0 -0
  638. codex/static_root/assets/pdf-doc-BcRNpoaW.js.br +0 -0
  639. codex/static_root/assets/pdf-doc-BcRNpoaW.js.gz +0 -0
  640. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js +0 -2
  641. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.br +0 -0
  642. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.gz +0 -0
  643. codex/static_root/assets/reader-DIPRg2VB.js +0 -2
  644. codex/static_root/assets/reader-DIPRg2VB.js.br +0 -0
  645. codex/static_root/assets/reader-DIPRg2VB.js.gz +0 -0
  646. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.br +0 -0
  647. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.gz +0 -0
  648. codex/static_root/assets/reader-DveZZr9x.css.br +0 -0
  649. codex/static_root/assets/reader-DveZZr9x.css.gz +0 -0
  650. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js +0 -1
  651. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.br +0 -0
  652. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.gz +0 -0
  653. codex/static_root/assets/relation-chips-3tTlR5QH.js +0 -1
  654. codex/static_root/assets/relation-chips-3tTlR5QH.js.br +0 -0
  655. codex/static_root/assets/relation-chips-3tTlR5QH.js.gz +0 -0
  656. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js +0 -2
  657. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.br +0 -0
  658. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.gz +0 -0
  659. codex/static_root/assets/settings-drawer-BdyFhA_r.js +0 -2
  660. codex/static_root/assets/settings-drawer-BdyFhA_r.js.br +0 -0
  661. codex/static_root/assets/settings-drawer-BdyFhA_r.js.gz +0 -0
  662. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js +0 -1
  663. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.br +0 -0
  664. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.gz +0 -0
  665. codex/static_root/assets/stats-tab-DeKjwvmh.js +0 -1
  666. codex/static_root/assets/stats-tab-DeKjwvmh.js.br +0 -0
  667. codex/static_root/assets/stats-tab-DeKjwvmh.js.gz +0 -0
  668. codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.br +0 -0
  669. codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.gz +0 -0
  670. codex/static_root/assets/stats-tab-DpfGsVX3.css.br +0 -0
  671. codex/static_root/assets/stats-tab-DpfGsVX3.css.gz +0 -0
  672. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css +0 -1
  673. codex/static_root/assets/task-tab-1XiWn9xP.06cb8e1b794d.css.gz +0 -0
  674. codex/static_root/assets/task-tab-1XiWn9xP.css +0 -1
  675. codex/static_root/assets/task-tab-1XiWn9xP.css.gz +0 -0
  676. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js +0 -1
  677. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.br +0 -0
  678. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.gz +0 -0
  679. codex/static_root/assets/task-tab-C8D0qRP_.js +0 -1
  680. codex/static_root/assets/task-tab-C8D0qRP_.js.br +0 -0
  681. codex/static_root/assets/task-tab-C8D0qRP_.js.gz +0 -0
  682. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js +0 -1
  683. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.br +0 -0
  684. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.gz +0 -0
  685. codex/static_root/assets/unauthorized-BHgBRF4z.js +0 -1
  686. codex/static_root/assets/unauthorized-BHgBRF4z.js.br +0 -0
  687. codex/static_root/assets/unauthorized-BHgBRF4z.js.gz +0 -0
  688. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js +0 -1
  689. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.br +0 -0
  690. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.gz +0 -0
  691. codex/static_root/assets/user-tab-BU31Z92y.js +0 -1
  692. codex/static_root/assets/user-tab-BU31Z92y.js.br +0 -0
  693. codex/static_root/assets/user-tab-BU31Z92y.js.gz +0 -0
  694. codex/static_root/js/choices-admin.8aa64c911203.json +0 -1
  695. codex/static_root/js/choices-admin.8aa64c911203.json.br +0 -0
  696. codex/static_root/js/choices-admin.8aa64c911203.json.gz +0 -0
  697. codex/static_root/js/choices-admin.json +0 -1
  698. codex/static_root/js/choices-admin.json.br +0 -0
  699. codex/static_root/js/choices-admin.json.gz +0 -0
  700. codex/static_root/js/choices.2f6b0359e1ef.json +0 -1
  701. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  702. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  703. codex/static_root/js/choices.json +0 -1
  704. codex/static_root/js/choices.json.br +0 -0
  705. codex/static_root/js/choices.json.gz +0 -0
  706. codex/static_root/manifest.45cb46e19686.json +0 -635
  707. codex/static_root/manifest.45cb46e19686.json.br +0 -0
  708. codex/static_root/manifest.45cb46e19686.json.gz +0 -0
  709. codex/views/browser/annotations.py +0 -339
  710. codex/views/browser/base.py +0 -139
  711. codex/views/browser/filters/annotations.py +0 -125
  712. codex/views/browser/metadata.py +0 -332
  713. {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/LICENSE +0 -0
  714. {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/WHEEL +0 -0
  715. {codex-1.7.0a0.dist-info → codex-1.7.0a1.dist-info}/entry_points.txt +0 -0
codex/choices.py ADDED
@@ -0,0 +1,404 @@
1
+ """Frontend Choices, Defaults and Messages."""
2
+
3
+ from collections.abc import Mapping
4
+ from types import MappingProxyType
5
+
6
+ BROWSER_BOOKMARK_FILTER_CHOICES = MappingProxyType(
7
+ {
8
+ "": "All",
9
+ "IN_PROGRESS": "In Progress",
10
+ "READ": "Read",
11
+ "UNREAD": "Unread",
12
+ },
13
+ )
14
+ BROWSER_ORDER_BY_CHOICES = MappingProxyType(
15
+ {
16
+ "age_rating": "Age Rating",
17
+ "bookmark_updated_at": "Last Read",
18
+ "community_rating": "Community Rating",
19
+ "created_at": "Added Time",
20
+ "critical_rating": "Critical Rating",
21
+ "date": "Publish Date",
22
+ "filename": "Filename",
23
+ "page_count": "Page Count",
24
+ "search_score": "Search Score",
25
+ "size": "File Size",
26
+ "sort_name": "Name",
27
+ "story_arc_number": "Story Arc Number",
28
+ "updated_at": "Updated Time",
29
+ }
30
+ )
31
+ _GROUP_NAMES = {
32
+ "p": "Publishers",
33
+ "i": "Imprints",
34
+ "s": "Series",
35
+ "v": "Volumes",
36
+ }
37
+ BROWSER_TOP_GROUP_CHOICES = MappingProxyType(
38
+ {
39
+ **_GROUP_NAMES,
40
+ "c": "Issues",
41
+ "f": "Folders",
42
+ "a": "Story Arcs",
43
+ },
44
+ )
45
+ VUETIFY_NULL_CODE = -1
46
+ BROWSER_CHOICES = MappingProxyType(
47
+ {
48
+ "bookmark_filter": BROWSER_BOOKMARK_FILTER_CHOICES,
49
+ "order_by": BROWSER_ORDER_BY_CHOICES,
50
+ "top_group": BROWSER_TOP_GROUP_CHOICES,
51
+ "vuetify_null_code": VUETIFY_NULL_CODE,
52
+ "settings_group": {**_GROUP_NAMES},
53
+ "identifier_types": {
54
+ "comicvine": "Comic Vine",
55
+ "comixology": "Comixology",
56
+ "asin": "Amazon",
57
+ "gtin": "GTIN",
58
+ "isbn": "ISBN",
59
+ "upc": "UPC",
60
+ },
61
+ }
62
+ )
63
+
64
+ READER_CHOICES = MappingProxyType(
65
+ {
66
+ "fit_to": MappingProxyType(
67
+ {
68
+ "H": "Fit to Height",
69
+ "O": "Original Size",
70
+ "S": "Fit to Screen",
71
+ "W": "Fit to Width",
72
+ }
73
+ ),
74
+ "reading_direction": MappingProxyType(
75
+ {
76
+ "btt": "Bottom to Top",
77
+ "ltr": "Left to Right",
78
+ "rtl": "Right to Left",
79
+ "ttb": "Top to Bottom",
80
+ }
81
+ ),
82
+ }
83
+ )
84
+ DEFAULT_BROWSER_ROUTE = MappingProxyType({"group": "r", "pks": (0,), "page": 1})
85
+ _DEFAULT_BROWSER_BREADCRUMBS = (DEFAULT_BROWSER_ROUTE,)
86
+ _DEFAULT_SHOW = MappingProxyType({"i": False, "p": True, "s": True, "v": False})
87
+ BROWSER_DEFAULTS = MappingProxyType(
88
+ {
89
+ "bookmark_filter": "",
90
+ "breadcrumbs": _DEFAULT_BROWSER_BREADCRUMBS,
91
+ "custom_covers": True,
92
+ "dynamic_covers": True,
93
+ "order_by": "sort_name",
94
+ "order_reverse": False,
95
+ "q": "",
96
+ # "search_results_limit": 100,
97
+ "show": _DEFAULT_SHOW,
98
+ "top_group": "p",
99
+ "twenty_four_hour_time": False,
100
+ }
101
+ )
102
+ READER_DEFAULTS = MappingProxyType(
103
+ {
104
+ "finish_on_last_page": True,
105
+ "fit_to": "S",
106
+ "reading_direction": "ltr",
107
+ "read_rtl_in_reverse": False,
108
+ "two_pages": False,
109
+ }
110
+ )
111
+
112
+ ADMIN_FLAG_CHOICES = MappingProxyType(
113
+ {
114
+ "AU": "Auto Update",
115
+ "FV": "Folder View",
116
+ "IM": "Import Metadata on Library Scan",
117
+ "NU": "Non Users",
118
+ "RG": "Registration",
119
+ "ST": "Send Stats",
120
+ }
121
+ )
122
+
123
+ ADMIN_STATUS_TITLES = MappingProxyType(
124
+ {
125
+ "CCC": "Create Covers",
126
+ "CCD": "Remove Covers",
127
+ "CFO": "Find Orphan Covers",
128
+ "IAF": "Adopt Orphan Folders",
129
+ "ICC": "Create Custom Covers",
130
+ "ICD": "Delete Custom Covers",
131
+ "ICL": "Link Custom Covers",
132
+ "ICM": "Custom Covers Moved",
133
+ "ICQ": "Discover Missing Custom Covers",
134
+ "ICU": "Modify Custom Covers",
135
+ "IDD": "Remove Folders",
136
+ "IDM": "Move Folders",
137
+ "IDU": "Modify Folders",
138
+ "IFC": "Create Books",
139
+ "IFD": "Remove Books",
140
+ "IFI": "Record Failed Imports",
141
+ "IFM": "Move Books",
142
+ "IFU": "Modify Books",
143
+ "IGU": "Update First Covers",
144
+ "IMC": "Link Books to Tags",
145
+ "IMQ": "Prepare Tags for Linking",
146
+ "ITC": "Create Missing Tags",
147
+ "ITQ": "Discover Missing Tags",
148
+ "ITR": "Read Book Tags",
149
+ "JCB": "Cleanup Orphan Bookmarks",
150
+ "JCD": "Cleanup Custom Covers",
151
+ "JCR": "Restart Codex",
152
+ "JCS": "Stop Codex",
153
+ "JCU": "Update Codex Software",
154
+ "JDB": "Backup Database",
155
+ "JDO": "Optimize Database",
156
+ "JFC": "Search Index Integrity Check",
157
+ "JFR": "Search Index Repair",
158
+ "JIC": "Database Integrity Check",
159
+ "JIF": "Database Foreign Key Check",
160
+ "JLV": "Check Codex Latest Version",
161
+ "JSD": "Cleanup Expired Sessions",
162
+ "JTD": "Cleanup Stale Tags",
163
+ "SIC": "Search Index Create",
164
+ "SID": "Search Index Remove Stale Records",
165
+ "SIO": "Search Index Optimize",
166
+ "SIU": "Search Index Update",
167
+ "SIX": "Search Index Clear",
168
+ "WPO": "Poll Library",
169
+ }
170
+ )
171
+
172
+ # Easier to store in vuetify format
173
+ ADMIN_TASK_GROUPS = MappingProxyType(
174
+ {
175
+ "tasks": (
176
+ {
177
+ "title": "Libraries",
178
+ "tasks": (
179
+ {
180
+ "value": "poll",
181
+ "title": "Poll All Libraries",
182
+ "desc": "Update Libraries if changes detected",
183
+ },
184
+ {
185
+ "value": "poll_force",
186
+ "title": "Force Update All Libraries",
187
+ "desc": "Forcibly update all comics in all libraries",
188
+ "confirm": "This can take a long time",
189
+ },
190
+ {
191
+ "value": "force_update_all_failed_imports",
192
+ "title": "Update All Failed Imports",
193
+ "desc": "Forcibly update all failed imports in all libraries",
194
+ "confirm": "This can take a long time",
195
+ },
196
+ {
197
+ "value": "watchdog_sync",
198
+ "title": "Sync Watchdog with DB",
199
+ "desc": "Ensure the Watchdog file watcher is enabled per database preferences for each library",
200
+ },
201
+ ),
202
+ },
203
+ {
204
+ "title": "Covers",
205
+ "tasks": (
206
+ {
207
+ "value": "purge_comic_covers",
208
+ "title": "Remove Comic Covers",
209
+ "desc": "from every library",
210
+ "confirm": "Are you sure?",
211
+ },
212
+ {
213
+ "value": "create_all_comic_covers",
214
+ "title": "Create All Comic Covers",
215
+ "desc": "Pre-generate covers for every comic in every library and all custom covers",
216
+ "confirm": "Are you sure?",
217
+ },
218
+ {
219
+ "value": "force_update_groups",
220
+ "title": "Update Group Timestamps",
221
+ "desc": "Force the update of group timestamps. Will bust the browser cache for browser views and covers.",
222
+ },
223
+ ),
224
+ },
225
+ {
226
+ "title": "Search Index",
227
+ "tasks": (
228
+ {
229
+ "value": "search_index_update",
230
+ "title": "Update Search Index",
231
+ "desc": "with recently changed comics",
232
+ },
233
+ {
234
+ "value": "search_index_rebuild",
235
+ "title": "Rebuild Search Index",
236
+ "desc": "Delete and rebuild the search index from scratch",
237
+ "confirm": "This can take a long time",
238
+ },
239
+ {
240
+ "value": "search_index_remove_stale",
241
+ "title": "Remove Stale Index Entries",
242
+ "desc": "Remove search index entries that are no longer in the library.",
243
+ },
244
+ {
245
+ "value": "search_index_merge_small",
246
+ "title": "Merge Small Search Index Segments",
247
+ "desc": "Improves search lookup times. Runs nightly if the Optimize Admin Flag is off.",
248
+ },
249
+ {
250
+ "value": "search_index_optimize",
251
+ "title": "Merge Search Index Into One Segment",
252
+ "desc": "Reduces disk space and improves search lookup times. Runs nightly if the Optimize Admin Flag is on.",
253
+ "confirm": "This can take a long time.",
254
+ },
255
+ {
256
+ "value": "search_index_abort",
257
+ "title": "Abort Search Indexing",
258
+ "desc": "Aborts search index update and remove tasks.",
259
+ },
260
+ {
261
+ "value": "search_index_clear",
262
+ "title": "Clear Search Index",
263
+ "desc": "of all entries",
264
+ },
265
+ ),
266
+ },
267
+ {
268
+ "title": "Database",
269
+ "tasks": (
270
+ {
271
+ "value": "db_vacuum",
272
+ "title": "Optimize & Compact Database",
273
+ "desc": "Run the sqlite3 OPTIMIZE and VACUUM pragmas. Runs nightly",
274
+ },
275
+ {
276
+ "value": "db_backup",
277
+ "title": "Backup Database",
278
+ "desc": "Runs nightly",
279
+ },
280
+ {
281
+ "value": "db_search_sync",
282
+ "title": "Sync Search Index to DB",
283
+ "desc": "Check to see if this database matches the current search index. If there is a mismatch, rebuild the search index. Runs on startup.",
284
+ },
285
+ ),
286
+ },
287
+ {
288
+ "title": "Codex Software",
289
+ "tasks": (
290
+ {
291
+ "value": "codex_latest_version",
292
+ "title": "Check for Codex Latest Version",
293
+ "desc": "Check PyPi for the latest version of Codex",
294
+ },
295
+ {
296
+ "value": "codex_update",
297
+ "title": "Update Codex",
298
+ "desc": "If Codex updates to a new version, it will restart",
299
+ "confirm": "Are you sure?",
300
+ },
301
+ {
302
+ "value": "codex_restart",
303
+ "title": "Restart Codex Server",
304
+ "desc": "Immediately",
305
+ "confirm": "Are you sure?",
306
+ },
307
+ {
308
+ "value": "codex_shutdown",
309
+ "title": "Shutdown Codex Server",
310
+ "desc": "Immediately",
311
+ "confirm": "Are you sure?",
312
+ },
313
+ ),
314
+ },
315
+ {
316
+ "title": "Notify",
317
+ "tasks": (
318
+ {
319
+ "value": "notify_library_changed",
320
+ "title": "Notify Library Changed ",
321
+ "desc": "Signal all clients that the libraries have changed and the browser should fetch new data.",
322
+ },
323
+ {
324
+ "value": "notify_librarian_status",
325
+ "title": "Notify Librarian Status",
326
+ "desc": "Signal Admin clients to fetch librarian status.",
327
+ },
328
+ ),
329
+ },
330
+ {
331
+ "title": "Cleanup",
332
+ "tasks": (
333
+ {
334
+ "value": "cleanup_fks",
335
+ "title": "Remove Orphan Tags",
336
+ "desc": "After deleting comics, unused linked objects remain in case new comics use them. Runs nightly.",
337
+ },
338
+ {
339
+ "value": "cleanup_db_custom_covers",
340
+ "title": "Remove Orphan Database Custom Covers",
341
+ "desc": "Remove Custom Covers from the db that no longer represent custom cover images on disk. Runs nightly.",
342
+ },
343
+ {
344
+ "value": "cleanup_sessions",
345
+ "title": "Cleanup Sessions",
346
+ "desc": "Remove corrupt and expired sessions. Runs nightly.",
347
+ },
348
+ {
349
+ "value": "cleanup_covers",
350
+ "title": "Remove Orphan Cover Thumbnails",
351
+ "desc": "no longer have source comics or custom images. Runs nightly.",
352
+ },
353
+ {
354
+ "value": "adopt_folders",
355
+ "title": "Adopt Orphan Folders",
356
+ "desc": "Move orphaned folders from the top of the folder tree to under their correct parent. Runs nightly and at startup.",
357
+ },
358
+ {
359
+ "value": "librarian_clear_status",
360
+ "title": "Clear Librarian Statuses",
361
+ "desc": "Mark all Librarian tasks finished.",
362
+ },
363
+ {
364
+ "value": "janitor_nightly",
365
+ "title": "Run Nightly Maintenance",
366
+ "desc": "Runs several tasks above that also run nightly.",
367
+ "confirm": "Launches several tasks that run nightly anyway.",
368
+ },
369
+ ),
370
+ },
371
+ )
372
+ }
373
+ )
374
+
375
+
376
+ def _group_task_values(groups):
377
+ """Extract values into sorted tuple."""
378
+ values = []
379
+ for group in groups["tasks"]:
380
+ for item in group["tasks"]:
381
+ values.append(item["value"])
382
+ return tuple(sorted(values))
383
+
384
+
385
+ ADMIN_TASKS = _group_task_values(ADMIN_TASK_GROUPS)
386
+ WEBSOCKET_MESSAGES = MappingProxyType(
387
+ {
388
+ "messages": {
389
+ "FAILED_IMPORTS": "FAILED_IMPORTS",
390
+ "LIBRARY_CHANGED": "LIBRARY_CHANGED",
391
+ "LIBRARIAN_STATUS": "LIBRARIAN_STATUS",
392
+ }
393
+ }
394
+ )
395
+ DUMMY_NULL_NAME = "_none_"
396
+
397
+
398
+ def mapping_to_dict(data):
399
+ """Convert nested Mapping objects to dicts."""
400
+ if isinstance(data, Mapping):
401
+ return {key: mapping_to_dict(value) for key, value in data.items()}
402
+ if isinstance(data, list | tuple | frozenset | set):
403
+ return [mapping_to_dict(item) for item in data]
404
+ return data
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env python3
2
+ """Dump choices to JSON."""
3
+
4
+ import json
5
+ from collections.abc import Mapping
6
+ from pathlib import Path
7
+ from types import MappingProxyType
8
+
9
+ from caseconverter import camelcase
10
+
11
+ from codex.choices import (
12
+ ADMIN_FLAG_CHOICES,
13
+ ADMIN_STATUS_TITLES,
14
+ ADMIN_TASK_GROUPS,
15
+ BROWSER_CHOICES,
16
+ BROWSER_DEFAULTS,
17
+ READER_CHOICES,
18
+ READER_DEFAULTS,
19
+ WEBSOCKET_MESSAGES,
20
+ )
21
+
22
+ _DEFAULTS = MappingProxyType(
23
+ {"browser-choices.json": BROWSER_DEFAULTS, "reader-choices.json": READER_DEFAULTS}
24
+ )
25
+
26
+ _DUMPS = MappingProxyType(
27
+ {
28
+ "admin-flag-choices.json": ADMIN_FLAG_CHOICES,
29
+ "admin-status-titles.json": ADMIN_STATUS_TITLES,
30
+ "browser-choices.json": BROWSER_CHOICES,
31
+ "reader-choices.json": READER_CHOICES,
32
+ }
33
+ )
34
+
35
+ _MAP_DUMPS = MappingProxyType(
36
+ {
37
+ "admin-tasks.json": ADMIN_TASK_GROUPS,
38
+ "browser-defaults.json": BROWSER_DEFAULTS,
39
+ "browser-map.json": BROWSER_CHOICES,
40
+ "reader-map.json": READER_CHOICES,
41
+ "websocket-messages.json": WEBSOCKET_MESSAGES,
42
+ }
43
+ )
44
+
45
+
46
+ def _to_vuetify_choices(defaults, key, obj_map):
47
+ """Transform a dict into a list of vuetify choices."""
48
+ default = defaults.get(key)
49
+ vuetify_list = []
50
+ for value, title in obj_map.items():
51
+ vuetify_dict = {
52
+ "value": value,
53
+ "title": title,
54
+ }
55
+ if default == value:
56
+ vuetify_dict["default"] = True
57
+ vuetify_list.append(vuetify_dict)
58
+ return vuetify_list
59
+
60
+
61
+ def _json_key(key):
62
+ """Transform key to json version."""
63
+ return key if key.upper() == key else camelcase(key)
64
+
65
+
66
+ def _make_json_serializable(data):
67
+ """Convert nested Mapping objects to dicts."""
68
+ if isinstance(data, Mapping):
69
+ json_dict = {}
70
+ for key, value in data.items():
71
+ if key == "pks":
72
+ # Special route serializer
73
+ # XXX possibly should use actual route serializer for route not just pks
74
+ json_dict[key] = ",".join(str(pk) for pk in sorted(value))
75
+ else:
76
+ json_dict[_json_key(key)] = _make_json_serializable(value)
77
+ return json_dict
78
+ if isinstance(data, list | tuple | frozenset | set):
79
+ return [_make_json_serializable(item) for item in data]
80
+ return data
81
+
82
+
83
+ def _to_vuetify_dict(fn, data):
84
+ """Convert mappings to vuetify dict list."""
85
+ vuetify_data = {}
86
+ defaults = _DEFAULTS.get(fn) or {}
87
+ for key, obj in data.items():
88
+ if isinstance(obj, Mapping):
89
+ vuetify_value = _to_vuetify_choices(defaults, key, obj)
90
+ else:
91
+ vuetify_value = _make_json_serializable(obj)
92
+ vuetify_data[_json_key(key)] = vuetify_value
93
+ return vuetify_data
94
+
95
+
96
+ def _dump(parent_path, fn, data, vuetify=True):
97
+ """Dump data to json file."""
98
+ vuetify_data = (
99
+ _to_vuetify_dict(fn, data) if vuetify else _make_json_serializable(data)
100
+ )
101
+ path = parent_path / Path(fn)
102
+ with path.open("w") as json_file:
103
+ json.dump(vuetify_data, json_file, indent=2)
104
+ json_file.write("\n")
105
+
106
+
107
+ def main():
108
+ """Dump all files."""
109
+ import sys
110
+
111
+ parent_path = sys.argv[1] if len(sys.argv) > 1 else "."
112
+ parent_path = Path(parent_path)
113
+ parent_path.mkdir(exist_ok=True)
114
+ for fn, data in _DUMPS.items():
115
+ _dump(parent_path, fn, data)
116
+
117
+ for fn, data in _MAP_DUMPS.items():
118
+ _dump(parent_path, fn, data, False)
119
+
120
+
121
+ if __name__ == "__main__":
122
+ main()
codex/db.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Low level database utilities."""
2
2
 
3
- import re
4
3
  import sqlite3
4
+ import subprocess
5
5
 
6
6
  from django.core.management import call_command
7
7
  from django.db import DEFAULT_DB_ALIAS, connection, connections
@@ -29,9 +29,9 @@ from codex.settings.settings import (
29
29
  )
30
30
  from codex.version import VERSION
31
31
 
32
- REPAIR_FLAG_PATH = CONFIG_PATH / "rebuild_db"
33
- DUMP_LINE_MATCHER = re.compile("TRANSACTION|ROLLBACK|COMMIT")
34
- REBUILT_DB_PATH = DB_PATH.parent / (DB_PATH.name + ".rebuilt")
32
+ _REPAIR_FLAG_PATH = CONFIG_PATH / "rebuild_db"
33
+ _REBUILT_DB_PATH = DB_PATH.parent / (DB_PATH.name + ".rebuilt")
34
+ _REPAIR_ARGS = ("sqlite3", DB_PATH, ".recover")
35
35
 
36
36
  LOG = get_logger(__name__)
37
37
 
@@ -82,24 +82,38 @@ def _repair_db():
82
82
  def _rebuild_db():
83
83
  """Dump and rebuild the database."""
84
84
  # Drastic
85
- if not REPAIR_FLAG_PATH.exists():
86
- return
85
+ if not _REPAIR_FLAG_PATH.exists():
86
+ return False
87
87
 
88
88
  LOG.warning("REBUILDING DATABASE!!")
89
- REPAIR_FLAG_PATH.unlink(missing_ok=True)
90
- with sqlite3.connect(REBUILT_DB_PATH) as new_db_conn:
89
+ _REBUILT_DB_PATH.unlink(missing_ok=True)
90
+ recover_proc = subprocess.Popen(_REPAIR_ARGS, stdout=subprocess.PIPE) # noqa: S603
91
+ with sqlite3.connect(_REBUILT_DB_PATH) as new_db_conn:
91
92
  new_db_cur = new_db_conn.cursor()
92
- with sqlite3.connect(DB_PATH) as old_db_conn:
93
- for line in old_db_conn.iterdump():
94
- if DUMP_LINE_MATCHER.search(line):
95
- continue
96
- new_db_cur.execute(line)
93
+ if recover_proc.stdout:
94
+ for line in recover_proc.stdout:
95
+ row = line.decode().strip()
96
+ replaced_row = (
97
+ "PRAGMA writable_schema = reset;"
98
+ if row == "PRAGMA writable_schema = off;"
99
+ else row
100
+ )
101
+ new_db_cur.execute(replaced_row)
102
+ new_db_cur.close()
103
+ if recover_proc.stdout:
104
+ recover_proc.stdout.close()
105
+ recover_proc.wait(timeout=15)
97
106
 
98
107
  backup_path = _get_backup_db_path("before-rebuild")
99
108
  DB_PATH.rename(backup_path)
100
109
  LOG.info("Backed up old db to %s", backup_path)
101
- REBUILT_DB_PATH.replace(DB_PATH)
110
+ _REBUILT_DB_PATH.replace(DB_PATH)
111
+ _REPAIR_FLAG_PATH.unlink(missing_ok=True)
102
112
  LOG.info("Rebuilt database.")
113
+ LOG.info("You may start codex normally now.")
114
+ for handler in LOG.handlers:
115
+ handler.flush()
116
+ return True
103
117
 
104
118
 
105
119
  def ensure_db_schema():
@@ -107,7 +121,8 @@ def ensure_db_schema():
107
121
  LOG.info("Ensuring database is correct and up to date...")
108
122
  table_names = connection.introspection.table_names()
109
123
  if db_exists := "django_migrations" in table_names:
110
- _rebuild_db()
124
+ if _rebuild_db():
125
+ return False
111
126
  _repair_db()
112
127
 
113
128
  if not db_exists or _has_unapplied_migrations():
@@ -117,3 +132,4 @@ def ensure_db_schema():
117
132
  else:
118
133
  LOG.info("Database up to date.")
119
134
  LOG.info("Database ready.")
135
+ return True
codex/exceptions.py CHANGED
@@ -11,8 +11,8 @@ from django.utils.http import urlencode
11
11
  from rest_framework.exceptions import APIException
12
12
  from rest_framework.status import HTTP_303_SEE_OTHER
13
13
 
14
+ from codex.choices import DEFAULT_BROWSER_ROUTE
14
15
  from codex.logger.logging import get_logger
15
- from codex.serializers.choices import DEFAULTS
16
16
  from codex.serializers.fields import BreadcrumbsField
17
17
  from codex.serializers.route import RouteSerializer
18
18
  from codex.views.util import pop_name
@@ -24,7 +24,6 @@ if TYPE_CHECKING:
24
24
  LOG = get_logger(__name__)
25
25
  _OPDS_REDIRECT_SETTINGS_KEYS = ("order_by", "top_group")
26
26
  _REDIRECT_SETTINGS_KEYS = ("breadcrumbs", *_OPDS_REDIRECT_SETTINGS_KEYS)
27
- _DEFAULT_ROUTE = DEFAULTS["breadcrumbs"][0]
28
27
 
29
28
 
30
29
  class SeeOtherRedirectError(APIException):
@@ -41,7 +40,7 @@ class SeeOtherRedirectError(APIException):
41
40
 
42
41
  # Get route params
43
42
  route = detail.get("route", {})
44
- params = route.get("params", _DEFAULT_ROUTE)
43
+ params = route.get("params", DEFAULT_BROWSER_ROUTE)
45
44
  params = pop_name(params)
46
45
  route = deepcopy(route)
47
46
  route["params"] = params
@@ -0,0 +1 @@
1
+ """Bookmark Thread."""
@@ -0,0 +1,38 @@
1
+ """Sends notifications to connections, reading from a queue."""
2
+
3
+ from codex.librarian.bookmark.tasks import BookmarkUpdateTask
4
+ from codex.librarian.bookmark.update import BookmarkUpdate
5
+ from codex.threads import AggregateMessageQueuedThread
6
+
7
+
8
+ class BookmarkThread(AggregateMessageQueuedThread, BookmarkUpdate):
9
+ """Aggregates Bookmark updates preventing floods updates db in batches.."""
10
+
11
+ FLOOD_DELAY = 3.0
12
+ MAX_DELAY = 5.0
13
+
14
+ def aggregate_items(self, item):
15
+ """Aggregate bookmark updates."""
16
+ if isinstance(item, BookmarkUpdateTask):
17
+ key = (tuple(item.auth_filter.items()), tuple(item.comic_filter.items()))
18
+ if key not in self.cache:
19
+ self.cache[key] = {}
20
+ self.cache[key].update(item.updates)
21
+ else:
22
+ self.log.warning(f"Unknown Bookmark task {item}")
23
+
24
+ def send_all_items(self):
25
+ """Run the task method."""
26
+ cleanup = set()
27
+ for filters, updates in self.cache.items():
28
+ try:
29
+ auth_filter, comic_filter = filters
30
+ auth_filter = dict(auth_filter)
31
+ comic_filter = dict(comic_filter)
32
+ self.update_bookmarks(auth_filter, comic_filter, updates)
33
+ self.log.debug(f"updated {auth_filter | comic_filter}")
34
+ cleanup.add(filters)
35
+ except Exception:
36
+ self.log.exception("Updating bookmarks")
37
+
38
+ self.cleanup_cache(cleanup)