Skip to content

v4.7.0 - #159

Merged
ajslater merged 428 commits into
mainfrom
develop
Jul 29, 2026
Merged

v4.7.0#159
ajslater merged 428 commits into
mainfrom
develop

Conversation

@ajslater

Copy link
Copy Markdown
Owner
  • Features
    • Metron accepts an API token instead of a username and password. Set it
      with --auth metron:key=TOKEN, the COMICBOX_METRON_KEY environment
      variable, or the online.auth.metron.key config key. The token wins if
      both are set.

* use OneOf instead of list syntax sugar for confuse

* update deps

* let yaml have raw yaml datetimes instead of strings

* use simplejson decode errors
commit 1fb394e109263188a16c4addeaab87bbdfdf882e
Author: AJ Slater <aj@slater.net>
Date:   Wed Feb 11 17:09:25 2026 -0800

    generate-schema scripts

commit fc9b4f5c27db827ae1592010b01708865cf3733e
Author: AJ Slater <aj@slater.net>
Date:   Wed Feb 11 17:09:08 2026 -0800

    format schemas

commit 9ccdf70d8c2318220c443714e509b6746f19a90e
Author: AJ Slater <aj@slater.net>
Date:   Wed Feb 11 16:39:04 2026 -0800

    fix schema

commit 1a082c52887571cd258ebbc467846461c8e9686f
Author: AJ Slater <aj@slater.net>
Date:   Wed Feb 11 13:29:02 2026 -0800

    add marshmallow jsonschema
ajslater and others added 29 commits July 19, 2026 13:24
mokkari 4.2.0 added average_rating and rating_count to the Issue model.
Map them into the native community_rating block. Unrated issues (null
average, zero count) emit nothing, and a zero count is never passed
through to the minimum=1 native field where it would clamp up to 1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
write_metadata() and BulkWriteItem accept delete_keys glom key paths,
layered onto general.delete_keys. Empty patch values are pruned on
schema load, so update-mode writes could never clear an existing tag;
delete_keys is the explicit clear mechanism. A pure-clear write may
pass an empty patch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extracted pdf pages were named from the archive type and only renamed if
the pdf reader reported the format it served. A reader that hands back a
page's embedded image instead of a one page pdf without reporting an
extension left jpeg data on disk named ".pdf".

Sniff the data's magic bytes at the pdf read boundary to fill in a format
the reader didn't report, so pages are named for what they contain. A
reported format still wins, so nothing that names correctly today changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--extract-pages RANGE with --pdf-pages pdf (or the default pdf format)
now writes one merged pdf spanning the range instead of a file per page.

The --pdf-pages help table is derived from the installed pdffile's
PageFormat enum, so it can never advertise a value the CLI rejects, and
all five modes are documented.

Also stop counting a pdf's embedded metadata (e.g. an embedded
ComicInfo.xml) as a page, which inflated the page count and left a stray
file when extracting ranges.

Requires comicbox-pdffile 0.6.3 for the read_pdf page-range argument.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- RUF036: order None last in union return types
- PLC0414: keep the explicit re-export aliases with a targeted noqa
- ISC004: parenthesize an implicit string concatenation
- PLR0917: extend the TestParser noqa to cover its positional-arg count
- Split bin/roman.py _walk_tree's scan loop into a _scan_dir helper to
  drop its cognitive complexity below threshold

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Default conversion wrote raw .ppm pixmaps that no comic reader
(including comicbox itself) recognizes as pages, yielding a zero-page
book — and --delete-orig then removed the working original. Conversion
now defaults to pixmap_jpeg whole-page renders, which also apply pdf
display rotation.

--pdf-pages image wrote rotated pages as stored — sideways or upside
down for scans relying on /Rotate (or a rotated content-stream
placement) for display. Rotated image-dominant pages are now rendered
to match the displayed orientation (pdffile 0.6.3 classify); unrotated
pages still extract their original bytes untouched.

Also store converted page images uncompressed: the compression decision
ran before pdf pages gained their image suffix, so page images were
pointlessly deflated.

Ships as v4.5.1 alongside the pdf range extraction and page naming
fixes already in NEWS; version stays 4.5.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The release ships as v4.5.0; both unreleased sections merge into one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
radon counts each assert as a branch, so the 10-assert core-fields test
ranked C (11). Group the scalar and nested-name checks into single dict
comparisons — rank B (6), same coverage, clearer failure diagnostics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
YesNoEnum was missing its YES member, so EnumBooleanField's truthy
coercion produced the string "Yes", failed the enum lookup, and got
swallowed by TrapExceptionsMeta. BlackAndWhite was dead in both
directions: monochrome could never be read from a comic nor written to
one, leaving the field impossible to set or clear. The member was
dropped in 04342a3 when YesNoField was rebased from BooleanField onto
EnumBooleanField.

Restore the original semantics: deserialize to a bool, with the schema's
Unknown meaning no value. An unset monochrome omits the tag rather than
writing Unknown, matching how every other absent field is treated.

Also fix the shared enum-boolean base, which mishandled False for Manga
as well: str(False) matched no enum member, and _serialize raised
AttributeError on any bool. Coercion now consults the enum vocabulary
first so multi-valued enums keep their extra members, then falls back to
reading the value as a boolean.

The tag had no test coverage, which is how this shipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mokkari 4.3.0 added `alt_names` to its Series and IssueSeries schemas.
Map them to comicbox reprints, the same representation MetronInfo.xml's
Series/AlternativeNames already round-trip through.

ComicVine has exposed volume `aliases` all along and comicbox ignored
them. Map those too: `get()` injects them from the volume it already
fetches for the publisher, so no extra API call.

Alternative names also feed online matching. `s_series` scores best-of
over the candidate's primary name and its aliases, and the pre-call
volume filter keeps a volume when any alias clears the threshold, so a
comic filed under a localized title matches its canonical volume.
Aliases only ever widen the gate; they cannot drop a volume the primary
name would have kept.

Metron's search results carry no alternative names — mokkari's
BasicSeries lacks the field, unlike the IssueSeries on issue detail —
so its candidates score exactly as before. Reading them at match time
would cost an API call per candidate.

The contributing-signals gate counts alternative names as candidate
series data. Since s_series can now score from them alone, omitting
them would drop W_SERIES from the renormalization denominator and
inflate the remaining signals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keys like "series:178012" mirror the urn form comicbox writes to
notes/GTIN, but were interpolated verbatim into issue-shaped URL
templates, producing broken links for ComicVine, Metron, Grand Comics
Database, and League of Comic Geeks. A new normalize_key() strips
urn/source/type prefixes (a type prefix overrides the positional id
type) and runs in create_identifier and the computed url pass, which
now also emits corrected keys, so native YAML/JSON/CLI input gets
comicvine long-code normalization too. Also: source:type:key tag
strings no longer truncate to the type word, every notes urn is read
instead of only the first, online-tagged story arcs get arc-typed
urls, and keys with unrecognized prefixes emit no url rather than a
broken one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mokkari 4.4.0 added an `api_token` parameter that authenticates with a
Bearer token and takes precedence over username/passwd. Comicbox
hard-coded "user AND password" for Metron in three places, so token
holders could not authenticate.

Reuse the generic `key` credential field rather than adding a new
`token` field: `--auth metron:key=`, `COMICBOX_METRON_KEY`, and
`online.auth.metron.key` already flowed through the CLI, env, confuse,
and redacting-repr plumbing; only the consumers needed changing.

The shared-session cache key grows to (user, password, key) so
token-only sessions do not all collide on ("", ""), which would have
made every distinct token share one account's rate-limit state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ajslater
ajslater merged commit 7f72607 into main Jul 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants