From 28234597b376c299dd29ccb177e8847d3a485c42 Mon Sep 17 00:00:00 2001 From: ObserverOfTime Date: Mon, 2 Aug 2021 17:59:23 +0300 Subject: [PATCH] Implement client-side search in Bakkin (#8351) --- .../bakkinselfhosted/src/BakkinSelfHosted.kt | 22 +++-- .../multisrc/bakkin/BakkinGenerator.kt | 5 +- .../tachiyomi/multisrc/bakkin/BakkinJSON.kt | 3 +- .../multisrc/bakkin/BakkinReaderX.kt | 90 ++++++++++--------- 4 files changed, 64 insertions(+), 56 deletions(-) diff --git a/multisrc/overrides/bakkin/bakkinselfhosted/src/BakkinSelfHosted.kt b/multisrc/overrides/bakkin/bakkinselfhosted/src/BakkinSelfHosted.kt index df2bd3dc4..883978188 100644 --- a/multisrc/overrides/bakkin/bakkinselfhosted/src/BakkinSelfHosted.kt +++ b/multisrc/overrides/bakkin/bakkinselfhosted/src/BakkinSelfHosted.kt @@ -11,19 +11,17 @@ class BakkinSelfHosted : BakkinReaderX("Bakkin Self-hosted", "", "en") { override fun setupPreferenceScreen(screen: PreferenceScreen) { super.setupPreferenceScreen(screen) - screen.addPreference( - EditTextPreference(screen.context).apply { - key = "baseUrl" - title = "Custom URL" - summary = "Connect to a self-hosted Bakkin Reader X server" - setDefaultValue("http://127.0.0.1/") + EditTextPreference(screen.context).apply { + key = "baseUrl" + title = "Custom URL" + summary = "Connect to a self-hosted Bakkin Reader X server" + setDefaultValue("http://127.0.0.1/") - setOnPreferenceChangeListener { _, newValue -> - // Make sure the URL ends with one slash - val url = (newValue as String).trimEnd('/') + '/' - preferences.edit().putString("baseUrl", url).commit() - } + setOnPreferenceChangeListener { _, newValue -> + // Make sure the URL ends with one slash + val url = (newValue as String).trimEnd('/') + '/' + preferences.edit().putString("baseUrl", url).commit() } - ) + }.let(screen::addPreference) } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinGenerator.kt index a1bd56dcc..ad93787df 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinGenerator.kt @@ -8,7 +8,7 @@ class BakkinGenerator : ThemeSourceGenerator { override val themeClass = "BakkinReaderX" - override val baseVersionCode: Int = 1 + override val baseVersionCode = 2 override val sources = listOf( SingleLang("Bakkin", "https://bakkin.moe/reader/", "en"), @@ -16,6 +16,7 @@ class BakkinGenerator : ThemeSourceGenerator { ) companion object { - @JvmStatic fun main(args: Array) = BakkinGenerator().createAll() + @JvmStatic + fun main(args: Array) = BakkinGenerator().createAll() } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinJSON.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinJSON.kt index 38e3e5c2f..8370699cb 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinJSON.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinJSON.kt @@ -14,7 +14,8 @@ internal data class Series( it.map { ch -> ch.copy(name = "$it - $ch") } }.iterator() - val cover get() = thumb ?: "static/nocover.png" + val cover: String + get() = thumb ?: "static/nocover.png" override fun toString() = name.ifEmpty { dir } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinReaderX.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinReaderX.kt index b04b9f3b1..7c84dac9b 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinReaderX.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakkin/BakkinReaderX.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.multisrc.bakkin import android.app.Application import android.os.Build -import androidx.preference.CheckBoxPreference +import androidx.preference.ListPreference import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.network.GET @@ -18,9 +18,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.jsonObject import okhttp3.Headers -import okhttp3.Request import okhttp3.Response -import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -41,28 +39,38 @@ abstract class BakkinReaderX( private val json by lazy { Injekt.get() } - private val mainUrl - get() = baseUrl + "/main.php" + - if (preferences.getBoolean("fullsize", false)) "?fullsize" else "" + private val mainUrl: String + get() = baseUrl + "main.php" + preferences.getString("quality", "") private var seriesCache = emptyList() private fun observableSeries(block: (List) -> R) = - if (seriesCache.isNotEmpty()) Observable.just(block(seriesCache)) - else client.newCall(GET(mainUrl, headers)).asObservableSuccess().map { - seriesCache = json.parseToJsonElement(it.body!!.string()) - .jsonObject.values.map(json::decodeFromJsonElement) - block(seriesCache) + if (seriesCache.isNotEmpty()) { + rx.Observable.just(block(seriesCache))!! + } else { + client.newCall(GET(mainUrl, headers)).asObservableSuccess().map { + seriesCache = json.parseToJsonElement(it.body!!.string()) + .jsonObject.values.map(json::decodeFromJsonElement) + block(seriesCache) + }!! } - override fun headersBuilder() = Headers.Builder().add("User-Agent", userAgent) + private fun List.search(query: String) = + if (query.isBlank()) this else filter { it.toString().contains(query, true) } + + override fun headersBuilder() = + Headers.Builder().add("User-Agent", userAgent) // Request the actual manga URL for the webview - override fun mangaDetailsRequest(manga: SManga) = GET("$baseUrl#m=${manga.url}", headers) + override fun mangaDetailsRequest(manga: SManga) = + GET("$baseUrl#m=${manga.url}", headers) - override fun fetchPopularManga(page: Int): Observable = + override fun fetchPopularManga(page: Int) = + fetchSearchManga(page, "", FilterList()) + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList) = observableSeries { series -> - series.map { + series.search(query).map { SManga.create().apply { url = it.dir title = it.toString() @@ -71,7 +79,7 @@ abstract class BakkinReaderX( }.let { MangasPage(it, false) } } - override fun fetchMangaDetails(manga: SManga): Observable = + override fun fetchMangaDetails(manga: SManga) = observableSeries { series -> series.first { it.dir == manga.url }.let { SManga.create().apply { @@ -89,65 +97,65 @@ abstract class BakkinReaderX( } } - override fun fetchChapterList(manga: SManga): Observable> = + override fun fetchChapterList(manga: SManga) = observableSeries { series -> series.first { it.dir == manga.url }.mapIndexed { idx, chapter -> SChapter.create().apply { url = chapter.dir name = chapter.toString() chapter_number = idx.toFloat() - date_upload = -1L + date_upload = 0L } } } - override fun fetchPageList(chapter: SChapter): Observable> = + override fun fetchPageList(chapter: SChapter) = observableSeries { series -> series.flatten().first { it.dir == chapter.url } - .mapIndexed { idx, page -> Page(idx, "", "$baseUrl$page") } + .mapIndexed { idx, page -> Page(idx, "", baseUrl + page) } } override fun setupPreferenceScreen(screen: PreferenceScreen) { - screen.addPreference( - CheckBoxPreference(screen.context).apply { - key = "fullsize" - summary = "View fullsize images" - setDefaultValue(false) + ListPreference(screen.context).apply { + key = "quality" + summary = "Image quality: %s" + entries = arrayOf("Original", "Compressed") + entryValues = arrayOf("?fullsize", "") + setDefaultValue("") - setOnPreferenceChangeListener { _, newValue -> - preferences.edit().putBoolean(key, newValue as Boolean).commit() - } + setOnPreferenceChangeListener { _, newValue -> + preferences.edit().putString(key, newValue as String).commit() } - ) + }.let(screen::addPreference) } - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = - throw UnsupportedOperationException("Search is not supported by this source.") - - override fun popularMangaRequest(page: Int): Request = + override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException("Not used!") - override fun latestUpdatesRequest(page: Int): Request = + override fun popularMangaRequest(page: Int) = throw UnsupportedOperationException("Not used!") - override fun searchMangaParse(response: Response): MangasPage = + override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("Not used!") - override fun popularMangaParse(response: Response): MangasPage = + override fun searchMangaParse(response: Response) = throw UnsupportedOperationException("Not used!") - override fun latestUpdatesParse(response: Response): MangasPage = + override fun popularMangaParse(response: Response) = throw UnsupportedOperationException("Not used!") - override fun mangaDetailsParse(response: Response): SManga = + override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException("Not used!") - override fun chapterListParse(response: Response): List = + override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException("Not used!") - override fun pageListParse(response: Response): List = + override fun chapterListParse(response: Response) = throw UnsupportedOperationException("Not used!") - override fun imageUrlParse(response: Response): String = + override fun pageListParse(response: Response) = + throw UnsupportedOperationException("Not used!") + + override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Not used!") }