codex 1.4.0a0__py3-none-any.whl → 1.4.1__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.
- codex/config_default.yaml +12 -4
- codex/db_functions.py +4 -2
- codex/integrity.py +17 -6
- codex/librarian/covers/coverd.py +3 -11
- codex/librarian/covers/create.py +15 -21
- codex/librarian/covers/tasks.py +2 -16
- codex/librarian/importer/aggregate_metadata.py +75 -41
- codex/librarian/importer/clean_metadata.py +30 -7
- codex/librarian/importer/create_fks.py +154 -55
- codex/librarian/importer/deleted.py +11 -2
- codex/librarian/importer/failed_imports.py +44 -5
- codex/librarian/importer/importerd.py +37 -12
- codex/librarian/importer/link_comics.py +54 -31
- codex/librarian/importer/moved.py +55 -11
- codex/librarian/importer/query_fks.py +210 -48
- codex/librarian/importer/tasks.py +7 -7
- codex/librarian/janitor/cleanup.py +17 -5
- codex/librarian/librariand.py +10 -0
- codex/librarian/watchdog/events.py +11 -14
- codex/librarian/watchdog/observers.py +5 -1
- codex/logger/loggerd.py +7 -3
- codex/logger/logging.py +1 -1
- codex/migrations/0024_comic_gtin_comic_story_arc_number.py +24 -0
- codex/migrations/0025_add_story_arc_number.py +83 -0
- codex/models.py +21 -11
- codex/search/backend.py +1 -1
- codex/search/indexes.py +1 -1
- codex/serializers/browser.py +1 -0
- codex/serializers/metadata.py +5 -1
- codex/serializers/models.py +16 -1
- codex/serializers/opds/v1.py +1 -0
- codex/serializers/opds/v2.py +5 -2
- codex/serializers/reader.py +55 -16
- codex/settings/settings.py +1 -1
- codex/static_root/assets/admin-12749881.ef0f50bac290.js +41 -0
- codex/static_root/assets/admin-12749881.ef0f50bac290.js.br +0 -0
- codex/static_root/assets/admin-12749881.ef0f50bac290.js.gz +0 -0
- codex/static_root/assets/admin-12749881.js +41 -0
- codex/static_root/assets/admin-12749881.js.br +0 -0
- codex/static_root/assets/admin-12749881.js.gz +0 -0
- codex/static_root/assets/admin-beda768d.a614eee46307.css +1 -0
- codex/static_root/assets/admin-beda768d.a614eee46307.css.br +0 -0
- codex/static_root/assets/admin-beda768d.a614eee46307.css.gz +0 -0
- codex/static_root/assets/admin-beda768d.css +1 -0
- codex/static_root/assets/admin-beda768d.css.br +0 -0
- codex/static_root/assets/admin-beda768d.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-41c225cc.3f84583b435b.css +1 -0
- codex/static_root/assets/admin-drawer-panel-41c225cc.3f84583b435b.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-41c225cc.3f84583b435b.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-41c225cc.css +1 -0
- codex/static_root/assets/admin-drawer-panel-41c225cc.css.br +0 -0
- codex/static_root/assets/admin-drawer-panel-41c225cc.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-522f1e6c.089d70878270.js +1 -0
- codex/static_root/assets/admin-drawer-panel-522f1e6c.089d70878270.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-522f1e6c.089d70878270.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-522f1e6c.js +1 -0
- codex/static_root/assets/admin-drawer-panel-522f1e6c.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-522f1e6c.js.gz +0 -0
- codex/static_root/assets/browser-7f7d7134.0fe3749b0f2f.css +1 -0
- codex/static_root/assets/browser-7f7d7134.0fe3749b0f2f.css.br +0 -0
- codex/static_root/assets/browser-7f7d7134.0fe3749b0f2f.css.gz +0 -0
- codex/static_root/assets/browser-7f7d7134.css +1 -0
- codex/static_root/assets/browser-7f7d7134.css.br +0 -0
- codex/static_root/assets/browser-7f7d7134.css.gz +0 -0
- codex/static_root/assets/browser-af622672.d51aca96d64d.js +1 -0
- codex/static_root/assets/browser-af622672.d51aca96d64d.js.br +0 -0
- codex/static_root/assets/browser-af622672.d51aca96d64d.js.gz +0 -0
- codex/static_root/assets/browser-af622672.js +1 -0
- codex/static_root/assets/browser-af622672.js.br +0 -0
- codex/static_root/assets/browser-af622672.js.gz +0 -0
- codex/static_root/assets/http-error-5e17b794.77ceeb2d4641.js +1 -0
- codex/static_root/assets/http-error-5e17b794.77ceeb2d4641.js.br +0 -0
- codex/static_root/assets/http-error-5e17b794.77ceeb2d4641.js.gz +0 -0
- codex/static_root/assets/http-error-5e17b794.js +1 -0
- codex/static_root/assets/http-error-5e17b794.js.br +0 -0
- codex/static_root/assets/http-error-5e17b794.js.gz +0 -0
- codex/static_root/assets/{main-a6ac9581.2fd9e52cbcc3.css → main-0898f4bb.181e0145c642.css} +1 -1
- codex/static_root/assets/main-0898f4bb.181e0145c642.css.br +0 -0
- codex/static_root/assets/{main-a6ac9581.2fd9e52cbcc3.css.gz → main-0898f4bb.181e0145c642.css.gz} +0 -0
- codex/static_root/assets/{main-a6ac9581.css → main-0898f4bb.css} +1 -1
- codex/static_root/assets/main-0898f4bb.css.br +0 -0
- codex/static_root/assets/{main-a6ac9581.css.gz → main-0898f4bb.css.gz} +0 -0
- codex/static_root/assets/main-9e76a4c3.6844a407d14c.js +1 -0
- codex/static_root/assets/main-9e76a4c3.6844a407d14c.js.br +0 -0
- codex/static_root/assets/main-9e76a4c3.6844a407d14c.js.gz +0 -0
- codex/static_root/assets/main-9e76a4c3.js +1 -0
- codex/static_root/assets/main-9e76a4c3.js.br +0 -0
- codex/static_root/assets/main-9e76a4c3.js.gz +0 -0
- codex/static_root/assets/metadata-dialog-62c29ce0.8418785c0453.js +1 -0
- codex/static_root/assets/metadata-dialog-62c29ce0.8418785c0453.js.br +0 -0
- codex/static_root/assets/metadata-dialog-62c29ce0.8418785c0453.js.gz +0 -0
- codex/static_root/assets/metadata-dialog-62c29ce0.js +1 -0
- codex/static_root/assets/metadata-dialog-62c29ce0.js.br +0 -0
- codex/static_root/assets/metadata-dialog-62c29ce0.js.gz +0 -0
- codex/static_root/assets/{metadata-dialog-785c4cfc.694a251cda37.css → metadata-dialog-cb306ffd.cc304996d7bb.css} +1 -1
- codex/static_root/assets/metadata-dialog-cb306ffd.cc304996d7bb.css.br +0 -0
- codex/static_root/assets/metadata-dialog-cb306ffd.cc304996d7bb.css.gz +0 -0
- codex/static_root/assets/{metadata-dialog-785c4cfc.css → metadata-dialog-cb306ffd.css} +1 -1
- codex/static_root/assets/metadata-dialog-cb306ffd.css.br +0 -0
- codex/static_root/assets/metadata-dialog-cb306ffd.css.gz +0 -0
- codex/static_root/assets/{page-pdf-abfd509d.3870dab8eaf4.js → page-pdf-157ba97e.613d7c2beb77.js} +61 -51
- codex/static_root/assets/page-pdf-157ba97e.613d7c2beb77.js.br +0 -0
- codex/static_root/assets/page-pdf-157ba97e.613d7c2beb77.js.gz +0 -0
- codex/static_root/assets/{page-pdf-abfd509d.js → page-pdf-157ba97e.js} +61 -51
- codex/static_root/assets/page-pdf-157ba97e.js.br +0 -0
- codex/static_root/assets/page-pdf-157ba97e.js.gz +0 -0
- codex/static_root/assets/reader-36266549.0b2cf1291f27.js +1 -0
- codex/static_root/assets/reader-36266549.0b2cf1291f27.js.br +0 -0
- codex/static_root/assets/reader-36266549.0b2cf1291f27.js.gz +0 -0
- codex/static_root/assets/reader-36266549.js +1 -0
- codex/static_root/assets/reader-36266549.js.br +0 -0
- codex/static_root/assets/reader-36266549.js.gz +0 -0
- codex/static_root/assets/reader-7f004141.506eecc6954b.css +1 -0
- codex/static_root/assets/reader-7f004141.506eecc6954b.css.br +0 -0
- codex/static_root/assets/reader-7f004141.506eecc6954b.css.gz +0 -0
- codex/static_root/assets/reader-7f004141.css +1 -0
- codex/static_root/assets/reader-7f004141.css.br +0 -0
- codex/static_root/assets/reader-7f004141.css.gz +0 -0
- codex/static_root/js/choices-admin.24cecf0a0568.json +1 -0
- codex/static_root/js/choices-admin.24cecf0a0568.json.br +0 -0
- codex/static_root/js/choices-admin.24cecf0a0568.json.gz +0 -0
- codex/static_root/js/choices-admin.json +1 -1
- codex/static_root/js/choices-admin.json.br +0 -0
- codex/static_root/js/choices-admin.json.gz +0 -0
- codex/static_root/js/choices.8c58714cf5b2.json +1 -0
- codex/static_root/js/choices.8c58714cf5b2.json.br +5 -0
- codex/static_root/js/choices.8c58714cf5b2.json.gz +0 -0
- codex/static_root/js/choices.json +1 -1
- codex/static_root/js/choices.json.br +0 -0
- codex/static_root/js/choices.json.gz +0 -0
- codex/static_root/{manifest.64a989215af8.json → manifest.d2f93a519ada.json} +34 -34
- codex/static_root/manifest.d2f93a519ada.json.br +0 -0
- codex/static_root/manifest.d2f93a519ada.json.gz +0 -0
- codex/static_root/manifest.json +34 -34
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/templates/headers-script-globals.html +1 -1
- codex/templates/{opds → opds_v1}/index.xml +3 -1
- codex/templates/{opds/opensearch.xml → opds_v1/opensearch_v1.xml} +1 -1
- codex/templates/search/indexes/codex/comic_text.txt +2 -2
- codex/urls/converters.py +1 -1
- codex/urls/opds/authentication.py +1 -1
- codex/urls/opds/root.py +8 -12
- codex/urls/opds/v1.py +12 -5
- codex/urls/opds/v2.py +2 -2
- codex/views/admin/tasks.py +6 -1
- codex/views/bookmark.py +2 -2
- codex/views/browser/base.py +23 -7
- codex/views/browser/browser.py +66 -56
- codex/views/browser/browser_annotations.py +159 -50
- codex/views/browser/browser_order_by.py +51 -105
- codex/views/browser/choices.py +75 -38
- codex/views/browser/filters/bookmark.py +6 -9
- codex/views/browser/filters/field.py +9 -6
- codex/views/browser/filters/group.py +12 -27
- codex/views/browser/filters/search.py +5 -10
- codex/views/browser/metadata.py +44 -19
- codex/views/download.py +1 -1
- codex/views/frontend.py +2 -3
- codex/views/mixins.py +15 -2
- codex/views/opds/const.py +8 -1
- codex/views/opds/util.py +37 -1
- codex/views/opds/v1/__init__.py +1 -1
- codex/views/opds/v1/data.py +21 -0
- codex/views/opds/v1/entry/__init__.py +1 -0
- codex/views/opds/v1/entry/data.py +23 -0
- codex/views/opds/v1/entry/entry.py +151 -0
- codex/views/opds/v1/entry/links.py +135 -0
- codex/views/opds/v1/facets.py +190 -0
- codex/views/opds/v1/feed.py +199 -0
- codex/views/opds/v1/links.py +198 -0
- codex/views/opds/{opensearch.py → v1/opensearch_v1.py} +3 -3
- codex/views/opds/v2/__init__.py +1 -1
- codex/views/opds/v2/const.py +10 -2
- codex/views/opds/v2/feed.py +82 -21
- codex/views/opds/v2/links.py +1 -1
- codex/views/opds/v2/publications.py +1 -1
- codex/views/opds/v2/top_links.py +1 -1
- codex/views/reader/page.py +6 -7
- codex/views/reader/reader.py +191 -61
- codex/views/session.py +2 -1
- {codex-1.4.0a0.dist-info → codex-1.4.1.dist-info}/METADATA +10 -41
- {codex-1.4.0a0.dist-info → codex-1.4.1.dist-info}/RECORD +187 -185
- codex/librarian/importer/db_ops.py +0 -248
- codex/pdf.py +0 -115
- codex/static_root/assets/admin-73d93dc7.2c3eb62e50a0.js +0 -48
- codex/static_root/assets/admin-73d93dc7.2c3eb62e50a0.js.br +0 -0
- codex/static_root/assets/admin-73d93dc7.2c3eb62e50a0.js.gz +0 -0
- codex/static_root/assets/admin-73d93dc7.js +0 -48
- codex/static_root/assets/admin-73d93dc7.js.br +0 -0
- codex/static_root/assets/admin-73d93dc7.js.gz +0 -0
- codex/static_root/assets/admin-79555229.5f2c4cb3a73c.css +0 -1
- codex/static_root/assets/admin-79555229.5f2c4cb3a73c.css.br +0 -0
- codex/static_root/assets/admin-79555229.5f2c4cb3a73c.css.gz +0 -0
- codex/static_root/assets/admin-79555229.css +0 -1
- codex/static_root/assets/admin-79555229.css.br +0 -0
- codex/static_root/assets/admin-79555229.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-64bcc083.a85324c9ccd8.js +0 -1
- codex/static_root/assets/admin-drawer-panel-64bcc083.a85324c9ccd8.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-64bcc083.a85324c9ccd8.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-64bcc083.js +0 -1
- codex/static_root/assets/admin-drawer-panel-64bcc083.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-64bcc083.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-cce8c0aa.2c0814fa2a9b.css +0 -1
- codex/static_root/assets/admin-drawer-panel-cce8c0aa.2c0814fa2a9b.css.br +0 -2
- codex/static_root/assets/admin-drawer-panel-cce8c0aa.2c0814fa2a9b.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-cce8c0aa.css +0 -1
- codex/static_root/assets/admin-drawer-panel-cce8c0aa.css.br +0 -2
- codex/static_root/assets/admin-drawer-panel-cce8c0aa.css.gz +0 -0
- codex/static_root/assets/browser-7325db61.css +0 -1
- codex/static_root/assets/browser-7325db61.css.br +0 -0
- codex/static_root/assets/browser-7325db61.css.gz +0 -0
- codex/static_root/assets/browser-7325db61.ed2cfbf8e8ee.css +0 -1
- codex/static_root/assets/browser-7325db61.ed2cfbf8e8ee.css.br +0 -0
- codex/static_root/assets/browser-7325db61.ed2cfbf8e8ee.css.gz +0 -0
- codex/static_root/assets/browser-d2caeed7.2262000a6d55.js +0 -1
- codex/static_root/assets/browser-d2caeed7.2262000a6d55.js.br +0 -0
- codex/static_root/assets/browser-d2caeed7.2262000a6d55.js.gz +0 -0
- codex/static_root/assets/browser-d2caeed7.js +0 -1
- codex/static_root/assets/browser-d2caeed7.js.br +0 -0
- codex/static_root/assets/browser-d2caeed7.js.gz +0 -0
- codex/static_root/assets/http-error-0221c37d.480d5066da92.js +0 -1
- codex/static_root/assets/http-error-0221c37d.480d5066da92.js.br +0 -0
- codex/static_root/assets/http-error-0221c37d.480d5066da92.js.gz +0 -0
- codex/static_root/assets/http-error-0221c37d.js +0 -1
- codex/static_root/assets/http-error-0221c37d.js.br +0 -0
- codex/static_root/assets/http-error-0221c37d.js.gz +0 -0
- codex/static_root/assets/main-a6ac9581.2fd9e52cbcc3.css.br +0 -0
- codex/static_root/assets/main-a6ac9581.css.br +0 -0
- codex/static_root/assets/main-e33dcfb0.a65044fc1a08.js +0 -1
- codex/static_root/assets/main-e33dcfb0.a65044fc1a08.js.br +0 -0
- codex/static_root/assets/main-e33dcfb0.a65044fc1a08.js.gz +0 -0
- codex/static_root/assets/main-e33dcfb0.js +0 -1
- codex/static_root/assets/main-e33dcfb0.js.br +0 -0
- codex/static_root/assets/main-e33dcfb0.js.gz +0 -0
- codex/static_root/assets/metadata-dialog-785c4cfc.694a251cda37.css.br +0 -0
- codex/static_root/assets/metadata-dialog-785c4cfc.694a251cda37.css.gz +0 -0
- codex/static_root/assets/metadata-dialog-785c4cfc.css.br +0 -0
- codex/static_root/assets/metadata-dialog-785c4cfc.css.gz +0 -0
- codex/static_root/assets/metadata-dialog-8b0e8aaa.d12b42b1c9da.js +0 -1
- codex/static_root/assets/metadata-dialog-8b0e8aaa.d12b42b1c9da.js.br +0 -0
- codex/static_root/assets/metadata-dialog-8b0e8aaa.d12b42b1c9da.js.gz +0 -0
- codex/static_root/assets/metadata-dialog-8b0e8aaa.js +0 -1
- codex/static_root/assets/metadata-dialog-8b0e8aaa.js.br +0 -0
- codex/static_root/assets/metadata-dialog-8b0e8aaa.js.gz +0 -0
- codex/static_root/assets/page-pdf-abfd509d.3870dab8eaf4.js.br +0 -0
- codex/static_root/assets/page-pdf-abfd509d.3870dab8eaf4.js.gz +0 -0
- codex/static_root/assets/page-pdf-abfd509d.js.br +0 -0
- codex/static_root/assets/page-pdf-abfd509d.js.gz +0 -0
- codex/static_root/assets/reader-a8b8f766.875abdd0d22e.css +0 -1
- codex/static_root/assets/reader-a8b8f766.875abdd0d22e.css.br +0 -0
- codex/static_root/assets/reader-a8b8f766.875abdd0d22e.css.gz +0 -0
- codex/static_root/assets/reader-a8b8f766.css +0 -1
- codex/static_root/assets/reader-a8b8f766.css.br +0 -0
- codex/static_root/assets/reader-a8b8f766.css.gz +0 -0
- codex/static_root/assets/reader-fe9345d2.759c31f82998.js +0 -1
- codex/static_root/assets/reader-fe9345d2.759c31f82998.js.br +0 -0
- codex/static_root/assets/reader-fe9345d2.759c31f82998.js.gz +0 -0
- codex/static_root/assets/reader-fe9345d2.js +0 -1
- codex/static_root/assets/reader-fe9345d2.js.br +0 -0
- codex/static_root/assets/reader-fe9345d2.js.gz +0 -0
- codex/static_root/js/choices-admin.3d958ea7f83b.json +0 -1
- codex/static_root/js/choices-admin.3d958ea7f83b.json.br +0 -0
- codex/static_root/js/choices-admin.3d958ea7f83b.json.gz +0 -0
- codex/static_root/js/choices.6bfc2a3d293f.json +0 -1
- codex/static_root/js/choices.6bfc2a3d293f.json.br +0 -0
- codex/static_root/js/choices.6bfc2a3d293f.json.gz +0 -0
- codex/static_root/manifest.64a989215af8.json.br +0 -0
- codex/static_root/manifest.64a989215af8.json.gz +0 -0
- codex/urls/opds/opensearch.py +0 -18
- codex/views/opds/v1/browser.py +0 -346
- codex/views/opds/v1/entry.py +0 -278
- codex/views/opds/v1/start.py +0 -28
- codex/views/opds/v1/util.py +0 -162
- codex/views/opds/v2/start.py +0 -28
- {codex-1.4.0a0.dist-info → codex-1.4.1.dist-info}/LICENSE +0 -0
- {codex-1.4.0a0.dist-info → codex-1.4.1.dist-info}/WHEEL +0 -0
- {codex-1.4.0a0.dist-info → codex-1.4.1.dist-info}/entry_points.txt +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as b,bm as u,b as f,c as m,o as c,e as _,w as l,k as g,t as k,bn as ie,bo as le,g as s,E as P,B as y,f as C,bp as I,ao as R,D as w,d as v,bq as ze,br as Fe,j as r,aD as L,bl as ce,bs as He,bt as Me,bu as Ge,bv as de,r as G,bw as ue,F as B,bx as ge,by as pe,aH as q,be as O,b8 as qe,b2 as H,aW as Ke,bz as je,M as Ye,J as Xe,K as D,ar as M,aY as K,at as Je,au as Ze,bA as Qe,bB as et,bC as tt,bD as ot,bE as at,n as j,p as Y,N as he,bF as st,T as _e,bG as me,bH as nt,bI as rt,bJ as it,bK as X,a9 as lt,bL as ct,bd as dt,bM as ut,bN as J,bO as ke,bP as gt,aA as z,bQ as pt,bR as ht,bS as _t,bT as mt,bU as kt,bV as vt,bW as ft,bX as bt,bY as Pt,bZ as wt,q as St,v as yt,V as Z,bk as ve,C as Q,bj as Ct,b_ as Tt,bh as ee,b$ as Rt}from"./admin-73d93dc7.js";import{_ as E,a as fe,b as be,P as Bt,c as Pe}from"./metadata-dialog-8b0e8aaa.js";const It={name:"ReaderNavButton",components:{PaginationNavButton:E},props:{value:{type:Number,required:!0},twoPages:{type:Boolean,default:!1}},computed:{...b(u,{storePage:e=>e.page,vertical:e=>{var t;return(t=e.activeSettings)==null?void 0:t.vertical},toRoute(e){return{params:{pk:e.pk,page:this.value}}}}),title(){return"to page "+this.value},disabled(){return this.value===this.storePage||this.twoPages&&!!(this.value%2)&&this.value-1===this.storePage}},methods:{...f(u,["setActivePage"]),onClick(){this.setActivePage(this.value,!0)}}};function Dt(e,t,a,d,i,o){const n=E;return e.vertical?(c(),_(n,{key:0,disabled:o.disabled,title:o.title,onClick:o.onClick},{default:l(()=>[g(k(a.value),1)]),_:1},8,["disabled","title","onClick"])):(c(),_(n,{key:1,disabled:o.disabled,title:o.title,to:e.toRoute},{default:l(()=>[g(k(a.value),1)]),_:1},8,["disabled","title","to"]))}const we=m(It,[["render",Dt]]),$t={name:"ReaderBookChangeNavButton",components:{PaginationNavButton:E},props:{direction:{type:String,required:!0}},computed:{...b(u,{toRoute(e){const t=e.routes.books;if(!t)return"";const a=t[this.direction];return a?{params:{...a}}:""}}),title(){return(this.direction==="prev"?"Previous":"Next")+" Book"},icon(){return this.direction==="prev"?ie:le},disabled(){return!this.toRoute}}};function Vt(e,t,a,d,i,o){const n=E;return c(),_(n,{icon:"",variant:"plain",disabled:o.disabled,title:o.title,to:e.toRoute},{default:l(()=>[s(P,null,{default:l(()=>[g(k(o.icon),1)]),_:1})]),_:1},8,["disabled","title","to"])}const Se=m($t,[["render",Vt]]),V="prev",x="next",xt={name:"ReaderNavToolbar",components:{PaginationSlider:fe,ReaderNavButton:we,PaginationToolbar:be,ReaderBookChangeNavButton:Se},computed:{...y(u,["activeSettings","activeBook"]),...b(u,{storePage:e=>e.page,key(e){return`${e.pk} - ${this.twoPages}`}}),maxPage(){return this.activeBook?this.activeBook.maxPage:0},twoPages(){return this.activeSettings.twoPages},step(){return this.activeSettings.twoPages?2:1},trackColor(){return this.twoPages&&+this.storePage>=this.maxPage-1?this.$vuetify.theme.current.colors.primary:""},readInReverse(){return this.activeSettings.readInReverse},min(){return this.readInReverse?this.maxPage:0},max(){return this.readInReverse?0:this.maxPage},bookPrev(){return this.readInReverse?"next":"prev"},bookNext(){return this.readInReverse?"prev":"next"}},mounted(){document.addEventListener("keyup",this._keyListener)},beforeUnmount(){document.removeEventListener("keyup",this._keyListener)},methods:{...f(u,["routeToBook","routeToDirection","routeToDirectionOne","routeToPage","setActivePage"]),onSliderUpdate(e){this.activeSettings.vertical?this.setActivePage(e,!0):this.routeToPage(e)},_keyListener(e){switch(e.stopPropagation(),e.key){case" ":!e.shiftKey&&window.innerHeight+window.scrollY+1>=document.body.scrollHeight?this.routeToDirection(x):e.shiftKey&&window.scrollY===0&&this.routeToDirection(V);break;case"j":case"ArrowRight":this.routeToDirection(x);break;case"k":case"ArrowLeft":this.routeToDirection(V);break;case",":this.routeToDirectionOne(V);break;case".":this.routeToDirectionOne(x);break;case"n":this.routeToBook(x);break;case"p":this.routeToBook(V);break}}}};function Lt(e,t,a,d,i,o){const n=Se,h=we,p=fe,T=be;return o.maxPage?(c(),_(T,{key:0},{default:l(()=>[s(n,{direction:o.bookPrev},null,8,["direction"]),s(h,{value:o.min,"two-pages":o.twoPages},null,8,["value","two-pages"]),(c(),_(p,{key:e.key,"model-value":e.storePage,min:0,max:o.maxPage,step:o.step,"track-color":o.trackColor,reverse:o.readInReverse,"onUpdate:modelValue":t[0]||(t[0]=$=>o.onSliderUpdate($))},null,8,["model-value","max","step","track-color","reverse"])),s(h,{value:o.max,"two-pages":o.twoPages},null,8,["value","two-pages"]),s(n,{direction:o.bookNext},null,8,["direction"])]),_:1})):C("",!0)}const ye=m(xt,[["render",Lt]]),Ot={rel:"prefetch",as:"image"},Ce=function(e){const t=[];for(const a of e)a&&t.push({...Ot,href:a});return{link:t}};const Et={name:"PageChangeLink",props:{direction:{type:String,required:!0}},head(){return Ce([this.prefetchSrc1,this.prefetchSrc2])},computed:{...b(u,{params(e){return e.routes[this.computedDirection]},prefetchSrc2(e){const t=e.books.get(this.params.pk);if(!t||!this.getSettings(t).twoPages)return!1;const d={...this.params,page:this.params.page+1};return d.page>t.maxPage?!1:I(d)},directionClass(e){let t=this.direction;return e.activeSettings.vertical&&(t+="Vertical"),t},pageChangeClass(e){let t="pageChange";return t+=e.activeSettings.vertical?"Row":"Column",t}}),computedDirection(){return this.normalizeDirection(this.direction)},prefetchSrc1(){return this.params?I(this.params):!1},route(){return this.params?{params:this.params}:{}},label(){return`${this.computedDirection==="prev"?"Previous":"Next"} Page`}},methods:{...f(u,["getSettings","normalizeDirection"])}};function Nt(e,t,a,d,i,o){const n=w("router-link");return c(),_(n,{to:o.route,"aria-label":o.label,class:R({[e.pageChangeClass]:!0,[e.directionClass]:!0}),onClick:t[0]||(t[0]=h=>h.stopImmediatePropagation())},null,8,["to","aria-label","class"])}const Te=m(Et,[["render",Nt],["__scopeId","data-v-29292846"]]);const At={name:"LoadingPage",components:{Placeholder:Bt},props:{twoPages:{type:Boolean,required:!0}}};function Ut(e,t,a,d,i,o){const n=w("Placeholder");return c(),v("div",{class:R(["pageLoading",{twoPages:a.twoPages}])},[s(n,{class:"pagePlaceholder"})],2)}const Wt=m(At,[["render",Ut],["__scopeId","data-v-13c9bf0b"]]);const te="unauthorized",zt={name:"ErrorPage",props:{twoPages:{type:Boolean,required:!0},type:{type:String,required:!0}},computed:{text(){return this.type===te?"Protected page":"Failed to load page"},icon(){return this.type===te?ze:Fe}}},Ft={class:"pageErrorContainer"},Ht={class:"pageErrorText"};function Mt(e,t,a,d,i,o){return c(),v("div",{class:R(["pageError",{twoPages:a.twoPages}])},[r("div",Ft,[r("div",Ht,k(o.text),1),s(P,{class:"pageErrorIcon"},{default:l(()=>[g(k(o.icon),1)]),_:1})])],2)}const Gt=m(zt,[["render",Mt],["__scopeId","data-v-3f1e3f4f"]]);const qt={name:"ImgPage",props:{src:{type:String,required:!0},fitToClass:{type:Object,required:!0}},emits:["load","error"]},Kt=["src"];function jt(e,t,a,d,i,o){return c(),v("img",L({class:a.fitToClass,src:a.src},e.$attrs,{onError:t[0]||(t[0]=n=>e.$emit("error")),onLoad:t[1]||(t[1]=n=>e.$emit("load"))}),null,16,Kt)}const oe=m(qt,[["render",jt],["__scopeId","data-v-5997abff"]]);const ae=ce(He(()=>Ge(()=>import("./page-pdf-abfd509d.js"),["assets/page-pdf-abfd509d.js","assets/admin-73d93dc7.js","assets/admin-79555229.css","assets/page-pdf-2d7d4f5d.css"]))),Yt=333,Xt={S:"Screen",W:"Width",H:"Height",O:"Original"},Jt={name:"BookPage",components:{ErrorPage:Gt,LoadingPage:Wt,PDFPage:ae,ImgPage:oe},props:{book:{type:Object,required:!0},page:{type:Number,required:!0}},data(){return{showProgress:!1,loaded:!1,error:!1}},computed:{pageClass(){return this.settings.vertical?"pageVertical":"pageHorizontal"},fitToClass(){let e={};const t=Xt[this.settings.fitTo];if(t){let a="fitTo";a+=t.charAt(0).toUpperCase()+t.slice(1).toLowerCase(),this.settings.twoPages&&(a+="Two",this.settings.vertical&&(a+="Vertical")),e[a]=!0}return e},src(){const e={pk:this.book.pk,page:this.page};return I(e)},component(){return this.book.fileType==="PDF"?ae:oe},settings(){return this.getSettings(this.book)}},mounted(){setTimeout(function(){this.loaded||(this.loading=!0)},Yt)},methods:{...f(u,["getSettings"]),onLoad(){this.showProgress=!1,this.loaded=!0,this.error=!1},onError(){this.error="load",this.showProgress=!1},onUnauthorized(){this.error="unauthorized",this.showProgress=!1}}},Zt=["id","data-page"];function Qt(e,t,a,d,i,o){const n=w("ErrorPage"),h=w("LoadingPage");return c(),v("div",{id:`page${a.page}`,"data-page":a.page,class:R(o.pageClass)},[i.error?(c(),_(n,{key:0,"two-pages":o.settings.twoPages,type:i.error},null,8,["two-pages","type"])):i.showProgress&&!i.loaded?(c(),_(h,{key:1,"two-pages":o.settings.twoPages},null,8,["two-pages"])):(c(),_(Me(o.component),{key:2,src:o.src,"fit-to-class":o.fitToClass,book:a.book,onError:o.onError,onLoad:o.onLoad,onUnauthorized:o.onUnauthorized},null,40,["src","fit-to-class","book","onError","onLoad","onUnauthorized"]))],10,Zt)}const Re=m(Jt,[["render",Qt],["__scopeId","data-v-f9e0354b"]]);const eo=48,to=48,oo={name:"PagesHorizontalWindow",components:{BookPage:Re,PageChangeLink:Te},props:{book:{type:Object,required:!0}},data(){return{activePage:0,pages:[]}},computed:{...y(u,["isOnCoverPage"]),...b(u,{prevBook:e=>{var t;return(t=e.routes.books)==null?void 0:t.prev},nextBook:e=>{var t;return(t=e.routes.books)==null?void 0:t.next},storePage:e=>e.page,storePk:e=>e.pk}),settings(){return this.getSettings(this.book)},twoPages(){return this.settings.twoPages},readInReverse(){return this.settings.readInReverse},secondPage(){return this.settings.twoPages&&!this.isOnCoverPage},windowIndex(){const e=this.activePage-this.pages[0];return Math.min(Math.max(0,e),this.book.maxPage)}},watch:{twoPages(){this.setActivePage(this.storePage,!0)},storePage(e){if(this.book.pk===this.storePk){this.activePage=e;const t=this.pages.at(0),a=this.pages.at(-1);(e<t||e>a)&&this.setPages()}},prevBook(e){this.book.pk===e.pk&&(this.activePage=this.book.maxPage)},nextBook(e){this.book.pk===e.pk&&(this.activePage=0)}},created(){this.book.pk===this.storePk?this.activePage=+this.$route.params.page:this.book.pk===this.prevBook.pk?this.activePage=this.book.maxPage:this.activePage=0,this.setPages()},methods:{...f(u,["getSettings","setBookChangeFlag","setActivePage"]),setPages(){const e=Math.max(this.activePage-eo,0),t=Math.min(this.activePage+to,this.book.maxPage),a=de.range(e,t+1);this.pages=a}}};function ao(e,t,a,d,i,o){const n=Te,h=w("BookPage");return c(),_(ge,{"show-arrows":"",continuous:"","model-value":o.windowIndex,reverse:o.readInReverse},{prev:l(()=>[s(n,{direction:"prev"})]),next:l(()=>[s(n,{direction:"next"})]),default:l(()=>[(c(!0),v(B,null,G(i.pages,p=>(c(),_(ue,{key:`c/${a.book.pk}/${p}`,class:"windowItem",disabled:"",eager:p>=e.storePage-1&&p<=e.storePage+2,"model-value":p,transition:!0},{default:l(()=>[!o.readInReverse||o.secondPage&&p<a.book.maxPage?(c(),_(h,{key:0,book:a.book,page:o.readInReverse?p+1:p},null,8,["book","page"])):C("",!0),o.readInReverse||o.secondPage&&p<a.book.maxPage?(c(),_(h,{key:1,book:a.book,page:o.readInReverse?p:p+1},null,8,["book","page"])):C("",!0)]),_:2},1032,["eager","model-value"]))),128))]),_:1},8,["model-value","reverse"])}const so=m(oo,[["render",ao],["__scopeId","data-v-da9ab604"]]);function Be(e,t){const{self:a=!1}=t.modifiers??{},d=t.value,i=typeof d=="object"&&d.options||{passive:!0},o=typeof d=="function"||"handleEvent"in d?d:d.handler,n=a?e:t.arg?document.querySelector(t.arg):window;n&&(n.addEventListener("scroll",o,i),e._onScroll=Object(e._onScroll),e._onScroll[t.instance.$.uid]={handler:o,options:i,target:a?void 0:n})}function Ie(e,t){var o;if(!((o=e._onScroll)!=null&&o[t.instance.$.uid]))return;const{handler:a,options:d,target:i=e}=e._onScroll[t.instance.$.uid];i.removeEventListener("scroll",a,d),delete e._onScroll[t.instance.$.uid]}function no(e,t){t.value!==t.oldValue&&(Ie(e,t),Be(e,t))}const ro={mounted:Be,unmounted:Ie,updated:no},io=12,se=250,ne={threshold:[.75]},lo={S:ne,H:ne},co={name:"PagesVerticalScroller",components:{BookPage:Re,VVirtualScroll:pe},props:{book:{type:Object,required:!0}},data(){return{innerHeight:window.innerHeight,innerWidth:window.innerWidth,intersectorOn:!1,programmaticScroll:!1}},computed:{...b(u,{storePage:e=>e.page}),...q(u,["reactWithScroll"]),settings(){return this.getSettings(this.book)},readInReverse(){return this.settings.readInReverse},items(){var a;const e=((a=this.book)==null?void 0:a.maxPage)+1,t=de.range(0,e);return this.readInReverse&&t.reverse(),t},visibleItems(){var e;return Math.min(((e=this.book)==null?void 0:e.maxPage)??0,io)},intersectOptions(){return lo[this.settings.fitTo]}},watch:{storePage(e){this.reactWithScroll&&this.scrollToPage(e)}},mounted(){window.addEventListener("resize",this.onResize),setTimeout(()=>{this.scrollToPage(this.storePage)},se)},beforeUnmount(){window.removeEventListener("resize",this.onResize)},methods:{...f(u,["setActivePage","setBookChangeFlag","getSettings"]),onIntersect(e,t){if(e&&this.intersectorOn){const d=+t[0].target.dataset.page;this.setActivePage(d,!1)}},onScroll(){if(this.programmaticScroll)return;this.intersectorOn=!0;const e=this.$refs.verticalScroll.$el,t=e.scrollTop;if(this.storePage===0&&t===0)this.setBookChangeFlag("prev");else if(this.storePage===this.book.maxPage){const a=e.scrollTopMax||e.scrollHeight-e.clientTop;window.innerHeight+t+1>=a&&this.setBookChangeFlag("next")}},scrollToPage(e){this.intersectorOn=!1,this.programmaticScroll=!0,this.$refs.verticalScroll.scrollToIndex(e),setTimeout(()=>{this.programmaticScroll=!1},se)},onResize(){this.innerHeight=window.innerHeight,this.innerWidth=window.innerWidth}}},uo=["data-page"];function go(e,t,a,d,i,o){const n=w("BookPage"),h=pe;return O((c(),_(h,{id:"verticalScroll",ref:"verticalScroll",items:o.items,"visible-items":o.visibleItems,height:i.innerHeight,width:i.innerWidth},{default:l(({item:p})=>[s(n,{book:a.book,page:p},null,8,["book","page"]),O(r("div",{class:"pageTracker","data-page":p},null,8,uo),[[qe,{handler:o.onIntersect,options:o.intersectOptions},void 0,{quiet:!0}]])]),_:1},8,["items","visible-items","height","width"])),[[ro,o.onScroll,"#verticalScroll"]])}const po=m(co,[["render",go],["__scopeId","data-v-c93f9571"]]),ho={name:"PagesView",components:{PagesHorizontalWindow:so,PagesVerticalScroller:po},props:{book:{type:Object,required:!0}},emits:["click"],computed:{...b(u,{storePk:e=>e.pk}),settings(){return this.getSettings(this.book)},vertical(){return this.settings.vertical}},watch:{$route(e){+e.params.pk===this.book.pk&&this.setActivePage(+e.params.page,!0)}},created(){this.book.pk===this.storePk&&this.setActivePage(+this.$route.params.page,!0)},methods:{...f(u,["getSettings","setActivePage"])}};function _o(e,t,a,d,i,o){const n=w("PagesVerticalScroller"),h=w("PagesHorizontalWindow");return o.vertical?(c(),_(n,{key:0,book:a.book,onClick:e.$emit.click},null,8,["book","onClick"])):(c(),_(h,{key:1,book:a.book,onClick:e.$emit.click},null,8,["book","onClick"]))}const De=m(ho,[["render",_o]]);const mo={name:"BookChangeActivator",props:{direction:{type:String,required:!0}},computed:{...y(u,["prevBookChangeShow","nextBookChangeShow"]),show(){return this[this.computedDirection+"BookChangeShow"]},computedDirection(){return this.normalizeDirection(this.direction)}},methods:{...f(u,["setBookChangeFlag","normalizeDirection"])}};function ko(e,t,a,d,i,o){return o.show?(c(),v("div",{key:0,class:R(["bookChangeColumn",{[a.direction]:!0}]),onClick:t[0]||(t[0]=H(n=>e.setBookChangeFlag(a.direction),["stop"]))},null,2)):C("",!0)}const $e=m(mo,[["render",ko],["__scopeId","data-v-2a8ea6a5"]]);const vo={name:"BooksWindow",components:{BookChangeActivator:$e,PagesView:De},emits:["click"],computed:{...b(u,{books:e=>e.books,bookChange:e=>e.bookChange,activeBookPk:e=>e.pk,bookRoutes:e=>e.routes.books})},watch:{$route(e,t){(!t||!t.params||+e.params.pk!=+t.params.pk)&&this.loadBooks(e.params)}},beforeMount(){this.setBookChangeFlag()},created(){this.loadBooks(this.$route.params)},methods:{...f(u,["setBookChangeFlag","loadBooks"]),click(){this.setBookChangeFlag(),this.$emit("click")},eager(e){return this.bookChange&&this.bookRoutes[this.bookChange]&&this.bookRoutes[this.bookChange].pk===e}}};function fo(e,t,a,d,i,o){const n=$e,h=De;return c(),_(ge,{id:"booksWindow",direction:"vertical","model-value":e.activeBookPk,"show-arrows":"",onClick:o.click},{prev:l(()=>[s(n,{direction:"prev"})]),next:l(()=>[s(n,{direction:"next"})]),default:l(()=>[(c(!0),v(B,null,G(e.books,([p,T])=>(c(),_(ue,{key:`c/${p}`,class:"windowItem",disabled:"",eager:o.eager(p),value:p,transition:!0},{default:l(()=>[s(h,{book:T,onClick:o.click},null,8,["book","onClick"])]),_:2},1032,["eager","value"]))),128))]),_:1},8,["model-value","onClick"])}const Ve=m(vo,[["render",fo],["__scopeId","data-v-ca6f1824"]]);const bo={name:"ReaderTitleToolbar",components:{MetadataDialog:Pe,SettingsDrawerButton:Ke},data(){return{mdiClose:je,routeChanged:!1}},head(){return{meta:[{hid:"description",name:"description",content:`reader ${this.activeTitle} page ${this.storePage}`}]}},computed:{...y(u,["activeTitle","activeBook"]),...b(u,{bookChange:e=>e.bookChange,seriesPosition:function(e){return this.activeBook&&e.seriesCount>1?`${this.activeBook.seriesIndex}/${e.seriesCount}`:""},vertical:e=>e.activeSettings.vertical,pk:e=>e.pk||0}),...b(Ye,{lastRoute:e=>e.page.routes.last}),...q(D,["isSettingsDrawerOpen"]),closeBookRoute:function(){const e={name:"browser",params:this.lastRoute};return e.params?e.hash=`#card-${this.pk}`:e.params=window.CODEX.LAST_ROUTE||Xe.browser.route,e}},watch:{$route(e,t){t&&(this.routeChanged=!0)}},mounted(){document.addEventListener("keyup",this._keyListener)},beforeUnmount(){document.removeEventListener("keyup",this._keyListener)},methods:{...f(D,["setTimestamp"]),...f(u,["routeToDirection","routeToDirectionOne","routeToBook","setBookChangeFlag"]),openMetadata(){this.$refs.metadataDialog.dialog=!0},onCloseBook(){this.routeChanged&&this.setTimestamp()},_keyListener(e){switch(e.stopPropagation(),e.key){case"Escape":this.$refs.closeBook.$el.click();break;case"m":this.openMetadata();break}}}},Po={key:0},wo={key:0,id:"seriesPosition",title:"Series Position"};function So(e,t,a,d,i,o){const n=Pe,h=w("SettingsDrawerButton");return c(),_(Ze,{id:"readerTopToolbar",class:"codexToolbar",density:"compact"},{default:l(()=>[s(K,null,{default:l(()=>[s(M,{id:"closeBook",ref:"closeBook",to:o.closeBookRoute,size:"large",onClick:o.onCloseBook},{default:l(()=>[e.$vuetify.display.smAndDown?(c(),_(P,{key:1,title:"Close Book"},{default:l(()=>[g(k(i.mdiClose),1)]),_:1})):(c(),v("span",Po,"close book"))]),_:1},8,["to","onClick"])]),_:1}),g(" "+k(e.bookChange)+" ",1),s(Je,{id:"toolbarTitle",class:"codexToolbarTitle"},{default:l(()=>[g(k(e.activeTitle),1)]),_:1}),e.seriesPosition?(c(),v("span",wo,k(e.seriesPosition),1)):C("",!0),s(K,null,{default:l(()=>[s(M,{id:"tagButton",onClick:H(o.openMetadata,["stop"])},{default:l(()=>[s(n,{ref:"metadataDialog",group:"c",pk:e.pk},null,8,["pk"])]),_:1},8,["onClick"]),s(h,{id:"settingsButton",onClick:t[0]||(t[0]=H(p=>e.isSettingsDrawerOpen=!0,["stop"]))})]),_:1})]),_:1})}const xe=m(bo,[["render",So],["__scopeId","data-v-4075b1a2"]]);const yo={name:"BookChangeDrawer",props:{direction:{type:String,required:!0}},head(){return Ce([this.prefetchSrc1,this.prefetchSrc2])},computed:{...y(u,["prevBookChangeShow","nextBookChangeShow"]),...b(u,{prefetchSrc2(e){if(!this.params)return!1;const t=e.books.get(this.params.pk),a=this.getSettings(t);if(!this.isDrawerOpen||!this.params||!a.twoPages)return!1;const d={pk:this.params.pk,page:this.params.page+1};return I(d)},isDrawerOpen(e){return e.bookChange===this.computedDirection},params(e){return e.routes.books[this.computedDirection]},icon(){return this.computedDirection==="next"?le:ie}}),show(){return this[this.computedDirection+"BookChangeShow"]},prefetchSrc1(){return!this.isDrawerOpen||!this.params?!1:I(this.params)},route(){return this.params?{params:this.params}:{}},label(){return`${this.computedDirection==="prev"?"Previous":"Next"} Book`},computedDirection(){return this.normalizeDirection(this.direction)}},methods:{...f(u,["getSettings","normalizeDirection"])}};function Co(e,t,a,d,i,o){const n=w("router-link");return o.show?(c(),_(Qe,{key:0,class:R({bookChangeDrawer:!0,[a.direction]:!0}),"disable-resize-watcher":"","disable-route-watcher":"",location:o.computedDirection==="prev"?"left":"right","model-value":e.isDrawerOpen,scrim:!1,temporary:"",touchless:""},{default:l(()=>[s(n,{class:"navLink",to:o.route,"aria-label":o.label,title:o.label,onClick:t[0]||(t[0]=h=>h.stopImmediatePropagation())},{default:l(()=>[s(P,{class:"bookChangeIcon"},{default:l(()=>[g(k(e.icon),1)]),_:1})]),_:1},8,["to","aria-label","title"])]),_:1},8,["class","location","model-value"])):C("",!0)}const Le=m(yo,[["render",Co],["__scopeId","data-v-33b1e110"]]);const To={name:"DownloadPanel",data(){return{mdiDownload:et,mdiFileImage:tt}},computed:{...y(u,["activeTitle"]),...b(u,{storePage:e=>e.page,pageSrc(e){const t={pk:e.pk,page:e.page};return ot(t)},downloadURL(e){return at(e.pk)}}),...y(u,["activeBook"]),pageName:function(){return`${this.activeTitle} - page ${this.storePage}.jpg`}},methods:{...f(D,["downloadIOSPWAFix"]),downloadPage(){this.downloadIOSPWAFix(this.pageSrc,this.pageName)},downloadBook(){this.downloadIOSPWAFix(this.downloadURL,this.activeBook.filename)}}},Ro={id:"downloadPanel"};function Bo(e,t,a,d,i,o){return c(),v("div",Ro,[s(Y,{onClick:o.downloadPage},{default:l(()=>[s(j,null,{default:l(()=>[s(P,null,{default:l(()=>[g(k(i.mdiFileImage),1)]),_:1}),g("Download Page "+k(e.storePage),1)]),_:1})]),_:1},8,["onClick"]),s(Y,{onClick:o.downloadBook},{default:l(()=>[s(j,null,{default:l(()=>[s(P,null,{default:l(()=>[g(k(i.mdiDownload),1)]),_:1}),g("Download Book ")]),_:1})]),_:1},8,["onClick"])])}const Oe=m(To,[["render",Bo],["__scopeId","data-v-c3777662"]]);const F=he()({name:"VRadio",props:{...st({falseIcon:"$radioOff",trueIcon:"$radioOn"})},setup(e,t){let{slots:a}=t;return _e(()=>s(me,L(e,{class:"v-radio",type:"radio"}),a)),{}}});const re=he()({name:"VRadioGroup",inheritAttrs:!1,props:{height:{type:[Number,String],default:"auto"},...nt(),...rt(it(),["multiple"]),trueIcon:{type:X,default:"$radioOn"},falseIcon:{type:X,default:"$radioOff"},type:{type:String,default:"radio"}},emits:{"update:modelValue":e=>!0},setup(e,t){let{attrs:a,slots:d}=t;const i=lt(),o=ct(()=>e.id||`radio-group-${i}`),n=dt(e,"modelValue");return _e(()=>{const[h,p]=ut(a),[T,$]=J.filterProps(e),[N,ta]=me.filterProps(e),A=d.label?d.label({label:e.label,props:{for:o.value}}):e.label;return s(J,L({class:"v-radio-group"},h,T,{modelValue:n.value,"onUpdate:modelValue":U=>n.value=U,id:o.value}),{...d,default:U=>{let{id:W,messagesId:Ne,isDisabled:Ae,isReadonly:Ue}=U;return s(B,null,[A&&s(ke,{id:W.value},{default:()=>[A]}),s(gt,L(N,{id:W.value,"aria-describedby":Ne.value,defaultsTarget:"VRadio",trueIcon:e.trueIcon,falseIcon:e.falseIcon,type:e.type,disabled:Ae.value,readonly:Ue.value,"aria-labelledby":A?W.value:void 0,multiple:!1},p,{modelValue:n.value,"onUpdate:modelValue":We=>n.value=We}),d)])}})}),{}}}),Io=["fitTo","twoPages","vertical","readInReverse"],Do={name:"ReaderSettingsPanel",data(){return{isGlobalScope:!1}},computed:{...b(u,{fitToChoices(e){const t=[];for(const a of e.choices.fitTo)a.value&&t.push(a);return t},selectedSettings:function(e){return this.isGlobalScope||!e.activeBook?e.readerSettings:e.activeBook.settings},isClearSettingsButtonDisabled:function(e){if(this.isGlobalScope||!e.activeBook)return!0;for(const t of Io){const a=e.activeBook.settings[t];if(!e.choices.nullValues.has(a))return!1}return!0},verticalLabel(e){const t=e.activeBook&&e.activeBook.settings?e.activeBook.settings.vertical:void 0;return t==null?"Horizontal or Vertical":t?"Scroll Pages Vertically":"Turn Pages Horizontally"},params(e){return{pk:e.pk,page:e.page}}}),...q(u,["readRTLInReverse"])},mounted(){document.addEventListener("keyup",this._keyListener)},beforeUnmount(){document.removeEventListener("keyup",this._keyListener)},methods:{...f(u,["clearSettingsLocal","setSettingsGlobal","setSettingsLocal"]),settingsDialogChanged:function(e){this.isGlobalScope?this.setSettingsGlobal(this.params,e):this.setSettingsLocal(this.params,e)},_keyListener:function(e){e.stopPropagation();let t;switch(e.key){case"w":t={fitTo:"W"};break;case"h":t={fitTo:"H"};break;case"s":t={fitTo:"S"};break;case"o":t={fitTo:"O"};break;case"2":t={twoPages:!this.selectedSettings.twoPages};break;case"r":t={readInReverse:!this.selectedSettings.readInReverse};break;case"v":t={vertical:!this.selectedSettings.vertical}}t&&this.setSettingsLocal(this.params,t)}}},$o={id:"readerSettings"};function Vo(e,t,a,d,i,o){return c(),v("div",$o,[s(re,{modelValue:i.isGlobalScope,"onUpdate:modelValue":t[0]||(t[0]=n=>i.isGlobalScope=n),density:"compact",label:"Scope","hide-details":"auto"},{default:l(()=>[s(F,{label:"Only this comic",value:!1}),s(F,{label:"Default for all comics",value:!0})]),_:1},8,["modelValue"]),s(re,{class:"displayRadioGroup",density:"compact",label:"Display","hide-details":"auto","model-value":e.selectedSettings.fitTo,"onUpdate:modelValue":t[1]||(t[1]=n=>o.settingsDialogChanged({fitTo:n}))},{default:l(()=>[(c(!0),v(B,null,G(e.fitToChoices,n=>(c(),_(F,{key:n.value,label:n.title,value:n.value},null,8,["label","value"]))),128))]),_:1},8,["model-value"]),s(z,{disabled:e.selectedSettings.vertical,class:"displayTwoPages",density:"compact",label:"Two pages","hide-details":"auto","model-value":e.selectedSettings.twoPages,"true-value":!0,indeterminate:e.selectedSettings.twoPages===null||e.selectedSettings.twoPages===void 0,"onUpdate:modelValue":t[2]||(t[2]=n=>o.settingsDialogChanged({twoPages:n}))},null,8,["disabled","model-value","indeterminate"]),s(ke,null,{default:l(()=>[g("Reading Direction")]),_:1}),s(pt,{class:"vertical",density:"compact",label:e.verticalLabel,"hide-details":"auto","model-value":e.selectedSettings.vertical,"true-value":!0,indeterminate:e.selectedSettings.vertical===null||e.selectedSettings.vertical===void 0,"onUpdate:modelValue":t[3]||(t[3]=n=>o.settingsDialogChanged({vertical:n}))},null,8,["label","model-value","indeterminate"]),s(z,{class:"readInReverse",density:"compact",label:"Read in Reverse","hide-details":"auto","model-value":e.selectedSettings.readInReverse,"true-value":!0,indeterminate:e.selectedSettings.readInReverse===null||e.selectedSettings.readInReverse===void 0,"onUpdate:modelValue":t[4]||(t[4]=n=>o.settingsDialogChanged({readInReverse:n}))},null,8,["model-value","indeterminate"]),i.isGlobalScope?(c(),_(z,{key:0,"model-value":e.selectedSettings.readRtlInReverse,class:"readRtlInReverse",density:"compact",label:"Read RTL comics in Reverse","hide-details":"auto","true-value":!0,"onUpdate:modelValue":t[5]||(t[5]=n=>o.settingsDialogChanged({readRtlInReverse:n}))},null,8,["model-value"])):C("",!0),i.isGlobalScope?C("",!0):(c(),_(M,{key:1,id:"clearSettingsButton",disabled:e.isClearSettingsButtonDisabled,title:"Use the default settings for all comics for this comic",onClick:t[6]||(t[6]=n=>e.clearSettingsLocal(e.params))},{default:l(()=>[g(" Clear Comic Settings ")]),_:1},8,["disabled"]))])}const Ee=m(Do,[["render",Vo],["__scopeId","data-v-72cc1f00"]]);const xo={name:"KeyboardShortcutsPanel",data(){return{mdiMenuLeft:ht,mdiMenuRight:_t,mdiKeyboardOutline:mt,mdiKeyboardSpace:kt,mdiAppleKeyboardShift:vt}},computed:{...y(D,["isMobile"])}},S=e=>(St("data-v-41483eb9"),e=e(),yt(),e),Lo=S(()=>r("h4",null,"Navigation",-1)),Oo={class:"highlight-table"},Eo=S(()=>r("td",null,"Previous page",-1)),No=S(()=>r("td",null,"Next page",-1)),Ao=S(()=>r("tr",null,[r("td",null,","),r("td",null,[g("Next "),r("em",null,"only"),g(" one page in two page mode.")])],-1)),Uo=S(()=>r("tr",null,[r("td",null,"."),r("td",null,[g("Previous "),r("em",null,"only"),g(" one page in two page mode.")])],-1)),Wo=S(()=>r("tr",null,[r("td",null,"p"),r("td",null,"Previous Book")],-1)),zo=S(()=>r("tr",null,[r("td",null,"n"),r("td",null,"Next Book")],-1)),Fo=S(()=>r("h4",null,"Fit Page To",-1)),Ho=S(()=>r("table",{class:"highlight-table"},[r("tbody",null,[r("tr",null,[r("td",null,"s"),r("td",null,"screen")]),r("tr",null,[r("td",null,"h"),r("td",null,"screen height")]),r("tr",null,[r("td",null,"w"),r("td",null,"screen width")]),r("tr",null,[r("td",null,"o"),r("td",null,"Show page at original size")]),r("tr",null,[r("td",null,"2"),r("td",null,"Toggle two page view")]),r("tr",null,[r("td",null,"r"),r("td",null,"Toggle Read in Reverse")])])],-1)),Mo=S(()=>r("h4",null,"Other",-1)),Go=S(()=>r("table",{class:"highlight-table"},[r("tbody",null,[r("tr",null,[r("td",null,"m"),r("td",null,"Show comic's metadata")]),r("tr",null,[r("td",null,"esc"),r("td",null,"Close book")])])],-1));function qo(e,t,a,d,i,o){return e.isMobile?C("",!0):(c(),_(wt,{key:0},{default:l(()=>[s(ft,{id:"readerKeyboardShortcuts"},{default:l(()=>[s(bt,{id:"shortcutsTitle"},{default:l(()=>[s(P,{id:"keyboardIcon"},{default:l(()=>[g(k(i.mdiKeyboardOutline),1)]),_:1}),g("Keyboard Shortcuts ")]),_:1}),s(Pt,null,{default:l(()=>[Lo,r("table",Oo,[r("tbody",null,[r("tr",null,[r("td",null,[s(P,{class:"keyIcon",density:"compact"},{default:l(()=>[g(k(i.mdiMenuLeft),1)]),_:1}),g(", j, "),r("div",null,[s(P,{class:"keyIcon",density:"compact"},{default:l(()=>[g(k(i.mdiAppleKeyboardShift),1)]),_:1}),s(P,{class:"keyIcon",density:"compact"},{default:l(()=>[g(k(i.mdiKeyboardSpace),1)]),_:1})])]),Eo]),r("tr",null,[r("td",null,[s(P,{class:"keyIcon",density:"compact"},{default:l(()=>[g(k(i.mdiMenuRight),1)]),_:1}),g(", k, "),s(P,{class:"keyIcon",density:"compact"},{default:l(()=>[g(k(i.mdiKeyboardSpace),1)]),_:1})]),No]),Ao,Uo,Wo,zo])]),Fo,Ho,Mo,Go]),_:1})]),_:1})]),_:1}))}const Ko=m(xo,[["render",qo],["__scopeId","data-v-41483eb9"]]),jo={name:"ReaderSettingsSuperPanel",components:{DownloadPanel:Oe,ReaderKeyboardShortcutsPanel:Ko,ReaderSettingsPanel:Ee}};function Yo(e,t,a,d,i,o){const n=Ee,h=w("ReaderKeyboardShortcutsPanel"),p=Oe;return c(),v(B,null,[s(n),s(Z),s(h),s(Z),s(p)],64)}const Xo=m(jo,[["render",Yo]]);const Jo={name:"MainReader",components:{BookChangeDrawer:Le,BooksWindow:Ve,ReaderNavToolbar:ye,ReaderTitleToolbar:xe,SettingsDrawer:ve},data(){return{showToolbars:!1,ReaderSettingsSuperPanel:ce(Xo)}},computed:{...y(Q,["isCodexViewable"]),...b(Q,{user:e=>e.user})},watch:{user(){this.loadReaderSettings()},isCodexViewable(){this.loadReaderSettings()}},created(){D().isSettingsDrawerOpen=!1,this.loadReaderSettings()},methods:{...f(u,["loadReaderSettings"]),toggleToolbars(){this.showToolbars=!this.showToolbars}}},Zo={key:0,id:"readerContainer"},Qo={key:1,id:"announcement"};function ea(e,t,a,d,i,o){const n=Le,h=xe,p=Ve,T=ye,$=w("router-link"),N=ve;return c(),v(B,null,[s(Ct,{id:"readerWrapper"},{default:l(()=>[s(n,{direction:"prev"}),e.isCodexViewable?(c(),v("div",Zo,[s(Tt,null,{default:l(()=>[O(s(h,null,null,512),[[ee,i.showToolbars]])]),_:1}),s(p,{onClick:o.toggleToolbars},null,8,["onClick"]),s(Rt,null,{default:l(()=>[O(s(T,null,null,512),[[ee,i.showToolbars]])]),_:1})])):(c(),v("div",Qo,[r("h1",null,[s($,{to:{name:"home"}},{default:l(()=>[g(" Log in ")]),_:1}),g(" to read comics ")])]))]),_:1}),s(n,{direction:"next"}),s(N,{title:"Reader Settings",panel:i.ReaderSettingsSuperPanel,temporary:""},null,8,["panel"])],64)}const sa=m(Jo,[["render",ea],["__scopeId","data-v-dff2aac6"]]);export{sa as default};
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"statusTitles":{"CCC":"Create Covers","CCD":"Remove Covers","CFO":"Find Orphan Covers","IDM":"Move Folders","IFM":"Move Books","ITR":"Read Book Tags","ITQ":"Discover Missing Tags","ITC":"Create Missing Tags","IDU":"Modify Folders","IFU":"Modify Books","IFC":"Create Books","IMQ":"Prepare Tags for Linking","IMC":"Link Books to Tags","IDD":"Remove Folders","IFD":"Remove Books","IFI":"Record Failed Imports","JTD":"Cleanup Stale Tags","JCU":"Update Codex Software","JCR":"Restart Codex","JCS":"Stop Codex","JDO":"Optimize Database","JDB":"Backup Database","JSD":"Cleanup Expired Sessions","SIX":"Search Index Clear","SIU":"Search Index Update","SID":"Search Index Remove Stale Records","SIM":"Search Index Optimize","WPO":"Poll Library"},"tasks":[{"title":"Libraries","tasks":[{"value":"poll","title":"Poll All Libraries","desc":"Update Libraries if changes detected"},{"value":"poll_force","title":"Force Update All Libraries","desc":"Forcibly update all comics in all libraries","confirm":"This can take a long time"},{"value":"force_update_all_failed_imports","title":"Update All Failed Imports","desc":"Forcibly update all failed imports in all libraries","confirm":"This can take a long time"}]},{"title":"Covers","tasks":[{"value":"purge_comic_covers","title":"Remove Comic Covers","desc":"from every library","confirm":"Are you sure?"}]},{"title":"Search Index","tasks":[{"value":"search_index_update","title":"Update Search Index","desc":"with recently changed comics"},{"value":"search_index_rebuild","title":"Rebuild Search Index","desc":"Delete and rebuild the search index from scratch","confirm":"This can take a long time"},{"value":"search_index_remove_stale","title":"Remove Stale Index Entries","desc":"Remove search index entries that are no longer in the library."},{"value":"search_index_merge_small","title":"Merge Small Search Index Segments","desc":"Improves search lookup times. Runs nightly if the Optimize Admin Flag is off."},{"value":"search_index_optimize","title":"Merge Search Index Into One Segment","desc":"Reduces disk space and improves search lookup times. Runs nightly if the Optimize Admin Flag is on.","confirm":"This can take a long time."},{"value":"search_index_abort","title":"Abort Search Indexing","desc":"Aborts search index update and remove tasks."}]},{"title":"Database","tasks":[{"value":"db_vacuum","title":"Optimize & Compact Database","desc":"Run the sqlite3 optimize & vacuum and pragmas. Runs nightly"},{"value":"db_backup","title":"Backup Database","desc":"Runs nightly"},{"value":"db_search_sync","title":"Sync Search Index to DB","desc":"Check to see if this database matches the current search index. If there is a mismatch, rebuild the search index. Runs on startup."},{"value":"watchdog_sync","title":"Sync Watchdog with DB","desc":"Ensure the Watchdog file watcher is enabled per database preferences for each library"}]},{"title":"Codex Software","tasks":[{"value":"codex_update","title":"Update Codex","desc":"If Codex updates to a new version, it will restart","confirm":"Are you sure?"},{"value":"codex_restart","title":"Restart Codex Server","desc":"Immediately","confirm":"Are you sure?"},{"value":"codex_shutdown","title":"Shutdown Codex Server","desc":"Immediately","confirm":"Are you sure?"}]},{"title":"Notify","tasks":[{"value":"notify_library_changed","title":"Notify Library Changed ","desc":"Signal all clients that the libraries have changed and the browser should fetch new data."},{"value":"notify_librarian_status","title":"Notify Librarian Status","desc":"Signal Admin clients to fetch librarian status."}]},{"title":"Cleanup","tasks":[{"value":"cleanup_fks","title":"Remove Orphan Tags","desc":"After deleting comics, unused linked objects remain in case new comics use them. Runs nightly."},{"value":"cleanup_sessions","title":"Cleanup Sessions","desc":"Remove corrupt and expired sessoions. Runs nightly."},{"value":"cleanup_covers","title":"Remove Orphan Covers","desc":"from comics that no longer exist. Runs nightly."},{"value":"librarian_clear_status","title":"Clear Librarian Statuses","desc":"Mark all Librarian tasks finished."},{"value":"janitor_nightly","title":"Run Nightly Maintenance","desc":"Runs several tasks above that also run nightly.","confirm":"Launches several tasks that run nightly anyway."}]}],"adminFlags":{"FV":"Folder View","RG":"Registration","NU":"Non Users","AU":"Auto Update","SO":"Search Index Full Optimization"}}
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"browser":{"bookmarkFilter":[{"title":"All","value":"ALL","default":true},{"title":"Unread","value":"UNREAD"},{"title":"In Progress","value":"IN_PROGRESS"},{"title":"Read","value":"READ"}],"q":"","topGroup":[{"title":"Publishers","value":"p","default":true},{"title":"Imprints","value":"i"},{"title":"Series","value":"s"},{"title":"Volumes","value":"v"},{"title":"Issues","value":"c"},{"title":"Folder View","value":"f"}],"settingsGroup":[{"title":"Publishers","value":"p","default":true},{"title":"Imprints","value":"i"},{"title":"Series","value":"s","default":true},{"title":"Volumes","value":"v"}],"orderBy":[{"title":"Name","value":"sort_name","default":true},{"title":"Publish Date","value":"date"},{"title":"Added Time","value":"created_at"},{"title":"Updated Time","value":"updated_at"},{"title":"Page Count","value":"page_count"},{"title":"File Size","value":"size"},{"title":"Filename","value":"path"},{"title":"Critical Rating","value":"critical_rating"},{"title":"Community Rating","value":"community_rating"},{"title":"Age Rating","value":"age_rating"},{"title":"Search Score","value":"search_score"}],"vuetifyNullCode":-1,"groupNames":{"p":"Publishers","i":"Imprints","s":"Series","v":"Volumes","c":"Issues","f":"Folders"},"route":{"group":"r","pk":0,"page":1}},"reader":{"fitTo":[{"title":"Fit to Screen","value":"S","default":true},{"title":"Fit to Width","value":"W"},{"title":"Fit to Height","value":"H"},{"title":"Original Size","value":"O"},{"title":"","value":""}]},"websockets":{"LIBRARY_CHANGED":"LIBRARY_CHANGED","LIBRARIAN_STATUS":"LIBRARIAN_STATUS","FAILED_IMPORTS":"FAILED_IMPORTS"}}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
codex/urls/opds/opensearch.py
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"""codex:opds:v1 URL Configuration."""
|
|
2
|
-
from django.urls import path
|
|
3
|
-
from django.views.decorators.cache import cache_page
|
|
4
|
-
|
|
5
|
-
from codex.views.opds.opensearch import OpenSearchView
|
|
6
|
-
|
|
7
|
-
TIMEOUT = 60 * 60
|
|
8
|
-
|
|
9
|
-
app_name = "opensearch"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
urlpatterns = [
|
|
13
|
-
path(
|
|
14
|
-
"/1.1",
|
|
15
|
-
cache_page(TIMEOUT)(OpenSearchView.as_view()),
|
|
16
|
-
name="1.1",
|
|
17
|
-
),
|
|
18
|
-
]
|
codex/views/opds/v1/browser.py
DELETED
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
"""OPDS browser."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime, timezone
|
|
4
|
-
|
|
5
|
-
from django.urls import reverse
|
|
6
|
-
from django.utils.http import urlencode
|
|
7
|
-
from drf_spectacular.utils import extend_schema
|
|
8
|
-
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
|
|
9
|
-
from rest_framework.response import Response
|
|
10
|
-
|
|
11
|
-
from codex.logger.logging import get_logger
|
|
12
|
-
from codex.serializers.opds.v1 import (
|
|
13
|
-
OPDS1TemplateSerializer,
|
|
14
|
-
)
|
|
15
|
-
from codex.views.browser.browser import BrowserView
|
|
16
|
-
from codex.views.opds.const import (
|
|
17
|
-
BLANK_TITLE,
|
|
18
|
-
FALSY,
|
|
19
|
-
MimeType,
|
|
20
|
-
Rel,
|
|
21
|
-
)
|
|
22
|
-
from codex.views.opds.util import update_href_query_params
|
|
23
|
-
from codex.views.opds.v1.entry import OPDS1Entry, OPDS1EntryObject
|
|
24
|
-
from codex.views.opds.v1.util import (
|
|
25
|
-
DEFAULT_FACETS,
|
|
26
|
-
Facet,
|
|
27
|
-
FacetGroups,
|
|
28
|
-
OPDSLink,
|
|
29
|
-
OpdsNs,
|
|
30
|
-
RootFacetGroups,
|
|
31
|
-
RootTopLinks,
|
|
32
|
-
TopLinks,
|
|
33
|
-
UserAgents,
|
|
34
|
-
)
|
|
35
|
-
from codex.views.template import CodexXMLTemplateView
|
|
36
|
-
|
|
37
|
-
LOG = get_logger(__name__)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class OPDS1BrowserView(BrowserView, CodexXMLTemplateView):
|
|
41
|
-
"""The main opds browser."""
|
|
42
|
-
|
|
43
|
-
authentication_classes = (BasicAuthentication, SessionAuthentication)
|
|
44
|
-
template_name = "opds/index.xml"
|
|
45
|
-
serializer_class = OPDS1TemplateSerializer
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
def opds_ns(self):
|
|
49
|
-
"""Dynamic opds namespace."""
|
|
50
|
-
try:
|
|
51
|
-
return OpdsNs.ACQUISITION if self.is_aq_feed else OpdsNs.CATALOG
|
|
52
|
-
except Exception as exc:
|
|
53
|
-
LOG.exception(exc)
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def id_tag(self):
|
|
57
|
-
"""Feed id is the url."""
|
|
58
|
-
try:
|
|
59
|
-
return self.request.build_absolute_uri()
|
|
60
|
-
except Exception as exc:
|
|
61
|
-
LOG.exception(exc)
|
|
62
|
-
|
|
63
|
-
@property
|
|
64
|
-
def title(self):
|
|
65
|
-
"""Create the feed title."""
|
|
66
|
-
result = ""
|
|
67
|
-
try:
|
|
68
|
-
if browser_title := self.obj.get("browser_title"):
|
|
69
|
-
parent_name = browser_title.get("parent_name", "All")
|
|
70
|
-
if not parent_name and self.kwargs.get("pk") == 0:
|
|
71
|
-
parent_name = "All"
|
|
72
|
-
group_name = browser_title.get("group_name")
|
|
73
|
-
result = " ".join(filter(None, (parent_name, group_name))).strip()
|
|
74
|
-
|
|
75
|
-
if not result:
|
|
76
|
-
result = BLANK_TITLE
|
|
77
|
-
except Exception as exc:
|
|
78
|
-
LOG.exception(exc)
|
|
79
|
-
return result
|
|
80
|
-
|
|
81
|
-
@property
|
|
82
|
-
def updated(self):
|
|
83
|
-
"""Hack in feed update time from cover timestamp."""
|
|
84
|
-
try:
|
|
85
|
-
if ts := self.obj.get("covers_timestamp"):
|
|
86
|
-
return datetime.fromtimestamp(ts, tz=timezone.utc)
|
|
87
|
-
except Exception as exc:
|
|
88
|
-
LOG.exception(exc)
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def items_per_page(self):
|
|
92
|
-
"""Return opensearch:itemsPerPage."""
|
|
93
|
-
try:
|
|
94
|
-
if self.params.get("q"):
|
|
95
|
-
return self.MAX_OBJ_PER_PAGE
|
|
96
|
-
except Exception as exc:
|
|
97
|
-
LOG.exception(exc)
|
|
98
|
-
|
|
99
|
-
@property
|
|
100
|
-
def total_results(self):
|
|
101
|
-
"""Return opensearch:totalResults."""
|
|
102
|
-
try:
|
|
103
|
-
if self.params.get("q"):
|
|
104
|
-
return self.obj.get("total_count", 0)
|
|
105
|
-
except Exception as exc:
|
|
106
|
-
LOG.exception(exc)
|
|
107
|
-
|
|
108
|
-
def _facet(self, kwargs, facet_group, facet_title, new_query_params):
|
|
109
|
-
href = reverse("opds:v1:browser", kwargs=kwargs)
|
|
110
|
-
facet_active = False
|
|
111
|
-
for key, val in new_query_params.items():
|
|
112
|
-
if self.request.query_params.get(key) == val:
|
|
113
|
-
facet_active = True
|
|
114
|
-
break
|
|
115
|
-
href = update_href_query_params(
|
|
116
|
-
href, self.request.query_params, new_query_params
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
title = " ".join(filter(None, (facet_group.title_prefix, facet_title))).strip()
|
|
120
|
-
return OPDSLink(
|
|
121
|
-
Rel.FACET,
|
|
122
|
-
href,
|
|
123
|
-
MimeType.NAV,
|
|
124
|
-
title=title,
|
|
125
|
-
facet_group=facet_group.query_param,
|
|
126
|
-
facet_active=facet_active,
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
def _facet_entry(self, item, facet_group, facet, query_params):
|
|
130
|
-
name = " ".join(
|
|
131
|
-
filter(None, (facet_group.glyph, facet_group.title_prefix, facet.title))
|
|
132
|
-
).strip()
|
|
133
|
-
entry_obj = OPDS1EntryObject(
|
|
134
|
-
group=item.get("group"),
|
|
135
|
-
pk=item.get("pk"),
|
|
136
|
-
name=name,
|
|
137
|
-
query_params=query_params,
|
|
138
|
-
)
|
|
139
|
-
issue_max = self.obj.get("issue_max")
|
|
140
|
-
data = (self.acquisition_groups, issue_max, False)
|
|
141
|
-
return OPDS1Entry(entry_obj, {**self.request.query_params}, data)
|
|
142
|
-
|
|
143
|
-
def _is_facet_active(self, facet_group, facet):
|
|
144
|
-
compare = [facet.value]
|
|
145
|
-
default_val = DEFAULT_FACETS.get(facet_group.query_param)
|
|
146
|
-
if facet.value == default_val:
|
|
147
|
-
compare += [None]
|
|
148
|
-
return self.request.query_params.get(facet_group.query_param) in compare
|
|
149
|
-
|
|
150
|
-
def _facet_or_facet_entry(self, facet_group, facet, entries):
|
|
151
|
-
# This logic preempts facet:activeFacet but no one uses it.
|
|
152
|
-
# don't add default facets if in default mode.
|
|
153
|
-
if self._is_facet_active(facet_group, facet):
|
|
154
|
-
return None
|
|
155
|
-
|
|
156
|
-
group = self.kwargs.get("group")
|
|
157
|
-
if (
|
|
158
|
-
facet_group.query_param == "topGroup"
|
|
159
|
-
and (group == "f" and facet.value != "f")
|
|
160
|
-
or (group != "f" and facet.value == "f")
|
|
161
|
-
):
|
|
162
|
-
kwargs = {"group": facet.value, "pk": 0, "page": 1}
|
|
163
|
-
else:
|
|
164
|
-
kwargs = self.kwargs
|
|
165
|
-
|
|
166
|
-
qps = {facet_group.query_param: facet.value}
|
|
167
|
-
if entries and self.kwargs.get("page") == 1:
|
|
168
|
-
facet = self._facet_entry(kwargs, facet_group, facet, qps)
|
|
169
|
-
else:
|
|
170
|
-
facet = self._facet(kwargs, facet_group, facet.title, qps)
|
|
171
|
-
return facet
|
|
172
|
-
|
|
173
|
-
def _facet_group(self, facet_group, entries):
|
|
174
|
-
facets = []
|
|
175
|
-
for facet in facet_group.facets:
|
|
176
|
-
if facet_obj := self._facet_or_facet_entry(facet_group, facet, entries):
|
|
177
|
-
facets += [facet_obj]
|
|
178
|
-
return facets
|
|
179
|
-
|
|
180
|
-
def _facets(self, entries=False, root=True):
|
|
181
|
-
facets = []
|
|
182
|
-
if not self.skip_order_facets:
|
|
183
|
-
facets += self._facet_group(FacetGroups.ORDER_BY, entries)
|
|
184
|
-
facets += self._facet_group(FacetGroups.ORDER_REVERSE, entries)
|
|
185
|
-
if root:
|
|
186
|
-
facets += self._facet_group(RootFacetGroups.TOP_GROUP, entries)
|
|
187
|
-
if facet_obj := self._facet_or_facet_entry(
|
|
188
|
-
RootFacetGroups.TOP_GROUP, Facet("f", "Folder View"), entries
|
|
189
|
-
):
|
|
190
|
-
facets += [facet_obj]
|
|
191
|
-
return facets
|
|
192
|
-
|
|
193
|
-
def _nav_link(self, kwargs, rel):
|
|
194
|
-
href = reverse("opds:v1:browser", kwargs={**kwargs})
|
|
195
|
-
href = update_href_query_params(href, self.request.query_params)
|
|
196
|
-
return OPDSLink(rel, href, MimeType.NAV)
|
|
197
|
-
|
|
198
|
-
def _top_link(self, top_link):
|
|
199
|
-
href = reverse("opds:v1:browser", kwargs={**top_link.kwargs, "page": 1})
|
|
200
|
-
if top_link.query_params:
|
|
201
|
-
href += "?" + urlencode(top_link.query_params, doseq=True)
|
|
202
|
-
return OPDSLink(top_link.rel, href, top_link.mime_type)
|
|
203
|
-
|
|
204
|
-
def _root_nav_links(self):
|
|
205
|
-
"""Navigation Root Links."""
|
|
206
|
-
links = []
|
|
207
|
-
if route := self.obj.get("up_route"):
|
|
208
|
-
links += [self._nav_link(route, Rel.UP)]
|
|
209
|
-
page = self.kwargs.get("page", 1)
|
|
210
|
-
if page > 1:
|
|
211
|
-
route = {**self.kwargs, "page": page - 1}
|
|
212
|
-
links += [self._nav_link(route, Rel.PREV)]
|
|
213
|
-
if page < self.obj.get("num_pages", 1):
|
|
214
|
-
route = {**self.kwargs, "page": page + 1}
|
|
215
|
-
links += [self._nav_link(route, Rel.NEXT)]
|
|
216
|
-
return links
|
|
217
|
-
|
|
218
|
-
def is_top_link_displayed(self, top_link):
|
|
219
|
-
"""Determine if this top link should be displayed."""
|
|
220
|
-
for key, value in top_link.kwargs.items():
|
|
221
|
-
if str(self.kwargs.get(key)) != str(value):
|
|
222
|
-
return False
|
|
223
|
-
|
|
224
|
-
for key, value in top_link.query_params.items():
|
|
225
|
-
if str(self.request.query_params.get(key)) != str(value):
|
|
226
|
-
return False
|
|
227
|
-
|
|
228
|
-
return True
|
|
229
|
-
|
|
230
|
-
@property
|
|
231
|
-
def links(self):
|
|
232
|
-
"""Create all the links."""
|
|
233
|
-
links = []
|
|
234
|
-
try:
|
|
235
|
-
mime_type = MimeType.ACQUISITION if self.is_aq_feed else MimeType.NAV
|
|
236
|
-
links += [
|
|
237
|
-
OPDSLink("self", self.request.get_full_path(), mime_type),
|
|
238
|
-
OPDSLink(
|
|
239
|
-
Rel.AUTHENTICATION,
|
|
240
|
-
reverse("opds:authentication:v1"),
|
|
241
|
-
MimeType.AUTHENTICATION,
|
|
242
|
-
),
|
|
243
|
-
OPDSLink("search", reverse("opds:opensearch:1.1"), MimeType.OPENSEARCH),
|
|
244
|
-
]
|
|
245
|
-
links += self._root_nav_links()
|
|
246
|
-
if self.use_facets:
|
|
247
|
-
for top_link in TopLinks.ALL + RootTopLinks.ALL:
|
|
248
|
-
if not self.is_top_link_displayed(top_link):
|
|
249
|
-
links += [self._top_link(top_link)]
|
|
250
|
-
if facets := self._facets():
|
|
251
|
-
links += facets
|
|
252
|
-
except Exception as exc:
|
|
253
|
-
LOG.exception(exc)
|
|
254
|
-
return links
|
|
255
|
-
|
|
256
|
-
def _top_link_entry(self, top_link):
|
|
257
|
-
"""Create a entry instead of a facet."""
|
|
258
|
-
name = " ".join(filter(None, (top_link.glyph, top_link.title)))
|
|
259
|
-
entry_obj = OPDS1EntryObject(
|
|
260
|
-
**top_link.kwargs,
|
|
261
|
-
name=name,
|
|
262
|
-
query_params=top_link.query_params,
|
|
263
|
-
summary=top_link.desc,
|
|
264
|
-
)
|
|
265
|
-
issue_max = self.obj.get("issue_max")
|
|
266
|
-
data = (self.acquisition_groups, issue_max, False)
|
|
267
|
-
return OPDS1Entry(entry_obj, {}, data)
|
|
268
|
-
|
|
269
|
-
def _add_top_links(self, top_links):
|
|
270
|
-
"""Add a list of top links as entries if they should be enabled."""
|
|
271
|
-
entries = []
|
|
272
|
-
for tl in top_links:
|
|
273
|
-
if not self.is_top_link_displayed(tl):
|
|
274
|
-
entries += [self._top_link_entry(tl)]
|
|
275
|
-
return entries
|
|
276
|
-
|
|
277
|
-
def _get_entries_section(self, key, metadata):
|
|
278
|
-
"""Get entries by key section."""
|
|
279
|
-
entries = []
|
|
280
|
-
issue_max = self.obj.get("issue_max")
|
|
281
|
-
data = (self.acquisition_groups, issue_max, metadata)
|
|
282
|
-
if objs := self.obj.get(key):
|
|
283
|
-
for obj in objs:
|
|
284
|
-
entries += [OPDS1Entry(obj, self.request.query_params, data)]
|
|
285
|
-
return entries
|
|
286
|
-
|
|
287
|
-
@property
|
|
288
|
-
def entries(self):
|
|
289
|
-
"""Create all the entries."""
|
|
290
|
-
entries = []
|
|
291
|
-
try:
|
|
292
|
-
at_root = self.kwargs.get("pk") == 0
|
|
293
|
-
if not self.use_facets and self.kwargs.get("page") == 1:
|
|
294
|
-
entries += self._add_top_links(TopLinks.ALL)
|
|
295
|
-
if at_root:
|
|
296
|
-
entries += self._add_top_links(RootTopLinks.ALL)
|
|
297
|
-
entries += self._facets(entries=True, root=at_root)
|
|
298
|
-
|
|
299
|
-
entries += self._get_entries_section("groups", False)
|
|
300
|
-
metadata = (
|
|
301
|
-
self.request.query_params.get("opdsMetadata", "").lower() not in FALSY
|
|
302
|
-
)
|
|
303
|
-
entries += self._get_entries_section("books", metadata)
|
|
304
|
-
except Exception as exc:
|
|
305
|
-
LOG.exception(exc)
|
|
306
|
-
return entries
|
|
307
|
-
|
|
308
|
-
def get_object(self):
|
|
309
|
-
"""Get the browser page and serialize it for this subclass."""
|
|
310
|
-
group = self.kwargs.get("group")
|
|
311
|
-
self.acquisition_groups = frozenset(self.valid_nav_groups[-2:])
|
|
312
|
-
self.is_opds_1_acquisition = group in self.acquisition_groups
|
|
313
|
-
self.is_opds_metadata = (
|
|
314
|
-
self.request.query_params.get("opdsMetadata", "").lower() not in FALSY
|
|
315
|
-
)
|
|
316
|
-
self.obj = super().get_object()
|
|
317
|
-
self.is_aq_feed = self.obj.get("model_group") == "c"
|
|
318
|
-
return self
|
|
319
|
-
|
|
320
|
-
def _detect_user_agent(self):
|
|
321
|
-
# Hacks for clients that don't support facets
|
|
322
|
-
user_agent = self.request.headers.get("User-Agent")
|
|
323
|
-
self.use_facets = False
|
|
324
|
-
self.skip_order_facets = False
|
|
325
|
-
if not user_agent:
|
|
326
|
-
return
|
|
327
|
-
for prefix in UserAgents.FACET_SUPPORT:
|
|
328
|
-
if user_agent.startswith(prefix):
|
|
329
|
-
self.use_facets = True
|
|
330
|
-
break
|
|
331
|
-
for prefix in UserAgents.CLIENT_REORDERS:
|
|
332
|
-
if user_agent.startswith(prefix):
|
|
333
|
-
self.skip_order_facets = True
|
|
334
|
-
break
|
|
335
|
-
|
|
336
|
-
@extend_schema(request=BrowserView.input_serializer_class)
|
|
337
|
-
def get(self, *args, **kwargs):
|
|
338
|
-
"""Get the feed."""
|
|
339
|
-
self.parse_params()
|
|
340
|
-
self.validate_settings()
|
|
341
|
-
self._detect_user_agent()
|
|
342
|
-
self.skip_order_facets |= self.kwargs.get("group") == "c"
|
|
343
|
-
|
|
344
|
-
obj = self.get_object()
|
|
345
|
-
serializer = self.get_serializer(obj)
|
|
346
|
-
return Response(serializer.data, content_type=self.content_type)
|