Compare commits

...

18 Commits

Author SHA1 Message Date
renovate[bot]
bd8ec479bc Update graphqlkotlin to v8.9.0 2026-04-16 10:12:53 +00:00
Shozikan
a11e5e623d [skip ci] Chore: Added Moku to README & Quick Grammar/Formatting Fixes (#1935)
* Chore: Added Moku to README & Quick Grammar/Formatting Fixes

* Chore: Updated README with Moku Desc Changes
2026-03-31 16:43:51 -04:00
renovate[bot]
489ffa1679 Update dependency io.github.oshai:kotlin-logging-jvm to v8 (#1913)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-20 20:09:45 -05:00
David Brochero
f977d181a8 fix: default body to empty string if not present for FlareSolverr POST requests (#1915)
* fix: convert `RequestBody` to `FormBody` in FlareSolverr `POST` requests

* linting

* ref: don't convert json to form

* remove unused import
2026-02-20 20:09:34 -05:00
David Brochero
2249d237dd fix: support for POST requests on CloudflareInterceptor (#1909)
* fix: support for POST requests

Works with Flaresolverr. Required for Kagane.

Byparr is not a drop-in replacement, it just ignores the `cmd`  and interprets everything as a GET request.

* Use encodeToString instead

* linting

* Use FormBody for encoding

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Add missing imports

* linting, again

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
2026-02-18 18:51:07 -05:00
renovate[bot]
c52457c80e Update dependency com.auth0:java-jwt to v4.5.1 (#1910)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:50:22 -05:00
renovate[bot]
3904cbf789 Update plugin download to v5.7.0 (#1908)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:50:10 -05:00
renovate[bot]
759ae9fca0 Update moko to v0.26.0 (#1907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:49:57 -05:00
renovate[bot]
06954591c7 Update dependency org.postgresql:postgresql to v42.7.10 (#1904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:49:47 -05:00
renovate[bot]
bbdae74567 Update dependency net.lingala.zip4j:zip4j to v2.11.6 (#1902)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:49:27 -05:00
renovate[bot]
154e54d833 Update dependency ch.qos.logback:logback-classic to v1.5.32 (#1901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-18 18:49:21 -05:00
Weblate (bot)
f18e0f4a62 Translations update from Hosted Weblate (#1845)
* Weblate translations

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Micka149 <dr.mischutckin2017@yandex.ru>
Co-authored-by: Roland Vezsenyi <miscogd5yf2paqvxvc@farvoid.com>
Co-authored-by: Syer10 <Mitchellptbo@gmail.com>
Co-authored-by: TheRay82 <raycoc1382@gmail.com>
Co-authored-by: UnknownSkyrimPasserby <f7022961@opayq.com>
Co-authored-by: 圭紫 <kaceykoo@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/suwayomi/suwayomi-server/ja/
Translate-URL: https://hosted.weblate.org/projects/suwayomi/suwayomi-server/pl/
Translate-URL: https://hosted.weblate.org/projects/suwayomi/suwayomi-server/ru/
Translation: Suwayomi/Suwayomi-Server

* Deleted translation using Weblate (Hungarian)

---------

Co-authored-by: Micka149 <dr.mischutckin2017@yandex.ru>
Co-authored-by: Roland Vezsenyi <miscogd5yf2paqvxvc@farvoid.com>
Co-authored-by: Syer10 <Mitchellptbo@gmail.com>
Co-authored-by: TheRay82 <raycoc1382@gmail.com>
Co-authored-by: UnknownSkyrimPasserby <f7022961@opayq.com>
Co-authored-by: 圭紫 <kaceykoo@gmail.com>
2026-02-14 11:38:22 -05:00
Constantin Piber
2b19bc850d Introduce Rect.set (#1900)
* Introduce `Rect.set`

As used by Young Jump+

Also fixes the `Rect(Rect)` constructor to use the correct values

* Missing line
2026-02-14 11:36:28 -05:00
renovate[bot]
a0fb30a3ad Update jte to v3.2.3 (#1862)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 11:36:16 -05:00
renovate[bot]
e5387ff5f7 Update kotlin to v2.3.10 (#1896)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 11:35:52 -05:00
renovate[bot]
123d8a2637 Update serialization to v1.10.0 (#1866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 11:35:38 -05:00
renovate[bot]
6c72659bd8 Update dependency com.android.tools.build:apksig to v9 (#1859)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 11:35:30 -05:00
Mitchell Syer
44d89506d4 [skip ci] Fix Wiki PR Check (#1897) 2026-02-08 15:23:40 -05:00
7 changed files with 94 additions and 34 deletions

View File

@@ -7,7 +7,7 @@ on:
paths: [docs/**, .github/workflows/wiki.yml]
concurrency:
group: wiki
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:

View File

@@ -37,13 +37,27 @@ public final class Rect {
this.right = 0;
this.bottom = 0;
} else {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.left = r.left;
this.top = r.top;
this.right = r.right;
this.bottom = r.bottom;
}
}
public void set(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public void set(Rect r) {
this.left = r.left;
this.top = r.top;
this.right = r.right;
this.bottom = r.bottom;
}
public final int getWidth() {
return right - left;
}

View File

@@ -3,7 +3,7 @@
|-----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| ![CI](https://github.com/Suwayomi/Suwayomi-Server/actions/workflows/build_push.yml/badge.svg) | [![stable release](https://img.shields.io/github/release/Suwayomi/Suwayomi-Server.svg?maxAge=3600&label=download)](https://github.com/Suwayomi/Suwayomi-Server/releases) | [![preview](https://img.shields.io/badge/dynamic/json?url=https://github.com/Suwayomi/Suwayomi-Server-preview/raw/main/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Suwayomi-Server-preview/releases/latest) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) |
## Table of Content
## Table of Contents
- [What is Suwayomi?](#what-is-suwayomi)
- [Features](#features)
- [Suwayomi client projects](#suwayomi-client-projects)
@@ -65,7 +65,7 @@ You can use Mihon (Tachiyomi) to access your Suwayomi-Server. For more info look
- Automated WebUI updates (supports the default WebUI and VUI)
- OPDS and OPDS-PSE support (endpoint: `/api/opds/v1.2`)
# Suwayomi client projects
# Suwayomi Client Projects
**You need a client/user interface app as a front-end for Suwayomi-Server, if you [Directly Download Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server/releases/latest) you'll get a bundled version of [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI) with it.**
Here's a list of known clients/user interfaces for Suwayomi-Server (checkout the respective GitHub repository for their features):
@@ -73,6 +73,7 @@ Here's a list of known clients/user interfaces for Suwayomi-Server (checkout the
- [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI): The web front-end that Suwayomi-Server ships with by default.
- [Suwayomi-VUI](https://github.com/Suwayomi/Suwayomi-VUI): A Suwayomi-Server preview focused web frontend built with svelte
- [Tachidesk-VaadinUI](https://github.com/Suwayomi/Tachidesk-VaadinUI): A Web front-end for Suwayomi-Server built with Vaadin.
- [Moku](https://github.com/Youwes09/Moku): A fast, minimal Tauri + Svelte desktop client with clean and minimal UI.
##### Inactive Clients (functional but outdated)
- [Tachidesk-JUI](https://github.com/Suwayomi/Tachidesk-JUI): The native desktop front-end for Suwayomi-Server.
- [Tachidesk-Sorayomi](https://github.com/Suwayomi/Tachidesk-Sorayomi): A Flutter front-end for Desktop(Linux, windows, etc.), Web and Android with a User Interface inspired by Mihon (Tachiyomi).

View File

@@ -1,22 +1,22 @@
[versions]
kotlin = "2.3.0"
kotlin = "2.3.10"
coroutines = "1.10.2"
serialization = "1.9.0"
serialization = "1.10.0"
jvmTarget = "21"
okhttp = "5.3.2" # Major version is locked by Tachiyomi extensions
javalin = "6.7.0"
jte = "3.2.1"
jte = "3.2.3"
jackson = "2.18.3" # jackson version locked by javalin, ref: `io.javalin.core.util.OptionalDependency`
exposed = "0.61.0"
dex2jar = "2.4.34"
polyglot = "24.2.2"
settings = "1.3.0"
twelvemonkeys = "3.13.0"
graphqlkotlin = "8.8.1"
graphqlkotlin = "8.9.0"
xmlserialization = "0.91.3"
ktlint = "1.8.0"
koin = "4.1.1"
moko = "0.25.2"
moko = "0.26.0"
[libraries]
# Kotlin
@@ -38,8 +38,8 @@ serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization-jvm", v
# Logging
slf4japi = "org.slf4j:slf4j-api:2.0.17"
logback = "ch.qos.logback:logback-classic:1.5.28"
kotlinlogging = "io.github.oshai:kotlin-logging-jvm:7.0.14"
logback = "ch.qos.logback:logback-classic:1.5.32"
kotlinlogging = "io.github.oshai:kotlin-logging-jvm:8.0.01"
# OkHttp
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
@@ -68,7 +68,7 @@ exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "e
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" }
exposed-javatime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" }
postgres = "org.postgresql:postgresql:42.7.9"
postgres = "org.postgresql:postgresql:42.7.10"
h2 = "com.h2database:h2:1.4.200" # current database driver, can't update to h2 v2 without sql migration
hikaricp = "com.zaxxer:HikariCP:7.0.2"
@@ -105,7 +105,7 @@ dex2jar-tools = { module = "de.femtopedia.dex2jar:dex-tools", version.ref = "dex
# APK
apk-parser = "net.dongliu:apk-parser:2.6.10"
apksig = "com.android.tools.build:apksig:8.13.2"
apksig = "com.android.tools.build:apksig:9.0.1"
# Xml
xmlpull = "xmlpull:xmlpull:1.1.3.4a"
@@ -113,7 +113,7 @@ xmlpull = "xmlpull:xmlpull:1.1.3.4a"
# Disk & File
appdirs = "ca.gosyer:kotlin-multiplatform-appdirs:2.0.0"
cache4k = "io.github.reactivecircus.cache4k:cache4k:0.14.0"
zip4j = "net.lingala.zip4j:zip4j:2.11.5"
zip4j = "net.lingala.zip4j:zip4j:2.11.6"
commonscompress = "org.apache.commons:commons-compress:1.28.0"
junrar = "com.github.junrar:junrar:7.5.7"
@@ -158,7 +158,7 @@ cronUtils = "com.cronutils:cron-utils:9.2.1"
kcef = "dev.datlag:kcef:2024.04.20.4"
# User
jwt = "com.auth0:java-jwt:4.5.0"
jwt = "com.auth0:java-jwt:4.5.1"
# lint - used for renovate to update ktlint version
ktlint = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" }
@@ -179,7 +179,7 @@ ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "14.0.1"}
buildconfig = { id = "com.github.gmazzo.buildconfig", version = "6.0.7"}
# Download
download = { id = "de.undercouch.download", version = "5.6.0"}
download = { id = "de.undercouch.download", version = "5.7.0"}
# ShadowJar
shadowjar = { id = "com.gradleup.shadow", version = "8.3.9"}

View File

@@ -53,4 +53,11 @@
<string name="manga_status_licensed">正式版</string>
<string name="manga_status_publishing_finished">連載終了</string>
<string name="manga_status_cancelled">打ち切り</string>
<string name="opds_feeds_history_title">履歴</string>
<string name="opds_feeds_history_entry_content">最近読んだ章</string>
<string name="opds_feeds_all_series_in_library_title">すべてのマンガ</string>
<string name="opds_feeds_all_series_in_library_entry_content">ライブラリに保存されたマンガを閲覧</string>
<string name="opds_feeds_library_sources_title">ソース</string>
<string name="opds_feeds_library_sources_entry_content">ソース別にライブラリ内のマンガを閲覧</string>
<string name="opds_feeds_search_results_title">検索結果</string>
</resources>

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="opds_search_description">Wyszukiwanie mangi w katalogu</string>
<string name="opds_search_description">Wyszukaj serie w katalogu.</string>
<string name="manga_status_on_hiatus">Zawieszone</string>
<string name="opds_feeds_genre_specific_title">Gatunek: %1$s</string>
<string name="opds_feeds_chapter_details">%1$s | %2$s | Szczegóły</string>
<string name="opds_chapter_details_base">%1$s | %2$s</string>
<string name="opds_feeds_library_updates_title">Historia Aktualizacji Biblioteki</string>
<string name="opds_feeds_categories_entry_content">Przeglądaj mangi uporządkowane według kategorii</string>
<string name="opds_feeds_categories_entry_content">Przeglądaj serie uporządkowane według kategorii</string>
<string name="opds_chapter_status_downloaded">⬇️</string>
<string name="opds_linktitle_self_feed">Aktualny Kanał</string>
<string name="opds_chapter_status_unread"></string>
@@ -14,11 +14,11 @@
<string name="opds_feeds_manga_chapters">%1$s Rozdziały</string>
<string name="opds_search_shortname">Suwayomi Wyszukiwanie OPDS</string>
<string name="opds_feeds_root">Suwayomi Katalog OPDS</string>
<string name="opds_feeds_sources_title">Źródła</string>
<string name="opds_feeds_sources_title">Wszystkie Źródła</string>
<string name="opds_feeds_genres_title">Gatunki</string>
<string name="opds_feeds_status_title">Status</string>
<string name="opds_feeds_languages_title">Języki</string>
<string name="opds_feeds_languages_entry_content">Przeglądaj mangi według języka treści</string>
<string name="opds_feeds_languages_entry_content">Przeglądaj serie według języka treści</string>
<string name="opds_feeds_library_updates_entry_content">Ostatnio zaktualizowane rozdziały z biblioteki</string>
<string name="opds_feeds_category_specific_title">Kategoria: %1$s</string>
<string name="opds_feeds_status_specific_title">Status: %1$s</string>
@@ -32,8 +32,8 @@
<string name="opds_facet_sort_date_asc">Data rosnąco</string>
<string name="opds_facet_sort_date_desc">Data malejąco</string>
<string name="opds_facet_filter_all_chapters">Wszystkie Rozdziały</string>
<string name="opds_facet_filter_unread_only">Tylko Nieprzeczytane</string>
<string name="opds_facet_filter_read_only">Tylko Przeczytane</string>
<string name="opds_facet_filter_unread_only">Nieprzeczytane</string>
<string name="opds_facet_filter_read_only">Przeczytane</string>
<string name="opds_linktitle_view_chapter_details">Wyświetl Szczegóły Rozdziału i Pobierz Strony</string>
<string name="opds_linktitle_download_cbz">Pobierz CBZ</string>
<string name="opds_linktitle_chapter_cover">Okładka Rozdziału</string>
@@ -51,11 +51,29 @@
<string name="manga_status_publishing_finished">Publikacja Zakończona</string>
<string name="manga_status_cancelled">Anulowano</string>
<string name="opds_feeds_categories_title">Kategorie</string>
<string name="opds_feeds_genres_entry_content">Przeglądaj mangi według tagów gatunku</string>
<string name="opds_feeds_status_entry_content">Przeglądaj mangi według statusu publikacji</string>
<string name="opds_feeds_genres_entry_content">Przeglądaj serie według tagów gatunku</string>
<string name="opds_feeds_status_entry_content">Przeglądaj serie według statusu publikacji</string>
<string name="opds_feeds_source_specific_popular_title">Źródło: %1$s - Popularne</string>
<string name="opds_feeds_library_source_specific_title">Biblioteka - Źródło: %1$s</string>
<string name="opds_feeds_source_specific_latest_title">Źródło: %1$s - Ostatnie</string>
<string name="opds_feeds_search_results_title">Wyniki Wyszukiwania</string>
<string name="opds_feeds_history_title">Historia</string>
<string name="opds_feeds_explore_title">Odkrywaj</string>
<string name="opds_feeds_explore_entry_content">Odkryj nowe serie ze swoich źródeł</string>
<string name="opds_feeds_history_entry_content">Ostatnio przeczytane rozdziały</string>
<string name="opds_feeds_all_series_in_library_title">Wszystkie serie</string>
<string name="opds_feeds_all_series_in_library_entry_content">Przeglądaj wszystkie serie zapisane w bibliotece</string>
<string name="opds_feeds_library_sources_title">Źródła</string>
<string name="opds_feeds_library_sources_entry_content">Przeglądaj serie w swojej bibliotece filtrowane według źródła</string>
<string name="opds_facet_sort_popular">Popularność</string>
<string name="opds_facet_sort_latest">Najnowsze</string>
<string name="opds_facet_sort_alpha_asc">Alfabetycznie od A do Z</string>
<string name="opds_facet_sort_alpha_desc">Alfabetycznie Z-A</string>
<string name="opds_facet_sort_last_read_desc">Ostatnio czytane</string>
<string name="opds_facet_sort_latest_chapter_desc">Najnowszy rozdział</string>
<string name="opds_facet_sort_date_added_desc">Data dodania</string>
<string name="opds_facet_sort_unread_desc">Nieprzeczytane rozdziały</string>
<string name="opds_facet_filter_all">Wszystkie</string>
<string name="opds_facet_filter_downloaded">Pobrane</string>
<string name="opds_facet_filter_ongoing">Trwające</string>
</resources>

View File

@@ -14,9 +14,9 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.Cookie
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
@@ -24,6 +24,7 @@ import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import okio.Buffer
import suwayomi.tachidesk.server.serverConfig
import uy.kohesive.injekt.injectLazy
import java.io.IOException
@@ -70,7 +71,8 @@ class CloudflareInterceptor(
flareResponse.solution.status in 200..299 &&
flareResponse.solution.response != null
) {
val isImage = flareResponse.solution.response.contains(CHROME_IMAGE_TEMPLATE_REGEX)
val isImage =
flareResponse.solution.response.contains(CHROME_IMAGE_TEMPLATE_REGEX)
if (!isImage) {
logger.debug { "Falling back to FlareSolverr response" }
@@ -87,7 +89,8 @@ class CloudflareInterceptor(
}
}
val request = CFClearance.requestWithFlareSolverr(flareResponse, setUserAgent, originalRequest)
val request =
CFClearance.requestWithFlareSolverr(flareResponse, setUserAgent, originalRequest)
chain.proceed(request)
} catch (e: Exception) {
@@ -187,7 +190,6 @@ object CFClearance {
onlyCookies: Boolean,
): FlareSolverResponse {
val timeout = serverConfig.flareSolverrTimeout.value.seconds
return with(json) {
mutex.withLock {
client.value
@@ -198,7 +200,7 @@ object CFClearance {
Json
.encodeToString(
FlareSolverRequest(
"request.get",
"request.${originalRequest.method.lowercase()}",
originalRequest.url.toString(),
session = serverConfig.flareSolverrSessionName.value,
sessionTtlMinutes = serverConfig.flareSolverrSessionTtl.value,
@@ -208,6 +210,22 @@ object CFClearance {
},
returnOnlyCookies = onlyCookies,
maxTimeout = timeout.inWholeMilliseconds.toInt(),
postData =
if (originalRequest.method == "POST") {
when (val body = originalRequest.body) {
is FormBody -> {
Buffer()
.also { body.writeTo(it) }
.readUtf8()
}
else -> {
""
}
}
} else {
null
},
),
).toRequestBody(jsonMediaType),
),
@@ -238,7 +256,9 @@ object CFClearance {
if (!cookie.path.isNullOrEmpty()) it.path(cookie.path)
// We need to convert the expires time to milliseconds for the persistent cookie store
if (cookie.expires != null && cookie.expires > 0) it.expiresAt((cookie.expires * 1000).toLong())
if (!cookie.domain.startsWith('.')) it.hostOnlyDomain(cookie.domain.removePrefix("."))
if (!cookie.domain.startsWith('.')) {
it.hostOnlyDomain(cookie.domain.removePrefix("."))
}
}.build()
}.groupBy { it.domain }
.flatMap { (domain, cookies) ->