codex 1.4.0a1__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/create.py +6 -8
- 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 +41 -5
- codex/librarian/importer/importerd.py +34 -11
- 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-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-c603e996.ab2d147c9ae1.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-c603e996.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.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.c0e270b2e6b6.json → manifest.d2f93a519ada.json} +32 -32
- codex/static_root/manifest.d2f93a519ada.json.br +0 -0
- codex/static_root/manifest.d2f93a519ada.json.gz +0 -0
- codex/static_root/manifest.json +32 -32
- 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/bookmark.py +2 -2
- codex/views/browser/base.py +23 -7
- codex/views/browser/browser.py +51 -41
- codex/views/browser/browser_annotations.py +159 -50
- codex/views/browser/browser_order_by.py +50 -106
- 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.0a1.dist-info → codex-1.4.1.dist-info}/METADATA +10 -41
- {codex-1.4.0a1.dist-info → codex-1.4.1.dist-info}/RECORD +172 -170
- codex/librarian/importer/db_ops.py +0 -251
- codex/pdf.py +0 -115
- codex/static_root/assets/admin-75c007ce.199fccf24c8d.js +0 -48
- codex/static_root/assets/admin-75c007ce.199fccf24c8d.js.br +0 -0
- codex/static_root/assets/admin-75c007ce.199fccf24c8d.js.gz +0 -0
- codex/static_root/assets/admin-75c007ce.js +0 -48
- codex/static_root/assets/admin-75c007ce.js.br +0 -0
- codex/static_root/assets/admin-75c007ce.js.gz +0 -0
- codex/static_root/assets/admin-848d48b1.5de8a0c45636.css +0 -1
- codex/static_root/assets/admin-848d48b1.5de8a0c45636.css.br +0 -0
- codex/static_root/assets/admin-848d48b1.5de8a0c45636.css.gz +0 -0
- codex/static_root/assets/admin-848d48b1.css +0 -1
- codex/static_root/assets/admin-848d48b1.css.br +0 -0
- codex/static_root/assets/admin-848d48b1.css.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-a110c068.edf187333272.js +0 -1
- codex/static_root/assets/admin-drawer-panel-a110c068.edf187333272.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-a110c068.edf187333272.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-a110c068.js +0 -1
- codex/static_root/assets/admin-drawer-panel-a110c068.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-a110c068.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-2c2380fd.8b515af7a743.js +0 -1
- codex/static_root/assets/browser-2c2380fd.8b515af7a743.js.br +0 -0
- codex/static_root/assets/browser-2c2380fd.8b515af7a743.js.gz +0 -0
- codex/static_root/assets/browser-2c2380fd.js +0 -1
- codex/static_root/assets/browser-2c2380fd.js.br +0 -0
- codex/static_root/assets/browser-2c2380fd.js.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/http-error-402decbe.9ea8de1df13f.js +0 -1
- codex/static_root/assets/http-error-402decbe.9ea8de1df13f.js.br +0 -0
- codex/static_root/assets/http-error-402decbe.9ea8de1df13f.js.gz +0 -0
- codex/static_root/assets/http-error-402decbe.js +0 -1
- codex/static_root/assets/http-error-402decbe.js.br +0 -0
- codex/static_root/assets/http-error-402decbe.js.gz +0 -0
- codex/static_root/assets/main-a7f327e9.6641fe833335.js +0 -1
- codex/static_root/assets/main-a7f327e9.6641fe833335.js.br +0 -0
- codex/static_root/assets/main-a7f327e9.6641fe833335.js.gz +0 -0
- codex/static_root/assets/main-a7f327e9.js +0 -1
- codex/static_root/assets/main-a7f327e9.js.br +0 -0
- codex/static_root/assets/main-a7f327e9.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-8a0bd8e1.c213b08d582f.js +0 -1
- codex/static_root/assets/metadata-dialog-8a0bd8e1.c213b08d582f.js.br +0 -0
- codex/static_root/assets/metadata-dialog-8a0bd8e1.c213b08d582f.js.gz +0 -0
- codex/static_root/assets/metadata-dialog-8a0bd8e1.js +0 -1
- codex/static_root/assets/metadata-dialog-8a0bd8e1.js.br +0 -0
- codex/static_root/assets/metadata-dialog-8a0bd8e1.js.gz +0 -0
- codex/static_root/assets/page-pdf-c603e996.ab2d147c9ae1.js.br +0 -0
- codex/static_root/assets/page-pdf-c603e996.ab2d147c9ae1.js.gz +0 -0
- codex/static_root/assets/page-pdf-c603e996.js.br +0 -0
- codex/static_root/assets/page-pdf-c603e996.js.gz +0 -0
- codex/static_root/assets/reader-c2965a5f.b011260169f7.js +0 -1
- codex/static_root/assets/reader-c2965a5f.b011260169f7.js.br +0 -0
- codex/static_root/assets/reader-c2965a5f.b011260169f7.js.gz +0 -0
- codex/static_root/assets/reader-c2965a5f.js +0 -1
- codex/static_root/assets/reader-c2965a5f.js.br +0 -0
- codex/static_root/assets/reader-c2965a5f.js.gz +0 -0
- codex/static_root/assets/reader-d8534888.2821de925986.css +0 -1
- codex/static_root/assets/reader-d8534888.2821de925986.css.br +0 -0
- codex/static_root/assets/reader-d8534888.2821de925986.css.gz +0 -0
- codex/static_root/assets/reader-d8534888.css +0 -1
- codex/static_root/assets/reader-d8534888.css.br +0 -0
- codex/static_root/assets/reader-d8534888.css.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.c0e270b2e6b6.json.br +0 -0
- codex/static_root/manifest.c0e270b2e6b6.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.0a1.dist-info → codex-1.4.1.dist-info}/LICENSE +0 -0
- {codex-1.4.0a1.dist-info → codex-1.4.1.dist-info}/WHEEL +0 -0
- {codex-1.4.0a1.dist-info → codex-1.4.1.dist-info}/entry_points.txt +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.pageChangeColumn[data-v-29292846]{position:fixed;height:100%;width:33vw}.pageChangeRow[data-v-29292846]{position:fixed;height:33vh;width:100%}.prev[data-v-29292846]{left:0px;cursor:w-resize}.prevVertical[data-v-29292846]{top:0px;cursor:n-resize}.next[data-v-29292846]{right:0px;cursor:e-resize}.nextVertical[data-v-29292846]{bottom:0px;cursor:s-resize}.pageLoading[data-v-13c9bf0b]{display:inline-flex;height:100vh;width:100vw;justify-content:center;align-items:center}.twoPages[data-v-13c9bf0b]{max-width:50vw}.pagePlaceholder[data-v-13c9bf0b]{height:50%!important;width:50%!important}.pageError[data-v-3f1e3f4f]{display:inline-block;height:100vh}.twoPages[data-v-3f1e3f4f]{max-width:50vw}.pageErrorContainer[data-v-3f1e3f4f]{display:grid;place-items:center;height:100%}.pageErrorText[data-v-3f1e3f4f]{position:relative;text-align:center;font-size:4vw;color:rgb(var(--v-theme-textDisabled));padding:.5em}.pageErrorIcon[data-v-3f1e3f4f]{color:rgb(var(--v-theme-error));width:75%;height:75%;opacity:.33}.pageErrorText[data-v-3f1e3f4f],.pageErrorIcon[data-v-3f1e3f4f]{grid-row:1;grid-column:1}.fitToScreen[data-v-5997abff],.fitToScreenTwo[data-v-5997abff]{height:100vh;object-fit:contain}.fitToScreenTwoVertical[data-v-5997abff]{height:50vh;object-fit:contain}.fitToScreen[data-v-5997abff]{width:100vw}.fitToHeight[data-v-5997abff],.fitToHeightTwo[data-v-5997abff]{height:100vh}.fitToHeightTwoVertical[data-v-5997abff]{height:50vh}.fitToWidth[data-v-5997abff]{width:100vw}.fitToWidthTwo[data-v-5997abff]{width:50vw}.fitToWidthTwoVertical[data-v-5997abff]{width:100vw}.fitToScreenTwo[data-v-5997abff]{max-width:50vw}.fitToOrig[data-v-5997abff],.fitToOrigTwo[data-v-5997abff],.fitToOrigTwoVertical[data-v-5997abff]{object-fit:none}.pageHorizontal[data-v-f9e0354b]{display:inline;font-size:0}.pageVertical[data-v-f9e0354b]{display:block;font-size:0}.windowItem[data-v-da9ab604]{font-size:0}[data-v-91a60a25] .v-virtual-scroll__item{position:relative}.pageTracker[data-v-91a60a25]{position:absolute;top:0;left:0;z-index:15;width:95vw;height:100%}.v-virtual-scroll{display:block;flex:1 1 auto;max-width:100%;overflow:auto;position:relative}.v-virtual-scroll__container{display:block}.bookChangeColumn[data-v-2a8ea6a5]{position:fixed;height:100%;width:33vw}.prev[data-v-2a8ea6a5]{cursor:n-resize;left:0px}.next[data-v-2a8ea6a5]{cursor:s-resize;right:0px}[data-v-ca6f1824] .windowItem{min-height:100vh;text-align:center}[data-v-ca6f1824] .v-window__controls{position:fixed;top:48px;height:calc(100vh - 96px);padding:0}#readerTopToolbar[data-v-4075b1a2]{width:100%;top:0px;padding-top:env(safe-area-inset-top);padding-left:calc(env(safe-area-inset-left)/2);padding-right:calc(env(safe-area-inset-right)/2);z-index:20}[data-v-4075b1a2] .v-toolbar__content{padding:0}#toolbarTitle[data-v-4075b1a2]{font-size:clamp(8pt,2.5vw,18pt);line-height:normal}[data-v-4075b1a2] .v-toolbar-title__placeholder{text-overflow:clip;white-space:normal}#seriesPosition[data-v-4075b1a2]{padding-left:10px;padding-right:10px;color:rgb(var(--v-theme-textSecondary));text-align:center}#tagButton[data-v-4075b1a2]{min-width:24px;height:24px;width:24px;margin:0}@media (max-width: 959.98px){#closeBook[data-v-4075b1a2]{min-width:32px}#tagButton[data-v-4075b1a2]{padding-left:2px;padding-right:2px;min-width:16px}#settingsButton[data-v-4075b1a2]{padding-left:2px;padding-right:2px}#seriesPosition[data-v-4075b1a2]{padding-left:0;padding-right:0}}.prev[data-v-33b1e110]{cursor:n-resize;left:0px}.next[data-v-33b1e110]{cursor:s-resize;right:0px}.navLink[data-v-33b1e110]{display:block;height:100%}.bookChangeIcon[data-v-33b1e110]{top:50%;left:50%;transform:translate(-50%) translateY(-50%);height:25%;width:25%;color:#fff}.bookChangeDrawer{width:33vw!important;opacity:.75!important;z-index:15!important}#downloadPanel[data-v-c3777662]{background-color:rgb(var(--v-theme-background))}#readerSettings[data-v-72cc1f00]{padding-top:10px;padding-left:15px;padding-right:env(safe-area-inset-right);padding-bottom:10px;background-color:inherit}.displayRadioGroup[data-v-72cc1f00]{margin-top:15px}.displayTwoPages[data-v-72cc1f00]{margin-top:5px;margin-bottom:10px}.readRtlInReverse[data-v-72cc1f00]{transition:visibility .25s,opacity .25s}#clearSettingsButton[data-v-72cc1f00]{margin-bottom:4px;transition:visibility .25s,opacity .25s}.v-radio-group>.v-input__control{flex-direction:column}.v-radio-group>.v-input__control>.v-label{margin-inline-start:8px}.v-radio-group>.v-input__control>.v-label+.v-selection-control-group{margin-top:8px}#readerKeyboardShortcuts[data-v-41483eb9]{background-color:rgb(var(--v-theme-background))}#shortcutsTitle[data-v-41483eb9]{padding:0 10px 0 17px;font-size:16px}#keyboardIcon[data-v-41483eb9]{margin-right:.33em!important;color:rgb(var(--v-theme-textDisabled))}[data-v-41483eb9] .v-expansion-panel-title--active{min-height:48px!important}[data-v-41483eb9] .v-expansion-panel-text__wrapper{padding-left:10px;padding-right:10px}.highlight-table[data-v-41483eb9]{margin-top:10px;border-collapse:collapse;color:rgb(var(--v-theme-textDisabled))}h4[data-v-41483eb9]{padding-left:.5em;color:rgb(var(--v-theme-textSecondary))}.highlight-table tr[data-v-41483eb9]:nth-child(odd){background-color:rgb(var(--v-theme-surface))!important}.highlight-table td[data-v-41483eb9]{min-width:60px;padding:5px}.highlight-table td[data-v-41483eb9]:first-child{text-align:center}.keyIcon[data-v-41483eb9]{margin:0}#readerContainer[data-v-dff2aac6]{max-width:100%;position:relative}#announcement[data-v-dff2aac6]{text-align:center}
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.pageChangeColumn[data-v-29292846]{position:fixed;height:100%;width:33vw}.pageChangeRow[data-v-29292846]{position:fixed;height:33vh;width:100%}.prev[data-v-29292846]{left:0px;cursor:w-resize}.prevVertical[data-v-29292846]{top:0px;cursor:n-resize}.next[data-v-29292846]{right:0px;cursor:e-resize}.nextVertical[data-v-29292846]{bottom:0px;cursor:s-resize}.pageLoading[data-v-13c9bf0b]{display:inline-flex;height:100vh;width:100vw;justify-content:center;align-items:center}.twoPages[data-v-13c9bf0b]{max-width:50vw}.pagePlaceholder[data-v-13c9bf0b]{height:50%!important;width:50%!important}.pageError[data-v-3f1e3f4f]{display:inline-block;height:100vh}.twoPages[data-v-3f1e3f4f]{max-width:50vw}.pageErrorContainer[data-v-3f1e3f4f]{display:grid;place-items:center;height:100%}.pageErrorText[data-v-3f1e3f4f]{position:relative;text-align:center;font-size:4vw;color:rgb(var(--v-theme-textDisabled));padding:.5em}.pageErrorIcon[data-v-3f1e3f4f]{color:rgb(var(--v-theme-error));width:75%;height:75%;opacity:.33}.pageErrorText[data-v-3f1e3f4f],.pageErrorIcon[data-v-3f1e3f4f]{grid-row:1;grid-column:1}.fitToScreen[data-v-5997abff],.fitToScreenTwo[data-v-5997abff]{height:100vh;object-fit:contain}.fitToScreenTwoVertical[data-v-5997abff]{height:50vh;object-fit:contain}.fitToScreen[data-v-5997abff]{width:100vw}.fitToHeight[data-v-5997abff],.fitToHeightTwo[data-v-5997abff]{height:100vh}.fitToHeightTwoVertical[data-v-5997abff]{height:50vh}.fitToWidth[data-v-5997abff]{width:100vw}.fitToWidthTwo[data-v-5997abff]{width:50vw}.fitToWidthTwoVertical[data-v-5997abff]{width:100vw}.fitToScreenTwo[data-v-5997abff]{max-width:50vw}.fitToOrig[data-v-5997abff],.fitToOrigTwo[data-v-5997abff],.fitToOrigTwoVertical[data-v-5997abff]{object-fit:none}.pageHorizontal[data-v-f9e0354b]{display:inline;font-size:0}.pageVertical[data-v-f9e0354b]{display:block;font-size:0}.windowItem[data-v-da9ab604]{font-size:0}[data-v-91a60a25] .v-virtual-scroll__item{position:relative}.pageTracker[data-v-91a60a25]{position:absolute;top:0;left:0;z-index:15;width:95vw;height:100%}.v-virtual-scroll{display:block;flex:1 1 auto;max-width:100%;overflow:auto;position:relative}.v-virtual-scroll__container{display:block}.bookChangeColumn[data-v-2a8ea6a5]{position:fixed;height:100%;width:33vw}.prev[data-v-2a8ea6a5]{cursor:n-resize;left:0px}.next[data-v-2a8ea6a5]{cursor:s-resize;right:0px}[data-v-ca6f1824] .windowItem{min-height:100vh;text-align:center}[data-v-ca6f1824] .v-window__controls{position:fixed;top:48px;height:calc(100vh - 96px);padding:0}#readerTopToolbar[data-v-4075b1a2]{width:100%;top:0px;padding-top:env(safe-area-inset-top);padding-left:calc(env(safe-area-inset-left)/2);padding-right:calc(env(safe-area-inset-right)/2);z-index:20}[data-v-4075b1a2] .v-toolbar__content{padding:0}#toolbarTitle[data-v-4075b1a2]{font-size:clamp(8pt,2.5vw,18pt);line-height:normal}[data-v-4075b1a2] .v-toolbar-title__placeholder{text-overflow:clip;white-space:normal}#seriesPosition[data-v-4075b1a2]{padding-left:10px;padding-right:10px;color:rgb(var(--v-theme-textSecondary));text-align:center}#tagButton[data-v-4075b1a2]{min-width:24px;height:24px;width:24px;margin:0}@media (max-width: 959.98px){#closeBook[data-v-4075b1a2]{min-width:32px}#tagButton[data-v-4075b1a2]{padding-left:2px;padding-right:2px;min-width:16px}#settingsButton[data-v-4075b1a2]{padding-left:2px;padding-right:2px}#seriesPosition[data-v-4075b1a2]{padding-left:0;padding-right:0}}.prev[data-v-33b1e110]{cursor:n-resize;left:0px}.next[data-v-33b1e110]{cursor:s-resize;right:0px}.navLink[data-v-33b1e110]{display:block;height:100%}.bookChangeIcon[data-v-33b1e110]{top:50%;left:50%;transform:translate(-50%) translateY(-50%);height:25%;width:25%;color:#fff}.bookChangeDrawer{width:33vw!important;opacity:.75!important;z-index:15!important}#downloadPanel[data-v-c3777662]{background-color:rgb(var(--v-theme-background))}#readerSettings[data-v-72cc1f00]{padding-top:10px;padding-left:15px;padding-right:env(safe-area-inset-right);padding-bottom:10px;background-color:inherit}.displayRadioGroup[data-v-72cc1f00]{margin-top:15px}.displayTwoPages[data-v-72cc1f00]{margin-top:5px;margin-bottom:10px}.readRtlInReverse[data-v-72cc1f00]{transition:visibility .25s,opacity .25s}#clearSettingsButton[data-v-72cc1f00]{margin-bottom:4px;transition:visibility .25s,opacity .25s}.v-radio-group>.v-input__control{flex-direction:column}.v-radio-group>.v-input__control>.v-label{margin-inline-start:8px}.v-radio-group>.v-input__control>.v-label+.v-selection-control-group{margin-top:8px}#readerKeyboardShortcuts[data-v-41483eb9]{background-color:rgb(var(--v-theme-background))}#shortcutsTitle[data-v-41483eb9]{padding:0 10px 0 17px;font-size:16px}#keyboardIcon[data-v-41483eb9]{margin-right:.33em!important;color:rgb(var(--v-theme-textDisabled))}[data-v-41483eb9] .v-expansion-panel-title--active{min-height:48px!important}[data-v-41483eb9] .v-expansion-panel-text__wrapper{padding-left:10px;padding-right:10px}.highlight-table[data-v-41483eb9]{margin-top:10px;border-collapse:collapse;color:rgb(var(--v-theme-textDisabled))}h4[data-v-41483eb9]{padding-left:.5em;color:rgb(var(--v-theme-textSecondary))}.highlight-table tr[data-v-41483eb9]:nth-child(odd){background-color:rgb(var(--v-theme-surface))!important}.highlight-table td[data-v-41483eb9]{min-width:60px;padding:5px}.highlight-table td[data-v-41483eb9]:first-child{text-align:center}.keyIcon[data-v-41483eb9]{margin:0}#readerContainer[data-v-dff2aac6]{max-width:100%;position:relative}#announcement[data-v-dff2aac6]{text-align:center}
|
|
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)
|