codex 1.7.15__py3-none-any.whl → 1.8.0a2__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 (1125) hide show
  1. codex/__init__.py +6 -1
  2. codex/applications/lifespan.py +16 -12
  3. codex/asgi.py +1 -2
  4. codex/choices/admin.py +63 -59
  5. codex/choices/browser.py +7 -10
  6. codex/choices/choices_to_json.py +21 -9
  7. codex/choices/search.py +133 -0
  8. codex/choices/statii.py +40 -0
  9. codex/librarian/bookmark/bookmarkd.py +56 -17
  10. codex/librarian/bookmark/latest_version.py +65 -0
  11. codex/librarian/bookmark/tasks.py +11 -1
  12. codex/librarian/bookmark/update.py +1 -1
  13. codex/librarian/bookmark/user_active.py +2 -3
  14. codex/librarian/covers/coverd.py +4 -1
  15. codex/librarian/covers/create.py +31 -22
  16. codex/librarian/covers/path.py +1 -1
  17. codex/librarian/covers/purge.py +22 -22
  18. codex/librarian/covers/status.py +37 -6
  19. codex/librarian/cron/crond.py +5 -3
  20. codex/librarian/librariand.py +57 -84
  21. codex/librarian/notifier/notifierd.py +8 -3
  22. codex/librarian/restarter/__init__.py +1 -0
  23. codex/librarian/restarter/restarter.py +55 -0
  24. codex/librarian/restarter/status.py +32 -0
  25. codex/librarian/restarter/tasks.py +13 -0
  26. codex/librarian/scribe/__init__.py +1 -0
  27. codex/librarian/scribe/importer/__init__.py +1 -0
  28. codex/librarian/scribe/importer/const.py +361 -0
  29. codex/librarian/scribe/importer/create/__init__.py +37 -0
  30. codex/librarian/scribe/importer/create/comics.py +172 -0
  31. codex/librarian/scribe/importer/create/const.py +131 -0
  32. codex/librarian/scribe/importer/create/covers.py +123 -0
  33. codex/librarian/scribe/importer/create/folders.py +98 -0
  34. codex/librarian/scribe/importer/create/foreign_keys.py +253 -0
  35. codex/librarian/scribe/importer/create/link_fks.py +73 -0
  36. codex/librarian/scribe/importer/delete/__init__.py +28 -0
  37. codex/librarian/scribe/importer/delete/comics.py +68 -0
  38. codex/librarian/scribe/importer/delete/covers.py +35 -0
  39. codex/librarian/scribe/importer/delete/folders.py +33 -0
  40. codex/librarian/scribe/importer/failed_imports.py +168 -0
  41. codex/librarian/scribe/importer/finish.py +70 -0
  42. codex/librarian/scribe/importer/importer.py +31 -0
  43. codex/librarian/scribe/importer/init.py +338 -0
  44. codex/librarian/scribe/importer/link/__init__.py +15 -0
  45. codex/librarian/scribe/importer/link/const.py +31 -0
  46. codex/librarian/scribe/importer/link/covers.py +70 -0
  47. codex/librarian/scribe/importer/link/delete.py +106 -0
  48. codex/librarian/scribe/importer/link/many_to_many.py +88 -0
  49. codex/librarian/scribe/importer/link/prepare.py +132 -0
  50. codex/librarian/scribe/importer/link/sum.py +19 -0
  51. codex/librarian/scribe/importer/moved/__init__.py +52 -0
  52. codex/librarian/scribe/importer/moved/comics.py +125 -0
  53. codex/librarian/scribe/importer/moved/covers.py +88 -0
  54. codex/librarian/scribe/importer/moved/folders.py +205 -0
  55. codex/librarian/scribe/importer/query/__init__.py +44 -0
  56. codex/librarian/scribe/importer/query/covers.py +55 -0
  57. codex/librarian/scribe/importer/query/filters.py +61 -0
  58. codex/librarian/scribe/importer/query/links.py +29 -0
  59. codex/librarian/scribe/importer/query/links_fk.py +99 -0
  60. codex/librarian/scribe/importer/query/links_m2m.py +102 -0
  61. codex/librarian/scribe/importer/query/query_fks.py +203 -0
  62. codex/librarian/scribe/importer/query/update_comics.py +59 -0
  63. codex/librarian/scribe/importer/query/update_fks.py +140 -0
  64. codex/librarian/scribe/importer/read/__init__.py +14 -0
  65. codex/librarian/scribe/importer/read/aggregate_path.py +108 -0
  66. codex/librarian/scribe/importer/read/const.py +144 -0
  67. codex/librarian/scribe/importer/read/extract.py +128 -0
  68. codex/librarian/scribe/importer/read/folders.py +37 -0
  69. codex/librarian/scribe/importer/read/foreign_keys.py +145 -0
  70. codex/librarian/scribe/importer/read/many_to_many.py +237 -0
  71. codex/librarian/scribe/importer/search/__init__.py +34 -0
  72. codex/librarian/scribe/importer/search/const.py +50 -0
  73. codex/librarian/scribe/importer/search/prepare.py +85 -0
  74. codex/librarian/scribe/importer/search/sync_m2m.py +84 -0
  75. codex/librarian/scribe/importer/search/update.py +245 -0
  76. codex/librarian/scribe/importer/statii/1 +27 -0
  77. codex/librarian/scribe/importer/statii/__init__.py +19 -0
  78. codex/librarian/scribe/importer/statii/create.py +67 -0
  79. codex/librarian/scribe/importer/statii/delete.py +39 -0
  80. codex/librarian/scribe/importer/statii/link.py +27 -0
  81. codex/librarian/scribe/importer/statii/moved.py +39 -0
  82. codex/librarian/scribe/importer/statii/query.py +46 -0
  83. codex/librarian/scribe/importer/statii/read.py +30 -0
  84. codex/librarian/scribe/importer/statii/search.py +28 -0
  85. codex/librarian/scribe/importer/status.py +21 -0
  86. codex/librarian/scribe/importer/tasks.py +49 -0
  87. codex/librarian/scribe/janitor/__init__.py +1 -0
  88. codex/librarian/scribe/janitor/adopt_folders.py +81 -0
  89. codex/librarian/scribe/janitor/cleanup.py +199 -0
  90. codex/librarian/scribe/janitor/failed_imports.py +27 -0
  91. codex/librarian/scribe/janitor/integrity.py +374 -0
  92. codex/librarian/scribe/janitor/janitor.py +125 -0
  93. codex/librarian/scribe/janitor/scheduled_time.py +13 -0
  94. codex/librarian/scribe/janitor/status.py +151 -0
  95. codex/librarian/scribe/janitor/tasks.py +71 -0
  96. codex/librarian/scribe/janitor/update.py +88 -0
  97. codex/librarian/scribe/janitor/vacuum.py +53 -0
  98. codex/librarian/scribe/lazy_importer.py +51 -0
  99. codex/librarian/scribe/priority.py +65 -0
  100. codex/librarian/scribe/scribed.py +130 -0
  101. codex/librarian/scribe/search/__init__.py +1 -0
  102. codex/librarian/scribe/search/handler.py +28 -0
  103. codex/librarian/scribe/search/optimize.py +31 -0
  104. codex/librarian/scribe/search/remove.py +44 -0
  105. codex/librarian/scribe/search/status.py +66 -0
  106. codex/librarian/scribe/search/sync.py +391 -0
  107. codex/librarian/scribe/search/tasks.py +28 -0
  108. codex/librarian/scribe/status.py +20 -0
  109. codex/librarian/scribe/tasks.py +31 -0
  110. codex/librarian/scribe/timestamp_update.py +135 -0
  111. codex/librarian/status.py +76 -0
  112. codex/librarian/status_controller.py +164 -0
  113. codex/librarian/tasks.py +0 -10
  114. codex/librarian/telemeter/scheduled_time.py +11 -4
  115. codex/librarian/telemeter/stats.py +0 -2
  116. codex/librarian/telemeter/tasks.py +3 -1
  117. codex/librarian/telemeter/telemeter.py +17 -11
  118. codex/librarian/threads.py +148 -0
  119. codex/librarian/watchdog/const.py +115 -0
  120. codex/librarian/watchdog/db_snapshot.py +16 -10
  121. codex/librarian/watchdog/dir_snapshot_diff.py +19 -1
  122. codex/librarian/watchdog/emitter.py +128 -102
  123. codex/librarian/watchdog/event_batcherd.py +120 -78
  124. codex/librarian/watchdog/events.py +22 -211
  125. codex/librarian/watchdog/handlers.py +203 -0
  126. codex/librarian/watchdog/memory.py +56 -0
  127. codex/librarian/watchdog/observers.py +94 -58
  128. codex/librarian/watchdog/status.py +18 -5
  129. codex/librarian/worker.py +32 -0
  130. codex/middleware.py +6 -8
  131. codex/migrations/0011_library_groups_and_metadata_changes.py +2 -1
  132. codex/migrations/0013_int_issue_count_longer_charfields.py +2 -1
  133. codex/migrations/0023_rename_credit_creator_and_more.py +2 -1
  134. codex/migrations/0026_comicbox_1.py +9 -9
  135. codex/migrations/0034_comicbox2.py +789 -0
  136. codex/models/__init__.py +1 -0
  137. codex/models/admin.py +13 -21
  138. codex/models/base.py +21 -2
  139. codex/models/comic.py +80 -43
  140. codex/models/fields.py +81 -0
  141. codex/models/functions.py +8 -2
  142. codex/models/groups.py +99 -34
  143. codex/models/identifier.py +79 -0
  144. codex/models/library.py +17 -3
  145. codex/models/named.py +52 -55
  146. codex/models/paths.py +16 -12
  147. codex/models/query.py +7 -5
  148. codex/run.py +12 -18
  149. codex/serializers/admin/groups.py +3 -0
  150. codex/serializers/admin/libraries.py +13 -1
  151. codex/serializers/admin/stats.py +5 -4
  152. codex/serializers/admin/tasks.py +3 -5
  153. codex/serializers/admin/users.py +9 -3
  154. codex/serializers/auth.py +13 -6
  155. codex/serializers/browser/choices.py +35 -18
  156. codex/serializers/browser/filters.py +7 -5
  157. codex/serializers/browser/metadata.py +12 -10
  158. codex/serializers/browser/mixins.py +6 -8
  159. codex/serializers/browser/mtime.py +6 -2
  160. codex/serializers/browser/page.py +8 -3
  161. codex/serializers/browser/settings.py +35 -5
  162. codex/serializers/fields/__init__.py +2 -2
  163. codex/serializers/fields/auth.py +4 -5
  164. codex/serializers/fields/base.py +16 -0
  165. codex/serializers/fields/browser.py +15 -31
  166. codex/serializers/fields/group.py +11 -8
  167. codex/serializers/fields/reader.py +14 -10
  168. codex/serializers/fields/sanitized.py +2 -0
  169. codex/serializers/fields/session.py +3 -8
  170. codex/serializers/fields/stats.py +3 -5
  171. codex/serializers/fields/vuetify.py +21 -10
  172. codex/serializers/mixins.py +42 -0
  173. codex/serializers/models/base.py +1 -1
  174. codex/serializers/models/comic.py +6 -2
  175. codex/serializers/models/named.py +62 -37
  176. codex/serializers/models/pycountry.py +0 -3
  177. codex/serializers/opds/v1.py +6 -6
  178. codex/serializers/opds/v2/feed.py +2 -4
  179. codex/serializers/opds/v2/publication.py +14 -14
  180. codex/serializers/opds/v2/unused.py +2 -0
  181. codex/serializers/reader.py +52 -31
  182. codex/serializers/route.py +6 -4
  183. codex/serializers/settings.py +6 -6
  184. codex/settings/__init__.py +424 -1
  185. codex/signals/django_signals.py +2 -35
  186. codex/signals/os_signals.py +4 -5
  187. codex/startup/__init__.py +180 -0
  188. codex/startup/db.py +130 -0
  189. codex/startup/logger_init.py +45 -0
  190. codex/startup/registration.py +13 -0
  191. codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js +1 -0
  192. codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.br +0 -0
  193. codex/static_root/assets/VCheckbox-DSndl51k.1e28c443c3cb.js.gz +0 -0
  194. codex/static_root/assets/VCheckbox-DSndl51k.js +1 -0
  195. codex/static_root/assets/VCheckbox-DSndl51k.js.br +0 -0
  196. codex/static_root/assets/VCheckbox-DSndl51k.js.gz +0 -0
  197. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js +1 -0
  198. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.br +0 -0
  199. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.d7463473d7a2.js.gz +0 -0
  200. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js +1 -0
  201. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.br +0 -0
  202. codex/static_root/assets/VCheckboxBtn-Bu2Pf64q.js.gz +0 -0
  203. codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js +1 -0
  204. codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.br +0 -0
  205. codex/static_root/assets/VCombobox-Uogv6Ckp.9f900e703605.js.gz +0 -0
  206. codex/static_root/assets/VCombobox-Uogv6Ckp.js +1 -0
  207. codex/static_root/assets/VCombobox-Uogv6Ckp.js.br +0 -0
  208. codex/static_root/assets/VCombobox-Uogv6Ckp.js.gz +0 -0
  209. codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js +1 -0
  210. codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.br +0 -0
  211. codex/static_root/assets/VDialog-BzaGu1HN.34f52763c3f8.js.gz +0 -0
  212. codex/static_root/assets/VDialog-BzaGu1HN.js +1 -0
  213. codex/static_root/assets/VDialog-BzaGu1HN.js.br +0 -0
  214. codex/static_root/assets/VDialog-BzaGu1HN.js.gz +0 -0
  215. codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css +1 -0
  216. codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css.br +0 -0
  217. codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css.gz +0 -0
  218. codex/static_root/assets/VDialog-CpWjrJ0R.css +1 -0
  219. codex/static_root/assets/VDialog-CpWjrJ0R.css.br +0 -0
  220. codex/static_root/assets/VDialog-CpWjrJ0R.css.gz +0 -0
  221. codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js +1 -0
  222. codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.br +0 -0
  223. codex/static_root/assets/VDivider-C3ikm0Ko.4938e9ced53e.js.gz +0 -0
  224. codex/static_root/assets/VDivider-C3ikm0Ko.js +1 -0
  225. codex/static_root/assets/VDivider-C3ikm0Ko.js.br +0 -0
  226. codex/static_root/assets/VDivider-C3ikm0Ko.js.gz +0 -0
  227. codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js +1 -0
  228. codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.br +0 -0
  229. codex/static_root/assets/VExpansionPanels-AmsInZN0.5cb7c833de3d.js.gz +0 -0
  230. codex/static_root/assets/VExpansionPanels-AmsInZN0.js +1 -0
  231. codex/static_root/assets/VExpansionPanels-AmsInZN0.js.br +0 -0
  232. codex/static_root/assets/VExpansionPanels-AmsInZN0.js.gz +0 -0
  233. codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js +1 -0
  234. codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.br +0 -0
  235. codex/static_root/assets/VForm-CyCdgusw.c737973a1e85.js.gz +0 -0
  236. codex/static_root/assets/VForm-CyCdgusw.js +1 -0
  237. codex/static_root/assets/VForm-CyCdgusw.js.br +0 -0
  238. codex/static_root/assets/VForm-CyCdgusw.js.gz +0 -0
  239. codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js +1 -0
  240. codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.br +0 -0
  241. codex/static_root/assets/VRadioGroup-BF0Xjrzi.e54d2bf41bb2.js.gz +0 -0
  242. codex/static_root/assets/VRadioGroup-BF0Xjrzi.js +1 -0
  243. codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.br +0 -0
  244. codex/static_root/assets/VRadioGroup-BF0Xjrzi.js.gz +0 -0
  245. codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js +1 -0
  246. codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.br +0 -0
  247. codex/static_root/assets/VSelect-Dv50OIkN.390adb1fe7fa.js.gz +0 -0
  248. codex/static_root/assets/VSelect-Dv50OIkN.js +1 -0
  249. codex/static_root/assets/VSelect-Dv50OIkN.js.br +0 -0
  250. codex/static_root/assets/VSelect-Dv50OIkN.js.gz +0 -0
  251. codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js +1 -0
  252. codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.br +0 -0
  253. codex/static_root/assets/VSelectionControl-DbKYScD5.8d2ab1ebe546.js.gz +0 -0
  254. codex/static_root/assets/VSelectionControl-DbKYScD5.js +1 -0
  255. codex/static_root/assets/VSelectionControl-DbKYScD5.js.br +0 -0
  256. codex/static_root/assets/VSelectionControl-DbKYScD5.js.gz +0 -0
  257. codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js +1 -0
  258. codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.br +0 -0
  259. codex/static_root/assets/VTable-BmOfHc7J.b2e1311009d1.js.gz +0 -0
  260. codex/static_root/assets/VTable-BmOfHc7J.js +1 -0
  261. codex/static_root/assets/VTable-BmOfHc7J.js.br +0 -0
  262. codex/static_root/assets/VTable-BmOfHc7J.js.gz +0 -0
  263. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css +1 -0
  264. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.br +0 -0
  265. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.gz +0 -0
  266. codex/static_root/assets/VTable-CQyv0wyO.css +1 -0
  267. codex/static_root/assets/VTable-CQyv0wyO.css.br +0 -0
  268. codex/static_root/assets/VTable-CQyv0wyO.css.gz +0 -0
  269. codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js +1 -0
  270. codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.br +0 -0
  271. codex/static_root/assets/VWindowItem-BLEDgagD.4b67c4a63c59.js.gz +0 -0
  272. codex/static_root/assets/VWindowItem-BLEDgagD.js +1 -0
  273. codex/static_root/assets/VWindowItem-BLEDgagD.js.br +0 -0
  274. codex/static_root/assets/VWindowItem-BLEDgagD.js.gz +0 -0
  275. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css +1 -0
  276. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.br +0 -0
  277. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.gz +0 -0
  278. codex/static_root/assets/VWindowItem-ChYLiXSE.css +1 -0
  279. codex/static_root/assets/VWindowItem-ChYLiXSE.css.br +0 -0
  280. codex/static_root/assets/VWindowItem-ChYLiXSE.css.gz +0 -0
  281. codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js +1 -0
  282. codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.br +0 -0
  283. codex/static_root/assets/admin-Bv40vYZw.8179e1ece835.js.gz +0 -0
  284. codex/static_root/assets/admin-Bv40vYZw.js +1 -0
  285. codex/static_root/assets/admin-Bv40vYZw.js.br +0 -0
  286. codex/static_root/assets/admin-Bv40vYZw.js.gz +0 -0
  287. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css +1 -0
  288. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.br +0 -0
  289. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.gz +0 -0
  290. codex/static_root/assets/admin-DJCVf2PA.css +1 -0
  291. codex/static_root/assets/admin-DJCVf2PA.css.br +0 -0
  292. codex/static_root/assets/admin-DJCVf2PA.css.gz +0 -0
  293. codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js +1 -0
  294. codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.br +0 -0
  295. codex/static_root/assets/admin-kjMoKlqD.55a1dd908124.js.gz +0 -0
  296. codex/static_root/assets/admin-kjMoKlqD.js +1 -0
  297. codex/static_root/assets/admin-kjMoKlqD.js.br +0 -0
  298. codex/static_root/assets/admin-kjMoKlqD.js.gz +0 -0
  299. codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js +1 -0
  300. codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.br +0 -0
  301. codex/static_root/assets/admin-menu-BNpuOmbI.e1f62ba483cd.js.gz +0 -0
  302. codex/static_root/assets/admin-menu-BNpuOmbI.js +1 -0
  303. codex/static_root/assets/admin-menu-BNpuOmbI.js.br +0 -0
  304. codex/static_root/assets/admin-menu-BNpuOmbI.js.gz +0 -0
  305. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css +1 -0
  306. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.br +0 -0
  307. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.gz +0 -0
  308. codex/static_root/assets/admin-menu-hpyUS8ku.css +1 -0
  309. codex/static_root/assets/admin-menu-hpyUS8ku.css.br +0 -0
  310. codex/static_root/assets/admin-menu-hpyUS8ku.css.gz +0 -0
  311. codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.a592809d4008.css +1 -0
  312. codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.css +1 -0
  313. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js +1 -0
  314. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.br +0 -0
  315. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.4cdd37d0dd16.js.gz +0 -0
  316. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js +1 -0
  317. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.br +0 -0
  318. codex/static_root/assets/admin-settings-button-progress-RfwaqLl2.js.gz +0 -0
  319. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css +1 -0
  320. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.br +0 -0
  321. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.gz +0 -0
  322. codex/static_root/assets/browser-Cdi7U5ku.css +1 -0
  323. codex/static_root/assets/browser-Cdi7U5ku.css.br +0 -0
  324. codex/static_root/assets/browser-Cdi7U5ku.css.gz +0 -0
  325. codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js +1 -0
  326. codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.br +0 -0
  327. codex/static_root/assets/browser-plYso4v5.87ef04b44d37.js.gz +0 -0
  328. codex/static_root/assets/browser-plYso4v5.js +1 -0
  329. codex/static_root/assets/browser-plYso4v5.js.br +0 -0
  330. codex/static_root/assets/browser-plYso4v5.js.gz +0 -0
  331. codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js +1 -0
  332. codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.br +0 -0
  333. codex/static_root/assets/change-password-dialog-DyhQwNv1.26383853ccc0.js.gz +0 -0
  334. codex/static_root/assets/change-password-dialog-DyhQwNv1.js +1 -0
  335. codex/static_root/assets/change-password-dialog-DyhQwNv1.js.br +0 -0
  336. codex/static_root/assets/change-password-dialog-DyhQwNv1.js.gz +0 -0
  337. codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js +1 -0
  338. codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.br +0 -0
  339. codex/static_root/assets/confirm-dialog-B7ndwV5M.d1f0728d4bd0.js.gz +0 -0
  340. codex/static_root/assets/confirm-dialog-B7ndwV5M.js +1 -0
  341. codex/static_root/assets/confirm-dialog-B7ndwV5M.js.br +0 -0
  342. codex/static_root/assets/confirm-dialog-B7ndwV5M.js.gz +0 -0
  343. codex/static_root/assets/confirm-dialog-YfC8mRQA.be37e8f67e0f.css +1 -0
  344. codex/static_root/assets/confirm-dialog-YfC8mRQA.css +1 -0
  345. codex/static_root/assets/datetime-column-Bt7J1qEf.css +1 -0
  346. codex/static_root/assets/datetime-column-Bt7J1qEf.css.br +0 -0
  347. codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css +1 -0
  348. codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css.br +0 -0
  349. codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js +1 -0
  350. codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.br +0 -0
  351. codex/static_root/assets/datetime-column-DANpNGGe.13985ff7d484.js.gz +0 -0
  352. codex/static_root/assets/datetime-column-DANpNGGe.js +1 -0
  353. codex/static_root/assets/datetime-column-DANpNGGe.js.br +0 -0
  354. codex/static_root/assets/datetime-column-DANpNGGe.js.gz +0 -0
  355. codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js +1 -0
  356. codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.br +0 -0
  357. codex/static_root/assets/filter-Dhe8cVmt.ad92d3b618e3.js.gz +0 -0
  358. codex/static_root/assets/filter-Dhe8cVmt.js +1 -0
  359. codex/static_root/assets/filter-Dhe8cVmt.js.br +0 -0
  360. codex/static_root/assets/filter-Dhe8cVmt.js.gz +0 -0
  361. codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js +1 -0
  362. codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.br +0 -0
  363. codex/static_root/assets/flag-tab-BZ9S7U8D.0b814b215567.js.gz +0 -0
  364. codex/static_root/assets/flag-tab-BZ9S7U8D.js +1 -0
  365. codex/static_root/assets/flag-tab-BZ9S7U8D.js.br +0 -0
  366. codex/static_root/assets/flag-tab-BZ9S7U8D.js.gz +0 -0
  367. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css +1 -0
  368. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.br +0 -0
  369. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.gz +0 -0
  370. codex/static_root/assets/forwardRefs-B_sUWZn6.css +1 -0
  371. codex/static_root/assets/forwardRefs-B_sUWZn6.css.br +0 -0
  372. codex/static_root/assets/forwardRefs-B_sUWZn6.css.gz +0 -0
  373. codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js +1 -0
  374. codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.br +0 -0
  375. codex/static_root/assets/forwardRefs-Z0d4Mnc7.deb4e7a1b8b5.js.gz +0 -0
  376. codex/static_root/assets/forwardRefs-Z0d4Mnc7.js +1 -0
  377. codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.br +0 -0
  378. codex/static_root/assets/forwardRefs-Z0d4Mnc7.js.gz +0 -0
  379. codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js +1 -0
  380. codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.br +0 -0
  381. codex/static_root/assets/group-tab-B0ASBB3_.8e10b90ff052.js.gz +0 -0
  382. codex/static_root/assets/group-tab-B0ASBB3_.js +1 -0
  383. codex/static_root/assets/group-tab-B0ASBB3_.js.br +0 -0
  384. codex/static_root/assets/group-tab-B0ASBB3_.js.gz +0 -0
  385. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css +1 -0
  386. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.br +0 -0
  387. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.gz +0 -0
  388. codex/static_root/assets/group-tab-CQ_Qw6h8.css +1 -0
  389. codex/static_root/assets/group-tab-CQ_Qw6h8.css.br +0 -0
  390. codex/static_root/assets/group-tab-CQ_Qw6h8.css.gz +0 -0
  391. codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js +1 -0
  392. codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.br +0 -0
  393. codex/static_root/assets/http-error-BP-mMZsK.72c4d00b40d2.js.gz +0 -0
  394. codex/static_root/assets/http-error-BP-mMZsK.js +1 -0
  395. codex/static_root/assets/http-error-BP-mMZsK.js.br +0 -0
  396. codex/static_root/assets/http-error-BP-mMZsK.js.gz +0 -0
  397. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css +1 -0
  398. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.br +0 -0
  399. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.gz +0 -0
  400. codex/static_root/assets/http-error-CB3k5P-n.css +1 -0
  401. codex/static_root/assets/http-error-CB3k5P-n.css.br +0 -0
  402. codex/static_root/assets/http-error-CB3k5P-n.css.gz +0 -0
  403. codex/static_root/assets/index-Cu9nQXJD.49795921eada.js +1 -0
  404. codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.br +0 -0
  405. codex/static_root/assets/index-Cu9nQXJD.49795921eada.js.gz +0 -0
  406. codex/static_root/assets/index-Cu9nQXJD.js +1 -0
  407. codex/static_root/assets/index-Cu9nQXJD.js.br +0 -0
  408. codex/static_root/assets/index-Cu9nQXJD.js.gz +0 -0
  409. codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js +1 -0
  410. codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.br +0 -0
  411. codex/static_root/assets/library-tab-8g2eSuGN.846cc1674a67.js.gz +0 -0
  412. codex/static_root/assets/library-tab-8g2eSuGN.js +1 -0
  413. codex/static_root/assets/library-tab-8g2eSuGN.js.br +0 -0
  414. codex/static_root/assets/library-tab-8g2eSuGN.js.gz +0 -0
  415. codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css +1 -0
  416. codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.br +0 -0
  417. codex/static_root/assets/library-tab-D9lxhAqv.02f7064c20f3.css.gz +0 -0
  418. codex/static_root/assets/library-tab-D9lxhAqv.css +1 -0
  419. codex/static_root/assets/library-tab-D9lxhAqv.css.br +0 -0
  420. codex/static_root/assets/library-tab-D9lxhAqv.css.gz +0 -0
  421. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css +5 -0
  422. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.br +0 -0
  423. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.gz +0 -0
  424. codex/static_root/assets/main-B8_0rUnw.css +5 -0
  425. codex/static_root/assets/main-B8_0rUnw.css.br +0 -0
  426. codex/static_root/assets/main-B8_0rUnw.css.gz +0 -0
  427. codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js +39 -0
  428. codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.br +0 -0
  429. codex/static_root/assets/main-BoAlbVoF.e41ba211717d.js.gz +0 -0
  430. codex/static_root/assets/main-BoAlbVoF.js +39 -0
  431. codex/static_root/assets/main-BoAlbVoF.js.br +0 -0
  432. codex/static_root/assets/main-BoAlbVoF.js.gz +0 -0
  433. codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js +1 -0
  434. codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.br +0 -0
  435. codex/static_root/assets/pager-full-pdf-DShiSKPO.026946648650.js.gz +0 -0
  436. codex/static_root/assets/pager-full-pdf-DShiSKPO.js +1 -0
  437. codex/static_root/assets/pager-full-pdf-DShiSKPO.js.br +0 -0
  438. codex/static_root/assets/pager-full-pdf-DShiSKPO.js.gz +0 -0
  439. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css +1 -0
  440. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.br +0 -0
  441. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.gz +0 -0
  442. codex/static_root/assets/pagination-toolbar-741OafNw.css +1 -0
  443. codex/static_root/assets/pagination-toolbar-741OafNw.css.br +0 -0
  444. codex/static_root/assets/pagination-toolbar-741OafNw.css.gz +0 -0
  445. codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js +1 -0
  446. codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.br +0 -0
  447. codex/static_root/assets/pagination-toolbar-DGfRDeRW.c3f463ad6edd.js.gz +0 -0
  448. codex/static_root/assets/pagination-toolbar-DGfRDeRW.js +1 -0
  449. codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.br +0 -0
  450. codex/static_root/assets/pagination-toolbar-DGfRDeRW.js.gz +0 -0
  451. codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js +372 -0
  452. codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.br +0 -0
  453. codex/static_root/assets/pdf-doc-D6Meu4vZ.91b43d057670.js.gz +0 -0
  454. codex/static_root/assets/pdf-doc-D6Meu4vZ.js +372 -0
  455. codex/static_root/assets/pdf-doc-D6Meu4vZ.js.br +0 -0
  456. codex/static_root/assets/pdf-doc-D6Meu4vZ.js.gz +0 -0
  457. codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js +2 -0
  458. codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.br +0 -0
  459. codex/static_root/assets/reader-CptqnqBZ.340bc756e164.js.gz +0 -0
  460. codex/static_root/assets/reader-CptqnqBZ.js +2 -0
  461. codex/static_root/assets/reader-CptqnqBZ.js.br +0 -0
  462. codex/static_root/assets/reader-CptqnqBZ.js.gz +0 -0
  463. codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css +1 -0
  464. codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.br +0 -0
  465. codex/static_root/assets/reader-LwL05rgA.c022ad3b7b94.css.gz +0 -0
  466. codex/static_root/assets/reader-LwL05rgA.css +1 -0
  467. codex/static_root/assets/reader-LwL05rgA.css.br +0 -0
  468. codex/static_root/assets/reader-LwL05rgA.css.gz +0 -0
  469. codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js +1 -0
  470. codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.br +0 -0
  471. codex/static_root/assets/relation-chips-CAXZIswb.e991a259ce59.js.gz +0 -0
  472. codex/static_root/assets/relation-chips-CAXZIswb.js +1 -0
  473. codex/static_root/assets/relation-chips-CAXZIswb.js.br +0 -0
  474. codex/static_root/assets/relation-chips-CAXZIswb.js.gz +0 -0
  475. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css +1 -0
  476. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.br +0 -0
  477. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.gz +0 -0
  478. codex/static_root/assets/relation-chips-CcFgPQOM.css +1 -0
  479. codex/static_root/assets/relation-chips-CcFgPQOM.css.br +0 -0
  480. codex/static_root/assets/relation-chips-CcFgPQOM.css.gz +0 -0
  481. codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js +2 -0
  482. codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.br +0 -0
  483. codex/static_root/assets/settings-drawer-B4gD41g6.82718694498e.js.gz +0 -0
  484. codex/static_root/assets/settings-drawer-B4gD41g6.js +2 -0
  485. codex/static_root/assets/settings-drawer-B4gD41g6.js.br +0 -0
  486. codex/static_root/assets/settings-drawer-B4gD41g6.js.gz +0 -0
  487. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css +1 -0
  488. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.br +0 -0
  489. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.gz +0 -0
  490. codex/static_root/assets/settings-drawer-CpS_aX4Z.css +1 -0
  491. codex/static_root/assets/settings-drawer-CpS_aX4Z.css.br +0 -0
  492. codex/static_root/assets/settings-drawer-CpS_aX4Z.css.gz +0 -0
  493. codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js +1 -0
  494. codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.br +0 -0
  495. codex/static_root/assets/ssrBoot-O6yTJ_UV.7180d77d283e.js.gz +0 -0
  496. codex/static_root/assets/ssrBoot-O6yTJ_UV.js +1 -0
  497. codex/static_root/assets/ssrBoot-O6yTJ_UV.js.br +0 -0
  498. codex/static_root/assets/ssrBoot-O6yTJ_UV.js.gz +0 -0
  499. codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js +1 -0
  500. codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.br +0 -0
  501. codex/static_root/assets/stats-tab-BZjOg19A.afb2e6b0d648.js.gz +0 -0
  502. codex/static_root/assets/stats-tab-BZjOg19A.js +1 -0
  503. codex/static_root/assets/stats-tab-BZjOg19A.js.br +0 -0
  504. codex/static_root/assets/stats-tab-BZjOg19A.js.gz +0 -0
  505. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css +1 -0
  506. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.br +0 -0
  507. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.gz +0 -0
  508. codex/static_root/assets/stats-tab-Dpqh5pF9.css +1 -0
  509. codex/static_root/assets/stats-tab-Dpqh5pF9.css.br +0 -0
  510. codex/static_root/assets/stats-tab-Dpqh5pF9.css.gz +0 -0
  511. codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js +1 -0
  512. codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.br +0 -0
  513. codex/static_root/assets/task-tab-GP2jPkRE.cfdfb9396ec4.js.gz +0 -0
  514. codex/static_root/assets/task-tab-GP2jPkRE.js +1 -0
  515. codex/static_root/assets/task-tab-GP2jPkRE.js.br +0 -0
  516. codex/static_root/assets/task-tab-GP2jPkRE.js.gz +0 -0
  517. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css +1 -0
  518. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.br +0 -0
  519. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.gz +0 -0
  520. codex/static_root/assets/unauthorized-BBwsmi0O.css +1 -0
  521. codex/static_root/assets/unauthorized-BBwsmi0O.css.br +0 -0
  522. codex/static_root/assets/unauthorized-BBwsmi0O.css.gz +0 -0
  523. codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js +1 -0
  524. codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.br +0 -0
  525. codex/static_root/assets/unauthorized-Bo3ThIrX.12d2efd95d7d.js.gz +0 -0
  526. codex/static_root/assets/unauthorized-Bo3ThIrX.js +1 -0
  527. codex/static_root/assets/unauthorized-Bo3ThIrX.js.br +0 -0
  528. codex/static_root/assets/unauthorized-Bo3ThIrX.js.gz +0 -0
  529. codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js +1 -0
  530. codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.br +0 -0
  531. codex/static_root/assets/user-tab-BQ82qBg3.17190dc83452.js.gz +0 -0
  532. codex/static_root/assets/user-tab-BQ82qBg3.js +1 -0
  533. codex/static_root/assets/user-tab-BQ82qBg3.js.br +0 -0
  534. codex/static_root/assets/user-tab-BQ82qBg3.js.gz +0 -0
  535. codex/static_root/img/folder.83168d8d3119.svg +1 -0
  536. codex/static_root/img/folder.83168d8d3119.svg.br +1 -0
  537. codex/static_root/img/folder.83168d8d3119.svg.gz +0 -0
  538. codex/static_root/img/folder.svg +1 -1
  539. codex/static_root/img/folder.svg.br +0 -0
  540. codex/static_root/img/folder.svg.gz +0 -0
  541. codex/static_root/img/imprint.3ca7a779b949.svg +1 -0
  542. codex/static_root/img/imprint.3ca7a779b949.svg.br +0 -0
  543. codex/static_root/img/imprint.3ca7a779b949.svg.gz +0 -0
  544. codex/static_root/img/imprint.svg +1 -1
  545. codex/static_root/img/imprint.svg.br +0 -0
  546. codex/static_root/img/imprint.svg.gz +0 -0
  547. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg +1 -0
  548. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.br +0 -0
  549. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.gz +0 -0
  550. codex/static_root/img/logo-maskable.svg +1 -1
  551. codex/static_root/img/logo-maskable.svg.br +0 -0
  552. codex/static_root/img/logo-maskable.svg.gz +0 -0
  553. codex/static_root/img/logo.00c902973831.svg +1 -0
  554. codex/static_root/img/logo.00c902973831.svg.br +0 -0
  555. codex/static_root/img/logo.00c902973831.svg.gz +0 -0
  556. codex/static_root/img/logo.svg +1 -1
  557. codex/static_root/img/logo.svg.br +0 -0
  558. codex/static_root/img/logo.svg.gz +0 -0
  559. codex/static_root/img/missing-cover-165.f4bb7740084c.webp +0 -0
  560. codex/static_root/img/missing-cover-165.webp +0 -0
  561. codex/static_root/img/missing-cover.7329518c5972.svg +1 -0
  562. codex/static_root/img/missing-cover.7329518c5972.svg.br +0 -0
  563. codex/static_root/img/missing-cover.7329518c5972.svg.gz +0 -0
  564. codex/static_root/img/missing-cover.svg +1 -1
  565. codex/static_root/img/missing-cover.svg.br +0 -0
  566. codex/static_root/img/missing-cover.svg.gz +0 -0
  567. codex/static_root/img/series.b092bbac0c2a.svg +1 -0
  568. codex/static_root/img/series.b092bbac0c2a.svg.br +0 -0
  569. codex/static_root/img/series.b092bbac0c2a.svg.gz +0 -0
  570. codex/static_root/img/series.svg +1 -1
  571. codex/static_root/img/series.svg.br +0 -0
  572. codex/static_root/img/series.svg.gz +0 -0
  573. codex/static_root/img/story-arc.884f7b1d95bd.svg +1 -0
  574. codex/static_root/img/story-arc.884f7b1d95bd.svg.br +0 -0
  575. codex/static_root/img/story-arc.884f7b1d95bd.svg.gz +0 -0
  576. codex/static_root/img/story-arc.svg +1 -1
  577. codex/static_root/img/story-arc.svg.br +0 -0
  578. codex/static_root/img/story-arc.svg.gz +0 -0
  579. codex/static_root/img/volume.516ec0c3018d.svg +1 -0
  580. codex/static_root/img/volume.516ec0c3018d.svg.br +0 -0
  581. codex/static_root/img/volume.516ec0c3018d.svg.gz +0 -0
  582. codex/static_root/img/volume.svg +1 -1
  583. codex/static_root/img/volume.svg.br +0 -0
  584. codex/static_root/img/volume.svg.gz +0 -0
  585. codex/static_root/manifest.0dc91d0dee6d.json +760 -0
  586. codex/static_root/manifest.0dc91d0dee6d.json.br +0 -0
  587. codex/static_root/manifest.0dc91d0dee6d.json.gz +0 -0
  588. codex/static_root/manifest.json +339 -336
  589. codex/static_root/manifest.json.br +0 -0
  590. codex/static_root/manifest.json.gz +0 -0
  591. codex/static_root/staticfiles.json +1 -1
  592. codex/templates/headers-script-globals.html +1 -0
  593. codex/urls/api/browser.py +10 -1
  594. codex/urls/converters.py +2 -5
  595. codex/urls/root.py +1 -1
  596. codex/util.py +14 -8
  597. codex/views/admin/api_key.py +1 -1
  598. codex/views/admin/flag.py +10 -9
  599. codex/views/admin/group.py +5 -3
  600. codex/views/admin/library.py +12 -9
  601. codex/views/admin/permissions.py +21 -0
  602. codex/views/admin/stats.py +6 -8
  603. codex/views/admin/tasks.py +47 -45
  604. codex/views/admin/user.py +5 -3
  605. codex/views/auth.py +29 -11
  606. codex/views/bookmark.py +25 -14
  607. codex/views/browser/annotate/bookmark.py +0 -3
  608. codex/views/browser/annotate/card.py +20 -5
  609. codex/views/browser/annotate/order.py +2 -6
  610. codex/views/browser/bookmark.py +10 -7
  611. codex/views/browser/breadcrumbs.py +7 -6
  612. codex/views/browser/browser.py +16 -16
  613. codex/views/browser/choices.py +81 -65
  614. codex/views/browser/cover.py +21 -19
  615. codex/views/browser/download.py +5 -5
  616. codex/views/browser/filters/bookmark.py +5 -0
  617. codex/views/browser/filters/field.py +3 -3
  618. codex/views/browser/filters/filter.py +3 -5
  619. codex/views/browser/filters/group.py +5 -5
  620. codex/views/browser/filters/search/field/column.py +13 -9
  621. codex/views/browser/filters/search/field/expression.py +1 -3
  622. codex/views/browser/filters/search/field/filter.py +2 -4
  623. codex/views/browser/filters/search/field/optimize.py +1 -1
  624. codex/views/browser/filters/search/field/parse.py +28 -7
  625. codex/views/browser/filters/search/fts.py +3 -4
  626. codex/views/browser/filters/search/parse.py +26 -26
  627. codex/views/browser/group_mtime.py +13 -10
  628. codex/views/browser/metadata/__init__.py +90 -1
  629. codex/views/browser/metadata/annotate.py +13 -27
  630. codex/views/browser/metadata/const.py +83 -0
  631. codex/views/browser/metadata/copy_intersections.py +14 -9
  632. codex/views/browser/metadata/query_intersections.py +67 -48
  633. codex/views/browser/mtime.py +4 -7
  634. codex/views/browser/order_by.py +4 -1
  635. codex/views/browser/page_in_bounds.py +5 -6
  636. codex/views/browser/paginate.py +3 -5
  637. codex/views/browser/params.py +3 -20
  638. codex/views/browser/settings.py +18 -4
  639. codex/views/browser/title.py +9 -5
  640. codex/views/browser/validate.py +6 -8
  641. codex/views/const.py +11 -9
  642. codex/views/download.py +2 -2
  643. codex/views/error.py +1 -1
  644. codex/views/exceptions.py +82 -0
  645. codex/views/frontend.py +8 -18
  646. codex/views/lazy_import.py +24 -0
  647. codex/views/mixins.py +34 -12
  648. codex/views/opds/auth.py +2 -2
  649. codex/views/opds/authentication_v1.py +2 -1
  650. codex/views/opds/const.py +1 -1
  651. codex/views/opds/urls.py +2 -1
  652. codex/views/opds/util.py +14 -41
  653. codex/views/opds/v1/entry/entry.py +12 -15
  654. codex/views/opds/v1/entry/links.py +15 -19
  655. codex/views/opds/v1/facets.py +8 -5
  656. codex/views/opds/v1/feed.py +23 -22
  657. codex/views/opds/v1/links.py +3 -7
  658. codex/views/opds/v1/opensearch_v1.py +7 -4
  659. codex/views/opds/v2/feed.py +13 -13
  660. codex/views/opds/v2/href.py +17 -12
  661. codex/views/opds/v2/links.py +3 -1
  662. codex/views/opds/v2/progression.py +31 -15
  663. codex/views/opds/v2/publications.py +18 -17
  664. codex/views/opds/v2/top_links.py +7 -2
  665. codex/views/public.py +12 -15
  666. codex/views/reader/arcs.py +143 -74
  667. codex/views/reader/books.py +72 -97
  668. codex/views/reader/page.py +13 -9
  669. codex/views/reader/params.py +32 -98
  670. codex/views/reader/reader.py +18 -73
  671. codex/views/reader/settings.py +4 -2
  672. codex/views/session.py +12 -19
  673. codex/views/settings.py +4 -9
  674. codex/views/template.py +8 -4
  675. codex/views/timezone.py +4 -5
  676. codex/views/util.py +3 -24
  677. codex/views/version.py +5 -3
  678. codex/websockets/consumers.py +7 -7
  679. codex/websockets/listener.py +4 -5
  680. codex-1.8.0a2.dist-info/METADATA +593 -0
  681. codex-1.8.0a2.dist-info/RECORD +1098 -0
  682. codex-1.8.0a2.dist-info/WHEEL +4 -0
  683. codex-1.8.0a2.dist-info/entry_points.txt +2 -0
  684. codex/db.py +0 -134
  685. codex/exceptions.py +0 -88
  686. codex/librarian/README.md +0 -4
  687. codex/librarian/delayed_taskd.py +0 -21
  688. codex/librarian/importer/__init__.py +0 -1
  689. codex/librarian/importer/aggregate.py +0 -256
  690. codex/librarian/importer/cache.py +0 -90
  691. codex/librarian/importer/const.py +0 -244
  692. codex/librarian/importer/create_comics.py +0 -139
  693. codex/librarian/importer/create_covers.py +0 -96
  694. codex/librarian/importer/create_fks.py +0 -346
  695. codex/librarian/importer/deleted.py +0 -138
  696. codex/librarian/importer/extract.py +0 -284
  697. codex/librarian/importer/failed_imports.py +0 -165
  698. codex/librarian/importer/importer.py +0 -101
  699. codex/librarian/importer/importerd.py +0 -122
  700. codex/librarian/importer/init.py +0 -264
  701. codex/librarian/importer/link_comics.py +0 -270
  702. codex/librarian/importer/link_covers.py +0 -73
  703. codex/librarian/importer/moved.py +0 -368
  704. codex/librarian/importer/query_covers.py +0 -53
  705. codex/librarian/importer/query_fks.py +0 -653
  706. codex/librarian/importer/status.py +0 -29
  707. codex/librarian/importer/tasks.py +0 -55
  708. codex/librarian/janitor/__init__.py +0 -1
  709. codex/librarian/janitor/cleanup.py +0 -167
  710. codex/librarian/janitor/failed_imports.py +0 -27
  711. codex/librarian/janitor/integrity.py +0 -378
  712. codex/librarian/janitor/janitor.py +0 -161
  713. codex/librarian/janitor/latest_version.py +0 -55
  714. codex/librarian/janitor/scheduled_time.py +0 -12
  715. codex/librarian/janitor/status.py +0 -22
  716. codex/librarian/janitor/tasks.py +0 -109
  717. codex/librarian/janitor/update.py +0 -109
  718. codex/librarian/janitor/vacuum.py +0 -51
  719. codex/librarian/search/__init__.py +0 -1
  720. codex/librarian/search/optimize.py +0 -43
  721. codex/librarian/search/remove.py +0 -53
  722. codex/librarian/search/searchd.py +0 -28
  723. codex/librarian/search/status.py +0 -13
  724. codex/librarian/search/tasks.py +0 -37
  725. codex/librarian/search/update.py +0 -305
  726. codex/librarian/watchdog/README.md +0 -11
  727. codex/logger/__init__.py +0 -1
  728. codex/logger/formatter.py +0 -36
  729. codex/logger/logger.py +0 -46
  730. codex/logger/loggerd.py +0 -102
  731. codex/logger/mp_queue.py +0 -5
  732. codex/logger_base.py +0 -12
  733. codex/memory.py +0 -56
  734. codex/permissions.py +0 -19
  735. codex/registration.py +0 -16
  736. codex/serializers/README.md +0 -4
  737. codex/settings/README.md +0 -4
  738. codex/settings/settings.py +0 -389
  739. codex/startup.py +0 -182
  740. codex/static_root/assets/VCheckbox-DraWPvy6.30c95a5ce5e6.js +0 -1
  741. codex/static_root/assets/VCheckbox-DraWPvy6.30c95a5ce5e6.js.br +0 -0
  742. codex/static_root/assets/VCheckbox-DraWPvy6.30c95a5ce5e6.js.gz +0 -0
  743. codex/static_root/assets/VCheckbox-DraWPvy6.js +0 -1
  744. codex/static_root/assets/VCheckbox-DraWPvy6.js.br +0 -0
  745. codex/static_root/assets/VCheckbox-DraWPvy6.js.gz +0 -0
  746. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.f38524c2448d.js +0 -1
  747. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.f38524c2448d.js.br +0 -0
  748. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.f38524c2448d.js.gz +0 -0
  749. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.js +0 -1
  750. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.js.br +0 -0
  751. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.js.gz +0 -0
  752. codex/static_root/assets/VCombobox-DKyNgHNV.b4e08dd5606d.js +0 -1
  753. codex/static_root/assets/VCombobox-DKyNgHNV.b4e08dd5606d.js.br +0 -0
  754. codex/static_root/assets/VCombobox-DKyNgHNV.b4e08dd5606d.js.gz +0 -0
  755. codex/static_root/assets/VCombobox-DKyNgHNV.js +0 -1
  756. codex/static_root/assets/VCombobox-DKyNgHNV.js.br +0 -0
  757. codex/static_root/assets/VCombobox-DKyNgHNV.js.gz +0 -0
  758. codex/static_root/assets/VDialog-C_zlnjF1.6c58e08b5374.css +0 -1
  759. codex/static_root/assets/VDialog-C_zlnjF1.6c58e08b5374.css.br +0 -0
  760. codex/static_root/assets/VDialog-C_zlnjF1.6c58e08b5374.css.gz +0 -0
  761. codex/static_root/assets/VDialog-C_zlnjF1.css +0 -1
  762. codex/static_root/assets/VDialog-C_zlnjF1.css.br +0 -0
  763. codex/static_root/assets/VDialog-C_zlnjF1.css.gz +0 -0
  764. codex/static_root/assets/VDialog-tf0N3lvG.eecb009783ed.js +0 -1
  765. codex/static_root/assets/VDialog-tf0N3lvG.eecb009783ed.js.br +0 -0
  766. codex/static_root/assets/VDialog-tf0N3lvG.eecb009783ed.js.gz +0 -0
  767. codex/static_root/assets/VDialog-tf0N3lvG.js +0 -1
  768. codex/static_root/assets/VDialog-tf0N3lvG.js.br +0 -0
  769. codex/static_root/assets/VDialog-tf0N3lvG.js.gz +0 -0
  770. codex/static_root/assets/VDivider-CTvTvFr_.3d0b477ddae0.js +0 -1
  771. codex/static_root/assets/VDivider-CTvTvFr_.3d0b477ddae0.js.br +0 -0
  772. codex/static_root/assets/VDivider-CTvTvFr_.3d0b477ddae0.js.gz +0 -0
  773. codex/static_root/assets/VDivider-CTvTvFr_.js +0 -1
  774. codex/static_root/assets/VDivider-CTvTvFr_.js.br +0 -0
  775. codex/static_root/assets/VDivider-CTvTvFr_.js.gz +0 -0
  776. codex/static_root/assets/VExpansionPanels-BjwwzLx6.203715bfa684.js +0 -1
  777. codex/static_root/assets/VExpansionPanels-BjwwzLx6.203715bfa684.js.br +0 -0
  778. codex/static_root/assets/VExpansionPanels-BjwwzLx6.203715bfa684.js.gz +0 -0
  779. codex/static_root/assets/VExpansionPanels-BjwwzLx6.js +0 -1
  780. codex/static_root/assets/VExpansionPanels-BjwwzLx6.js.br +0 -0
  781. codex/static_root/assets/VExpansionPanels-BjwwzLx6.js.gz +0 -0
  782. codex/static_root/assets/VForm-Dw7aCtM5.9266634dfe00.js +0 -1
  783. codex/static_root/assets/VForm-Dw7aCtM5.9266634dfe00.js.br +0 -0
  784. codex/static_root/assets/VForm-Dw7aCtM5.9266634dfe00.js.gz +0 -0
  785. codex/static_root/assets/VForm-Dw7aCtM5.js +0 -1
  786. codex/static_root/assets/VForm-Dw7aCtM5.js.br +0 -0
  787. codex/static_root/assets/VForm-Dw7aCtM5.js.gz +0 -0
  788. codex/static_root/assets/VRadioGroup-DJBFM2Br.79fa65084b8d.js +0 -1
  789. codex/static_root/assets/VRadioGroup-DJBFM2Br.79fa65084b8d.js.br +0 -0
  790. codex/static_root/assets/VRadioGroup-DJBFM2Br.79fa65084b8d.js.gz +0 -0
  791. codex/static_root/assets/VRadioGroup-DJBFM2Br.js +0 -1
  792. codex/static_root/assets/VRadioGroup-DJBFM2Br.js.br +0 -0
  793. codex/static_root/assets/VRadioGroup-DJBFM2Br.js.gz +0 -0
  794. codex/static_root/assets/VSelect-Cv8OuNtL.a5e2fe245f1a.js +0 -1
  795. codex/static_root/assets/VSelect-Cv8OuNtL.a5e2fe245f1a.js.br +0 -0
  796. codex/static_root/assets/VSelect-Cv8OuNtL.a5e2fe245f1a.js.gz +0 -0
  797. codex/static_root/assets/VSelect-Cv8OuNtL.js +0 -1
  798. codex/static_root/assets/VSelect-Cv8OuNtL.js.br +0 -0
  799. codex/static_root/assets/VSelect-Cv8OuNtL.js.gz +0 -0
  800. codex/static_root/assets/VSelectionControl-DoFzRlEh.a927b53c246b.js +0 -1
  801. codex/static_root/assets/VSelectionControl-DoFzRlEh.a927b53c246b.js.br +0 -0
  802. codex/static_root/assets/VSelectionControl-DoFzRlEh.a927b53c246b.js.gz +0 -0
  803. codex/static_root/assets/VSelectionControl-DoFzRlEh.js +0 -1
  804. codex/static_root/assets/VSelectionControl-DoFzRlEh.js.br +0 -0
  805. codex/static_root/assets/VSelectionControl-DoFzRlEh.js.gz +0 -0
  806. codex/static_root/assets/VTable-C-cNChDa.b2aabb112acf.js +0 -1
  807. codex/static_root/assets/VTable-C-cNChDa.b2aabb112acf.js.br +0 -0
  808. codex/static_root/assets/VTable-C-cNChDa.b2aabb112acf.js.gz +0 -0
  809. codex/static_root/assets/VTable-C-cNChDa.js +0 -1
  810. codex/static_root/assets/VTable-C-cNChDa.js.br +0 -0
  811. codex/static_root/assets/VTable-C-cNChDa.js.gz +0 -0
  812. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css +0 -1
  813. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.br +0 -0
  814. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.gz +0 -0
  815. codex/static_root/assets/VTable-CHRVGI94.css +0 -1
  816. codex/static_root/assets/VTable-CHRVGI94.css.br +0 -0
  817. codex/static_root/assets/VTable-CHRVGI94.css.gz +0 -0
  818. codex/static_root/assets/VWindowItem-CWBhiE_Y.css +0 -1
  819. codex/static_root/assets/VWindowItem-CWBhiE_Y.css.br +0 -0
  820. codex/static_root/assets/VWindowItem-CWBhiE_Y.css.gz +0 -0
  821. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css +0 -1
  822. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br +0 -0
  823. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz +0 -0
  824. codex/static_root/assets/VWindowItem-DL6bN3h7.45f85724527c.js +0 -1
  825. codex/static_root/assets/VWindowItem-DL6bN3h7.45f85724527c.js.br +0 -0
  826. codex/static_root/assets/VWindowItem-DL6bN3h7.45f85724527c.js.gz +0 -0
  827. codex/static_root/assets/VWindowItem-DL6bN3h7.js +0 -1
  828. codex/static_root/assets/VWindowItem-DL6bN3h7.js.br +0 -0
  829. codex/static_root/assets/VWindowItem-DL6bN3h7.js.gz +0 -0
  830. codex/static_root/assets/admin-BQ68PA7O.8bf1f757ca31.js +0 -1
  831. codex/static_root/assets/admin-BQ68PA7O.8bf1f757ca31.js.br +0 -0
  832. codex/static_root/assets/admin-BQ68PA7O.8bf1f757ca31.js.gz +0 -0
  833. codex/static_root/assets/admin-BQ68PA7O.js +0 -1
  834. codex/static_root/assets/admin-BQ68PA7O.js.br +0 -0
  835. codex/static_root/assets/admin-BQ68PA7O.js.gz +0 -0
  836. codex/static_root/assets/admin-Cg7RkTjo.191b04128f17.js +0 -1
  837. codex/static_root/assets/admin-Cg7RkTjo.191b04128f17.js.br +0 -0
  838. codex/static_root/assets/admin-Cg7RkTjo.191b04128f17.js.gz +0 -0
  839. codex/static_root/assets/admin-Cg7RkTjo.js +0 -1
  840. codex/static_root/assets/admin-Cg7RkTjo.js.br +0 -0
  841. codex/static_root/assets/admin-Cg7RkTjo.js.gz +0 -0
  842. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css +0 -1
  843. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.br +0 -0
  844. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.gz +0 -0
  845. codex/static_root/assets/admin-klMr_GZK.css +0 -1
  846. codex/static_root/assets/admin-klMr_GZK.css.br +0 -0
  847. codex/static_root/assets/admin-klMr_GZK.css.gz +0 -0
  848. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css +0 -1
  849. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.br +0 -0
  850. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.gz +0 -0
  851. codex/static_root/assets/admin-menu-CKlcsy9S.css +0 -1
  852. codex/static_root/assets/admin-menu-CKlcsy9S.css.br +0 -0
  853. codex/static_root/assets/admin-menu-CKlcsy9S.css.gz +0 -0
  854. codex/static_root/assets/admin-menu-Chx211s6.c63738168d93.js +0 -1
  855. codex/static_root/assets/admin-menu-Chx211s6.c63738168d93.js.br +0 -0
  856. codex/static_root/assets/admin-menu-Chx211s6.c63738168d93.js.gz +0 -0
  857. codex/static_root/assets/admin-menu-Chx211s6.js +0 -1
  858. codex/static_root/assets/admin-menu-Chx211s6.js.br +0 -0
  859. codex/static_root/assets/admin-menu-Chx211s6.js.gz +0 -0
  860. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.7689648ee782.js +0 -1
  861. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.7689648ee782.js.br +0 -0
  862. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.7689648ee782.js.gz +0 -0
  863. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.js +0 -1
  864. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.js.br +0 -0
  865. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.js.gz +0 -0
  866. codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.435dc945daf1.css +0 -1
  867. codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.css +0 -1
  868. codex/static_root/assets/browser-BKDmwxmv.6f4eca6489a1.js +0 -1
  869. codex/static_root/assets/browser-BKDmwxmv.6f4eca6489a1.js.br +0 -0
  870. codex/static_root/assets/browser-BKDmwxmv.6f4eca6489a1.js.gz +0 -0
  871. codex/static_root/assets/browser-BKDmwxmv.js +0 -1
  872. codex/static_root/assets/browser-BKDmwxmv.js.br +0 -0
  873. codex/static_root/assets/browser-BKDmwxmv.js.gz +0 -0
  874. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css +0 -1
  875. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.br +0 -0
  876. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.gz +0 -0
  877. codex/static_root/assets/browser-sNm790x9.css +0 -1
  878. codex/static_root/assets/browser-sNm790x9.css.br +0 -0
  879. codex/static_root/assets/browser-sNm790x9.css.gz +0 -0
  880. codex/static_root/assets/change-password-dialog-DqupgUbt.e35dc497629b.js +0 -1
  881. codex/static_root/assets/change-password-dialog-DqupgUbt.e35dc497629b.js.br +0 -0
  882. codex/static_root/assets/change-password-dialog-DqupgUbt.e35dc497629b.js.gz +0 -0
  883. codex/static_root/assets/change-password-dialog-DqupgUbt.js +0 -1
  884. codex/static_root/assets/change-password-dialog-DqupgUbt.js.br +0 -0
  885. codex/static_root/assets/change-password-dialog-DqupgUbt.js.gz +0 -0
  886. codex/static_root/assets/confirm-dialog-AMnfyuMm.278235fdacbf.js +0 -1
  887. codex/static_root/assets/confirm-dialog-AMnfyuMm.278235fdacbf.js.br +0 -0
  888. codex/static_root/assets/confirm-dialog-AMnfyuMm.278235fdacbf.js.gz +0 -0
  889. codex/static_root/assets/confirm-dialog-AMnfyuMm.js +0 -1
  890. codex/static_root/assets/confirm-dialog-AMnfyuMm.js.br +0 -0
  891. codex/static_root/assets/confirm-dialog-AMnfyuMm.js.gz +0 -0
  892. codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css +0 -1
  893. codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css.br +0 -0
  894. codex/static_root/assets/confirm-dialog-BI5kQLy_.css +0 -1
  895. codex/static_root/assets/confirm-dialog-BI5kQLy_.css.br +0 -0
  896. codex/static_root/assets/datetime-column-BavtvLnf.1f3bf499e063.css +0 -1
  897. codex/static_root/assets/datetime-column-BavtvLnf.css +0 -1
  898. codex/static_root/assets/datetime-column-m-oshrDM.7e17980c4b7a.js +0 -1
  899. codex/static_root/assets/datetime-column-m-oshrDM.7e17980c4b7a.js.br +0 -0
  900. codex/static_root/assets/datetime-column-m-oshrDM.7e17980c4b7a.js.gz +0 -0
  901. codex/static_root/assets/datetime-column-m-oshrDM.js +0 -1
  902. codex/static_root/assets/datetime-column-m-oshrDM.js.br +0 -0
  903. codex/static_root/assets/datetime-column-m-oshrDM.js.gz +0 -0
  904. codex/static_root/assets/filter-BucmWboA.c5589372c258.js +0 -1
  905. codex/static_root/assets/filter-BucmWboA.c5589372c258.js.br +0 -0
  906. codex/static_root/assets/filter-BucmWboA.c5589372c258.js.gz +0 -0
  907. codex/static_root/assets/filter-BucmWboA.js +0 -1
  908. codex/static_root/assets/filter-BucmWboA.js.br +0 -0
  909. codex/static_root/assets/filter-BucmWboA.js.gz +0 -0
  910. codex/static_root/assets/flag-tab-C434E1_2.49632d2b141d.js +0 -1
  911. codex/static_root/assets/flag-tab-C434E1_2.49632d2b141d.js.br +0 -0
  912. codex/static_root/assets/flag-tab-C434E1_2.49632d2b141d.js.gz +0 -0
  913. codex/static_root/assets/flag-tab-C434E1_2.js +0 -1
  914. codex/static_root/assets/flag-tab-C434E1_2.js.br +0 -0
  915. codex/static_root/assets/flag-tab-C434E1_2.js.gz +0 -0
  916. codex/static_root/assets/forwardRefs-C8KYLdfc.css +0 -1
  917. codex/static_root/assets/forwardRefs-C8KYLdfc.css.br +0 -0
  918. codex/static_root/assets/forwardRefs-C8KYLdfc.css.gz +0 -0
  919. codex/static_root/assets/forwardRefs-C8KYLdfc.f5843191eb9e.css +0 -1
  920. codex/static_root/assets/forwardRefs-C8KYLdfc.f5843191eb9e.css.br +0 -0
  921. codex/static_root/assets/forwardRefs-C8KYLdfc.f5843191eb9e.css.gz +0 -0
  922. codex/static_root/assets/forwardRefs-CGpIPavG.d61e8212d1dc.js +0 -1
  923. codex/static_root/assets/forwardRefs-CGpIPavG.d61e8212d1dc.js.br +0 -0
  924. codex/static_root/assets/forwardRefs-CGpIPavG.d61e8212d1dc.js.gz +0 -0
  925. codex/static_root/assets/forwardRefs-CGpIPavG.js +0 -1
  926. codex/static_root/assets/forwardRefs-CGpIPavG.js.br +0 -0
  927. codex/static_root/assets/forwardRefs-CGpIPavG.js.gz +0 -0
  928. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css +0 -1
  929. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.br +0 -0
  930. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.gz +0 -0
  931. codex/static_root/assets/group-tab-Bi681uR0.css +0 -1
  932. codex/static_root/assets/group-tab-Bi681uR0.css.br +0 -0
  933. codex/static_root/assets/group-tab-Bi681uR0.css.gz +0 -0
  934. codex/static_root/assets/group-tab-MrhEvTPy.9233e2e5e80e.js +0 -1
  935. codex/static_root/assets/group-tab-MrhEvTPy.9233e2e5e80e.js.br +0 -0
  936. codex/static_root/assets/group-tab-MrhEvTPy.9233e2e5e80e.js.gz +0 -0
  937. codex/static_root/assets/group-tab-MrhEvTPy.js +0 -1
  938. codex/static_root/assets/group-tab-MrhEvTPy.js.br +0 -0
  939. codex/static_root/assets/group-tab-MrhEvTPy.js.gz +0 -0
  940. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css +0 -1
  941. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.br +0 -0
  942. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.gz +0 -0
  943. codex/static_root/assets/http-error-CODU7jcH.css +0 -1
  944. codex/static_root/assets/http-error-CODU7jcH.css.br +0 -0
  945. codex/static_root/assets/http-error-CODU7jcH.css.gz +0 -0
  946. codex/static_root/assets/http-error-gBWEusWz.be314a60dc2e.js +0 -1
  947. codex/static_root/assets/http-error-gBWEusWz.be314a60dc2e.js.br +0 -0
  948. codex/static_root/assets/http-error-gBWEusWz.be314a60dc2e.js.gz +0 -0
  949. codex/static_root/assets/http-error-gBWEusWz.js +0 -1
  950. codex/static_root/assets/http-error-gBWEusWz.js.br +0 -0
  951. codex/static_root/assets/http-error-gBWEusWz.js.gz +0 -0
  952. codex/static_root/assets/index-Cu_QC2K8.de1f7935ff98.js +0 -1
  953. codex/static_root/assets/index-Cu_QC2K8.de1f7935ff98.js.br +0 -0
  954. codex/static_root/assets/index-Cu_QC2K8.de1f7935ff98.js.gz +0 -0
  955. codex/static_root/assets/index-Cu_QC2K8.js +0 -1
  956. codex/static_root/assets/index-Cu_QC2K8.js.br +0 -0
  957. codex/static_root/assets/index-Cu_QC2K8.js.gz +0 -0
  958. codex/static_root/assets/library-tab-Ce1d8Ypk.c87088afd4e1.js +0 -1
  959. codex/static_root/assets/library-tab-Ce1d8Ypk.c87088afd4e1.js.br +0 -0
  960. codex/static_root/assets/library-tab-Ce1d8Ypk.c87088afd4e1.js.gz +0 -0
  961. codex/static_root/assets/library-tab-Ce1d8Ypk.js +0 -1
  962. codex/static_root/assets/library-tab-Ce1d8Ypk.js.br +0 -0
  963. codex/static_root/assets/library-tab-Ce1d8Ypk.js.gz +0 -0
  964. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css +0 -1
  965. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.br +0 -0
  966. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.gz +0 -0
  967. codex/static_root/assets/library-tab-DLpvMqPW.css +0 -1
  968. codex/static_root/assets/library-tab-DLpvMqPW.css.br +0 -0
  969. codex/static_root/assets/library-tab-DLpvMqPW.css.gz +0 -0
  970. codex/static_root/assets/main-CpP-5rLh.ce09dfd7874f.js +0 -39
  971. codex/static_root/assets/main-CpP-5rLh.ce09dfd7874f.js.br +0 -0
  972. codex/static_root/assets/main-CpP-5rLh.ce09dfd7874f.js.gz +0 -0
  973. codex/static_root/assets/main-CpP-5rLh.js +0 -39
  974. codex/static_root/assets/main-CpP-5rLh.js.br +0 -0
  975. codex/static_root/assets/main-CpP-5rLh.js.gz +0 -0
  976. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css +0 -5
  977. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.br +0 -0
  978. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.gz +0 -0
  979. codex/static_root/assets/main-Of3aYkZ7.css +0 -5
  980. codex/static_root/assets/main-Of3aYkZ7.css.br +0 -0
  981. codex/static_root/assets/main-Of3aYkZ7.css.gz +0 -0
  982. codex/static_root/assets/pager-full-pdf-D8B8_31l.f1659a2dac96.js +0 -1
  983. codex/static_root/assets/pager-full-pdf-D8B8_31l.f1659a2dac96.js.br +0 -0
  984. codex/static_root/assets/pager-full-pdf-D8B8_31l.f1659a2dac96.js.gz +0 -0
  985. codex/static_root/assets/pager-full-pdf-D8B8_31l.js +0 -1
  986. codex/static_root/assets/pager-full-pdf-D8B8_31l.js.br +0 -0
  987. codex/static_root/assets/pager-full-pdf-D8B8_31l.js.gz +0 -0
  988. codex/static_root/assets/pagination-toolbar-OKWewkNI.a2773ff43624.js +0 -1
  989. codex/static_root/assets/pagination-toolbar-OKWewkNI.a2773ff43624.js.br +0 -0
  990. codex/static_root/assets/pagination-toolbar-OKWewkNI.a2773ff43624.js.gz +0 -0
  991. codex/static_root/assets/pagination-toolbar-OKWewkNI.js +0 -1
  992. codex/static_root/assets/pagination-toolbar-OKWewkNI.js.br +0 -0
  993. codex/static_root/assets/pagination-toolbar-OKWewkNI.js.gz +0 -0
  994. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css +0 -1
  995. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.br +0 -0
  996. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.gz +0 -0
  997. codex/static_root/assets/pagination-toolbar-aHRrdz48.css +0 -1
  998. codex/static_root/assets/pagination-toolbar-aHRrdz48.css.br +0 -0
  999. codex/static_root/assets/pagination-toolbar-aHRrdz48.css.gz +0 -0
  1000. codex/static_root/assets/pdf-doc-DpmuaK3i.2dca76dcae13.js +0 -372
  1001. codex/static_root/assets/pdf-doc-DpmuaK3i.2dca76dcae13.js.br +0 -0
  1002. codex/static_root/assets/pdf-doc-DpmuaK3i.2dca76dcae13.js.gz +0 -0
  1003. codex/static_root/assets/pdf-doc-DpmuaK3i.js +0 -372
  1004. codex/static_root/assets/pdf-doc-DpmuaK3i.js.br +0 -0
  1005. codex/static_root/assets/pdf-doc-DpmuaK3i.js.gz +0 -0
  1006. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css +0 -1
  1007. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.br +0 -0
  1008. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.gz +0 -0
  1009. codex/static_root/assets/reader-BwgJtbgj.css +0 -1
  1010. codex/static_root/assets/reader-BwgJtbgj.css.br +0 -0
  1011. codex/static_root/assets/reader-BwgJtbgj.css.gz +0 -0
  1012. codex/static_root/assets/reader-CyitMKSa.d70f4fc1c014.js +0 -2
  1013. codex/static_root/assets/reader-CyitMKSa.d70f4fc1c014.js.br +0 -0
  1014. codex/static_root/assets/reader-CyitMKSa.d70f4fc1c014.js.gz +0 -0
  1015. codex/static_root/assets/reader-CyitMKSa.js +0 -2
  1016. codex/static_root/assets/reader-CyitMKSa.js.br +0 -0
  1017. codex/static_root/assets/reader-CyitMKSa.js.gz +0 -0
  1018. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css +0 -1
  1019. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.br +0 -0
  1020. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.gz +0 -0
  1021. codex/static_root/assets/relation-chips-BuShhy1e.css +0 -1
  1022. codex/static_root/assets/relation-chips-BuShhy1e.css.br +0 -0
  1023. codex/static_root/assets/relation-chips-BuShhy1e.css.gz +0 -0
  1024. codex/static_root/assets/relation-chips-QzwrdJWs.99957808773d.js +0 -1
  1025. codex/static_root/assets/relation-chips-QzwrdJWs.99957808773d.js.br +0 -0
  1026. codex/static_root/assets/relation-chips-QzwrdJWs.99957808773d.js.gz +0 -0
  1027. codex/static_root/assets/relation-chips-QzwrdJWs.js +0 -1
  1028. codex/static_root/assets/relation-chips-QzwrdJWs.js.br +0 -0
  1029. codex/static_root/assets/relation-chips-QzwrdJWs.js.gz +0 -0
  1030. codex/static_root/assets/settings-drawer-DYzm391t.67fd6c1c26cd.js +0 -2
  1031. codex/static_root/assets/settings-drawer-DYzm391t.67fd6c1c26cd.js.br +0 -0
  1032. codex/static_root/assets/settings-drawer-DYzm391t.67fd6c1c26cd.js.gz +0 -0
  1033. codex/static_root/assets/settings-drawer-DYzm391t.js +0 -2
  1034. codex/static_root/assets/settings-drawer-DYzm391t.js.br +0 -0
  1035. codex/static_root/assets/settings-drawer-DYzm391t.js.gz +0 -0
  1036. codex/static_root/assets/settings-drawer-WyG6HLH-.css +0 -1
  1037. codex/static_root/assets/settings-drawer-WyG6HLH-.css.br +0 -0
  1038. codex/static_root/assets/settings-drawer-WyG6HLH-.css.gz +0 -0
  1039. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css +0 -1
  1040. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.br +0 -0
  1041. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.gz +0 -0
  1042. codex/static_root/assets/ssrBoot-D216TWr1.0b11737afb21.js +0 -1
  1043. codex/static_root/assets/ssrBoot-D216TWr1.0b11737afb21.js.br +0 -0
  1044. codex/static_root/assets/ssrBoot-D216TWr1.0b11737afb21.js.gz +0 -0
  1045. codex/static_root/assets/ssrBoot-D216TWr1.js +0 -1
  1046. codex/static_root/assets/ssrBoot-D216TWr1.js.br +0 -0
  1047. codex/static_root/assets/ssrBoot-D216TWr1.js.gz +0 -0
  1048. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css +0 -1
  1049. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.br +0 -0
  1050. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.gz +0 -0
  1051. codex/static_root/assets/stats-tab-CGY8r-es.css +0 -1
  1052. codex/static_root/assets/stats-tab-CGY8r-es.css.br +0 -0
  1053. codex/static_root/assets/stats-tab-CGY8r-es.css.gz +0 -0
  1054. codex/static_root/assets/stats-tab-CXkOoD0h.1e2709686bf6.js +0 -1
  1055. codex/static_root/assets/stats-tab-CXkOoD0h.1e2709686bf6.js.br +0 -0
  1056. codex/static_root/assets/stats-tab-CXkOoD0h.1e2709686bf6.js.gz +0 -0
  1057. codex/static_root/assets/stats-tab-CXkOoD0h.js +0 -1
  1058. codex/static_root/assets/stats-tab-CXkOoD0h.js.br +0 -0
  1059. codex/static_root/assets/stats-tab-CXkOoD0h.js.gz +0 -0
  1060. codex/static_root/assets/task-tab-BlzgZqUZ.9448f1240271.js +0 -1
  1061. codex/static_root/assets/task-tab-BlzgZqUZ.9448f1240271.js.br +0 -0
  1062. codex/static_root/assets/task-tab-BlzgZqUZ.9448f1240271.js.gz +0 -0
  1063. codex/static_root/assets/task-tab-BlzgZqUZ.js +0 -1
  1064. codex/static_root/assets/task-tab-BlzgZqUZ.js.br +0 -0
  1065. codex/static_root/assets/task-tab-BlzgZqUZ.js.gz +0 -0
  1066. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css +0 -1
  1067. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.br +0 -0
  1068. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.gz +0 -0
  1069. codex/static_root/assets/unauthorized-DE63n2Pi.css +0 -1
  1070. codex/static_root/assets/unauthorized-DE63n2Pi.css.br +0 -0
  1071. codex/static_root/assets/unauthorized-DE63n2Pi.css.gz +0 -0
  1072. codex/static_root/assets/unauthorized-_61uqek6.56ab5c978077.js +0 -1
  1073. codex/static_root/assets/unauthorized-_61uqek6.56ab5c978077.js.br +0 -0
  1074. codex/static_root/assets/unauthorized-_61uqek6.56ab5c978077.js.gz +0 -0
  1075. codex/static_root/assets/unauthorized-_61uqek6.js +0 -1
  1076. codex/static_root/assets/unauthorized-_61uqek6.js.br +0 -0
  1077. codex/static_root/assets/unauthorized-_61uqek6.js.gz +0 -0
  1078. codex/static_root/assets/user-tab-CNxfPmZf.aed110a6c62b.js +0 -1
  1079. codex/static_root/assets/user-tab-CNxfPmZf.aed110a6c62b.js.br +0 -0
  1080. codex/static_root/assets/user-tab-CNxfPmZf.aed110a6c62b.js.gz +0 -0
  1081. codex/static_root/assets/user-tab-CNxfPmZf.js +0 -1
  1082. codex/static_root/assets/user-tab-CNxfPmZf.js.br +0 -0
  1083. codex/static_root/assets/user-tab-CNxfPmZf.js.gz +0 -0
  1084. codex/static_root/img/folder.f28936a3701d.svg +0 -1
  1085. codex/static_root/img/folder.f28936a3701d.svg.br +0 -0
  1086. codex/static_root/img/folder.f28936a3701d.svg.gz +0 -0
  1087. codex/static_root/img/imprint.7c2adebb76d6.svg +0 -1
  1088. codex/static_root/img/imprint.7c2adebb76d6.svg.br +0 -0
  1089. codex/static_root/img/imprint.7c2adebb76d6.svg.gz +0 -0
  1090. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg +0 -1
  1091. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.br +0 -0
  1092. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.gz +0 -0
  1093. codex/static_root/img/logo.0f5344a028ca.svg +0 -1
  1094. codex/static_root/img/logo.0f5344a028ca.svg.br +0 -0
  1095. codex/static_root/img/logo.0f5344a028ca.svg.gz +0 -0
  1096. codex/static_root/img/missing-cover-165.0743171f2148.webp +0 -0
  1097. codex/static_root/img/missing-cover.ddb038cc2c56.svg +0 -1
  1098. codex/static_root/img/missing-cover.ddb038cc2c56.svg.br +0 -0
  1099. codex/static_root/img/missing-cover.ddb038cc2c56.svg.gz +0 -0
  1100. codex/static_root/img/series.ec8a889b8f95.svg +0 -1
  1101. codex/static_root/img/series.ec8a889b8f95.svg.br +0 -0
  1102. codex/static_root/img/series.ec8a889b8f95.svg.gz +0 -0
  1103. codex/static_root/img/story-arc.ca10014355ef.svg +0 -1
  1104. codex/static_root/img/story-arc.ca10014355ef.svg.br +0 -1
  1105. codex/static_root/img/story-arc.ca10014355ef.svg.gz +0 -0
  1106. codex/static_root/img/volume.814e4c79461a.svg +0 -1
  1107. codex/static_root/img/volume.814e4c79461a.svg.br +0 -0
  1108. codex/static_root/img/volume.814e4c79461a.svg.gz +0 -0
  1109. codex/static_root/manifest.95906ea9e563.json +0 -757
  1110. codex/static_root/manifest.95906ea9e563.json.br +0 -0
  1111. codex/static_root/manifest.95906ea9e563.json.gz +0 -0
  1112. codex/status.py +0 -35
  1113. codex/status_controller.py +0 -153
  1114. codex/templates/README.md +0 -3
  1115. codex/threads.py +0 -130
  1116. codex/views/README.md +0 -4
  1117. codex/views/browser/filters/search/aliases.py +0 -81
  1118. codex/views/browser/metadata/metadata.py +0 -83
  1119. codex/websockets/README.md +0 -4
  1120. codex/worker_base.py +0 -14
  1121. codex-1.7.15.dist-info/METADATA +0 -599
  1122. codex-1.7.15.dist-info/RECORD +0 -1052
  1123. codex-1.7.15.dist-info/WHEEL +0 -4
  1124. codex-1.7.15.dist-info/entry_points.txt +0 -3
  1125. {codex-1.7.15.dist-info → codex-1.8.0a2.dist-info/licenses}/LICENSE +0 -0
@@ -1,27 +1,19 @@
1
1
  """Metadata query fk & m2m intersections."""
2
2
 
3
- from types import MappingProxyType
4
-
5
3
  from django.db.models import Count
4
+ from django.db.models.query import QuerySet
6
5
 
7
- from codex.librarian.importer.const import COMIC_M2M_FIELD_NAMES
6
+ from codex.librarian.scribe.importer.const import COMIC_FK_FIELDS, COMIC_M2M_FIELDS
8
7
  from codex.models import Comic
9
8
  from codex.models.functions import JsonGroupArray
10
- from codex.models.groups import Imprint, Publisher, Series, Volume
9
+ from codex.models.groups import Volume
11
10
  from codex.views.browser.metadata.annotate import MetadataAnnotateView
12
- from codex.views.const import METADATA_GROUP_RELATION, MODEL_REL_MAP
13
-
14
- _CONTRIBUTOR_RELATIONS = ("role", "person")
15
- _GROUP_MODELS = MappingProxyType(
16
- {
17
- "i": (Publisher,),
18
- "s": (Publisher, Imprint),
19
- "v": (Publisher, Imprint, Series),
20
- "c": (Publisher, Imprint, Series, Volume),
21
- "f": (Publisher, Imprint, Series, Volume),
22
- "a": (Publisher, Imprint, Series, Volume),
23
- }
11
+ from codex.views.browser.metadata.const import (
12
+ COMIC_MAIN_FIELD_NAME_BACK_REL_MAP,
13
+ GROUP_MODELS,
14
+ M2M_QUERY_OPTIMIZERS,
24
15
  )
16
+ from codex.views.const import METADATA_GROUP_RELATION, MODEL_REL_MAP
25
17
 
26
18
 
27
19
  class MetadataQueryIntersectionsView(MetadataAnnotateView):
@@ -40,32 +32,30 @@ class MetadataQueryIntersectionsView(MetadataAnnotateView):
40
32
  pks = self.kwargs["pks"]
41
33
  group_filter = {rel: pks}
42
34
 
43
- for model in _GROUP_MODELS.get(group, ()):
35
+ for model in GROUP_MODELS.get(group, ()):
44
36
  field_name = MODEL_REL_MAP[model]
45
37
  qs = model.objects.filter(**group_filter)
46
- qs = qs.only("name").distinct()
47
- qs = qs.group_by("name") # type:ignore[reportAttributeAccessIssue]
38
+ only = ["name"]
39
+ if model is Volume:
40
+ only.append("number_to")
41
+ qs = qs.only(*only).distinct()
42
+ qs = qs.group_by(*only) # pyright:ignore[reportAttributeAccessIssue]
48
43
  qs = qs.annotate(ids=JsonGroupArray("id", distinct=True))
49
- qs = qs.values("ids", "name")
44
+ qs = qs.values("ids", *only)
50
45
  groups[field_name] = qs
51
46
  return groups
52
47
 
53
48
  @staticmethod
54
- def _get_optimized_m2m_query(key, qs):
55
- if key == "contributors":
56
- qs = qs.prefetch_related(*_CONTRIBUTOR_RELATIONS)
57
- qs = qs.only(*_CONTRIBUTOR_RELATIONS)
58
- elif key == "story_arc_numbers":
59
- qs = qs.select_related("story_arc")
60
- qs = qs.only("story_arc", "number")
61
- elif key == "identifiers":
62
- qs = qs.select_related("identifier_type")
63
- qs = qs.only("identifier_type", "nss", "url")
64
- else:
65
- qs = qs.only("name")
66
- return qs
67
-
68
- def _get_m2m_intersection_query(self, field_name, comic_pks, comic_pks_count):
49
+ def _get_optimized_m2m_query(qs):
50
+ optimizers = M2M_QUERY_OPTIMIZERS.get(qs.model, {})
51
+ if prefetch := optimizers.get("prefetch"):
52
+ qs = qs.prefetch_related(*prefetch)
53
+ if select := optimizers.get("select", ("identifier",)):
54
+ qs = qs.select_related(*select)
55
+ only = optimizers.get("only", ("name", "identifier"))
56
+ return qs.only(*only)
57
+
58
+ def _get_m2m_intersection_query(self, field_name: str, comic_pks: frozenset[int]):
69
59
  """Get intersection query for one field."""
70
60
  model = Comic._meta.get_field(field_name).related_model
71
61
  if not model:
@@ -74,29 +64,58 @@ class MetadataQueryIntersectionsView(MetadataAnnotateView):
74
64
 
75
65
  intersection_qs = model.objects.filter(comic__pk__in=comic_pks)
76
66
  intersection_qs = intersection_qs.alias(count=Count("comic")).filter(
77
- count=comic_pks_count
67
+ count=len(comic_pks)
78
68
  )
79
- return self._get_optimized_m2m_query(field_name, intersection_qs)
69
+ return self._get_optimized_m2m_query(intersection_qs)
80
70
 
81
- def _query_m2m_intersections(self, filtered_qs):
82
- """Query the through models to figure out m2m intersections."""
83
- # Speed ok, but still does a query per m2m model
84
- m2m_intersections = {}
71
+ def _get_comic_pks(self, filtered_qs: QuerySet) -> frozenset[int]:
85
72
  pk_field = self.rel_prefix + "pk"
86
73
  comic_pks = filtered_qs.distinct().values_list(pk_field, flat=True)
87
74
  # In fts mode the join doesn't work for the query.
88
75
  # Evaluating it now is probably faster than running the filter for every m2m anyway.
89
- comic_pks = set(comic_pks)
90
- comic_pks_count = len(comic_pks)
76
+ return frozenset(comic_pks)
77
+
78
+ def _query_m2m_intersections(self, comic_pks: frozenset[int]):
79
+ """Query the through models to figure out m2m intersections."""
80
+ # Speed ok, but still does a query per m2m model
81
+ m2m_intersections = {}
91
82
 
92
- for field_name in COMIC_M2M_FIELD_NAMES:
93
- m2m_intersections[field_name] = self._get_m2m_intersection_query(
94
- field_name, comic_pks, comic_pks_count
83
+ for field in COMIC_M2M_FIELDS:
84
+ m2m_intersections[field.name] = self._get_m2m_intersection_query(
85
+ field.name, comic_pks
95
86
  )
96
87
  return m2m_intersections
97
88
 
89
+ def _get_fk_intersection_query(
90
+ self, field_name: str, comic_pks: frozenset[int], rel: str
91
+ ):
92
+ """Get intersection query for one field."""
93
+ model = Comic._meta.get_field(field_name).related_model
94
+ if not model:
95
+ reason = f"No model found for comic field: {field_name}"
96
+ raise ValueError(reason)
97
+
98
+ rel += "__in"
99
+ intersection_qs = model.objects.filter(**{rel: comic_pks})
100
+ intersection_qs = intersection_qs.alias(count=Count("comic")).filter(
101
+ count=len(comic_pks)
102
+ )
103
+ return intersection_qs.only("name")
104
+
105
+ def _query_fk_intersections(self, comic_pks: frozenset[int]):
106
+ fk_intersections = {}
107
+
108
+ for field in COMIC_FK_FIELDS:
109
+ rel = COMIC_MAIN_FIELD_NAME_BACK_REL_MAP.get(field.name, "comic__pk")
110
+ fk_intersections[field.name] = self._get_fk_intersection_query(
111
+ field.name, comic_pks, rel
112
+ )
113
+ return fk_intersections
114
+
98
115
  def query_intersections(self, filtered_qs):
99
116
  """Query complex intersections."""
100
117
  groups = self._query_groups()
101
- m2m_intersections = self._query_m2m_intersections(filtered_qs)
102
- return groups, m2m_intersections
118
+ comic_pks = self._get_comic_pks(filtered_qs)
119
+ fk_intersections = self._query_fk_intersections(comic_pks)
120
+ m2m_intersections = self._query_m2m_intersections(comic_pks)
121
+ return groups, fk_intersections, m2m_intersections
@@ -2,25 +2,22 @@
2
2
 
3
3
  from drf_spectacular.utils import extend_schema
4
4
  from rest_framework.response import Response
5
+ from rest_framework.serializers import BaseSerializer
5
6
 
6
- from codex.logger.logger import get_logger
7
7
  from codex.models.groups import Publisher
8
8
  from codex.serializers.browser.mtime import GroupsMtimeSerializer, MtimeSerializer
9
9
  from codex.util import max_none
10
10
  from codex.views.browser.group_mtime import BrowserGroupMtimeView
11
11
  from codex.views.const import GROUP_MODEL_MAP
12
12
 
13
- LOG = get_logger(__name__)
14
-
15
13
 
16
14
  class MtimeView(BrowserGroupMtimeView):
17
15
  """Get the mtimes for the submitted groups."""
18
16
 
19
- input_serializer_class = GroupsMtimeSerializer
20
- serializer_class = MtimeSerializer
17
+ input_serializer_class: type[GroupsMtimeSerializer] = GroupsMtimeSerializer # pyright: ignore[reportIncompatibleVariableOverride]
18
+ serializer_class: type[BaseSerializer] | None = MtimeSerializer
21
19
 
22
- REPARSE_JSON_FIELDS = frozenset({"groups", "filters"})
23
- TARGET = "mtime"
20
+ TARGET: str = "mtime"
24
21
 
25
22
  def _get_group_mtime(self, item):
26
23
  """Get one group's mtimes."""
@@ -1,6 +1,7 @@
1
1
  """Base view for ordering the query."""
2
2
 
3
3
  from codex.models import Comic
4
+ from codex.models.groups import Volume
4
5
  from codex.views.browser.group_mtime import BrowserGroupMtimeView
5
6
 
6
7
 
@@ -39,6 +40,7 @@ class BrowserOrderByView(BrowserGroupMtimeView):
39
40
  *comic_sort_names,
40
41
  "issue_number",
41
42
  "issue_suffix",
43
+ "collection_title",
42
44
  "sort_name",
43
45
  ]
44
46
  else:
@@ -55,9 +57,10 @@ class BrowserOrderByView(BrowserGroupMtimeView):
55
57
 
56
58
  def add_order_by(self, qs, order_key="", comic_sort_names=None):
57
59
  """Create the order_by list."""
58
- order_fields_head = ()
59
60
  if qs.model is Comic:
60
61
  order_fields_head = self._add_comic_order_by(order_key, comic_sort_names)
62
+ elif qs.model is Volume and order_key == "sort_name":
63
+ order_fields_head = ["name", "number_to"]
61
64
  else:
62
65
  order_fields_head = ["order_value"]
63
66
 
@@ -1,18 +1,17 @@
1
1
  """Browser Page Bounds Checking."""
2
2
 
3
- from codex.logger.logger import get_logger
3
+ from loguru import logger
4
+
4
5
  from codex.views.browser.annotate.card import BrowserAnnotateCardView
5
6
  from codex.views.util import Route
6
7
 
7
- LOG = get_logger(__name__)
8
-
9
8
 
10
9
  class BrowserPageInBoundsView(BrowserAnnotateCardView):
11
10
  """Browser Page Bounds Checking."""
12
11
 
13
12
  def _get_back_one_page_route(self, num_pages):
14
13
  """Get max page if oob or 1."""
15
- LOG.debug("Redirect back one page.")
14
+ logger.debug("Redirect back one page.")
16
15
  group = self.kwargs.get("group")
17
16
  pks = self.kwargs.get("pks")
18
17
  page = self.kwargs.get("page", 1)
@@ -49,14 +48,14 @@ class BrowserPageInBoundsView(BrowserAnnotateCardView):
49
48
  up_breadcrumbs = self._get_up_breadcrumbs()
50
49
  route_mask = up_breadcrumbs[-1]
51
50
  settings_mask = {"breadcrumbs": up_breadcrumbs}
52
- LOG.debug("Redirect up a level.")
51
+ logger.debug("Redirect up a level.")
53
52
  except IndexError:
54
53
  group = self.kwargs.get("group")
55
54
  pks = "0"
56
55
  new_page = 1
57
56
  route_mask = {"group": group, "pks": pks, "page": new_page}
58
57
  settings_mask = {"breadcrumbs": [route_mask]}
59
- LOG.debug("Redirect to all at current group.")
58
+ logger.debug("Redirect to all at current group.")
60
59
  return route_mask, settings_mask
61
60
 
62
61
  def _handle_page_out_of_bounds(self, num_pages):
@@ -3,13 +3,11 @@
3
3
  from math import ceil
4
4
 
5
5
  from django.core.paginator import EmptyPage, Paginator
6
+ from loguru import logger
6
7
 
7
- from codex.logger.logger import get_logger
8
- from codex.settings.settings import MAX_OBJ_PER_PAGE
8
+ from codex.settings import MAX_OBJ_PER_PAGE
9
9
  from codex.views.browser.page_in_bounds import BrowserPageInBoundsView
10
10
 
11
- LOG = get_logger(__name__)
12
-
13
11
 
14
12
  class BrowserPaginateView(BrowserPageInBoundsView):
15
13
  """Paginate Groups and Books."""
@@ -24,7 +22,7 @@ class BrowserPaginateView(BrowserPageInBoundsView):
24
22
  except EmptyPage:
25
23
  if self.model_group != "f":
26
24
  model_name = qs.model.__name__ if qs.model else "UnknownGroup"
27
- LOG.warning(f"No {model_name}s on page {page}")
25
+ logger.warning(f"No {model_name}s on page {page}")
28
26
  qs = qs.model.objects.none()
29
27
 
30
28
  return qs
@@ -6,39 +6,23 @@ from typing import Any
6
6
  from codex.serializers.browser.settings import BrowserSettingsSerializer
7
7
  from codex.views.const import FOLDER_GROUP, STORY_ARC_GROUP
8
8
  from codex.views.session import SessionView
9
- from codex.views.util import reparse_json_query_params
10
9
 
11
10
 
12
11
  class BrowserParamsView(SessionView):
13
12
  """Browser Params Parsing."""
14
13
 
15
- input_serializer_class = BrowserSettingsSerializer
16
- REPARSE_JSON_FIELDS = frozenset({"breadcrumbs", "filters", "show"})
14
+ input_serializer_class: type[BrowserSettingsSerializer] = BrowserSettingsSerializer
17
15
 
18
16
  def __init__(self, *args, **kwargs):
19
17
  """Initialize properties."""
20
18
  super().__init__(*args, **kwargs)
21
19
  self._params: MappingProxyType[str, Any] | None = None
22
20
 
23
- def _parse_query_params(self):
24
- """Parse GET query parameters: filter object & snake case."""
25
- query_params = reparse_json_query_params(
26
- self.request.GET, self.REPARSE_JSON_FIELDS
27
- )
28
- if "q" not in query_params and (query := query_params.get("query")):
29
- # parse query param for opds v2
30
- query_params["q"] = query
31
- return query_params
32
-
33
- def validate_settings(self):
34
- """Not used until browser/validate.py."""
35
-
36
21
  @property
37
22
  def params(self):
38
- """Validate sbmitted settings and apply them over the session settings."""
23
+ """Validate submitted settings and apply them over the session settings."""
39
24
  if self._params is None:
40
- data = self._parse_query_params()
41
- serializer = self.input_serializer_class(data=data)
25
+ serializer = self.input_serializer_class(data=self.request.GET)
42
26
  serializer.is_valid(raise_exception=True)
43
27
 
44
28
  params: dict[str, Any] = {}
@@ -60,5 +44,4 @@ class BrowserParamsView(SessionView):
60
44
  if validated_data:
61
45
  params.update(validated_data)
62
46
  self._params = MappingProxyType(params)
63
- self.validate_settings()
64
47
  return self._params
@@ -1,6 +1,13 @@
1
1
  """Browser session view."""
2
2
 
3
- from codex.serializers.browser.settings import BrowserSettingsSerializer
3
+ from drf_spectacular.utils import extend_schema
4
+ from rest_framework.serializers import BaseSerializer
5
+ from typing_extensions import override
6
+
7
+ from codex.serializers.browser.settings import (
8
+ BrowserSettingsInputSerializer,
9
+ BrowserSettingsSerializer,
10
+ )
4
11
  from codex.views.const import GROUP_ORDER
5
12
  from codex.views.settings import SettingsView
6
13
 
@@ -8,10 +15,11 @@ from codex.views.settings import SettingsView
8
15
  class BrowserSettingsView(SettingsView):
9
16
  """Get Browser Settings."""
10
17
 
18
+ input_serializer_class = BrowserSettingsInputSerializer
11
19
  # Put Browser Settings is normally done through BrowserView.get()
12
- serializer_class = BrowserSettingsSerializer
20
+ serializer_class: type[BaseSerializer] | None = BrowserSettingsSerializer
13
21
 
14
- SESSION_KEY = SettingsView.BROWSER_SESSION_KEY
22
+ SESSION_KEY: str = SettingsView.BROWSER_SESSION_KEY
15
23
 
16
24
  @staticmethod
17
25
  def _strip_breadcrumb_names(params):
@@ -49,11 +57,12 @@ class BrowserSettingsView(SettingsView):
49
57
  if group == top_group:
50
58
  return
51
59
 
52
- if group in ("f", "a"):
60
+ if group in "fa":
53
61
  params["top_group"] = group
54
62
  else:
55
63
  cls._validate_browse_top_group(params, group, top_group)
56
64
 
65
+ @override
57
66
  def validate_settings_get(self, validated_data, params):
58
67
  """Change bad settings."""
59
68
  top_group = params["top_group"]
@@ -64,3 +73,8 @@ class BrowserSettingsView(SettingsView):
64
73
  params = self._strip_breadcrumb_names(params)
65
74
 
66
75
  return params
76
+
77
+ @override
78
+ @extend_schema(parameters=[BrowserSettingsInputSerializer])
79
+ def get(self, *args, **kwargs):
80
+ return super().get(*args, **kwargs)
@@ -18,26 +18,30 @@ class BrowserTitleView(BrowserBreadcrumbsView):
18
18
  return plural.capitalize(), 0
19
19
 
20
20
  def _get_group_name(self):
21
+ group_number_to = None
21
22
  group_count = 0
23
+ group_name = ""
22
24
  if gi := self.group_instance:
25
+ group_name = gi.name
23
26
  if isinstance(gi, Volume):
27
+ group_number_to = gi.number_to
24
28
  group_count = gi.series.volume_count
25
29
  elif isinstance(gi, Comic):
30
+ group_number_to = gi.volume.number_to
26
31
  group_count = gi.volume.issue_count
27
- group_name = gi.name
28
- else:
29
- group_name = ""
30
- return group_name, group_count
32
+ return group_name, group_number_to, group_count
31
33
 
32
34
  def get_browser_page_title(self):
33
35
  """Get the proper title for this browse level."""
34
36
  pks = self.kwargs.get("pks")
35
37
  if not pks:
36
38
  group_name, group_count = self._get_root_group_name()
39
+ group_number_to = None
37
40
  else:
38
- group_name, group_count = self._get_group_name()
41
+ group_name, group_number_to, group_count = self._get_group_name()
39
42
 
40
43
  return {
41
44
  "group_name": group_name,
45
+ "group_number_to": group_number_to,
42
46
  "group_count": group_count,
43
47
  }
@@ -5,11 +5,10 @@ from copy import deepcopy
5
5
  from types import MappingProxyType
6
6
  from typing import Any
7
7
 
8
+ from loguru import logger
8
9
  from rest_framework.exceptions import NotFound
9
10
 
10
11
  from codex.choices.browser import DEFAULT_BROWSER_ROUTE
11
- from codex.exceptions import SeeOtherRedirectError
12
- from codex.logger.logger import get_logger
13
12
  from codex.models.groups import BrowserGroupModel
14
13
  from codex.util import mapping_to_dict
15
14
  from codex.views.browser.filters.search.parse import SearchFilterView
@@ -20,8 +19,7 @@ from codex.views.const import (
20
19
  ROOT_GROUP,
21
20
  STORY_ARC_GROUP,
22
21
  )
23
-
24
- LOG = get_logger(__name__)
22
+ from codex.views.exceptions import SeeOtherRedirectError
25
23
 
26
24
 
27
25
  class BrowserValidateView(SearchFilterView):
@@ -58,7 +56,7 @@ class BrowserValidateView(SearchFilterView):
58
56
  if model is None:
59
57
  group = self.kwargs["group"]
60
58
  detail = f"Cannot browse {group=}"
61
- LOG.debug(detail)
59
+ logger.debug(detail)
62
60
  raise NotFound(detail=detail)
63
61
  self._model = model
64
62
  return self._model
@@ -74,10 +72,10 @@ class BrowserValidateView(SearchFilterView):
74
72
  self, reason, route_mask=None, settings_mask: Mapping | None = None
75
73
  ):
76
74
  """Redirect the client to a valid group url."""
77
- route: dict[str, Any] = mapping_to_dict(self.DEFAULT_ROUTE) # type:ignore[reportAssignmentType]
75
+ route: dict[str, Any] = mapping_to_dict(self.DEFAULT_ROUTE)
78
76
  if route_mask:
79
77
  route["params"].update(route_mask)
80
- settings: dict[str, Any] = deepcopy(mapping_to_dict(self.params)) # type: ignore[reportAssignmentType]
78
+ settings: dict[str, Any] = deepcopy(mapping_to_dict(self.params))
81
79
  if settings_mask:
82
80
  settings.update(settings_mask)
83
81
  detail = {"route": route, "settings": settings, "reason": reason}
@@ -104,7 +102,7 @@ class BrowserValidateView(SearchFilterView):
104
102
  nav_group = self.kwargs.get("group")
105
103
  top_group = self.params.get("top_group")
106
104
  if top_group not in valid_top_groups:
107
- reason = f"top_group {top_group} not in valid nav groups, changed to "
105
+ reason = f"top_group {top_group} not in valid nav groups {valid_top_groups}, changed to "
108
106
  if nav_group in valid_top_groups:
109
107
  valid_top_group = nav_group
110
108
  reason += "nav group: "
codex/views/const.py CHANGED
@@ -13,14 +13,14 @@ from codex.models import (
13
13
  BrowserGroupModel,
14
14
  Character,
15
15
  Comic,
16
- Contributor,
17
- ContributorPerson,
18
- ContributorRole,
19
16
  Country,
17
+ Credit,
18
+ CreditPerson,
19
+ CreditRole,
20
20
  Folder,
21
21
  Genre,
22
22
  Identifier,
23
- IdentifierType,
23
+ IdentifierSource,
24
24
  Imprint,
25
25
  Language,
26
26
  Library,
@@ -35,9 +35,10 @@ from codex.models import (
35
35
  Tag,
36
36
  Tagger,
37
37
  Team,
38
+ Universe,
38
39
  Volume,
39
40
  )
40
- from codex.settings.settings import CODEX_PATH
41
+ from codex.settings import CODEX_PATH
41
42
 
42
43
  ROOT_GROUP = "r"
43
44
  FOLDER_GROUP = "f"
@@ -124,9 +125,12 @@ METADATA_MODELS = (
124
125
  AgeRating,
125
126
  Character,
126
127
  Country,
128
+ Credit,
129
+ CreditPerson,
130
+ CreditRole,
127
131
  Genre,
128
132
  Identifier,
129
- IdentifierType,
133
+ IdentifierSource,
130
134
  Language,
131
135
  Location,
132
136
  OriginalFormat,
@@ -137,9 +141,7 @@ METADATA_MODELS = (
137
141
  Team,
138
142
  Tag,
139
143
  Tagger,
140
- Contributor,
141
- ContributorPerson,
142
- ContributorRole,
144
+ Universe,
143
145
  )
144
146
  CONFIG_MODELS = (
145
147
  Library,
codex/views/download.py CHANGED
@@ -15,7 +15,7 @@ class DownloadView(AuthFilterAPIView):
15
15
 
16
16
  content_type = "application/vnd.comicbook+zip"
17
17
 
18
- AS_ATTACHMENT = True
18
+ AS_ATTACHMENT: bool = True
19
19
 
20
20
  @extend_schema(responses={(200, content_type): OpenApiTypes.BINARY})
21
21
  def get(self, *_args, **kwargs):
@@ -55,4 +55,4 @@ class DownloadView(AuthFilterAPIView):
55
55
  class FileView(DownloadView):
56
56
  """View a single comic in the browser."""
57
57
 
58
- AS_ATTACHMENT = False
58
+ AS_ATTACHMENT: bool = False
codex/views/error.py CHANGED
@@ -5,7 +5,7 @@ from django.urls import reverse
5
5
  from rest_framework import status
6
6
  from rest_framework.views import exception_handler
7
7
 
8
- from codex.exceptions import SeeOtherRedirectError
8
+ from codex.views.exceptions import SeeOtherRedirectError
9
9
 
10
10
  _OPDS_PREFIX = "opds/v"
11
11
 
@@ -0,0 +1,82 @@
1
+ """Special Redirect Error."""
2
+
3
+ from collections.abc import Mapping
4
+ from copy import deepcopy
5
+ from pprint import pformat
6
+
7
+ from django.core.validators import EMPTY_VALUES
8
+ from django.shortcuts import redirect
9
+ from django.urls import reverse
10
+ from loguru import logger
11
+ from rest_framework.exceptions import APIException
12
+ from rest_framework.status import HTTP_303_SEE_OTHER
13
+
14
+ from codex.choices.browser import DEFAULT_BROWSER_ROUTE
15
+ from codex.serializers.fields.browser import BreadcrumbsField
16
+ from codex.serializers.route import RouteSerializer
17
+ from codex.views.util import pop_name
18
+
19
+ _OPDS_REDIRECT_SETTINGS_KEYS = ("order_by", "top_group")
20
+ _REDIRECT_SETTINGS_KEYS = ("breadcrumbs", *_OPDS_REDIRECT_SETTINGS_KEYS)
21
+
22
+
23
+ class SeeOtherRedirectError(APIException):
24
+ """Redirect for 303."""
25
+
26
+ status_code = HTTP_303_SEE_OTHER
27
+ default_code = "redirect"
28
+ default_detail = "redirect to a valid route"
29
+
30
+ def __init__(self, detail):
31
+ """Create a response to pass to the exception handler."""
32
+ super().__init__(detail)
33
+ # Copy to edit and not write over refs
34
+ detail = dict(detail)
35
+
36
+ # Get route params
37
+ route = detail.get("route", {})
38
+ params = route.get("params", DEFAULT_BROWSER_ROUTE)
39
+ params = pop_name(params)
40
+ route = deepcopy(route)
41
+ route["params"] = params
42
+
43
+ # For OPDS
44
+ self.route_kwargs = params
45
+
46
+ serializer = RouteSerializer(params)
47
+ route["params"] = serializer.data
48
+ detail["route"] = route
49
+
50
+ filtered_settings = {}
51
+ settings = detail.get("settings", {})
52
+ for key in _REDIRECT_SETTINGS_KEYS:
53
+ value = settings.get(key)
54
+ if value in EMPTY_VALUES:
55
+ continue
56
+ if key == "breadcrumbs":
57
+ value = BreadcrumbsField().to_representation(value)
58
+ filtered_settings[key] = value
59
+ detail["settings"] = filtered_settings
60
+
61
+ self.detail = detail
62
+
63
+ logger.debug(f"redirect {pformat(self.detail)}")
64
+
65
+ def _get_query_params(self):
66
+ """Change OPDS settings like the frontend does with error.detail."""
67
+ query_params = {}
68
+ settings = (
69
+ self.detail.get("settings", {}) if isinstance(self.detail, Mapping) else {}
70
+ )
71
+ for key in _OPDS_REDIRECT_SETTINGS_KEYS:
72
+ value = settings.get(key)
73
+ if value not in EMPTY_VALUES:
74
+ query_params[key] = value
75
+ return query_params
76
+
77
+ def get_response(self, url_name):
78
+ """Return a Django Redirect Response."""
79
+ # only used in codex_exception_handler for opds stuff
80
+ query = self._get_query_params()
81
+ url = reverse(url_name, kwargs=self.route_kwargs, query=query)
82
+ return redirect(url, permanent=False)