Skip to content

Add IReader extension support to Suwayomi-Server#1784

Open
kazemcodes wants to merge 37 commits intoSuwayomi:masterfrom
kazemcodes:ireader-integration
Open

Add IReader extension support to Suwayomi-Server#1784
kazemcodes wants to merge 37 commits intoSuwayomi:masterfrom
kazemcodes:ireader-integration

Conversation

@kazemcodes
Copy link

  • Integrated IReader source-api (38 files) for novel/light novel reading
  • Created separate database tables for IReader extensions and sources
  • Implemented extension management (install, update, uninstall)
  • Added REST API endpoints under /api/v1/ireader/
  • Full parallel operation with existing Tachiyomi functionality
  • Zero breaking changes to existing code
  • Comprehensive documentation included

- Integrated IReader source-api (38 files) for novel/light novel reading
- Created separate database tables for IReader extensions and sources
- Implemented extension management (install, update, uninstall)
- Added REST API endpoints under /api/v1/ireader/
- Full parallel operation with existing Tachiyomi functionality
- Zero breaking changes to existing code
- Comprehensive documentation included
- Add IReader source API interfaces (Source, CatalogSource, HttpSource, SourceFactory)
- Implement IReader extension loading following Tachiyomi pattern
- Add database tables for IReader extensions and sources
- Add API controllers for IReader extensions and sources
- Support loading IReader Android APKs via dex2jar conversion
- Add extension management (install, uninstall, update)
- Add IReader source listing and retrieval
@Syer10
Copy link
Collaborator

Syer10 commented Nov 12, 2025

Interesting, your are the dev of IReader? I'm not against novel support for Suwayomi.

A few notes to start with.

  • We do not support the REST api anymore, endpoints should be added under the GraphQL api in the GraphQL package
  • I saw quite a bit of duplicate code, especially with the extensions installer. There should be a way to deduplicate this code so that functions can be shared between Manga and Novel extension installers.
  • I saw a few expect functions and classes. Since we are a single platform program, there should be no expect/actual, just implementations.

- Fix deprecated -Xcontext-receivers to -Xcontext-parameters
- Fix KtLint violations (package names, wildcard imports, file naming)
- Add missing findInstance extension functions
- Fix task dependencies in build.gradle.kts
- Reorganize package structure (core_api -> coreapi)
- Add comprehensive IReader documentation
@kazemcodes
Copy link
Author

yes, I'm dev of IReader, I will try to fix the issue you mentioned,
by the way thanks for creating base implementation

@kazemcodes
Copy link
Author

I complete all changes you mentioned

Interesting, your are the dev of IReader? I'm not against novel support for Suwayomi.

A few notes to start with.

  • We do not support the REST api anymore, endpoints should be added under the GraphQL api in the GraphQL package
  • I saw quite a bit of duplicate code, especially with the extensions installer. There should be a way to deduplicate this code so that functions can be shared between Manga and Novel extension installers.
  • I saw a few expect functions and classes. Since we are a single platform program, there should be no expect/actual, just implementations.

@Syer10
Copy link
Collaborator

Syer10 commented Nov 12, 2025

Its a start. I will do a more in-depth review when I have time.

The GraphQL parts are not complete but I can also tell you what's needed later.

Copy link
Collaborator

@Syer10 Syer10 left a comment

Choose a reason for hiding this comment

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

Initial round of review

import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture

class IReaderExtensionQuery {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This implementation is wrong, it should mimic the ExtensionQuery and ExtensionMutation classes.

Any query that changes the database needs to be a mutation, and (almost) all database tables should have a dedicated Query class.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This class still deviates quite a bit from the ExtensionQuery class. It doesn't implement proper sorting, filtering, and adds a bunch of useless queries. Change it to mimic the ExtensionQuery class

import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture

class IReaderNovelQuery {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a group of mutations that should be split up into multiple several files, try to mimic the Manga side when creating these variants.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not mimicing the MangaQuery class.

Copy link
Author

Choose a reason for hiding this comment

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

can you check this file again, does it now meets you expectation now?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Much better

@kazemcodes
Copy link
Author

I made some changes, when you had time check them out

@kazemcodes kazemcodes requested a review from Syer10 November 15, 2025 15:45
Copy link
Collaborator

@Syer10 Syer10 left a comment

Choose a reason for hiding this comment

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

Round 2

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we using a novelUrl instead of a database id?

Copy link
Author

Choose a reason for hiding this comment

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

The current design uses novelUrl because this mutation is intended for source-level browsing - fetching novel content directly from IReader sources without requiring the novel to be persisted in the database first. This allows users to preview content before adding novels to their library.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we using a chapter url instead of a database id?

Copy link
Author

Choose a reason for hiding this comment

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

The current design uses chapterUrl because this mutation is intended for source-level browsing - fetching chapter content directly from IReader sources without requiring the chapter to be persisted in the database first. This allows users to preview content before adding novels to their library.

import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture

class IReaderNovelQuery {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not mimicing the MangaQuery class.

@KolbyML
Copy link
Contributor

KolbyML commented Dec 10, 2025

@kazemcodes this is cool, hope you continue

# Conflicts:
#	server/build.gradle.kts
#	server/src/main/kotlin/ireader/core/http/BrowserEngine.kt
#	server/src/main/kotlin/ireader/core/http/Exception.kt
#	server/src/main/kotlin/ireader/core/http/HttpClientExtJVM.kt
#	server/src/main/kotlin/ireader/core/http/HttpClients.kt
#	server/src/main/kotlin/ireader/core/http/JS.kt
#	server/src/main/kotlin/ireader/core/http/JSFactory.kt
#	server/src/main/kotlin/ireader/core/http/PersistentCookieStore.kt
#	server/src/main/kotlin/ireader/core/http/WebViewManger.kt
#	server/src/main/kotlin/ireader/core/http/WebViewUtil.kt
#	server/src/main/kotlin/ireader/core/log/Log.kt
#	server/src/main/kotlin/ireader/core/source/CatalogSource.kt
#	server/src/main/kotlin/ireader/core/source/ErrorHandling.kt
#	server/src/main/kotlin/ireader/core/source/Ext.kt
#	server/src/main/kotlin/ireader/core/source/HttpSource.kt
#	server/src/main/kotlin/ireader/core/source/ParsedHttpSource.kt
#	server/src/main/kotlin/ireader/core/source/ParsingUtils.kt
#	server/src/main/kotlin/ireader/core/source/Source.kt
#	server/src/main/kotlin/ireader/core/source/SourceFactory.kt
#	server/src/main/kotlin/ireader/core/source/model/ChapterInfo.kt
#	server/src/main/kotlin/ireader/core/source/model/Command.kt
#	server/src/main/kotlin/ireader/core/source/model/Filter.kt
#	server/src/main/kotlin/ireader/core/source/model/FilterList.kt
#	server/src/main/kotlin/ireader/core/source/model/MangasPageInfo.kt
#	server/src/main/kotlin/ireader/core/source/model/Page.kt
#	server/src/main/kotlin/ireader/core/util/CoroutineExt.kt
#	server/src/main/kotlin/suwayomi/tachidesk/manga/MangaAPI.kt
#	server/src/main/kotlin/suwayomi/tachidesk/manga/impl/IReaderSource.kt
#	server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ireader/IReaderExtension.kt
#	server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ireader/IReaderExtensionsList.kt
#	server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ireader/IReaderGithubApi.kt
@kazemcodes
Copy link
Author

kazemcodes commented Dec 10, 2025

Looking at the recent options, I think you got hit by the dex2jar update. You can probably remove a lot of that code by adding this to the dex2jar runner.

Unless you are referencing another dex2jar issue.

there is another problem with dex2jar
this is an answer from claude opus 4.5 model
"The .dontSanitizeNames(true) is already present. The stackmap frame issue is a fundamental problem with how dex2jar converts Dalvik bytecode to JVM bytecode - it doesn't always generate correct stackmap frames for complex control flow (especially Kotlin coroutines)."

@kazemcodes
Copy link
Author

kazemcodes commented Dec 10, 2025

I think the issue is with coroutines current versions, there seems to be some problem with it, not sure, it works fine before with any issue without flag, but after I updated the my source-api module in order to create even better sources, this bug happens here ,
I decided to recode the source in something better than orginal tachi sources which handles cloudflare, ratelimit, and other stuff better

@Syer10
Copy link
Collaborator

Syer10 commented Dec 11, 2025

Try making sure the extensions don't include any dependencies in its apks. Use the Android Studio APK explorer. For example when I implemented Apollo in the Suwayomi extension it pulled in other dependencies that conflicted with the apps dependencies.
https://github.com/Suwayomi/tachiyomi-extension/blob/769c2d3b2412fc3ddb50d5a479f418215dedfd6d/src/all/tachidesk/build.gradle#L30

Otherwise that verify error sounds familiar, but I forget where.

@kazemcodes
Copy link
Author

Try making sure the extensions don't include any dependencies in its apks. Use the Android Studio APK explorer. For example when I implemented Apollo in the Suwayomi extension it pulled in other dependencies that conflicted with the apps dependencies.
https://github.com/Suwayomi/tachiyomi-extension/blob/769c2d3b2412fc3ddb50d5a479f418215dedfd6d/src/all/tachidesk/build.gradle#L30

Otherwise that verify error sounds familiar, but I forget where.

I will try to find a solution for this problem

@Syer10
Copy link
Collaborator

Syer10 commented Dec 11, 2025

I think I remember where I encountered that error before.
Keiyoushi once tested enabling proguard for the extensions but it caused the verify exception that you are talking about in Suwayomi, so it was decided not to do it and leave proguard off.

@kazemcodes
Copy link
Author

I think I remember where I encountered that error before. Keiyoushi once tested enabling proguard for the extensions but it caused the verify exception that you are talking about in Suwayomi, so it was decided not to do it and leave proguard off.

I tried multiple ways to fix this issue, and after trying every thing,I decided to not use dex2jar at all, directly using .jar files that main ireader-extensions repo create ,
the problem wasn't even in proguard rule as extensions is not using proguard rules at all, jar are faster to use in jvm

@kazemcodes
Copy link
Author

can you recheck the new file changes, I almost resolved all things you mentioned

@kazemcodes kazemcodes requested a review from Syer10 December 12, 2025 18:53
Copy link
Collaborator

Choose a reason for hiding this comment

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

This file shouldn't be added to the repo.

Copy link
Collaborator

Choose a reason for hiding this comment

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

These novels need to be in the database at this point. We cannot serve data that is not saved. They also need database ids so that we can use them later.

Copy link
Collaborator

Choose a reason for hiding this comment

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

These chapters need to be in the database at this point. We cannot serve data that is not saved. They also need database ids so that we can use them later.

import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture

class IReaderNovelQuery {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Much better

Comment on lines 129 to 143
data class IReaderChapterType(
val name: String,
val key: String,
val dateUpload: Long,
val number: Float,
val scanlator: String,
) {
constructor(chapterInfo: ChapterInfo) : this(
name = chapterInfo.name,
key = chapterInfo.key,
dateUpload = chapterInfo.dateUpload,
number = chapterInfo.number,
scanlator = chapterInfo.scanlator,
)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Chapters should be in the database

@kazemcodes
Copy link
Author

Thanks for review, I will fix the issue you mentioned later

@kazemcodes kazemcodes requested a review from Syer10 December 15, 2025 20:22
@kazemcodes
Copy link
Author

Any more issues?

@Syer10
Copy link
Collaborator

Syer10 commented Dec 21, 2025

There is still a bunch of comments that need to be addressed from my previous review

@sohilsayed
Copy link

Really looking forward for this
Keep up the good work @kazemcodes

@kaihouguide
Copy link

kaihouguide commented Jan 17, 2026

yo this is hype really waiting for LN support and maybe anime if possible it'd be the ultimate all in 1 app

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.

5 participants

Comments