codex 1.6.0__py3-none-any.whl → 1.6.0a1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (768) hide show
  1. codex/exceptions.py +18 -22
  2. codex/integrity.py +3 -66
  3. codex/librarian/covers/coverd.py +2 -2
  4. codex/librarian/covers/create.py +29 -50
  5. codex/librarian/covers/path.py +6 -8
  6. codex/librarian/covers/purge.py +18 -28
  7. codex/librarian/covers/tasks.py +2 -3
  8. codex/librarian/importer/{aggregate.py → aggregate_metadata.py} +88 -58
  9. codex/librarian/importer/{extract.py → clean_metadata.py} +4 -33
  10. codex/librarian/importer/const.py +13 -46
  11. codex/librarian/importer/create_comics.py +17 -101
  12. codex/librarian/importer/create_fks.py +134 -99
  13. codex/librarian/importer/deleted.py +28 -103
  14. codex/librarian/importer/failed_imports.py +64 -42
  15. codex/librarian/importer/importerd.py +290 -71
  16. codex/librarian/importer/link_comics.py +26 -26
  17. codex/librarian/importer/moved.py +81 -128
  18. codex/librarian/importer/query_fks.py +122 -142
  19. codex/librarian/importer/status.py +39 -8
  20. codex/librarian/importer/tasks.py +9 -26
  21. codex/librarian/importer/update_comics.py +89 -0
  22. codex/librarian/janitor/cleanup.py +2 -26
  23. codex/librarian/janitor/failed_imports.py +1 -1
  24. codex/librarian/janitor/janitor.py +1 -13
  25. codex/librarian/janitor/janitord.py +1 -1
  26. codex/librarian/janitor/status.py +0 -1
  27. codex/librarian/janitor/tasks.py +0 -5
  28. codex/librarian/librariand.py +5 -9
  29. codex/librarian/notifier/notifierd.py +1 -1
  30. codex/librarian/notifier/tasks.py +4 -4
  31. codex/librarian/search/update.py +1 -1
  32. codex/librarian/watchdog/db_snapshot.py +6 -9
  33. codex/librarian/watchdog/emitter.py +0 -3
  34. codex/librarian/watchdog/event_batcherd.py +3 -19
  35. codex/librarian/watchdog/events.py +36 -176
  36. codex/librarian/watchdog/observers.py +3 -13
  37. codex/middleware.py +2 -1
  38. codex/migrations/0027_sort_name.py +149 -0
  39. codex/models/admin.py +2 -0
  40. codex/models/base.py +0 -3
  41. codex/models/comic.py +9 -13
  42. codex/models/{util.py → const.py} +2 -15
  43. codex/models/groups.py +14 -28
  44. codex/models/library.py +3 -11
  45. codex/models/paths.py +14 -61
  46. codex/permissions.py +1 -1
  47. codex/search/query.py +2 -25
  48. codex/search/writing.py +1 -1
  49. codex/serializers/admin.py +44 -53
  50. codex/serializers/browser/choices.py +42 -37
  51. codex/serializers/browser/filters.py +131 -32
  52. codex/serializers/browser/metadata.py +1 -45
  53. codex/serializers/browser/mixins.py +4 -37
  54. codex/serializers/browser/page.py +6 -3
  55. codex/serializers/browser/settings.py +11 -42
  56. codex/serializers/choices.py +1 -14
  57. codex/serializers/models/pycountry.py +51 -11
  58. codex/serializers/opds/v2.py +16 -10
  59. codex/serializers/opds/v2_unused.py +3 -5
  60. codex/serializers/reader.py +7 -21
  61. codex/serializers/redirect.py +2 -3
  62. codex/serializers/route.py +7 -16
  63. codex/settings/settings.py +8 -23
  64. codex/startup.py +3 -77
  65. codex/static_root/assets/VCheckbox-u_aWQJA7.a0db8a7bd681.js +1 -0
  66. codex/static_root/assets/VCheckbox-u_aWQJA7.a0db8a7bd681.js.br +0 -0
  67. codex/static_root/assets/VCheckbox-u_aWQJA7.a0db8a7bd681.js.gz +0 -0
  68. codex/static_root/assets/VCheckbox-u_aWQJA7.js +1 -0
  69. codex/static_root/assets/VCheckbox-u_aWQJA7.js.br +0 -0
  70. codex/static_root/assets/VCheckbox-u_aWQJA7.js.gz +0 -0
  71. codex/static_root/assets/{VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js → VCheckboxBtn-yCN3TB6A.29d48d14ab3b.js} +1 -1
  72. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.29d48d14ab3b.js.br +0 -0
  73. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.29d48d14ab3b.js.gz +0 -0
  74. codex/static_root/assets/{VCheckboxBtn-DxNOKONG.js → VCheckboxBtn-yCN3TB6A.js} +1 -1
  75. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.js.br +0 -0
  76. codex/static_root/assets/VCheckboxBtn-yCN3TB6A.js.gz +0 -0
  77. codex/static_root/assets/VCombobox-dsIKbjps.d3c8da1d75b3.js +1 -0
  78. codex/static_root/assets/VCombobox-dsIKbjps.d3c8da1d75b3.js.br +0 -0
  79. codex/static_root/assets/VCombobox-dsIKbjps.d3c8da1d75b3.js.gz +0 -0
  80. codex/static_root/assets/VCombobox-dsIKbjps.js +1 -0
  81. codex/static_root/assets/VCombobox-dsIKbjps.js.br +0 -0
  82. codex/static_root/assets/VCombobox-dsIKbjps.js.gz +0 -0
  83. codex/static_root/assets/VDialog-BNHg8txZ.21bed7754d3a.js +1 -0
  84. codex/static_root/assets/VDialog-BNHg8txZ.21bed7754d3a.js.br +0 -0
  85. codex/static_root/assets/VDialog-BNHg8txZ.21bed7754d3a.js.gz +0 -0
  86. codex/static_root/assets/VDialog-BNHg8txZ.js +1 -0
  87. codex/static_root/assets/VDialog-BNHg8txZ.js.br +0 -0
  88. codex/static_root/assets/VDialog-BNHg8txZ.js.gz +0 -0
  89. codex/static_root/assets/{VDialog-lQ13FnRR.1c801ad756b2.css → VDialog-C5Nxd_zP.css} +1 -1
  90. codex/static_root/assets/VDialog-C5Nxd_zP.css.br +0 -0
  91. codex/static_root/assets/VDialog-C5Nxd_zP.css.gz +0 -0
  92. codex/static_root/assets/{VDialog-lQ13FnRR.css → VDialog-C5Nxd_zP.d327f505ef0e.css} +1 -1
  93. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.br +0 -0
  94. codex/static_root/assets/VDialog-C5Nxd_zP.d327f505ef0e.css.gz +0 -0
  95. codex/static_root/assets/VExpansionPanels-CX4W4vZK.8e90fe0b34f4.js +1 -0
  96. codex/static_root/assets/VExpansionPanels-CX4W4vZK.8e90fe0b34f4.js.br +0 -0
  97. codex/static_root/assets/VExpansionPanels-CX4W4vZK.8e90fe0b34f4.js.gz +0 -0
  98. codex/static_root/assets/VExpansionPanels-CX4W4vZK.js +1 -0
  99. codex/static_root/assets/VExpansionPanels-CX4W4vZK.js.br +0 -0
  100. codex/static_root/assets/VExpansionPanels-CX4W4vZK.js.gz +0 -0
  101. codex/static_root/assets/VRadioGroup-jCr3CAsk.685daccd04d8.js +1 -0
  102. codex/static_root/assets/VRadioGroup-jCr3CAsk.685daccd04d8.js.br +0 -0
  103. codex/static_root/assets/VRadioGroup-jCr3CAsk.685daccd04d8.js.gz +0 -0
  104. codex/static_root/assets/VRadioGroup-jCr3CAsk.js +1 -0
  105. codex/static_root/assets/VRadioGroup-jCr3CAsk.js.br +0 -0
  106. codex/static_root/assets/VRadioGroup-jCr3CAsk.js.gz +0 -0
  107. codex/static_root/assets/VSelect--XHNpxvB.ff050ef0d6de.js +1 -0
  108. codex/static_root/assets/VSelect--XHNpxvB.ff050ef0d6de.js.br +0 -0
  109. codex/static_root/assets/VSelect--XHNpxvB.ff050ef0d6de.js.gz +0 -0
  110. codex/static_root/assets/VSelect--XHNpxvB.js +1 -0
  111. codex/static_root/assets/VSelect--XHNpxvB.js.br +0 -0
  112. codex/static_root/assets/VSelect--XHNpxvB.js.gz +0 -0
  113. codex/static_root/assets/VSelectionControl-CVIKc_ra.0b2cc426e8b8.js +1 -0
  114. codex/static_root/assets/VSelectionControl-CVIKc_ra.0b2cc426e8b8.js.br +0 -0
  115. codex/static_root/assets/VSelectionControl-CVIKc_ra.0b2cc426e8b8.js.gz +0 -0
  116. codex/static_root/assets/VSelectionControl-CVIKc_ra.js +1 -0
  117. codex/static_root/assets/VSelectionControl-CVIKc_ra.js.br +0 -0
  118. codex/static_root/assets/VSelectionControl-CVIKc_ra.js.gz +0 -0
  119. codex/static_root/assets/VSlideGroup-CZw5_eNv.7ae5182e5988.js +1 -0
  120. codex/static_root/assets/VSlideGroup-CZw5_eNv.7ae5182e5988.js.br +0 -0
  121. codex/static_root/assets/VSlideGroup-CZw5_eNv.7ae5182e5988.js.gz +0 -0
  122. codex/static_root/assets/VSlideGroup-CZw5_eNv.js +1 -0
  123. codex/static_root/assets/VSlideGroup-CZw5_eNv.js.br +0 -0
  124. codex/static_root/assets/VSlideGroup-CZw5_eNv.js.gz +0 -0
  125. codex/static_root/assets/{VTable-2RHFqfg6.f0f2106b158b.js → VTable-hGJDFK5t.d2f84d68747b.js} +1 -1
  126. codex/static_root/assets/VTable-hGJDFK5t.d2f84d68747b.js.br +0 -0
  127. codex/static_root/assets/VTable-hGJDFK5t.d2f84d68747b.js.gz +0 -0
  128. codex/static_root/assets/{VTable-2RHFqfg6.js → VTable-hGJDFK5t.js} +1 -1
  129. codex/static_root/assets/VTable-hGJDFK5t.js.br +0 -0
  130. codex/static_root/assets/VTable-hGJDFK5t.js.gz +0 -0
  131. codex/static_root/assets/VTextField-C8y3lyz9.eb58405614ad.js +1 -0
  132. codex/static_root/assets/VTextField-C8y3lyz9.eb58405614ad.js.br +0 -0
  133. codex/static_root/assets/VTextField-C8y3lyz9.eb58405614ad.js.gz +0 -0
  134. codex/static_root/assets/VTextField-C8y3lyz9.js +1 -0
  135. codex/static_root/assets/VTextField-C8y3lyz9.js.br +0 -0
  136. codex/static_root/assets/VTextField-C8y3lyz9.js.gz +0 -0
  137. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css +1 -0
  138. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.br +0 -0
  139. codex/static_root/assets/VTextField-DuIIp-VY.580110ad24dc.css.gz +0 -0
  140. codex/static_root/assets/VTextField-DuIIp-VY.css +1 -0
  141. codex/static_root/assets/VTextField-DuIIp-VY.css.br +0 -0
  142. codex/static_root/assets/VTextField-DuIIp-VY.css.gz +0 -0
  143. codex/static_root/assets/VWindowItem-BHpZIa_r.2b3c5f9594e6.js +1 -0
  144. codex/static_root/assets/VWindowItem-BHpZIa_r.2b3c5f9594e6.js.br +0 -0
  145. codex/static_root/assets/VWindowItem-BHpZIa_r.2b3c5f9594e6.js.gz +0 -0
  146. codex/static_root/assets/VWindowItem-BHpZIa_r.js +1 -0
  147. codex/static_root/assets/VWindowItem-BHpZIa_r.js.br +0 -0
  148. codex/static_root/assets/VWindowItem-BHpZIa_r.js.gz +0 -0
  149. codex/static_root/assets/{admin-B8Bp2Uih.82c98714bcf1.css → admin-BbrOU9Y9.29936748af9e.css} +1 -1
  150. codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.br +0 -0
  151. codex/static_root/assets/admin-BbrOU9Y9.29936748af9e.css.gz +0 -0
  152. codex/static_root/assets/{admin-B8Bp2Uih.css → admin-BbrOU9Y9.css} +1 -1
  153. codex/static_root/assets/admin-BbrOU9Y9.css.br +0 -0
  154. codex/static_root/assets/admin-BbrOU9Y9.css.gz +0 -0
  155. codex/static_root/assets/admin-Bvd-SvGS.412e5b1b7ed1.js +1 -0
  156. codex/static_root/assets/admin-Bvd-SvGS.412e5b1b7ed1.js.br +0 -0
  157. codex/static_root/assets/admin-Bvd-SvGS.412e5b1b7ed1.js.gz +0 -0
  158. codex/static_root/assets/admin-Bvd-SvGS.js +1 -0
  159. codex/static_root/assets/admin-Bvd-SvGS.js.br +0 -0
  160. codex/static_root/assets/admin-Bvd-SvGS.js.gz +0 -0
  161. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css +1 -0
  162. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.br +0 -0
  163. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.1514926c78e8.css.gz +0 -0
  164. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css +1 -0
  165. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.br +0 -0
  166. codex/static_root/assets/admin-drawer-panel-BF0dMvEE.css.gz +0 -0
  167. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.059e3bde9568.js +30 -0
  168. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.059e3bde9568.js.br +0 -0
  169. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.059e3bde9568.js.gz +0 -0
  170. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.js +30 -0
  171. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.js.br +0 -0
  172. codex/static_root/assets/admin-drawer-panel-D2OV5rDa.js.gz +0 -0
  173. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css +1 -0
  174. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css.br +0 -0
  175. codex/static_root/assets/browser-CZeVqRNy.ccfca9a05bfe.css.gz +0 -0
  176. codex/static_root/assets/browser-CZeVqRNy.css +1 -0
  177. codex/static_root/assets/browser-CZeVqRNy.css.br +0 -0
  178. codex/static_root/assets/browser-CZeVqRNy.css.gz +0 -0
  179. codex/static_root/assets/browser-rc5ObkeN.0c1f38d229ac.js +1 -0
  180. codex/static_root/assets/browser-rc5ObkeN.0c1f38d229ac.js.br +0 -0
  181. codex/static_root/assets/browser-rc5ObkeN.0c1f38d229ac.js.gz +0 -0
  182. codex/static_root/assets/browser-rc5ObkeN.js +1 -0
  183. codex/static_root/assets/browser-rc5ObkeN.js.br +0 -0
  184. codex/static_root/assets/browser-rc5ObkeN.js.gz +0 -0
  185. codex/static_root/assets/change-password-dialog-CRHk2tjq.d4d4b5945cd4.js +1 -0
  186. codex/static_root/assets/change-password-dialog-CRHk2tjq.d4d4b5945cd4.js.br +0 -0
  187. codex/static_root/assets/change-password-dialog-CRHk2tjq.d4d4b5945cd4.js.gz +0 -0
  188. codex/static_root/assets/change-password-dialog-CRHk2tjq.js +1 -0
  189. codex/static_root/assets/change-password-dialog-CRHk2tjq.js.br +0 -0
  190. codex/static_root/assets/change-password-dialog-CRHk2tjq.js.gz +0 -0
  191. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css +1 -0
  192. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.br +0 -0
  193. codex/static_root/assets/change-password-dialog-HvIvmmIE.73be0c8a8278.css.gz +0 -0
  194. codex/static_root/assets/change-password-dialog-HvIvmmIE.css +1 -0
  195. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.br +0 -0
  196. codex/static_root/assets/change-password-dialog-HvIvmmIE.css.gz +0 -0
  197. codex/static_root/assets/confirm-dialog-DnHKM44R.d57a0196ac5a.js +1 -0
  198. codex/static_root/assets/confirm-dialog-DnHKM44R.d57a0196ac5a.js.br +0 -0
  199. codex/static_root/assets/confirm-dialog-DnHKM44R.d57a0196ac5a.js.gz +0 -0
  200. codex/static_root/assets/confirm-dialog-DnHKM44R.js +1 -0
  201. codex/static_root/assets/confirm-dialog-DnHKM44R.js.br +0 -0
  202. codex/static_root/assets/confirm-dialog-DnHKM44R.js.gz +0 -0
  203. codex/static_root/assets/datetime-column-BEqDvdeI.44b65455a2c3.js +1 -0
  204. codex/static_root/assets/datetime-column-BEqDvdeI.44b65455a2c3.js.br +0 -0
  205. codex/static_root/assets/datetime-column-BEqDvdeI.44b65455a2c3.js.gz +0 -0
  206. codex/static_root/assets/datetime-column-BEqDvdeI.js +1 -0
  207. codex/static_root/assets/datetime-column-BEqDvdeI.js.br +0 -0
  208. codex/static_root/assets/datetime-column-BEqDvdeI.js.gz +0 -0
  209. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css +1 -0
  210. codex/static_root/assets/datetime-column-Dg_RxTVM.1fa7c5cbead7.css.br +0 -0
  211. codex/static_root/assets/datetime-column-Dg_RxTVM.css +1 -0
  212. codex/static_root/assets/datetime-column-Dg_RxTVM.css.br +0 -0
  213. codex/static_root/assets/filter-_wYL6jQC.dbc7d7e7b855.js +1 -0
  214. codex/static_root/assets/filter-_wYL6jQC.dbc7d7e7b855.js.br +0 -0
  215. codex/static_root/assets/filter-_wYL6jQC.dbc7d7e7b855.js.gz +0 -0
  216. codex/static_root/assets/filter-_wYL6jQC.js +1 -0
  217. codex/static_root/assets/filter-_wYL6jQC.js.br +0 -0
  218. codex/static_root/assets/filter-_wYL6jQC.js.gz +0 -0
  219. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css +1 -0
  220. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.br +0 -0
  221. codex/static_root/assets/flag-tab-BacZLlVi.8deba6a5370d.css.gz +0 -0
  222. codex/static_root/assets/flag-tab-BacZLlVi.css +1 -0
  223. codex/static_root/assets/flag-tab-BacZLlVi.css.br +0 -0
  224. codex/static_root/assets/flag-tab-BacZLlVi.css.gz +0 -0
  225. codex/static_root/assets/flag-tab-Dpyvhwb_.2812bd46db2d.js +1 -0
  226. codex/static_root/assets/flag-tab-Dpyvhwb_.2812bd46db2d.js.br +0 -0
  227. codex/static_root/assets/flag-tab-Dpyvhwb_.2812bd46db2d.js.gz +0 -0
  228. codex/static_root/assets/flag-tab-Dpyvhwb_.js +1 -0
  229. codex/static_root/assets/flag-tab-Dpyvhwb_.js.br +0 -0
  230. codex/static_root/assets/flag-tab-Dpyvhwb_.js.gz +0 -0
  231. codex/static_root/assets/{group-tab-D5vWrihT.1afb2ce453ff.js → group-tab-DAjvuSUO.4494d4846fa6.js} +1 -1
  232. codex/static_root/assets/group-tab-DAjvuSUO.4494d4846fa6.js.br +0 -0
  233. codex/static_root/assets/group-tab-DAjvuSUO.4494d4846fa6.js.gz +0 -0
  234. codex/static_root/assets/{group-tab-D5vWrihT.js → group-tab-DAjvuSUO.js} +1 -1
  235. codex/static_root/assets/group-tab-DAjvuSUO.js.br +0 -0
  236. codex/static_root/assets/group-tab-DAjvuSUO.js.gz +0 -0
  237. codex/static_root/assets/http-error-CDQ-296a.6ea61686beb8.js +1 -0
  238. codex/static_root/assets/http-error-CDQ-296a.6ea61686beb8.js.br +0 -0
  239. codex/static_root/assets/http-error-CDQ-296a.6ea61686beb8.js.gz +0 -0
  240. codex/static_root/assets/http-error-CDQ-296a.js +1 -0
  241. codex/static_root/assets/http-error-CDQ-296a.js.br +0 -0
  242. codex/static_root/assets/http-error-CDQ-296a.js.gz +0 -0
  243. codex/static_root/assets/http-error-_wlDqEcp.5b78d3e332c9.css +1 -0
  244. codex/static_root/assets/{http-error-DKulXuTl.95e42988d5d5.css.br → http-error-_wlDqEcp.5b78d3e332c9.css.br} +0 -0
  245. codex/static_root/assets/http-error-_wlDqEcp.5b78d3e332c9.css.gz +0 -0
  246. codex/static_root/assets/http-error-_wlDqEcp.css +1 -0
  247. codex/static_root/assets/{http-error-DKulXuTl.css.br → http-error-_wlDqEcp.css.br} +0 -0
  248. codex/static_root/assets/http-error-_wlDqEcp.css.gz +0 -0
  249. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js +1 -0
  250. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.br +0 -0
  251. codex/static_root/assets/index-DUjeNg4x.36d50c91b2c1.js.gz +0 -0
  252. codex/static_root/assets/index-DUjeNg4x.js +1 -0
  253. codex/static_root/assets/index-DUjeNg4x.js.br +0 -0
  254. codex/static_root/assets/index-DUjeNg4x.js.gz +0 -0
  255. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css +1 -0
  256. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.br +2 -0
  257. codex/static_root/assets/library-tab-CXbkxNZt.954f2850a439.css.gz +0 -0
  258. codex/static_root/assets/library-tab-CXbkxNZt.css +1 -0
  259. codex/static_root/assets/library-tab-CXbkxNZt.css.br +2 -0
  260. codex/static_root/assets/library-tab-CXbkxNZt.css.gz +0 -0
  261. codex/static_root/assets/library-tab-LsexSRi2.34b88bbbfcdc.js +1 -0
  262. codex/static_root/assets/library-tab-LsexSRi2.34b88bbbfcdc.js.br +0 -0
  263. codex/static_root/assets/library-tab-LsexSRi2.34b88bbbfcdc.js.gz +0 -0
  264. codex/static_root/assets/library-tab-LsexSRi2.js +1 -0
  265. codex/static_root/assets/library-tab-LsexSRi2.js.br +0 -0
  266. codex/static_root/assets/library-tab-LsexSRi2.js.gz +0 -0
  267. codex/static_root/assets/main-CjPnwTfF.0f333ec81a42.js +32 -0
  268. codex/static_root/assets/main-CjPnwTfF.0f333ec81a42.js.br +0 -0
  269. codex/static_root/assets/main-CjPnwTfF.0f333ec81a42.js.gz +0 -0
  270. codex/static_root/assets/main-CjPnwTfF.js +32 -0
  271. codex/static_root/assets/main-CjPnwTfF.js.br +0 -0
  272. codex/static_root/assets/main-CjPnwTfF.js.gz +0 -0
  273. codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css → main-sK7HC5h4.6f04ddfc5f1a.css} +1 -1
  274. codex/static_root/assets/main-sK7HC5h4.6f04ddfc5f1a.css.br +0 -0
  275. codex/static_root/assets/{main-Ztp855PW.d46d718fac45.css.gz → main-sK7HC5h4.6f04ddfc5f1a.css.gz} +0 -0
  276. codex/static_root/assets/{main-Ztp855PW.css → main-sK7HC5h4.css} +1 -1
  277. codex/static_root/assets/main-sK7HC5h4.css.br +0 -0
  278. codex/static_root/assets/{main-Ztp855PW.css.gz → main-sK7HC5h4.css.gz} +0 -0
  279. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css +1 -0
  280. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.br +0 -0
  281. codex/static_root/assets/pagination-toolbar-B3wS4_7p.7695fafdefce.css.gz +0 -0
  282. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css +1 -0
  283. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.br +0 -0
  284. codex/static_root/assets/pagination-toolbar-B3wS4_7p.css.gz +0 -0
  285. codex/static_root/assets/pagination-toolbar-B955aa-d.3fd9249f7342.js +1 -0
  286. codex/static_root/assets/pagination-toolbar-B955aa-d.3fd9249f7342.js.br +0 -0
  287. codex/static_root/assets/pagination-toolbar-B955aa-d.3fd9249f7342.js.gz +0 -0
  288. codex/static_root/assets/pagination-toolbar-B955aa-d.js +1 -0
  289. codex/static_root/assets/pagination-toolbar-B955aa-d.js.br +0 -0
  290. codex/static_root/assets/pagination-toolbar-B955aa-d.js.gz +0 -0
  291. codex/static_root/assets/pdf-doc-DPDmmEEp.74cab27a76e1.js +35 -0
  292. codex/static_root/assets/pdf-doc-DPDmmEEp.74cab27a76e1.js.br +0 -0
  293. codex/static_root/assets/pdf-doc-DPDmmEEp.74cab27a76e1.js.gz +0 -0
  294. codex/static_root/assets/pdf-doc-DPDmmEEp.js +35 -0
  295. codex/static_root/assets/pdf-doc-DPDmmEEp.js.br +0 -0
  296. codex/static_root/assets/pdf-doc-DPDmmEEp.js.gz +0 -0
  297. codex/static_root/assets/reader-BuMh4x3f.f4d7f1c97387.js +2 -0
  298. codex/static_root/assets/reader-BuMh4x3f.f4d7f1c97387.js.br +0 -0
  299. codex/static_root/assets/reader-BuMh4x3f.f4d7f1c97387.js.gz +0 -0
  300. codex/static_root/assets/reader-BuMh4x3f.js +2 -0
  301. codex/static_root/assets/reader-BuMh4x3f.js.br +0 -0
  302. codex/static_root/assets/reader-BuMh4x3f.js.gz +0 -0
  303. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css +1 -0
  304. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css.br +0 -0
  305. codex/static_root/assets/reader-Dspy46e8.925a6b05bfcf.css.gz +0 -0
  306. codex/static_root/assets/reader-Dspy46e8.css +1 -0
  307. codex/static_root/assets/reader-Dspy46e8.css.br +0 -0
  308. codex/static_root/assets/reader-Dspy46e8.css.gz +0 -0
  309. codex/static_root/assets/{relation-chips-Bsc-gUxE.98e65384c3c9.css → relation-chips-D6T6FX7G.css} +1 -1
  310. codex/static_root/assets/relation-chips-D6T6FX7G.css.br +0 -0
  311. codex/static_root/assets/relation-chips-D6T6FX7G.css.gz +0 -0
  312. codex/static_root/assets/{relation-chips-Bsc-gUxE.css → relation-chips-D6T6FX7G.db095b2497e4.css} +1 -1
  313. codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.br +0 -0
  314. codex/static_root/assets/relation-chips-D6T6FX7G.db095b2497e4.css.gz +0 -0
  315. codex/static_root/assets/relation-chips-DN_pPmnS.684c4eae4bdb.js +1 -0
  316. codex/static_root/assets/relation-chips-DN_pPmnS.684c4eae4bdb.js.br +0 -0
  317. codex/static_root/assets/relation-chips-DN_pPmnS.684c4eae4bdb.js.gz +0 -0
  318. codex/static_root/assets/relation-chips-DN_pPmnS.js +1 -0
  319. codex/static_root/assets/relation-chips-DN_pPmnS.js.br +0 -0
  320. codex/static_root/assets/relation-chips-DN_pPmnS.js.gz +0 -0
  321. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css +1 -0
  322. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css.br +0 -0
  323. codex/static_root/assets/settings-drawer-BgUazs7O.7bbeb1fd98f1.css.gz +0 -0
  324. codex/static_root/assets/settings-drawer-BgUazs7O.css +1 -0
  325. codex/static_root/assets/settings-drawer-BgUazs7O.css.br +0 -0
  326. codex/static_root/assets/settings-drawer-BgUazs7O.css.gz +0 -0
  327. codex/static_root/assets/settings-drawer-D4FgDG4z.de28fd4ce82a.js +2 -0
  328. codex/static_root/assets/settings-drawer-D4FgDG4z.de28fd4ce82a.js.br +0 -0
  329. codex/static_root/assets/settings-drawer-D4FgDG4z.de28fd4ce82a.js.gz +0 -0
  330. codex/static_root/assets/settings-drawer-D4FgDG4z.js +2 -0
  331. codex/static_root/assets/settings-drawer-D4FgDG4z.js.br +0 -0
  332. codex/static_root/assets/settings-drawer-D4FgDG4z.js.gz +0 -0
  333. codex/static_root/assets/stats-tab-AwbCeW63.a95f7d9b2059.js +1 -0
  334. codex/static_root/assets/stats-tab-AwbCeW63.a95f7d9b2059.js.br +0 -0
  335. codex/static_root/assets/stats-tab-AwbCeW63.a95f7d9b2059.js.gz +0 -0
  336. codex/static_root/assets/stats-tab-AwbCeW63.js +1 -0
  337. codex/static_root/assets/stats-tab-AwbCeW63.js.br +0 -0
  338. codex/static_root/assets/stats-tab-AwbCeW63.js.gz +0 -0
  339. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css +1 -0
  340. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.br +2 -0
  341. codex/static_root/assets/stats-tab-TsyG3wH_.b93c080356fc.css.gz +0 -0
  342. codex/static_root/assets/stats-tab-TsyG3wH_.css +1 -0
  343. codex/static_root/assets/stats-tab-TsyG3wH_.css.br +2 -0
  344. codex/static_root/assets/stats-tab-TsyG3wH_.css.gz +0 -0
  345. codex/static_root/assets/task-tab-DeHQTHuz.5f967defca9f.js +1 -0
  346. codex/static_root/assets/task-tab-DeHQTHuz.5f967defca9f.js.br +0 -0
  347. codex/static_root/assets/task-tab-DeHQTHuz.5f967defca9f.js.gz +0 -0
  348. codex/static_root/assets/task-tab-DeHQTHuz.js +1 -0
  349. codex/static_root/assets/task-tab-DeHQTHuz.js.br +0 -0
  350. codex/static_root/assets/task-tab-DeHQTHuz.js.gz +0 -0
  351. codex/static_root/assets/to-case-kUm8NPpW.5b3369f511b8.js +1 -0
  352. codex/static_root/assets/to-case-kUm8NPpW.js +1 -0
  353. codex/static_root/assets/unauthorized-BXCbvRsL.bc44d7ba68b3.js +1 -0
  354. codex/static_root/assets/unauthorized-BXCbvRsL.bc44d7ba68b3.js.br +0 -0
  355. codex/static_root/assets/unauthorized-BXCbvRsL.bc44d7ba68b3.js.gz +0 -0
  356. codex/static_root/assets/unauthorized-BXCbvRsL.js +1 -0
  357. codex/static_root/assets/unauthorized-BXCbvRsL.js.br +0 -0
  358. codex/static_root/assets/unauthorized-BXCbvRsL.js.gz +0 -0
  359. codex/static_root/assets/{unauthorized-CibJYD8o.4c2de98c2b53.css → unauthorized-DWgytUow.ca2f13dbdbf5.css} +1 -1
  360. codex/static_root/assets/unauthorized-DWgytUow.ca2f13dbdbf5.css.br +0 -0
  361. codex/static_root/assets/unauthorized-DWgytUow.ca2f13dbdbf5.css.gz +0 -0
  362. codex/static_root/assets/{unauthorized-CibJYD8o.css → unauthorized-DWgytUow.css} +1 -1
  363. codex/static_root/assets/unauthorized-DWgytUow.css.br +0 -0
  364. codex/static_root/assets/unauthorized-DWgytUow.css.gz +0 -0
  365. codex/static_root/assets/user-tab-Dq4qYzgp.5d1b6c07edd0.js +1 -0
  366. codex/static_root/assets/user-tab-Dq4qYzgp.5d1b6c07edd0.js.br +0 -0
  367. codex/static_root/assets/user-tab-Dq4qYzgp.5d1b6c07edd0.js.gz +0 -0
  368. codex/static_root/assets/user-tab-Dq4qYzgp.js +1 -0
  369. codex/static_root/assets/user-tab-Dq4qYzgp.js.br +0 -0
  370. codex/static_root/assets/user-tab-Dq4qYzgp.js.gz +0 -0
  371. codex/static_root/js/choices-admin.248384ece3f6.json +1 -0
  372. codex/static_root/js/choices-admin.248384ece3f6.json.br +0 -0
  373. codex/static_root/js/choices-admin.248384ece3f6.json.gz +0 -0
  374. codex/static_root/js/choices-admin.json +1 -1
  375. codex/static_root/js/choices-admin.json.br +0 -0
  376. codex/static_root/js/choices-admin.json.gz +0 -0
  377. codex/static_root/js/choices.b60817ba0a93.json +1 -0
  378. codex/static_root/js/choices.b60817ba0a93.json.br +0 -0
  379. codex/static_root/js/choices.b60817ba0a93.json.gz +0 -0
  380. codex/static_root/js/choices.json +1 -1
  381. codex/static_root/js/choices.json.br +0 -0
  382. codex/static_root/js/choices.json.gz +0 -0
  383. codex/static_root/manifest.b5fe5d7ef44e.json +641 -0
  384. codex/static_root/manifest.b5fe5d7ef44e.json.br +0 -0
  385. codex/static_root/manifest.b5fe5d7ef44e.json.gz +0 -0
  386. codex/static_root/manifest.json +298 -279
  387. codex/static_root/manifest.json.br +0 -0
  388. codex/static_root/manifest.json.gz +0 -0
  389. codex/static_root/staticfiles.json +1 -1
  390. codex/status_controller.py +2 -11
  391. codex/urls/api/auth.py +1 -2
  392. codex/urls/api/browser.py +4 -13
  393. codex/urls/api/reader.py +9 -3
  394. codex/urls/api/v3.py +0 -2
  395. codex/urls/opds/binary.py +1 -1
  396. codex/views/admin/api_key.py +8 -7
  397. codex/views/admin/flag.py +7 -2
  398. codex/views/admin/group.py +6 -2
  399. codex/views/admin/library.py +37 -44
  400. codex/views/admin/stats.py +83 -20
  401. codex/views/admin/tasks.py +12 -26
  402. codex/views/admin/user.py +9 -3
  403. codex/views/auth.py +54 -31
  404. codex/views/bookmark.py +72 -92
  405. codex/views/browser/base.py +90 -42
  406. codex/views/browser/browser.py +371 -92
  407. codex/views/browser/{annotations.py → browser_annotations.py} +121 -67
  408. codex/views/browser/browser_breadcrumbs.py +175 -0
  409. codex/views/browser/browser_order_by.py +63 -0
  410. codex/views/browser/choices.py +85 -38
  411. codex/views/browser/const.py +3 -0
  412. codex/views/browser/filters/annotations.py +19 -87
  413. codex/views/browser/filters/bookmark.py +12 -24
  414. codex/views/browser/filters/field.py +6 -8
  415. codex/views/browser/filters/group.py +14 -35
  416. codex/views/browser/filters/search.py +20 -31
  417. codex/views/browser/metadata.py +73 -112
  418. codex/views/browser/session.py +12 -0
  419. codex/views/const.py +0 -140
  420. codex/views/cover.py +77 -0
  421. codex/views/download.py +8 -5
  422. codex/views/frontend.py +2 -4
  423. codex/views/opds/authentication_v1.py +45 -46
  424. codex/views/opds/binary.py +10 -5
  425. codex/views/opds/const.py +0 -13
  426. codex/views/opds/urls.py +4 -6
  427. codex/views/opds/util.py +12 -4
  428. codex/views/opds/v1/entry/links.py +33 -18
  429. codex/views/opds/v1/facets.py +7 -7
  430. codex/views/opds/v1/feed.py +45 -55
  431. codex/views/opds/v1/links.py +5 -7
  432. codex/views/opds/v1/opensearch_v1.py +6 -2
  433. codex/views/opds/v2/feed.py +26 -25
  434. codex/views/opds/v2/links.py +2 -4
  435. codex/views/opds/v2/publications.py +54 -34
  436. codex/views/opds/v2/top_links.py +2 -2
  437. codex/views/reader/page.py +8 -15
  438. codex/views/reader/reader.py +322 -19
  439. codex/views/reader/{settings.py → session.py} +2 -4
  440. codex/views/session.py +102 -83
  441. codex/views/template.py +3 -3
  442. codex/views/version.py +2 -2
  443. codex/websockets/consumers.py +10 -14
  444. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/METADATA +15 -22
  445. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/RECORD +448 -466
  446. codex/librarian/importer/cache.py +0 -93
  447. codex/librarian/importer/create_covers.py +0 -96
  448. codex/librarian/importer/importer.py +0 -96
  449. codex/librarian/importer/init.py +0 -265
  450. codex/librarian/importer/link_covers.py +0 -73
  451. codex/librarian/importer/query_covers.py +0 -52
  452. codex/migrations/0027_import_order_and_covers.py +0 -280
  453. codex/serializers/browser/mtime.py +0 -21
  454. codex/serializers/fields.py +0 -149
  455. codex/serializers/settings.py +0 -12
  456. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js +0 -1
  457. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.br +0 -0
  458. codex/static_root/assets/VCheckbox-DanrzdHo.8ec5e2094cbf.js.gz +0 -0
  459. codex/static_root/assets/VCheckbox-DanrzdHo.js +0 -1
  460. codex/static_root/assets/VCheckbox-DanrzdHo.js.br +0 -0
  461. codex/static_root/assets/VCheckbox-DanrzdHo.js.gz +0 -0
  462. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.br +0 -0
  463. codex/static_root/assets/VCheckboxBtn-DxNOKONG.5ab34c4c47aa.js.gz +0 -0
  464. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.br +0 -0
  465. codex/static_root/assets/VCheckboxBtn-DxNOKONG.js.gz +0 -0
  466. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js +0 -1
  467. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.br +0 -0
  468. codex/static_root/assets/VCombobox-DDvdoPTG.11d080e8edd7.js.gz +0 -0
  469. codex/static_root/assets/VCombobox-DDvdoPTG.js +0 -1
  470. codex/static_root/assets/VCombobox-DDvdoPTG.js.br +0 -0
  471. codex/static_root/assets/VCombobox-DDvdoPTG.js.gz +0 -0
  472. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js +0 -1
  473. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.br +0 -0
  474. codex/static_root/assets/VDialog-Bd5dN_E1.457666d7fce1.js.gz +0 -0
  475. codex/static_root/assets/VDialog-Bd5dN_E1.js +0 -1
  476. codex/static_root/assets/VDialog-Bd5dN_E1.js.br +0 -0
  477. codex/static_root/assets/VDialog-Bd5dN_E1.js.gz +0 -0
  478. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.br +0 -0
  479. codex/static_root/assets/VDialog-lQ13FnRR.1c801ad756b2.css.gz +0 -0
  480. codex/static_root/assets/VDialog-lQ13FnRR.css.br +0 -0
  481. codex/static_root/assets/VDialog-lQ13FnRR.css.gz +0 -0
  482. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js +0 -1
  483. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.br +0 -0
  484. codex/static_root/assets/VExpansionPanels-DqTuYpTR.12673cf9f391.js.gz +0 -0
  485. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js +0 -1
  486. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.br +0 -0
  487. codex/static_root/assets/VExpansionPanels-DqTuYpTR.js.gz +0 -0
  488. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js +0 -1
  489. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.br +0 -0
  490. codex/static_root/assets/VRadioGroup-DKb8XPr-.3cf6bf5bf3bc.js.gz +0 -0
  491. codex/static_root/assets/VRadioGroup-DKb8XPr-.js +0 -1
  492. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.br +0 -0
  493. codex/static_root/assets/VRadioGroup-DKb8XPr-.js.gz +0 -0
  494. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js +0 -1
  495. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.br +0 -0
  496. codex/static_root/assets/VSelect-C_yPbyCG.08bd6b53a7ce.js.gz +0 -0
  497. codex/static_root/assets/VSelect-C_yPbyCG.js +0 -1
  498. codex/static_root/assets/VSelect-C_yPbyCG.js.br +0 -0
  499. codex/static_root/assets/VSelect-C_yPbyCG.js.gz +0 -0
  500. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js +0 -1
  501. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.br +0 -0
  502. codex/static_root/assets/VSelectionControl-CmFPvGMS.802c9b3e6e28.js.gz +0 -0
  503. codex/static_root/assets/VSelectionControl-CmFPvGMS.js +0 -1
  504. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.br +0 -0
  505. codex/static_root/assets/VSelectionControl-CmFPvGMS.js.gz +0 -0
  506. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js +0 -1
  507. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.br +0 -0
  508. codex/static_root/assets/VSlideGroup-D5FZWsM1.a47491fe3e6d.js.gz +0 -0
  509. codex/static_root/assets/VSlideGroup-D5FZWsM1.js +0 -1
  510. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.br +0 -0
  511. codex/static_root/assets/VSlideGroup-D5FZWsM1.js.gz +0 -0
  512. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.br +0 -0
  513. codex/static_root/assets/VTable-2RHFqfg6.f0f2106b158b.js.gz +0 -0
  514. codex/static_root/assets/VTable-2RHFqfg6.js.br +0 -0
  515. codex/static_root/assets/VTable-2RHFqfg6.js.gz +0 -0
  516. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css +0 -1
  517. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.br +0 -0
  518. codex/static_root/assets/VTextField-BssVoDhB.4cc388b4aa3c.css.gz +0 -0
  519. codex/static_root/assets/VTextField-BssVoDhB.css +0 -1
  520. codex/static_root/assets/VTextField-BssVoDhB.css.br +0 -0
  521. codex/static_root/assets/VTextField-BssVoDhB.css.gz +0 -0
  522. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js +0 -1
  523. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.br +0 -0
  524. codex/static_root/assets/VTextField-o1N9ylIb.7fffaeff8d40.js.gz +0 -0
  525. codex/static_root/assets/VTextField-o1N9ylIb.js +0 -1
  526. codex/static_root/assets/VTextField-o1N9ylIb.js.br +0 -0
  527. codex/static_root/assets/VTextField-o1N9ylIb.js.gz +0 -0
  528. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js +0 -1
  529. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.br +0 -0
  530. codex/static_root/assets/VWindowItem-C_zvuz9C.663fa48efea4.js.gz +0 -0
  531. codex/static_root/assets/VWindowItem-C_zvuz9C.js +0 -1
  532. codex/static_root/assets/VWindowItem-C_zvuz9C.js.br +0 -0
  533. codex/static_root/assets/VWindowItem-C_zvuz9C.js.gz +0 -0
  534. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.br +0 -0
  535. codex/static_root/assets/admin-B8Bp2Uih.82c98714bcf1.css.gz +0 -0
  536. codex/static_root/assets/admin-B8Bp2Uih.css.br +0 -0
  537. codex/static_root/assets/admin-B8Bp2Uih.css.gz +0 -0
  538. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js +0 -1
  539. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.br +0 -0
  540. codex/static_root/assets/admin-DHyHEWZ3.7a8015456c0f.js.gz +0 -0
  541. codex/static_root/assets/admin-DHyHEWZ3.js +0 -1
  542. codex/static_root/assets/admin-DHyHEWZ3.js.br +0 -0
  543. codex/static_root/assets/admin-DHyHEWZ3.js.gz +0 -0
  544. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js +0 -30
  545. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.br +0 -0
  546. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.19507a95375b.js.gz +0 -0
  547. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js +0 -30
  548. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.br +0 -0
  549. codex/static_root/assets/admin-drawer-panel-BXpIDQXM.js.gz +0 -0
  550. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css +0 -1
  551. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.br +0 -0
  552. codex/static_root/assets/admin-drawer-panel-mne3FIj6.561b3f75fe65.css.gz +0 -0
  553. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css +0 -1
  554. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.br +0 -0
  555. codex/static_root/assets/admin-drawer-panel-mne3FIj6.css.gz +0 -0
  556. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js +0 -1
  557. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.br +0 -0
  558. codex/static_root/assets/browser-D0Vjmmp_.a1bfaf48d65f.js.gz +0 -0
  559. codex/static_root/assets/browser-D0Vjmmp_.js +0 -1
  560. codex/static_root/assets/browser-D0Vjmmp_.js.br +0 -0
  561. codex/static_root/assets/browser-D0Vjmmp_.js.gz +0 -0
  562. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css +0 -1
  563. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.br +0 -0
  564. codex/static_root/assets/browser-D7QQDneO.155cb612ed0c.css.gz +0 -0
  565. codex/static_root/assets/browser-D7QQDneO.css +0 -1
  566. codex/static_root/assets/browser-D7QQDneO.css.br +0 -0
  567. codex/static_root/assets/browser-D7QQDneO.css.gz +0 -0
  568. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css +0 -1
  569. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.br +0 -0
  570. codex/static_root/assets/change-password-dialog-0u6IJA87.5f9a9aa573b7.css.gz +0 -0
  571. codex/static_root/assets/change-password-dialog-0u6IJA87.css +0 -1
  572. codex/static_root/assets/change-password-dialog-0u6IJA87.css.br +0 -0
  573. codex/static_root/assets/change-password-dialog-0u6IJA87.css.gz +0 -0
  574. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js +0 -1
  575. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.br +0 -0
  576. codex/static_root/assets/change-password-dialog-BBsJLPXZ.e642f7e2b96f.js.gz +0 -0
  577. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js +0 -1
  578. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.br +0 -0
  579. codex/static_root/assets/change-password-dialog-BBsJLPXZ.js.gz +0 -0
  580. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js +0 -1
  581. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.br +0 -0
  582. codex/static_root/assets/confirm-dialog-DCKvg3ai.2a3277b3c147.js.gz +0 -0
  583. codex/static_root/assets/confirm-dialog-DCKvg3ai.js +0 -1
  584. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.br +0 -0
  585. codex/static_root/assets/confirm-dialog-DCKvg3ai.js.gz +0 -0
  586. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js +0 -1
  587. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.bec27f144aca.js.br +0 -0
  588. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js +0 -1
  589. codex/static_root/assets/copy-to-clipboard-DoUvDJVx.js.br +0 -0
  590. codex/static_root/assets/datetime-column-DeCthByU.1f3bf499e063.css +0 -1
  591. codex/static_root/assets/datetime-column-DeCthByU.css +0 -1
  592. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js +0 -1
  593. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.br +0 -0
  594. codex/static_root/assets/datetime-column-jHKA_uNm.039c7da2036f.js.gz +0 -0
  595. codex/static_root/assets/datetime-column-jHKA_uNm.js +0 -1
  596. codex/static_root/assets/datetime-column-jHKA_uNm.js.br +0 -0
  597. codex/static_root/assets/datetime-column-jHKA_uNm.js.gz +0 -0
  598. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js +0 -1
  599. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.br +0 -0
  600. codex/static_root/assets/filter-DgPg2ts9.af0fcf0888c6.js.gz +0 -0
  601. codex/static_root/assets/filter-DgPg2ts9.js +0 -1
  602. codex/static_root/assets/filter-DgPg2ts9.js.br +0 -0
  603. codex/static_root/assets/filter-DgPg2ts9.js.gz +0 -0
  604. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js +0 -1
  605. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.br +0 -0
  606. codex/static_root/assets/flag-tab-9qxOALxP.f89bc9891671.js.gz +0 -0
  607. codex/static_root/assets/flag-tab-9qxOALxP.js +0 -1
  608. codex/static_root/assets/flag-tab-9qxOALxP.js.br +0 -0
  609. codex/static_root/assets/flag-tab-9qxOALxP.js.gz +0 -0
  610. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css +0 -1
  611. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.br +0 -0
  612. codex/static_root/assets/flag-tab-BNwbLfrN.b755a99fff7e.css.gz +0 -0
  613. codex/static_root/assets/flag-tab-BNwbLfrN.css +0 -1
  614. codex/static_root/assets/flag-tab-BNwbLfrN.css.br +0 -0
  615. codex/static_root/assets/flag-tab-BNwbLfrN.css.gz +0 -0
  616. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.br +0 -0
  617. codex/static_root/assets/group-tab-D5vWrihT.1afb2ce453ff.js.gz +0 -0
  618. codex/static_root/assets/group-tab-D5vWrihT.js.br +0 -0
  619. codex/static_root/assets/group-tab-D5vWrihT.js.gz +0 -0
  620. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js +0 -1
  621. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.br +0 -0
  622. codex/static_root/assets/http-error-B4FHoKfs.141fdae409bc.js.gz +0 -0
  623. codex/static_root/assets/http-error-B4FHoKfs.js +0 -1
  624. codex/static_root/assets/http-error-B4FHoKfs.js.br +0 -0
  625. codex/static_root/assets/http-error-B4FHoKfs.js.gz +0 -0
  626. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css +0 -1
  627. codex/static_root/assets/http-error-DKulXuTl.95e42988d5d5.css.gz +0 -0
  628. codex/static_root/assets/http-error-DKulXuTl.css +0 -1
  629. codex/static_root/assets/http-error-DKulXuTl.css.gz +0 -0
  630. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css +0 -1
  631. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.br +0 -0
  632. codex/static_root/assets/library-tab-BN0SfPcH.913e236f625e.css.gz +0 -0
  633. codex/static_root/assets/library-tab-BN0SfPcH.css +0 -1
  634. codex/static_root/assets/library-tab-BN0SfPcH.css.br +0 -0
  635. codex/static_root/assets/library-tab-BN0SfPcH.css.gz +0 -0
  636. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js +0 -1
  637. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.br +0 -0
  638. codex/static_root/assets/library-tab-BWo0cmzk.0e3d67d0c41a.js.gz +0 -0
  639. codex/static_root/assets/library-tab-BWo0cmzk.js +0 -1
  640. codex/static_root/assets/library-tab-BWo0cmzk.js.br +0 -0
  641. codex/static_root/assets/library-tab-BWo0cmzk.js.gz +0 -0
  642. codex/static_root/assets/main-Ztp855PW.css.br +0 -0
  643. codex/static_root/assets/main-Ztp855PW.d46d718fac45.css.br +0 -0
  644. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js +0 -32
  645. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.br +0 -0
  646. codex/static_root/assets/main-ipmlipkF.5e60e6e8e447.js.gz +0 -0
  647. codex/static_root/assets/main-ipmlipkF.js +0 -32
  648. codex/static_root/assets/main-ipmlipkF.js.br +0 -0
  649. codex/static_root/assets/main-ipmlipkF.js.gz +0 -0
  650. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css +0 -1
  651. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.br +0 -0
  652. codex/static_root/assets/pagination-toolbar-BA9ifTed.b4865334ee08.css.gz +0 -0
  653. codex/static_root/assets/pagination-toolbar-BA9ifTed.css +0 -1
  654. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.br +0 -0
  655. codex/static_root/assets/pagination-toolbar-BA9ifTed.css.gz +0 -0
  656. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js +0 -1
  657. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.br +0 -0
  658. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.b3341b8028df.js.gz +0 -0
  659. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js +0 -1
  660. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.br +0 -0
  661. codex/static_root/assets/pagination-toolbar-kZ-Xdv8c.js.gz +0 -0
  662. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js +0 -305
  663. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.br +0 -0
  664. codex/static_root/assets/pdf-doc-C2StaYUz.cb848834dbe1.js.gz +0 -0
  665. codex/static_root/assets/pdf-doc-C2StaYUz.js +0 -305
  666. codex/static_root/assets/pdf-doc-C2StaYUz.js.br +0 -0
  667. codex/static_root/assets/pdf-doc-C2StaYUz.js.gz +0 -0
  668. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js +0 -2
  669. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.br +0 -0
  670. codex/static_root/assets/reader-CCnq3j1-.b6b38ed5521e.js.gz +0 -0
  671. codex/static_root/assets/reader-CCnq3j1-.js +0 -2
  672. codex/static_root/assets/reader-CCnq3j1-.js.br +0 -0
  673. codex/static_root/assets/reader-CCnq3j1-.js.gz +0 -0
  674. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css +0 -1
  675. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.br +0 -0
  676. codex/static_root/assets/reader-CqXFa_gE.78267e9de0c2.css.gz +0 -0
  677. codex/static_root/assets/reader-CqXFa_gE.css +0 -1
  678. codex/static_root/assets/reader-CqXFa_gE.css.br +0 -0
  679. codex/static_root/assets/reader-CqXFa_gE.css.gz +0 -0
  680. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.br +0 -0
  681. codex/static_root/assets/relation-chips-Bsc-gUxE.98e65384c3c9.css.gz +0 -0
  682. codex/static_root/assets/relation-chips-Bsc-gUxE.css.br +0 -0
  683. codex/static_root/assets/relation-chips-Bsc-gUxE.css.gz +0 -0
  684. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js +0 -1
  685. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.br +0 -0
  686. codex/static_root/assets/relation-chips-C9ysW0tU.670f1d1f273f.js.gz +0 -0
  687. codex/static_root/assets/relation-chips-C9ysW0tU.js +0 -1
  688. codex/static_root/assets/relation-chips-C9ysW0tU.js.br +0 -0
  689. codex/static_root/assets/relation-chips-C9ysW0tU.js.gz +0 -0
  690. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js +0 -2
  691. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.br +0 -0
  692. codex/static_root/assets/settings-drawer-C0ofzAhW.c0def8f383cb.js.gz +0 -0
  693. codex/static_root/assets/settings-drawer-C0ofzAhW.js +0 -2
  694. codex/static_root/assets/settings-drawer-C0ofzAhW.js.br +0 -0
  695. codex/static_root/assets/settings-drawer-C0ofzAhW.js.gz +0 -0
  696. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css +0 -1
  697. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.br +0 -0
  698. codex/static_root/assets/settings-drawer-nZ9HvKSZ.01744e131806.css.gz +0 -0
  699. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css +0 -1
  700. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.br +0 -0
  701. codex/static_root/assets/settings-drawer-nZ9HvKSZ.css.gz +0 -0
  702. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css +0 -1
  703. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.br +0 -0
  704. codex/static_root/assets/stats-tab-B4yKuY0c.a5728396494b.css.gz +0 -0
  705. codex/static_root/assets/stats-tab-B4yKuY0c.css +0 -1
  706. codex/static_root/assets/stats-tab-B4yKuY0c.css.br +0 -0
  707. codex/static_root/assets/stats-tab-B4yKuY0c.css.gz +0 -0
  708. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js +0 -1
  709. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.br +0 -0
  710. codex/static_root/assets/stats-tab-BqJj7j1w.38a3459d61ea.js.gz +0 -0
  711. codex/static_root/assets/stats-tab-BqJj7j1w.js +0 -1
  712. codex/static_root/assets/stats-tab-BqJj7j1w.js.br +0 -0
  713. codex/static_root/assets/stats-tab-BqJj7j1w.js.gz +0 -0
  714. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js +0 -1
  715. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.br +0 -0
  716. codex/static_root/assets/task-tab-BsPzNk8S.e00630a60b43.js.gz +0 -0
  717. codex/static_root/assets/task-tab-BsPzNk8S.js +0 -1
  718. codex/static_root/assets/task-tab-BsPzNk8S.js.br +0 -0
  719. codex/static_root/assets/task-tab-BsPzNk8S.js.gz +0 -0
  720. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js +0 -1
  721. codex/static_root/assets/to-case-KvqtSug2.9c02da2e47c7.js.br +0 -0
  722. codex/static_root/assets/to-case-KvqtSug2.js +0 -1
  723. codex/static_root/assets/to-case-KvqtSug2.js.br +0 -0
  724. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.br +0 -0
  725. codex/static_root/assets/unauthorized-CibJYD8o.4c2de98c2b53.css.gz +0 -0
  726. codex/static_root/assets/unauthorized-CibJYD8o.css.br +0 -0
  727. codex/static_root/assets/unauthorized-CibJYD8o.css.gz +0 -0
  728. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js +0 -1
  729. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.br +0 -0
  730. codex/static_root/assets/unauthorized-DwSdNzX2.f418e69f3afe.js.gz +0 -0
  731. codex/static_root/assets/unauthorized-DwSdNzX2.js +0 -1
  732. codex/static_root/assets/unauthorized-DwSdNzX2.js.br +0 -0
  733. codex/static_root/assets/unauthorized-DwSdNzX2.js.gz +0 -0
  734. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js +0 -1
  735. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.br +0 -0
  736. codex/static_root/assets/user-tab-DrJOb9Ys.083d993726d8.js.gz +0 -0
  737. codex/static_root/assets/user-tab-DrJOb9Ys.js +0 -1
  738. codex/static_root/assets/user-tab-DrJOb9Ys.js.br +0 -0
  739. codex/static_root/assets/user-tab-DrJOb9Ys.js.gz +0 -0
  740. codex/static_root/js/choices-admin.3521e2a863df.json +0 -1
  741. codex/static_root/js/choices-admin.3521e2a863df.json.br +0 -0
  742. codex/static_root/js/choices-admin.3521e2a863df.json.gz +0 -0
  743. codex/static_root/js/choices.2f6b0359e1ef.json +0 -1
  744. codex/static_root/js/choices.2f6b0359e1ef.json.br +0 -0
  745. codex/static_root/js/choices.2f6b0359e1ef.json.gz +0 -0
  746. codex/static_root/manifest.1c84116d9a0a.json +0 -622
  747. codex/static_root/manifest.1c84116d9a0a.json.br +0 -0
  748. codex/static_root/manifest.1c84116d9a0a.json.gz +0 -0
  749. codex/util.py +0 -12
  750. codex/views/admin/auth.py +0 -28
  751. codex/views/browser/breadcrumbs.py +0 -202
  752. codex/views/browser/cover.py +0 -165
  753. codex/views/browser/mtime.py +0 -61
  754. codex/views/browser/order_by.py +0 -65
  755. codex/views/browser/paginate.py +0 -106
  756. codex/views/browser/settings.py +0 -66
  757. codex/views/browser/title.py +0 -48
  758. codex/views/browser/validate.py +0 -161
  759. codex/views/opds/auth.py +0 -17
  760. codex/views/public.py +0 -36
  761. codex/views/reader/arcs.py +0 -92
  762. codex/views/reader/books.py +0 -181
  763. codex/views/reader/init.py +0 -125
  764. codex/views/settings.py +0 -47
  765. codex/views/util.py +0 -77
  766. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/LICENSE +0 -0
  767. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/WHEEL +0 -0
  768. {codex-1.6.0.dist-info → codex-1.6.0a1.dist-info}/entry_points.txt +0 -0
@@ -10,7 +10,6 @@ from codex.librarian.importer.const import (
10
10
  DICT_MODEL_REL_LINK_MAP,
11
11
  FOLDERS_FIELD,
12
12
  IMPRINT,
13
- M2M_MDS,
14
13
  PARENT_FOLDER,
15
14
  PUBLISHER,
16
15
  SERIES,
@@ -18,8 +17,7 @@ from codex.librarian.importer.const import (
18
17
  STORY_ARCS_METADATA_KEY,
19
18
  VOLUME,
20
19
  )
21
- from codex.librarian.importer.link_covers import LinkCoversImporter
22
- from codex.librarian.importer.status import ImportStatusTypes
20
+ from codex.librarian.importer.status import ImportStatusTypes, status_notify
23
21
  from codex.models import (
24
22
  Comic,
25
23
  Folder,
@@ -29,10 +27,10 @@ from codex.models import (
29
27
  Volume,
30
28
  )
31
29
  from codex.models.named import Identifier
32
- from codex.status import Status
30
+ from codex.threads import QueuedThread
33
31
 
34
32
 
35
- class LinkComicsImporter(LinkCoversImporter):
33
+ class LinkComicsMixin(QueuedThread):
36
34
  """Link comics methods."""
37
35
 
38
36
  @staticmethod
@@ -42,12 +40,13 @@ class LinkComicsImporter(LinkCoversImporter):
42
40
  return md.get(field_name, group_class.DEFAULT_NAME)
43
41
 
44
42
  @classmethod
45
- def get_comic_fk_links(cls, md, path):
43
+ def get_comic_fk_links(cls, md, library, path):
46
44
  """Get links for all foreign keys for creating and updating."""
47
45
  publisher_name = cls._get_group_name(Publisher, md)
48
46
  imprint_name = cls._get_group_name(Imprint, md)
49
47
  series_name = cls._get_group_name(Series, md)
50
48
  volume_name = cls._get_group_name(Volume, md)
49
+ md["library"] = library
51
50
  md[PUBLISHER] = Publisher.objects.get(name=publisher_name)
52
51
  md[IMPRINT] = Imprint.objects.get(
53
52
  publisher__name=publisher_name, name=imprint_name
@@ -123,15 +122,13 @@ class LinkComicsImporter(LinkCoversImporter):
123
122
  result = frozenset(pks)
124
123
  all_m2m_links[key][comic_pk] = result
125
124
 
126
- def _link_comic_m2m_fields(self):
125
+ def _link_comic_m2m_fields(self, m2m_mds):
127
126
  """Get the complete m2m field data to create."""
128
127
  all_m2m_links = {}
129
- comic_paths = frozenset(self.metadata.get(M2M_MDS, {}).keys())
130
- if not comic_paths:
131
- return all_m2m_links
128
+ comic_paths = frozenset(m2m_mds.keys())
132
129
  comics = Comic.objects.filter(path__in=comic_paths).values_list("pk", "path")
133
130
  for comic_pk, comic_path in comics:
134
- md = self.metadata[M2M_MDS][comic_path]
131
+ md = m2m_mds[comic_path]
135
132
  link_data = (all_m2m_links, md, comic_pk)
136
133
  self._link_prepare_special_m2ms(
137
134
  link_data, FOLDERS_FIELD, Folder, self._get_link_folders_filter
@@ -144,7 +141,6 @@ class LinkComicsImporter(LinkCoversImporter):
144
141
  self._link_prepare_special_m2ms(link_data, field_name, model, method)
145
142
 
146
143
  self._link_named_m2ms(all_m2m_links, comic_pk, md)
147
- self.metadata.pop(M2M_MDS)
148
144
  return all_m2m_links
149
145
 
150
146
  def _query_relation_adjustments(
@@ -206,9 +202,10 @@ class LinkComicsImporter(LinkCoversImporter):
206
202
  tms, all_del_pks = self._query_relation_adjustments(
207
203
  m2m_links, ThroughModel, through_field_id_name, status
208
204
  )
209
- status.total = status.total or 0
210
- status.total += len(tms) + len(all_del_pks)
211
- self.status_controller.update(status)
205
+ if status:
206
+ status.total = status.total or 0
207
+ status.total += len(tms) + len(all_del_pks)
208
+ self.status_controller.update(status)
212
209
 
213
210
  update_fields = ("comic_id", through_field_id_name)
214
211
  ThroughModel.objects.bulk_create(
@@ -219,9 +216,10 @@ class LinkComicsImporter(LinkCoversImporter):
219
216
  )
220
217
  if created_count := len(tms):
221
218
  self.log.info(f"Linked {created_count} new {field_name} to altered comics.")
222
- status.complete = status.complete or 0
223
- status.complete += created_count
224
- self.status_controller.update(status)
219
+ if status:
220
+ status.complete = status.complete or 0
221
+ status.complete += created_count
222
+ self.status_controller.update(status)
225
223
 
226
224
  if del_count := len(all_del_pks):
227
225
  del_qs = ThroughModel.objects.filter(pk__in=all_del_pks)
@@ -229,16 +227,19 @@ class LinkComicsImporter(LinkCoversImporter):
229
227
  self.log.info(
230
228
  f"Deleted {del_count} stale {field_name} relations for altered comics.",
231
229
  )
232
- status.complete = status.complete or 0
233
- status.complete += del_count
234
- self.status_controller.update(status)
230
+ if status:
231
+ status.complete = status.complete or 0
232
+ status.complete += del_count
233
+ self.status_controller.update(status)
235
234
  return created_count, del_count
236
235
 
237
- def bulk_query_and_link_comic_m2m_fields(self):
236
+ @status_notify(status_type=ImportStatusTypes.LINK_M2M_FIELDS, updates=False)
237
+ def bulk_query_and_link_comic_m2m_fields(self, all_m2m_mds, status=None):
238
238
  """Combine query and bulk link into a batch."""
239
- status = Status(ImportStatusTypes.LINK_M2M_FIELDS)
240
- self.status_controller.start(status)
241
- all_m2m_links = self._link_comic_m2m_fields()
239
+ if status:
240
+ status.complete = 0
241
+ status.total = 0
242
+ all_m2m_links = self._link_comic_m2m_fields(all_m2m_mds)
242
243
  created_total = 0
243
244
  del_total = 0
244
245
  for field_name, m2m_links in all_m2m_links.items():
@@ -255,5 +256,4 @@ class LinkComicsImporter(LinkCoversImporter):
255
256
  self.log.info(f"Linked {created_total} comics to tags.")
256
257
  if del_total:
257
258
  self.log.info(f"Deleted {del_total} stale relations for altered comics.")
258
- self.status_controller.finish(status)
259
259
  return created_total + del_total
@@ -4,54 +4,56 @@ from pathlib import Path
4
4
 
5
5
  from django.db.models.functions import Now
6
6
 
7
- from codex.librarian.importer.aggregate import AggregateMetadataImporter
8
7
  from codex.librarian.importer.const import (
9
8
  BULK_UPDATE_FOLDER_MODIFIED_FIELDS,
10
- CLASS_CUSTOM_COVER_GROUP_MAP,
11
- CUSTOM_COVER_UPDATE_FIELDS,
12
9
  FOLDERS_FIELD,
13
- LINK_COVER_PKS,
14
10
  MOVED_BULK_COMIC_UPDATE_FIELDS,
15
11
  MOVED_BULK_FOLDER_UPDATE_FIELDS,
16
12
  PARENT_FOLDER,
17
13
  )
18
- from codex.librarian.importer.status import ImportStatusTypes
19
- from codex.models import Comic, CustomCover, Folder
20
- from codex.status import Status
14
+ from codex.librarian.importer.create_comics import CreateComicsMixin
15
+ from codex.librarian.importer.create_fks import (
16
+ CreateForeignKeysMixin,
17
+ )
18
+ from codex.librarian.importer.query_fks import QueryForeignKeysMixin
19
+ from codex.librarian.importer.status import ImportStatusTypes, status_notify
20
+ from codex.models import Comic, Folder, Library
21
21
 
22
22
 
23
- class MovedImporter(AggregateMetadataImporter):
23
+ class MovedMixin(CreateComicsMixin, CreateForeignKeysMixin, QueryForeignKeysMixin):
24
24
  """Methods for moving comics and folders."""
25
25
 
26
- def _bulk_comics_moved(self):
26
+ @status_notify(status_type=ImportStatusTypes.FILES_MOVED, updates=False)
27
+ def _bulk_comics_moved(self, moved_paths, library, status=None):
27
28
  """Move comcis."""
28
- num_files_moved = len(self.task.files_moved)
29
- if not num_files_moved:
30
- return
31
- status = Status(ImportStatusTypes.FILES_MOVED, 0, num_files_moved)
32
- self.status_controller.start(status)
29
+ count = 0
30
+ if not moved_paths:
31
+ return count
33
32
 
34
33
  # Prepare FKs
35
34
  create_folder_paths = set()
36
- self.query_missing_folder_paths(create_folder_paths, status)
37
- self.bulk_folders_create(frozenset(create_folder_paths), status)
35
+ self.query_missing_folder_paths(
36
+ moved_paths.values(), library.path, create_folder_paths, status=status
37
+ )
38
+ self.bulk_folders_create(create_folder_paths, library, status=status)
38
39
 
39
40
  # Update Comics
40
41
  comics = Comic.objects.filter(
41
- library=self.library, path__in=self.task.files_moved.keys()
42
+ library=library, path__in=moved_paths.keys()
42
43
  ).only("pk", "path", PARENT_FOLDER, FOLDERS_FIELD)
43
44
 
44
45
  folder_m2m_links = {}
46
+ now = Now()
45
47
  updated_comics = []
46
48
  for comic in comics.iterator():
47
49
  try:
48
- new_path = self.task.files_moved[comic.path]
50
+ new_path = moved_paths[comic.path]
49
51
  comic.path = new_path
50
52
  new_path = Path(new_path)
51
53
  comic.parent_folder = Folder.objects.get( # type: ignore
52
54
  path=new_path.parent
53
55
  )
54
- comic.updated_at = Now()
56
+ comic.updated_at = now
55
57
  comic.presave()
56
58
  folder_m2m_links[comic.pk] = Folder.objects.filter(
57
59
  path__in=new_path.parents
@@ -59,88 +61,19 @@ class MovedImporter(AggregateMetadataImporter):
59
61
  updated_comics.append(comic)
60
62
  except Exception:
61
63
  self.log.exception(f"moving {comic.path}")
62
- self.task.files_moved = {}
63
64
 
64
65
  Comic.objects.bulk_update(updated_comics, MOVED_BULK_COMIC_UPDATE_FIELDS)
65
66
 
66
67
  # Update m2m field
67
68
  if folder_m2m_links:
68
- self.bulk_fix_comic_m2m_field(FOLDERS_FIELD, folder_m2m_links, status)
69
+ self.bulk_fix_comic_m2m_field(FOLDERS_FIELD, folder_m2m_links, None)
69
70
  count = len(comics)
70
71
  if count:
71
72
  self.log.info(f"Moved {count} comics.")
72
73
 
73
- self.changed += count
74
- self.status_controller.finish(status)
75
-
76
- def _bulk_covers_moved_prepare(self, status):
77
- """Create an update map for bulk update."""
78
- covers = CustomCover.objects.filter(
79
- library=self.library, path__in=self.task.covers_moved.keys()
80
- ).only("pk", "path")
81
-
82
- if status:
83
- status.total = covers.count()
84
-
85
- moved_covers = []
86
- unlink_pks = set()
87
- for cover in covers.iterator():
88
- try:
89
- new_path = self.task.covers_moved[cover.path]
90
- cover.path = new_path
91
- new_path = Path(new_path)
92
- cover.updated_at = Now()
93
- cover.presave()
94
- moved_covers.append(cover)
95
- unlink_pks.add(cover.pk)
96
- except Exception:
97
- self.log.exception(f"moving {cover.path}")
98
- return moved_covers, unlink_pks
99
-
100
- def _bulk_covers_moved_unlink(self, unlink_pks):
101
- """Unlink moved covers because they could have moved between group dirs."""
102
- if not unlink_pks:
103
- return
104
- self.log.debug(f"Unlinking {len(unlink_pks)} moved custom covers.")
105
- for model in CLASS_CUSTOM_COVER_GROUP_MAP:
106
- groups = model.objects.filter(custom_cover__in=unlink_pks)
107
- unlink_groups = []
108
- for group in groups:
109
- group.custom_cover = None
110
- unlink_groups.append(group)
111
- if unlink_groups:
112
- model.objects.bulk_update(unlink_groups, ["custom_cover"])
113
- self.log.debug(
114
- f"Unlinked {len(unlink_groups)} {model.__name__} moved custom covers."
115
- )
116
-
117
- self._remove_covers(unlink_pks, custom=True) # type: ignore
118
-
119
- def _bulk_covers_moved(self, status=None):
120
- """Move covers."""
121
- num_covers_moved = len(self.task.covers_moved)
122
- if not num_covers_moved:
123
- return
124
- status = Status(ImportStatusTypes.COVERS_MOVED, None, num_covers_moved)
125
- self.status_controller.start(status)
126
-
127
- moved_covers, unlink_pks = self._bulk_covers_moved_prepare(status)
128
- if LINK_COVER_PKS not in self.metadata:
129
- self.metadata[LINK_COVER_PKS] = set()
130
- self.metadata[LINK_COVER_PKS].update(unlink_pks)
131
- if moved_covers:
132
- CustomCover.objects.bulk_update(moved_covers, CUSTOM_COVER_UPDATE_FIELDS)
133
-
134
- self._bulk_covers_moved_unlink(unlink_pks)
74
+ return count
135
75
 
136
- count = len(moved_covers)
137
- if count:
138
- self.log.info(f"Moved {count} custom covers.")
139
-
140
- self.changed += count
141
- self.status_controller.finish(status)
142
-
143
- def _get_parent_folders(self, dest_folder_paths, status):
76
+ def _get_parent_folders(self, library, dest_folder_paths, status):
144
77
  """Get destination parent folders."""
145
78
  # Determine parent folder paths.
146
79
  dest_parent_folder_paths = set()
@@ -151,12 +84,12 @@ class MovedImporter(AggregateMetadataImporter):
151
84
 
152
85
  # Create only intermediate subfolders.
153
86
  existing_folder_paths = Folder.objects.filter(
154
- library=self.library, path__in=dest_parent_folder_paths
87
+ library=library, path__in=dest_parent_folder_paths
155
88
  ).values_list("path", flat=True)
156
89
  create_folder_paths = frozenset(
157
90
  dest_parent_folder_paths - frozenset(existing_folder_paths)
158
91
  )
159
- self.bulk_folders_create(create_folder_paths, status)
92
+ self.bulk_folders_create(create_folder_paths, library, status=status)
160
93
 
161
94
  # get parent folders path to model obj dict
162
95
  dest_parent_folders_objs = Folder.objects.filter(
@@ -167,33 +100,34 @@ class MovedImporter(AggregateMetadataImporter):
167
100
  dest_parent_folders[folder.path] = folder
168
101
  return dest_parent_folders
169
102
 
170
- def bulk_folders_moved(self):
103
+ @status_notify(status_type=ImportStatusTypes.DIRS_MOVED, updates=False)
104
+ def _bulk_folders_moved(self, folders_moved, library, **kwargs):
171
105
  """Move folders in the database instead of recreating them."""
172
- num_dirs_moved = len(self.task.dirs_moved)
173
- if not num_dirs_moved:
174
- return
175
- status = Status(ImportStatusTypes.DIRS_MOVED, None, num_dirs_moved)
176
- self.status_controller.start(status)
106
+ if not folders_moved:
107
+ return 0
177
108
 
178
- dest_folder_paths = frozenset(self.task.dirs_moved.values())
179
- dest_parent_folders = self._get_parent_folders(dest_folder_paths, status)
109
+ dest_folder_paths = frozenset(folders_moved.values())
110
+ status = kwargs.get("status")
111
+ dest_parent_folders = self._get_parent_folders(
112
+ library, dest_folder_paths, status
113
+ )
180
114
 
181
- src_folder_paths = frozenset(self.task.dirs_moved.keys())
115
+ src_folder_paths = frozenset(folders_moved.keys())
182
116
  folders_to_move = Folder.objects.filter(
183
- library=self.library, path__in=src_folder_paths
117
+ library=library, path__in=src_folder_paths
184
118
  ).order_by("path")
185
119
 
186
120
  update_folders = []
121
+ now = Now()
187
122
  for folder in folders_to_move.iterator():
188
- new_path = self.task.dirs_moved[folder.path]
123
+ new_path = folders_moved[folder.path]
189
124
  folder.name = Path(new_path).name
190
125
  folder.path = new_path
191
126
  parent_path_str = str(Path(new_path).parent)
192
127
  folder.parent_folder = dest_parent_folders.get(parent_path_str)
193
128
  folder.presave()
194
- folder.updated_at = Now()
129
+ folder.updated_at = now # type: ignore
195
130
  update_folders.append(folder)
196
- self.task.dirs_moved = {}
197
131
 
198
132
  update_folders = sorted(update_folders, key=lambda x: len(Path(x.path).parts))
199
133
 
@@ -201,39 +135,58 @@ class MovedImporter(AggregateMetadataImporter):
201
135
  count = len(update_folders)
202
136
  if count:
203
137
  self.log.info(f"Moved {count} folders.")
204
- self.changed += count
205
- self.status_controller.finish(status)
138
+ return count
206
139
 
207
- def _bulk_folders_modified(self):
140
+ @status_notify(status_type=ImportStatusTypes.DIRS_MODIFIED, updates=False)
141
+ def bulk_folders_modified(self, paths, library, **kwargs):
208
142
  """Update folders stat and nothing else."""
209
- num_dirs_modified = len(self.task.dirs_modified)
210
- if not num_dirs_modified:
211
- return
212
- status = Status(ImportStatusTypes.DIRS_MODIFIED, None, num_dirs_modified)
213
- self.status_controller.start(status)
214
-
215
- folders = Folder.objects.filter(
216
- library=self.library, path__in=self.task.dirs_modified
217
- ).only("stat", "updated_at")
218
- self.task.dirs_modified = frozenset()
143
+ count = 0
144
+ if not paths:
145
+ return count
146
+ folders = Folder.objects.filter(library=library, path__in=paths).only(
147
+ "stat", "updated_at"
148
+ )
219
149
  update_folders = []
150
+ now = Now()
220
151
  for folder in folders.iterator():
221
152
  if Path(folder.path).exists():
222
- folder.updated_at = Now()
153
+ folder.updated_at = now
223
154
  folder.presave()
224
155
  update_folders.append(folder)
225
156
  Folder.objects.bulk_update(
226
157
  update_folders, fields=BULK_UPDATE_FOLDER_MODIFIED_FIELDS
227
158
  )
228
- count = len(update_folders)
159
+ count += len(update_folders)
229
160
  if count:
230
161
  self.log.info(f"Modified {count} folders")
231
- self.changed += count
232
- self.status_controller.finish(status)
162
+ return count
233
163
 
234
- def move_and_modify_dirs(self):
164
+ def adopt_orphan_folders(self):
165
+ """Find orphan folders and move them into their correct place."""
166
+ libraries = Library.objects.only("pk", "path")
167
+ for library in libraries.iterator():
168
+ orphan_folder_paths = (
169
+ Folder.objects.filter(library=library, parent_folder=None)
170
+ .exclude(path=library.path)
171
+ .values_list("path", flat=True)
172
+ )
173
+
174
+ folders_moved = {}
175
+ for path in orphan_folder_paths:
176
+ folders_moved[path] = path
177
+
178
+ self._bulk_folders_moved(folders_moved, library)
179
+
180
+ def move_and_modify_dirs(self, library, task):
235
181
  """Move files and dirs and modify dirs."""
236
- self.bulk_folders_moved()
237
- self._bulk_comics_moved()
238
- self._bulk_covers_moved()
239
- self._bulk_folders_modified()
182
+ changed = 0
183
+ changed += self._bulk_folders_moved(task.dirs_moved, library)
184
+ task.dirs_moved = None
185
+
186
+ changed += self._bulk_comics_moved(task.files_moved, library)
187
+ task.files_moved = None
188
+
189
+ changed += self.bulk_folders_modified(task.dirs_modified, library)
190
+ task.dirs_modified = None
191
+
192
+ return changed