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
codex/views/reader/reader.py
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
"""Views for reading comic books."""
|
|
2
|
-
from django.db.models import F
|
|
2
|
+
from django.db.models import F, IntegerField, Value
|
|
3
3
|
from django.urls import reverse
|
|
4
4
|
from rest_framework.exceptions import NotFound
|
|
5
5
|
from rest_framework.response import Response
|
|
6
6
|
|
|
7
7
|
from codex.logger.logging import get_logger
|
|
8
|
-
from codex.models import Bookmark, Comic
|
|
9
|
-
from codex.serializers.reader import
|
|
8
|
+
from codex.models import AdminFlag, Bookmark, Comic
|
|
9
|
+
from codex.serializers.reader import ReaderComicsSerializer
|
|
10
10
|
from codex.serializers.redirect import ReaderRedirectSerializer
|
|
11
11
|
from codex.views.bookmark import BookmarkBaseView
|
|
12
12
|
from codex.views.session import BrowserSessionViewBase
|
|
13
13
|
|
|
14
14
|
LOG = get_logger(__name__)
|
|
15
|
-
PAGE_TTL = 60 * 60 * 24
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class ReaderView(BookmarkBaseView):
|
|
19
18
|
"""Get info for displaying comic pages."""
|
|
20
19
|
|
|
21
|
-
serializer_class =
|
|
20
|
+
serializer_class = ReaderComicsSerializer
|
|
22
21
|
|
|
23
22
|
SETTINGS_ATTRS = ("fit_to", "two_pages", "read_in_reverse", "vertical")
|
|
24
23
|
_COMIC_FIELDS = (
|
|
@@ -30,103 +29,234 @@ class ReaderView(BookmarkBaseView):
|
|
|
30
29
|
"volume",
|
|
31
30
|
"read_ltr",
|
|
32
31
|
)
|
|
32
|
+
_VALID_ARC_GROUPS = frozenset(("f", "s", "a"))
|
|
33
33
|
|
|
34
|
-
def
|
|
35
|
-
"""Get bookmarks and filename and append to book list."""
|
|
36
|
-
book.settings = (
|
|
37
|
-
Bookmark.objects.filter(**bookmark_filter, comic=book)
|
|
38
|
-
.only(*self.SETTINGS_ATTRS)
|
|
39
|
-
.first()
|
|
40
|
-
)
|
|
41
|
-
book.filename = book.filename()
|
|
42
|
-
books.append(book)
|
|
43
|
-
|
|
44
|
-
def _get_comic_query_params(self, pk):
|
|
34
|
+
def _get_comics_list(self):
|
|
45
35
|
"""Get the reader naviation group filter."""
|
|
46
|
-
|
|
47
|
-
top_group = session.get("top_group")
|
|
36
|
+
arc_group = self.params.get("arc_group")
|
|
48
37
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
rel = "
|
|
38
|
+
if arc_group == "a":
|
|
39
|
+
# for story arcs
|
|
40
|
+
rel = "story_arc_numbers__story_arc"
|
|
41
|
+
fields = self._COMIC_FIELDS
|
|
42
|
+
arc_name_rel = "story_arc_numbers__story_arc__name"
|
|
43
|
+
arc_pk_rel = "story_arc_numbers__story_arc__pk"
|
|
44
|
+
arc_index = F("story_arc_numbers__number")
|
|
45
|
+
ordering = ("arc_index", "date", *Comic.ORDERING)
|
|
46
|
+
elif arc_group == self.FOLDER_GROUP:
|
|
47
|
+
# folder mode
|
|
48
|
+
rel = "parent_folder"
|
|
49
|
+
fields = (*self._COMIC_FIELDS, "parent_folder")
|
|
50
|
+
arc_pk_rel = "parent_folder__pk"
|
|
51
|
+
arc_name_rel = "parent_folder__name"
|
|
52
|
+
arc_index = Value(None, IntegerField())
|
|
52
53
|
ordering = ("path", "pk")
|
|
53
|
-
select_related_fields += ["parent_folder"]
|
|
54
54
|
else:
|
|
55
|
-
|
|
55
|
+
# browser mode.
|
|
56
|
+
rel = "series"
|
|
57
|
+
fields = self._COMIC_FIELDS
|
|
58
|
+
arc_pk_rel = "series__pk"
|
|
59
|
+
arc_name_rel = "series__name"
|
|
60
|
+
arc_index = Value(None, IntegerField())
|
|
56
61
|
ordering = Comic.ORDERING
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
group_acl_filter = self.get_group_acl_filter(Comic)
|
|
64
|
+
arc_pk = self.params.get("arc_pk")
|
|
65
|
+
if not arc_pk:
|
|
66
|
+
rel += "__comic"
|
|
67
|
+
arc_pk = self.kwargs.get("pk")
|
|
68
|
+
nav_filter = {rel: arc_pk}
|
|
59
69
|
|
|
60
|
-
|
|
61
|
-
"""Get comics for the series or folder."""
|
|
62
|
-
pk = self.kwargs.get("pk")
|
|
63
|
-
group_acl_filter = self.get_group_acl_filter(True)
|
|
64
|
-
(
|
|
65
|
-
group_nav_filter,
|
|
66
|
-
ordering,
|
|
67
|
-
select_related_fields,
|
|
68
|
-
) = self._get_comic_query_params(pk)
|
|
69
|
-
|
|
70
|
-
return (
|
|
70
|
+
qs = (
|
|
71
71
|
Comic.objects.filter(group_acl_filter)
|
|
72
|
-
.filter(**
|
|
73
|
-
.
|
|
74
|
-
.only(*
|
|
72
|
+
.filter(**nav_filter)
|
|
73
|
+
.prefetch_related("story_arc_numbers__story_arc")
|
|
74
|
+
.only(*fields)
|
|
75
75
|
.annotate(
|
|
76
76
|
series_name=F("series__name"),
|
|
77
77
|
volume_name=F("volume__name"),
|
|
78
78
|
issue_count=F("volume__issue_count"),
|
|
79
79
|
)
|
|
80
|
-
.
|
|
80
|
+
.annotate(
|
|
81
|
+
arc_pk=F(arc_pk_rel),
|
|
82
|
+
arc_name=F(arc_name_rel),
|
|
83
|
+
arc_index=arc_index,
|
|
84
|
+
)
|
|
81
85
|
)
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
"""Raise not found exception."""
|
|
85
|
-
pk = self.kwargs.get("pk")
|
|
86
|
-
detail = {
|
|
87
|
-
"route": reverse("app:start"),
|
|
88
|
-
"reason": f"comic {pk} not found",
|
|
89
|
-
"serializer": ReaderRedirectSerializer,
|
|
90
|
-
}
|
|
91
|
-
raise NotFound(detail=detail)
|
|
87
|
+
return qs.order_by(*ordering)
|
|
92
88
|
|
|
93
|
-
def
|
|
94
|
-
"""Get
|
|
89
|
+
def _append_with_settings(self, book, bookmark_filter):
|
|
90
|
+
"""Get bookmarks and filename and append to book list."""
|
|
91
|
+
book.settings = (
|
|
92
|
+
Bookmark.objects.filter(**bookmark_filter, comic=book)
|
|
93
|
+
.only(*self.SETTINGS_ATTRS)
|
|
94
|
+
.first()
|
|
95
|
+
)
|
|
96
|
+
return book
|
|
97
|
+
|
|
98
|
+
def _get_book_collection(self):
|
|
99
|
+
"""Get the -1, +1 window around the current issue.
|
|
95
100
|
|
|
96
101
|
Uses iteration in python. There are some complicated ways of
|
|
97
102
|
doing this with __gt[0] & __lt[0] in the db, but I think they
|
|
98
103
|
might be even more expensive.
|
|
104
|
+
|
|
105
|
+
Yields 1 to 3 books
|
|
99
106
|
"""
|
|
100
|
-
comics = self.
|
|
107
|
+
comics = self._get_comics_list()
|
|
101
108
|
bookmark_filter = self.get_bookmark_filter()
|
|
102
|
-
|
|
103
|
-
# Select the -1, +1 window around the current issue
|
|
104
|
-
# Yields 1 to 3 books
|
|
105
|
-
books = []
|
|
109
|
+
books = {}
|
|
106
110
|
prev_book = None
|
|
107
111
|
pk = self.kwargs.get("pk")
|
|
108
112
|
for index, book in enumerate(comics):
|
|
109
|
-
book.series_index = index + 1 # type: ignore
|
|
110
113
|
if books:
|
|
111
114
|
# after match set next comic and break
|
|
112
|
-
self._append_with_settings(
|
|
115
|
+
books["next"] = self._append_with_settings(book, bookmark_filter)
|
|
113
116
|
break
|
|
114
117
|
if book.pk == pk:
|
|
115
118
|
# first match. set previous and current comic
|
|
116
119
|
if prev_book:
|
|
117
|
-
self._append_with_settings(
|
|
118
|
-
|
|
120
|
+
books["prev"] = self._append_with_settings(
|
|
121
|
+
prev_book, bookmark_filter
|
|
122
|
+
)
|
|
123
|
+
# create extra current book attrs:
|
|
124
|
+
if book.arc_index is None: # type: ignore
|
|
125
|
+
book.arc_index = index + 1 # type: ignore
|
|
126
|
+
book.filename = book.filename() # type: ignore
|
|
127
|
+
|
|
128
|
+
books["current"] = self._append_with_settings(book, bookmark_filter)
|
|
119
129
|
else:
|
|
120
130
|
# Haven't matched yet, so set the previous comic
|
|
121
131
|
prev_book = book
|
|
132
|
+
return books, comics.count()
|
|
133
|
+
|
|
134
|
+
def _get_folder_arc(self, book):
|
|
135
|
+
"""Create the folder arc."""
|
|
136
|
+
efv_flag = (
|
|
137
|
+
AdminFlag.objects.only("on")
|
|
138
|
+
.get(key=AdminFlag.FlagChoices.FOLDER_VIEW.value)
|
|
139
|
+
.on
|
|
140
|
+
)
|
|
122
141
|
|
|
123
|
-
if
|
|
142
|
+
if efv_flag:
|
|
143
|
+
folder_arc = {
|
|
144
|
+
"group": self.FOLDER_GROUP,
|
|
145
|
+
"pk": book.parent_folder.pk,
|
|
146
|
+
"name": book.parent_folder.name,
|
|
147
|
+
}
|
|
148
|
+
else:
|
|
149
|
+
folder_arc = None
|
|
150
|
+
return folder_arc
|
|
151
|
+
|
|
152
|
+
def _get_arcs(self, book):
|
|
153
|
+
"""Get all series/folder/story arcs."""
|
|
154
|
+
# create top arcs
|
|
155
|
+
folder_arc = self._get_folder_arc(book)
|
|
156
|
+
series_arc = {"group": "s", "pk": book.series.pk, "name": book.series.name}
|
|
157
|
+
|
|
158
|
+
# order top arcs
|
|
159
|
+
top_group = self.params.get("top_group")
|
|
160
|
+
if top_group == self.FOLDER_GROUP and folder_arc:
|
|
161
|
+
arc = folder_arc
|
|
162
|
+
other_arc = series_arc
|
|
163
|
+
else:
|
|
164
|
+
arc = series_arc
|
|
165
|
+
other_arc = folder_arc
|
|
166
|
+
|
|
167
|
+
arcs = []
|
|
168
|
+
arcs.append(arc)
|
|
169
|
+
if other_arc:
|
|
170
|
+
arcs.append(other_arc)
|
|
171
|
+
|
|
172
|
+
# story arcs
|
|
173
|
+
sas = []
|
|
174
|
+
for san in book.story_arc_numbers.all():
|
|
175
|
+
sa = san.story_arc
|
|
176
|
+
arc = {
|
|
177
|
+
"group": "a",
|
|
178
|
+
"pk": sa.pk,
|
|
179
|
+
"name": sa.name,
|
|
180
|
+
}
|
|
181
|
+
sas.append(arc)
|
|
182
|
+
sas = sorted(sas, key=lambda x: x["name"])
|
|
183
|
+
arcs += sas
|
|
184
|
+
return arcs
|
|
185
|
+
|
|
186
|
+
def _raise_not_found(self):
|
|
187
|
+
"""Raise not found exception."""
|
|
188
|
+
pk = self.kwargs.get("pk")
|
|
189
|
+
detail = {
|
|
190
|
+
"route": reverse("app:start"),
|
|
191
|
+
"reason": f"comic {pk} not found",
|
|
192
|
+
"serializer": ReaderRedirectSerializer,
|
|
193
|
+
}
|
|
194
|
+
raise NotFound(detail=detail)
|
|
195
|
+
|
|
196
|
+
def get_object(self):
|
|
197
|
+
"""Get the previous and next comics in a group or story arc."""
|
|
198
|
+
# Books
|
|
199
|
+
books, arc_count = self._get_book_collection()
|
|
200
|
+
|
|
201
|
+
current = books.get("current")
|
|
202
|
+
if not current:
|
|
124
203
|
self._raise_not_found()
|
|
125
204
|
|
|
126
|
-
|
|
205
|
+
prev_book = books.get("prev")
|
|
206
|
+
next_book = books.get("next")
|
|
207
|
+
books = {
|
|
208
|
+
"current": current,
|
|
209
|
+
"prev_book": prev_book,
|
|
210
|
+
"next_book": next_book,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Arcs
|
|
214
|
+
arcs = self._get_arcs(current)
|
|
215
|
+
|
|
216
|
+
arc_group = self.params.get("arc_group")
|
|
217
|
+
arc = {
|
|
218
|
+
"group": arc_group,
|
|
219
|
+
"pk": current.arc_pk, # type: ignore
|
|
220
|
+
"index": current.arc_index, # type: ignore
|
|
221
|
+
"count": arc_count,
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
"books": books,
|
|
226
|
+
"arcs": arcs,
|
|
227
|
+
"arc": arc,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
def _parse_params(self):
|
|
231
|
+
data = self.request.GET
|
|
232
|
+
|
|
233
|
+
# PARAMS
|
|
234
|
+
session = self.request.session.get(BrowserSessionViewBase.SESSION_KEY, {})
|
|
235
|
+
top_group = session.get("top_group", "s")
|
|
236
|
+
arc_group = data.get("arcGroup")
|
|
237
|
+
if not arc_group:
|
|
238
|
+
arc_group = top_group
|
|
239
|
+
|
|
240
|
+
if arc_group not in self._VALID_ARC_GROUPS:
|
|
241
|
+
arc_group = "s"
|
|
242
|
+
|
|
243
|
+
arc_pk = data.get("arcPk")
|
|
244
|
+
if arc_pk is not None:
|
|
245
|
+
arc_pk = int(arc_pk)
|
|
246
|
+
elif top_group == "a":
|
|
247
|
+
last_route = session.get("route", {})
|
|
248
|
+
arc_pk = last_route.get("pk")
|
|
249
|
+
|
|
250
|
+
params = {
|
|
251
|
+
"arc_group": arc_group,
|
|
252
|
+
"arc_pk": arc_pk,
|
|
253
|
+
"top_group": top_group,
|
|
254
|
+
}
|
|
255
|
+
self.params = params
|
|
127
256
|
|
|
128
257
|
def get(self, *args, **kwargs):
|
|
129
258
|
"""Get the book info."""
|
|
259
|
+
self._parse_params()
|
|
130
260
|
obj = self.get_object()
|
|
131
261
|
serializer = self.get_serializer(obj)
|
|
132
262
|
return Response(serializer.data)
|
codex/views/session.py
CHANGED
|
@@ -63,6 +63,7 @@ class BrowserSessionViewBase(SessionViewBaseBase):
|
|
|
63
63
|
|
|
64
64
|
SESSION_KEY = "browser" # type: ignore
|
|
65
65
|
CREATOR_PERSON_UI_FIELD = "creators"
|
|
66
|
+
STORY_ARC_UI_FIELD = "story_arcs"
|
|
66
67
|
_DYNAMIC_FILTER_DEFAULTS = {
|
|
67
68
|
"age_rating": [],
|
|
68
69
|
"characters": [],
|
|
@@ -79,7 +80,7 @@ class BrowserSessionViewBase(SessionViewBaseBase):
|
|
|
79
80
|
"q": "",
|
|
80
81
|
"read_ltr": [],
|
|
81
82
|
"series_groups": [],
|
|
82
|
-
|
|
83
|
+
STORY_ARC_UI_FIELD: [],
|
|
83
84
|
"tags": [],
|
|
84
85
|
"teams": [],
|
|
85
86
|
"year": [],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codex
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: A comic archive web server.
|
|
5
5
|
Home-page: https://github.com/ajslater/codex
|
|
6
6
|
License: GPL-3.0-only
|
|
@@ -28,27 +28,24 @@ Requires-Dist: aioprocessing (>=2.0.1,<3.0.0)
|
|
|
28
28
|
Requires-Dist: ansicolors (>=1.1,<2.0)
|
|
29
29
|
Requires-Dist: case-converter (>=1.1.0,<2.0.0)
|
|
30
30
|
Requires-Dist: channels (>=4.0.0,<5.0.0)
|
|
31
|
-
Requires-Dist: comicbox (>=0.
|
|
31
|
+
Requires-Dist: comicbox[pdf] (>=0.10.1,<0.11.0)
|
|
32
32
|
Requires-Dist: django (>=4.2,<5.0)
|
|
33
|
-
Requires-Dist: django-cors-headers (>=
|
|
33
|
+
Requires-Dist: django-cors-headers (>=4.0,<5.0)
|
|
34
34
|
Requires-Dist: django-haystack (>=3.2.1,<4.0.0)
|
|
35
35
|
Requires-Dist: django-rest-registration (>=0.8.0,<0.9.0)
|
|
36
|
-
Requires-Dist: django-vite (
|
|
36
|
+
Requires-Dist: django-vite (==2.1.1)
|
|
37
37
|
Requires-Dist: djangorestframework (>=3.11,<4.0)
|
|
38
38
|
Requires-Dist: djangorestframework-camel-case (>=1.3.0,<2.0.0)
|
|
39
39
|
Requires-Dist: drf-spectacular (>=0.26.0,<0.27.0)
|
|
40
|
-
Requires-Dist: filelock (>=3.4.2,<4.0.0)
|
|
41
|
-
Requires-Dist: filetype (>=1.0.12,<2.0.0)
|
|
42
40
|
Requires-Dist: fnvhash (>=0.1,<0.2)
|
|
43
41
|
Requires-Dist: humanfriendly (>=10.0,<11.0)
|
|
44
42
|
Requires-Dist: humanize (>=4.0.0,<5.0.0)
|
|
45
43
|
Requires-Dist: hypercorn[h3] (>=0.14.1,<0.15.0)
|
|
46
44
|
Requires-Dist: psutil (>=5.9.4,<6.0.0)
|
|
47
45
|
Requires-Dist: pycountry (>=22.1,<23.0)
|
|
48
|
-
Requires-Dist: pymupdf (>=1.21.1,<2.0.0)
|
|
49
46
|
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
|
50
47
|
Requires-Dist: requests (>=2.24,<3.0)
|
|
51
|
-
Requires-Dist: tzlocal (>=
|
|
48
|
+
Requires-Dist: tzlocal (>=5.0,<6.0)
|
|
52
49
|
Requires-Dist: watchdog (>=3.0,<4.0)
|
|
53
50
|
Requires-Dist: websocket_client (>=1.2,<2.0)
|
|
54
51
|
Requires-Dist: whitenoise[brotli] (>=6.0,<7.0)
|
|
@@ -163,45 +160,17 @@ packaged for Linux, but here are some instructions:
|
|
|
163
160
|
|
|
164
161
|
Unrar as packaged for Alpine Linux v3.14 seems to work on Alpine v3.15
|
|
165
162
|
|
|
166
|
-
Codex will also prefer to use the `unrar-cffi` package it finds it installed,
|
|
167
|
-
this is not required.
|
|
168
|
-
|
|
169
163
|
#### Windows
|
|
170
164
|
|
|
171
165
|
Windows users should use Docker to run Codex until this documentation section is
|
|
172
166
|
complete.
|
|
173
167
|
|
|
174
|
-
Codex can _probably_
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
##### Windows Linux Subsystem
|
|
179
|
-
|
|
180
|
-
Untested. Try following the instructions for [Debian](#debian) above.
|
|
181
|
-
|
|
182
|
-
##### Cygwin
|
|
168
|
+
Codex can _probably_ Windows Linux Subsystem but I haven't done personally
|
|
169
|
+
tested it yet. Try following the instructions for [Debian](#debian) above. There
|
|
170
|
+
may be outstanding platform related bugs.
|
|
183
171
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
1. Install [Cygwin](https://www.cygwin.com/).
|
|
187
|
-
2. Install wget with cygwin.
|
|
188
|
-
3. Install:
|
|
189
|
-
- python3.9+
|
|
190
|
-
- gcc
|
|
191
|
-
- gcc-g++
|
|
192
|
-
- libffi-devel
|
|
193
|
-
- libjpeg-devel
|
|
194
|
-
- libssl-devel
|
|
195
|
-
- mpfr
|
|
196
|
-
- mpc
|
|
197
|
-
- python3-devel
|
|
198
|
-
- python39-cffi
|
|
199
|
-
- python3.9-openssl with cygwin.
|
|
200
|
-
4. Using a terminal:
|
|
201
|
-
|
|
202
|
-
```sh
|
|
203
|
-
pip install wheel
|
|
204
|
-
```
|
|
172
|
+
Contributions to this documentation accepted on
|
|
173
|
+
[the outstanding issue](https://github.com/ajslater/codex/issues/76) or discord.
|
|
205
174
|
|
|
206
175
|
#### Install Codex with pip
|
|
207
176
|
|