From 0658c1926c6dbc51280b3b603405ffd10312b07c Mon Sep 17 00:00:00 2001 From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> Date: Sun, 2 Feb 2025 14:24:40 +0500 Subject: [PATCH] revert kotlin 2.1.0 and deps for now (#7468) generated serializers seem to be missing in final apk, need further investigation --- buildSrc/build.gradle.kts | 2 +- .../src/main/kotlin/keiyoushi.lint.gradle.kts | 50 ----- .../src/main/kotlin/lib-android.gradle.kts | 11 -- .../src/main/kotlin/lib-multisrc.gradle.kts | 28 ++- common.gradle | 47 +++-- gradle/libs.versions.toml | 15 +- lib-multisrc/heancms/build.gradle.kts | 2 +- lib-multisrc/kemono/build.gradle.kts | 2 +- .../tachiyomi/multisrc/madara/Madara.kt | 174 ++++++++++-------- lib-multisrc/mangadventure/build.gradle.kts | 2 +- src/all/comickfun/build.gradle | 2 +- src/all/mangadex/build.gradle | 2 +- .../extension/en/coffeemanga/CoffeeManga.kt | 14 +- .../extension/en/luascans/LuaScans.kt | 11 +- src/en/mangamo/build.gradle | 2 +- .../extension/en/mangamo/MangamoAuth.kt | 7 +- .../tachiyomi/extension/en/retsu/Retsu.kt | 11 +- .../extension/id/mangkomik/SirenKomik.kt | 13 +- .../extension/pt/sussyscan/SussyToons.kt | 76 ++++---- .../extension/pt/sussyscan/SussyToonsDto.kt | 12 +- .../tachiyomi/extension/pt/taiyo/Taiyo.kt | 76 +++++--- .../extension/tr/hattorimanga/HattoriManga.kt | 57 +++--- .../extension/vi/lxhentai/LxHentai.kt | 83 +++++---- .../vi/truyentranh3q/TruyenTranh3Q.kt | 84 +++++---- .../extension/vi/yurineko/YuriNeko.kt | 46 ++--- 25 files changed, 443 insertions(+), 386 deletions(-) delete mode 100644 buildSrc/src/main/kotlin/keiyoushi.lint.gradle.kts diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 6a112583f..deebe960b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -12,5 +12,5 @@ dependencies { implementation(libs.gradle.agp) implementation(libs.gradle.kotlin) implementation(libs.gradle.serialization) - implementation(libs.spotless.gradle) + implementation(libs.gradle.kotlinter) } diff --git a/buildSrc/src/main/kotlin/keiyoushi.lint.gradle.kts b/buildSrc/src/main/kotlin/keiyoushi.lint.gradle.kts deleted file mode 100644 index 65b486e49..000000000 --- a/buildSrc/src/main/kotlin/keiyoushi.lint.gradle.kts +++ /dev/null @@ -1,50 +0,0 @@ -plugins { - id("com.diffplug.spotless") -} - -spotless { - ratchetFrom = "105f615b339e681a630f21dc0d363b8ca1cb17d5" - - kotlin { - target("**/*.kt", "**/*.kts") - targetExclude("**/build/**/*.kt") - ktlint() - .editorConfigOverride(mapOf( - "ktlint_standard_discouraged-comment-location" to "disabled", - "ktlint_function_signature_body_expression_wrapping" to "default", - "ktlint_standard_no-empty-first-line-in-class-body" to "disable", - "ktlint_standard_chain-method-continuation" to "disable" - )) - trimTrailingWhitespace() - endWithNewline() - } - - format("gradle") { - target("**/*.gradle") - trimTrailingWhitespace() - endWithNewline() - } - - format("xml") { - target("**/*.xml") - targetExclude("**/build/**/*.xml") - trimTrailingWhitespace() - endWithNewline() - } -} - -tasks { - named("preBuild") { - dependsOn( - tasks.getByName("spotlessCheck") - ) - } - - if (System.getenv("CI") != "true") { - named("spotlessCheck") { - dependsOn( - tasks.getByName("spotlessApply") - ) - } - } -} diff --git a/buildSrc/src/main/kotlin/lib-android.gradle.kts b/buildSrc/src/main/kotlin/lib-android.gradle.kts index 0e1c83130..ee9eb1c22 100644 --- a/buildSrc/src/main/kotlin/lib-android.gradle.kts +++ b/buildSrc/src/main/kotlin/lib-android.gradle.kts @@ -2,7 +2,6 @@ plugins { id("com.android.library") kotlin("android") id("kotlinx-serialization") - id("keiyoushi.lint") } android { @@ -17,16 +16,6 @@ android { buildFeatures { androidResources = false } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - freeCompilerArgs += "-opt-in=kotlinx.serialization.ExperimentalSerializationApi" - } } dependencies { diff --git a/buildSrc/src/main/kotlin/lib-multisrc.gradle.kts b/buildSrc/src/main/kotlin/lib-multisrc.gradle.kts index 3ed2f14b2..402ebebf6 100644 --- a/buildSrc/src/main/kotlin/lib-multisrc.gradle.kts +++ b/buildSrc/src/main/kotlin/lib-multisrc.gradle.kts @@ -2,7 +2,7 @@ plugins { id("com.android.library") kotlin("android") id("kotlinx-serialization") - id("keiyoushi.lint") + id("org.jmailen.kotlinter") } android { @@ -23,21 +23,35 @@ android { } } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() freeCompilerArgs += "-opt-in=kotlinx.serialization.ExperimentalSerializationApi" } } +kotlinter { + experimentalRules = true + disabledRules = arrayOf( + "experimental:argument-list-wrapping", // Doesn't play well with Android Studio + "experimental:comment-wrapping", + ) +} + dependencies { compileOnly(versionCatalogs.named("libs").findBundle("common").get()) } +tasks { + preBuild { + dependsOn(lintKotlin) + } + + if (System.getenv("CI") != "true") { + lintKotlin { + dependsOn(formatKotlin) + } + } +} + tasks.register("printDependentExtensions") { doLast { project.printDependentExtensions() diff --git a/common.gradle b/common.gradle index 787dcf07b..f916f509a 100644 --- a/common.gradle +++ b/common.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlinx-serialization' -apply plugin: 'keiyoushi.lint' +apply plugin: 'org.jmailen.kotlinter' assert !ext.has("pkgNameSuffix") assert !ext.has("libVersion") @@ -18,17 +18,6 @@ android { sourceSets { main { manifest.srcFile "AndroidManifest.xml" - if (!manifest.srcFile.exists()) { - def buildDir = layout.buildDirectory.get().getAsFile().path - mkdir(buildDir) - File tempFile = new File(buildDir, "tempAndroidManifest.xml") - if (!tempFile.exists()) { - tempFile.withWriter { - it.write('\n\n') - } - } - manifest.srcFile(tempFile.path) - } java.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] @@ -92,14 +81,22 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() + jvmTarget = JavaVersion.VERSION_1_8.toString() freeCompilerArgs += "-opt-in=kotlinx.serialization.ExperimentalSerializationApi" } + + kotlinter { + experimentalRules = true + disabledRules = [ + "experimental:argument-list-wrapping", // Doesn't play well with Android Studio + "experimental:comment-wrapping", + ] + } } dependencies { @@ -107,3 +104,23 @@ dependencies { implementation(project(":core")) compileOnly(libs.bundles.common) } + +tasks.register("writeManifestFile") { + doLast { + def manifest = android.sourceSets.getByName("main").manifest + if (!manifest.srcFile.exists()) { + File tempFile = layout.buildDirectory.get().file("tempAndroidManifest.xml").getAsFile() + if (!tempFile.exists()) { + tempFile.withWriter { + it.write('\n\n') + } + } + manifest.srcFile(tempFile.path) + } + } +} + +preBuild.dependsOn(writeManifestFile, lintKotlin) +if (System.getenv("CI") != "true") { + lintKotlin.dependsOn(formatKotlin) +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aeea7d93c..e5127d7fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,13 @@ [versions] -kotlin_version = "2.1.0" -coroutines_version = "1.10.1" -serialization_version = "1.8.0" +kotlin_version = "1.7.21" +coroutines_version = "1.6.4" +serialization_version = "1.4.0" [libraries] -gradle-agp = { module = "com.android.tools.build:gradle", version = "8.8.0" } +gradle-agp = { module = "com.android.tools.build:gradle", version = "8.6.1" } gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" } gradle-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version" } - -spotless-gradle = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version = "7.0.2" } +gradle-kotlinter = { module = "org.jmailen.gradle:kotlinter-gradle", version = "3.13.0" } tachiyomi-lib = { module = "com.github.tachiyomiorg:extensions-lib", version = "1.4.2" } @@ -21,8 +20,8 @@ coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-androi injekt-core = { module = "com.github.null2264.injekt:injekt-core", version = "4135455a2a" } rxjava = { module = "io.reactivex:rxjava", version = "1.3.8" } -jsoup = { module = "org.jsoup:jsoup", version = "1.18.3" } -okhttp = { module = "com.squareup.okhttp3:okhttp", version = "5.0.0-alpha.14" } +jsoup = { module = "org.jsoup:jsoup", version = "1.15.1" } +okhttp = { module = "com.squareup.okhttp3:okhttp", version = "5.0.0-alpha.11" } quickjs = { module = "app.cash.quickjs:quickjs-android", version = "0.9.2" } [bundles] diff --git a/lib-multisrc/heancms/build.gradle.kts b/lib-multisrc/heancms/build.gradle.kts index 7aabb2b3d..ac3762176 100644 --- a/lib-multisrc/heancms/build.gradle.kts +++ b/lib-multisrc/heancms/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("lib-multisrc") } -baseVersionCode = 27 +baseVersionCode = 28 dependencies { api(project(":lib:i18n")) diff --git a/lib-multisrc/kemono/build.gradle.kts b/lib-multisrc/kemono/build.gradle.kts index e43682c17..92c1c905d 100644 --- a/lib-multisrc/kemono/build.gradle.kts +++ b/lib-multisrc/kemono/build.gradle.kts @@ -2,4 +2,4 @@ plugins { id("lib-multisrc") } -baseVersionCode = 17 +baseVersionCode = 18 diff --git a/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt b/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt index 8c191c145..e85938e35 100644 --- a/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt +++ b/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt @@ -109,9 +109,7 @@ abstract class Madara( protected open val useLoadMoreRequest = LoadMoreStrategy.AutoDetect enum class LoadMoreStrategy { - AutoDetect, - Always, - Never, + AutoDetect, Always, Never } /** @@ -120,9 +118,7 @@ abstract class Madara( private var loadMoreRequestDetected = LoadMoreDetection.Pending private enum class LoadMoreDetection { - Pending, - True, - False, + Pending, True, False } protected fun detectLoadMore(document: Document) { @@ -136,10 +132,12 @@ abstract class Madara( } } - protected fun useLoadMoreRequest(): Boolean = when (useLoadMoreRequest) { - LoadMoreStrategy.Always -> true - LoadMoreStrategy.Never -> false - else -> loadMoreRequestDetected == LoadMoreDetection.True + protected fun useLoadMoreRequest(): Boolean { + return when (useLoadMoreRequest) { + LoadMoreStrategy.Always -> true + LoadMoreStrategy.Never -> false + else -> loadMoreRequestDetected == LoadMoreDetection.True + } } // Popular Manga @@ -178,17 +176,19 @@ abstract class Madara( return manga } - override fun popularMangaRequest(page: Int): Request = if (useLoadMoreRequest()) { - loadMoreRequest(page, popular = true) - } else { - GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=views", headers) - } + override fun popularMangaRequest(page: Int): Request = + if (useLoadMoreRequest()) { + loadMoreRequest(page, popular = true) + } else { + GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=views", headers) + } - override fun popularMangaNextPageSelector(): String? = if (useLoadMoreRequest()) { - "body:not(:has(.no-posts))" - } else { - "div.nav-previous, nav.navigation-ajax, a.nextpostslink" - } + override fun popularMangaNextPageSelector(): String? = + if (useLoadMoreRequest()) { + "body:not(:has(.no-posts))" + } else { + "div.nav-previous, nav.navigation-ajax, a.nextpostslink" + } // Latest Updates @@ -199,11 +199,12 @@ abstract class Madara( return popularMangaFromElement(element) } - override fun latestUpdatesRequest(page: Int): Request = if (useLoadMoreRequest()) { - loadMoreRequest(page, popular = false) - } else { - GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=latest", headers) - } + override fun latestUpdatesRequest(page: Int): Request = + if (useLoadMoreRequest()) { + loadMoreRequest(page, popular = false) + } else { + GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=latest", headers) + } override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector() @@ -250,16 +251,20 @@ abstract class Madara( return super.fetchSearchManga(page, query, filters) } - protected open fun searchPage(page: Int): String = if (page == 1) { - "" - } else { - "page/$page/" + protected open fun searchPage(page: Int): String { + return if (page == 1) { + "" + } else { + "page/$page/" + } } - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = if (useLoadMoreRequest()) { - searchLoadMoreRequest(page, query, filters) - } else { - searchRequest(page, query, filters) + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return if (useLoadMoreRequest()) { + searchLoadMoreRequest(page, query, filters) + } else { + searchRequest(page, query, filters) + } } protected open fun searchRequest(page: Int, query: String, filters: FilterList): Request { @@ -305,9 +310,7 @@ abstract class Madara( filter.state .filter { it.state } .let { list -> - if (list.isNotEmpty()) { - list.forEach { genre -> url.addQueryParameter("genre[]", genre.id) } - } + if (list.isNotEmpty()) { list.forEach { genre -> url.addQueryParameter("genre[]", genre.id) } } } } else -> {} @@ -486,7 +489,8 @@ abstract class Madara( intl["adult_content_filter_only"] to "1", ) - open class UriPartFilter(displayName: String, private val vals: Array>, state: Int = 0) : Filter.Select(displayName, vals.map { it.first }.toTypedArray(), state) { + open class UriPartFilter(displayName: String, private val vals: Array>, state: Int = 0) : + Filter.Select(displayName, vals.map { it.first }.toTypedArray(), state) { fun toUriPart() = vals[state].second } @@ -495,21 +499,21 @@ abstract class Madara( protected class AuthorFilter(title: String) : Filter.Text(title) protected class ArtistFilter(title: String) : Filter.Text(title) protected class YearFilter(title: String) : Filter.Text(title) - protected class StatusFilter(title: String, status: List) : Filter.Group(title, status) + protected class StatusFilter(title: String, status: List) : + Filter.Group(title, status) - protected class OrderByFilter(title: String, options: List>, state: Int = 0) : UriPartFilter(title, options.toTypedArray(), state) + protected class OrderByFilter(title: String, options: List>, state: Int = 0) : + UriPartFilter(title, options.toTypedArray(), state) - protected class GenreConditionFilter(title: String, options: List>) : - UriPartFilter( - title, - options.toTypedArray(), - ) + protected class GenreConditionFilter(title: String, options: List>) : UriPartFilter( + title, + options.toTypedArray(), + ) - protected class AdultContentFilter(title: String, options: List>) : - UriPartFilter( - title, - options.toTypedArray(), - ) + protected class AdultContentFilter(title: String, options: List>) : UriPartFilter( + title, + options.toTypedArray(), + ) protected class GenreList(title: String, genres: List) : Filter.Group(title, genres.map { GenreCheckBox(it.name, it.id) }) class GenreCheckBox(name: String, val id: String = name) : Filter.CheckBox(name) @@ -753,24 +757,32 @@ abstract class Madara( open val altName = intl["alt_names_heading"] open val updatingRegex = "Updating|Atualizando".toRegex(RegexOption.IGNORE_CASE) - fun String.notUpdating(): Boolean = this.contains(updatingRegex).not() + fun String.notUpdating(): Boolean { + return this.contains(updatingRegex).not() + } - private fun String.containsIn(array: Array): Boolean = this.lowercase() in array.map { it.lowercase() } + private fun String.containsIn(array: Array): Boolean { + return this.lowercase() in array.map { it.lowercase() } + } - protected open fun imageFromElement(element: Element): String? = when { - element.hasAttr("data-src") -> element.attr("abs:data-src") - element.hasAttr("data-lazy-src") -> element.attr("abs:data-lazy-src") - element.hasAttr("srcset") -> element.attr("abs:srcset").getSrcSetImage() - element.hasAttr("data-cfsrc") -> element.attr("abs:data-cfsrc") - else -> element.attr("abs:src") + protected open fun imageFromElement(element: Element): String? { + return when { + element.hasAttr("data-src") -> element.attr("abs:data-src") + element.hasAttr("data-lazy-src") -> element.attr("abs:data-lazy-src") + element.hasAttr("srcset") -> element.attr("abs:srcset").getSrcSetImage() + element.hasAttr("data-cfsrc") -> element.attr("abs:data-cfsrc") + else -> element.attr("abs:src") + } } /** * Get the best image quality available from srcset */ - protected fun String.getSrcSetImage(): String? = this.split(" ") - .filter(URL_REGEX::matches) - .maxOfOrNull(String::toString) + protected fun String.getSrcSetImage(): String? { + return this.split(" ") + .filter(URL_REGEX::matches) + .maxOfOrNull(String::toString) + } /** * Set it to true if the source uses the new AJAX endpoint to @@ -795,7 +807,9 @@ abstract class Madara( return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, form) } - protected open fun xhrChaptersRequest(mangaUrl: String): Request = POST("$mangaUrl/ajax/chapters", xhrHeaders) + protected open fun xhrChaptersRequest(mangaUrl: String): Request { + return POST("$mangaUrl/ajax/chapters", xhrHeaders) + } override fun chapterListParse(response: Response): List { val document = response.asJsoup() @@ -866,10 +880,12 @@ abstract class Madara( open fun parseChapterDate(date: String?): Long { date ?: return 0 - fun SimpleDateFormat.tryParse(string: String): Long = try { - parse(string)?.time ?: 0 - } catch (_: ParseException) { - 0 + fun SimpleDateFormat.tryParse(string: String): Long { + return try { + parse(string)?.time ?: 0 + } catch (_: ParseException) { + 0 + } } return when { @@ -990,7 +1006,9 @@ abstract class Madara( } } - override fun imageRequest(page: Page): Request = GET(page.imageUrl!!, headers.newBuilder().set("Referer", page.url).build()) + override fun imageRequest(page: Page): Request { + return GET(page.imageUrl!!, headers.newBuilder().set("Referer", page.url).build()) + } override fun imageUrlParse(document: Document) = "" @@ -1065,22 +1083,26 @@ abstract class Madara( /** * The request to the search page (or another one) that have the genres list. */ - protected open fun genresRequest(): Request = GET("$baseUrl/?s=genre&post_type=wp-manga", headers) + protected open fun genresRequest(): Request { + return GET("$baseUrl/?s=genre&post_type=wp-manga", headers) + } /** * Get the genres from the search page document. * * @param document The search page document */ - protected open fun parseGenres(document: Document): List = document.selectFirst("div.checkbox-group") - ?.select("div.checkbox") - .orEmpty() - .map { li -> - Genre( - li.selectFirst("label")!!.text(), - li.selectFirst("input[type=checkbox]")!!.`val`(), - ) - } + protected open fun parseGenres(document: Document): List { + return document.selectFirst("div.checkbox-group") + ?.select("div.checkbox") + .orEmpty() + .map { li -> + Genre( + li.selectFirst("label")!!.text(), + li.selectFirst("input[type=checkbox]")!!.`val`(), + ) + } + } // https://stackoverflow.com/a/66614516 protected fun String.decodeHex(): ByteArray { diff --git a/lib-multisrc/mangadventure/build.gradle.kts b/lib-multisrc/mangadventure/build.gradle.kts index f5a077b4b..bbea4c992 100644 --- a/lib-multisrc/mangadventure/build.gradle.kts +++ b/lib-multisrc/mangadventure/build.gradle.kts @@ -2,4 +2,4 @@ plugins { id("lib-multisrc") } -baseVersionCode = 13 +baseVersionCode = 14 diff --git a/src/all/comickfun/build.gradle b/src/all/comickfun/build.gradle index faaa0f61e..1796e90c1 100644 --- a/src/all/comickfun/build.gradle +++ b/src/all/comickfun/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Comick' extClass = '.ComickFactory' - extVersionCode = 51 + extVersionCode = 52 isNsfw = true } diff --git a/src/all/mangadex/build.gradle b/src/all/mangadex/build.gradle index a1cc3535c..69e45f9fc 100644 --- a/src/all/mangadex/build.gradle +++ b/src/all/mangadex/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'MangaDex' extClass = '.MangaDexFactory' - extVersionCode = 197 + extVersionCode = 198 isNsfw = true } diff --git a/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt b/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt index 68eaa5798..02a974d62 100644 --- a/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt +++ b/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt @@ -6,11 +6,13 @@ import org.jsoup.nodes.Element class CoffeeManga : Madara("Coffee Manga", "https://coffeemanga.io", "en") { override val useNewChapterEndpoint = false - override fun imageFromElement(element: Element): String? = when { - element.attr("data-src").isNotBlank() -> element.attr("abs:data-src") - element.attr("data-lazy-src").isNotBlank() -> element.attr("abs:data-lazy-src") - element.attr("srcset").isNotBlank() -> element.attr("abs:srcset").getSrcSetImage() - element.attr("data-cfsrc").isNotBlank() -> element.attr("abs:data-cfsrc") - else -> element.attr("abs:src") + override fun imageFromElement(element: Element): String? { + return when { + element.attr("data-src").isNotBlank() -> element.attr("abs:data-src") + element.attr("data-lazy-src").isNotBlank() -> element.attr("abs:data-lazy-src") + element.attr("srcset").isNotBlank() -> element.attr("abs:srcset").getSrcSetImage() + element.attr("data-cfsrc").isNotBlank() -> element.attr("abs:data-cfsrc") + else -> element.attr("abs:src") + } } } diff --git a/src/en/luascans/src/eu/kanade/tachiyomi/extension/en/luascans/LuaScans.kt b/src/en/luascans/src/eu/kanade/tachiyomi/extension/en/luascans/LuaScans.kt index b3701b5b2..a6f30741d 100644 --- a/src/en/luascans/src/eu/kanade/tachiyomi/extension/en/luascans/LuaScans.kt +++ b/src/en/luascans/src/eu/kanade/tachiyomi/extension/en/luascans/LuaScans.kt @@ -2,12 +2,11 @@ package eu.kanade.tachiyomi.extension.en.luascans import eu.kanade.tachiyomi.multisrc.heancms.HeanCms -class LuaScans : - HeanCms( - "Lua Scans", - "https://luacomic.org", - "en", - ) { +class LuaScans : HeanCms( + "Lua Scans", + "https://luacomic.org", + "en", +) { // Moved from Keyoapp to HeanCms override val versionId = 3 diff --git a/src/en/mangamo/build.gradle b/src/en/mangamo/build.gradle index 647332f2f..b5dd1e62a 100644 --- a/src/en/mangamo/build.gradle +++ b/src/en/mangamo/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Mangamo' extClass = '.Mangamo' - extVersionCode = 2 + extVersionCode = 1 isNsfw = false } diff --git a/src/en/mangamo/src/eu/kanade/tachiyomi/extension/en/mangamo/MangamoAuth.kt b/src/en/mangamo/src/eu/kanade/tachiyomi/extension/en/mangamo/MangamoAuth.kt index f6d3d939b..95036d8a5 100644 --- a/src/en/mangamo/src/eu/kanade/tachiyomi/extension/en/mangamo/MangamoAuth.kt +++ b/src/en/mangamo/src/eu/kanade/tachiyomi/extension/en/mangamo/MangamoAuth.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.network.POST import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.internal.EMPTY_HEADERS class MangamoAuth( private val helper: MangamoHelper, @@ -52,7 +53,8 @@ class MangamoAuth( val googleIdentityResponse = client.newCall( POST( "https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${MangamoConstants.FIREBASE_API_KEY}", - body = "{\"token\":\"$customToken\",\"returnSecureToken\":true}".toRequestBody(), + EMPTY_HEADERS, + "{\"token\":\"$customToken\",\"returnSecureToken\":true}".toRequestBody(), ), ).execute() @@ -95,7 +97,8 @@ class MangamoAuth( val googleIdentityResponse = client.newCall( POST( "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${MangamoConstants.FIREBASE_API_KEY}", - body = "{\"returnSecureToken\":true}".toRequestBody(), + EMPTY_HEADERS, + "{\"returnSecureToken\":true}".toRequestBody(), ), ).execute() diff --git a/src/en/retsu/src/eu/kanade/tachiyomi/extension/en/retsu/Retsu.kt b/src/en/retsu/src/eu/kanade/tachiyomi/extension/en/retsu/Retsu.kt index 716aedc00..06a30a6f5 100644 --- a/src/en/retsu/src/eu/kanade/tachiyomi/extension/en/retsu/Retsu.kt +++ b/src/en/retsu/src/eu/kanade/tachiyomi/extension/en/retsu/Retsu.kt @@ -2,12 +2,11 @@ package eu.kanade.tachiyomi.extension.en.retsu import eu.kanade.tachiyomi.multisrc.madara.Madara -class Retsu : - Madara( - "Retsu", - "https://retsu.org", - "en", - ) { +class Retsu : Madara( + "Retsu", + "https://retsu.org", + "en", +) { override fun popularMangaSelector() = "div.manga__item" override val popularMangaUrlSelector = "h4 a" diff --git a/src/id/mangkomik/src/eu/kanade/tachiyomi/extension/id/mangkomik/SirenKomik.kt b/src/id/mangkomik/src/eu/kanade/tachiyomi/extension/id/mangkomik/SirenKomik.kt index 929dee077..cff59c279 100644 --- a/src/id/mangkomik/src/eu/kanade/tachiyomi/extension/id/mangkomik/SirenKomik.kt +++ b/src/id/mangkomik/src/eu/kanade/tachiyomi/extension/id/mangkomik/SirenKomik.kt @@ -12,13 +12,12 @@ import java.io.IOException import java.text.SimpleDateFormat import java.util.Locale -class SirenKomik : - MangaThemesia( - "Siren Komik", - "https://sirenkomik.my.id", - "id", - dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("id")), - ) { +class SirenKomik : MangaThemesia( + "Siren Komik", + "https://sirenkomik.my.id", + "id", + dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("id")), +) { override val id = 8457447675410081142 override val hasProjectPage = true diff --git a/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt b/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt index 4f67a85da..789c669e8 100644 --- a/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt +++ b/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt @@ -32,9 +32,7 @@ import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Locale -class SussyToons : - HttpSource(), - ConfigurableSource { +class SussyToons : HttpSource(), ConfigurableSource { override val name = "Sussy Toons" @@ -104,7 +102,9 @@ class SussyToons : // ============================= Popular ================================== - override fun popularMangaRequest(page: Int): Request = GET("$apiUrl/obras/top5", headers) + override fun popularMangaRequest(page: Int): Request { + return GET("$apiUrl/obras/top5", headers) + } override fun popularMangaParse(response: Response): MangasPage { val dto = response.parseAs>>() @@ -152,7 +152,8 @@ class SussyToons : return GET(url, headers) } - override fun mangaDetailsParse(response: Response) = response.parseAs>().results.toSManga() + override fun mangaDetailsParse(response: Response) = + response.parseAs>().results.toSManga() private val SManga.id: String get() { val mangaUrl = apiUrl.toHttpUrl().newBuilder() @@ -165,16 +166,18 @@ class SussyToons : override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga) - override fun chapterListParse(response: Response): List = response.parseAs>().results.chapters.map { - SChapter.create().apply { - name = it.name - it.chapterNumber?.let { - chapter_number = it + override fun chapterListParse(response: Response): List { + return response.parseAs>().results.chapters.map { + SChapter.create().apply { + name = it.name + it.chapterNumber?.let { + chapter_number = it + } + setUrlWithoutDomain("$baseUrl/capitulo/${it.id}") + date_upload = it.updateAt.toDate() } - setUrlWithoutDomain("$baseUrl/capitulo/${it.id}") - date_upload = it.updateAt.toDate() - } - }.sortedBy(SChapter::chapter_number).reversed() + }.sortedBy(SChapter::chapter_number).reversed() + } // ============================= Pages ==================================== @@ -205,22 +208,30 @@ class SussyToons : Page(index, imageUrl = imageUrl.toString()) } } - private fun pageListParse(document: Document): List = document.select(pageUrlSelector).mapIndexed { index, element -> - Page(index, document.location(), element.absUrl("src")) + private fun pageListParse(document: Document): List { + return document.select(pageUrlSelector).mapIndexed { index, element -> + Page(index, document.location(), element.absUrl("src")) + } + } + private fun extractScriptData(document: Document): String { + return document.select("script").map(Element::data) + .firstOrNull(pageRegex::containsMatchIn) + ?: throw Exception("Failed to load pages: Script data not found") } - private fun extractScriptData(document: Document): String = document.select("script").map(Element::data) - .firstOrNull(pageRegex::containsMatchIn) - ?: throw Exception("Failed to load pages: Script data not found") - private fun extractJsonContent(scriptData: String): String = pageRegex.find(scriptData) - ?.groups?.get(1)?.value - ?.let { json.decodeFromString("\"$it\"") } - ?: throw Exception("Failed to extract JSON from script") + private fun extractJsonContent(scriptData: String): String { + return pageRegex.find(scriptData) + ?.groups?.get(1)?.value + ?.let { json.decodeFromString("\"$it\"") } + ?: throw Exception("Failed to extract JSON from script") + } - private fun parseJsonToChapterPageDto(jsonContent: String): ChapterPageDto = try { - jsonContent.parseAs>().results - } catch (e: Exception) { - throw Exception("Failed to load pages: ${e.message}") + private fun parseJsonToChapterPageDto(jsonContent: String): ChapterPageDto { + return try { + jsonContent.parseAs>().results + } catch (e: Exception) { + throw Exception("Failed to load pages: ${e.message}") + } } override fun imageUrlParse(response: Response): String = "" @@ -334,14 +345,13 @@ class SussyToons : return json.decodeFromStream(body.byteStream()) } - private inline fun String.parseAs(): T = json.decodeFromString(this) - - private fun String.toDate() = try { - dateFormat.parse(this)!!.time - } catch (_: Exception) { - 0L + private inline fun String.parseAs(): T { + return json.decodeFromString(this) } + private fun String.toDate() = + try { dateFormat.parse(this)!!.time } catch (_: Exception) { 0L } + /** * Normalizes path segments: * Ex: [ "/a/b/", "/a/b", "a/b/", "a/b" ] diff --git a/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToonsDto.kt b/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToonsDto.kt index c1872c075..72889de79 100644 --- a/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToonsDto.kt +++ b/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToonsDto.kt @@ -41,11 +41,13 @@ class MangaDto( @SerialName("stt_nome") val value: String?, ) { - fun toStatus(): Int = when (value?.lowercase()) { - "em andamento" -> SManga.ONGOING - "completo" -> SManga.COMPLETED - "hiato" -> SManga.ON_HIATUS - else -> SManga.UNKNOWN + fun toStatus(): Int { + return when (value?.lowercase()) { + "em andamento" -> SManga.ONGOING + "completo" -> SManga.COMPLETED + "hiato" -> SManga.ON_HIATUS + else -> SManga.UNKNOWN + } } } } diff --git a/src/pt/taiyo/src/eu/kanade/tachiyomi/extension/pt/taiyo/Taiyo.kt b/src/pt/taiyo/src/eu/kanade/tachiyomi/extension/pt/taiyo/Taiyo.kt index 0b3d89b5c..211acbf09 100644 --- a/src/pt/taiyo/src/eu/kanade/tachiyomi/extension/pt/taiyo/Taiyo.kt +++ b/src/pt/taiyo/src/eu/kanade/tachiyomi/extension/pt/taiyo/Taiyo.kt @@ -32,6 +32,8 @@ import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response +import okhttp3.internal.http.HTTP_FORBIDDEN +import okhttp3.internal.http.HTTP_UNAUTHORIZED import org.jsoup.nodes.Document import org.jsoup.nodes.Element import org.jsoup.select.Elements @@ -39,8 +41,6 @@ import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy -import java.net.HttpURLConnection.HTTP_FORBIDDEN -import java.net.HttpURLConnection.HTTP_UNAUTHORIZED import java.text.SimpleDateFormat import java.util.Locale @@ -85,13 +85,15 @@ class Taiyo : ParsedHttpSource() { // =============================== Search =============================== - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable = if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler - val id = query.removePrefix(PREFIX_SEARCH) - client.newCall(GET("$baseUrl/media/$id")) - .asObservableSuccess() - .map(::searchMangaByIdParse) - } else { - super.fetchSearchManga(page, query, filters) + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler + val id = query.removePrefix(PREFIX_SEARCH) + client.newCall(GET("$baseUrl/media/$id")) + .asObservableSuccess() + .map(::searchMangaByIdParse) + } else { + super.fetchSearchManga(page, query, filters) + } } private fun searchMangaByIdParse(response: Response): MangasPage { @@ -144,11 +146,17 @@ class Taiyo : ParsedHttpSource() { return MangasPage(mangas, mangas.isNotEmpty()) } - override fun searchMangaSelector(): String = throw UnsupportedOperationException() + override fun searchMangaSelector(): String { + throw UnsupportedOperationException() + } - override fun searchMangaFromElement(element: Element): SManga = throw UnsupportedOperationException() + override fun searchMangaFromElement(element: Element): SManga { + throw UnsupportedOperationException() + } - override fun searchMangaNextPageSelector(): String? = throw UnsupportedOperationException() + override fun searchMangaNextPageSelector(): String? { + throw UnsupportedOperationException() + } // =========================== Manga Details ============================ override fun mangaDetailsParse(document: Document) = SManga.create().apply { @@ -227,9 +235,13 @@ class Taiyo : ParsedHttpSource() { return Observable.just(chapters.sortedByDescending { it.chapter_number }) } - override fun chapterListSelector(): String = throw UnsupportedOperationException() + override fun chapterListSelector(): String { + throw UnsupportedOperationException() + } - override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException() + override fun chapterFromElement(element: Element): SChapter { + throw UnsupportedOperationException() + } // =============================== Pages ================================ override fun pageListParse(document: Document): List { @@ -244,7 +256,9 @@ class Taiyo : ParsedHttpSource() { } } - override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException() + override fun imageUrlParse(document: Document): String { + throw UnsupportedOperationException() + } // ============================= Utilities ============================== private fun Element.getImageUrl() = absUrl("srcset").substringBefore(" ") @@ -253,19 +267,23 @@ class Taiyo : ParsedHttpSource() { json.decodeFromStream(it.body.byteStream()) } - private fun String.toDate(): Long = runCatching { DATE_FORMATTER.parse(this)?.time } - .getOrNull() ?: 0L + private fun String.toDate(): Long { + return runCatching { DATE_FORMATTER.parse(this)?.time } + .getOrNull() ?: 0L + } private inline fun Document.parseJsonFromDocument( itemName: String = "media", crossinline transformer: String.() -> String, - ): T? = runCatching { - val script = selectFirst("script:containsData($itemName\\\\\":):containsData(\\\"6:\\[)")!!.data() - val obj = script.substringAfter(",{\\\"$itemName\\\":") - .run(transformer) - .replace("\\", "") - json.decodeFromString(obj) - }.onFailure { it.printStackTrace() }.getOrNull() + ): T? { + return runCatching { + val script = selectFirst("script:containsData($itemName\\\\\":):containsData(\\\"6:\\[)")!!.data() + val obj = script.substringAfter(",{\\\"$itemName\\\":") + .run(transformer) + .replace("\\", "") + json.decodeFromString(obj) + }.onFailure { it.printStackTrace() }.getOrNull() + } // ============================= Authorization ======================== @@ -286,10 +304,12 @@ class Taiyo : ParsedHttpSource() { return chain.proceed(req) } - private fun getToken(): String = fetchBearerToken().also { - preferences.edit() - .putString(BEARER_TOKEN_PREF, it) - .apply() + private fun getToken(): String { + return fetchBearerToken().also { + preferences.edit() + .putString(BEARER_TOKEN_PREF, it) + .apply() + } } private fun fetchBearerToken(): String { diff --git a/src/tr/hattorimanga/src/eu/kanade/tachiyomi/extension/tr/hattorimanga/HattoriManga.kt b/src/tr/hattorimanga/src/eu/kanade/tachiyomi/extension/tr/hattorimanga/HattoriManga.kt index a6e3fd845..767ee93e4 100644 --- a/src/tr/hattorimanga/src/eu/kanade/tachiyomi/extension/tr/hattorimanga/HattoriManga.kt +++ b/src/tr/hattorimanga/src/eu/kanade/tachiyomi/extension/tr/hattorimanga/HattoriManga.kt @@ -93,7 +93,8 @@ class HattoriManga : HttpSource() { csrfToken = document.selectFirst("meta[name=csrf-token]")!!.attr("content") } - override fun chapterListParse(response: Response) = throw UnsupportedOperationException() + override fun chapterListParse(response: Response) = + throw UnsupportedOperationException() override fun fetchChapterList(manga: SManga): Observable> { val slug = manga.url.substringAfterLast('/') @@ -115,9 +116,10 @@ class HattoriManga : HttpSource() { return Observable.just(chapters) } - private fun fetchChapterPageableList(slug: String, page: Int, manga: SManga): HMChapterDto = client.newCall(GET("$baseUrl/load-more-chapters/$slug?page=$page", headers)) - .execute() - .parseAs() + private fun fetchChapterPageableList(slug: String, page: Int, manga: SManga): HMChapterDto = + client.newCall(GET("$baseUrl/load-more-chapters/$slug?page=$page", headers)) + .execute() + .parseAs() override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/latest-chapters") @@ -147,20 +149,24 @@ class HattoriManga : HttpSource() { } } - override fun pageListParse(response: Response): List = response.asJsoup().select(".image-wrapper img").mapIndexed { index, element -> - Page(index, imageUrl = "$baseUrl${element.attr("data-src")}") - }.takeIf { it.isNotEmpty() } ?: throw Exception("Oturum açmanız, WebView'ı açmanız ve oturum açmanız gerekir") + override fun pageListParse(response: Response): List { + return response.asJsoup().select(".image-wrapper img").mapIndexed { index, element -> + Page(index, imageUrl = "$baseUrl${element.attr("data-src")}") + }.takeIf { it.isNotEmpty() } ?: throw Exception("Oturum açmanız, WebView'ı açmanız ve oturum açmanız gerekir") + } - override fun latestUpdatesParse(response: Response): MangasPage = response.use { - val mangas = it.parseAs().chapters.map { - SManga.create().apply { - val manga = it.manga - title = manga.title - thumbnail_url = "$baseUrl/storage/${manga.thumbnail}" - url = "/manga/${manga.slug}" - } - }.distinctBy { manga -> manga.title } - MangasPage(mangas, false) + override fun latestUpdatesParse(response: Response): MangasPage { + return response.use { + val mangas = it.parseAs().chapters.map { + SManga.create().apply { + val manga = it.manga + title = manga.title + thumbnail_url = "$baseUrl/storage/${manga.thumbnail}" + url = "/manga/${manga.slug}" + } + }.distinctBy { manga -> manga.title } + MangasPage(mangas, false) + } } override fun popularMangaParse(response: Response): MangasPage { @@ -257,18 +263,19 @@ class HattoriManga : HttpSource() { setUrlWithoutDomain(REGEX_MANGA_URL.find(script)!!.groups[1]!!.value) } - private fun parseGenres(document: Document): List = document.select(".tags-blog a") - .map { element -> Genre(element.text()) } + private fun parseGenres(document: Document): List { + return document.select(".tags-blog a") + .map { element -> Genre(element.text()) } + } - private inline fun Response.parseAs(): T = json.decodeFromString(body.string()) + private inline fun Response.parseAs(): T { + return json.decodeFromString(body.string()) + } private fun Response.isPageExpired() = code == 419 - private fun String.toDate(): Long = try { - dateFormat.parse(trim())!!.time - } catch (_: Exception) { - 0L - } + private fun String.toDate(): Long = + try { dateFormat.parse(trim())!!.time } catch (_: Exception) { 0L } class GenreList(title: String, genres: List) : Filter.Group(title, genres.map { GenreCheckBox(it.name, it.id) }) diff --git a/src/vi/lxhentai/src/eu/kanade/tachiyomi/extension/vi/lxhentai/LxHentai.kt b/src/vi/lxhentai/src/eu/kanade/tachiyomi/extension/vi/lxhentai/LxHentai.kt index 8a2793107..882693d0f 100644 --- a/src/vi/lxhentai/src/eu/kanade/tachiyomi/extension/vi/lxhentai/LxHentai.kt +++ b/src/vi/lxhentai/src/eu/kanade/tachiyomi/extension/vi/lxhentai/LxHentai.kt @@ -25,9 +25,7 @@ import uy.kohesive.injekt.api.get import java.text.SimpleDateFormat import java.util.Locale -class LxHentai : - ParsedHttpSource(), - ConfigurableSource { +class LxHentai : ParsedHttpSource(), ConfigurableSource { override val name = "LXHentai" @@ -43,30 +41,38 @@ class LxHentai : override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl) - override fun popularMangaRequest(page: Int) = searchMangaRequest(page, "", FilterList(SortBy(3))) + override fun popularMangaRequest(page: Int) = + searchMangaRequest(page, "", FilterList(SortBy(3))) override fun popularMangaSelector() = searchMangaSelector() - override fun popularMangaFromElement(element: Element) = searchMangaFromElement(element) + override fun popularMangaFromElement(element: Element) = + searchMangaFromElement(element) - override fun popularMangaNextPageSelector() = searchMangaNextPageSelector() + override fun popularMangaNextPageSelector() = + searchMangaNextPageSelector() - override fun latestUpdatesRequest(page: Int) = searchMangaRequest(page, "", FilterList(SortBy(0))) + override fun latestUpdatesRequest(page: Int) = + searchMangaRequest(page, "", FilterList(SortBy(0))) override fun latestUpdatesSelector() = searchMangaSelector() - override fun latestUpdatesFromElement(element: Element) = searchMangaFromElement(element) + override fun latestUpdatesFromElement(element: Element) = + searchMangaFromElement(element) - override fun latestUpdatesNextPageSelector() = searchMangaNextPageSelector() + override fun latestUpdatesNextPageSelector() = + searchMangaNextPageSelector() - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable = when { - query.startsWith(PREFIX_ID_SEARCH) -> { - val slug = query.substringAfter(PREFIX_ID_SEARCH) - val mangaUrl = "/truyen/$slug" - fetchMangaDetails(SManga.create().apply { url = mangaUrl }) - .map { MangasPage(listOf(it), false) } + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return when { + query.startsWith(PREFIX_ID_SEARCH) -> { + val slug = query.substringAfter(PREFIX_ID_SEARCH) + val mangaUrl = "/truyen/$slug" + fetchMangaDetails(SManga.create().apply { url = mangaUrl }) + .map { MangasPage(listOf(it), false) } + } + else -> super.fetchSearchManga(page, query, filters) } - else -> super.fetchSearchManga(page, query, filters) } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { @@ -162,33 +168,32 @@ class LxHentai : private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) - private open class UriPartFilter(displayName: String, val vals: Array>, state: Int = 0) : Filter.Select(displayName, vals.map { it.first }.toTypedArray(), state) { + private open class UriPartFilter(displayName: String, val vals: Array>, state: Int = 0) : + Filter.Select(displayName, vals.map { it.first }.toTypedArray(), state) { fun toUriPart() = vals[state].second } - private class SortBy(state: Int = 0) : - UriPartFilter( - "Sắp xếp theo", - arrayOf( - Pair("Mới cập nhật", "-updated_at"), - Pair("Mới nhất", "-created_at"), - Pair("Cũ nhất", "created_at"), - Pair("Xem nhiều", "-views"), - Pair("A-Z", "name"), - Pair("Z-A", "-name"), - ), - state, - ) + private class SortBy(state: Int = 0) : UriPartFilter( + "Sắp xếp theo", + arrayOf( + Pair("Mới cập nhật", "-updated_at"), + Pair("Mới nhất", "-created_at"), + Pair("Cũ nhất", "created_at"), + Pair("Xem nhiều", "-views"), + Pair("A-Z", "name"), + Pair("Z-A", "-name"), + ), + state, + ) - private class Status : - UriPartFilter( - "Trạng thái", - arrayOf( - Pair("Tất cả", "1,2"), - Pair("Đang tiến hành", "2"), - Pair("Đã hoàn thành", "1"), - ), - ) + private class Status : UriPartFilter( + "Trạng thái", + arrayOf( + Pair("Tất cả", "1,2"), + Pair("Đang tiến hành", "2"), + Pair("Đã hoàn thành", "1"), + ), + ) private class Genre(name: String, val id: Int) : Filter.TriState(name) private class GenreList(genres: List) : Filter.Group("Thể loại", genres) diff --git a/src/vi/truyentranh3q/src/eu/kanade/tachiyomi/extension/vi/truyentranh3q/TruyenTranh3Q.kt b/src/vi/truyentranh3q/src/eu/kanade/tachiyomi/extension/vi/truyentranh3q/TruyenTranh3Q.kt index 1fed71d74..655a251e2 100644 --- a/src/vi/truyentranh3q/src/eu/kanade/tachiyomi/extension/vi/truyentranh3q/TruyenTranh3Q.kt +++ b/src/vi/truyentranh3q/src/eu/kanade/tachiyomi/extension/vi/truyentranh3q/TruyenTranh3Q.kt @@ -34,31 +34,39 @@ class TruyenTranh3Q : ParsedHttpSource() { .rateLimit(3) .build() - override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", "$baseUrl/") + override fun headersBuilder(): Headers.Builder { + return super.headersBuilder().add("Referer", "$baseUrl/") + } private val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.US) - override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/danh-sach/truyen-yeu-thich?page=$page", headers) + override fun popularMangaRequest(page: Int): Request { + return GET("$baseUrl/danh-sach/truyen-yeu-thich?page=$page", headers) + } override fun popularMangaSelector(): String = "ul.list_grid.grid > li" - override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { - element.select("h3 a").let { - title = it.text() - setUrlWithoutDomain(it.attr("abs:href")) - } - thumbnail_url = element.selectFirst(".book_avatar a img") - ?.absUrl("src") - ?.let { url -> - url.toHttpUrlOrNull() - ?.queryParameter("url") - ?: url + override fun popularMangaFromElement(element: Element): SManga { + return SManga.create().apply { + element.select("h3 a").let { + title = it.text() + setUrlWithoutDomain(it.attr("abs:href")) } + thumbnail_url = element.selectFirst(".book_avatar a img") + ?.absUrl("src") + ?.let { url -> + url.toHttpUrlOrNull() + ?.queryParameter("url") + ?: url + } + } } override fun popularMangaNextPageSelector(): String? = ".page_redirect > a:last-child > p:not(.active)" - override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/danh-sach/truyen-moi-cap-nhat?page=$page", headers) + override fun latestUpdatesRequest(page: Int): Request { + return GET("$baseUrl/danh-sach/truyen-moi-cap-nhat?page=$page", headers) + } // same as popularManga override fun latestUpdatesSelector(): String = popularMangaSelector() @@ -113,19 +121,21 @@ class TruyenTranh3Q : ParsedHttpSource() { override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) override fun searchMangaNextPageSelector(): String? = popularMangaNextPageSelector() - override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { - document.selectFirst(".book_info > .book_other")?.let { info -> - title = info.selectFirst("h1[itemprop=name]")!!.text() - author = info.selectFirst("ul.list-info li.author p.col-xs-9")?.text() - status = when (info.selectFirst("ul.list-info li.status p.col-xs-9")?.text()) { - "Đang Cập Nhật" -> SManga.ONGOING - "Hoàn Thành" -> SManga.COMPLETED - else -> SManga.UNKNOWN + override fun mangaDetailsParse(document: Document): SManga { + return SManga.create().apply { + document.selectFirst(".book_info > .book_other")?.let { info -> + title = info.selectFirst("h1[itemprop=name]")!!.text() + author = info.selectFirst("ul.list-info li.author p.col-xs-9")?.text() + status = when (info.selectFirst("ul.list-info li.status p.col-xs-9")?.text()) { + "Đang Cập Nhật" -> SManga.ONGOING + "Hoàn Thành" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + genre = info.select(".list01 li a").joinToString { it.text() } } - genre = info.select(".list01 li a").joinToString { it.text() } + description = document.selectFirst(".book_detail > .story-detail-info")?.text() + thumbnail_url = document.selectFirst(".book_detail > .book_info > .book_avatar > img")?.attr("abs:src") } - description = document.selectFirst(".book_detail > .story-detail-info")?.text() - thumbnail_url = document.selectFirst(".book_detail > .book_info > .book_avatar > img")?.attr("abs:src") } // chapters @@ -173,19 +183,23 @@ class TruyenTranh3Q : ParsedHttpSource() { } } - override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { - element.selectFirst(".name-chap > a")?.let { - name = it.text() - setUrlWithoutDomain(it.attr("abs:href")) + override fun chapterFromElement(element: Element): SChapter { + return SChapter.create().apply { + element.selectFirst(".name-chap > a")?.let { + name = it.text() + setUrlWithoutDomain(it.attr("abs:href")) + } + date_upload = parseChapterDate(element.selectFirst(".time-chap")?.text() ?: "") } - date_upload = parseChapterDate(element.selectFirst(".time-chap")?.text() ?: "") } // parse pages private val pageListSelector = ".chapter_content .page-chapter img" - override fun pageListParse(document: Document): List = document.select(pageListSelector).mapIndexed { idx, it -> - Page(idx, imageUrl = it.absUrl("data-src")) + override fun pageListParse(document: Document): List { + return document.select(pageListSelector).mapIndexed { idx, it -> + Page(idx, imageUrl = it.absUrl("data-src")) + } } override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException() @@ -234,8 +248,10 @@ class TruyenTranh3Q : ParsedHttpSource() { private fun genresRequest() = GET("$baseUrl/$searchPath", headers) - private fun parseGenres(document: Document): List = document.select(".genre-item").mapIndexed { index, element -> - Genre(element.text(), index + 1) + private fun parseGenres(document: Document): List { + return document.select(".genre-item").mapIndexed { index, element -> + Genre(element.text(), index + 1) + } } private fun fetchGenres() { diff --git a/src/vi/yurineko/src/eu/kanade/tachiyomi/extension/vi/yurineko/YuriNeko.kt b/src/vi/yurineko/src/eu/kanade/tachiyomi/extension/vi/yurineko/YuriNeko.kt index 68ce45d50..34bdb6422 100644 --- a/src/vi/yurineko/src/eu/kanade/tachiyomi/extension/vi/yurineko/YuriNeko.kt +++ b/src/vi/yurineko/src/eu/kanade/tachiyomi/extension/vi/yurineko/YuriNeko.kt @@ -36,9 +36,7 @@ import java.io.IOException import java.net.URLDecoder import java.util.concurrent.TimeUnit -class YuriNeko : - HttpSource(), - ConfigurableSource { +class YuriNeko : HttpSource(), ConfigurableSource { override val name = "YuriNeko" @@ -109,20 +107,22 @@ class YuriNeko : override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException() - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable = when { - query.startsWith(PREFIX_ID_SEARCH) -> { - val id = query.removePrefix(PREFIX_ID_SEARCH).trim() - if (id.toIntOrNull() == null) { - throw Exception("ID tìm kiếm không hợp lệ (phải là một số).") + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return when { + query.startsWith(PREFIX_ID_SEARCH) -> { + val id = query.removePrefix(PREFIX_ID_SEARCH).trim() + if (id.toIntOrNull() == null) { + throw Exception("ID tìm kiếm không hợp lệ (phải là một số).") + } + fetchMangaDetails( + SManga.create().apply { + url = "/manga/$id" + }, + ) + .map { MangasPage(listOf(it), false) } } - fetchMangaDetails( - SManga.create().apply { - url = "/manga/$id" - }, - ) - .map { MangasPage(listOf(it), false) } + else -> super.fetchSearchManga(page, query, filters) } - else -> super.fetchSearchManga(page, query, filters) } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { @@ -182,13 +182,15 @@ class YuriNeko : override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response) - override fun fetchMangaDetails(manga: SManga): Observable = client.newCall(GET("$apiUrl${manga.url}")) - .asObservableSuccess() - .map { mangaDetailsParse(it) } + override fun fetchMangaDetails(manga: SManga): Observable = + client.newCall(GET("$apiUrl${manga.url}")) + .asObservableSuccess() + .map { mangaDetailsParse(it) } override fun mangaDetailsRequest(manga: SManga): Request = GET("$baseUrl${manga.url}") - override fun mangaDetailsParse(response: Response): SManga = response.parseAs().toSManga(storageUrl) + override fun mangaDetailsParse(response: Response): SManga = + response.parseAs().toSManga(storageUrl) override fun chapterListRequest(manga: SManga): Request = GET("$apiUrl${manga.url}") @@ -200,11 +202,13 @@ class YuriNeko : override fun pageListRequest(chapter: SChapter): Request = GET("$apiUrl${chapter.url}") - override fun pageListParse(response: Response): List = response.parseAs().toPageList(storageUrl) + override fun pageListParse(response: Response): List = + response.parseAs().toPageList(storageUrl) override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException() - open class UriPartFilter(displayName: String, private val vals: Array>) : Filter.Select(displayName, vals.map { it.first }.toTypedArray()) { + open class UriPartFilter(displayName: String, private val vals: Array>) : + Filter.Select(displayName, vals.map { it.first }.toTypedArray()) { fun toUriPart() = vals[state].second }