codex 1.8.0a2__py3-none-any.whl → 1.8.0a3__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 (477) hide show
  1. codex/choices/admin.py +4 -4
  2. codex/choices/statii.py +1 -1
  3. codex/librarian/covers/status.py +1 -1
  4. codex/librarian/librariand.py +2 -0
  5. codex/librarian/scribe/importer/const.py +8 -0
  6. codex/librarian/scribe/importer/create/foreign_keys.py +1 -1
  7. codex/librarian/scribe/importer/delete/covers.py +3 -1
  8. codex/librarian/scribe/importer/failed/__init__.py +1 -0
  9. codex/librarian/scribe/importer/failed/create.py +97 -0
  10. codex/librarian/scribe/importer/failed/failed.py +54 -0
  11. codex/librarian/scribe/importer/failed/query.py +100 -0
  12. codex/librarian/scribe/importer/init.py +2 -2
  13. codex/librarian/scribe/importer/link/covers.py +1 -1
  14. codex/librarian/scribe/importer/read/aggregate_path.py +4 -2
  15. codex/librarian/scribe/importer/search/__init__.py +1 -1
  16. codex/librarian/scribe/importer/search/update.py +20 -9
  17. codex/librarian/scribe/importer/statii/__init__.py +2 -0
  18. codex/librarian/scribe/importer/statii/failed.py +50 -0
  19. codex/librarian/scribe/importer/status.py +0 -12
  20. codex/librarian/scribe/janitor/janitor.py +13 -5
  21. codex/librarian/scribe/janitor/status.py +3 -2
  22. codex/librarian/scribe/search/optimize.py +1 -2
  23. codex/librarian/scribe/search/remove.py +2 -2
  24. codex/librarian/scribe/search/status.py +8 -8
  25. codex/librarian/scribe/search/sync.py +10 -3
  26. codex/librarian/scribe/status.py +2 -1
  27. codex/librarian/status.py +5 -5
  28. codex/librarian/status_controller.py +41 -20
  29. codex/librarian/watchdog/const.py +30 -1
  30. codex/librarian/watchdog/emitter.py +26 -34
  31. codex/librarian/watchdog/event_batcherd.py +18 -14
  32. codex/librarian/watchdog/observers.py +11 -15
  33. codex/migrations/0035_alter_librarianstatus_status_type.py +72 -0
  34. codex/startup/__init__.py +1 -1
  35. codex/static_root/assets/{VCheckbox-DSndl51k.1e28c443c3cb.js → VCheckbox-DOvv8UEO.e3653c1670c8.js} +1 -1
  36. codex/static_root/assets/VCheckbox-DOvv8UEO.e3653c1670c8.js.br +0 -0
  37. codex/static_root/assets/VCheckbox-DOvv8UEO.e3653c1670c8.js.gz +0 -0
  38. codex/static_root/assets/{VCheckbox-DSndl51k.js → VCheckbox-DOvv8UEO.js} +1 -1
  39. codex/static_root/assets/VCheckbox-DOvv8UEO.js.br +0 -0
  40. codex/static_root/assets/VCheckbox-DOvv8UEO.js.gz +0 -0
  41. codex/static_root/assets/{VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js → VCheckboxBtn-BeZZDumo.59731a32657e.js} +1 -1
  42. codex/static_root/assets/VCheckboxBtn-BeZZDumo.59731a32657e.js.br +0 -0
  43. codex/static_root/assets/VCheckboxBtn-BeZZDumo.59731a32657e.js.gz +0 -0
  44. codex/static_root/assets/{VCheckboxBtn-Bu2Pf64q.js → VCheckboxBtn-BeZZDumo.js} +1 -1
  45. codex/static_root/assets/VCheckboxBtn-BeZZDumo.js.br +0 -0
  46. codex/static_root/assets/VCheckboxBtn-BeZZDumo.js.gz +0 -0
  47. codex/static_root/assets/{VCombobox-Uogv6Ckp.9f900e703605.js → VCombobox-BRJRW2px.369544360b22.js} +1 -1
  48. codex/static_root/assets/VCombobox-BRJRW2px.369544360b22.js.br +0 -0
  49. codex/static_root/assets/VCombobox-BRJRW2px.369544360b22.js.gz +0 -0
  50. codex/static_root/assets/{VCombobox-Uogv6Ckp.js → VCombobox-BRJRW2px.js} +1 -1
  51. codex/static_root/assets/VCombobox-BRJRW2px.js.br +0 -0
  52. codex/static_root/assets/VCombobox-BRJRW2px.js.gz +0 -0
  53. codex/static_root/assets/{VDialog-BzaGu1HN.34f52763c3f8.js → VDialog-D_vkvatj.83e078fa850c.js} +1 -1
  54. codex/static_root/assets/VDialog-D_vkvatj.83e078fa850c.js.br +0 -0
  55. codex/static_root/assets/VDialog-D_vkvatj.83e078fa850c.js.gz +0 -0
  56. codex/static_root/assets/{VDialog-BzaGu1HN.js → VDialog-D_vkvatj.js} +1 -1
  57. codex/static_root/assets/VDialog-D_vkvatj.js.br +0 -0
  58. codex/static_root/assets/VDialog-D_vkvatj.js.gz +0 -0
  59. codex/static_root/assets/{VDivider-C3ikm0Ko.4938e9ced53e.js → VDivider-BH2Oj58Z.83d2c907faff.js} +1 -1
  60. codex/static_root/assets/VDivider-BH2Oj58Z.83d2c907faff.js.br +0 -0
  61. codex/static_root/assets/VDivider-BH2Oj58Z.83d2c907faff.js.gz +0 -0
  62. codex/static_root/assets/{VDivider-C3ikm0Ko.js → VDivider-BH2Oj58Z.js} +1 -1
  63. codex/static_root/assets/VDivider-BH2Oj58Z.js.br +0 -0
  64. codex/static_root/assets/VDivider-BH2Oj58Z.js.gz +0 -0
  65. codex/static_root/assets/{VExpansionPanels-AmsInZN0.5cb7c833de3d.js → VExpansionPanels-Ccv4gBFD.ed063db2e518.js} +1 -1
  66. codex/static_root/assets/VExpansionPanels-Ccv4gBFD.ed063db2e518.js.br +0 -0
  67. codex/static_root/assets/VExpansionPanels-Ccv4gBFD.ed063db2e518.js.gz +0 -0
  68. codex/static_root/assets/{VExpansionPanels-AmsInZN0.js → VExpansionPanels-Ccv4gBFD.js} +1 -1
  69. codex/static_root/assets/VExpansionPanels-Ccv4gBFD.js.br +0 -0
  70. codex/static_root/assets/VExpansionPanels-Ccv4gBFD.js.gz +0 -0
  71. codex/static_root/assets/{VForm-CyCdgusw.c737973a1e85.js → VForm-S5eiHGJ0.d304a07dc6d1.js} +1 -1
  72. codex/static_root/assets/VForm-S5eiHGJ0.d304a07dc6d1.js.br +0 -0
  73. codex/static_root/assets/VForm-S5eiHGJ0.d304a07dc6d1.js.gz +0 -0
  74. codex/static_root/assets/{VForm-CyCdgusw.js → VForm-S5eiHGJ0.js} +1 -1
  75. codex/static_root/assets/VForm-S5eiHGJ0.js.br +0 -0
  76. codex/static_root/assets/VForm-S5eiHGJ0.js.gz +0 -0
  77. codex/static_root/assets/{VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js → VRadioGroup-CyCYk3Z_.4309dbf0173c.js} +1 -1
  78. codex/static_root/assets/VRadioGroup-CyCYk3Z_.4309dbf0173c.js.br +0 -0
  79. codex/static_root/assets/VRadioGroup-CyCYk3Z_.4309dbf0173c.js.gz +0 -0
  80. codex/static_root/assets/{VRadioGroup-BF0Xjrzi.js → VRadioGroup-CyCYk3Z_.js} +1 -1
  81. codex/static_root/assets/VRadioGroup-CyCYk3Z_.js.br +0 -0
  82. codex/static_root/assets/VRadioGroup-CyCYk3Z_.js.gz +0 -0
  83. codex/static_root/assets/{VSelect-Dv50OIkN.js → VSelect-BOhtkCV1.057479737b7f.js} +1 -1
  84. codex/static_root/assets/VSelect-BOhtkCV1.057479737b7f.js.br +0 -0
  85. codex/static_root/assets/VSelect-BOhtkCV1.057479737b7f.js.gz +0 -0
  86. codex/static_root/assets/{VSelect-Dv50OIkN.390adb1fe7fa.js → VSelect-BOhtkCV1.js} +1 -1
  87. codex/static_root/assets/VSelect-BOhtkCV1.js.br +0 -0
  88. codex/static_root/assets/VSelect-BOhtkCV1.js.gz +0 -0
  89. codex/static_root/assets/{VSelectionControl-DbKYScD5.js → VSelectionControl-CmXEFw20.e256f0d0f97d.js} +1 -1
  90. codex/static_root/assets/VSelectionControl-CmXEFw20.e256f0d0f97d.js.br +0 -0
  91. codex/static_root/assets/VSelectionControl-CmXEFw20.e256f0d0f97d.js.gz +0 -0
  92. codex/static_root/assets/{VSelectionControl-DbKYScD5.8d2ab1ebe546.js → VSelectionControl-CmXEFw20.js} +1 -1
  93. codex/static_root/assets/VSelectionControl-CmXEFw20.js.br +0 -0
  94. codex/static_root/assets/VSelectionControl-CmXEFw20.js.gz +0 -0
  95. codex/static_root/assets/{VTable-BmOfHc7J.b2e1311009d1.js → VTable-BDxzw_rH.24ce227e6076.js} +1 -1
  96. codex/static_root/assets/VTable-BDxzw_rH.24ce227e6076.js.br +0 -0
  97. codex/static_root/assets/VTable-BDxzw_rH.24ce227e6076.js.gz +0 -0
  98. codex/static_root/assets/{VTable-BmOfHc7J.js → VTable-BDxzw_rH.js} +1 -1
  99. codex/static_root/assets/VTable-BDxzw_rH.js.br +0 -0
  100. codex/static_root/assets/VTable-BDxzw_rH.js.gz +0 -0
  101. codex/static_root/assets/{VWindowItem-BLEDgagD.4b67c4a63c59.js → VWindowItem-CuDwxsEy.4d68002250ae.js} +1 -1
  102. codex/static_root/assets/VWindowItem-CuDwxsEy.4d68002250ae.js.br +0 -0
  103. codex/static_root/assets/VWindowItem-CuDwxsEy.4d68002250ae.js.gz +0 -0
  104. codex/static_root/assets/{VWindowItem-BLEDgagD.js → VWindowItem-CuDwxsEy.js} +1 -1
  105. codex/static_root/assets/VWindowItem-CuDwxsEy.js.br +0 -0
  106. codex/static_root/assets/VWindowItem-CuDwxsEy.js.gz +0 -0
  107. codex/static_root/assets/{admin-kjMoKlqD.55a1dd908124.js → admin-BZQmoFts.d8e6303f8aee.js} +1 -1
  108. codex/static_root/assets/admin-BZQmoFts.d8e6303f8aee.js.br +0 -0
  109. codex/static_root/assets/admin-BZQmoFts.d8e6303f8aee.js.gz +0 -0
  110. codex/static_root/assets/{admin-kjMoKlqD.js → admin-BZQmoFts.js} +1 -1
  111. codex/static_root/assets/admin-BZQmoFts.js.br +0 -0
  112. codex/static_root/assets/admin-BZQmoFts.js.gz +0 -0
  113. codex/static_root/assets/{admin-Bv40vYZw.8179e1ece835.js → admin-U3AawSbo.f171316d0a93.js} +1 -1
  114. codex/static_root/assets/admin-U3AawSbo.f171316d0a93.js.br +0 -0
  115. codex/static_root/assets/admin-U3AawSbo.f171316d0a93.js.gz +0 -0
  116. codex/static_root/assets/{admin-Bv40vYZw.js → admin-U3AawSbo.js} +1 -1
  117. codex/static_root/assets/admin-U3AawSbo.js.br +0 -0
  118. codex/static_root/assets/admin-U3AawSbo.js.gz +0 -0
  119. codex/static_root/assets/admin-menu-D9RDVBlr.3b62ee7a8b95.js +1 -0
  120. codex/static_root/assets/admin-menu-D9RDVBlr.3b62ee7a8b95.js.br +0 -0
  121. codex/static_root/assets/admin-menu-D9RDVBlr.3b62ee7a8b95.js.gz +0 -0
  122. codex/static_root/assets/admin-menu-D9RDVBlr.js +1 -0
  123. codex/static_root/assets/admin-menu-D9RDVBlr.js.br +0 -0
  124. codex/static_root/assets/admin-menu-D9RDVBlr.js.gz +0 -0
  125. codex/static_root/assets/{admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js → admin-settings-button-progress-DwWq9uM1.fbacafc0db08.js} +1 -1
  126. codex/static_root/assets/admin-settings-button-progress-DwWq9uM1.fbacafc0db08.js.br +0 -0
  127. codex/static_root/assets/admin-settings-button-progress-DwWq9uM1.fbacafc0db08.js.gz +0 -0
  128. codex/static_root/assets/{admin-settings-button-progress-RfwaqLl2.js → admin-settings-button-progress-DwWq9uM1.js} +1 -1
  129. codex/static_root/assets/admin-settings-button-progress-DwWq9uM1.js.br +0 -0
  130. codex/static_root/assets/admin-settings-button-progress-DwWq9uM1.js.gz +0 -0
  131. codex/static_root/assets/{browser-plYso4v5.js → browser-DFM_JsAK.bffd4eb259d8.js} +1 -1
  132. codex/static_root/assets/browser-DFM_JsAK.bffd4eb259d8.js.br +0 -0
  133. codex/static_root/assets/browser-DFM_JsAK.bffd4eb259d8.js.gz +0 -0
  134. codex/static_root/assets/{browser-plYso4v5.87ef04b44d37.js → browser-DFM_JsAK.js} +1 -1
  135. codex/static_root/assets/browser-DFM_JsAK.js.br +0 -0
  136. codex/static_root/assets/browser-DFM_JsAK.js.gz +0 -0
  137. codex/static_root/assets/{change-password-dialog-DyhQwNv1.26383853ccc0.js → change-password-dialog-yLNkzMp9.50da9f352709.js} +1 -1
  138. codex/static_root/assets/change-password-dialog-yLNkzMp9.50da9f352709.js.br +0 -0
  139. codex/static_root/assets/change-password-dialog-yLNkzMp9.50da9f352709.js.gz +0 -0
  140. codex/static_root/assets/{change-password-dialog-DyhQwNv1.js → change-password-dialog-yLNkzMp9.js} +1 -1
  141. codex/static_root/assets/change-password-dialog-yLNkzMp9.js.br +0 -0
  142. codex/static_root/assets/change-password-dialog-yLNkzMp9.js.gz +0 -0
  143. codex/static_root/assets/{confirm-dialog-B7ndwV5M.d1f0728d4bd0.js → confirm-dialog-q6RAb_qs.120460c84883.js} +1 -1
  144. codex/static_root/assets/confirm-dialog-q6RAb_qs.120460c84883.js.br +0 -0
  145. codex/static_root/assets/confirm-dialog-q6RAb_qs.120460c84883.js.gz +0 -0
  146. codex/static_root/assets/{confirm-dialog-B7ndwV5M.js → confirm-dialog-q6RAb_qs.js} +1 -1
  147. codex/static_root/assets/confirm-dialog-q6RAb_qs.js.br +0 -0
  148. codex/static_root/assets/confirm-dialog-q6RAb_qs.js.gz +0 -0
  149. codex/static_root/assets/{datetime-column-DANpNGGe.13985ff7d484.js → datetime-column-HJ5dvW99.ba0a30b3fc0d.js} +1 -1
  150. codex/static_root/assets/datetime-column-HJ5dvW99.ba0a30b3fc0d.js.br +0 -0
  151. codex/static_root/assets/datetime-column-HJ5dvW99.ba0a30b3fc0d.js.gz +0 -0
  152. codex/static_root/assets/{datetime-column-DANpNGGe.js → datetime-column-HJ5dvW99.js} +1 -1
  153. codex/static_root/assets/datetime-column-HJ5dvW99.js.br +0 -0
  154. codex/static_root/assets/datetime-column-HJ5dvW99.js.gz +0 -0
  155. codex/static_root/assets/{filter-Dhe8cVmt.ad92d3b618e3.js → filter-r_zFj-tS.161a85ef1860.js} +1 -1
  156. codex/static_root/assets/filter-r_zFj-tS.161a85ef1860.js.br +0 -0
  157. codex/static_root/assets/filter-r_zFj-tS.161a85ef1860.js.gz +0 -0
  158. codex/static_root/assets/{filter-Dhe8cVmt.js → filter-r_zFj-tS.js} +1 -1
  159. codex/static_root/assets/filter-r_zFj-tS.js.br +0 -0
  160. codex/static_root/assets/filter-r_zFj-tS.js.gz +0 -0
  161. codex/static_root/assets/{flag-tab-BZ9S7U8D.0b814b215567.js → flag-tab-D0Z4uhsg.06e720e71319.js} +1 -1
  162. codex/static_root/assets/flag-tab-D0Z4uhsg.06e720e71319.js.br +0 -0
  163. codex/static_root/assets/flag-tab-D0Z4uhsg.06e720e71319.js.gz +0 -0
  164. codex/static_root/assets/{flag-tab-BZ9S7U8D.js → flag-tab-D0Z4uhsg.js} +1 -1
  165. codex/static_root/assets/flag-tab-D0Z4uhsg.js.br +0 -0
  166. codex/static_root/assets/flag-tab-D0Z4uhsg.js.gz +0 -0
  167. codex/static_root/assets/{forwardRefs-Z0d4Mnc7.js → forwardRefs-Nj5UEeg5.50a55d7d8b68.js} +1 -1
  168. codex/static_root/assets/forwardRefs-Nj5UEeg5.50a55d7d8b68.js.br +0 -0
  169. codex/static_root/assets/forwardRefs-Nj5UEeg5.50a55d7d8b68.js.gz +0 -0
  170. codex/static_root/assets/{forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js → forwardRefs-Nj5UEeg5.js} +1 -1
  171. codex/static_root/assets/forwardRefs-Nj5UEeg5.js.br +0 -0
  172. codex/static_root/assets/forwardRefs-Nj5UEeg5.js.gz +0 -0
  173. codex/static_root/assets/{group-tab-B0ASBB3_.8e10b90ff052.js → group-tab-lamd9pcq.604a78bd4e4f.js} +1 -1
  174. codex/static_root/assets/group-tab-lamd9pcq.604a78bd4e4f.js.br +0 -0
  175. codex/static_root/assets/group-tab-lamd9pcq.604a78bd4e4f.js.gz +0 -0
  176. codex/static_root/assets/{group-tab-B0ASBB3_.js → group-tab-lamd9pcq.js} +1 -1
  177. codex/static_root/assets/group-tab-lamd9pcq.js.br +0 -0
  178. codex/static_root/assets/group-tab-lamd9pcq.js.gz +0 -0
  179. codex/static_root/assets/{http-error-BP-mMZsK.72c4d00b40d2.js → http-error-DRYA5ir1.46f4babacf15.js} +1 -1
  180. codex/static_root/assets/http-error-DRYA5ir1.46f4babacf15.js.br +0 -0
  181. codex/static_root/assets/http-error-DRYA5ir1.46f4babacf15.js.gz +0 -0
  182. codex/static_root/assets/{http-error-BP-mMZsK.js → http-error-DRYA5ir1.js} +1 -1
  183. codex/static_root/assets/http-error-DRYA5ir1.js.br +0 -0
  184. codex/static_root/assets/http-error-DRYA5ir1.js.gz +0 -0
  185. codex/static_root/assets/{index-Cu9nQXJD.49795921eada.js → index-Cl7tPJIx.c0a239cf7069.js} +1 -1
  186. codex/static_root/assets/index-Cl7tPJIx.c0a239cf7069.js.br +0 -0
  187. codex/static_root/assets/index-Cl7tPJIx.c0a239cf7069.js.gz +0 -0
  188. codex/static_root/assets/{index-Cu9nQXJD.js → index-Cl7tPJIx.js} +1 -1
  189. codex/static_root/assets/index-Cl7tPJIx.js.br +0 -0
  190. codex/static_root/assets/index-Cl7tPJIx.js.gz +0 -0
  191. codex/static_root/assets/library-tab-2UucZZAW.f4541a086231.js +1 -0
  192. codex/static_root/assets/library-tab-2UucZZAW.f4541a086231.js.br +0 -0
  193. codex/static_root/assets/library-tab-2UucZZAW.f4541a086231.js.gz +0 -0
  194. codex/static_root/assets/library-tab-2UucZZAW.js +1 -0
  195. codex/static_root/assets/library-tab-2UucZZAW.js.br +0 -0
  196. codex/static_root/assets/library-tab-2UucZZAW.js.gz +0 -0
  197. codex/static_root/assets/{library-tab-D9lxhAqv.02f7064c20f3.css → library-tab-5StL67ei.0fad8998a237.css} +1 -1
  198. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.br +0 -0
  199. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.gz +0 -0
  200. codex/static_root/assets/{library-tab-D9lxhAqv.css → library-tab-5StL67ei.css} +1 -1
  201. codex/static_root/assets/library-tab-5StL67ei.css.br +0 -0
  202. codex/static_root/assets/library-tab-5StL67ei.css.gz +0 -0
  203. codex/static_root/assets/main-BX4TjIpG.dc79406e2a7b.js +39 -0
  204. codex/static_root/assets/main-BX4TjIpG.dc79406e2a7b.js.br +0 -0
  205. codex/static_root/assets/main-BX4TjIpG.dc79406e2a7b.js.gz +0 -0
  206. codex/static_root/assets/main-BX4TjIpG.js +39 -0
  207. codex/static_root/assets/main-BX4TjIpG.js.br +0 -0
  208. codex/static_root/assets/main-BX4TjIpG.js.gz +0 -0
  209. codex/static_root/assets/pager-full-pdf-KI4NQUMe.762b6bef9373.js +1 -0
  210. codex/static_root/assets/pager-full-pdf-KI4NQUMe.762b6bef9373.js.br +0 -0
  211. codex/static_root/assets/pager-full-pdf-KI4NQUMe.762b6bef9373.js.gz +0 -0
  212. codex/static_root/assets/pager-full-pdf-KI4NQUMe.js +1 -0
  213. codex/static_root/assets/pager-full-pdf-KI4NQUMe.js.br +0 -0
  214. codex/static_root/assets/pager-full-pdf-KI4NQUMe.js.gz +0 -0
  215. codex/static_root/assets/{pagination-toolbar-DGfRDeRW.c3f463ad6edd.js → pagination-toolbar-48pwYEe_.892375c5aa51.js} +1 -1
  216. codex/static_root/assets/pagination-toolbar-48pwYEe_.892375c5aa51.js.br +0 -0
  217. codex/static_root/assets/pagination-toolbar-48pwYEe_.892375c5aa51.js.gz +0 -0
  218. codex/static_root/assets/{pagination-toolbar-DGfRDeRW.js → pagination-toolbar-48pwYEe_.js} +1 -1
  219. codex/static_root/assets/pagination-toolbar-48pwYEe_.js.br +0 -0
  220. codex/static_root/assets/pagination-toolbar-48pwYEe_.js.gz +0 -0
  221. codex/static_root/assets/{pdf-doc-D6Meu4vZ.91b43d057670.js → pdf-doc-GyrCvyP5.54b26ba8d93c.js} +14 -14
  222. codex/static_root/assets/pdf-doc-GyrCvyP5.54b26ba8d93c.js.br +0 -0
  223. codex/static_root/assets/pdf-doc-GyrCvyP5.54b26ba8d93c.js.gz +0 -0
  224. codex/static_root/assets/{pdf-doc-D6Meu4vZ.js → pdf-doc-GyrCvyP5.js} +14 -14
  225. codex/static_root/assets/pdf-doc-GyrCvyP5.js.br +0 -0
  226. codex/static_root/assets/pdf-doc-GyrCvyP5.js.gz +0 -0
  227. codex/static_root/assets/{reader-LwL05rgA.c022ad3b7b94.css → reader-HE07eoaG.8626eeb7c718.css} +1 -1
  228. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.br +0 -0
  229. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.gz +0 -0
  230. codex/static_root/assets/{reader-LwL05rgA.css → reader-HE07eoaG.css} +1 -1
  231. codex/static_root/assets/reader-HE07eoaG.css.br +0 -0
  232. codex/static_root/assets/reader-HE07eoaG.css.gz +0 -0
  233. codex/static_root/assets/reader-lmk4MiSj.9239243e1be1.js +2 -0
  234. codex/static_root/assets/reader-lmk4MiSj.9239243e1be1.js.br +0 -0
  235. codex/static_root/assets/reader-lmk4MiSj.9239243e1be1.js.gz +0 -0
  236. codex/static_root/assets/reader-lmk4MiSj.js +2 -0
  237. codex/static_root/assets/reader-lmk4MiSj.js.br +0 -0
  238. codex/static_root/assets/reader-lmk4MiSj.js.gz +0 -0
  239. codex/static_root/assets/{relation-chips-CAXZIswb.e991a259ce59.js → relation-chips-Dgb6LQdZ.c028ab2df979.js} +1 -1
  240. codex/static_root/assets/relation-chips-Dgb6LQdZ.c028ab2df979.js.br +0 -0
  241. codex/static_root/assets/relation-chips-Dgb6LQdZ.c028ab2df979.js.gz +0 -0
  242. codex/static_root/assets/{relation-chips-CAXZIswb.js → relation-chips-Dgb6LQdZ.js} +1 -1
  243. codex/static_root/assets/relation-chips-Dgb6LQdZ.js.br +0 -0
  244. codex/static_root/assets/relation-chips-Dgb6LQdZ.js.gz +0 -0
  245. codex/static_root/assets/{settings-drawer-B4gD41g6.js → settings-drawer-CRmLEncr.6937d45e18af.js} +2 -2
  246. codex/static_root/assets/settings-drawer-CRmLEncr.6937d45e18af.js.br +0 -0
  247. codex/static_root/assets/settings-drawer-CRmLEncr.6937d45e18af.js.gz +0 -0
  248. codex/static_root/assets/{settings-drawer-B4gD41g6.82718694498e.js → settings-drawer-CRmLEncr.js} +2 -2
  249. codex/static_root/assets/settings-drawer-CRmLEncr.js.br +0 -0
  250. codex/static_root/assets/settings-drawer-CRmLEncr.js.gz +0 -0
  251. codex/static_root/assets/{ssrBoot-O6yTJ_UV.7180d77d283e.js → ssrBoot-CCKPlpgB.c90fa83e0817.js} +1 -1
  252. codex/static_root/assets/ssrBoot-CCKPlpgB.c90fa83e0817.js.br +0 -0
  253. codex/static_root/assets/ssrBoot-CCKPlpgB.c90fa83e0817.js.gz +0 -0
  254. codex/static_root/assets/{ssrBoot-O6yTJ_UV.js → ssrBoot-CCKPlpgB.js} +1 -1
  255. codex/static_root/assets/ssrBoot-CCKPlpgB.js.br +0 -0
  256. codex/static_root/assets/ssrBoot-CCKPlpgB.js.gz +0 -0
  257. codex/static_root/assets/{stats-tab-BZjOg19A.afb2e6b0d648.js → stats-tab-CrU_p2gC.e12768f9423d.js} +1 -1
  258. codex/static_root/assets/stats-tab-CrU_p2gC.e12768f9423d.js.br +0 -0
  259. codex/static_root/assets/stats-tab-CrU_p2gC.e12768f9423d.js.gz +0 -0
  260. codex/static_root/assets/{stats-tab-BZjOg19A.js → stats-tab-CrU_p2gC.js} +1 -1
  261. codex/static_root/assets/stats-tab-CrU_p2gC.js.br +0 -0
  262. codex/static_root/assets/stats-tab-CrU_p2gC.js.gz +0 -0
  263. codex/static_root/assets/task-tab-Bp0wsH4V.2a5135c30818.js +1 -0
  264. codex/static_root/assets/task-tab-Bp0wsH4V.2a5135c30818.js.br +0 -0
  265. codex/static_root/assets/task-tab-Bp0wsH4V.2a5135c30818.js.gz +0 -0
  266. codex/static_root/assets/task-tab-Bp0wsH4V.js +1 -0
  267. codex/static_root/assets/task-tab-Bp0wsH4V.js.br +0 -0
  268. codex/static_root/assets/task-tab-Bp0wsH4V.js.gz +0 -0
  269. codex/static_root/assets/{unauthorized-Bo3ThIrX.12d2efd95d7d.js → unauthorized-DObmibd6.b47434919de7.js} +1 -1
  270. codex/static_root/assets/unauthorized-DObmibd6.b47434919de7.js.br +0 -0
  271. codex/static_root/assets/unauthorized-DObmibd6.b47434919de7.js.gz +0 -0
  272. codex/static_root/assets/{unauthorized-Bo3ThIrX.js → unauthorized-DObmibd6.js} +1 -1
  273. codex/static_root/assets/unauthorized-DObmibd6.js.br +0 -0
  274. codex/static_root/assets/unauthorized-DObmibd6.js.gz +0 -0
  275. codex/static_root/assets/{user-tab-BQ82qBg3.17190dc83452.js → user-tab-DedY8MbN.624af3a6a978.js} +1 -1
  276. codex/static_root/assets/user-tab-DedY8MbN.624af3a6a978.js.br +0 -0
  277. codex/static_root/assets/user-tab-DedY8MbN.624af3a6a978.js.gz +0 -0
  278. codex/static_root/assets/{user-tab-BQ82qBg3.js → user-tab-DedY8MbN.js} +1 -1
  279. codex/static_root/assets/user-tab-DedY8MbN.js.br +0 -0
  280. codex/static_root/assets/user-tab-DedY8MbN.js.gz +0 -0
  281. codex/static_root/{manifest.0dc91d0dee6d.json → manifest.4217bf6f9edb.json} +313 -313
  282. codex/static_root/manifest.4217bf6f9edb.json.br +0 -0
  283. codex/static_root/manifest.4217bf6f9edb.json.gz +0 -0
  284. codex/static_root/manifest.json +313 -313
  285. codex/static_root/manifest.json.br +0 -0
  286. codex/static_root/manifest.json.gz +0 -0
  287. codex/static_root/staticfiles.json +1 -1
  288. codex/views/admin/library.py +4 -1
  289. codex/views/browser/params.py +21 -17
  290. codex/views/reader/arcs.py +16 -6
  291. codex/views/reader/params.py +4 -1
  292. codex/views/session.py +1 -0
  293. {codex-1.8.0a2.dist-info → codex-1.8.0a3.dist-info}/METADATA +2 -2
  294. {codex-1.8.0a2.dist-info → codex-1.8.0a3.dist-info}/RECORD +297 -293
  295. codex/librarian/scribe/importer/failed_imports.py +0 -168
  296. codex/librarian/scribe/importer/statii/1 +0 -27
  297. codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.br +0 -0
  298. codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.gz +0 -0
  299. codex/static_root/assets/VCheckbox-DSndl51k.js.br +0 -0
  300. codex/static_root/assets/VCheckbox-DSndl51k.js.gz +0 -0
  301. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.br +0 -0
  302. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.gz +0 -0
  303. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.br +0 -0
  304. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.gz +0 -0
  305. codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.br +0 -0
  306. codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.gz +0 -0
  307. codex/static_root/assets/VCombobox-Uogv6Ckp.js.br +0 -0
  308. codex/static_root/assets/VCombobox-Uogv6Ckp.js.gz +0 -0
  309. codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.br +0 -0
  310. codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.gz +0 -0
  311. codex/static_root/assets/VDialog-BzaGu1HN.js.br +0 -0
  312. codex/static_root/assets/VDialog-BzaGu1HN.js.gz +0 -0
  313. codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.br +0 -0
  314. codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.gz +0 -0
  315. codex/static_root/assets/VDivider-C3ikm0Ko.js.br +0 -0
  316. codex/static_root/assets/VDivider-C3ikm0Ko.js.gz +0 -0
  317. codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.br +0 -0
  318. codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.gz +0 -0
  319. codex/static_root/assets/VExpansionPanels-AmsInZN0.js.br +0 -0
  320. codex/static_root/assets/VExpansionPanels-AmsInZN0.js.gz +0 -0
  321. codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.br +0 -0
  322. codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.gz +0 -0
  323. codex/static_root/assets/VForm-CyCdgusw.js.br +0 -0
  324. codex/static_root/assets/VForm-CyCdgusw.js.gz +0 -0
  325. codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.br +0 -0
  326. codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.gz +0 -0
  327. codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.br +0 -0
  328. codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.gz +0 -0
  329. codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.br +0 -0
  330. codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.gz +0 -0
  331. codex/static_root/assets/VSelect-Dv50OIkN.js.br +0 -0
  332. codex/static_root/assets/VSelect-Dv50OIkN.js.gz +0 -0
  333. codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.br +0 -0
  334. codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.gz +0 -0
  335. codex/static_root/assets/VSelectionControl-DbKYScD5.js.br +0 -0
  336. codex/static_root/assets/VSelectionControl-DbKYScD5.js.gz +0 -0
  337. codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.br +0 -0
  338. codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.gz +0 -0
  339. codex/static_root/assets/VTable-BmOfHc7J.js.br +0 -0
  340. codex/static_root/assets/VTable-BmOfHc7J.js.gz +0 -0
  341. codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.br +0 -0
  342. codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.gz +0 -0
  343. codex/static_root/assets/VWindowItem-BLEDgagD.js.br +0 -0
  344. codex/static_root/assets/VWindowItem-BLEDgagD.js.gz +0 -0
  345. codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.br +0 -0
  346. codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.gz +0 -0
  347. codex/static_root/assets/admin-Bv40vYZw.js.br +0 -0
  348. codex/static_root/assets/admin-Bv40vYZw.js.gz +0 -0
  349. codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.br +0 -0
  350. codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.gz +0 -0
  351. codex/static_root/assets/admin-kjMoKlqD.js.br +0 -0
  352. codex/static_root/assets/admin-kjMoKlqD.js.gz +0 -0
  353. codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js +0 -1
  354. codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.br +0 -0
  355. codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.gz +0 -0
  356. codex/static_root/assets/admin-menu-BNpuOmbI.js +0 -1
  357. codex/static_root/assets/admin-menu-BNpuOmbI.js.br +0 -0
  358. codex/static_root/assets/admin-menu-BNpuOmbI.js.gz +0 -0
  359. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.br +0 -0
  360. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.gz +0 -0
  361. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.br +0 -0
  362. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.gz +0 -0
  363. codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.br +0 -0
  364. codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.gz +0 -0
  365. codex/static_root/assets/browser-plYso4v5.js.br +0 -0
  366. codex/static_root/assets/browser-plYso4v5.js.gz +0 -0
  367. codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.br +0 -0
  368. codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.gz +0 -0
  369. codex/static_root/assets/change-password-dialog-DyhQwNv1.js.br +0 -0
  370. codex/static_root/assets/change-password-dialog-DyhQwNv1.js.gz +0 -0
  371. codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.br +0 -0
  372. codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.gz +0 -0
  373. codex/static_root/assets/confirm-dialog-B7ndwV5M.js.br +0 -0
  374. codex/static_root/assets/confirm-dialog-B7ndwV5M.js.gz +0 -0
  375. codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.br +0 -0
  376. codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.gz +0 -0
  377. codex/static_root/assets/datetime-column-DANpNGGe.js.br +0 -0
  378. codex/static_root/assets/datetime-column-DANpNGGe.js.gz +0 -0
  379. codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.br +0 -0
  380. codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.gz +0 -0
  381. codex/static_root/assets/filter-Dhe8cVmt.js.br +0 -0
  382. codex/static_root/assets/filter-Dhe8cVmt.js.gz +0 -0
  383. codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.br +0 -0
  384. codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.gz +0 -0
  385. codex/static_root/assets/flag-tab-BZ9S7U8D.js.br +0 -0
  386. codex/static_root/assets/flag-tab-BZ9S7U8D.js.gz +0 -0
  387. codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.br +0 -0
  388. codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.gz +0 -0
  389. codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.br +0 -0
  390. codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.gz +0 -0
  391. codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.br +0 -0
  392. codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.gz +0 -0
  393. codex/static_root/assets/group-tab-B0ASBB3_.js.br +0 -0
  394. codex/static_root/assets/group-tab-B0ASBB3_.js.gz +0 -0
  395. codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.br +0 -0
  396. codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.gz +0 -0
  397. codex/static_root/assets/http-error-BP-mMZsK.js.br +0 -0
  398. codex/static_root/assets/http-error-BP-mMZsK.js.gz +0 -0
  399. codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.br +0 -0
  400. codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.gz +0 -0
  401. codex/static_root/assets/index-Cu9nQXJD.js.br +0 -0
  402. codex/static_root/assets/index-Cu9nQXJD.js.gz +0 -0
  403. codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js +0 -1
  404. codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.br +0 -0
  405. codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.gz +0 -0
  406. codex/static_root/assets/library-tab-8g2eSuGN.js +0 -1
  407. codex/static_root/assets/library-tab-8g2eSuGN.js.br +0 -0
  408. codex/static_root/assets/library-tab-8g2eSuGN.js.gz +0 -0
  409. codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.br +0 -0
  410. codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.gz +0 -0
  411. codex/static_root/assets/library-tab-D9lxhAqv.css.br +0 -0
  412. codex/static_root/assets/library-tab-D9lxhAqv.css.gz +0 -0
  413. codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js +0 -39
  414. codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.br +0 -0
  415. codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.gz +0 -0
  416. codex/static_root/assets/main-BoAlbVoF.js +0 -39
  417. codex/static_root/assets/main-BoAlbVoF.js.br +0 -0
  418. codex/static_root/assets/main-BoAlbVoF.js.gz +0 -0
  419. codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js +0 -1
  420. codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.br +0 -0
  421. codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.gz +0 -0
  422. codex/static_root/assets/pager-full-pdf-DShiSKPO.js +0 -1
  423. codex/static_root/assets/pager-full-pdf-DShiSKPO.js.br +0 -0
  424. codex/static_root/assets/pager-full-pdf-DShiSKPO.js.gz +0 -0
  425. codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.br +0 -0
  426. codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.gz +0 -0
  427. codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.br +0 -0
  428. codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.gz +0 -0
  429. codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.br +0 -0
  430. codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.gz +0 -0
  431. codex/static_root/assets/pdf-doc-D6Meu4vZ.js.br +0 -0
  432. codex/static_root/assets/pdf-doc-D6Meu4vZ.js.gz +0 -0
  433. codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js +0 -2
  434. codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.br +0 -0
  435. codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.gz +0 -0
  436. codex/static_root/assets/reader-CptqnqBZ.js +0 -2
  437. codex/static_root/assets/reader-CptqnqBZ.js.br +0 -0
  438. codex/static_root/assets/reader-CptqnqBZ.js.gz +0 -0
  439. codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.br +0 -0
  440. codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.gz +0 -0
  441. codex/static_root/assets/reader-LwL05rgA.css.br +0 -0
  442. codex/static_root/assets/reader-LwL05rgA.css.gz +0 -0
  443. codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.br +0 -0
  444. codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.gz +0 -0
  445. codex/static_root/assets/relation-chips-CAXZIswb.js.br +0 -0
  446. codex/static_root/assets/relation-chips-CAXZIswb.js.gz +0 -0
  447. codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.br +0 -0
  448. codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.gz +0 -0
  449. codex/static_root/assets/settings-drawer-B4gD41g6.js.br +0 -0
  450. codex/static_root/assets/settings-drawer-B4gD41g6.js.gz +0 -0
  451. codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.br +0 -0
  452. codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.gz +0 -0
  453. codex/static_root/assets/ssrBoot-O6yTJ_UV.js.br +0 -0
  454. codex/static_root/assets/ssrBoot-O6yTJ_UV.js.gz +0 -0
  455. codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.br +0 -0
  456. codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.gz +0 -0
  457. codex/static_root/assets/stats-tab-BZjOg19A.js.br +0 -0
  458. codex/static_root/assets/stats-tab-BZjOg19A.js.gz +0 -0
  459. codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js +0 -1
  460. codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.br +0 -0
  461. codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.gz +0 -0
  462. codex/static_root/assets/task-tab-GP2jPkRE.js +0 -1
  463. codex/static_root/assets/task-tab-GP2jPkRE.js.br +0 -0
  464. codex/static_root/assets/task-tab-GP2jPkRE.js.gz +0 -0
  465. codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.br +0 -0
  466. codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.gz +0 -0
  467. codex/static_root/assets/unauthorized-Bo3ThIrX.js.br +0 -0
  468. codex/static_root/assets/unauthorized-Bo3ThIrX.js.gz +0 -0
  469. codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.br +0 -0
  470. codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.gz +0 -0
  471. codex/static_root/assets/user-tab-BQ82qBg3.js.br +0 -0
  472. codex/static_root/assets/user-tab-BQ82qBg3.js.gz +0 -0
  473. codex/static_root/manifest.0dc91d0dee6d.json.br +0 -0
  474. codex/static_root/manifest.0dc91d0dee6d.json.gz +0 -0
  475. {codex-1.8.0a2.dist-info → codex-1.8.0a3.dist-info}/WHEEL +0 -0
  476. {codex-1.8.0a2.dist-info → codex-1.8.0a3.dist-info}/entry_points.txt +0 -0
  477. {codex-1.8.0a2.dist-info → codex-1.8.0a3.dist-info}/licenses/LICENSE +0 -0
codex/choices/admin.py CHANGED
@@ -118,23 +118,23 @@ ADMIN_TASK_GROUPS: MappingProxyType[
118
118
  {
119
119
  "value": "db_fts_rebuild",
120
120
  "title": "Repair Search Index",
121
- "desc": "Probably faster than Rebuild if integrity check fails.",
121
+ "desc": "Probably faster than Rebuild if the integrity check fails.",
122
122
  },
123
123
  {
124
124
  "value": "search_index_abort",
125
- "title": "Abort Legacy Search Index Sync",
125
+ "title": "Abort Search Index Sync",
126
126
  "desc": "Aborts search index sync tasks.",
127
127
  },
128
128
  {
129
129
  "value": "search_index_update",
130
130
  "title": "Sync Search Index",
131
- "desc": "with recently changed comics. This should not need to be run.",
131
+ "desc": "with recently changed comics.",
132
132
  "confirm": "This can take a long time",
133
133
  },
134
134
  {
135
135
  "value": "search_index_rebuild",
136
136
  "title": "Rebuild Search Index Using Sync.",
137
- "desc": "Delete and rebuild the search index from scratch using the legacy syncer. This should not need to be run.",
137
+ "desc": "Delete and rebuild the search index from scratch using the syncer.",
138
138
  "confirm": "This can take a long time",
139
139
  },
140
140
  ),
codex/choices/statii.py CHANGED
@@ -8,11 +8,11 @@ from codex.librarian.covers.status import COVERS_STATII
8
8
  from codex.librarian.restarter.status import RESTARTER_STATII
9
9
  from codex.librarian.scribe.importer.statii.create import CREATE_STATII
10
10
  from codex.librarian.scribe.importer.statii.delete import REMOVE_STATII
11
+ from codex.librarian.scribe.importer.statii.failed import FAILED_IMPORTS_STATII
11
12
  from codex.librarian.scribe.importer.statii.link import LINK_STATII
12
13
  from codex.librarian.scribe.importer.statii.query import QUERY_STATII
13
14
  from codex.librarian.scribe.importer.statii.read import READ_STATII
14
15
  from codex.librarian.scribe.importer.statii.search import IMPORTER_SEARCH_INDEX_STATII
15
- from codex.librarian.scribe.importer.status import FAILED_IMPORTS_STATII
16
16
  from codex.librarian.scribe.janitor.status import JANITOR_STATII
17
17
  from codex.librarian.scribe.search.status import SEARCH_INDEX_STATII
18
18
  from codex.librarian.scribe.status import SCRIBE_STATII
@@ -23,7 +23,7 @@ class RemoveCoversStatus(CoversStatus):
23
23
 
24
24
  CODE = "CRC"
25
25
  VERB = "Remove"
26
- LOG_SUCCESS = True
26
+ log_success = True
27
27
 
28
28
 
29
29
  class FindOrphanCoversStatus(CoversStatus):
@@ -21,6 +21,7 @@ from codex.librarian.restarter.restarter import CodexRestarter
21
21
  from codex.librarian.restarter.tasks import CodexRestarterTask
22
22
  from codex.librarian.scribe.janitor.tasks import JanitorAdoptOrphanFoldersTask
23
23
  from codex.librarian.scribe.scribed import ScribeThread
24
+ from codex.librarian.scribe.search.tasks import SearchIndexSyncTask
24
25
  from codex.librarian.scribe.tasks import ScribeTask
25
26
  from codex.librarian.tasks import LibrarianShutdownTask, WakeCronTask
26
27
  from codex.librarian.watchdog.event_batcherd import WatchdogEventBatcherThread
@@ -63,6 +64,7 @@ class LibrarianDaemon(Process):
63
64
  startup_tasks = (
64
65
  JanitorAdoptOrphanFoldersTask(),
65
66
  WatchdogSyncTask(),
67
+ SearchIndexSyncTask(),
66
68
  )
67
69
 
68
70
  for task in startup_tasks:
@@ -359,3 +359,11 @@ ALL_COMIC_GROUP_FIELD_NAMES = (
359
359
  "story_arc_numbers",
360
360
  "folders",
361
361
  )
362
+
363
+ ##########
364
+ # Failed #
365
+ ##########
366
+ UPDATE_FIS = "update_fis"
367
+ CREATE_FIS = "create_fis"
368
+ DELETE_FI_PATHS = "delete_fi_paths"
369
+ BULK_UPDATE_FAILED_IMPORT_FIELDS = ("name", "stat", "updated_at")
@@ -174,7 +174,7 @@ class CreateForeignKeysCreateUpdateImporter(CreateForeignKeysFolderImporter):
174
174
  self.status_controller.update(status)
175
175
  key_args_map, update_args_map = MODEL_CREATE_ARGS_MAP[model]
176
176
  update_objs = []
177
- update_tuples = sorted(update_tuples, key=lambda t: str(t))
177
+ update_tuples = sorted(update_tuples, key=str)
178
178
  fts_update_pks = set()
179
179
  for values_tuple in update_tuples:
180
180
  key_args, update_args = self._get_create_update_args(
@@ -16,7 +16,9 @@ class DeletedCoversImporter(SearchIndexImporter):
16
16
 
17
17
  def bulk_covers_deleted(self, **kwargs):
18
18
  """Bulk delete comics found missing from the filesystem."""
19
- status = ImporterRemoveCoversStatus(0, len(self.task.covers_deleted))
19
+ status = ImporterRemoveCoversStatus(
20
+ 0, len(self.task.covers_deleted), log_success=False
21
+ )
20
22
  try:
21
23
  if not self.task.covers_deleted:
22
24
  return 0
@@ -0,0 +1 @@
1
+ """Failed imports."""
@@ -0,0 +1,97 @@
1
+ """Update and create failed imports."""
2
+
3
+ from django.db.models.functions import Now
4
+
5
+ from codex.librarian.scribe.importer.const import (
6
+ BULK_UPDATE_FAILED_IMPORT_FIELDS,
7
+ CREATE_FIS,
8
+ UPDATE_FIS,
9
+ )
10
+ from codex.librarian.scribe.importer.failed.query import FailedImportsQueryImporter
11
+ from codex.librarian.scribe.importer.statii.failed import (
12
+ ImporterFailedImportsCreateStatus,
13
+ ImporterFailedImportsUpdateStatus,
14
+ )
15
+ from codex.models import FailedImport
16
+
17
+
18
+ class FailedImportsCreateUpdateImporter(FailedImportsQueryImporter):
19
+ """Methods for failed imports."""
20
+
21
+ def _bulk_update_failed_imports(
22
+ self, status: ImporterFailedImportsUpdateStatus | None
23
+ ):
24
+ """Bulk update failed imports."""
25
+ update_failed_imports = self.metadata.pop(UPDATE_FIS, None)
26
+ try:
27
+ if not update_failed_imports:
28
+ return
29
+ if status:
30
+ self.status_controller.start(status)
31
+ update_failed_import_objs = FailedImport.objects.filter(
32
+ library=self.library, path__in=update_failed_imports.keys()
33
+ ).only(*BULK_UPDATE_FAILED_IMPORT_FIELDS)
34
+ if not update_failed_import_objs:
35
+ return
36
+ for fi in update_failed_import_objs:
37
+ try:
38
+ exc = update_failed_imports.pop(fi.path)
39
+ fi.set_reason(exc)
40
+ fi.updated_at = Now()
41
+ fi.presave()
42
+ except OSError as exc:
43
+ self.log.warning(f"Presaving failed import {fi.path}: {exc}")
44
+ except Exception:
45
+ self.log.exception(
46
+ f"Error preparing failed import update for {fi.path}"
47
+ )
48
+
49
+ FailedImport.objects.bulk_update(
50
+ update_failed_import_objs, fields=BULK_UPDATE_FAILED_IMPORT_FIELDS
51
+ )
52
+ count = len(update_failed_import_objs)
53
+ level = "INFO" if count else "DEBUG"
54
+ self.log.log(level, f"Updated {count} old failed imports.")
55
+ finally:
56
+ self.status_controller.finish(status)
57
+
58
+ def _bulk_create_failed_imports(
59
+ self, status: ImporterFailedImportsCreateStatus | None
60
+ ):
61
+ """Bulk create failed imports."""
62
+ create_failed_imports = self.metadata.pop(CREATE_FIS, None)
63
+ try:
64
+ if not create_failed_imports:
65
+ return 0
66
+ if status:
67
+ self.status_controller.start(status)
68
+ create_objs = []
69
+ for path, exc in create_failed_imports.items():
70
+ try:
71
+ fi = FailedImport(
72
+ library=self.library, path=path, parent_folder=None
73
+ )
74
+ fi.set_reason(exc)
75
+ create_objs.append(fi)
76
+ fi.presave()
77
+ except OSError:
78
+ self.log.warning(
79
+ f"Error preparing failed import create for {path}: {exc}"
80
+ )
81
+ except Exception:
82
+ self.log.exception(
83
+ f"Error preparing failed import create for {path}"
84
+ )
85
+ count = len(create_objs)
86
+ if count:
87
+ FailedImport.objects.bulk_create(
88
+ create_objs,
89
+ update_conflicts=True,
90
+ update_fields=BULK_UPDATE_FAILED_IMPORT_FIELDS,
91
+ unique_fields=FailedImport._meta.unique_together[0],
92
+ )
93
+ level = "INFO" if count else "DEBUG"
94
+ self.log.log(level, f"Added {count} comics to failed imports.")
95
+ finally:
96
+ self.status_controller.finish(status)
97
+ return count
@@ -0,0 +1,54 @@
1
+ """Update and create failed imports."""
2
+
3
+ from codex.librarian.scribe.importer.const import DELETE_FI_PATHS
4
+ from codex.librarian.scribe.importer.failed.create import (
5
+ FailedImportsCreateUpdateImporter,
6
+ )
7
+ from codex.librarian.scribe.importer.statii.failed import (
8
+ ImporterFailedImportsDeleteStatus,
9
+ )
10
+ from codex.models import FailedImport
11
+
12
+
13
+ class FailedImportsImporter(FailedImportsCreateUpdateImporter):
14
+ """Methods for failed imports."""
15
+
16
+ def _bulk_cleanup_failed_imports(
17
+ self, status: ImporterFailedImportsDeleteStatus | None
18
+ ):
19
+ """Remove FailedImport objects that have since succeeded."""
20
+ delete_failed_imports_paths = self.metadata.pop(DELETE_FI_PATHS, None)
21
+ try:
22
+ if not delete_failed_imports_paths:
23
+ return 0
24
+ if status:
25
+ self.status_controller.start(status)
26
+ # Cleanup FailedImports that were actually successful
27
+ qs = FailedImport.objects.filter(library=self.library).filter(
28
+ path__in=delete_failed_imports_paths
29
+ )
30
+ count, _ = qs.delete()
31
+ level = "INFO" if count else "DEBUG"
32
+ self.log.log(
33
+ level, f"Cleaned up {count} failed imports from {self.library.path}"
34
+ )
35
+ return count
36
+ finally:
37
+ self.status_controller.finish(status)
38
+
39
+ def fail_imports(self):
40
+ """Handle failed imports."""
41
+ created_count = 0
42
+ update_status = create_status = delete_status = None
43
+ try:
44
+ update_status, create_status, delete_status = self._query_failed_imports()
45
+ self._bulk_update_failed_imports(update_status)
46
+ created_count += self._bulk_create_failed_imports(create_status)
47
+ self._bulk_cleanup_failed_imports(delete_status)
48
+ except Exception:
49
+ self.log.exception("Processing failed imports")
50
+ finally:
51
+ self.status_controller.finish_many(
52
+ (update_status, create_status, delete_status)
53
+ )
54
+ self.counts.failed_imports = created_count
@@ -0,0 +1,100 @@
1
+ """Update and create failed imports."""
2
+
3
+ from pathlib import Path
4
+
5
+ from codex.librarian.scribe.importer.const import (
6
+ CREATE_FIS,
7
+ DELETE_FI_PATHS,
8
+ FIS,
9
+ UPDATE_FIS,
10
+ )
11
+ from codex.librarian.scribe.importer.delete import DeletedImporter
12
+ from codex.librarian.scribe.importer.statii.failed import (
13
+ ImporterFailedImportsCreateStatus,
14
+ ImporterFailedImportsDeleteStatus,
15
+ ImporterFailedImportsQueryStatus,
16
+ ImporterFailedImportsUpdateStatus,
17
+ )
18
+ from codex.models import Comic, FailedImport
19
+
20
+
21
+ class FailedImportsQueryImporter(DeletedImporter):
22
+ """Methods for failed imports."""
23
+
24
+ def _query_failed_import_deletes(self, existing_failed_import_paths, new_fis_paths):
25
+ """Calculate Deletes."""
26
+ untouched_failed_import_paths = existing_failed_import_paths - frozenset(
27
+ new_fis_paths
28
+ )
29
+
30
+ qs = Comic.objects.filter(
31
+ library=self.library, path__in=untouched_failed_import_paths
32
+ ).only("path")
33
+ succeeded_failed_imports = frozenset(qs.values_list("path", flat=True))
34
+
35
+ possibly_missing_failed_import_paths = (
36
+ untouched_failed_import_paths - succeeded_failed_imports
37
+ )
38
+ missing_failed_import_paths = set()
39
+ for path in possibly_missing_failed_import_paths:
40
+ name = path.casefold()
41
+ # Case sensitive matching. exists() and is_file() are case insensitive.
42
+ # This will fail if there is a parent directory case mismatch and need to be replaced
43
+ # with a recursive level by level matcher.
44
+ for path_obj in Path(path).parent.iterdir():
45
+ if path_obj.name.casefold() == name:
46
+ break
47
+ else:
48
+ missing_failed_import_paths.add(path)
49
+
50
+ return succeeded_failed_imports | missing_failed_import_paths
51
+
52
+ def _query_failed_imports(
53
+ self,
54
+ ) -> tuple[
55
+ ImporterFailedImportsUpdateStatus | None,
56
+ ImporterFailedImportsCreateStatus | None,
57
+ ImporterFailedImportsDeleteStatus | None,
58
+ ]:
59
+ """Determine what to do with failed imports."""
60
+ status = ImporterFailedImportsQueryStatus(0)
61
+ update_status = create_status = delete_status = None
62
+ try:
63
+ self.status_controller.start(status)
64
+ # Calculate creates and updates
65
+ fis = self.metadata.pop(FIS, {})
66
+ existing_failed_import_paths = set(
67
+ FailedImport.objects.filter(library=self.library).values_list(
68
+ "path", flat=True
69
+ )
70
+ )
71
+ status.total = len(fis) + len(existing_failed_import_paths)
72
+ self.status_controller.update(status)
73
+ self.metadata[UPDATE_FIS] = {}
74
+ self.metadata[CREATE_FIS] = {}
75
+ for path, exc in fis.items():
76
+ if path in existing_failed_import_paths:
77
+ self.metadata[UPDATE_FIS][path] = exc
78
+ else:
79
+ self.metadata[CREATE_FIS][path] = exc
80
+ status.increment_complete()
81
+ self.status_controller.update(status)
82
+ if num_update := len(self.metadata[UPDATE_FIS]):
83
+ update_status = ImporterFailedImportsUpdateStatus(0, num_update)
84
+ self.status_controller.update(update_status)
85
+ if num_create := len(self.metadata[CREATE_FIS]):
86
+ create_status = ImporterFailedImportsCreateStatus(0, num_create)
87
+ self.status_controller.update(create_status)
88
+
89
+ if DELETE_FI_PATHS not in self.metadata:
90
+ self.metadata[DELETE_FI_PATHS] = set()
91
+ self.metadata[DELETE_FI_PATHS] |= self._query_failed_import_deletes(
92
+ existing_failed_import_paths, fis.keys()
93
+ )
94
+ status.increment_complete(len(existing_failed_import_paths))
95
+ if num_delete := len(self.metadata[DELETE_FI_PATHS]):
96
+ delete_status = ImporterFailedImportsDeleteStatus(0, num_delete)
97
+ self.status_controller.update(delete_status)
98
+ finally:
99
+ self.status_controller.finish(status, notify=True)
100
+ return update_status, create_status, delete_status
@@ -38,7 +38,7 @@ from codex.librarian.scribe.importer.statii.query import (
38
38
  )
39
39
  from codex.librarian.scribe.importer.statii.read import (
40
40
  ImporterAggregateStatus,
41
- ImporterReadStatus,
41
+ ImporterReadComicsStatus,
42
42
  )
43
43
  from codex.librarian.scribe.importer.statii.search import (
44
44
  ImporterFTSCreateStatus,
@@ -214,7 +214,7 @@ class InitImporter(WorkerStatusMixin):
214
214
  """Initialize librarian statuses for modified or created ops."""
215
215
  total_paths = len(self.task.files_modified) + len(self.task.files_created)
216
216
  status_list += [
217
- ImporterReadStatus(0, total_paths, subtitle=path),
217
+ ImporterReadComicsStatus(0, total_paths, subtitle=path),
218
218
  ImporterAggregateStatus(0, total_paths, subtitle=path),
219
219
  ImporterQueryMissingTagsStatus(subtitle=path),
220
220
  ImporterQueryComicUpdatesStatus(subtitle=path),
@@ -6,7 +6,7 @@ from codex.librarian.scribe.importer.const import (
6
6
  CLASS_CUSTOM_COVER_GROUP_MAP,
7
7
  LINK_COVER_PKS,
8
8
  )
9
- from codex.librarian.scribe.importer.failed_imports import FailedImportsImporter
9
+ from codex.librarian.scribe.importer.failed.failed import FailedImportsImporter
10
10
  from codex.librarian.scribe.importer.statii.link import ImporterLinkCoversStatus
11
11
  from codex.models import CustomCover, Folder
12
12
 
@@ -18,8 +18,10 @@ from codex.librarian.scribe.importer.const import (
18
18
  QUERY_MODELS,
19
19
  )
20
20
  from codex.librarian.scribe.importer.read.folders import AggregatePathMetadataImporter
21
+ from codex.librarian.scribe.importer.statii.failed import (
22
+ ImporterFailedImportsQueryStatus,
23
+ )
21
24
  from codex.librarian.scribe.importer.statii.read import ImporterAggregateStatus
22
- from codex.librarian.scribe.importer.status import ImporterFailedImportsStatus
23
25
 
24
26
  _UNUSED_COMICBOX_FIELDS = (
25
27
  "alternate_images",
@@ -102,7 +104,7 @@ class AggregateMetadataImporter(AggregatePathMetadataImporter):
102
104
  fis = self.metadata[FIS].keys()
103
105
 
104
106
  # Set statii
105
- fi_status = ImporterFailedImportsStatus(0, len(fis))
107
+ fi_status = ImporterFailedImportsQueryStatus(0, len(fis))
106
108
  self.status_controller.update(fi_status, notify=False)
107
109
  self.status_controller.finish(status)
108
110
  return status.complete
@@ -21,7 +21,7 @@ class SearchIndexImporter(SearchIndexPrepareImporter):
21
21
  indexer = SearchIndexer(
22
22
  self.log, self.librarian_queue, self.db_write_lock, event=self.abort_event
23
23
  )
24
- return indexer.remove_stale_records()
24
+ return indexer.remove_stale_records(log_success=False)
25
25
 
26
26
  def full_text_search(self):
27
27
  """Sync the fts index with the imported database."""
@@ -128,7 +128,7 @@ class SearchIndexCreateUpdateImporter(SearchIndexSyncManyToManyImporter):
128
128
  *,
129
129
  create: bool,
130
130
  ):
131
- if self.abort_event.is_set():
131
+ if not obj_list or self.abort_event.is_set():
132
132
  return
133
133
  verb = "create" if create else "update"
134
134
  verbing = (verb[:-1] + "ing").capitalize()
@@ -161,6 +161,10 @@ class SearchIndexCreateUpdateImporter(SearchIndexSyncManyToManyImporter):
161
161
  self.log.debug(f"No search entries to {verb}.")
162
162
  return updated_pks
163
163
  self.status_controller.start(status)
164
+ verbing = "creating" if create else "updating"
165
+ self.log.debug(
166
+ f"Preparing {total_entries} comics for search index {verbing}..."
167
+ )
164
168
 
165
169
  obj_list = []
166
170
  if create:
@@ -173,20 +177,27 @@ class SearchIndexCreateUpdateImporter(SearchIndexSyncManyToManyImporter):
173
177
  self._create_comicfts_entry(pk, entry, obj_list, status)
174
178
  updated_pks = pks
175
179
  else:
176
- comic_ids = tuple(self.metadata[FTS_UPDATE].keys())
177
- comicftss = ComicFTS.objects.filter(comic_id__in=comic_ids)
178
- for comicfts in comicftss:
179
- if self.abort_event.is_set():
180
- return tuple(updated_pks)
181
- self._update_comicfts_entry(comicfts, obj_list, status)
180
+ if pks := tuple(self.metadata[FTS_UPDATE].keys()):
181
+ comicftss = ComicFTS.objects.filter(comic_id__in=pks)
182
+ for comicfts in comicftss:
183
+ if self.abort_event.is_set():
184
+ return updated_pks
185
+ self._update_comicfts_entry(comicfts, obj_list, status)
186
+ if self.metadata[FTS_UPDATE]:
187
+ # If updates not popped, turn them into creates.
188
+ if FTS_CREATE not in self.metadata:
189
+ self.metadata[FTS_CREATE] = {}
190
+ self.metadata[FTS_CREATE].update(self.metadata[FTS_UPDATE])
182
191
  self.metadata.pop(FTS_UPDATE)
183
-
184
- self.log.debug(f"Preparing {total_entries} comics for search indexing...")
192
+ self.log.debug(
193
+ f"Prepared {len(obj_list)} comics for search index {verbing}..."
194
+ )
185
195
  self._update_search_index_create_or_update(
186
196
  obj_list,
187
197
  status,
188
198
  create=create,
189
199
  )
200
+ updated_pks = pks
190
201
 
191
202
  finally:
192
203
  self.status_controller.finish(status)
@@ -2,6 +2,7 @@
2
2
 
3
3
  from codex.librarian.scribe.importer.statii.create import CREATE_STATII
4
4
  from codex.librarian.scribe.importer.statii.delete import REMOVE_STATII
5
+ from codex.librarian.scribe.importer.statii.failed import FAILED_IMPORTS_STATII
5
6
  from codex.librarian.scribe.importer.statii.link import LINK_STATII
6
7
  from codex.librarian.scribe.importer.statii.moved import MOVED_STATII
7
8
  from codex.librarian.scribe.importer.statii.query import QUERY_STATII
@@ -16,4 +17,5 @@ IMPORTER_STATII = (
16
17
  *QUERY_STATII,
17
18
  *READ_STATII,
18
19
  *IMPORTER_SEARCH_INDEX_STATII,
20
+ *FAILED_IMPORTS_STATII,
19
21
  )
@@ -0,0 +1,50 @@
1
+ """Importer Failed Imports Sattii."""
2
+
3
+ from abc import ABC
4
+
5
+ from codex.librarian.scribe.importer.status import ImporterStatus
6
+
7
+
8
+ class ImporterFailedImportStatus(ImporterStatus, ABC):
9
+ """Importer Failed Imports Statii."""
10
+
11
+ ITEM_NAME = "failed imports"
12
+
13
+
14
+ class ImporterFailedImportsQueryStatus(ImporterFailedImportStatus, ABC):
15
+ """Importer Failed Imports Query Statii."""
16
+
17
+ CODE = "IFQ"
18
+ VERB = "Query"
19
+ _verbed = "Queried"
20
+
21
+
22
+ class ImporterFailedImportsUpdateStatus(ImporterFailedImportStatus, ABC):
23
+ """Importer Failed Imports Update Statii."""
24
+
25
+ CODE = "IFU"
26
+ VERB = "Update"
27
+
28
+
29
+ class ImporterFailedImportsCreateStatus(ImporterFailedImportStatus, ABC):
30
+ """Importer Failed Imports Create Statii."""
31
+
32
+ CODE = "IFC"
33
+ VERB = "Mark Failed"
34
+ _verbed = "Marked Failed"
35
+
36
+
37
+ class ImporterFailedImportsDeleteStatus(ImporterFailedImportStatus, ABC):
38
+ """Importer Failed Imports Create Statii."""
39
+
40
+ CODE = "IFD"
41
+ VERB = "Clean up"
42
+ _verbed = "Cleaned up"
43
+
44
+
45
+ FAILED_IMPORTS_STATII = (
46
+ ImporterFailedImportsQueryStatus,
47
+ ImporterFailedImportsUpdateStatus,
48
+ ImporterFailedImportsCreateStatus,
49
+ ImporterFailedImportsDeleteStatus,
50
+ )
@@ -7,15 +7,3 @@ from codex.librarian.scribe.status import ScribeStatus
7
7
 
8
8
  class ImporterStatus(ScribeStatus, ABC):
9
9
  """Importer Status."""
10
-
11
-
12
- class ImporterFailedImportsStatus(ImporterStatus):
13
- """Importer Failed Imports Status."""
14
-
15
- CODE = "IFI"
16
- VERB = "Mark"
17
- _verbed = "Marked"
18
- ITEM_NAME = "failed imports"
19
-
20
-
21
- FAILED_IMPORTS_STATII = (ImporterFailedImportsStatus,)
@@ -13,6 +13,7 @@ from codex.librarian.scribe.janitor.status import (
13
13
  JanitorCodexLatestVersionStatus,
14
14
  JanitorDBBackupStatus,
15
15
  JanitorDBFKIntegrityStatus,
16
+ JanitorDBFTSIntegrityStatus,
16
17
  JanitorDBIntegrityStatus,
17
18
  JanitorDBOptimizeStatus,
18
19
  )
@@ -36,28 +37,34 @@ from codex.librarian.scribe.janitor.update import JanitorCodexUpdate
36
37
  from codex.librarian.scribe.search.status import (
37
38
  SearchIndexCleanStatus,
38
39
  SearchIndexOptimizeStatus,
40
+ SearchIndexSyncCreateStatus,
41
+ SearchIndexSyncUpdateStatus,
39
42
  )
40
43
  from codex.librarian.scribe.search.tasks import (
41
44
  SearchIndexOptimizeTask,
45
+ SearchIndexSyncTask,
42
46
  )
43
47
  from codex.models import Timestamp
44
48
 
45
49
  _JANITOR_STATII = (
46
50
  JanitorCodexLatestVersionStatus,
51
+ JanitorAdoptOrphanFoldersStatus,
52
+ ImporterMoveFoldersStatus,
47
53
  JanitorDBFKIntegrityStatus,
48
54
  JanitorDBIntegrityStatus,
49
- JanitorCleanupCoversStatus,
55
+ JanitorDBFTSIntegrityStatus,
50
56
  JanitorCleanupTagsStatus,
57
+ JanitorCleanupCoversStatus,
51
58
  JanitorCleanupSessionsStatus,
52
59
  JanitorCleanupBookmarksStatus,
60
+ SearchIndexCleanStatus,
61
+ SearchIndexSyncUpdateStatus,
62
+ SearchIndexSyncCreateStatus,
63
+ SearchIndexOptimizeStatus,
53
64
  JanitorDBOptimizeStatus,
54
65
  JanitorDBBackupStatus,
55
66
  FindOrphanCoversStatus,
56
67
  RemoveCoversStatus,
57
- JanitorAdoptOrphanFoldersStatus,
58
- ImporterMoveFoldersStatus,
59
- SearchIndexCleanStatus,
60
- SearchIndexOptimizeStatus,
61
68
  )
62
69
 
63
70
 
@@ -78,6 +85,7 @@ class Janitor(JanitorCodexUpdate):
78
85
  JanitorCleanCoversTask(),
79
86
  JanitorCleanupSessionsTask(),
80
87
  JanitorCleanupBookmarksTask(),
88
+ SearchIndexSyncTask(),
81
89
  SearchIndexOptimizeTask(),
82
90
  JanitorVacuumTask(),
83
91
  JanitorBackupTask(),
@@ -44,6 +44,7 @@ class JanitorCodexUpdateStatus(JanitorStatus):
44
44
  VERB = "Update"
45
45
  ITEM_NAME = "Codex server software"
46
46
  SINGLE = True
47
+ log_success = True
47
48
 
48
49
 
49
50
  class JanitorDBOptimizeStatus(JanitorStatus):
@@ -53,7 +54,7 @@ class JanitorDBOptimizeStatus(JanitorStatus):
53
54
  VERB = "Optimize"
54
55
  ITEM_NAME = "database"
55
56
  SINGLE = True
56
- LOG_SUCCESS = True
57
+ log_success = True
57
58
 
58
59
 
59
60
  class JanitorDBBackupStatus(JanitorStatus):
@@ -131,7 +132,7 @@ class JanitorDBFTSRebuildStatus(JanitorStatus):
131
132
  _verbed = "Rebuilt"
132
133
  ITEM_NAME = "full text search virtual table"
133
134
  SINGLE = True
134
- LOG_SUCCESS = True
135
+ log_success = True
135
136
 
136
137
 
137
138
  JANITOR_STATII = (
@@ -21,8 +21,7 @@ class SearchIndexerOptimize(WorkerStatusMixin):
21
21
  """Remove records not in the database from the index, trapping exceptions."""
22
22
  status = SearchIndexOptimizeStatus()
23
23
  try:
24
- self.status_controller.update(status)
25
- self.log.debug("Optimizing search index...")
24
+ self.status_controller.start(status)
26
25
  with connection.cursor() as cursor:
27
26
  cursor.execute(_OPTIMIZE_SQL)
28
27
  except Exception:
@@ -31,10 +31,10 @@ class SearchIndexerRemove(SearchIndexerOptimize):
31
31
  status.complete = count
32
32
  return count
33
33
 
34
- def remove_stale_records(self) -> int:
34
+ def remove_stale_records(self, *, log_success: bool = True) -> int:
35
35
  """Remove records not in the database from the index, trapping exceptions."""
36
36
  count = 0
37
- status = SearchIndexCleanStatus()
37
+ status = SearchIndexCleanStatus(log_success=log_success)
38
38
  try:
39
39
  count = self._remove_stale_records(status)
40
40
  except Exception: