codex 1.7.15__py3-none-any.whl → 1.8.0__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 (1130) 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 +64 -60
  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 +13 -2
  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/covers/tasks.py +2 -1
  20. codex/librarian/cron/crond.py +5 -3
  21. codex/librarian/librariand.py +59 -84
  22. codex/librarian/notifier/notifierd.py +8 -3
  23. codex/librarian/restarter/__init__.py +1 -0
  24. codex/librarian/restarter/restarter.py +55 -0
  25. codex/librarian/restarter/status.py +32 -0
  26. codex/librarian/restarter/tasks.py +15 -0
  27. codex/librarian/scribe/__init__.py +1 -0
  28. codex/librarian/scribe/importer/__init__.py +1 -0
  29. codex/librarian/scribe/importer/const.py +369 -0
  30. codex/librarian/scribe/importer/create/__init__.py +37 -0
  31. codex/librarian/scribe/importer/create/comics.py +172 -0
  32. codex/librarian/scribe/importer/create/const.py +131 -0
  33. codex/librarian/scribe/importer/create/covers.py +123 -0
  34. codex/librarian/scribe/importer/create/folders.py +98 -0
  35. codex/librarian/scribe/importer/create/foreign_keys.py +253 -0
  36. codex/librarian/scribe/importer/create/link_fks.py +73 -0
  37. codex/librarian/scribe/importer/delete/__init__.py +28 -0
  38. codex/librarian/scribe/importer/delete/comics.py +68 -0
  39. codex/librarian/scribe/importer/delete/covers.py +37 -0
  40. codex/librarian/scribe/importer/delete/folders.py +33 -0
  41. codex/librarian/scribe/importer/failed/__init__.py +1 -0
  42. codex/librarian/scribe/importer/failed/create.py +97 -0
  43. codex/librarian/scribe/importer/failed/failed.py +54 -0
  44. codex/librarian/scribe/importer/failed/query.py +103 -0
  45. codex/librarian/scribe/importer/finish.py +70 -0
  46. codex/librarian/scribe/importer/importer.py +31 -0
  47. codex/librarian/scribe/importer/init.py +338 -0
  48. codex/librarian/scribe/importer/link/__init__.py +15 -0
  49. codex/librarian/scribe/importer/link/const.py +31 -0
  50. codex/librarian/scribe/importer/link/covers.py +70 -0
  51. codex/librarian/scribe/importer/link/delete.py +106 -0
  52. codex/librarian/scribe/importer/link/many_to_many.py +88 -0
  53. codex/librarian/scribe/importer/link/prepare.py +132 -0
  54. codex/librarian/scribe/importer/link/sum.py +19 -0
  55. codex/librarian/scribe/importer/moved/__init__.py +52 -0
  56. codex/librarian/scribe/importer/moved/comics.py +125 -0
  57. codex/librarian/scribe/importer/moved/covers.py +88 -0
  58. codex/librarian/scribe/importer/moved/folders.py +205 -0
  59. codex/librarian/scribe/importer/query/__init__.py +44 -0
  60. codex/librarian/scribe/importer/query/covers.py +55 -0
  61. codex/librarian/scribe/importer/query/filters.py +61 -0
  62. codex/librarian/scribe/importer/query/foreign_keys.py +203 -0
  63. codex/librarian/scribe/importer/query/links.py +29 -0
  64. codex/librarian/scribe/importer/query/links_fk.py +99 -0
  65. codex/librarian/scribe/importer/query/links_m2m.py +102 -0
  66. codex/librarian/scribe/importer/query/update_comics.py +59 -0
  67. codex/librarian/scribe/importer/query/update_fks.py +140 -0
  68. codex/librarian/scribe/importer/read/__init__.py +14 -0
  69. codex/librarian/scribe/importer/read/aggregate_path.py +110 -0
  70. codex/librarian/scribe/importer/read/const.py +144 -0
  71. codex/librarian/scribe/importer/read/extract.py +128 -0
  72. codex/librarian/scribe/importer/read/folders.py +37 -0
  73. codex/librarian/scribe/importer/read/foreign_keys.py +145 -0
  74. codex/librarian/scribe/importer/read/many_to_many.py +237 -0
  75. codex/librarian/scribe/importer/search/__init__.py +34 -0
  76. codex/librarian/scribe/importer/search/const.py +50 -0
  77. codex/librarian/scribe/importer/search/prepare.py +85 -0
  78. codex/librarian/scribe/importer/search/sync_m2m.py +86 -0
  79. codex/librarian/scribe/importer/search/update.py +273 -0
  80. codex/librarian/scribe/importer/statii/__init__.py +21 -0
  81. codex/librarian/scribe/importer/statii/create.py +67 -0
  82. codex/librarian/scribe/importer/statii/delete.py +39 -0
  83. codex/librarian/scribe/importer/statii/failed.py +50 -0
  84. codex/librarian/scribe/importer/statii/link.py +27 -0
  85. codex/librarian/scribe/importer/statii/moved.py +39 -0
  86. codex/librarian/scribe/importer/statii/query.py +46 -0
  87. codex/librarian/scribe/importer/statii/read.py +30 -0
  88. codex/librarian/scribe/importer/statii/search.py +28 -0
  89. codex/librarian/scribe/importer/status.py +9 -0
  90. codex/librarian/scribe/importer/tasks.py +49 -0
  91. codex/librarian/scribe/janitor/__init__.py +1 -0
  92. codex/librarian/scribe/janitor/adopt_folders.py +81 -0
  93. codex/librarian/scribe/janitor/cleanup.py +199 -0
  94. codex/librarian/scribe/janitor/failed_imports.py +27 -0
  95. codex/librarian/scribe/janitor/integrity.py +375 -0
  96. codex/librarian/scribe/janitor/janitor.py +133 -0
  97. codex/librarian/scribe/janitor/scheduled_time.py +13 -0
  98. codex/librarian/scribe/janitor/status.py +152 -0
  99. codex/librarian/scribe/janitor/tasks.py +71 -0
  100. codex/librarian/scribe/janitor/update.py +88 -0
  101. codex/librarian/scribe/janitor/vacuum.py +53 -0
  102. codex/librarian/scribe/lazy_importer.py +51 -0
  103. codex/librarian/scribe/priority.py +69 -0
  104. codex/librarian/scribe/scribed.py +130 -0
  105. codex/librarian/scribe/search/__init__.py +1 -0
  106. codex/librarian/scribe/search/handler.py +28 -0
  107. codex/librarian/scribe/search/optimize.py +30 -0
  108. codex/librarian/scribe/search/remove.py +44 -0
  109. codex/librarian/scribe/search/status.py +66 -0
  110. codex/librarian/scribe/search/sync.py +398 -0
  111. codex/librarian/scribe/search/tasks.py +28 -0
  112. codex/librarian/scribe/status.py +21 -0
  113. codex/librarian/scribe/tasks.py +32 -0
  114. codex/librarian/scribe/timestamp_update.py +135 -0
  115. codex/librarian/status.py +76 -0
  116. codex/librarian/status_controller.py +196 -0
  117. codex/librarian/tasks.py +0 -10
  118. codex/librarian/telemeter/scheduled_time.py +11 -4
  119. codex/librarian/telemeter/stats.py +0 -2
  120. codex/librarian/telemeter/tasks.py +3 -1
  121. codex/librarian/telemeter/telemeter.py +17 -11
  122. codex/librarian/threads.py +148 -0
  123. codex/librarian/watchdog/const.py +139 -0
  124. codex/librarian/watchdog/db_snapshot.py +16 -10
  125. codex/librarian/watchdog/dir_snapshot_diff.py +19 -1
  126. codex/librarian/watchdog/emitter.py +140 -124
  127. codex/librarian/watchdog/event_batcherd.py +134 -88
  128. codex/librarian/watchdog/events.py +22 -211
  129. codex/librarian/watchdog/handlers.py +203 -0
  130. codex/librarian/watchdog/memory.py +56 -0
  131. codex/librarian/watchdog/observers.py +89 -55
  132. codex/librarian/watchdog/status.py +18 -5
  133. codex/librarian/watchdog/tasks.py +2 -1
  134. codex/librarian/worker.py +32 -0
  135. codex/middleware.py +6 -8
  136. codex/migrations/0011_library_groups_and_metadata_changes.py +2 -1
  137. codex/migrations/0013_int_issue_count_longer_charfields.py +2 -1
  138. codex/migrations/0023_rename_credit_creator_and_more.py +2 -1
  139. codex/migrations/0026_comicbox_1.py +9 -9
  140. codex/migrations/0034_comicbox2.py +792 -0
  141. codex/models/__init__.py +1 -0
  142. codex/models/admin.py +14 -22
  143. codex/models/base.py +21 -2
  144. codex/models/comic.py +80 -43
  145. codex/models/fields.py +81 -0
  146. codex/models/functions.py +8 -2
  147. codex/models/groups.py +99 -34
  148. codex/models/identifier.py +79 -0
  149. codex/models/library.py +17 -3
  150. codex/models/named.py +52 -55
  151. codex/models/paths.py +16 -12
  152. codex/models/query.py +7 -5
  153. codex/run.py +12 -18
  154. codex/serializers/admin/groups.py +3 -0
  155. codex/serializers/admin/libraries.py +13 -1
  156. codex/serializers/admin/stats.py +5 -4
  157. codex/serializers/admin/tasks.py +3 -5
  158. codex/serializers/admin/users.py +9 -3
  159. codex/serializers/auth.py +13 -6
  160. codex/serializers/browser/choices.py +35 -18
  161. codex/serializers/browser/filters.py +7 -5
  162. codex/serializers/browser/metadata.py +12 -10
  163. codex/serializers/browser/mixins.py +6 -8
  164. codex/serializers/browser/mtime.py +6 -2
  165. codex/serializers/browser/page.py +8 -3
  166. codex/serializers/browser/settings.py +35 -5
  167. codex/serializers/fields/__init__.py +2 -2
  168. codex/serializers/fields/auth.py +4 -5
  169. codex/serializers/fields/base.py +16 -0
  170. codex/serializers/fields/browser.py +15 -31
  171. codex/serializers/fields/group.py +11 -8
  172. codex/serializers/fields/reader.py +14 -10
  173. codex/serializers/fields/sanitized.py +2 -0
  174. codex/serializers/fields/session.py +3 -8
  175. codex/serializers/fields/stats.py +3 -5
  176. codex/serializers/fields/vuetify.py +21 -10
  177. codex/serializers/mixins.py +42 -0
  178. codex/serializers/models/base.py +1 -1
  179. codex/serializers/models/comic.py +6 -2
  180. codex/serializers/models/named.py +62 -37
  181. codex/serializers/models/pycountry.py +0 -3
  182. codex/serializers/opds/v1.py +6 -6
  183. codex/serializers/opds/v2/feed.py +2 -4
  184. codex/serializers/opds/v2/publication.py +14 -14
  185. codex/serializers/opds/v2/unused.py +2 -0
  186. codex/serializers/reader.py +52 -31
  187. codex/serializers/route.py +6 -4
  188. codex/serializers/settings.py +6 -6
  189. codex/settings/__init__.py +423 -1
  190. codex/signals/django_signals.py +2 -35
  191. codex/signals/os_signals.py +4 -5
  192. codex/startup/__init__.py +180 -0
  193. codex/startup/db.py +130 -0
  194. codex/startup/logger_init.py +45 -0
  195. codex/startup/registration.py +13 -0
  196. codex/static_root/assets/VCheckbox-BD4eUg4g.3d575d473135.js +1 -0
  197. codex/static_root/assets/VCheckbox-BD4eUg4g.3d575d473135.js.br +0 -0
  198. codex/static_root/assets/VCheckbox-BD4eUg4g.3d575d473135.js.gz +0 -0
  199. codex/static_root/assets/VCheckbox-BD4eUg4g.js +1 -0
  200. codex/static_root/assets/VCheckbox-BD4eUg4g.js.br +0 -0
  201. codex/static_root/assets/VCheckbox-BD4eUg4g.js.gz +0 -0
  202. codex/static_root/assets/VCheckboxBtn-BwlWS4y9.b40b085f1d67.js +1 -0
  203. codex/static_root/assets/VCheckboxBtn-BwlWS4y9.b40b085f1d67.js.br +0 -0
  204. codex/static_root/assets/VCheckboxBtn-BwlWS4y9.b40b085f1d67.js.gz +0 -0
  205. codex/static_root/assets/VCheckboxBtn-BwlWS4y9.js +1 -0
  206. codex/static_root/assets/VCheckboxBtn-BwlWS4y9.js.br +0 -0
  207. codex/static_root/assets/VCheckboxBtn-BwlWS4y9.js.gz +0 -0
  208. codex/static_root/assets/VCombobox-DyLCrBiS.3e13940cf92c.js +1 -0
  209. codex/static_root/assets/VCombobox-DyLCrBiS.3e13940cf92c.js.br +0 -0
  210. codex/static_root/assets/VCombobox-DyLCrBiS.3e13940cf92c.js.gz +0 -0
  211. codex/static_root/assets/VCombobox-DyLCrBiS.js +1 -0
  212. codex/static_root/assets/VCombobox-DyLCrBiS.js.br +0 -0
  213. codex/static_root/assets/VCombobox-DyLCrBiS.js.gz +0 -0
  214. codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css +1 -0
  215. codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css.br +0 -0
  216. codex/static_root/assets/VDialog-CpWjrJ0R.610ffc6302d4.css.gz +0 -0
  217. codex/static_root/assets/VDialog-CpWjrJ0R.css +1 -0
  218. codex/static_root/assets/VDialog-CpWjrJ0R.css.br +0 -0
  219. codex/static_root/assets/VDialog-CpWjrJ0R.css.gz +0 -0
  220. codex/static_root/assets/VDialog-N7erUTvb.ea9a9b29fb16.js +1 -0
  221. codex/static_root/assets/VDialog-N7erUTvb.ea9a9b29fb16.js.br +0 -0
  222. codex/static_root/assets/VDialog-N7erUTvb.ea9a9b29fb16.js.gz +0 -0
  223. codex/static_root/assets/VDialog-N7erUTvb.js +1 -0
  224. codex/static_root/assets/VDialog-N7erUTvb.js.br +0 -0
  225. codex/static_root/assets/VDialog-N7erUTvb.js.gz +0 -0
  226. codex/static_root/assets/VDivider-DFsQRi0x.d079d29e9764.js +1 -0
  227. codex/static_root/assets/VDivider-DFsQRi0x.d079d29e9764.js.br +0 -0
  228. codex/static_root/assets/VDivider-DFsQRi0x.d079d29e9764.js.gz +0 -0
  229. codex/static_root/assets/VDivider-DFsQRi0x.js +1 -0
  230. codex/static_root/assets/VDivider-DFsQRi0x.js.br +0 -0
  231. codex/static_root/assets/VDivider-DFsQRi0x.js.gz +0 -0
  232. codex/static_root/assets/VExpansionPanels-D_1ryJs5.c67ae2359ced.js +1 -0
  233. codex/static_root/assets/VExpansionPanels-D_1ryJs5.c67ae2359ced.js.br +0 -0
  234. codex/static_root/assets/VExpansionPanels-D_1ryJs5.c67ae2359ced.js.gz +0 -0
  235. codex/static_root/assets/VExpansionPanels-D_1ryJs5.js +1 -0
  236. codex/static_root/assets/VExpansionPanels-D_1ryJs5.js.br +0 -0
  237. codex/static_root/assets/VExpansionPanels-D_1ryJs5.js.gz +0 -0
  238. codex/static_root/assets/VForm-Bhq1UjFg.c9c80e741c2a.js +1 -0
  239. codex/static_root/assets/VForm-Bhq1UjFg.c9c80e741c2a.js.br +0 -0
  240. codex/static_root/assets/VForm-Bhq1UjFg.c9c80e741c2a.js.gz +0 -0
  241. codex/static_root/assets/VForm-Bhq1UjFg.js +1 -0
  242. codex/static_root/assets/VForm-Bhq1UjFg.js.br +0 -0
  243. codex/static_root/assets/VForm-Bhq1UjFg.js.gz +0 -0
  244. codex/static_root/assets/VRadioGroup-IJTnZQT5.731c3f06cee5.js +1 -0
  245. codex/static_root/assets/VRadioGroup-IJTnZQT5.731c3f06cee5.js.br +0 -0
  246. codex/static_root/assets/VRadioGroup-IJTnZQT5.731c3f06cee5.js.gz +0 -0
  247. codex/static_root/assets/VRadioGroup-IJTnZQT5.js +1 -0
  248. codex/static_root/assets/VRadioGroup-IJTnZQT5.js.br +0 -0
  249. codex/static_root/assets/VRadioGroup-IJTnZQT5.js.gz +0 -0
  250. codex/static_root/assets/VSelect-C857NCMc.567124f78bac.js +1 -0
  251. codex/static_root/assets/VSelect-C857NCMc.567124f78bac.js.br +0 -0
  252. codex/static_root/assets/VSelect-C857NCMc.567124f78bac.js.gz +0 -0
  253. codex/static_root/assets/VSelect-C857NCMc.js +1 -0
  254. codex/static_root/assets/VSelect-C857NCMc.js.br +0 -0
  255. codex/static_root/assets/VSelect-C857NCMc.js.gz +0 -0
  256. codex/static_root/assets/VSelectionControl-BUBBamEF.2e9636e900d8.js +1 -0
  257. codex/static_root/assets/VSelectionControl-BUBBamEF.2e9636e900d8.js.br +0 -0
  258. codex/static_root/assets/VSelectionControl-BUBBamEF.2e9636e900d8.js.gz +0 -0
  259. codex/static_root/assets/VSelectionControl-BUBBamEF.js +1 -0
  260. codex/static_root/assets/VSelectionControl-BUBBamEF.js.br +0 -0
  261. codex/static_root/assets/VSelectionControl-BUBBamEF.js.gz +0 -0
  262. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css +1 -0
  263. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.br +0 -0
  264. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.gz +0 -0
  265. codex/static_root/assets/VTable-CQyv0wyO.css +1 -0
  266. codex/static_root/assets/VTable-CQyv0wyO.css.br +0 -0
  267. codex/static_root/assets/VTable-CQyv0wyO.css.gz +0 -0
  268. codex/static_root/assets/VTable-CwYzcGki.ddd22f371cdb.js +1 -0
  269. codex/static_root/assets/VTable-CwYzcGki.ddd22f371cdb.js.br +0 -0
  270. codex/static_root/assets/VTable-CwYzcGki.ddd22f371cdb.js.gz +0 -0
  271. codex/static_root/assets/VTable-CwYzcGki.js +1 -0
  272. codex/static_root/assets/VTable-CwYzcGki.js.br +0 -0
  273. codex/static_root/assets/VTable-CwYzcGki.js.gz +0 -0
  274. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css +1 -0
  275. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.br +0 -0
  276. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.gz +0 -0
  277. codex/static_root/assets/VWindowItem-ChYLiXSE.css +1 -0
  278. codex/static_root/assets/VWindowItem-ChYLiXSE.css.br +0 -0
  279. codex/static_root/assets/VWindowItem-ChYLiXSE.css.gz +0 -0
  280. codex/static_root/assets/VWindowItem-WsjNvbu_.0c1a85eba03e.js +1 -0
  281. codex/static_root/assets/VWindowItem-WsjNvbu_.0c1a85eba03e.js.br +0 -0
  282. codex/static_root/assets/VWindowItem-WsjNvbu_.0c1a85eba03e.js.gz +0 -0
  283. codex/static_root/assets/VWindowItem-WsjNvbu_.js +1 -0
  284. codex/static_root/assets/VWindowItem-WsjNvbu_.js.br +0 -0
  285. codex/static_root/assets/VWindowItem-WsjNvbu_.js.gz +0 -0
  286. codex/static_root/assets/admin-ByuViOU9.9a1ee0a29ae2.js +1 -0
  287. codex/static_root/assets/admin-ByuViOU9.9a1ee0a29ae2.js.br +0 -0
  288. codex/static_root/assets/admin-ByuViOU9.9a1ee0a29ae2.js.gz +0 -0
  289. codex/static_root/assets/admin-ByuViOU9.js +1 -0
  290. codex/static_root/assets/admin-ByuViOU9.js.br +0 -0
  291. codex/static_root/assets/admin-ByuViOU9.js.gz +0 -0
  292. codex/static_root/assets/admin-CJauEn2X.b0c66e357083.js +1 -0
  293. codex/static_root/assets/admin-CJauEn2X.b0c66e357083.js.br +0 -0
  294. codex/static_root/assets/admin-CJauEn2X.b0c66e357083.js.gz +0 -0
  295. codex/static_root/assets/admin-CJauEn2X.js +1 -0
  296. codex/static_root/assets/admin-CJauEn2X.js.br +0 -0
  297. codex/static_root/assets/admin-CJauEn2X.js.gz +0 -0
  298. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css +1 -0
  299. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.br +0 -0
  300. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.gz +0 -0
  301. codex/static_root/assets/admin-DJCVf2PA.css +1 -0
  302. codex/static_root/assets/admin-DJCVf2PA.css.br +0 -0
  303. codex/static_root/assets/admin-DJCVf2PA.css.gz +0 -0
  304. codex/static_root/assets/admin-menu-BRVAx54U.2c7d6cfd8a50.js +1 -0
  305. codex/static_root/assets/admin-menu-BRVAx54U.2c7d6cfd8a50.js.br +0 -0
  306. codex/static_root/assets/admin-menu-BRVAx54U.2c7d6cfd8a50.js.gz +0 -0
  307. codex/static_root/assets/admin-menu-BRVAx54U.js +1 -0
  308. codex/static_root/assets/admin-menu-BRVAx54U.js.br +0 -0
  309. codex/static_root/assets/admin-menu-BRVAx54U.js.gz +0 -0
  310. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css +1 -0
  311. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.br +0 -0
  312. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.gz +0 -0
  313. codex/static_root/assets/admin-menu-hpyUS8ku.css +1 -0
  314. codex/static_root/assets/admin-menu-hpyUS8ku.css.br +0 -0
  315. codex/static_root/assets/admin-menu-hpyUS8ku.css.gz +0 -0
  316. codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.a592809d4008.css +1 -0
  317. codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.css +1 -0
  318. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.4fe043a87c09.js +1 -0
  319. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.4fe043a87c09.js.br +0 -0
  320. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.4fe043a87c09.js.gz +0 -0
  321. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.js +1 -0
  322. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.js.br +0 -0
  323. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.js.gz +0 -0
  324. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css +1 -0
  325. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.br +0 -0
  326. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.gz +0 -0
  327. codex/static_root/assets/browser-Cdi7U5ku.css +1 -0
  328. codex/static_root/assets/browser-Cdi7U5ku.css.br +0 -0
  329. codex/static_root/assets/browser-Cdi7U5ku.css.gz +0 -0
  330. codex/static_root/assets/browser-OtRiWIux.be28cec0e65a.js +1 -0
  331. codex/static_root/assets/browser-OtRiWIux.be28cec0e65a.js.br +0 -0
  332. codex/static_root/assets/browser-OtRiWIux.be28cec0e65a.js.gz +0 -0
  333. codex/static_root/assets/browser-OtRiWIux.js +1 -0
  334. codex/static_root/assets/browser-OtRiWIux.js.br +0 -0
  335. codex/static_root/assets/browser-OtRiWIux.js.gz +0 -0
  336. codex/static_root/assets/change-password-dialog-DE8R9FId.f3180b3946dd.js +1 -0
  337. codex/static_root/assets/change-password-dialog-DE8R9FId.f3180b3946dd.js.br +0 -0
  338. codex/static_root/assets/change-password-dialog-DE8R9FId.f3180b3946dd.js.gz +0 -0
  339. codex/static_root/assets/change-password-dialog-DE8R9FId.js +1 -0
  340. codex/static_root/assets/change-password-dialog-DE8R9FId.js.br +0 -0
  341. codex/static_root/assets/change-password-dialog-DE8R9FId.js.gz +0 -0
  342. codex/static_root/assets/confirm-dialog-Dy-4G4rU.c2de2d0acce1.js +1 -0
  343. codex/static_root/assets/confirm-dialog-Dy-4G4rU.c2de2d0acce1.js.br +0 -0
  344. codex/static_root/assets/confirm-dialog-Dy-4G4rU.c2de2d0acce1.js.gz +0 -0
  345. codex/static_root/assets/confirm-dialog-Dy-4G4rU.js +1 -0
  346. codex/static_root/assets/confirm-dialog-Dy-4G4rU.js.br +0 -0
  347. codex/static_root/assets/confirm-dialog-Dy-4G4rU.js.gz +0 -0
  348. codex/static_root/assets/confirm-dialog-YfC8mRQA.be37e8f67e0f.css +1 -0
  349. codex/static_root/assets/confirm-dialog-YfC8mRQA.css +1 -0
  350. codex/static_root/assets/datetime-column-Bt7J1qEf.css +1 -0
  351. codex/static_root/assets/datetime-column-Bt7J1qEf.css.br +0 -0
  352. codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css +1 -0
  353. codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css.br +0 -0
  354. codex/static_root/assets/datetime-column-C86OiFxS.32dca850b5fb.js +1 -0
  355. codex/static_root/assets/datetime-column-C86OiFxS.32dca850b5fb.js.br +0 -0
  356. codex/static_root/assets/datetime-column-C86OiFxS.32dca850b5fb.js.gz +0 -0
  357. codex/static_root/assets/datetime-column-C86OiFxS.js +1 -0
  358. codex/static_root/assets/datetime-column-C86OiFxS.js.br +0 -0
  359. codex/static_root/assets/datetime-column-C86OiFxS.js.gz +0 -0
  360. codex/static_root/assets/filter-OaiDOf0D.41d89efe9cd5.js +1 -0
  361. codex/static_root/assets/filter-OaiDOf0D.41d89efe9cd5.js.br +0 -0
  362. codex/static_root/assets/filter-OaiDOf0D.41d89efe9cd5.js.gz +0 -0
  363. codex/static_root/assets/filter-OaiDOf0D.js +1 -0
  364. codex/static_root/assets/filter-OaiDOf0D.js.br +0 -0
  365. codex/static_root/assets/filter-OaiDOf0D.js.gz +0 -0
  366. codex/static_root/assets/flag-tab-ChsErni6.0fca30995a0e.js +1 -0
  367. codex/static_root/assets/flag-tab-ChsErni6.0fca30995a0e.js.br +0 -0
  368. codex/static_root/assets/flag-tab-ChsErni6.0fca30995a0e.js.gz +0 -0
  369. codex/static_root/assets/flag-tab-ChsErni6.js +1 -0
  370. codex/static_root/assets/flag-tab-ChsErni6.js.br +0 -0
  371. codex/static_root/assets/flag-tab-ChsErni6.js.gz +0 -0
  372. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css +1 -0
  373. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.br +0 -0
  374. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.gz +0 -0
  375. codex/static_root/assets/forwardRefs-B_sUWZn6.css +1 -0
  376. codex/static_root/assets/forwardRefs-B_sUWZn6.css.br +0 -0
  377. codex/static_root/assets/forwardRefs-B_sUWZn6.css.gz +0 -0
  378. codex/static_root/assets/forwardRefs-BjkhALLr.1bfbdea189d7.js +1 -0
  379. codex/static_root/assets/forwardRefs-BjkhALLr.1bfbdea189d7.js.br +0 -0
  380. codex/static_root/assets/forwardRefs-BjkhALLr.1bfbdea189d7.js.gz +0 -0
  381. codex/static_root/assets/forwardRefs-BjkhALLr.js +1 -0
  382. codex/static_root/assets/forwardRefs-BjkhALLr.js.br +0 -0
  383. codex/static_root/assets/forwardRefs-BjkhALLr.js.gz +0 -0
  384. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css +1 -0
  385. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.br +0 -0
  386. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.gz +0 -0
  387. codex/static_root/assets/group-tab-CQ_Qw6h8.css +1 -0
  388. codex/static_root/assets/group-tab-CQ_Qw6h8.css.br +0 -0
  389. codex/static_root/assets/group-tab-CQ_Qw6h8.css.gz +0 -0
  390. codex/static_root/assets/group-tab-DB4vz9MA.42dd130d0118.js +1 -0
  391. codex/static_root/assets/group-tab-DB4vz9MA.42dd130d0118.js.br +0 -0
  392. codex/static_root/assets/group-tab-DB4vz9MA.42dd130d0118.js.gz +0 -0
  393. codex/static_root/assets/group-tab-DB4vz9MA.js +1 -0
  394. codex/static_root/assets/group-tab-DB4vz9MA.js.br +0 -0
  395. codex/static_root/assets/group-tab-DB4vz9MA.js.gz +0 -0
  396. codex/static_root/assets/http-error-7Kkr0CW4.c16118f162ac.js +1 -0
  397. codex/static_root/assets/http-error-7Kkr0CW4.c16118f162ac.js.br +0 -0
  398. codex/static_root/assets/http-error-7Kkr0CW4.c16118f162ac.js.gz +0 -0
  399. codex/static_root/assets/http-error-7Kkr0CW4.js +1 -0
  400. codex/static_root/assets/http-error-7Kkr0CW4.js.br +0 -0
  401. codex/static_root/assets/http-error-7Kkr0CW4.js.gz +0 -0
  402. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css +1 -0
  403. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.br +0 -0
  404. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.gz +0 -0
  405. codex/static_root/assets/http-error-CB3k5P-n.css +1 -0
  406. codex/static_root/assets/http-error-CB3k5P-n.css.br +0 -0
  407. codex/static_root/assets/http-error-CB3k5P-n.css.gz +0 -0
  408. codex/static_root/assets/index-yvfyzOV3.c886587fcfb6.js +1 -0
  409. codex/static_root/assets/index-yvfyzOV3.c886587fcfb6.js.br +0 -0
  410. codex/static_root/assets/index-yvfyzOV3.c886587fcfb6.js.gz +0 -0
  411. codex/static_root/assets/index-yvfyzOV3.js +1 -0
  412. codex/static_root/assets/index-yvfyzOV3.js.br +0 -0
  413. codex/static_root/assets/index-yvfyzOV3.js.gz +0 -0
  414. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css +1 -0
  415. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.br +0 -0
  416. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.gz +0 -0
  417. codex/static_root/assets/library-tab-5StL67ei.css +1 -0
  418. codex/static_root/assets/library-tab-5StL67ei.css.br +0 -0
  419. codex/static_root/assets/library-tab-5StL67ei.css.gz +0 -0
  420. codex/static_root/assets/library-tab-BJM2q4YE.0eb19632c084.js +1 -0
  421. codex/static_root/assets/library-tab-BJM2q4YE.0eb19632c084.js.br +0 -0
  422. codex/static_root/assets/library-tab-BJM2q4YE.0eb19632c084.js.gz +0 -0
  423. codex/static_root/assets/library-tab-BJM2q4YE.js +1 -0
  424. codex/static_root/assets/library-tab-BJM2q4YE.js.br +0 -0
  425. codex/static_root/assets/library-tab-BJM2q4YE.js.gz +0 -0
  426. codex/static_root/assets/main-0gkU-bgy.475633238e98.js +39 -0
  427. codex/static_root/assets/main-0gkU-bgy.475633238e98.js.br +0 -0
  428. codex/static_root/assets/main-0gkU-bgy.475633238e98.js.gz +0 -0
  429. codex/static_root/assets/main-0gkU-bgy.js +39 -0
  430. codex/static_root/assets/main-0gkU-bgy.js.br +0 -0
  431. codex/static_root/assets/main-0gkU-bgy.js.gz +0 -0
  432. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css +5 -0
  433. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.br +0 -0
  434. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.gz +0 -0
  435. codex/static_root/assets/main-B8_0rUnw.css +5 -0
  436. codex/static_root/assets/main-B8_0rUnw.css.br +0 -0
  437. codex/static_root/assets/main-B8_0rUnw.css.gz +0 -0
  438. codex/static_root/assets/pager-full-pdf-dMflY9TZ.14b64093d057.js +1 -0
  439. codex/static_root/assets/pager-full-pdf-dMflY9TZ.14b64093d057.js.br +0 -0
  440. codex/static_root/assets/pager-full-pdf-dMflY9TZ.14b64093d057.js.gz +0 -0
  441. codex/static_root/assets/pager-full-pdf-dMflY9TZ.js +1 -0
  442. codex/static_root/assets/pager-full-pdf-dMflY9TZ.js.br +0 -0
  443. codex/static_root/assets/pager-full-pdf-dMflY9TZ.js.gz +0 -0
  444. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css +1 -0
  445. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.br +0 -0
  446. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.gz +0 -0
  447. codex/static_root/assets/pagination-toolbar-741OafNw.css +1 -0
  448. codex/static_root/assets/pagination-toolbar-741OafNw.css.br +0 -0
  449. codex/static_root/assets/pagination-toolbar-741OafNw.css.gz +0 -0
  450. codex/static_root/assets/pagination-toolbar-BzWY1XTi.b1fbe47f722d.js +1 -0
  451. codex/static_root/assets/pagination-toolbar-BzWY1XTi.b1fbe47f722d.js.br +0 -0
  452. codex/static_root/assets/pagination-toolbar-BzWY1XTi.b1fbe47f722d.js.gz +0 -0
  453. codex/static_root/assets/pagination-toolbar-BzWY1XTi.js +1 -0
  454. codex/static_root/assets/pagination-toolbar-BzWY1XTi.js.br +0 -0
  455. codex/static_root/assets/pagination-toolbar-BzWY1XTi.js.gz +0 -0
  456. codex/static_root/assets/pdf-doc-remlTMFH.4063b6ec0033.js +372 -0
  457. codex/static_root/assets/pdf-doc-remlTMFH.4063b6ec0033.js.br +0 -0
  458. codex/static_root/assets/pdf-doc-remlTMFH.4063b6ec0033.js.gz +0 -0
  459. codex/static_root/assets/pdf-doc-remlTMFH.js +372 -0
  460. codex/static_root/assets/pdf-doc-remlTMFH.js.br +0 -0
  461. codex/static_root/assets/pdf-doc-remlTMFH.js.gz +0 -0
  462. codex/static_root/assets/reader-CmiUt5h2.65e3cb07aac9.js +2 -0
  463. codex/static_root/assets/reader-CmiUt5h2.65e3cb07aac9.js.br +0 -0
  464. codex/static_root/assets/reader-CmiUt5h2.65e3cb07aac9.js.gz +0 -0
  465. codex/static_root/assets/reader-CmiUt5h2.js +2 -0
  466. codex/static_root/assets/reader-CmiUt5h2.js.br +0 -0
  467. codex/static_root/assets/reader-CmiUt5h2.js.gz +0 -0
  468. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css +1 -0
  469. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.br +0 -0
  470. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.gz +0 -0
  471. codex/static_root/assets/reader-HE07eoaG.css +1 -0
  472. codex/static_root/assets/reader-HE07eoaG.css.br +0 -0
  473. codex/static_root/assets/reader-HE07eoaG.css.gz +0 -0
  474. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css +1 -0
  475. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.br +0 -0
  476. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.gz +0 -0
  477. codex/static_root/assets/relation-chips-CcFgPQOM.css +1 -0
  478. codex/static_root/assets/relation-chips-CcFgPQOM.css.br +0 -0
  479. codex/static_root/assets/relation-chips-CcFgPQOM.css.gz +0 -0
  480. codex/static_root/assets/relation-chips-Dl0i3EP7.1f365f5c1e41.js +1 -0
  481. codex/static_root/assets/relation-chips-Dl0i3EP7.1f365f5c1e41.js.br +0 -0
  482. codex/static_root/assets/relation-chips-Dl0i3EP7.1f365f5c1e41.js.gz +0 -0
  483. codex/static_root/assets/relation-chips-Dl0i3EP7.js +1 -0
  484. codex/static_root/assets/relation-chips-Dl0i3EP7.js.br +0 -0
  485. codex/static_root/assets/relation-chips-Dl0i3EP7.js.gz +0 -0
  486. codex/static_root/assets/settings-drawer-CpKXWPSA.82625de924bb.js +2 -0
  487. codex/static_root/assets/settings-drawer-CpKXWPSA.82625de924bb.js.br +0 -0
  488. codex/static_root/assets/settings-drawer-CpKXWPSA.82625de924bb.js.gz +0 -0
  489. codex/static_root/assets/settings-drawer-CpKXWPSA.js +2 -0
  490. codex/static_root/assets/settings-drawer-CpKXWPSA.js.br +0 -0
  491. codex/static_root/assets/settings-drawer-CpKXWPSA.js.gz +0 -0
  492. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css +1 -0
  493. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.br +0 -0
  494. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.gz +0 -0
  495. codex/static_root/assets/settings-drawer-CpS_aX4Z.css +1 -0
  496. codex/static_root/assets/settings-drawer-CpS_aX4Z.css.br +0 -0
  497. codex/static_root/assets/settings-drawer-CpS_aX4Z.css.gz +0 -0
  498. codex/static_root/assets/ssrBoot-D4fyL90J.0eef13056f93.js +1 -0
  499. codex/static_root/assets/ssrBoot-D4fyL90J.0eef13056f93.js.br +0 -0
  500. codex/static_root/assets/ssrBoot-D4fyL90J.0eef13056f93.js.gz +0 -0
  501. codex/static_root/assets/ssrBoot-D4fyL90J.js +1 -0
  502. codex/static_root/assets/ssrBoot-D4fyL90J.js.br +0 -0
  503. codex/static_root/assets/ssrBoot-D4fyL90J.js.gz +0 -0
  504. codex/static_root/assets/stats-tab-Cu7saNBy.8ad3f7a0995a.js +1 -0
  505. codex/static_root/assets/stats-tab-Cu7saNBy.8ad3f7a0995a.js.br +0 -0
  506. codex/static_root/assets/stats-tab-Cu7saNBy.8ad3f7a0995a.js.gz +0 -0
  507. codex/static_root/assets/stats-tab-Cu7saNBy.js +1 -0
  508. codex/static_root/assets/stats-tab-Cu7saNBy.js.br +0 -0
  509. codex/static_root/assets/stats-tab-Cu7saNBy.js.gz +0 -0
  510. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css +1 -0
  511. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.br +0 -0
  512. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.gz +0 -0
  513. codex/static_root/assets/stats-tab-Dpqh5pF9.css +1 -0
  514. codex/static_root/assets/stats-tab-Dpqh5pF9.css.br +0 -0
  515. codex/static_root/assets/stats-tab-Dpqh5pF9.css.gz +0 -0
  516. codex/static_root/assets/task-tab-B66NRaoH.fdb8c98f0652.js +1 -0
  517. codex/static_root/assets/task-tab-B66NRaoH.fdb8c98f0652.js.br +0 -0
  518. codex/static_root/assets/task-tab-B66NRaoH.fdb8c98f0652.js.gz +0 -0
  519. codex/static_root/assets/task-tab-B66NRaoH.js +1 -0
  520. codex/static_root/assets/task-tab-B66NRaoH.js.br +0 -0
  521. codex/static_root/assets/task-tab-B66NRaoH.js.gz +0 -0
  522. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css +1 -0
  523. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.br +0 -0
  524. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.gz +0 -0
  525. codex/static_root/assets/unauthorized-BBwsmi0O.css +1 -0
  526. codex/static_root/assets/unauthorized-BBwsmi0O.css.br +0 -0
  527. codex/static_root/assets/unauthorized-BBwsmi0O.css.gz +0 -0
  528. codex/static_root/assets/unauthorized-CLNP5Zx1.9f072de5e06c.js +1 -0
  529. codex/static_root/assets/unauthorized-CLNP5Zx1.9f072de5e06c.js.br +0 -0
  530. codex/static_root/assets/unauthorized-CLNP5Zx1.9f072de5e06c.js.gz +0 -0
  531. codex/static_root/assets/unauthorized-CLNP5Zx1.js +1 -0
  532. codex/static_root/assets/unauthorized-CLNP5Zx1.js.br +0 -0
  533. codex/static_root/assets/unauthorized-CLNP5Zx1.js.gz +0 -0
  534. codex/static_root/assets/user-tab-BqhQ3sls.cacf99be60fb.js +1 -0
  535. codex/static_root/assets/user-tab-BqhQ3sls.cacf99be60fb.js.br +0 -0
  536. codex/static_root/assets/user-tab-BqhQ3sls.cacf99be60fb.js.gz +0 -0
  537. codex/static_root/assets/user-tab-BqhQ3sls.js +1 -0
  538. codex/static_root/assets/user-tab-BqhQ3sls.js.br +0 -0
  539. codex/static_root/assets/user-tab-BqhQ3sls.js.gz +0 -0
  540. codex/static_root/img/folder.83168d8d3119.svg +1 -0
  541. codex/static_root/img/folder.83168d8d3119.svg.br +1 -0
  542. codex/static_root/img/folder.83168d8d3119.svg.gz +0 -0
  543. codex/static_root/img/folder.svg +1 -1
  544. codex/static_root/img/folder.svg.br +0 -0
  545. codex/static_root/img/folder.svg.gz +0 -0
  546. codex/static_root/img/imprint.3ca7a779b949.svg +1 -0
  547. codex/static_root/img/imprint.3ca7a779b949.svg.br +0 -0
  548. codex/static_root/img/imprint.3ca7a779b949.svg.gz +0 -0
  549. codex/static_root/img/imprint.svg +1 -1
  550. codex/static_root/img/imprint.svg.br +0 -0
  551. codex/static_root/img/imprint.svg.gz +0 -0
  552. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg +1 -0
  553. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.br +0 -0
  554. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.gz +0 -0
  555. codex/static_root/img/logo-maskable.svg +1 -1
  556. codex/static_root/img/logo-maskable.svg.br +0 -0
  557. codex/static_root/img/logo-maskable.svg.gz +0 -0
  558. codex/static_root/img/logo.00c902973831.svg +1 -0
  559. codex/static_root/img/logo.00c902973831.svg.br +0 -0
  560. codex/static_root/img/logo.00c902973831.svg.gz +0 -0
  561. codex/static_root/img/logo.svg +1 -1
  562. codex/static_root/img/logo.svg.br +0 -0
  563. codex/static_root/img/logo.svg.gz +0 -0
  564. codex/static_root/img/missing-cover-165.f4bb7740084c.webp +0 -0
  565. codex/static_root/img/missing-cover-165.webp +0 -0
  566. codex/static_root/img/missing-cover.7329518c5972.svg +1 -0
  567. codex/static_root/img/missing-cover.7329518c5972.svg.br +0 -0
  568. codex/static_root/img/missing-cover.7329518c5972.svg.gz +0 -0
  569. codex/static_root/img/missing-cover.svg +1 -1
  570. codex/static_root/img/missing-cover.svg.br +0 -0
  571. codex/static_root/img/missing-cover.svg.gz +0 -0
  572. codex/static_root/img/series.b092bbac0c2a.svg +1 -0
  573. codex/static_root/img/series.b092bbac0c2a.svg.br +0 -0
  574. codex/static_root/img/series.b092bbac0c2a.svg.gz +0 -0
  575. codex/static_root/img/series.svg +1 -1
  576. codex/static_root/img/series.svg.br +0 -0
  577. codex/static_root/img/series.svg.gz +0 -0
  578. codex/static_root/img/story-arc.884f7b1d95bd.svg +1 -0
  579. codex/static_root/img/story-arc.884f7b1d95bd.svg.br +0 -0
  580. codex/static_root/img/story-arc.884f7b1d95bd.svg.gz +0 -0
  581. codex/static_root/img/story-arc.svg +1 -1
  582. codex/static_root/img/story-arc.svg.br +0 -0
  583. codex/static_root/img/story-arc.svg.gz +0 -0
  584. codex/static_root/img/volume.516ec0c3018d.svg +1 -0
  585. codex/static_root/img/volume.516ec0c3018d.svg.br +0 -0
  586. codex/static_root/img/volume.516ec0c3018d.svg.gz +0 -0
  587. codex/static_root/img/volume.svg +1 -1
  588. codex/static_root/img/volume.svg.br +0 -0
  589. codex/static_root/img/volume.svg.gz +0 -0
  590. codex/static_root/manifest.474fa7aff739.json +760 -0
  591. codex/static_root/manifest.474fa7aff739.json.br +0 -0
  592. codex/static_root/manifest.474fa7aff739.json.gz +0 -0
  593. codex/static_root/manifest.json +341 -338
  594. codex/static_root/manifest.json.br +0 -0
  595. codex/static_root/manifest.json.gz +0 -0
  596. codex/static_root/staticfiles.json +1 -1
  597. codex/templates/headers-script-globals.html +1 -0
  598. codex/urls/api/browser.py +10 -1
  599. codex/urls/converters.py +2 -5
  600. codex/urls/root.py +1 -1
  601. codex/util.py +14 -8
  602. codex/views/admin/api_key.py +1 -1
  603. codex/views/admin/flag.py +10 -9
  604. codex/views/admin/group.py +5 -3
  605. codex/views/admin/library.py +15 -9
  606. codex/views/admin/permissions.py +21 -0
  607. codex/views/admin/stats.py +6 -8
  608. codex/views/admin/tasks.py +48 -48
  609. codex/views/admin/user.py +5 -3
  610. codex/views/auth.py +29 -11
  611. codex/views/bookmark.py +25 -14
  612. codex/views/browser/annotate/bookmark.py +0 -3
  613. codex/views/browser/annotate/card.py +20 -5
  614. codex/views/browser/annotate/order.py +3 -7
  615. codex/views/browser/bookmark.py +10 -7
  616. codex/views/browser/breadcrumbs.py +8 -7
  617. codex/views/browser/browser.py +16 -16
  618. codex/views/browser/choices.py +81 -65
  619. codex/views/browser/cover.py +21 -19
  620. codex/views/browser/download.py +5 -5
  621. codex/views/browser/filters/bookmark.py +5 -0
  622. codex/views/browser/filters/field.py +3 -3
  623. codex/views/browser/filters/filter.py +3 -5
  624. codex/views/browser/filters/group.py +5 -5
  625. codex/views/browser/filters/search/field/column.py +13 -9
  626. codex/views/browser/filters/search/field/expression.py +1 -3
  627. codex/views/browser/filters/search/field/filter.py +2 -4
  628. codex/views/browser/filters/search/field/optimize.py +1 -1
  629. codex/views/browser/filters/search/field/parse.py +28 -7
  630. codex/views/browser/filters/search/fts.py +3 -4
  631. codex/views/browser/filters/search/parse.py +26 -26
  632. codex/views/browser/group_mtime.py +13 -10
  633. codex/views/browser/metadata/__init__.py +90 -1
  634. codex/views/browser/metadata/annotate.py +13 -27
  635. codex/views/browser/metadata/const.py +83 -0
  636. codex/views/browser/metadata/copy_intersections.py +14 -9
  637. codex/views/browser/metadata/query_intersections.py +67 -48
  638. codex/views/browser/mtime.py +4 -7
  639. codex/views/browser/order_by.py +4 -1
  640. codex/views/browser/page_in_bounds.py +6 -7
  641. codex/views/browser/paginate.py +3 -5
  642. codex/views/browser/params.py +23 -36
  643. codex/views/browser/settings.py +18 -4
  644. codex/views/browser/title.py +9 -5
  645. codex/views/browser/validate.py +6 -8
  646. codex/views/const.py +11 -9
  647. codex/views/download.py +2 -2
  648. codex/views/error.py +1 -1
  649. codex/views/exceptions.py +82 -0
  650. codex/views/frontend.py +8 -18
  651. codex/views/lazy_import.py +24 -0
  652. codex/views/mixins.py +34 -12
  653. codex/views/opds/auth.py +2 -2
  654. codex/views/opds/authentication_v1.py +2 -1
  655. codex/views/opds/const.py +1 -1
  656. codex/views/opds/urls.py +2 -1
  657. codex/views/opds/util.py +14 -41
  658. codex/views/opds/v1/entry/entry.py +12 -15
  659. codex/views/opds/v1/entry/links.py +15 -19
  660. codex/views/opds/v1/facets.py +8 -5
  661. codex/views/opds/v1/feed.py +23 -22
  662. codex/views/opds/v1/links.py +3 -7
  663. codex/views/opds/v1/opensearch_v1.py +7 -4
  664. codex/views/opds/v2/feed.py +14 -15
  665. codex/views/opds/v2/href.py +17 -12
  666. codex/views/opds/v2/links.py +3 -1
  667. codex/views/opds/v2/progression.py +31 -15
  668. codex/views/opds/v2/publications.py +18 -17
  669. codex/views/opds/v2/top_links.py +7 -2
  670. codex/views/public.py +12 -15
  671. codex/views/reader/arcs.py +153 -74
  672. codex/views/reader/books.py +72 -97
  673. codex/views/reader/page.py +13 -9
  674. codex/views/reader/params.py +33 -96
  675. codex/views/reader/reader.py +18 -73
  676. codex/views/reader/settings.py +4 -2
  677. codex/views/session.py +13 -19
  678. codex/views/settings.py +4 -9
  679. codex/views/template.py +8 -4
  680. codex/views/timezone.py +4 -5
  681. codex/views/util.py +3 -24
  682. codex/views/version.py +5 -3
  683. codex/websockets/consumers.py +7 -7
  684. codex/websockets/listener.py +4 -5
  685. codex-1.8.0.dist-info/METADATA +592 -0
  686. codex-1.8.0.dist-info/RECORD +1101 -0
  687. codex-1.8.0.dist-info/WHEEL +4 -0
  688. codex-1.8.0.dist-info/entry_points.txt +2 -0
  689. codex/db.py +0 -134
  690. codex/exceptions.py +0 -88
  691. codex/librarian/README.md +0 -4
  692. codex/librarian/delayed_taskd.py +0 -21
  693. codex/librarian/importer/__init__.py +0 -1
  694. codex/librarian/importer/aggregate.py +0 -256
  695. codex/librarian/importer/cache.py +0 -90
  696. codex/librarian/importer/const.py +0 -244
  697. codex/librarian/importer/create_comics.py +0 -139
  698. codex/librarian/importer/create_covers.py +0 -96
  699. codex/librarian/importer/create_fks.py +0 -346
  700. codex/librarian/importer/deleted.py +0 -138
  701. codex/librarian/importer/extract.py +0 -284
  702. codex/librarian/importer/failed_imports.py +0 -165
  703. codex/librarian/importer/importer.py +0 -101
  704. codex/librarian/importer/importerd.py +0 -122
  705. codex/librarian/importer/init.py +0 -264
  706. codex/librarian/importer/link_comics.py +0 -270
  707. codex/librarian/importer/link_covers.py +0 -73
  708. codex/librarian/importer/moved.py +0 -368
  709. codex/librarian/importer/query_covers.py +0 -53
  710. codex/librarian/importer/query_fks.py +0 -653
  711. codex/librarian/importer/status.py +0 -29
  712. codex/librarian/importer/tasks.py +0 -55
  713. codex/librarian/janitor/__init__.py +0 -1
  714. codex/librarian/janitor/cleanup.py +0 -167
  715. codex/librarian/janitor/failed_imports.py +0 -27
  716. codex/librarian/janitor/integrity.py +0 -378
  717. codex/librarian/janitor/janitor.py +0 -161
  718. codex/librarian/janitor/latest_version.py +0 -55
  719. codex/librarian/janitor/scheduled_time.py +0 -12
  720. codex/librarian/janitor/status.py +0 -22
  721. codex/librarian/janitor/tasks.py +0 -109
  722. codex/librarian/janitor/update.py +0 -109
  723. codex/librarian/janitor/vacuum.py +0 -51
  724. codex/librarian/search/__init__.py +0 -1
  725. codex/librarian/search/optimize.py +0 -43
  726. codex/librarian/search/remove.py +0 -53
  727. codex/librarian/search/searchd.py +0 -28
  728. codex/librarian/search/status.py +0 -13
  729. codex/librarian/search/tasks.py +0 -37
  730. codex/librarian/search/update.py +0 -305
  731. codex/librarian/watchdog/README.md +0 -11
  732. codex/logger/__init__.py +0 -1
  733. codex/logger/formatter.py +0 -36
  734. codex/logger/logger.py +0 -46
  735. codex/logger/loggerd.py +0 -102
  736. codex/logger/mp_queue.py +0 -5
  737. codex/logger_base.py +0 -12
  738. codex/memory.py +0 -56
  739. codex/permissions.py +0 -19
  740. codex/registration.py +0 -16
  741. codex/serializers/README.md +0 -4
  742. codex/settings/README.md +0 -4
  743. codex/settings/settings.py +0 -389
  744. codex/startup.py +0 -182
  745. codex/static_root/assets/VCheckbox-DraWPvy6.30c95a5ce5e6.js +0 -1
  746. codex/static_root/assets/VCheckbox-DraWPvy6.30c95a5ce5e6.js.br +0 -0
  747. codex/static_root/assets/VCheckbox-DraWPvy6.30c95a5ce5e6.js.gz +0 -0
  748. codex/static_root/assets/VCheckbox-DraWPvy6.js +0 -1
  749. codex/static_root/assets/VCheckbox-DraWPvy6.js.br +0 -0
  750. codex/static_root/assets/VCheckbox-DraWPvy6.js.gz +0 -0
  751. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.f38524c2448d.js +0 -1
  752. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.f38524c2448d.js.br +0 -0
  753. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.f38524c2448d.js.gz +0 -0
  754. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.js +0 -1
  755. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.js.br +0 -0
  756. codex/static_root/assets/VCheckboxBtn-Bxf1MS02.js.gz +0 -0
  757. codex/static_root/assets/VCombobox-DKyNgHNV.b4e08dd5606d.js +0 -1
  758. codex/static_root/assets/VCombobox-DKyNgHNV.b4e08dd5606d.js.br +0 -0
  759. codex/static_root/assets/VCombobox-DKyNgHNV.b4e08dd5606d.js.gz +0 -0
  760. codex/static_root/assets/VCombobox-DKyNgHNV.js +0 -1
  761. codex/static_root/assets/VCombobox-DKyNgHNV.js.br +0 -0
  762. codex/static_root/assets/VCombobox-DKyNgHNV.js.gz +0 -0
  763. codex/static_root/assets/VDialog-C_zlnjF1.6c58e08b5374.css +0 -1
  764. codex/static_root/assets/VDialog-C_zlnjF1.6c58e08b5374.css.br +0 -0
  765. codex/static_root/assets/VDialog-C_zlnjF1.6c58e08b5374.css.gz +0 -0
  766. codex/static_root/assets/VDialog-C_zlnjF1.css +0 -1
  767. codex/static_root/assets/VDialog-C_zlnjF1.css.br +0 -0
  768. codex/static_root/assets/VDialog-C_zlnjF1.css.gz +0 -0
  769. codex/static_root/assets/VDialog-tf0N3lvG.eecb009783ed.js +0 -1
  770. codex/static_root/assets/VDialog-tf0N3lvG.eecb009783ed.js.br +0 -0
  771. codex/static_root/assets/VDialog-tf0N3lvG.eecb009783ed.js.gz +0 -0
  772. codex/static_root/assets/VDialog-tf0N3lvG.js +0 -1
  773. codex/static_root/assets/VDialog-tf0N3lvG.js.br +0 -0
  774. codex/static_root/assets/VDialog-tf0N3lvG.js.gz +0 -0
  775. codex/static_root/assets/VDivider-CTvTvFr_.3d0b477ddae0.js +0 -1
  776. codex/static_root/assets/VDivider-CTvTvFr_.3d0b477ddae0.js.br +0 -0
  777. codex/static_root/assets/VDivider-CTvTvFr_.3d0b477ddae0.js.gz +0 -0
  778. codex/static_root/assets/VDivider-CTvTvFr_.js +0 -1
  779. codex/static_root/assets/VDivider-CTvTvFr_.js.br +0 -0
  780. codex/static_root/assets/VDivider-CTvTvFr_.js.gz +0 -0
  781. codex/static_root/assets/VExpansionPanels-BjwwzLx6.203715bfa684.js +0 -1
  782. codex/static_root/assets/VExpansionPanels-BjwwzLx6.203715bfa684.js.br +0 -0
  783. codex/static_root/assets/VExpansionPanels-BjwwzLx6.203715bfa684.js.gz +0 -0
  784. codex/static_root/assets/VExpansionPanels-BjwwzLx6.js +0 -1
  785. codex/static_root/assets/VExpansionPanels-BjwwzLx6.js.br +0 -0
  786. codex/static_root/assets/VExpansionPanels-BjwwzLx6.js.gz +0 -0
  787. codex/static_root/assets/VForm-Dw7aCtM5.9266634dfe00.js +0 -1
  788. codex/static_root/assets/VForm-Dw7aCtM5.9266634dfe00.js.br +0 -0
  789. codex/static_root/assets/VForm-Dw7aCtM5.9266634dfe00.js.gz +0 -0
  790. codex/static_root/assets/VForm-Dw7aCtM5.js +0 -1
  791. codex/static_root/assets/VForm-Dw7aCtM5.js.br +0 -0
  792. codex/static_root/assets/VForm-Dw7aCtM5.js.gz +0 -0
  793. codex/static_root/assets/VRadioGroup-DJBFM2Br.79fa65084b8d.js +0 -1
  794. codex/static_root/assets/VRadioGroup-DJBFM2Br.79fa65084b8d.js.br +0 -0
  795. codex/static_root/assets/VRadioGroup-DJBFM2Br.79fa65084b8d.js.gz +0 -0
  796. codex/static_root/assets/VRadioGroup-DJBFM2Br.js +0 -1
  797. codex/static_root/assets/VRadioGroup-DJBFM2Br.js.br +0 -0
  798. codex/static_root/assets/VRadioGroup-DJBFM2Br.js.gz +0 -0
  799. codex/static_root/assets/VSelect-Cv8OuNtL.a5e2fe245f1a.js +0 -1
  800. codex/static_root/assets/VSelect-Cv8OuNtL.a5e2fe245f1a.js.br +0 -0
  801. codex/static_root/assets/VSelect-Cv8OuNtL.a5e2fe245f1a.js.gz +0 -0
  802. codex/static_root/assets/VSelect-Cv8OuNtL.js +0 -1
  803. codex/static_root/assets/VSelect-Cv8OuNtL.js.br +0 -0
  804. codex/static_root/assets/VSelect-Cv8OuNtL.js.gz +0 -0
  805. codex/static_root/assets/VSelectionControl-DoFzRlEh.a927b53c246b.js +0 -1
  806. codex/static_root/assets/VSelectionControl-DoFzRlEh.a927b53c246b.js.br +0 -0
  807. codex/static_root/assets/VSelectionControl-DoFzRlEh.a927b53c246b.js.gz +0 -0
  808. codex/static_root/assets/VSelectionControl-DoFzRlEh.js +0 -1
  809. codex/static_root/assets/VSelectionControl-DoFzRlEh.js.br +0 -0
  810. codex/static_root/assets/VSelectionControl-DoFzRlEh.js.gz +0 -0
  811. codex/static_root/assets/VTable-C-cNChDa.b2aabb112acf.js +0 -1
  812. codex/static_root/assets/VTable-C-cNChDa.b2aabb112acf.js.br +0 -0
  813. codex/static_root/assets/VTable-C-cNChDa.b2aabb112acf.js.gz +0 -0
  814. codex/static_root/assets/VTable-C-cNChDa.js +0 -1
  815. codex/static_root/assets/VTable-C-cNChDa.js.br +0 -0
  816. codex/static_root/assets/VTable-C-cNChDa.js.gz +0 -0
  817. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css +0 -1
  818. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.br +0 -0
  819. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.gz +0 -0
  820. codex/static_root/assets/VTable-CHRVGI94.css +0 -1
  821. codex/static_root/assets/VTable-CHRVGI94.css.br +0 -0
  822. codex/static_root/assets/VTable-CHRVGI94.css.gz +0 -0
  823. codex/static_root/assets/VWindowItem-CWBhiE_Y.css +0 -1
  824. codex/static_root/assets/VWindowItem-CWBhiE_Y.css.br +0 -0
  825. codex/static_root/assets/VWindowItem-CWBhiE_Y.css.gz +0 -0
  826. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css +0 -1
  827. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br +0 -0
  828. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz +0 -0
  829. codex/static_root/assets/VWindowItem-DL6bN3h7.45f85724527c.js +0 -1
  830. codex/static_root/assets/VWindowItem-DL6bN3h7.45f85724527c.js.br +0 -0
  831. codex/static_root/assets/VWindowItem-DL6bN3h7.45f85724527c.js.gz +0 -0
  832. codex/static_root/assets/VWindowItem-DL6bN3h7.js +0 -1
  833. codex/static_root/assets/VWindowItem-DL6bN3h7.js.br +0 -0
  834. codex/static_root/assets/VWindowItem-DL6bN3h7.js.gz +0 -0
  835. codex/static_root/assets/admin-BQ68PA7O.8bf1f757ca31.js +0 -1
  836. codex/static_root/assets/admin-BQ68PA7O.8bf1f757ca31.js.br +0 -0
  837. codex/static_root/assets/admin-BQ68PA7O.8bf1f757ca31.js.gz +0 -0
  838. codex/static_root/assets/admin-BQ68PA7O.js +0 -1
  839. codex/static_root/assets/admin-BQ68PA7O.js.br +0 -0
  840. codex/static_root/assets/admin-BQ68PA7O.js.gz +0 -0
  841. codex/static_root/assets/admin-Cg7RkTjo.191b04128f17.js +0 -1
  842. codex/static_root/assets/admin-Cg7RkTjo.191b04128f17.js.br +0 -0
  843. codex/static_root/assets/admin-Cg7RkTjo.191b04128f17.js.gz +0 -0
  844. codex/static_root/assets/admin-Cg7RkTjo.js +0 -1
  845. codex/static_root/assets/admin-Cg7RkTjo.js.br +0 -0
  846. codex/static_root/assets/admin-Cg7RkTjo.js.gz +0 -0
  847. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css +0 -1
  848. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.br +0 -0
  849. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.gz +0 -0
  850. codex/static_root/assets/admin-klMr_GZK.css +0 -1
  851. codex/static_root/assets/admin-klMr_GZK.css.br +0 -0
  852. codex/static_root/assets/admin-klMr_GZK.css.gz +0 -0
  853. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css +0 -1
  854. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.br +0 -0
  855. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.gz +0 -0
  856. codex/static_root/assets/admin-menu-CKlcsy9S.css +0 -1
  857. codex/static_root/assets/admin-menu-CKlcsy9S.css.br +0 -0
  858. codex/static_root/assets/admin-menu-CKlcsy9S.css.gz +0 -0
  859. codex/static_root/assets/admin-menu-Chx211s6.c63738168d93.js +0 -1
  860. codex/static_root/assets/admin-menu-Chx211s6.c63738168d93.js.br +0 -0
  861. codex/static_root/assets/admin-menu-Chx211s6.c63738168d93.js.gz +0 -0
  862. codex/static_root/assets/admin-menu-Chx211s6.js +0 -1
  863. codex/static_root/assets/admin-menu-Chx211s6.js.br +0 -0
  864. codex/static_root/assets/admin-menu-Chx211s6.js.gz +0 -0
  865. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.7689648ee782.js +0 -1
  866. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.7689648ee782.js.br +0 -0
  867. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.7689648ee782.js.gz +0 -0
  868. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.js +0 -1
  869. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.js.br +0 -0
  870. codex/static_root/assets/admin-settings-button-progress-DPuwgSVv.js.gz +0 -0
  871. codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.435dc945daf1.css +0 -1
  872. codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.css +0 -1
  873. codex/static_root/assets/browser-BKDmwxmv.6f4eca6489a1.js +0 -1
  874. codex/static_root/assets/browser-BKDmwxmv.6f4eca6489a1.js.br +0 -0
  875. codex/static_root/assets/browser-BKDmwxmv.6f4eca6489a1.js.gz +0 -0
  876. codex/static_root/assets/browser-BKDmwxmv.js +0 -1
  877. codex/static_root/assets/browser-BKDmwxmv.js.br +0 -0
  878. codex/static_root/assets/browser-BKDmwxmv.js.gz +0 -0
  879. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css +0 -1
  880. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.br +0 -0
  881. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.gz +0 -0
  882. codex/static_root/assets/browser-sNm790x9.css +0 -1
  883. codex/static_root/assets/browser-sNm790x9.css.br +0 -0
  884. codex/static_root/assets/browser-sNm790x9.css.gz +0 -0
  885. codex/static_root/assets/change-password-dialog-DqupgUbt.e35dc497629b.js +0 -1
  886. codex/static_root/assets/change-password-dialog-DqupgUbt.e35dc497629b.js.br +0 -0
  887. codex/static_root/assets/change-password-dialog-DqupgUbt.e35dc497629b.js.gz +0 -0
  888. codex/static_root/assets/change-password-dialog-DqupgUbt.js +0 -1
  889. codex/static_root/assets/change-password-dialog-DqupgUbt.js.br +0 -0
  890. codex/static_root/assets/change-password-dialog-DqupgUbt.js.gz +0 -0
  891. codex/static_root/assets/confirm-dialog-AMnfyuMm.278235fdacbf.js +0 -1
  892. codex/static_root/assets/confirm-dialog-AMnfyuMm.278235fdacbf.js.br +0 -0
  893. codex/static_root/assets/confirm-dialog-AMnfyuMm.278235fdacbf.js.gz +0 -0
  894. codex/static_root/assets/confirm-dialog-AMnfyuMm.js +0 -1
  895. codex/static_root/assets/confirm-dialog-AMnfyuMm.js.br +0 -0
  896. codex/static_root/assets/confirm-dialog-AMnfyuMm.js.gz +0 -0
  897. codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css +0 -1
  898. codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css.br +0 -0
  899. codex/static_root/assets/confirm-dialog-BI5kQLy_.css +0 -1
  900. codex/static_root/assets/confirm-dialog-BI5kQLy_.css.br +0 -0
  901. codex/static_root/assets/datetime-column-BavtvLnf.1f3bf499e063.css +0 -1
  902. codex/static_root/assets/datetime-column-BavtvLnf.css +0 -1
  903. codex/static_root/assets/datetime-column-m-oshrDM.7e17980c4b7a.js +0 -1
  904. codex/static_root/assets/datetime-column-m-oshrDM.7e17980c4b7a.js.br +0 -0
  905. codex/static_root/assets/datetime-column-m-oshrDM.7e17980c4b7a.js.gz +0 -0
  906. codex/static_root/assets/datetime-column-m-oshrDM.js +0 -1
  907. codex/static_root/assets/datetime-column-m-oshrDM.js.br +0 -0
  908. codex/static_root/assets/datetime-column-m-oshrDM.js.gz +0 -0
  909. codex/static_root/assets/filter-BucmWboA.c5589372c258.js +0 -1
  910. codex/static_root/assets/filter-BucmWboA.c5589372c258.js.br +0 -0
  911. codex/static_root/assets/filter-BucmWboA.c5589372c258.js.gz +0 -0
  912. codex/static_root/assets/filter-BucmWboA.js +0 -1
  913. codex/static_root/assets/filter-BucmWboA.js.br +0 -0
  914. codex/static_root/assets/filter-BucmWboA.js.gz +0 -0
  915. codex/static_root/assets/flag-tab-C434E1_2.49632d2b141d.js +0 -1
  916. codex/static_root/assets/flag-tab-C434E1_2.49632d2b141d.js.br +0 -0
  917. codex/static_root/assets/flag-tab-C434E1_2.49632d2b141d.js.gz +0 -0
  918. codex/static_root/assets/flag-tab-C434E1_2.js +0 -1
  919. codex/static_root/assets/flag-tab-C434E1_2.js.br +0 -0
  920. codex/static_root/assets/flag-tab-C434E1_2.js.gz +0 -0
  921. codex/static_root/assets/forwardRefs-C8KYLdfc.css +0 -1
  922. codex/static_root/assets/forwardRefs-C8KYLdfc.css.br +0 -0
  923. codex/static_root/assets/forwardRefs-C8KYLdfc.css.gz +0 -0
  924. codex/static_root/assets/forwardRefs-C8KYLdfc.f5843191eb9e.css +0 -1
  925. codex/static_root/assets/forwardRefs-C8KYLdfc.f5843191eb9e.css.br +0 -0
  926. codex/static_root/assets/forwardRefs-C8KYLdfc.f5843191eb9e.css.gz +0 -0
  927. codex/static_root/assets/forwardRefs-CGpIPavG.d61e8212d1dc.js +0 -1
  928. codex/static_root/assets/forwardRefs-CGpIPavG.d61e8212d1dc.js.br +0 -0
  929. codex/static_root/assets/forwardRefs-CGpIPavG.d61e8212d1dc.js.gz +0 -0
  930. codex/static_root/assets/forwardRefs-CGpIPavG.js +0 -1
  931. codex/static_root/assets/forwardRefs-CGpIPavG.js.br +0 -0
  932. codex/static_root/assets/forwardRefs-CGpIPavG.js.gz +0 -0
  933. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css +0 -1
  934. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.br +0 -0
  935. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.gz +0 -0
  936. codex/static_root/assets/group-tab-Bi681uR0.css +0 -1
  937. codex/static_root/assets/group-tab-Bi681uR0.css.br +0 -0
  938. codex/static_root/assets/group-tab-Bi681uR0.css.gz +0 -0
  939. codex/static_root/assets/group-tab-MrhEvTPy.9233e2e5e80e.js +0 -1
  940. codex/static_root/assets/group-tab-MrhEvTPy.9233e2e5e80e.js.br +0 -0
  941. codex/static_root/assets/group-tab-MrhEvTPy.9233e2e5e80e.js.gz +0 -0
  942. codex/static_root/assets/group-tab-MrhEvTPy.js +0 -1
  943. codex/static_root/assets/group-tab-MrhEvTPy.js.br +0 -0
  944. codex/static_root/assets/group-tab-MrhEvTPy.js.gz +0 -0
  945. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css +0 -1
  946. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.br +0 -0
  947. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.gz +0 -0
  948. codex/static_root/assets/http-error-CODU7jcH.css +0 -1
  949. codex/static_root/assets/http-error-CODU7jcH.css.br +0 -0
  950. codex/static_root/assets/http-error-CODU7jcH.css.gz +0 -0
  951. codex/static_root/assets/http-error-gBWEusWz.be314a60dc2e.js +0 -1
  952. codex/static_root/assets/http-error-gBWEusWz.be314a60dc2e.js.br +0 -0
  953. codex/static_root/assets/http-error-gBWEusWz.be314a60dc2e.js.gz +0 -0
  954. codex/static_root/assets/http-error-gBWEusWz.js +0 -1
  955. codex/static_root/assets/http-error-gBWEusWz.js.br +0 -0
  956. codex/static_root/assets/http-error-gBWEusWz.js.gz +0 -0
  957. codex/static_root/assets/index-Cu_QC2K8.de1f7935ff98.js +0 -1
  958. codex/static_root/assets/index-Cu_QC2K8.de1f7935ff98.js.br +0 -0
  959. codex/static_root/assets/index-Cu_QC2K8.de1f7935ff98.js.gz +0 -0
  960. codex/static_root/assets/index-Cu_QC2K8.js +0 -1
  961. codex/static_root/assets/index-Cu_QC2K8.js.br +0 -0
  962. codex/static_root/assets/index-Cu_QC2K8.js.gz +0 -0
  963. codex/static_root/assets/library-tab-Ce1d8Ypk.c87088afd4e1.js +0 -1
  964. codex/static_root/assets/library-tab-Ce1d8Ypk.c87088afd4e1.js.br +0 -0
  965. codex/static_root/assets/library-tab-Ce1d8Ypk.c87088afd4e1.js.gz +0 -0
  966. codex/static_root/assets/library-tab-Ce1d8Ypk.js +0 -1
  967. codex/static_root/assets/library-tab-Ce1d8Ypk.js.br +0 -0
  968. codex/static_root/assets/library-tab-Ce1d8Ypk.js.gz +0 -0
  969. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css +0 -1
  970. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.br +0 -0
  971. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.gz +0 -0
  972. codex/static_root/assets/library-tab-DLpvMqPW.css +0 -1
  973. codex/static_root/assets/library-tab-DLpvMqPW.css.br +0 -0
  974. codex/static_root/assets/library-tab-DLpvMqPW.css.gz +0 -0
  975. codex/static_root/assets/main-CpP-5rLh.ce09dfd7874f.js +0 -39
  976. codex/static_root/assets/main-CpP-5rLh.ce09dfd7874f.js.br +0 -0
  977. codex/static_root/assets/main-CpP-5rLh.ce09dfd7874f.js.gz +0 -0
  978. codex/static_root/assets/main-CpP-5rLh.js +0 -39
  979. codex/static_root/assets/main-CpP-5rLh.js.br +0 -0
  980. codex/static_root/assets/main-CpP-5rLh.js.gz +0 -0
  981. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css +0 -5
  982. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.br +0 -0
  983. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.gz +0 -0
  984. codex/static_root/assets/main-Of3aYkZ7.css +0 -5
  985. codex/static_root/assets/main-Of3aYkZ7.css.br +0 -0
  986. codex/static_root/assets/main-Of3aYkZ7.css.gz +0 -0
  987. codex/static_root/assets/pager-full-pdf-D8B8_31l.f1659a2dac96.js +0 -1
  988. codex/static_root/assets/pager-full-pdf-D8B8_31l.f1659a2dac96.js.br +0 -0
  989. codex/static_root/assets/pager-full-pdf-D8B8_31l.f1659a2dac96.js.gz +0 -0
  990. codex/static_root/assets/pager-full-pdf-D8B8_31l.js +0 -1
  991. codex/static_root/assets/pager-full-pdf-D8B8_31l.js.br +0 -0
  992. codex/static_root/assets/pager-full-pdf-D8B8_31l.js.gz +0 -0
  993. codex/static_root/assets/pagination-toolbar-OKWewkNI.a2773ff43624.js +0 -1
  994. codex/static_root/assets/pagination-toolbar-OKWewkNI.a2773ff43624.js.br +0 -0
  995. codex/static_root/assets/pagination-toolbar-OKWewkNI.a2773ff43624.js.gz +0 -0
  996. codex/static_root/assets/pagination-toolbar-OKWewkNI.js +0 -1
  997. codex/static_root/assets/pagination-toolbar-OKWewkNI.js.br +0 -0
  998. codex/static_root/assets/pagination-toolbar-OKWewkNI.js.gz +0 -0
  999. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css +0 -1
  1000. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.br +0 -0
  1001. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.gz +0 -0
  1002. codex/static_root/assets/pagination-toolbar-aHRrdz48.css +0 -1
  1003. codex/static_root/assets/pagination-toolbar-aHRrdz48.css.br +0 -0
  1004. codex/static_root/assets/pagination-toolbar-aHRrdz48.css.gz +0 -0
  1005. codex/static_root/assets/pdf-doc-DpmuaK3i.2dca76dcae13.js +0 -372
  1006. codex/static_root/assets/pdf-doc-DpmuaK3i.2dca76dcae13.js.br +0 -0
  1007. codex/static_root/assets/pdf-doc-DpmuaK3i.2dca76dcae13.js.gz +0 -0
  1008. codex/static_root/assets/pdf-doc-DpmuaK3i.js +0 -372
  1009. codex/static_root/assets/pdf-doc-DpmuaK3i.js.br +0 -0
  1010. codex/static_root/assets/pdf-doc-DpmuaK3i.js.gz +0 -0
  1011. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css +0 -1
  1012. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.br +0 -0
  1013. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.gz +0 -0
  1014. codex/static_root/assets/reader-BwgJtbgj.css +0 -1
  1015. codex/static_root/assets/reader-BwgJtbgj.css.br +0 -0
  1016. codex/static_root/assets/reader-BwgJtbgj.css.gz +0 -0
  1017. codex/static_root/assets/reader-CyitMKSa.d70f4fc1c014.js +0 -2
  1018. codex/static_root/assets/reader-CyitMKSa.d70f4fc1c014.js.br +0 -0
  1019. codex/static_root/assets/reader-CyitMKSa.d70f4fc1c014.js.gz +0 -0
  1020. codex/static_root/assets/reader-CyitMKSa.js +0 -2
  1021. codex/static_root/assets/reader-CyitMKSa.js.br +0 -0
  1022. codex/static_root/assets/reader-CyitMKSa.js.gz +0 -0
  1023. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css +0 -1
  1024. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.br +0 -0
  1025. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.gz +0 -0
  1026. codex/static_root/assets/relation-chips-BuShhy1e.css +0 -1
  1027. codex/static_root/assets/relation-chips-BuShhy1e.css.br +0 -0
  1028. codex/static_root/assets/relation-chips-BuShhy1e.css.gz +0 -0
  1029. codex/static_root/assets/relation-chips-QzwrdJWs.99957808773d.js +0 -1
  1030. codex/static_root/assets/relation-chips-QzwrdJWs.99957808773d.js.br +0 -0
  1031. codex/static_root/assets/relation-chips-QzwrdJWs.99957808773d.js.gz +0 -0
  1032. codex/static_root/assets/relation-chips-QzwrdJWs.js +0 -1
  1033. codex/static_root/assets/relation-chips-QzwrdJWs.js.br +0 -0
  1034. codex/static_root/assets/relation-chips-QzwrdJWs.js.gz +0 -0
  1035. codex/static_root/assets/settings-drawer-DYzm391t.67fd6c1c26cd.js +0 -2
  1036. codex/static_root/assets/settings-drawer-DYzm391t.67fd6c1c26cd.js.br +0 -0
  1037. codex/static_root/assets/settings-drawer-DYzm391t.67fd6c1c26cd.js.gz +0 -0
  1038. codex/static_root/assets/settings-drawer-DYzm391t.js +0 -2
  1039. codex/static_root/assets/settings-drawer-DYzm391t.js.br +0 -0
  1040. codex/static_root/assets/settings-drawer-DYzm391t.js.gz +0 -0
  1041. codex/static_root/assets/settings-drawer-WyG6HLH-.css +0 -1
  1042. codex/static_root/assets/settings-drawer-WyG6HLH-.css.br +0 -0
  1043. codex/static_root/assets/settings-drawer-WyG6HLH-.css.gz +0 -0
  1044. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css +0 -1
  1045. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.br +0 -0
  1046. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.gz +0 -0
  1047. codex/static_root/assets/ssrBoot-D216TWr1.0b11737afb21.js +0 -1
  1048. codex/static_root/assets/ssrBoot-D216TWr1.0b11737afb21.js.br +0 -0
  1049. codex/static_root/assets/ssrBoot-D216TWr1.0b11737afb21.js.gz +0 -0
  1050. codex/static_root/assets/ssrBoot-D216TWr1.js +0 -1
  1051. codex/static_root/assets/ssrBoot-D216TWr1.js.br +0 -0
  1052. codex/static_root/assets/ssrBoot-D216TWr1.js.gz +0 -0
  1053. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css +0 -1
  1054. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.br +0 -0
  1055. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.gz +0 -0
  1056. codex/static_root/assets/stats-tab-CGY8r-es.css +0 -1
  1057. codex/static_root/assets/stats-tab-CGY8r-es.css.br +0 -0
  1058. codex/static_root/assets/stats-tab-CGY8r-es.css.gz +0 -0
  1059. codex/static_root/assets/stats-tab-CXkOoD0h.1e2709686bf6.js +0 -1
  1060. codex/static_root/assets/stats-tab-CXkOoD0h.1e2709686bf6.js.br +0 -0
  1061. codex/static_root/assets/stats-tab-CXkOoD0h.1e2709686bf6.js.gz +0 -0
  1062. codex/static_root/assets/stats-tab-CXkOoD0h.js +0 -1
  1063. codex/static_root/assets/stats-tab-CXkOoD0h.js.br +0 -0
  1064. codex/static_root/assets/stats-tab-CXkOoD0h.js.gz +0 -0
  1065. codex/static_root/assets/task-tab-BlzgZqUZ.9448f1240271.js +0 -1
  1066. codex/static_root/assets/task-tab-BlzgZqUZ.9448f1240271.js.br +0 -0
  1067. codex/static_root/assets/task-tab-BlzgZqUZ.9448f1240271.js.gz +0 -0
  1068. codex/static_root/assets/task-tab-BlzgZqUZ.js +0 -1
  1069. codex/static_root/assets/task-tab-BlzgZqUZ.js.br +0 -0
  1070. codex/static_root/assets/task-tab-BlzgZqUZ.js.gz +0 -0
  1071. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css +0 -1
  1072. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.br +0 -0
  1073. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.gz +0 -0
  1074. codex/static_root/assets/unauthorized-DE63n2Pi.css +0 -1
  1075. codex/static_root/assets/unauthorized-DE63n2Pi.css.br +0 -0
  1076. codex/static_root/assets/unauthorized-DE63n2Pi.css.gz +0 -0
  1077. codex/static_root/assets/unauthorized-_61uqek6.56ab5c978077.js +0 -1
  1078. codex/static_root/assets/unauthorized-_61uqek6.56ab5c978077.js.br +0 -0
  1079. codex/static_root/assets/unauthorized-_61uqek6.56ab5c978077.js.gz +0 -0
  1080. codex/static_root/assets/unauthorized-_61uqek6.js +0 -1
  1081. codex/static_root/assets/unauthorized-_61uqek6.js.br +0 -0
  1082. codex/static_root/assets/unauthorized-_61uqek6.js.gz +0 -0
  1083. codex/static_root/assets/user-tab-CNxfPmZf.aed110a6c62b.js +0 -1
  1084. codex/static_root/assets/user-tab-CNxfPmZf.aed110a6c62b.js.br +0 -0
  1085. codex/static_root/assets/user-tab-CNxfPmZf.aed110a6c62b.js.gz +0 -0
  1086. codex/static_root/assets/user-tab-CNxfPmZf.js +0 -1
  1087. codex/static_root/assets/user-tab-CNxfPmZf.js.br +0 -0
  1088. codex/static_root/assets/user-tab-CNxfPmZf.js.gz +0 -0
  1089. codex/static_root/img/folder.f28936a3701d.svg +0 -1
  1090. codex/static_root/img/folder.f28936a3701d.svg.br +0 -0
  1091. codex/static_root/img/folder.f28936a3701d.svg.gz +0 -0
  1092. codex/static_root/img/imprint.7c2adebb76d6.svg +0 -1
  1093. codex/static_root/img/imprint.7c2adebb76d6.svg.br +0 -0
  1094. codex/static_root/img/imprint.7c2adebb76d6.svg.gz +0 -0
  1095. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg +0 -1
  1096. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.br +0 -0
  1097. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.gz +0 -0
  1098. codex/static_root/img/logo.0f5344a028ca.svg +0 -1
  1099. codex/static_root/img/logo.0f5344a028ca.svg.br +0 -0
  1100. codex/static_root/img/logo.0f5344a028ca.svg.gz +0 -0
  1101. codex/static_root/img/missing-cover-165.0743171f2148.webp +0 -0
  1102. codex/static_root/img/missing-cover.ddb038cc2c56.svg +0 -1
  1103. codex/static_root/img/missing-cover.ddb038cc2c56.svg.br +0 -0
  1104. codex/static_root/img/missing-cover.ddb038cc2c56.svg.gz +0 -0
  1105. codex/static_root/img/series.ec8a889b8f95.svg +0 -1
  1106. codex/static_root/img/series.ec8a889b8f95.svg.br +0 -0
  1107. codex/static_root/img/series.ec8a889b8f95.svg.gz +0 -0
  1108. codex/static_root/img/story-arc.ca10014355ef.svg +0 -1
  1109. codex/static_root/img/story-arc.ca10014355ef.svg.br +0 -1
  1110. codex/static_root/img/story-arc.ca10014355ef.svg.gz +0 -0
  1111. codex/static_root/img/volume.814e4c79461a.svg +0 -1
  1112. codex/static_root/img/volume.814e4c79461a.svg.br +0 -0
  1113. codex/static_root/img/volume.814e4c79461a.svg.gz +0 -0
  1114. codex/static_root/manifest.95906ea9e563.json +0 -757
  1115. codex/static_root/manifest.95906ea9e563.json.br +0 -0
  1116. codex/static_root/manifest.95906ea9e563.json.gz +0 -0
  1117. codex/status.py +0 -35
  1118. codex/status_controller.py +0 -153
  1119. codex/templates/README.md +0 -3
  1120. codex/threads.py +0 -130
  1121. codex/views/README.md +0 -4
  1122. codex/views/browser/filters/search/aliases.py +0 -81
  1123. codex/views/browser/metadata/metadata.py +0 -83
  1124. codex/websockets/README.md +0 -4
  1125. codex/worker_base.py +0 -14
  1126. codex-1.7.15.dist-info/METADATA +0 -599
  1127. codex-1.7.15.dist-info/RECORD +0 -1052
  1128. codex-1.7.15.dist-info/WHEEL +0 -4
  1129. codex-1.7.15.dist-info/entry_points.txt +0 -3
  1130. {codex-1.7.15.dist-info → codex-1.8.0.dist-info/licenses}/LICENSE +0 -0
@@ -3,13 +3,21 @@
3
3
  from collections.abc import Mapping
4
4
  from dataclasses import dataclass
5
5
 
6
+ from loguru import logger
7
+ from typing_extensions import override
8
+
9
+ from codex.librarian.bookmark.latest_version import CodexLatestVersionUpdater
6
10
  from codex.librarian.bookmark.tasks import (
7
11
  BookmarkUpdateTask,
12
+ ClearLibrarianStatusTask,
13
+ CodexLatestVersionTask,
8
14
  UserActiveTask,
9
15
  )
10
- from codex.librarian.bookmark.update import BookmarkUpdate
16
+ from codex.librarian.bookmark.update import BookmarkUpdateMixin
11
17
  from codex.librarian.bookmark.user_active import UserActiveMixin
12
- from codex.threads import AggregateMessageQueuedThread
18
+ from codex.librarian.telemeter.tasks import TelemeterTask
19
+ from codex.librarian.telemeter.telemeter import send_telemetry
20
+ from codex.librarian.threads import AggregateMessageQueuedThread
13
21
 
14
22
 
15
23
  @dataclass
@@ -20,6 +28,7 @@ class BookmarkKey:
20
28
  comic_pks: tuple = ()
21
29
  user_pk: int = 0
22
30
 
31
+ @override
23
32
  def __hash__(self):
24
33
  """Hash the dict as a tuple."""
25
34
  auth_filters = (
@@ -27,43 +36,73 @@ class BookmarkKey:
27
36
  )
28
37
  return hash((auth_filters, self.comic_pks, self.user_pk))
29
38
 
39
+ @override
30
40
  def __eq__(self, other):
31
41
  """Equal uses hashes."""
32
42
  return self.__hash__() == other.__hash__()
33
43
 
34
44
 
35
45
  class BookmarkThread(
36
- UserActiveMixin,
37
46
  AggregateMessageQueuedThread,
38
- BookmarkUpdate,
47
+ BookmarkUpdateMixin,
48
+ UserActiveMixin,
39
49
  ):
40
50
  """Aggregates Bookmark updates preventing floods updates db in batches.."""
41
51
 
42
52
  FLOOD_DELAY = 3.0
43
53
  MAX_DELAY = 5.0
44
54
 
55
+ def __init__(self, *args, **kwargs):
56
+ """Init mixins."""
57
+ super().__init__(*args, **kwargs)
58
+ self.init_group_acl()
59
+ self.init_user_active()
60
+
61
+ def _process_task_immediately(self, task):
62
+ if self.db_write_lock.locked():
63
+ self.log.warning(f"Database locked, not processing {task}")
64
+ match task:
65
+ case TelemeterTask():
66
+ send_telemetry(self.log)
67
+ case ClearLibrarianStatusTask():
68
+ self.status_controller.finish_many([])
69
+ case CodexLatestVersionTask():
70
+ worker = CodexLatestVersionUpdater(
71
+ self.log, self.librarian_queue, self.db_write_lock
72
+ )
73
+ worker.update_latest_version(force=task.force)
74
+ case _:
75
+ self.log.warning(f"Unknown Bookmark task {task}")
76
+
77
+ @override
45
78
  def aggregate_items(self, item):
46
79
  """Aggregate bookmark updates."""
47
- if isinstance(item, UserActiveTask):
48
- # Wedge the user active recorer into the bookmark thread because it
49
- # it also wants to be done offline and low priority.
50
- key = BookmarkKey(user_pk=item.pk)
51
- self.cache[key] = None
52
- elif isinstance(item, BookmarkUpdateTask):
53
- key = BookmarkKey(item.auth_filter, item.comic_pks)
54
- if key not in self.cache:
55
- self.cache[key] = {}
56
- self.cache[key].update(item.updates)
57
- else:
58
- self.log.warning(f"Unknown Bookmark task {item}")
80
+ task = item
81
+ match task:
82
+ case UserActiveTask():
83
+ # Wedge the user active recorer into the bookmark thread because it
84
+ # it also wants to be done offline and low priority.
85
+ key = BookmarkKey(user_pk=item.pk)
86
+ self.cache[key] = None
87
+ case BookmarkUpdateTask():
88
+ key = BookmarkKey(item.auth_filter, item.comic_pks)
89
+ if key not in self.cache:
90
+ self.cache[key] = {}
91
+ self.cache[key].update(item.updates)
92
+ case _:
93
+ self._process_task_immediately(task)
59
94
 
95
+ @override
60
96
  def send_all_items(self):
61
97
  """Run the task method."""
98
+ if self.db_write_lock.locked():
99
+ self.log.debug("Database locked, waiting to process bookmarks.")
100
+ return
62
101
  cleanup = set()
63
102
  for key, value in self.cache.items():
64
103
  try:
65
104
  if key.user_pk:
66
- self.update_user_active(key.user_pk, self.log)
105
+ self.update_user_active(key.user_pk, logger)
67
106
  elif key.comic_pks:
68
107
  self.update_bookmarks(key.auth_filter, key.comic_pks, value)
69
108
  cleanup.add(key)
@@ -0,0 +1,65 @@
1
+ """Fetch the current codex version."""
2
+
3
+ import json
4
+ from datetime import timedelta
5
+
6
+ import requests
7
+ from django.utils import timezone
8
+
9
+ from codex.librarian.scribe.janitor.status import JanitorCodexLatestVersionStatus
10
+ from codex.librarian.scribe.janitor.tasks import JanitorCodexUpdateTask
11
+ from codex.librarian.worker import WorkerStatusMixin
12
+ from codex.models import Timestamp
13
+ from codex.version import PACKAGE_NAME
14
+
15
+ _PYPI_URL_TEMPLATE = "https://pypi.python.org/pypi/%s/json"
16
+ _REPO_URL = _PYPI_URL_TEMPLATE % PACKAGE_NAME
17
+ _CACHE_EXPIRY = timedelta(days=1) - timedelta(minutes=5)
18
+ _REPO_TIMEOUT = 5
19
+
20
+
21
+ class CodexLatestVersionUpdater(WorkerStatusMixin):
22
+ """Methods for fetching the latest version."""
23
+
24
+ @staticmethod
25
+ def _fetch_latest_version():
26
+ """Fetch Latest Remotely."""
27
+ response = requests.get(_REPO_URL, timeout=_REPO_TIMEOUT)
28
+ return json.loads(response.text)["info"]["version"]
29
+
30
+ def update_latest_version(self, *, force: bool, update: bool = False):
31
+ """Get the latest version from a remote repo using a cache."""
32
+ if self.db_write_lock.locked():
33
+ self.log.warning("Database locked, not retrieving latest codex version.")
34
+ return
35
+ status = JanitorCodexLatestVersionStatus()
36
+ try:
37
+ self.status_controller.start(status)
38
+ ts = Timestamp.objects.get(key=Timestamp.Choices.CODEX_VERSION.value)
39
+ do_fetch = (
40
+ force
41
+ or not ts.version
42
+ or (timezone.now() - ts.updated_at > _CACHE_EXPIRY)
43
+ )
44
+ if do_fetch:
45
+ latest_version = self._fetch_latest_version()
46
+ if not latest_version:
47
+ reason = "Bad latest version fetched."
48
+ raise ValueError(reason)
49
+ ts.version = latest_version
50
+ ts.save()
51
+ level = "INFO"
52
+ log_txt = f"Saved new latest codex version {latest_version}."
53
+ if update:
54
+ task = JanitorCodexUpdateTask()
55
+ self.librarian_queue.put(task)
56
+ else:
57
+ level = "DEBUG"
58
+ log_txt = "Not fetching new latest version, not expired."
59
+ self.log.log(level, log_txt)
60
+ finally:
61
+ self.status_controller.finish(status)
62
+
63
+ def __init__(self, *args, **kwargs):
64
+ """Init Worker."""
65
+ self.init_worker(*args, **kwargs)
@@ -1,12 +1,12 @@
1
1
  """Bookmark Tasks."""
2
2
 
3
+ from abc import ABC
3
4
  from collections.abc import Mapping
4
5
  from dataclasses import dataclass
5
6
  from typing import Any
6
7
 
7
8
 
8
- @dataclass
9
- class BookmarkTask:
9
+ class BookmarkTask(ABC): # noqa: B024
10
10
  """Bookmark Base Class."""
11
11
 
12
12
 
@@ -24,3 +24,14 @@ class UserActiveTask(BookmarkTask):
24
24
  """Update the user's last active status."""
25
25
 
26
26
  pk: int
27
+
28
+
29
+ class ClearLibrarianStatusTask(BookmarkTask):
30
+ """Clear all librarian statuses."""
31
+
32
+
33
+ @dataclass
34
+ class CodexLatestVersionTask(BookmarkTask):
35
+ """Get the latest version."""
36
+
37
+ force: bool = False
@@ -22,7 +22,7 @@ _BOOKMARK_UPDATE_FIELDS = frozenset(
22
22
  )
23
23
 
24
24
 
25
- class BookmarkUpdate(GroupACLMixin):
25
+ class BookmarkUpdateMixin(GroupACLMixin):
26
26
  """Update Bookmarks."""
27
27
 
28
28
  # Used by Bookmarkd and view.bookmark.
@@ -15,10 +15,9 @@ class UserActiveMixin:
15
15
  # only hit the disk to record user activity every so often
16
16
  USER_ACTIVE_RESOLUTION = timedelta(hours=1)
17
17
 
18
- def __init__(self, *args, **kwargs):
18
+ def init_user_active(self):
19
19
  """Init the last recorded dict."""
20
- super().__init__(*args, **kwargs)
21
- self._user_active_recorded = {}
20
+ self._user_active_recorded = {} # pyright: ignore[reportUninitializedInstanceVariable]
22
21
 
23
22
  def update_user_active(self, pk: int, log):
24
23
  """Update user active."""
@@ -1,5 +1,7 @@
1
1
  """Functions for dealing with comic cover thumbnails."""
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from codex.librarian.covers.purge import CoverPurgeThread
4
6
  from codex.librarian.covers.tasks import (
5
7
  CoverCreateAllTask,
@@ -13,6 +15,7 @@ from codex.librarian.covers.tasks import (
13
15
  class CoverThread(CoverPurgeThread):
14
16
  """Create comic covers in it's own thread."""
15
17
 
18
+ @override
16
19
  def process_item(self, item):
17
20
  """Run the task method."""
18
21
  task = item
@@ -21,7 +24,7 @@ class CoverThread(CoverPurgeThread):
21
24
  elif isinstance(task, CoverRemoveAllTask):
22
25
  self.purge_all_comic_covers(self.librarian_queue)
23
26
  elif isinstance(task, CoverRemoveTask):
24
- self.purge_comic_covers(task.pks, task.custom)
27
+ self.purge_comic_covers(task.pks, custom=task.custom)
25
28
  elif isinstance(task, CoverRemoveOrphansTask):
26
29
  self.cleanup_orphan_covers()
27
30
  elif isinstance(task, CoverCreateAllTask):
@@ -1,6 +1,8 @@
1
1
  """Create comic cover paths."""
2
2
 
3
+ from abc import ABC
3
4
  from io import BytesIO
5
+ from multiprocessing.queues import Queue
4
6
  from pathlib import Path
5
7
  from time import time
6
8
 
@@ -9,11 +11,11 @@ from humanize import naturaldelta
9
11
  from PIL import Image
10
12
 
11
13
  from codex.librarian.covers.path import CoverPathMixin
12
- from codex.librarian.covers.status import CoverStatusTypes
14
+ from codex.librarian.covers.status import CreateCoversStatus
13
15
  from codex.librarian.covers.tasks import CoverSaveToCache
16
+ from codex.librarian.threads import QueuedThread
14
17
  from codex.models import Comic, CustomCover
15
- from codex.status import Status
16
- from codex.threads import QueuedThread
18
+ from codex.settings import COMICBOX_CONFIG
17
19
 
18
20
  _COVER_RATIO = 1.5372233400402415 # modal cover ratio
19
21
  THUMBNAIL_WIDTH = 165
@@ -21,7 +23,7 @@ THUMBNAIL_HEIGHT = round(THUMBNAIL_WIDTH * _COVER_RATIO)
21
23
  _THUMBNAIL_SIZE = (THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
22
24
 
23
25
 
24
- class CoverCreateThread(QueuedThread, CoverPathMixin):
26
+ class CoverCreateThread(QueuedThread, CoverPathMixin, ABC):
25
27
  """Create methods for covers."""
26
28
 
27
29
  @classmethod
@@ -40,14 +42,14 @@ class CoverCreateThread(QueuedThread, CoverPathMixin):
40
42
  return cover_thumb_buffer
41
43
 
42
44
  @classmethod
43
- def _get_comic_cover_image(cls, comic_path):
45
+ def _get_comic_cover_image(cls, comic_path, log):
44
46
  """
45
47
  Create comic cover if none exists.
46
48
 
47
49
  Return image thumb data or path to missing file thumb.
48
50
  """
49
- with Comicbox(comic_path) as cb:
50
- image_data = cb.get_cover_image()
51
+ with Comicbox(comic_path, config=COMICBOX_CONFIG, logger=log) as car:
52
+ image_data = car.get_cover_page(to_pixmap=True)
51
53
  if not image_data:
52
54
  reason = "Read empty cover"
53
55
  raise ValueError(reason)
@@ -60,7 +62,9 @@ class CoverCreateThread(QueuedThread, CoverPathMixin):
60
62
  return f.read()
61
63
 
62
64
  @classmethod
63
- def create_cover_from_path(cls, pk, cover_path, log, librarian_queue, custom):
65
+ def create_cover_from_path(
66
+ cls, pk: int, cover_path: str, log, librarian_queue: Queue, *, custom: bool
67
+ ):
64
68
  """
65
69
  Create cover for path.
66
70
 
@@ -73,7 +77,7 @@ class CoverCreateThread(QueuedThread, CoverPathMixin):
73
77
  if custom:
74
78
  cover_image = cls._get_custom_cover_image(db_path)
75
79
  else:
76
- cover_image = cls._get_comic_cover_image(db_path)
80
+ cover_image = cls._get_comic_cover_image(db_path, log)
77
81
  thumb_buffer = cls._create_cover_thumbnail(cover_image)
78
82
  thumb_bytes = thumb_buffer.getvalue()
79
83
  thumb_buffer.seek(0)
@@ -87,8 +91,9 @@ class CoverCreateThread(QueuedThread, CoverPathMixin):
87
91
  librarian_queue.put(task)
88
92
  return thumb_buffer
89
93
 
90
- def save_cover_to_cache(self, cover_path, data):
94
+ def save_cover_to_cache(self, cover_path_str: str, data):
91
95
  """Save cover thumb image to the disk cache."""
96
+ cover_path = Path(cover_path_str)
92
97
  cover_path.parent.mkdir(exist_ok=True, parents=True)
93
98
  if data:
94
99
  with cover_path.open("wb") as cover_file:
@@ -97,12 +102,12 @@ class CoverCreateThread(QueuedThread, CoverPathMixin):
97
102
  # zero length file is code for missing.
98
103
  cover_path.touch()
99
104
 
100
- def _bulk_create_comic_covers(self, pks, custom):
105
+ def _bulk_create_comic_covers(self, pks, custom) -> int:
101
106
  """Create bulk comic covers."""
102
107
  num_comics = len(pks)
103
108
  if not num_comics:
104
- return None
105
- status = Status(CoverStatusTypes.CREATE_COVERS, 0, num_comics)
109
+ return 0
110
+ status = CreateCoversStatus(0, num_comics)
106
111
  try:
107
112
  start_time = time()
108
113
  self.log.debug(f"Creating {num_comics} comic covers...")
@@ -115,27 +120,31 @@ class CoverCreateThread(QueuedThread, CoverPathMixin):
115
120
  if cover_path.exists():
116
121
  status.decrement_total()
117
122
  else:
118
- # bulk contributor creates covers inline
123
+ # bulk credit creates covers inline
119
124
  data = self.create_cover_from_path(
120
- pk, cover_path, self.log, self.librarian_queue, custom=False
125
+ pk,
126
+ str(cover_path),
127
+ self.log,
128
+ self.librarian_queue,
129
+ custom=False,
121
130
  )
122
131
  if data:
123
132
  data.close()
124
133
  status.increment_complete()
125
134
  self.status_controller.update(status)
126
135
 
127
- total_elapsed = naturaldelta(time() - start_time)
128
136
  desc = "custom" if custom else "comic"
129
- self.log.info(
130
- f"Created {status.complete} {desc} covers in {total_elapsed}."
131
- )
137
+ count = status.complete
138
+ level = "INFO" if count else "DEBUG"
139
+ elapsed = naturaldelta(time() - start_time)
140
+ self.log.log(level, f"Created {count} {desc} covers in {elapsed}.")
132
141
  finally:
133
142
  self.status_controller.finish(status)
134
- return status.complete
143
+ return status.complete or 0
135
144
 
136
145
  def create_all_covers(self):
137
146
  """Create all covers for all libraries."""
138
147
  pks = CustomCover.objects.values_list("pk", flat=True)
139
- self._bulk_create_comic_covers(pks, custom=True)
148
+ count = self._bulk_create_comic_covers(pks, custom=True)
140
149
  pks = Comic.objects.values_list("pk", flat=True)
141
- self._bulk_create_comic_covers(pks, custom=False)
150
+ count += self._bulk_create_comic_covers(pks, custom=False)
@@ -4,7 +4,7 @@ from pathlib import Path
4
4
 
5
5
  from fnvhash import fnv1a_32
6
6
 
7
- from codex.settings.settings import ROOT_CACHE_PATH
7
+ from codex.settings import ROOT_CACHE_PATH
8
8
 
9
9
 
10
10
  class CoverPathMixin:
@@ -2,23 +2,20 @@
2
2
 
3
3
  import os
4
4
  import shutil
5
+ from abc import ABC
5
6
  from pathlib import Path
6
7
 
7
8
  from codex.librarian.covers.create import CoverCreateThread
8
- from codex.librarian.covers.status import CoverStatusTypes
9
+ from codex.librarian.covers.status import FindOrphanCoversStatus, RemoveCoversStatus
9
10
  from codex.librarian.notifier.tasks import COVERS_CHANGED_TASK
10
11
  from codex.models import Comic
11
12
  from codex.models.paths import CustomCover
12
- from codex.status import Status
13
13
 
14
14
 
15
- class CoverPurgeThread(CoverCreateThread):
15
+ class CoverPurgeThread(CoverCreateThread, ABC):
16
16
  """Cover Purge methods."""
17
17
 
18
- _CLEANUP_STATUS_MAP = (
19
- Status(CoverStatusTypes.FIND_ORPHAN),
20
- Status(CoverStatusTypes.PURGE_COVERS),
21
- )
18
+ _CLEANUP_STATUS_MAP = (FindOrphanCoversStatus, RemoveCoversStatus)
22
19
 
23
20
  @classmethod
24
21
  def _cleanup_cover_dirs(cls, path, cover_root):
@@ -31,10 +28,10 @@ class CoverPurgeThread(CoverCreateThread):
31
28
  except OSError:
32
29
  pass
33
30
 
34
- def purge_cover_paths(self, cover_paths, cover_root):
31
+ def purge_cover_paths(self, cover_paths, cover_root) -> int:
35
32
  """Purge a set a cover paths."""
36
33
  self.log.debug(f"Removing {len(cover_paths)} possible cover thumbnails...")
37
- status = Status(CoverStatusTypes.PURGE_COVERS, 0, len(cover_paths))
34
+ status = RemoveCoversStatus(0, len(cover_paths))
38
35
  try:
39
36
  self.status_controller.start(status)
40
37
  cover_dirs = set()
@@ -48,12 +45,11 @@ class CoverPurgeThread(CoverCreateThread):
48
45
  self.status_controller.update(status, notify=False)
49
46
  for cover_dir in cover_dirs:
50
47
  self._cleanup_cover_dirs(cover_dir, cover_root)
51
- self.log.info(f"Removed {status.complete} cover thumbnails.")
52
48
  finally:
53
49
  self.status_controller.finish(status)
54
- return status.complete
50
+ return status.complete or 0
55
51
 
56
- def purge_comic_covers(self, pks: frozenset[int], custom: bool):
52
+ def purge_comic_covers(self, pks: frozenset[int], *, custom: bool):
57
53
  """Purge a set a cover paths."""
58
54
  cover_paths = self.get_cover_paths(pks, custom)
59
55
  cover_root = self.CUSTOM_COVERS_ROOT if custom else self.COVERS_ROOT
@@ -62,20 +58,26 @@ class CoverPurgeThread(CoverCreateThread):
62
58
  def purge_all_comic_covers(self, librarian_queue):
63
59
  """Purge every comic cover."""
64
60
  self.log.debug("Removing entire comic cover cache.")
61
+ changed = False
65
62
  try:
66
- shutil.rmtree(self.COVERS_ROOT)
67
- self.log.info("Removed entire comic cover cache.")
68
- shutil.rmtree(self.CUSTOM_COVERS_ROOT)
69
- self.log.info("Removed entire custom cover cache.")
63
+ if self.COVERS_ROOT.exists():
64
+ shutil.rmtree(self.COVERS_ROOT)
65
+ changed = True
66
+ if self.COVERS_ROOT.exists():
67
+ shutil.rmtree(self.CUSTOM_COVERS_ROOT)
68
+ changed = True
69
+ self.log.success("Removed entire comic cover cache and custom cover cache.")
70
70
  except OSError as exc:
71
71
  self.log.warning(exc)
72
- librarian_queue.put(COVERS_CHANGED_TASK)
72
+ if changed:
73
+ librarian_queue.put(COVERS_CHANGED_TASK)
73
74
 
74
75
  def _cleanup_orphan_covers(self, cover_class, cover_root, name):
75
76
  """Remove all orphan cover thumbs."""
77
+ status = FindOrphanCoversStatus()
76
78
  try:
77
79
  self.log.debug(f"Removing covers from missing {name}.")
78
- self.status_controller.start_many(self._CLEANUP_STATUS_MAP)
80
+ self.status_controller.start(status)
79
81
  pks = cover_class.objects.all().values_list("pk", flat=True)
80
82
  db_cover_paths = self.get_cover_paths(pks, custom=False)
81
83
 
@@ -87,11 +89,9 @@ class CoverPurgeThread(CoverCreateThread):
87
89
  if fs_cover_path not in db_cover_paths:
88
90
  orphan_cover_paths.add(fs_cover_path)
89
91
  finally:
90
- self.status_controller.finish(CoverStatusTypes.FIND_ORPHAN)
92
+ self.status_controller.finish(status)
91
93
 
92
- count = self.purge_cover_paths(orphan_cover_paths, cover_root)
93
- self.log.info(f"Removed {count} covers for missing {name}.")
94
- return count
94
+ self.purge_cover_paths(orphan_cover_paths, cover_root)
95
95
 
96
96
  def cleanup_orphan_covers(self):
97
97
  """Cleanup both comic and custom covers."""
@@ -1,11 +1,42 @@
1
1
  """Cover status types."""
2
2
 
3
- from django.db.models import TextChoices
3
+ from abc import ABC
4
4
 
5
+ from codex.librarian.status import Status
5
6
 
6
- class CoverStatusTypes(TextChoices):
7
- """Cover Types."""
8
7
 
9
- CREATE_COVERS = "CCC"
10
- PURGE_COVERS = "CCD"
11
- FIND_ORPHAN = "CFO"
8
+ class CoversStatus(Status, ABC):
9
+ """Covers Status."""
10
+
11
+ ITEM_NAME = "covers"
12
+
13
+
14
+ class CreateCoversStatus(CoversStatus):
15
+ """Create Covers Status."""
16
+
17
+ CODE = "CCC"
18
+ VERB = "Create"
19
+
20
+
21
+ class RemoveCoversStatus(CoversStatus):
22
+ """Purge Covers Status."""
23
+
24
+ CODE = "CRC"
25
+ VERB = "Remove"
26
+ log_success = True
27
+
28
+
29
+ class FindOrphanCoversStatus(CoversStatus):
30
+ """Find Orphan Covers Status."""
31
+
32
+ CODE = "CFO"
33
+ ITEM_NAME = "orphan covers"
34
+ VERB = "Find"
35
+ _verbed = "Found"
36
+
37
+
38
+ COVERS_STATII = (
39
+ CreateCoversStatus,
40
+ RemoveCoversStatus,
41
+ FindOrphanCoversStatus,
42
+ )
@@ -1,10 +1,11 @@
1
1
  """Covers Tasks."""
2
2
 
3
+ from abc import ABC
3
4
  from dataclasses import dataclass
4
5
 
5
6
 
6
7
  @dataclass
7
- class CoverTask:
8
+ class CoverTask(ABC): # noqa: B024
8
9
  """Handle with the CoverThread."""
9
10
 
10
11
 
@@ -5,12 +5,13 @@ from time import sleep
5
5
  from types import MappingProxyType
6
6
 
7
7
  from django.utils import timezone as django_timezone
8
+ from typing_extensions import override
8
9
 
9
- from codex.librarian.janitor.scheduled_time import get_janitor_time
10
- from codex.librarian.janitor.tasks import JanitorNightlyTask
10
+ from codex.librarian.scribe.janitor.scheduled_time import get_janitor_time
11
+ from codex.librarian.scribe.janitor.tasks import JanitorNightlyTask
11
12
  from codex.librarian.telemeter.scheduled_time import get_telemeter_time
12
13
  from codex.librarian.telemeter.tasks import TelemeterTask
13
- from codex.threads import NamedThread
14
+ from codex.librarian.threads import NamedThread
14
15
 
15
16
  _TASK_TIME_FUNCTION_MAP = MappingProxyType(
16
17
  {
@@ -58,6 +59,7 @@ class CronThread(NamedThread):
58
59
  # Times are always ordered so stop checking at the first future job.
59
60
  break
60
61
 
62
+ @override
61
63
  def run(self):
62
64
  """Cron loop."""
63
65
  try: