feat: add ja.soraraw - #668
Merged
Merged
Conversation
kinboy56
marked this pull request as draft
August 3, 2026 09:54
kinboy56
marked this pull request as ready for review
August 3, 2026 22:20
kkantan
requested changes
Aug 4, 2026
Contributor
Author
|
Thanks for the review — all 6 points are addressed. Two changes go beyond the comments:
Two things the description left out, now added to it:
Search and the three listings were also checked on device. |
kkantan
requested changes
Aug 5, 2026
kkantan
approved these changes
Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sections
own search does, and the author filter
supportsAuthorSearchenables, which matches the authoralone
Implementation Notes
queried.
/search?q=is statically generated and ignores the query — the browser downloads acatalogue and filters it itself. The api host does expose
/search, but it answers 500 for everyquery (
Unknown column 'Manga.number_views' in 'ORDER BY'), and/mangasignores every queryparameter it was tried with. The dump is 13 pages of 2000 entries, about 4.7 MB over the wire
with the gzip the host serves. The walk stops at 50 matches, since matching is a substring test
over around 26000 entries. A page that can't be read ends the walk and returns what matched
before it — the 404 the dump ends with is its terminator, and that is how the site's own search
stops walking it. The first page is the exception: nothing has been collected there yet, so a
page 1 that can't be read fails the search rather than returning an empty result that reads as
"no matches".
the query when both arrive. It comes in as a text filter value rather than as part of the query,
so it is read out of the filter list.
hidesFiltersWhileSearchingdoesn't collide with it — thatsetting hides filters while a query is present, and an author search arrives with no query.
than asking the site for a page, which is what
config.hidesFiltersWhileSearchingis set for.modefield.modedescribes how the site'sown reader lays a series out, not what kind of comic it is: across 31 series measured, every
horizontalone held page-shaped art, but so did a third of theverticalones — ordinaryjapanese manga that would otherwise open in a continuous scroll. The overseas genres track the
content instead, appearing on 2 of 7021
horizontalseries and 644 of 979verticalones across8000 catalogue entries, which matches the share of
verticalseries that really are webtoons.are cut into page-shaped chunks about as often as into tall strips, so the shape of a page says
nothing about whether the panels are meant to run together.
name on the image server in a
bfield, encrypted with AES-256-CTR under a key the site'sscripts derive from the chapter uuid. An earlier revision of this PR rebuilt the names from the
order and id fields, which are handed out in the clear, and probed the extension with a HEAD
request per chapter — of 50 chapters sampled, 47 held webp and 3 held jpg. That guess was wrong
often enough to 404 whole chapters, so
decrypt_pathnow reads the real name out ofb. Thisdrops one request per chapter and makes the extension exact instead of statistical.
tried and dropped: genre names are not unique (41 of the 1834 the site lists are used by more
than one genre), and the ones that read as suggestive are already flagged as adult by the site
itself, so a name-based guess disagreed with the site more often than it added anything.
MangaStatus::Unknownratherthan falling back to ongoing.
source.
Known limitation: chapters served as one stacked image
A small share of chapters are served as a single image holding every page of the chapter stacked on
top of each other, taller than the reader can draw. This source refuses those chapters with an
error naming the height, rather than handing back a page that renders blank.
Measured on "BLUE GIANT MOMENTUM":
At least 5 of that series' 71 chapters are affected, and other series are too — "となりの黒川さん" serves
chapter 49 as one 800x24003 image holding 21 pages. Nothing in the response separates the two
cases: every chapter carries
mode: "image", and a stacked chapter lists exactly one page named001_{id}like any short chapter would, so only the shape of the image itself gives it away.get_page_listtherefore measures a chapter only when it holds four images or fewer, reading theheight off the first 16 KB with a
Rangerequest; ordinary chapters take no extra request at all.Why the pages are not split in the source
Splitting was implemented and works up to the point of display: the page count comes out right and
the cuts land exactly on the page boundaries — scanning the difference between neighbouring pixel
rows around every expected cut put all 23 boundaries of the blue giant image at an offset of 0 (row
difference 88.5 at the cuts against 15.5 inside a page), and all 20 of the kurokawa image likewise.
On device every slice still rendered blank, whether the slices were returned as
PageContent::Imagefrom
get_page_listor cut in aPageImageProcessor.The cause turned out to be in the host rather than in this source, and is filed as
Aidoku/AidokuRunner#3:
Canvas.copyImageanddrawImageconvert the destination rect using thesource image's height where they need the destination context's height, so a canvas shorter
than the image it draws from receives nothing — and the call still reports success. Confirming it
took a throwaway build that passed
dst_y = image height - canvas heightto cancel the conversionout: the compensated slices came back with real pixels (2–3 MB each, varying by offset) while the
slices asking for
dst_y = 0stayed at the same 52176 bytes of flat colour. That also rules outthe reading I had assumed first, that a 49152 px image simply fails to decode.
Compensating for the bug in this source would break the moment the host is fixed, so the slicing is
left out and the affected chapters fail loudly instead. If AidokuRunner#3 lands, restoring it is a
small change — the cut geometry is already known to be right, and the code comment on
check_drawablesays as much.Open questions
A few implementation choices were made without being able to fully verify them against the site's
behavior, and are flagged here for reviewers:
PATH_SECRET's first 8 digits read as a date (20250805). If the site rotates this valueperiodically, decryption would start failing for everyone at once on some future date. I could not
confirm whether the value is fixed or rotates, so it is currently hardcoded.
MAX_DRAWABLE_HEIGHT = 16384is a holdover from an earlier (and since disproven) theory thatthe failure was a GPU texture size limit. The real cause turned out to be the AidokuRunner Canvas
bug described above, so this threshold is not backed by a measurement and may be too conservative
or too permissive.
STRIP_IMAGE_LIMIT = 4bounds how many images a chapter can hold before it's considered forheight measurement. A stacked chapter with more than 4 listed images would skip the check and
still reach the reader as a blank page, undetected.
Test Plan
18 tests, kept in
src/test.rs, cover the functionality against the live site:it to the author column — a walk over the live dump can't tell that apart from a query, since a
query matches authors too
the site marks as
vertical, and for an adult seriesnetwork
message — reaching that point also proves the decrypted path resolved and the
Rangereadreturned the header
They are unit tests rather than integration tests: the crate is
crate-type = ["cdylib"], andadding
rlibso atests/binary coulduseit makes the library itself stop building witherror: #[panic_handler] function required, but not found.Search and the three listings were also checked on device.
Code quality checks passed:
cargo test,cargo fmt,cargo clippy, andaidoku verify.