Skip to content

Yomu Comics: Fix NullPointerException on encrypted payloads - #18483

Merged
AwkwardPeak7 merged 2 commits into
keiyoushi:mainfrom
Biglongs1:yomucomics-encrypted-payloads
Aug 19, 2026
Merged

Yomu Comics: Fix NullPointerException on encrypted payloads#18483
AwkwardPeak7 merged 2 commits into
keiyoushi:mainfrom
Biglongs1:yomucomics-encrypted-payloads

Conversation

@Biglongs1

Copy link
Copy Markdown
Contributor

Closes #17914

The site now ships its library, chapter list and page payloads encrypted with CryptoJS AES. The old code looked for capitulos_lista / imagens_lista in plain text and then did matches[selectRealArray(chapterArrays)!!], so the lookup returned null and the !! threw the reported NullPointerException.

Payloads are now decrypted with lib:cryptoaes using the passphrase the site derives in its bundle. On /api/library the field holding the list is renamed often (garimpo, catalogo, ...), so the encrypted value is located by its U2FsdGVkX1 prefix instead of by name.

The series page is now read from the flight response (RSC: 1) rather than the HTML. In the HTML the ByteText chunk is split across self.__next_f.push script tags, which truncates the encrypted payload and yields an empty chapter list; the RSC body is a single stream. It is also far smaller: a large series is ~1 MB as RSC against ~16 MB as HTML.

Other changes:

  • Migrated to KeiSource.
  • Removed Utils.kt. The "pick the real array" heuristics are no longer needed now that the payload is unambiguous.
  • Rate limiting is scoped to the site host, since the images come from cdn.yomu.com.br.
  • Genres are fetched from /api/genres instead of being hardcoded.
  • contentWarning set to MIXED (the catalogue mixes regular and adult types), replacing the previous "or MIXED, please confirm" placeholder.
  • Manga and chapter URL formats are unchanged, so existing entries and reading history are preserved.

Tested on an emulator with Mihon: popular, latest, text search, URL search, filters, details, chapter list and reading pages.

Checklist:

  • Updated versionCode value in build.gradle.kts
  • Updated baseVersionCode in build.gradle.kts (if updated multisrc theme code)
  • Referenced all related issues in the PR body (e.g. "Closes #xyz")
  • Set the contentWarning configuration in build.gradle.kts appropriately
  • Have not changed source names
  • Have explicitly kept the id if a source's name or language were changed
  • Have tested the modifications by compiling and running the extension through Android Studio
  • Have removed web_hi_res_512.png when adding a new extension
  • This PR is AI-assisted, I have reviewed the changes manually and confirmed they are not slop

The site now ships its library, chapter and page payloads encrypted with CryptoJS AES, so the old plain-text lookups returned null. Decrypts them with lib:cryptoaes, reads the series page from the flight response and migrates the source to KeiSource.
abstract class YomuComics : KeiSource() {

override val supportsLatest = true
private val siteHost: String by lazy { baseUrl.toHttpUrl().host }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private val siteHost: String by lazy { baseUrl.toHttpUrl().host }
private val siteHost: String get() = baseUrl.toHttpUrl().host

also inline it


override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
private val rscHeaders: Headers by lazy { headers.newBuilder().set("RSC", "1").build() }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private val rscHeaders: Headers by lazy { headers.newBuilder().set("RSC", "1").build() }
private val rscHeaders: Headers get() = headersBuilder().set("RSC", "1").build()

name = title?.takeIf(String::isNotBlank) ?: "Capítulo $label"
chapter_number = number.toFloat()
date_upload = parseChapterDate(releaseAt, releaseDate)
date_upload = releaseAt?.let(Instant::parseOrNull)?.toEpochMilliseconds() ?: releaseDate.toTimestamp()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the date utils
Instant.tryParse
DATE_FORMAT.tryParseDate

name = title?.takeUnless { it.isBlank() } ?: "Capítulo $chapterNumberLabel"
fun toSChapter(mangaSlug: String) = SChapter.create().apply {
val label = number.formatted()
url = "/ler/$mangaSlug/$label?chapterId=$id"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps save just the id in url and save rest of required data in memo

Use the date utils, store the chapter id in the url with the rest in memo, and turn siteHost/rscHeaders into getters.
@AwkwardPeak7
AwkwardPeak7 merged commit 1132e6b into keiyoushi:main Aug 19, 2026
3 checks passed
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Aug 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Yomu Comics is throwing a NullPointerException

2 participants