codex 1.7.14__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 (1142) 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/VSelect-DQPZyfSb.57477277e7dd.css +1 -0
  257. codex/static_root/assets/VSelect-DQPZyfSb.57477277e7dd.css.br +0 -0
  258. codex/static_root/assets/VSelect-DQPZyfSb.57477277e7dd.css.gz +0 -0
  259. codex/static_root/assets/VSelect-DQPZyfSb.css +1 -0
  260. codex/static_root/assets/VSelect-DQPZyfSb.css.br +0 -0
  261. codex/static_root/assets/VSelect-DQPZyfSb.css.gz +0 -0
  262. codex/static_root/assets/VSelectionControl-BUBBamEF.2e9636e900d8.js +1 -0
  263. codex/static_root/assets/VSelectionControl-BUBBamEF.2e9636e900d8.js.br +0 -0
  264. codex/static_root/assets/VSelectionControl-BUBBamEF.2e9636e900d8.js.gz +0 -0
  265. codex/static_root/assets/VSelectionControl-BUBBamEF.js +1 -0
  266. codex/static_root/assets/VSelectionControl-BUBBamEF.js.br +0 -0
  267. codex/static_root/assets/VSelectionControl-BUBBamEF.js.gz +0 -0
  268. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css +1 -0
  269. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.br +0 -0
  270. codex/static_root/assets/VTable-CQyv0wyO.1740239d481b.css.gz +0 -0
  271. codex/static_root/assets/VTable-CQyv0wyO.css +1 -0
  272. codex/static_root/assets/VTable-CQyv0wyO.css.br +0 -0
  273. codex/static_root/assets/VTable-CQyv0wyO.css.gz +0 -0
  274. codex/static_root/assets/VTable-CwYzcGki.ddd22f371cdb.js +1 -0
  275. codex/static_root/assets/VTable-CwYzcGki.ddd22f371cdb.js.br +0 -0
  276. codex/static_root/assets/VTable-CwYzcGki.ddd22f371cdb.js.gz +0 -0
  277. codex/static_root/assets/VTable-CwYzcGki.js +1 -0
  278. codex/static_root/assets/VTable-CwYzcGki.js.br +0 -0
  279. codex/static_root/assets/VTable-CwYzcGki.js.gz +0 -0
  280. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css +1 -0
  281. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.br +0 -0
  282. codex/static_root/assets/VWindowItem-ChYLiXSE.a9c679a2977e.css.gz +0 -0
  283. codex/static_root/assets/VWindowItem-ChYLiXSE.css +1 -0
  284. codex/static_root/assets/VWindowItem-ChYLiXSE.css.br +0 -0
  285. codex/static_root/assets/VWindowItem-ChYLiXSE.css.gz +0 -0
  286. codex/static_root/assets/VWindowItem-WsjNvbu_.0c1a85eba03e.js +1 -0
  287. codex/static_root/assets/VWindowItem-WsjNvbu_.0c1a85eba03e.js.br +0 -0
  288. codex/static_root/assets/VWindowItem-WsjNvbu_.0c1a85eba03e.js.gz +0 -0
  289. codex/static_root/assets/VWindowItem-WsjNvbu_.js +1 -0
  290. codex/static_root/assets/VWindowItem-WsjNvbu_.js.br +0 -0
  291. codex/static_root/assets/VWindowItem-WsjNvbu_.js.gz +0 -0
  292. codex/static_root/assets/admin-ByuViOU9.9a1ee0a29ae2.js +1 -0
  293. codex/static_root/assets/admin-ByuViOU9.9a1ee0a29ae2.js.br +0 -0
  294. codex/static_root/assets/admin-ByuViOU9.9a1ee0a29ae2.js.gz +0 -0
  295. codex/static_root/assets/admin-ByuViOU9.js +1 -0
  296. codex/static_root/assets/admin-ByuViOU9.js.br +0 -0
  297. codex/static_root/assets/admin-ByuViOU9.js.gz +0 -0
  298. codex/static_root/assets/admin-CJauEn2X.b0c66e357083.js +1 -0
  299. codex/static_root/assets/admin-CJauEn2X.b0c66e357083.js.br +0 -0
  300. codex/static_root/assets/admin-CJauEn2X.b0c66e357083.js.gz +0 -0
  301. codex/static_root/assets/admin-CJauEn2X.js +1 -0
  302. codex/static_root/assets/admin-CJauEn2X.js.br +0 -0
  303. codex/static_root/assets/admin-CJauEn2X.js.gz +0 -0
  304. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css +1 -0
  305. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.br +0 -0
  306. codex/static_root/assets/admin-DJCVf2PA.7ba26fd73264.css.gz +0 -0
  307. codex/static_root/assets/admin-DJCVf2PA.css +1 -0
  308. codex/static_root/assets/admin-DJCVf2PA.css.br +0 -0
  309. codex/static_root/assets/admin-DJCVf2PA.css.gz +0 -0
  310. codex/static_root/assets/admin-menu-BRVAx54U.2c7d6cfd8a50.js +1 -0
  311. codex/static_root/assets/admin-menu-BRVAx54U.2c7d6cfd8a50.js.br +0 -0
  312. codex/static_root/assets/admin-menu-BRVAx54U.2c7d6cfd8a50.js.gz +0 -0
  313. codex/static_root/assets/admin-menu-BRVAx54U.js +1 -0
  314. codex/static_root/assets/admin-menu-BRVAx54U.js.br +0 -0
  315. codex/static_root/assets/admin-menu-BRVAx54U.js.gz +0 -0
  316. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css +1 -0
  317. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.br +0 -0
  318. codex/static_root/assets/admin-menu-hpyUS8ku.18284a11084d.css.gz +0 -0
  319. codex/static_root/assets/admin-menu-hpyUS8ku.css +1 -0
  320. codex/static_root/assets/admin-menu-hpyUS8ku.css.br +0 -0
  321. codex/static_root/assets/admin-menu-hpyUS8ku.css.gz +0 -0
  322. codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.a592809d4008.css +1 -0
  323. codex/static_root/assets/admin-settings-button-progress-Cks9_KN-.css +1 -0
  324. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.4fe043a87c09.js +1 -0
  325. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.4fe043a87c09.js.br +0 -0
  326. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.4fe043a87c09.js.gz +0 -0
  327. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.js +1 -0
  328. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.js.br +0 -0
  329. codex/static_root/assets/admin-settings-button-progress-Do1FKRa_.js.gz +0 -0
  330. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css +1 -0
  331. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.br +0 -0
  332. codex/static_root/assets/browser-Cdi7U5ku.bab9fccf0326.css.gz +0 -0
  333. codex/static_root/assets/browser-Cdi7U5ku.css +1 -0
  334. codex/static_root/assets/browser-Cdi7U5ku.css.br +0 -0
  335. codex/static_root/assets/browser-Cdi7U5ku.css.gz +0 -0
  336. codex/static_root/assets/browser-OtRiWIux.be28cec0e65a.js +1 -0
  337. codex/static_root/assets/browser-OtRiWIux.be28cec0e65a.js.br +0 -0
  338. codex/static_root/assets/browser-OtRiWIux.be28cec0e65a.js.gz +0 -0
  339. codex/static_root/assets/browser-OtRiWIux.js +1 -0
  340. codex/static_root/assets/browser-OtRiWIux.js.br +0 -0
  341. codex/static_root/assets/browser-OtRiWIux.js.gz +0 -0
  342. codex/static_root/assets/change-password-dialog-DE8R9FId.f3180b3946dd.js +1 -0
  343. codex/static_root/assets/change-password-dialog-DE8R9FId.f3180b3946dd.js.br +0 -0
  344. codex/static_root/assets/change-password-dialog-DE8R9FId.f3180b3946dd.js.gz +0 -0
  345. codex/static_root/assets/change-password-dialog-DE8R9FId.js +1 -0
  346. codex/static_root/assets/change-password-dialog-DE8R9FId.js.br +0 -0
  347. codex/static_root/assets/change-password-dialog-DE8R9FId.js.gz +0 -0
  348. codex/static_root/assets/confirm-dialog-Dy-4G4rU.c2de2d0acce1.js +1 -0
  349. codex/static_root/assets/confirm-dialog-Dy-4G4rU.c2de2d0acce1.js.br +0 -0
  350. codex/static_root/assets/confirm-dialog-Dy-4G4rU.c2de2d0acce1.js.gz +0 -0
  351. codex/static_root/assets/confirm-dialog-Dy-4G4rU.js +1 -0
  352. codex/static_root/assets/confirm-dialog-Dy-4G4rU.js.br +0 -0
  353. codex/static_root/assets/confirm-dialog-Dy-4G4rU.js.gz +0 -0
  354. codex/static_root/assets/confirm-dialog-YfC8mRQA.be37e8f67e0f.css +1 -0
  355. codex/static_root/assets/confirm-dialog-YfC8mRQA.css +1 -0
  356. codex/static_root/assets/datetime-column-Bt7J1qEf.css +1 -0
  357. codex/static_root/assets/datetime-column-Bt7J1qEf.css.br +0 -0
  358. codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css +1 -0
  359. codex/static_root/assets/datetime-column-Bt7J1qEf.d83164b4d4cb.css.br +0 -0
  360. codex/static_root/assets/datetime-column-C86OiFxS.32dca850b5fb.js +1 -0
  361. codex/static_root/assets/datetime-column-C86OiFxS.32dca850b5fb.js.br +0 -0
  362. codex/static_root/assets/datetime-column-C86OiFxS.32dca850b5fb.js.gz +0 -0
  363. codex/static_root/assets/datetime-column-C86OiFxS.js +1 -0
  364. codex/static_root/assets/datetime-column-C86OiFxS.js.br +0 -0
  365. codex/static_root/assets/datetime-column-C86OiFxS.js.gz +0 -0
  366. codex/static_root/assets/filter-OaiDOf0D.41d89efe9cd5.js +1 -0
  367. codex/static_root/assets/filter-OaiDOf0D.41d89efe9cd5.js.br +0 -0
  368. codex/static_root/assets/filter-OaiDOf0D.41d89efe9cd5.js.gz +0 -0
  369. codex/static_root/assets/filter-OaiDOf0D.js +1 -0
  370. codex/static_root/assets/filter-OaiDOf0D.js.br +0 -0
  371. codex/static_root/assets/filter-OaiDOf0D.js.gz +0 -0
  372. codex/static_root/assets/flag-tab-ChsErni6.0fca30995a0e.js +1 -0
  373. codex/static_root/assets/flag-tab-ChsErni6.0fca30995a0e.js.br +0 -0
  374. codex/static_root/assets/flag-tab-ChsErni6.0fca30995a0e.js.gz +0 -0
  375. codex/static_root/assets/flag-tab-ChsErni6.js +1 -0
  376. codex/static_root/assets/flag-tab-ChsErni6.js.br +0 -0
  377. codex/static_root/assets/flag-tab-ChsErni6.js.gz +0 -0
  378. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css +1 -0
  379. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.br +0 -0
  380. codex/static_root/assets/forwardRefs-B_sUWZn6.5114f206ca9c.css.gz +0 -0
  381. codex/static_root/assets/forwardRefs-B_sUWZn6.css +1 -0
  382. codex/static_root/assets/forwardRefs-B_sUWZn6.css.br +0 -0
  383. codex/static_root/assets/forwardRefs-B_sUWZn6.css.gz +0 -0
  384. codex/static_root/assets/forwardRefs-BjkhALLr.1bfbdea189d7.js +1 -0
  385. codex/static_root/assets/forwardRefs-BjkhALLr.1bfbdea189d7.js.br +0 -0
  386. codex/static_root/assets/forwardRefs-BjkhALLr.1bfbdea189d7.js.gz +0 -0
  387. codex/static_root/assets/forwardRefs-BjkhALLr.js +1 -0
  388. codex/static_root/assets/forwardRefs-BjkhALLr.js.br +0 -0
  389. codex/static_root/assets/forwardRefs-BjkhALLr.js.gz +0 -0
  390. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css +1 -0
  391. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.br +0 -0
  392. codex/static_root/assets/group-tab-CQ_Qw6h8.078d0a9225ba.css.gz +0 -0
  393. codex/static_root/assets/group-tab-CQ_Qw6h8.css +1 -0
  394. codex/static_root/assets/group-tab-CQ_Qw6h8.css.br +0 -0
  395. codex/static_root/assets/group-tab-CQ_Qw6h8.css.gz +0 -0
  396. codex/static_root/assets/group-tab-DB4vz9MA.42dd130d0118.js +1 -0
  397. codex/static_root/assets/group-tab-DB4vz9MA.42dd130d0118.js.br +0 -0
  398. codex/static_root/assets/group-tab-DB4vz9MA.42dd130d0118.js.gz +0 -0
  399. codex/static_root/assets/group-tab-DB4vz9MA.js +1 -0
  400. codex/static_root/assets/group-tab-DB4vz9MA.js.br +0 -0
  401. codex/static_root/assets/group-tab-DB4vz9MA.js.gz +0 -0
  402. codex/static_root/assets/http-error-7Kkr0CW4.c16118f162ac.js +1 -0
  403. codex/static_root/assets/http-error-7Kkr0CW4.c16118f162ac.js.br +0 -0
  404. codex/static_root/assets/http-error-7Kkr0CW4.c16118f162ac.js.gz +0 -0
  405. codex/static_root/assets/http-error-7Kkr0CW4.js +1 -0
  406. codex/static_root/assets/http-error-7Kkr0CW4.js.br +0 -0
  407. codex/static_root/assets/http-error-7Kkr0CW4.js.gz +0 -0
  408. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css +1 -0
  409. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.br +0 -0
  410. codex/static_root/assets/http-error-CB3k5P-n.82d886ac81c7.css.gz +0 -0
  411. codex/static_root/assets/http-error-CB3k5P-n.css +1 -0
  412. codex/static_root/assets/http-error-CB3k5P-n.css.br +0 -0
  413. codex/static_root/assets/http-error-CB3k5P-n.css.gz +0 -0
  414. codex/static_root/assets/index-yvfyzOV3.c886587fcfb6.js +1 -0
  415. codex/static_root/assets/index-yvfyzOV3.c886587fcfb6.js.br +0 -0
  416. codex/static_root/assets/index-yvfyzOV3.c886587fcfb6.js.gz +0 -0
  417. codex/static_root/assets/index-yvfyzOV3.js +1 -0
  418. codex/static_root/assets/index-yvfyzOV3.js.br +0 -0
  419. codex/static_root/assets/index-yvfyzOV3.js.gz +0 -0
  420. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css +1 -0
  421. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.br +0 -0
  422. codex/static_root/assets/library-tab-5StL67ei.0fad8998a237.css.gz +0 -0
  423. codex/static_root/assets/library-tab-5StL67ei.css +1 -0
  424. codex/static_root/assets/library-tab-5StL67ei.css.br +0 -0
  425. codex/static_root/assets/library-tab-5StL67ei.css.gz +0 -0
  426. codex/static_root/assets/library-tab-BJM2q4YE.0eb19632c084.js +1 -0
  427. codex/static_root/assets/library-tab-BJM2q4YE.0eb19632c084.js.br +0 -0
  428. codex/static_root/assets/library-tab-BJM2q4YE.0eb19632c084.js.gz +0 -0
  429. codex/static_root/assets/library-tab-BJM2q4YE.js +1 -0
  430. codex/static_root/assets/library-tab-BJM2q4YE.js.br +0 -0
  431. codex/static_root/assets/library-tab-BJM2q4YE.js.gz +0 -0
  432. codex/static_root/assets/main-0gkU-bgy.475633238e98.js +39 -0
  433. codex/static_root/assets/main-0gkU-bgy.475633238e98.js.br +0 -0
  434. codex/static_root/assets/main-0gkU-bgy.475633238e98.js.gz +0 -0
  435. codex/static_root/assets/main-0gkU-bgy.js +39 -0
  436. codex/static_root/assets/main-0gkU-bgy.js.br +0 -0
  437. codex/static_root/assets/main-0gkU-bgy.js.gz +0 -0
  438. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css +5 -0
  439. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.br +0 -0
  440. codex/static_root/assets/main-B8_0rUnw.a9be0875ae25.css.gz +0 -0
  441. codex/static_root/assets/main-B8_0rUnw.css +5 -0
  442. codex/static_root/assets/main-B8_0rUnw.css.br +0 -0
  443. codex/static_root/assets/main-B8_0rUnw.css.gz +0 -0
  444. codex/static_root/assets/pager-full-pdf-dMflY9TZ.14b64093d057.js +1 -0
  445. codex/static_root/assets/pager-full-pdf-dMflY9TZ.14b64093d057.js.br +0 -0
  446. codex/static_root/assets/pager-full-pdf-dMflY9TZ.14b64093d057.js.gz +0 -0
  447. codex/static_root/assets/pager-full-pdf-dMflY9TZ.js +1 -0
  448. codex/static_root/assets/pager-full-pdf-dMflY9TZ.js.br +0 -0
  449. codex/static_root/assets/pager-full-pdf-dMflY9TZ.js.gz +0 -0
  450. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css +1 -0
  451. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.br +0 -0
  452. codex/static_root/assets/pagination-toolbar-741OafNw.4f9155469274.css.gz +0 -0
  453. codex/static_root/assets/pagination-toolbar-741OafNw.css +1 -0
  454. codex/static_root/assets/pagination-toolbar-741OafNw.css.br +0 -0
  455. codex/static_root/assets/pagination-toolbar-741OafNw.css.gz +0 -0
  456. codex/static_root/assets/pagination-toolbar-BzWY1XTi.b1fbe47f722d.js +1 -0
  457. codex/static_root/assets/pagination-toolbar-BzWY1XTi.b1fbe47f722d.js.br +0 -0
  458. codex/static_root/assets/pagination-toolbar-BzWY1XTi.b1fbe47f722d.js.gz +0 -0
  459. codex/static_root/assets/pagination-toolbar-BzWY1XTi.js +1 -0
  460. codex/static_root/assets/pagination-toolbar-BzWY1XTi.js.br +0 -0
  461. codex/static_root/assets/pagination-toolbar-BzWY1XTi.js.gz +0 -0
  462. codex/static_root/assets/pdf-doc-remlTMFH.4063b6ec0033.js +372 -0
  463. codex/static_root/assets/pdf-doc-remlTMFH.4063b6ec0033.js.br +0 -0
  464. codex/static_root/assets/pdf-doc-remlTMFH.4063b6ec0033.js.gz +0 -0
  465. codex/static_root/assets/pdf-doc-remlTMFH.js +372 -0
  466. codex/static_root/assets/pdf-doc-remlTMFH.js.br +0 -0
  467. codex/static_root/assets/pdf-doc-remlTMFH.js.gz +0 -0
  468. codex/static_root/assets/reader-CmiUt5h2.65e3cb07aac9.js +2 -0
  469. codex/static_root/assets/reader-CmiUt5h2.65e3cb07aac9.js.br +0 -0
  470. codex/static_root/assets/reader-CmiUt5h2.65e3cb07aac9.js.gz +0 -0
  471. codex/static_root/assets/reader-CmiUt5h2.js +2 -0
  472. codex/static_root/assets/reader-CmiUt5h2.js.br +0 -0
  473. codex/static_root/assets/reader-CmiUt5h2.js.gz +0 -0
  474. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css +1 -0
  475. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.br +0 -0
  476. codex/static_root/assets/reader-HE07eoaG.8626eeb7c718.css.gz +0 -0
  477. codex/static_root/assets/reader-HE07eoaG.css +1 -0
  478. codex/static_root/assets/reader-HE07eoaG.css.br +0 -0
  479. codex/static_root/assets/reader-HE07eoaG.css.gz +0 -0
  480. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css +1 -0
  481. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.br +0 -0
  482. codex/static_root/assets/relation-chips-CcFgPQOM.0b468249b62e.css.gz +0 -0
  483. codex/static_root/assets/relation-chips-CcFgPQOM.css +1 -0
  484. codex/static_root/assets/relation-chips-CcFgPQOM.css.br +0 -0
  485. codex/static_root/assets/relation-chips-CcFgPQOM.css.gz +0 -0
  486. codex/static_root/assets/relation-chips-Dl0i3EP7.1f365f5c1e41.js +1 -0
  487. codex/static_root/assets/relation-chips-Dl0i3EP7.1f365f5c1e41.js.br +0 -0
  488. codex/static_root/assets/relation-chips-Dl0i3EP7.1f365f5c1e41.js.gz +0 -0
  489. codex/static_root/assets/relation-chips-Dl0i3EP7.js +1 -0
  490. codex/static_root/assets/relation-chips-Dl0i3EP7.js.br +0 -0
  491. codex/static_root/assets/relation-chips-Dl0i3EP7.js.gz +0 -0
  492. codex/static_root/assets/settings-drawer-CpKXWPSA.82625de924bb.js +2 -0
  493. codex/static_root/assets/settings-drawer-CpKXWPSA.82625de924bb.js.br +0 -0
  494. codex/static_root/assets/settings-drawer-CpKXWPSA.82625de924bb.js.gz +0 -0
  495. codex/static_root/assets/settings-drawer-CpKXWPSA.js +2 -0
  496. codex/static_root/assets/settings-drawer-CpKXWPSA.js.br +0 -0
  497. codex/static_root/assets/settings-drawer-CpKXWPSA.js.gz +0 -0
  498. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css +1 -0
  499. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.br +0 -0
  500. codex/static_root/assets/settings-drawer-CpS_aX4Z.9d4d9533d033.css.gz +0 -0
  501. codex/static_root/assets/settings-drawer-CpS_aX4Z.css +1 -0
  502. codex/static_root/assets/settings-drawer-CpS_aX4Z.css.br +0 -0
  503. codex/static_root/assets/settings-drawer-CpS_aX4Z.css.gz +0 -0
  504. codex/static_root/assets/ssrBoot-D4fyL90J.0eef13056f93.js +1 -0
  505. codex/static_root/assets/ssrBoot-D4fyL90J.0eef13056f93.js.br +0 -0
  506. codex/static_root/assets/ssrBoot-D4fyL90J.0eef13056f93.js.gz +0 -0
  507. codex/static_root/assets/ssrBoot-D4fyL90J.js +1 -0
  508. codex/static_root/assets/ssrBoot-D4fyL90J.js.br +0 -0
  509. codex/static_root/assets/ssrBoot-D4fyL90J.js.gz +0 -0
  510. codex/static_root/assets/stats-tab-Cu7saNBy.8ad3f7a0995a.js +1 -0
  511. codex/static_root/assets/stats-tab-Cu7saNBy.8ad3f7a0995a.js.br +0 -0
  512. codex/static_root/assets/stats-tab-Cu7saNBy.8ad3f7a0995a.js.gz +0 -0
  513. codex/static_root/assets/stats-tab-Cu7saNBy.js +1 -0
  514. codex/static_root/assets/stats-tab-Cu7saNBy.js.br +0 -0
  515. codex/static_root/assets/stats-tab-Cu7saNBy.js.gz +0 -0
  516. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css +1 -0
  517. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.br +0 -0
  518. codex/static_root/assets/stats-tab-Dpqh5pF9.8dba36f90032.css.gz +0 -0
  519. codex/static_root/assets/stats-tab-Dpqh5pF9.css +1 -0
  520. codex/static_root/assets/stats-tab-Dpqh5pF9.css.br +0 -0
  521. codex/static_root/assets/stats-tab-Dpqh5pF9.css.gz +0 -0
  522. codex/static_root/assets/task-tab-B66NRaoH.fdb8c98f0652.js +1 -0
  523. codex/static_root/assets/task-tab-B66NRaoH.fdb8c98f0652.js.br +0 -0
  524. codex/static_root/assets/task-tab-B66NRaoH.fdb8c98f0652.js.gz +0 -0
  525. codex/static_root/assets/task-tab-B66NRaoH.js +1 -0
  526. codex/static_root/assets/task-tab-B66NRaoH.js.br +0 -0
  527. codex/static_root/assets/task-tab-B66NRaoH.js.gz +0 -0
  528. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css +1 -0
  529. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.br +0 -0
  530. codex/static_root/assets/unauthorized-BBwsmi0O.19d4882b821d.css.gz +0 -0
  531. codex/static_root/assets/unauthorized-BBwsmi0O.css +1 -0
  532. codex/static_root/assets/unauthorized-BBwsmi0O.css.br +0 -0
  533. codex/static_root/assets/unauthorized-BBwsmi0O.css.gz +0 -0
  534. codex/static_root/assets/unauthorized-CLNP5Zx1.9f072de5e06c.js +1 -0
  535. codex/static_root/assets/unauthorized-CLNP5Zx1.9f072de5e06c.js.br +0 -0
  536. codex/static_root/assets/unauthorized-CLNP5Zx1.9f072de5e06c.js.gz +0 -0
  537. codex/static_root/assets/unauthorized-CLNP5Zx1.js +1 -0
  538. codex/static_root/assets/unauthorized-CLNP5Zx1.js.br +0 -0
  539. codex/static_root/assets/unauthorized-CLNP5Zx1.js.gz +0 -0
  540. codex/static_root/assets/user-tab-BqhQ3sls.cacf99be60fb.js +1 -0
  541. codex/static_root/assets/user-tab-BqhQ3sls.cacf99be60fb.js.br +0 -0
  542. codex/static_root/assets/user-tab-BqhQ3sls.cacf99be60fb.js.gz +0 -0
  543. codex/static_root/assets/user-tab-BqhQ3sls.js +1 -0
  544. codex/static_root/assets/user-tab-BqhQ3sls.js.br +0 -0
  545. codex/static_root/assets/user-tab-BqhQ3sls.js.gz +0 -0
  546. codex/static_root/img/folder.83168d8d3119.svg +1 -0
  547. codex/static_root/img/folder.83168d8d3119.svg.br +1 -0
  548. codex/static_root/img/folder.83168d8d3119.svg.gz +0 -0
  549. codex/static_root/img/folder.svg +1 -1
  550. codex/static_root/img/folder.svg.br +0 -0
  551. codex/static_root/img/folder.svg.gz +0 -0
  552. codex/static_root/img/imprint.3ca7a779b949.svg +1 -0
  553. codex/static_root/img/imprint.3ca7a779b949.svg.br +0 -0
  554. codex/static_root/img/imprint.3ca7a779b949.svg.gz +0 -0
  555. codex/static_root/img/imprint.svg +1 -1
  556. codex/static_root/img/imprint.svg.br +0 -0
  557. codex/static_root/img/imprint.svg.gz +0 -0
  558. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg +1 -0
  559. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.br +0 -0
  560. codex/static_root/img/logo-maskable.aeef5c2fffc8.svg.gz +0 -0
  561. codex/static_root/img/logo-maskable.svg +1 -1
  562. codex/static_root/img/logo-maskable.svg.br +0 -0
  563. codex/static_root/img/logo-maskable.svg.gz +0 -0
  564. codex/static_root/img/logo.00c902973831.svg +1 -0
  565. codex/static_root/img/logo.00c902973831.svg.br +0 -0
  566. codex/static_root/img/logo.00c902973831.svg.gz +0 -0
  567. codex/static_root/img/logo.svg +1 -1
  568. codex/static_root/img/logo.svg.br +0 -0
  569. codex/static_root/img/logo.svg.gz +0 -0
  570. codex/static_root/img/missing-cover-165.f4bb7740084c.webp +0 -0
  571. codex/static_root/img/missing-cover-165.webp +0 -0
  572. codex/static_root/img/missing-cover.7329518c5972.svg +1 -0
  573. codex/static_root/img/missing-cover.7329518c5972.svg.br +0 -0
  574. codex/static_root/img/missing-cover.7329518c5972.svg.gz +0 -0
  575. codex/static_root/img/missing-cover.svg +1 -1
  576. codex/static_root/img/missing-cover.svg.br +0 -0
  577. codex/static_root/img/missing-cover.svg.gz +0 -0
  578. codex/static_root/img/series.b092bbac0c2a.svg +1 -0
  579. codex/static_root/img/series.b092bbac0c2a.svg.br +0 -0
  580. codex/static_root/img/series.b092bbac0c2a.svg.gz +0 -0
  581. codex/static_root/img/series.svg +1 -1
  582. codex/static_root/img/series.svg.br +0 -0
  583. codex/static_root/img/series.svg.gz +0 -0
  584. codex/static_root/img/story-arc.884f7b1d95bd.svg +1 -0
  585. codex/static_root/img/story-arc.884f7b1d95bd.svg.br +0 -0
  586. codex/static_root/img/story-arc.884f7b1d95bd.svg.gz +0 -0
  587. codex/static_root/img/story-arc.svg +1 -1
  588. codex/static_root/img/story-arc.svg.br +0 -0
  589. codex/static_root/img/story-arc.svg.gz +0 -0
  590. codex/static_root/img/volume.516ec0c3018d.svg +1 -0
  591. codex/static_root/img/volume.516ec0c3018d.svg.br +0 -0
  592. codex/static_root/img/volume.516ec0c3018d.svg.gz +0 -0
  593. codex/static_root/img/volume.svg +1 -1
  594. codex/static_root/img/volume.svg.br +0 -0
  595. codex/static_root/img/volume.svg.gz +0 -0
  596. codex/static_root/manifest.474fa7aff739.json +760 -0
  597. codex/static_root/manifest.474fa7aff739.json.br +0 -0
  598. codex/static_root/manifest.474fa7aff739.json.gz +0 -0
  599. codex/static_root/manifest.json +350 -347
  600. codex/static_root/manifest.json.br +0 -0
  601. codex/static_root/manifest.json.gz +0 -0
  602. codex/static_root/staticfiles.json +1 -1
  603. codex/templates/headers-script-globals.html +1 -0
  604. codex/urls/api/browser.py +10 -1
  605. codex/urls/converters.py +2 -5
  606. codex/urls/root.py +1 -1
  607. codex/util.py +14 -8
  608. codex/views/admin/api_key.py +1 -1
  609. codex/views/admin/flag.py +10 -9
  610. codex/views/admin/group.py +5 -3
  611. codex/views/admin/library.py +15 -9
  612. codex/views/admin/permissions.py +21 -0
  613. codex/views/admin/stats.py +6 -8
  614. codex/views/admin/tasks.py +48 -48
  615. codex/views/admin/user.py +5 -3
  616. codex/views/auth.py +29 -11
  617. codex/views/bookmark.py +25 -14
  618. codex/views/browser/annotate/bookmark.py +0 -3
  619. codex/views/browser/annotate/card.py +20 -5
  620. codex/views/browser/annotate/order.py +3 -7
  621. codex/views/browser/bookmark.py +10 -7
  622. codex/views/browser/breadcrumbs.py +8 -7
  623. codex/views/browser/browser.py +16 -16
  624. codex/views/browser/choices.py +81 -65
  625. codex/views/browser/cover.py +21 -19
  626. codex/views/browser/download.py +5 -5
  627. codex/views/browser/filters/bookmark.py +5 -0
  628. codex/views/browser/filters/field.py +3 -3
  629. codex/views/browser/filters/filter.py +3 -5
  630. codex/views/browser/filters/group.py +5 -5
  631. codex/views/browser/filters/search/field/column.py +13 -9
  632. codex/views/browser/filters/search/field/expression.py +1 -3
  633. codex/views/browser/filters/search/field/filter.py +2 -4
  634. codex/views/browser/filters/search/field/optimize.py +1 -1
  635. codex/views/browser/filters/search/field/parse.py +28 -7
  636. codex/views/browser/filters/search/fts.py +3 -4
  637. codex/views/browser/filters/search/parse.py +26 -26
  638. codex/views/browser/group_mtime.py +13 -10
  639. codex/views/browser/metadata/__init__.py +90 -1
  640. codex/views/browser/metadata/annotate.py +13 -27
  641. codex/views/browser/metadata/const.py +83 -0
  642. codex/views/browser/metadata/copy_intersections.py +14 -9
  643. codex/views/browser/metadata/query_intersections.py +67 -48
  644. codex/views/browser/mtime.py +4 -7
  645. codex/views/browser/order_by.py +4 -1
  646. codex/views/browser/page_in_bounds.py +6 -7
  647. codex/views/browser/paginate.py +3 -5
  648. codex/views/browser/params.py +23 -36
  649. codex/views/browser/settings.py +18 -4
  650. codex/views/browser/title.py +9 -5
  651. codex/views/browser/validate.py +6 -8
  652. codex/views/const.py +11 -9
  653. codex/views/download.py +2 -2
  654. codex/views/error.py +1 -1
  655. codex/views/exceptions.py +82 -0
  656. codex/views/frontend.py +8 -18
  657. codex/views/lazy_import.py +24 -0
  658. codex/views/mixins.py +34 -12
  659. codex/views/opds/auth.py +2 -2
  660. codex/views/opds/authentication_v1.py +2 -1
  661. codex/views/opds/const.py +1 -1
  662. codex/views/opds/urls.py +2 -1
  663. codex/views/opds/util.py +14 -41
  664. codex/views/opds/v1/entry/entry.py +12 -15
  665. codex/views/opds/v1/entry/links.py +15 -19
  666. codex/views/opds/v1/facets.py +8 -5
  667. codex/views/opds/v1/feed.py +23 -22
  668. codex/views/opds/v1/links.py +3 -7
  669. codex/views/opds/v1/opensearch_v1.py +7 -4
  670. codex/views/opds/v2/feed.py +14 -15
  671. codex/views/opds/v2/href.py +17 -12
  672. codex/views/opds/v2/links.py +3 -1
  673. codex/views/opds/v2/progression.py +31 -15
  674. codex/views/opds/v2/publications.py +18 -17
  675. codex/views/opds/v2/top_links.py +7 -2
  676. codex/views/public.py +12 -15
  677. codex/views/reader/arcs.py +153 -74
  678. codex/views/reader/books.py +72 -97
  679. codex/views/reader/page.py +13 -9
  680. codex/views/reader/params.py +33 -96
  681. codex/views/reader/reader.py +18 -73
  682. codex/views/reader/settings.py +4 -2
  683. codex/views/session.py +13 -19
  684. codex/views/settings.py +4 -9
  685. codex/views/template.py +8 -4
  686. codex/views/timezone.py +4 -5
  687. codex/views/util.py +3 -24
  688. codex/views/version.py +5 -3
  689. codex/websockets/consumers.py +7 -7
  690. codex/websockets/listener.py +4 -5
  691. codex-1.8.0.dist-info/METADATA +592 -0
  692. codex-1.8.0.dist-info/RECORD +1101 -0
  693. codex-1.8.0.dist-info/WHEEL +4 -0
  694. codex-1.8.0.dist-info/entry_points.txt +2 -0
  695. codex/db.py +0 -134
  696. codex/exceptions.py +0 -88
  697. codex/librarian/README.md +0 -4
  698. codex/librarian/delayed_taskd.py +0 -21
  699. codex/librarian/importer/__init__.py +0 -1
  700. codex/librarian/importer/aggregate.py +0 -256
  701. codex/librarian/importer/cache.py +0 -90
  702. codex/librarian/importer/const.py +0 -244
  703. codex/librarian/importer/create_comics.py +0 -139
  704. codex/librarian/importer/create_covers.py +0 -96
  705. codex/librarian/importer/create_fks.py +0 -346
  706. codex/librarian/importer/deleted.py +0 -138
  707. codex/librarian/importer/extract.py +0 -284
  708. codex/librarian/importer/failed_imports.py +0 -165
  709. codex/librarian/importer/importer.py +0 -101
  710. codex/librarian/importer/importerd.py +0 -122
  711. codex/librarian/importer/init.py +0 -264
  712. codex/librarian/importer/link_comics.py +0 -270
  713. codex/librarian/importer/link_covers.py +0 -73
  714. codex/librarian/importer/moved.py +0 -368
  715. codex/librarian/importer/query_covers.py +0 -53
  716. codex/librarian/importer/query_fks.py +0 -653
  717. codex/librarian/importer/status.py +0 -29
  718. codex/librarian/importer/tasks.py +0 -55
  719. codex/librarian/janitor/__init__.py +0 -1
  720. codex/librarian/janitor/cleanup.py +0 -167
  721. codex/librarian/janitor/failed_imports.py +0 -27
  722. codex/librarian/janitor/integrity.py +0 -378
  723. codex/librarian/janitor/janitor.py +0 -161
  724. codex/librarian/janitor/latest_version.py +0 -55
  725. codex/librarian/janitor/scheduled_time.py +0 -12
  726. codex/librarian/janitor/status.py +0 -22
  727. codex/librarian/janitor/tasks.py +0 -109
  728. codex/librarian/janitor/update.py +0 -109
  729. codex/librarian/janitor/vacuum.py +0 -51
  730. codex/librarian/search/__init__.py +0 -1
  731. codex/librarian/search/optimize.py +0 -43
  732. codex/librarian/search/remove.py +0 -53
  733. codex/librarian/search/searchd.py +0 -28
  734. codex/librarian/search/status.py +0 -13
  735. codex/librarian/search/tasks.py +0 -37
  736. codex/librarian/search/update.py +0 -305
  737. codex/librarian/watchdog/README.md +0 -11
  738. codex/logger/__init__.py +0 -1
  739. codex/logger/formatter.py +0 -36
  740. codex/logger/logger.py +0 -46
  741. codex/logger/loggerd.py +0 -102
  742. codex/logger/mp_queue.py +0 -5
  743. codex/logger_base.py +0 -12
  744. codex/memory.py +0 -56
  745. codex/permissions.py +0 -19
  746. codex/registration.py +0 -16
  747. codex/serializers/README.md +0 -4
  748. codex/settings/README.md +0 -4
  749. codex/settings/settings.py +0 -389
  750. codex/startup.py +0 -182
  751. codex/static_root/assets/VCheckbox-BP93zyXK.a1358c39a5fc.js +0 -1
  752. codex/static_root/assets/VCheckbox-BP93zyXK.a1358c39a5fc.js.br +0 -0
  753. codex/static_root/assets/VCheckbox-BP93zyXK.a1358c39a5fc.js.gz +0 -0
  754. codex/static_root/assets/VCheckbox-BP93zyXK.js +0 -1
  755. codex/static_root/assets/VCheckbox-BP93zyXK.js.br +0 -0
  756. codex/static_root/assets/VCheckbox-BP93zyXK.js.gz +0 -0
  757. codex/static_root/assets/VCheckboxBtn-CRHYDPms.a17a831d104a.js +0 -1
  758. codex/static_root/assets/VCheckboxBtn-CRHYDPms.a17a831d104a.js.br +0 -0
  759. codex/static_root/assets/VCheckboxBtn-CRHYDPms.a17a831d104a.js.gz +0 -0
  760. codex/static_root/assets/VCheckboxBtn-CRHYDPms.js +0 -1
  761. codex/static_root/assets/VCheckboxBtn-CRHYDPms.js.br +0 -0
  762. codex/static_root/assets/VCheckboxBtn-CRHYDPms.js.gz +0 -0
  763. codex/static_root/assets/VCombobox-BMwdQ72S.106aafc35928.js +0 -1
  764. codex/static_root/assets/VCombobox-BMwdQ72S.106aafc35928.js.br +0 -0
  765. codex/static_root/assets/VCombobox-BMwdQ72S.106aafc35928.js.gz +0 -0
  766. codex/static_root/assets/VCombobox-BMwdQ72S.js +0 -1
  767. codex/static_root/assets/VCombobox-BMwdQ72S.js.br +0 -0
  768. codex/static_root/assets/VCombobox-BMwdQ72S.js.gz +0 -0
  769. codex/static_root/assets/VDialog-BScRe1ug.c1e3368e7223.js +0 -1
  770. codex/static_root/assets/VDialog-BScRe1ug.c1e3368e7223.js.br +0 -0
  771. codex/static_root/assets/VDialog-BScRe1ug.c1e3368e7223.js.gz +0 -0
  772. codex/static_root/assets/VDialog-BScRe1ug.js +0 -1
  773. codex/static_root/assets/VDialog-BScRe1ug.js.br +0 -0
  774. codex/static_root/assets/VDialog-BScRe1ug.js.gz +0 -0
  775. codex/static_root/assets/VDialog-y9QOVA5M.627a99a930c7.css +0 -1
  776. codex/static_root/assets/VDialog-y9QOVA5M.627a99a930c7.css.br +0 -0
  777. codex/static_root/assets/VDialog-y9QOVA5M.627a99a930c7.css.gz +0 -0
  778. codex/static_root/assets/VDialog-y9QOVA5M.css +0 -1
  779. codex/static_root/assets/VDialog-y9QOVA5M.css.br +0 -0
  780. codex/static_root/assets/VDialog-y9QOVA5M.css.gz +0 -0
  781. codex/static_root/assets/VDivider-tFagM0PC.3cc0ce822729.js +0 -1
  782. codex/static_root/assets/VDivider-tFagM0PC.3cc0ce822729.js.br +0 -0
  783. codex/static_root/assets/VDivider-tFagM0PC.3cc0ce822729.js.gz +0 -0
  784. codex/static_root/assets/VDivider-tFagM0PC.js +0 -1
  785. codex/static_root/assets/VDivider-tFagM0PC.js.br +0 -0
  786. codex/static_root/assets/VDivider-tFagM0PC.js.gz +0 -0
  787. codex/static_root/assets/VExpansionPanels-DGHiJ89C.b60a171f4cde.js +0 -1
  788. codex/static_root/assets/VExpansionPanels-DGHiJ89C.b60a171f4cde.js.br +0 -0
  789. codex/static_root/assets/VExpansionPanels-DGHiJ89C.b60a171f4cde.js.gz +0 -0
  790. codex/static_root/assets/VExpansionPanels-DGHiJ89C.js +0 -1
  791. codex/static_root/assets/VExpansionPanels-DGHiJ89C.js.br +0 -0
  792. codex/static_root/assets/VExpansionPanels-DGHiJ89C.js.gz +0 -0
  793. codex/static_root/assets/VForm-B__yH-Y4.63f4a1e9770b.js +0 -1
  794. codex/static_root/assets/VForm-B__yH-Y4.63f4a1e9770b.js.br +0 -0
  795. codex/static_root/assets/VForm-B__yH-Y4.63f4a1e9770b.js.gz +0 -0
  796. codex/static_root/assets/VForm-B__yH-Y4.js +0 -1
  797. codex/static_root/assets/VForm-B__yH-Y4.js.br +0 -0
  798. codex/static_root/assets/VForm-B__yH-Y4.js.gz +0 -0
  799. codex/static_root/assets/VRadioGroup-CPOGOEPv.20e361436bc6.js +0 -1
  800. codex/static_root/assets/VRadioGroup-CPOGOEPv.20e361436bc6.js.br +0 -0
  801. codex/static_root/assets/VRadioGroup-CPOGOEPv.20e361436bc6.js.gz +0 -0
  802. codex/static_root/assets/VRadioGroup-CPOGOEPv.js +0 -1
  803. codex/static_root/assets/VRadioGroup-CPOGOEPv.js.br +0 -0
  804. codex/static_root/assets/VRadioGroup-CPOGOEPv.js.gz +0 -0
  805. codex/static_root/assets/VSelect-B_F15uRm.a7297ec26f7a.js +0 -1
  806. codex/static_root/assets/VSelect-B_F15uRm.a7297ec26f7a.js.br +0 -0
  807. codex/static_root/assets/VSelect-B_F15uRm.a7297ec26f7a.js.gz +0 -0
  808. codex/static_root/assets/VSelect-B_F15uRm.js +0 -1
  809. codex/static_root/assets/VSelect-B_F15uRm.js.br +0 -0
  810. codex/static_root/assets/VSelect-B_F15uRm.js.gz +0 -0
  811. codex/static_root/assets/VSelect-CKXqRkBF.a8be1e193eba.css +0 -1
  812. codex/static_root/assets/VSelect-CKXqRkBF.a8be1e193eba.css.br +0 -0
  813. codex/static_root/assets/VSelect-CKXqRkBF.a8be1e193eba.css.gz +0 -0
  814. codex/static_root/assets/VSelect-CKXqRkBF.css +0 -1
  815. codex/static_root/assets/VSelect-CKXqRkBF.css.br +0 -0
  816. codex/static_root/assets/VSelect-CKXqRkBF.css.gz +0 -0
  817. codex/static_root/assets/VSelectionControl-CjjwyQ-Y.db7787ff7c1d.js +0 -1
  818. codex/static_root/assets/VSelectionControl-CjjwyQ-Y.db7787ff7c1d.js.br +0 -0
  819. codex/static_root/assets/VSelectionControl-CjjwyQ-Y.db7787ff7c1d.js.gz +0 -0
  820. codex/static_root/assets/VSelectionControl-CjjwyQ-Y.js +0 -1
  821. codex/static_root/assets/VSelectionControl-CjjwyQ-Y.js.br +0 -0
  822. codex/static_root/assets/VSelectionControl-CjjwyQ-Y.js.gz +0 -0
  823. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css +0 -1
  824. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.br +0 -0
  825. codex/static_root/assets/VTable-CHRVGI94.0a75643f6486.css.gz +0 -0
  826. codex/static_root/assets/VTable-CHRVGI94.css +0 -1
  827. codex/static_root/assets/VTable-CHRVGI94.css.br +0 -0
  828. codex/static_root/assets/VTable-CHRVGI94.css.gz +0 -0
  829. codex/static_root/assets/VTable-DuRw3_Nt.d9e0088b79d2.js +0 -1
  830. codex/static_root/assets/VTable-DuRw3_Nt.d9e0088b79d2.js.br +0 -0
  831. codex/static_root/assets/VTable-DuRw3_Nt.d9e0088b79d2.js.gz +0 -0
  832. codex/static_root/assets/VTable-DuRw3_Nt.js +0 -1
  833. codex/static_root/assets/VTable-DuRw3_Nt.js.br +0 -0
  834. codex/static_root/assets/VTable-DuRw3_Nt.js.gz +0 -0
  835. codex/static_root/assets/VWindowItem-CBh8U6qD.49437fb41631.js +0 -1
  836. codex/static_root/assets/VWindowItem-CBh8U6qD.49437fb41631.js.br +0 -0
  837. codex/static_root/assets/VWindowItem-CBh8U6qD.49437fb41631.js.gz +0 -0
  838. codex/static_root/assets/VWindowItem-CBh8U6qD.js +0 -1
  839. codex/static_root/assets/VWindowItem-CBh8U6qD.js.br +0 -0
  840. codex/static_root/assets/VWindowItem-CBh8U6qD.js.gz +0 -0
  841. codex/static_root/assets/VWindowItem-CWBhiE_Y.css +0 -1
  842. codex/static_root/assets/VWindowItem-CWBhiE_Y.css.br +0 -0
  843. codex/static_root/assets/VWindowItem-CWBhiE_Y.css.gz +0 -0
  844. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css +0 -1
  845. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.br +0 -0
  846. codex/static_root/assets/VWindowItem-CWBhiE_Y.f7fb19752bf3.css.gz +0 -0
  847. codex/static_root/assets/admin-BiuZANLl.249b6c087031.js +0 -1
  848. codex/static_root/assets/admin-BiuZANLl.249b6c087031.js.br +0 -0
  849. codex/static_root/assets/admin-BiuZANLl.249b6c087031.js.gz +0 -0
  850. codex/static_root/assets/admin-BiuZANLl.js +0 -1
  851. codex/static_root/assets/admin-BiuZANLl.js.br +0 -0
  852. codex/static_root/assets/admin-BiuZANLl.js.gz +0 -0
  853. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css +0 -1
  854. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.br +0 -0
  855. codex/static_root/assets/admin-klMr_GZK.3784e4f1d624.css.gz +0 -0
  856. codex/static_root/assets/admin-klMr_GZK.css +0 -1
  857. codex/static_root/assets/admin-klMr_GZK.css.br +0 -0
  858. codex/static_root/assets/admin-klMr_GZK.css.gz +0 -0
  859. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css +0 -1
  860. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.br +0 -0
  861. codex/static_root/assets/admin-menu-CKlcsy9S.41b2cf82b873.css.gz +0 -0
  862. codex/static_root/assets/admin-menu-CKlcsy9S.css +0 -1
  863. codex/static_root/assets/admin-menu-CKlcsy9S.css.br +0 -0
  864. codex/static_root/assets/admin-menu-CKlcsy9S.css.gz +0 -0
  865. codex/static_root/assets/admin-menu-DqBUjKk4.96d3ee51d1ee.js +0 -1
  866. codex/static_root/assets/admin-menu-DqBUjKk4.96d3ee51d1ee.js.br +0 -0
  867. codex/static_root/assets/admin-menu-DqBUjKk4.96d3ee51d1ee.js.gz +0 -0
  868. codex/static_root/assets/admin-menu-DqBUjKk4.js +0 -1
  869. codex/static_root/assets/admin-menu-DqBUjKk4.js.br +0 -0
  870. codex/static_root/assets/admin-menu-DqBUjKk4.js.gz +0 -0
  871. codex/static_root/assets/admin-rFfBszpt.fe7fc34dcff9.js +0 -1
  872. codex/static_root/assets/admin-rFfBszpt.fe7fc34dcff9.js.br +0 -0
  873. codex/static_root/assets/admin-rFfBszpt.fe7fc34dcff9.js.gz +0 -0
  874. codex/static_root/assets/admin-rFfBszpt.js +0 -1
  875. codex/static_root/assets/admin-rFfBszpt.js.br +0 -0
  876. codex/static_root/assets/admin-rFfBszpt.js.gz +0 -0
  877. codex/static_root/assets/admin-settings-button-progress-OU_loI8p.87ac446b1a6a.js +0 -1
  878. codex/static_root/assets/admin-settings-button-progress-OU_loI8p.87ac446b1a6a.js.br +0 -0
  879. codex/static_root/assets/admin-settings-button-progress-OU_loI8p.87ac446b1a6a.js.gz +0 -0
  880. codex/static_root/assets/admin-settings-button-progress-OU_loI8p.js +0 -1
  881. codex/static_root/assets/admin-settings-button-progress-OU_loI8p.js.br +0 -0
  882. codex/static_root/assets/admin-settings-button-progress-OU_loI8p.js.gz +0 -0
  883. codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.435dc945daf1.css +0 -1
  884. codex/static_root/assets/admin-settings-button-progress-XVi7SeHr.css +0 -1
  885. codex/static_root/assets/browser-D0QppR66.501322534a7c.js +0 -1
  886. codex/static_root/assets/browser-D0QppR66.501322534a7c.js.br +0 -0
  887. codex/static_root/assets/browser-D0QppR66.501322534a7c.js.gz +0 -0
  888. codex/static_root/assets/browser-D0QppR66.js +0 -1
  889. codex/static_root/assets/browser-D0QppR66.js.br +0 -0
  890. codex/static_root/assets/browser-D0QppR66.js.gz +0 -0
  891. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css +0 -1
  892. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.br +0 -0
  893. codex/static_root/assets/browser-sNm790x9.305a6a4f38fd.css.gz +0 -0
  894. codex/static_root/assets/browser-sNm790x9.css +0 -1
  895. codex/static_root/assets/browser-sNm790x9.css.br +0 -0
  896. codex/static_root/assets/browser-sNm790x9.css.gz +0 -0
  897. codex/static_root/assets/change-password-dialog-DQ_0TaFN.5faa73705235.js +0 -1
  898. codex/static_root/assets/change-password-dialog-DQ_0TaFN.5faa73705235.js.br +0 -0
  899. codex/static_root/assets/change-password-dialog-DQ_0TaFN.5faa73705235.js.gz +0 -0
  900. codex/static_root/assets/change-password-dialog-DQ_0TaFN.js +0 -1
  901. codex/static_root/assets/change-password-dialog-DQ_0TaFN.js.br +0 -0
  902. codex/static_root/assets/change-password-dialog-DQ_0TaFN.js.gz +0 -0
  903. codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css +0 -1
  904. codex/static_root/assets/confirm-dialog-BI5kQLy_.1b5309ad95ec.css.br +0 -0
  905. codex/static_root/assets/confirm-dialog-BI5kQLy_.css +0 -1
  906. codex/static_root/assets/confirm-dialog-BI5kQLy_.css.br +0 -0
  907. codex/static_root/assets/confirm-dialog-Bkr6kSge.f41952e0b099.js +0 -1
  908. codex/static_root/assets/confirm-dialog-Bkr6kSge.f41952e0b099.js.br +0 -0
  909. codex/static_root/assets/confirm-dialog-Bkr6kSge.f41952e0b099.js.gz +0 -0
  910. codex/static_root/assets/confirm-dialog-Bkr6kSge.js +0 -1
  911. codex/static_root/assets/confirm-dialog-Bkr6kSge.js.br +0 -0
  912. codex/static_root/assets/confirm-dialog-Bkr6kSge.js.gz +0 -0
  913. codex/static_root/assets/datetime-column-BavtvLnf.1f3bf499e063.css +0 -1
  914. codex/static_root/assets/datetime-column-BavtvLnf.css +0 -1
  915. codex/static_root/assets/datetime-column-DN4pF5Fz.eef663675e36.js +0 -1
  916. codex/static_root/assets/datetime-column-DN4pF5Fz.eef663675e36.js.br +0 -2
  917. codex/static_root/assets/datetime-column-DN4pF5Fz.eef663675e36.js.gz +0 -0
  918. codex/static_root/assets/datetime-column-DN4pF5Fz.js +0 -1
  919. codex/static_root/assets/datetime-column-DN4pF5Fz.js.br +0 -2
  920. codex/static_root/assets/datetime-column-DN4pF5Fz.js.gz +0 -0
  921. codex/static_root/assets/filter-C84dddvE.1f40ef69fc98.js +0 -1
  922. codex/static_root/assets/filter-C84dddvE.1f40ef69fc98.js.br +0 -0
  923. codex/static_root/assets/filter-C84dddvE.1f40ef69fc98.js.gz +0 -0
  924. codex/static_root/assets/filter-C84dddvE.js +0 -1
  925. codex/static_root/assets/filter-C84dddvE.js.br +0 -0
  926. codex/static_root/assets/filter-C84dddvE.js.gz +0 -0
  927. codex/static_root/assets/flag-tab-kXJbxWWt.afd96e3b065a.js +0 -1
  928. codex/static_root/assets/flag-tab-kXJbxWWt.afd96e3b065a.js.br +0 -0
  929. codex/static_root/assets/flag-tab-kXJbxWWt.afd96e3b065a.js.gz +0 -0
  930. codex/static_root/assets/flag-tab-kXJbxWWt.js +0 -1
  931. codex/static_root/assets/flag-tab-kXJbxWWt.js.br +0 -0
  932. codex/static_root/assets/flag-tab-kXJbxWWt.js.gz +0 -0
  933. codex/static_root/assets/forwardRefs-Dbjzugu8.a95409be3194.css +0 -1
  934. codex/static_root/assets/forwardRefs-Dbjzugu8.a95409be3194.css.br +0 -0
  935. codex/static_root/assets/forwardRefs-Dbjzugu8.a95409be3194.css.gz +0 -0
  936. codex/static_root/assets/forwardRefs-Dbjzugu8.css +0 -1
  937. codex/static_root/assets/forwardRefs-Dbjzugu8.css.br +0 -0
  938. codex/static_root/assets/forwardRefs-Dbjzugu8.css.gz +0 -0
  939. codex/static_root/assets/forwardRefs-DkWUbz_i.6267360fb97d.js +0 -1
  940. codex/static_root/assets/forwardRefs-DkWUbz_i.6267360fb97d.js.br +0 -0
  941. codex/static_root/assets/forwardRefs-DkWUbz_i.6267360fb97d.js.gz +0 -0
  942. codex/static_root/assets/forwardRefs-DkWUbz_i.js +0 -1
  943. codex/static_root/assets/forwardRefs-DkWUbz_i.js.br +0 -0
  944. codex/static_root/assets/forwardRefs-DkWUbz_i.js.gz +0 -0
  945. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css +0 -1
  946. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.br +0 -0
  947. codex/static_root/assets/group-tab-Bi681uR0.3246ac0f7cec.css.gz +0 -0
  948. codex/static_root/assets/group-tab-Bi681uR0.css +0 -1
  949. codex/static_root/assets/group-tab-Bi681uR0.css.br +0 -0
  950. codex/static_root/assets/group-tab-Bi681uR0.css.gz +0 -0
  951. codex/static_root/assets/group-tab-jH91_dZ-.4e96931a3f26.js +0 -1
  952. codex/static_root/assets/group-tab-jH91_dZ-.4e96931a3f26.js.br +0 -0
  953. codex/static_root/assets/group-tab-jH91_dZ-.4e96931a3f26.js.gz +0 -0
  954. codex/static_root/assets/group-tab-jH91_dZ-.js +0 -1
  955. codex/static_root/assets/group-tab-jH91_dZ-.js.br +0 -0
  956. codex/static_root/assets/group-tab-jH91_dZ-.js.gz +0 -0
  957. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css +0 -1
  958. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.br +0 -0
  959. codex/static_root/assets/http-error-CODU7jcH.8c13689ae574.css.gz +0 -0
  960. codex/static_root/assets/http-error-CODU7jcH.css +0 -1
  961. codex/static_root/assets/http-error-CODU7jcH.css.br +0 -0
  962. codex/static_root/assets/http-error-CODU7jcH.css.gz +0 -0
  963. codex/static_root/assets/http-error-CrojtCix.9d0501bde853.js +0 -1
  964. codex/static_root/assets/http-error-CrojtCix.9d0501bde853.js.br +0 -0
  965. codex/static_root/assets/http-error-CrojtCix.9d0501bde853.js.gz +0 -0
  966. codex/static_root/assets/http-error-CrojtCix.js +0 -1
  967. codex/static_root/assets/http-error-CrojtCix.js.br +0 -0
  968. codex/static_root/assets/http-error-CrojtCix.js.gz +0 -0
  969. codex/static_root/assets/index-DHunaD9D.c820322b9e49.js +0 -1
  970. codex/static_root/assets/index-DHunaD9D.c820322b9e49.js.br +0 -0
  971. codex/static_root/assets/index-DHunaD9D.c820322b9e49.js.gz +0 -0
  972. codex/static_root/assets/index-DHunaD9D.js +0 -1
  973. codex/static_root/assets/index-DHunaD9D.js.br +0 -0
  974. codex/static_root/assets/index-DHunaD9D.js.gz +0 -0
  975. codex/static_root/assets/library-tab-BzOyajRi.6c8c04906eec.js +0 -1
  976. codex/static_root/assets/library-tab-BzOyajRi.6c8c04906eec.js.br +0 -0
  977. codex/static_root/assets/library-tab-BzOyajRi.6c8c04906eec.js.gz +0 -0
  978. codex/static_root/assets/library-tab-BzOyajRi.js +0 -1
  979. codex/static_root/assets/library-tab-BzOyajRi.js.br +0 -0
  980. codex/static_root/assets/library-tab-BzOyajRi.js.gz +0 -0
  981. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css +0 -1
  982. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.br +0 -0
  983. codex/static_root/assets/library-tab-DLpvMqPW.2989f610950b.css.gz +0 -0
  984. codex/static_root/assets/library-tab-DLpvMqPW.css +0 -1
  985. codex/static_root/assets/library-tab-DLpvMqPW.css.br +0 -0
  986. codex/static_root/assets/library-tab-DLpvMqPW.css.gz +0 -0
  987. codex/static_root/assets/main-Dl2Lrwga.e767cd79bb5e.js +0 -39
  988. codex/static_root/assets/main-Dl2Lrwga.e767cd79bb5e.js.br +0 -0
  989. codex/static_root/assets/main-Dl2Lrwga.e767cd79bb5e.js.gz +0 -0
  990. codex/static_root/assets/main-Dl2Lrwga.js +0 -39
  991. codex/static_root/assets/main-Dl2Lrwga.js.br +0 -0
  992. codex/static_root/assets/main-Dl2Lrwga.js.gz +0 -0
  993. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css +0 -5
  994. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.br +0 -0
  995. codex/static_root/assets/main-Of3aYkZ7.91c75c4fbaa6.css.gz +0 -0
  996. codex/static_root/assets/main-Of3aYkZ7.css +0 -5
  997. codex/static_root/assets/main-Of3aYkZ7.css.br +0 -0
  998. codex/static_root/assets/main-Of3aYkZ7.css.gz +0 -0
  999. codex/static_root/assets/pager-full-pdf-DKdyHoRL.a504cc00db7c.js +0 -1
  1000. codex/static_root/assets/pager-full-pdf-DKdyHoRL.a504cc00db7c.js.br +0 -0
  1001. codex/static_root/assets/pager-full-pdf-DKdyHoRL.a504cc00db7c.js.gz +0 -0
  1002. codex/static_root/assets/pager-full-pdf-DKdyHoRL.js +0 -1
  1003. codex/static_root/assets/pager-full-pdf-DKdyHoRL.js.br +0 -0
  1004. codex/static_root/assets/pager-full-pdf-DKdyHoRL.js.gz +0 -0
  1005. codex/static_root/assets/pagination-toolbar-T0N6Ubp7.1f07380772ae.js +0 -1
  1006. codex/static_root/assets/pagination-toolbar-T0N6Ubp7.1f07380772ae.js.br +0 -0
  1007. codex/static_root/assets/pagination-toolbar-T0N6Ubp7.1f07380772ae.js.gz +0 -0
  1008. codex/static_root/assets/pagination-toolbar-T0N6Ubp7.js +0 -1
  1009. codex/static_root/assets/pagination-toolbar-T0N6Ubp7.js.br +0 -0
  1010. codex/static_root/assets/pagination-toolbar-T0N6Ubp7.js.gz +0 -0
  1011. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css +0 -1
  1012. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.br +0 -0
  1013. codex/static_root/assets/pagination-toolbar-aHRrdz48.2cbd38f9256c.css.gz +0 -0
  1014. codex/static_root/assets/pagination-toolbar-aHRrdz48.css +0 -1
  1015. codex/static_root/assets/pagination-toolbar-aHRrdz48.css.br +0 -0
  1016. codex/static_root/assets/pagination-toolbar-aHRrdz48.css.gz +0 -0
  1017. codex/static_root/assets/pdf-doc-CBiUfHpD.9e3e989242e7.js +0 -372
  1018. codex/static_root/assets/pdf-doc-CBiUfHpD.9e3e989242e7.js.br +0 -0
  1019. codex/static_root/assets/pdf-doc-CBiUfHpD.9e3e989242e7.js.gz +0 -0
  1020. codex/static_root/assets/pdf-doc-CBiUfHpD.js +0 -372
  1021. codex/static_root/assets/pdf-doc-CBiUfHpD.js.br +0 -0
  1022. codex/static_root/assets/pdf-doc-CBiUfHpD.js.gz +0 -0
  1023. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css +0 -1
  1024. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.br +0 -0
  1025. codex/static_root/assets/reader-BwgJtbgj.c8b86f482c17.css.gz +0 -0
  1026. codex/static_root/assets/reader-BwgJtbgj.css +0 -1
  1027. codex/static_root/assets/reader-BwgJtbgj.css.br +0 -0
  1028. codex/static_root/assets/reader-BwgJtbgj.css.gz +0 -0
  1029. codex/static_root/assets/reader-D3uSXJi4.6bf741d0ed65.js +0 -2
  1030. codex/static_root/assets/reader-D3uSXJi4.6bf741d0ed65.js.br +0 -0
  1031. codex/static_root/assets/reader-D3uSXJi4.6bf741d0ed65.js.gz +0 -0
  1032. codex/static_root/assets/reader-D3uSXJi4.js +0 -2
  1033. codex/static_root/assets/reader-D3uSXJi4.js.br +0 -0
  1034. codex/static_root/assets/reader-D3uSXJi4.js.gz +0 -0
  1035. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css +0 -1
  1036. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.br +0 -0
  1037. codex/static_root/assets/relation-chips-BuShhy1e.822bb69b0cfe.css.gz +0 -0
  1038. codex/static_root/assets/relation-chips-BuShhy1e.css +0 -1
  1039. codex/static_root/assets/relation-chips-BuShhy1e.css.br +0 -0
  1040. codex/static_root/assets/relation-chips-BuShhy1e.css.gz +0 -0
  1041. codex/static_root/assets/relation-chips-DWjWPY3v.d76db684e8a8.js +0 -1
  1042. codex/static_root/assets/relation-chips-DWjWPY3v.d76db684e8a8.js.br +0 -0
  1043. codex/static_root/assets/relation-chips-DWjWPY3v.d76db684e8a8.js.gz +0 -0
  1044. codex/static_root/assets/relation-chips-DWjWPY3v.js +0 -1
  1045. codex/static_root/assets/relation-chips-DWjWPY3v.js.br +0 -0
  1046. codex/static_root/assets/relation-chips-DWjWPY3v.js.gz +0 -0
  1047. codex/static_root/assets/settings-drawer-Bu83HJ70.a7672fb29169.js +0 -2
  1048. codex/static_root/assets/settings-drawer-Bu83HJ70.a7672fb29169.js.br +0 -0
  1049. codex/static_root/assets/settings-drawer-Bu83HJ70.a7672fb29169.js.gz +0 -0
  1050. codex/static_root/assets/settings-drawer-Bu83HJ70.js +0 -2
  1051. codex/static_root/assets/settings-drawer-Bu83HJ70.js.br +0 -0
  1052. codex/static_root/assets/settings-drawer-Bu83HJ70.js.gz +0 -0
  1053. codex/static_root/assets/settings-drawer-WyG6HLH-.css +0 -1
  1054. codex/static_root/assets/settings-drawer-WyG6HLH-.css.br +0 -0
  1055. codex/static_root/assets/settings-drawer-WyG6HLH-.css.gz +0 -0
  1056. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css +0 -1
  1057. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.br +0 -0
  1058. codex/static_root/assets/settings-drawer-WyG6HLH-.fe251f6d0a75.css.gz +0 -0
  1059. codex/static_root/assets/ssrBoot-CYaxTeZo.308983ed6c53.js +0 -1
  1060. codex/static_root/assets/ssrBoot-CYaxTeZo.308983ed6c53.js.br +0 -0
  1061. codex/static_root/assets/ssrBoot-CYaxTeZo.308983ed6c53.js.gz +0 -0
  1062. codex/static_root/assets/ssrBoot-CYaxTeZo.js +0 -1
  1063. codex/static_root/assets/ssrBoot-CYaxTeZo.js.br +0 -0
  1064. codex/static_root/assets/ssrBoot-CYaxTeZo.js.gz +0 -0
  1065. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css +0 -1
  1066. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.br +0 -0
  1067. codex/static_root/assets/stats-tab-CGY8r-es.b06c55bdaeaa.css.gz +0 -0
  1068. codex/static_root/assets/stats-tab-CGY8r-es.css +0 -1
  1069. codex/static_root/assets/stats-tab-CGY8r-es.css.br +0 -0
  1070. codex/static_root/assets/stats-tab-CGY8r-es.css.gz +0 -0
  1071. codex/static_root/assets/stats-tab-aWxmJFqf.ef7a1a878842.js +0 -1
  1072. codex/static_root/assets/stats-tab-aWxmJFqf.ef7a1a878842.js.br +0 -0
  1073. codex/static_root/assets/stats-tab-aWxmJFqf.ef7a1a878842.js.gz +0 -0
  1074. codex/static_root/assets/stats-tab-aWxmJFqf.js +0 -1
  1075. codex/static_root/assets/stats-tab-aWxmJFqf.js.br +0 -0
  1076. codex/static_root/assets/stats-tab-aWxmJFqf.js.gz +0 -0
  1077. codex/static_root/assets/task-tab-fAvDZsSF.607dda8657e0.js +0 -1
  1078. codex/static_root/assets/task-tab-fAvDZsSF.607dda8657e0.js.br +0 -0
  1079. codex/static_root/assets/task-tab-fAvDZsSF.607dda8657e0.js.gz +0 -0
  1080. codex/static_root/assets/task-tab-fAvDZsSF.js +0 -1
  1081. codex/static_root/assets/task-tab-fAvDZsSF.js.br +0 -0
  1082. codex/static_root/assets/task-tab-fAvDZsSF.js.gz +0 -0
  1083. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css +0 -1
  1084. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.br +0 -0
  1085. codex/static_root/assets/unauthorized-DE63n2Pi.b0357009b13d.css.gz +0 -0
  1086. codex/static_root/assets/unauthorized-DE63n2Pi.css +0 -1
  1087. codex/static_root/assets/unauthorized-DE63n2Pi.css.br +0 -0
  1088. codex/static_root/assets/unauthorized-DE63n2Pi.css.gz +0 -0
  1089. codex/static_root/assets/unauthorized-T8UCTUHd.16d825eec49d.js +0 -1
  1090. codex/static_root/assets/unauthorized-T8UCTUHd.16d825eec49d.js.br +0 -0
  1091. codex/static_root/assets/unauthorized-T8UCTUHd.16d825eec49d.js.gz +0 -0
  1092. codex/static_root/assets/unauthorized-T8UCTUHd.js +0 -1
  1093. codex/static_root/assets/unauthorized-T8UCTUHd.js.br +0 -0
  1094. codex/static_root/assets/unauthorized-T8UCTUHd.js.gz +0 -0
  1095. codex/static_root/assets/user-tab-CI1MB3ic.ed8693e40a0b.js +0 -1
  1096. codex/static_root/assets/user-tab-CI1MB3ic.ed8693e40a0b.js.br +0 -0
  1097. codex/static_root/assets/user-tab-CI1MB3ic.ed8693e40a0b.js.gz +0 -0
  1098. codex/static_root/assets/user-tab-CI1MB3ic.js +0 -1
  1099. codex/static_root/assets/user-tab-CI1MB3ic.js.br +0 -0
  1100. codex/static_root/assets/user-tab-CI1MB3ic.js.gz +0 -0
  1101. codex/static_root/img/folder.f28936a3701d.svg +0 -1
  1102. codex/static_root/img/folder.f28936a3701d.svg.br +0 -0
  1103. codex/static_root/img/folder.f28936a3701d.svg.gz +0 -0
  1104. codex/static_root/img/imprint.7c2adebb76d6.svg +0 -1
  1105. codex/static_root/img/imprint.7c2adebb76d6.svg.br +0 -0
  1106. codex/static_root/img/imprint.7c2adebb76d6.svg.gz +0 -0
  1107. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg +0 -1
  1108. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.br +0 -0
  1109. codex/static_root/img/logo-maskable.8f7de7f1c6a8.svg.gz +0 -0
  1110. codex/static_root/img/logo.0f5344a028ca.svg +0 -1
  1111. codex/static_root/img/logo.0f5344a028ca.svg.br +0 -0
  1112. codex/static_root/img/logo.0f5344a028ca.svg.gz +0 -0
  1113. codex/static_root/img/missing-cover-165.0743171f2148.webp +0 -0
  1114. codex/static_root/img/missing-cover.ddb038cc2c56.svg +0 -1
  1115. codex/static_root/img/missing-cover.ddb038cc2c56.svg.br +0 -0
  1116. codex/static_root/img/missing-cover.ddb038cc2c56.svg.gz +0 -0
  1117. codex/static_root/img/series.ec8a889b8f95.svg +0 -1
  1118. codex/static_root/img/series.ec8a889b8f95.svg.br +0 -0
  1119. codex/static_root/img/series.ec8a889b8f95.svg.gz +0 -0
  1120. codex/static_root/img/story-arc.ca10014355ef.svg +0 -1
  1121. codex/static_root/img/story-arc.ca10014355ef.svg.br +0 -1
  1122. codex/static_root/img/story-arc.ca10014355ef.svg.gz +0 -0
  1123. codex/static_root/img/volume.814e4c79461a.svg +0 -1
  1124. codex/static_root/img/volume.814e4c79461a.svg.br +0 -0
  1125. codex/static_root/img/volume.814e4c79461a.svg.gz +0 -0
  1126. codex/static_root/manifest.b23c14b76074.json +0 -757
  1127. codex/static_root/manifest.b23c14b76074.json.br +0 -0
  1128. codex/static_root/manifest.b23c14b76074.json.gz +0 -0
  1129. codex/status.py +0 -35
  1130. codex/status_controller.py +0 -153
  1131. codex/templates/README.md +0 -3
  1132. codex/threads.py +0 -130
  1133. codex/views/README.md +0 -4
  1134. codex/views/browser/filters/search/aliases.py +0 -81
  1135. codex/views/browser/metadata/metadata.py +0 -83
  1136. codex/websockets/README.md +0 -4
  1137. codex/worker_base.py +0 -14
  1138. codex-1.7.14.dist-info/METADATA +0 -599
  1139. codex-1.7.14.dist-info/RECORD +0 -1052
  1140. codex-1.7.14.dist-info/WHEEL +0 -4
  1141. codex-1.7.14.dist-info/entry_points.txt +0 -3
  1142. {codex-1.7.14.dist-info → codex-1.8.0.dist-info/licenses}/LICENSE +0 -0
@@ -1,21 +1,24 @@
1
1
  """OPDS v1 feed."""
2
2
 
3
+ from collections.abc import Sequence
3
4
  from typing import TYPE_CHECKING, Any
4
5
 
5
6
  from drf_spectacular.utils import extend_schema
7
+ from loguru import logger
6
8
  from rest_framework.response import Response
7
- from rest_framework.throttling import ScopedRateThrottle
9
+ from rest_framework.serializers import BaseSerializer
10
+ from rest_framework.throttling import BaseThrottle, ScopedRateThrottle
11
+ from typing_extensions import override
8
12
 
9
- from codex.librarian.importer.tasks import LazyImportComicsTask
10
13
  from codex.librarian.mp_queue import LIBRARIAN_QUEUE
11
- from codex.logger.logger import get_logger
14
+ from codex.librarian.scribe.tasks import LazyImportComicsTask
12
15
  from codex.serializers.browser.settings import OPDSSettingsSerializer
13
16
  from codex.serializers.opds.v1 import (
14
17
  OPDS1TemplateSerializer,
15
18
  )
16
- from codex.settings.settings import FALSY, MAX_OBJ_PER_PAGE
17
- from codex.views.mixins import UserActiveViewMixin
18
- from codex.views.opds.auth import OPDSTemplateView
19
+ from codex.settings import FALSY, MAX_OBJ_PER_PAGE
20
+ from codex.views.mixins import UserActiveMixin
21
+ from codex.views.opds.auth import OPDSTemplateMixin
19
22
  from codex.views.opds.const import BLANK_TITLE
20
23
  from codex.views.opds.v1.entry.data import OPDS1EntryData
21
24
  from codex.views.opds.v1.entry.entry import OPDS1Entry
@@ -29,9 +32,6 @@ if TYPE_CHECKING:
29
32
  from collections.abc import Mapping
30
33
 
31
34
 
32
- LOG = get_logger(__name__)
33
-
34
-
35
35
  class OpdsNs:
36
36
  """XML Namespaces."""
37
37
 
@@ -39,15 +39,15 @@ class OpdsNs:
39
39
  ACQUISITION = "http://opds-spec.org/2010/acquisition"
40
40
 
41
41
 
42
- class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
42
+ class OPDS1FeedView(OPDSTemplateMixin, UserActiveMixin, OPDS1LinksView):
43
43
  """OPDS 1 Feed."""
44
44
 
45
45
  template_name = "opds_v1/index.xml"
46
- serializer_class = OPDS1TemplateSerializer
47
- input_serializer_class = OPDSSettingsSerializer
48
- throttle_classes = (ScopedRateThrottle,)
46
+ serializer_class: type[BaseSerializer] | None = OPDS1TemplateSerializer
47
+ input_serializer_class: type[OPDSSettingsSerializer] = OPDSSettingsSerializer # pyright: ignore[reportIncompatibleVariableOverride]
48
+ throttle_classes: Sequence[type[BaseThrottle]] = (ScopedRateThrottle,)
49
49
  throttle_scope = "opds"
50
- TARGET = "opds1"
50
+ TARGET: str = "opds1"
51
51
 
52
52
  @property
53
53
  def opds_ns(self):
@@ -55,7 +55,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
55
55
  try:
56
56
  return OpdsNs.ACQUISITION if self.is_opds_acquisition else OpdsNs.CATALOG
57
57
  except Exception:
58
- LOG.exception("Getting OPDS v1 namespace")
58
+ logger.exception("Getting OPDS v1 namespace")
59
59
 
60
60
  @property
61
61
  def is_acquisition(self):
@@ -68,7 +68,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
68
68
  try:
69
69
  return self.request.build_absolute_uri()
70
70
  except Exception:
71
- LOG.exception("Getting OPDS v1 ID Tag")
71
+ logger.exception("Getting OPDS v1 ID Tag")
72
72
 
73
73
  @property
74
74
  def title(self):
@@ -87,7 +87,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
87
87
  if not result:
88
88
  result = BLANK_TITLE
89
89
  except Exception:
90
- LOG.exception("Getting OPDS v1 feed title")
90
+ logger.exception("Getting OPDS v1 feed title")
91
91
  return result
92
92
 
93
93
  @property
@@ -99,7 +99,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
99
99
  if mtime:
100
100
  datestr = mtime.isoformat()
101
101
  except Exception:
102
- LOG.exception("Getting OPDS v1 updated")
102
+ logger.exception("Getting OPDS v1 updated")
103
103
  return datestr
104
104
 
105
105
  @property
@@ -109,7 +109,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
109
109
  if self.params.get("q"):
110
110
  return MAX_OBJ_PER_PAGE
111
111
  except Exception:
112
- LOG.exception("Getting OPDS v1 items per page")
112
+ logger.exception("Getting OPDS v1 items per page")
113
113
 
114
114
  @property
115
115
  def total_results(self):
@@ -118,7 +118,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
118
118
  if self.params.get("q"):
119
119
  return self.obj.get("total_count", 0)
120
120
  except Exception:
121
- LOG.exception("Getting OPDS v1 total results")
121
+ logger.exception("Getting OPDS v1 total results")
122
122
 
123
123
  def _get_entries_section(self, key, metadata):
124
124
  """Get entries by key section."""
@@ -141,7 +141,7 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
141
141
  import_pks.add(obj.pk)
142
142
  entries.append(entry)
143
143
  if import_pks:
144
- task = LazyImportComicsTask(frozenset(import_pks))
144
+ task = LazyImportComicsTask(group="c", pks=frozenset(import_pks))
145
145
  LIBRARIAN_QUEUE.put(task)
146
146
  return entries
147
147
 
@@ -161,9 +161,10 @@ class OPDS1FeedView(OPDS1LinksView, OPDSTemplateView, UserActiveViewMixin):
161
161
  metadata = self.request.GET.get("opdsMetadata", "").lower() not in FALSY
162
162
  entries += self._get_entries_section("books", metadata)
163
163
  except Exception:
164
- LOG.exception("Getting OPDS v1 entries")
164
+ logger.exception("Getting OPDS v1 entries")
165
165
  return entries
166
166
 
167
+ @override
167
168
  @extend_schema(parameters=[input_serializer_class])
168
169
  def get(self, *_args, **_kwargs):
169
170
  """Get the feed."""
@@ -7,18 +7,15 @@ from types import MappingProxyType
7
7
 
8
8
  import simplejson as json
9
9
  from django.urls import reverse
10
+ from loguru import logger
10
11
 
11
- from codex.logger.logger import get_logger
12
12
  from codex.views.opds.const import MimeType, Rel
13
- from codex.views.opds.util import update_href_query_params
14
13
  from codex.views.opds.v1.data import OPDS1Link
15
14
  from codex.views.opds.v1.entry.data import OPDS1EntryData, OPDS1EntryObject
16
15
  from codex.views.opds.v1.entry.entry import OPDS1Entry
17
16
  from codex.views.opds.v1.facets import OPDS1FacetsView
18
17
  from codex.views.util import pop_name
19
18
 
20
- LOG = get_logger(__name__)
21
-
22
19
 
23
20
  class TopRoutes:
24
21
  """Routes for top groups."""
@@ -130,8 +127,7 @@ class OPDS1LinksView(OPDS1FacetsView):
130
127
  if query_params is None:
131
128
  query_params = self.request.GET
132
129
  kwargs = pop_name(kwargs)
133
- href = reverse("opds:v1:feed", kwargs=kwargs)
134
- href = update_href_query_params(href, query_params)
130
+ href = reverse("opds:v1:feed", kwargs=kwargs, query=query_params)
135
131
  return OPDS1Link(rel, href, mime_type)
136
132
 
137
133
  def _top_link(self, top_link):
@@ -182,7 +178,7 @@ class OPDS1LinksView(OPDS1FacetsView):
182
178
  if facets := self.facets(entries=False, root=True):
183
179
  links += facets
184
180
  except Exception:
185
- LOG.exception("Getting OPDS v1 links")
181
+ logger.exception("Getting OPDS v1 links")
186
182
  return links
187
183
 
188
184
  def _top_link_entry(self, top_link):
@@ -1,17 +1,20 @@
1
1
  """Serve an opensearch v1 document."""
2
2
 
3
+ from collections.abc import Sequence
4
+
3
5
  from drf_spectacular.types import OpenApiTypes
4
6
  from drf_spectacular.utils import extend_schema
5
- from rest_framework.throttling import ScopedRateThrottle
7
+ from rest_framework.throttling import BaseThrottle, ScopedRateThrottle
6
8
 
7
- from codex.views.opds.auth import OPDSTemplateView
9
+ from codex.views.opds.auth import OPDSTemplateMixin
10
+ from codex.views.template import CodexAPIView
8
11
 
9
12
 
10
13
  @extend_schema(responses={("200", "application/xml"): OpenApiTypes.BYTE})
11
- class OpenSearch1View(OPDSTemplateView):
14
+ class OpenSearch1View(OPDSTemplateMixin, CodexAPIView):
12
15
  """OpenSearchView."""
13
16
 
14
17
  template_name = "opds_v1/opensearch_v1.xml"
15
18
  content_type = "application/xml"
16
- throttle_classes = (ScopedRateThrottle,)
19
+ throttle_classes: Sequence[type[BaseThrottle]] = (ScopedRateThrottle,)
17
20
  throttle_scope = "opensearch"
@@ -4,13 +4,15 @@ from types import MappingProxyType
4
4
 
5
5
  from drf_spectacular.utils import extend_schema
6
6
  from rest_framework.response import Response
7
+ from rest_framework.serializers import BaseSerializer
8
+ from typing_extensions import override
7
9
 
8
- from codex.logger.logger import get_logger
10
+ from codex.choices.admin import AdminFlagChoices
9
11
  from codex.models import AdminFlag
10
12
  from codex.serializers.browser.settings import OPDSSettingsSerializer
11
13
  from codex.serializers.opds.v2.feed import OPDS2FeedSerializer
12
- from codex.settings.settings import MAX_OBJ_PER_PAGE
13
- from codex.views.mixins import UserActiveViewMixin
14
+ from codex.settings import MAX_OBJ_PER_PAGE
15
+ from codex.views.mixins import UserActiveMixin
14
16
  from codex.views.opds.auth import OPDSAuthMixin
15
17
  from codex.views.opds.const import BLANK_TITLE
16
18
  from codex.views.opds.v2.const import (
@@ -25,20 +27,18 @@ from codex.views.opds.v2.href import HrefData
25
27
  from codex.views.opds.v2.links import LinkData
26
28
  from codex.views.opds.v2.publications import OPDS2PublicationView
27
29
 
28
- LOG = get_logger(__name__)
29
30
 
30
-
31
- class OPDS2FeedView(OPDSAuthMixin, OPDS2PublicationView, UserActiveViewMixin):
31
+ class OPDS2FeedView(OPDSAuthMixin, UserActiveMixin, OPDS2PublicationView):
32
32
  """OPDS 2.0 Feed."""
33
33
 
34
34
  DEFAULT_ROUTE = MappingProxyType(
35
35
  {**OPDS2PublicationView.DEFAULT_ROUTE, "name": "opds:v2:feed"}
36
36
  )
37
- TARGET = "opds2"
37
+ TARGET: str = "opds2"
38
38
  throttle_scope = "opds"
39
39
 
40
- serializer_class = OPDS2FeedSerializer
41
- input_serializer_class = OPDSSettingsSerializer
40
+ serializer_class: type[BaseSerializer] | None = OPDS2FeedSerializer
41
+ input_serializer_class: type[OPDSSettingsSerializer] = OPDSSettingsSerializer # pyright: ignore[reportIncompatibleVariableOverride]
42
42
 
43
43
  def _title(self, browser_title):
44
44
  """Create the feed title."""
@@ -71,7 +71,7 @@ class OPDS2FeedView(OPDSAuthMixin, OPDS2PublicationView, UserActiveViewMixin):
71
71
  # Folder perms
72
72
  efv_flag = (
73
73
  AdminFlag.objects.only("on")
74
- .get(key=AdminFlag.FlagChoices.FOLDER_VIEW.value)
74
+ .get(key=AdminFlagChoices.FOLDER_VIEW.value)
75
75
  .on
76
76
  )
77
77
  if not efv_flag:
@@ -164,8 +164,7 @@ class OPDS2FeedView(OPDSAuthMixin, OPDS2PublicationView, UserActiveViewMixin):
164
164
  groups += self._create_links_section(GROUPS, TOP_NAV_GROUP_SECTION_DATA)
165
165
 
166
166
  # Regular Groups
167
- group_nav_dict = {"title": title, "links": group_qs}
168
- tup = (NavigationGroup(**group_nav_dict),)
167
+ tup = (NavigationGroup(title=title, links=group_qs),)
169
168
  groups += self._create_links_section(tup, GROUPS_SECTION_DATA)
170
169
 
171
170
  # Publications
@@ -176,6 +175,7 @@ class OPDS2FeedView(OPDSAuthMixin, OPDS2PublicationView, UserActiveViewMixin):
176
175
  def _get_facets(self):
177
176
  return self._create_links_section(FACETS, FACETS_SECTION_DATA)
178
177
 
178
+ @override
179
179
  def get_object(self):
180
180
  """Get the browser page and serialize it for this subclass."""
181
181
  group_qs, book_qs, _, total_count, zero_pad, mtime = self.group_and_books
@@ -210,9 +210,8 @@ class OPDS2FeedView(OPDSAuthMixin, OPDS2PublicationView, UserActiveViewMixin):
210
210
  }
211
211
  )
212
212
 
213
- @extend_schema(
214
- parameters=[input_serializer_class],
215
- )
213
+ @override
214
+ @extend_schema(parameters=[input_serializer_class])
216
215
  def get(self, *_args, **_kwargs):
217
216
  """Get the feed."""
218
217
  obj = self.get_object()
@@ -1,14 +1,15 @@
1
1
  """Href methods for OPDS v2.0 Feed."""
2
2
 
3
- from abc import ABC
4
3
  from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from django.urls import reverse
7
- from rest_framework.views import APIView
8
7
 
9
- from codex.views.opds.util import update_href_query_params
10
8
  from codex.views.util import pop_name
11
9
 
10
+ if TYPE_CHECKING:
11
+ from rest_framework.request import Request
12
+
12
13
 
13
14
  @dataclass
14
15
  class HrefData:
@@ -22,7 +23,7 @@ class HrefData:
22
23
  max_page: int | None = None
23
24
 
24
25
 
25
- class OPDS2HrefMixin(APIView, ABC):
26
+ class OPDS2HrefMixin:
26
27
  """Create links method."""
27
28
 
28
29
  @property
@@ -37,24 +38,28 @@ class OPDS2HrefMixin(APIView, ABC):
37
38
  page = int(kwargs["page"])
38
39
  return page >= min_page and page <= max_page
39
40
 
40
- def _href_update_query_params(self, href, data):
41
+ def _href_update_query_params(self, data):
41
42
  """Update the query params."""
43
+ query = {}
42
44
  if data.absolute_query_params and data.query_params:
43
- href = update_href_query_params(href, data.query_params)
45
+ query.update(data.query_params)
44
46
  elif hasattr(self, "request"):
45
47
  # if request link and not init static links
46
- href = update_href_query_params(
47
- href, self.request.GET, new_query_params=data.query_params
48
- )
49
- return href
48
+ if TYPE_CHECKING:
49
+ self.request: Request # pyright: ignore[reportUninitializedInstanceVariable]
50
+ query.update(self.request.GET)
51
+ query.update(data.query_params)
52
+ return query
50
53
 
51
54
  def href(self, data):
52
55
  """Create an href."""
53
56
  url_name = data.url_name if data.url_name else "opds:v2:feed"
57
+ if TYPE_CHECKING:
58
+ self.kwargs: dict # pyright: ignore[reportUninitializedInstanceVariable]
54
59
  kwargs = data.kwargs if data.kwargs is not None else self.kwargs
55
60
  if "page" in kwargs and not self._href_page_validate(kwargs, data):
56
61
  return None
57
62
 
58
63
  kwargs = pop_name(kwargs)
59
- href = reverse(url_name, kwargs=kwargs)
60
- return self._href_update_query_params(href, data)
64
+ query = self._href_update_query_params(data)
65
+ return reverse(url_name, kwargs=kwargs, query=query)
@@ -7,8 +7,9 @@ from datetime import datetime
7
7
  from urllib.parse import parse_qsl, urlparse
8
8
 
9
9
  from django.db.models import QuerySet
10
+ from typing_extensions import override
10
11
 
11
- from codex.settings.settings import FALSY
12
+ from codex.settings import FALSY
12
13
  from codex.views.browser.browser import BrowserView
13
14
  from codex.views.opds.const import MimeType, Rel
14
15
  from codex.views.opds.v2.href import HrefData, OPDS2HrefMixin
@@ -52,6 +53,7 @@ class OPDS2LinksView(OPDS2HrefMixin, BrowserView):
52
53
  return self._group_and_books
53
54
 
54
55
  @property
56
+ @override
55
57
  def num_pages(self) -> int:
56
58
  """Memoize num_pages."""
57
59
  if self._num_pages is None:
@@ -2,43 +2,55 @@
2
2
  # https://github.com/opds-community/drafts/discussions/67#discussioncomment-6414507
3
3
 
4
4
  from types import MappingProxyType
5
+ from typing import TYPE_CHECKING
5
6
 
6
7
  from django.db.models.expressions import F, Value
7
8
  from django.db.models.fields import FloatField
8
9
  from django.db.models.functions.comparison import Cast, Coalesce, Greatest, Least
9
10
  from django.db.models.query_utils import FilteredRelation
11
+ from loguru import logger
10
12
  from rest_framework.exceptions import ValidationError
11
13
  from rest_framework.response import Response
14
+ from rest_framework.serializers import BaseSerializer
15
+ from typing_extensions import override
12
16
 
13
- from codex.logger.logger import get_logger
17
+ from codex.models.comic import Comic
14
18
  from codex.serializers.opds.v2.progression import OPDS2ProgressionSerializer
15
19
  from codex.util import max_none
16
20
  from codex.views.auth import AuthFilterGenericAPIView
17
- from codex.views.bookmark import BookmarkFilterMixin, BookmarkPageView
21
+ from codex.views.bookmark import BookmarkFilterMixin, BookmarkPageMixin
18
22
  from codex.views.const import GROUP_MODEL_MAP
19
23
  from codex.views.opds.v2.href import HrefData, OPDS2HrefMixin
20
24
 
25
+ if TYPE_CHECKING:
26
+ from codex.models.groups import BrowserGroupModel
27
+
21
28
  _EMPTY_DEVICE = MappingProxyType(
22
29
  {
23
30
  "id": "",
24
31
  "name": "",
25
32
  }
26
33
  )
27
- LOG = get_logger(__name__)
28
34
 
29
35
 
30
36
  # This is an independent api requiring a separate get.
31
37
  class OPDS2ProgressionView(
32
- BookmarkFilterMixin, OPDS2HrefMixin, BookmarkPageView, AuthFilterGenericAPIView
38
+ BookmarkFilterMixin, OPDS2HrefMixin, BookmarkPageMixin, AuthFilterGenericAPIView
33
39
  ):
34
40
  """OPDS 2 Progression view."""
35
41
 
36
- serializer_class = OPDS2ProgressionSerializer
42
+ serializer_class: type[BaseSerializer] | None = OPDS2ProgressionSerializer
43
+
44
+ def __init__(self, *args, **kwargs):
45
+ """Initialize Bookmark Filter."""
46
+ self.init_bookmark_filter()
47
+ super().__init__(*args, **kwargs)
48
+ self._obj: BrowserGroupModel = Comic()
37
49
 
38
50
  @property
39
51
  def modified(self):
40
52
  """Get modified from bookmark."""
41
- return self._obj.bookmark_updated_at # type: ignore[reportAttributeAccessIssue]
53
+ return self._obj.bookmark_updated_at # pyright: ignore[reportAttributeAccessIssue]
42
54
 
43
55
  @property
44
56
  def device(self):
@@ -49,16 +61,16 @@ class OPDS2ProgressionView(
49
61
  @property
50
62
  def title(self):
51
63
  """The locator title is the page number."""
52
- return f"Page {self._obj.page}" # type: ignore[reportAttributeAccessIssue]
64
+ return f"Page {self._obj.page}" # pyright: ignore[reportAttributeAccessIssue]
53
65
 
54
66
  @property
55
67
  def _progression_href(self):
56
68
  """Build a Progression HRef."""
57
69
  acq_kwargs = {
58
70
  "pk": self._obj.pk,
59
- "page": self._obj.page, # type: ignore[reportAttributeAccessIssue]
71
+ "page": self._obj.page, # pyright: ignore[reportAttributeAccessIssue]
60
72
  }
61
- max_page = max_none(self._obj.page_count - 1, 0) # type: ignore[reportAttributeAccessIssue]
73
+ max_page = max_none(self._obj.page_count - 1, 0) # pyright: ignore[reportAttributeAccessIssue]
62
74
  data = HrefData(
63
75
  acq_kwargs,
64
76
  url_name="opds:bin:page",
@@ -71,9 +83,9 @@ class OPDS2ProgressionView(
71
83
  def _locations(self):
72
84
  """Build the Locations object."""
73
85
  return {
74
- "position": self._obj.page, # type: ignore[reportAttributeAccessIssue]
75
- "progression": self._obj.progress, # type: ignore[reportAttributeAccessIssue]
76
- "total_progression": self._obj.progress, # type: ignore[reportAttributeAccessIssue]
86
+ "position": self._obj.page, # pyright: ignore[reportAttributeAccessIssue]
87
+ "progression": self._obj.progress, # pyright: ignore[reportAttributeAccessIssue]
88
+ "total_progression": self._obj.progress, # pyright: ignore[reportAttributeAccessIssue]
77
89
  }
78
90
 
79
91
  @property
@@ -86,12 +98,13 @@ class OPDS2ProgressionView(
86
98
  "locations": self._locations,
87
99
  }
88
100
 
101
+ @override
89
102
  def get_object(self):
90
103
  """Build the progression data object."""
91
104
  group = self.kwargs.get("group")
92
105
  pk = self.kwargs.get("pk")
93
106
 
94
- if not pk:
107
+ if not (group and pk):
95
108
  reason = f"Bad primary key for {group}:{pk}"
96
109
  return ValidationError(reason, code="422")
97
110
 
@@ -130,7 +143,10 @@ class OPDS2ProgressionView(
130
143
  serializer = self.get_serializer(obj)
131
144
  return Response(serializer.data)
132
145
  except Exception:
133
- LOG.exception("progression")
146
+ logger.exception("progression")
134
147
  raise
135
148
 
136
- # PUT handled by BookmarkPageView parent
149
+ def put(self, *_args, **_kwargs):
150
+ """Update the bookmark."""
151
+ self.update_bookmark()
152
+ return Response()
@@ -7,27 +7,28 @@ from urllib.parse import quote_plus
7
7
 
8
8
  from codex.librarian.covers.create import THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH
9
9
  from codex.models import Comic
10
- from codex.settings.settings import FALSY
10
+ from codex.settings import FALSY
11
11
  from codex.views.opds.const import AUTHOR_ROLES, MimeType, Rel
12
- from codex.views.opds.util import get_contributors, get_m2m_objects
12
+ from codex.views.opds.util import get_credits, get_m2m_objects
13
13
  from codex.views.opds.v2.href import HrefData
14
14
  from codex.views.opds.v2.links import LinkData
15
15
  from codex.views.opds.v2.top_links import OPDS2TopLinksView
16
16
 
17
- _MD_CONTRIBUTOR_MAP = MappingProxyType(
17
+ _MD_CREDIT_MAP = MappingProxyType(
18
+ # If OPDS2 is ever popular, make this comprehensive by using comicbox role enums
18
19
  {
19
20
  "author": AUTHOR_ROLES,
20
- # "translator": {}, unused
21
+ "translator": {"Translator"},
21
22
  "editor": {"Editor"},
22
- "artist": {"CoverArtist"},
23
- # "illustrator": {}, unused, could use penciller
23
+ "artist": {"CoverArtist", "Cover", "Artist"},
24
+ "illustrator": {"Illustrator"},
24
25
  "letterer": {"Letterer"},
25
26
  "penciller": {"Penciller"},
26
- "colorist": {"Colorist"},
27
- "inker": {"Inker"},
27
+ "colorist": {"Colorist", "Colors"},
28
+ "inker": {"Inker", "Inks"},
28
29
  }
29
30
  )
30
- _CONTRIBUTOR_ROLES = frozenset({x for s in _MD_CONTRIBUTOR_MAP.values() for x in s})
31
+ _CREDIT_ROLES = frozenset({x for s in _MD_CREDIT_MAP.values() for x in s})
31
32
 
32
33
 
33
34
  class OPDS2PublicationView(OPDS2TopLinksView):
@@ -65,10 +66,10 @@ class OPDS2PublicationView(OPDS2TopLinksView):
65
66
  ]
66
67
 
67
68
  @staticmethod
68
- def _add_contributors(md, pks, key, roles):
69
- """Add contributors to metadata."""
70
- if contributors := get_contributors(pks, roles, exclude=False):
71
- md[key] = contributors
69
+ def _add_credits(md, pks, key, roles):
70
+ """Add credits to metadata."""
71
+ if credit_objs := get_credits(pks, roles, exclude=False):
72
+ md[key] = credit_objs
72
73
 
73
74
  def _publication_optional_metadata(self, md, obj):
74
75
  """Add optional Publication Metadtata."""
@@ -87,10 +88,10 @@ class OPDS2PublicationView(OPDS2TopLinksView):
87
88
 
88
89
  def _publication_extended_metadata(self, md, obj):
89
90
  """Publication m2m metadata only on the metadata alternate link."""
90
- for key, roles in _MD_CONTRIBUTOR_MAP.items():
91
- self._add_contributors(md, obj.ids, key, roles)
92
- if contributors := get_contributors(obj.ids, _CONTRIBUTOR_ROLES, exclude=True):
93
- md["contributor"] = contributors
91
+ for key, roles in _MD_CREDIT_MAP.items():
92
+ self._add_credits(md, obj.ids, key, roles)
93
+ if credit_objs := get_credits(obj.ids, _CREDIT_ROLES, exclude=True):
94
+ md["credit"] = credit_objs
94
95
 
95
96
  if m2m_objs := get_m2m_objects(obj.ids):
96
97
  # Subjects can also have links
@@ -64,7 +64,7 @@ class OPDS2TopLinksView(OPDS2LinksView):
64
64
 
65
65
  def get_links(self, up_route):
66
66
  """Get the top links section of the feed."""
67
- page = self.kwargs.get("page")
67
+ page = self.kwargs.get("page", 0)
68
68
  top_href_data = HrefData(self._top_route())
69
69
  top_link_data = LinkData(Rel.TOP, top_href_data)
70
70
  up_href_data = HrefData(up_route)
@@ -73,7 +73,12 @@ class OPDS2TopLinksView(OPDS2LinksView):
73
73
  self.link_self(),
74
74
  *self._get_static_links(),
75
75
  self._link_page("first", 1),
76
- self._link_page("previous", page - 1),
76
+ ]
77
+ if page > 1:
78
+ links_data += [
79
+ self._link_page("previous", page - 1),
80
+ ]
81
+ links_data += [
77
82
  self._link_page("next", page + 1),
78
83
  self._link_page("last", self.num_pages),
79
84
  self.link(top_link_data),
codex/views/public.py CHANGED
@@ -2,39 +2,36 @@
2
2
 
3
3
  from rest_framework.generics import GenericAPIView
4
4
  from rest_framework.mixins import RetrieveModelMixin
5
+ from rest_framework.serializers import BaseSerializer
6
+ from typing_extensions import override
5
7
 
6
- from codex.choices.admin import ADMIN_FLAG_CHOICES
7
- from codex.logger.logger import get_logger
8
+ from codex.choices.admin import AdminFlagChoices
8
9
  from codex.models import AdminFlag
9
10
  from codex.serializers.auth import AuthAdminFlagsSerializer
10
11
 
11
- LOG = get_logger(__name__)
12
- _ADMIN_FLAG_KEYS = frozenset(
13
- {
14
- AdminFlag.FlagChoices.NON_USERS.value,
15
- AdminFlag.FlagChoices.REGISTRATION.value,
16
- AdminFlag.FlagChoices.BANNER_TEXT.value,
17
- }
12
+ _ADMIN_FLAG_KEYS = (
13
+ AdminFlagChoices.BANNER_TEXT.value,
14
+ AdminFlagChoices.LAZY_IMPORT_METADATA.value,
15
+ AdminFlagChoices.NON_USERS.value,
16
+ AdminFlagChoices.REGISTRATION.value,
18
17
  )
19
18
 
20
19
 
21
20
  class AdminFlagsView(GenericAPIView, RetrieveModelMixin):
22
21
  """Get admin flags relevant to auth."""
23
22
 
24
- serializer_class = AuthAdminFlagsSerializer
23
+ serializer_class: type[BaseSerializer] | None = AuthAdminFlagsSerializer
25
24
  queryset = AdminFlag.objects.filter(key__in=_ADMIN_FLAG_KEYS).only(
26
25
  "key", "on", "value"
27
26
  )
28
27
 
28
+ @override
29
29
  def get_object(self):
30
30
  """Get admin flags."""
31
31
  flags = {}
32
32
  for obj in self.get_queryset():
33
- name = ADMIN_FLAG_CHOICES[obj.key].lower().replace(" ", "_")
34
- if obj.key == AdminFlag.FlagChoices.BANNER_TEXT.value:
35
- val = obj.value
36
- else:
37
- val = obj.on
33
+ name = AdminFlagChoices(obj.key).name.lower()
34
+ val = obj.value if obj.key == AdminFlagChoices.BANNER_TEXT.value else obj.on
38
35
  flags[name] = val
39
36
  return flags
40
37