From 1c6acb0eb5e5f43cf2c41ce89a7ef82d600c11e0 Mon Sep 17 00:00:00 2001 From: vulpes310 <85771934+vulpes310@users.noreply.github.com> Date: Mon, 14 Jun 2021 04:16:06 -0700 Subject: [PATCH] Rewrite NyaHentai Filter and add deeplink support (#7618) * Rewrite NyaHentai Filter and add deeplink support [Fix] tarUrl not initialized when using filter search The tagUrl is not initialized and will never get initialized, resulting in the search page not been able to load more than one page. Fixed by rewrite the searchMangaRequest. [Feat] Enable filter search for parody, character, artist, and group [Feat] Enable sort by time or popularity search when not in a specific language. [Feat] Add deeplink support * Fix filter parody value * Fix query search URL schema --- .../nyahentai/default/AndroidManifest.xml | 22 +++ .../tachiyomi/multisrc/nyahentai/NyaHentai.kt | 146 +++++++++++++----- .../multisrc/nyahentai/NyaHentaiGenerator.kt | 2 +- .../nyahentai/NyaHentaiUrlActivity.kt | 42 +++++ 4 files changed, 170 insertions(+), 42 deletions(-) create mode 100644 multisrc/overrides/nyahentai/default/AndroidManifest.xml create mode 100644 multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiUrlActivity.kt diff --git a/multisrc/overrides/nyahentai/default/AndroidManifest.xml b/multisrc/overrides/nyahentai/default/AndroidManifest.xml new file mode 100644 index 000000000..7414bc582 --- /dev/null +++ b/multisrc/overrides/nyahentai/default/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentai.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentai.kt index b60fd7ae9..79e57499f 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentai.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentai.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.multisrc.nyahentai import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage @@ -14,15 +15,19 @@ import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import rx.Observable -abstract class NyaHentai ( +abstract class NyaHentai( override val name: String, override val baseUrl: String, override val lang: String - ) : ParsedHttpSource() { +) : ParsedHttpSource() { companion object { - const val TAG = "NyaHentai" + private const val NOT_FOUND_MESSAGE = "If you used a filter, check if the keyword actually exists." + private const val Filter_SEARCH_MESSAGE = "NOTE: Ignored if using text search!" + const val PREFIX_ID_SEARCH = "id:" } + val nyaLang = when (lang) { "en" -> "english" "zh" -> "chinese" @@ -30,7 +35,7 @@ abstract class NyaHentai ( else -> "" } - val languageUrl = when (nyaLang){ + val languageUrl = when (nyaLang) { "" -> baseUrl else -> "$baseUrl/language/$nyaLang" } @@ -149,10 +154,13 @@ abstract class NyaHentai ( throw UnsupportedOperationException("Not used") override fun popularMangaRequest(page: Int): Request = - GET(when (nyaLang){ - "" -> "$languageUrl/page/$page" - else -> "$languageUrl/popular/page/$page" - }, headers) + GET( + when (nyaLang) { + "" -> "$languageUrl/page/$page" + else -> "$languageUrl/popular/page/$page" + }, + headers + ) override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element) @@ -160,43 +168,55 @@ abstract class NyaHentai ( override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector() - private lateinit var tagUrl: String - - // TODO: Additional filter options, specifically the type[] parameter override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - // todo: remove "english" from the search query in the future - var url = "$baseUrl/search/q_$query $nyaLang/page/$page" - - if (query.isBlank()) { - filters.forEach { filter -> - when (filter) { - is Tag -> { - url = if (page == 1) { - "$baseUrl/tag/${filter.state}/$nyaLang" // "Contents" tag - } else { - "$tagUrl/page/$page" - } - } + if (query.isNotBlank()) { + // Normal search + return GET("$baseUrl/search/q_$query $nyaLang/page/$page", headers) + } else { + val type = filters.filterIsInstance() + .joinToString("") { + (it as UriPartFilter).toUriPart() } + val keyword = filters.filterIsInstance().toString() + .replace("[", "").replace("]", "") + var sort = nyaLang + if (nyaLang == "") { + sort = filters.filterIsInstance() + .joinToString("") { + (it as UriPartFilter).toUriPart() + } } + val url = "$baseUrl/$type/$keyword/$sort/page/$page" + return GET(url, headers) } + } - return GET(url, headers) + // For NyaHentaiUrlActivity + private fun searchMangaByIdRequest(id: String) = GET("$baseUrl/g/$id", headers) + + private fun searchMangaByIdParse(response: Response, id: String): MangasPage { + val sManga = mangaDetailsParse(response) + sManga.url = "/g/$id/" + return MangasPage(listOf(sManga), false) + } + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return if (query.startsWith(PREFIX_ID_SEARCH)) { + val id = query.removePrefix(PREFIX_ID_SEARCH) + client.newCall(searchMangaByIdRequest(id)) + .asObservableSuccess() + .map { response -> searchMangaByIdParse(response, id) } + } else { + super.fetchSearchManga(page, query, filters) + } } override fun searchMangaParse(response: Response): MangasPage { - return if (response.request.url.toString().contains("tag?")) { - response.asJsoup().select("table.table tbody tr a:first-of-type").attr("abs:href").let { - if (it.isNotEmpty()) { - tagUrl = it - super.searchMangaParse(client.newCall(GET(tagUrl, headers)).execute()) - } else { - MangasPage(emptyList(), false) - } - } - } else { - super.searchMangaParse(response) + if (!response.isSuccessful) { + response.close() + throw Exception(NOT_FOUND_MESSAGE) } + return super.searchMangaParse(response) } override fun searchMangaSelector() = latestUpdatesSelector() @@ -205,11 +225,55 @@ abstract class NyaHentai ( override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector() - override fun getFilterList() = FilterList( - Filter.Header("NOTE: Ignored if using text search!"), - Filter.Separator(), - Tag("Tag") + override fun getFilterList(): FilterList { + if (nyaLang == "") { + return FilterList( + Filter.Header(Filter_SEARCH_MESSAGE), + Filter.Separator(), + SortFilter(), + TypeFilter(), + Text("Keyword") + ) + } else { + return FilterList( + Filter.Header(Filter_SEARCH_MESSAGE), + Filter.Separator(), + TypeFilter(), + Text("Keyword") + ) + } + } + + private open class UriPartFilter( + displayName: String, + val pair: Array>, + defaultState: Int = 0 + ) : Filter.Select(displayName, pair.map { it.first }.toTypedArray(), defaultState) { + open fun toUriPart() = pair[state].second + } + + private class TypeFilter : UriPartFilter( + "Type", + arrayOf( + Pair("Tag", "tag"), + Pair("Parody", "parody"), + Pair("Character", "character"), + Pair("Artist", "artist"), + Pair("Group", "group") + ) ) - private class Tag(name: String) : Filter.Text(name) + private class SortFilter : UriPartFilter( + "Sort by", + arrayOf( + Pair("Time", ""), + Pair("Popular", "popular"), + ) + ) + + private class Text(name: String) : Filter.Text(name) { + override fun toString(): String { + return state + } + } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiGenerator.kt index 378be9ffb..e9c56146d 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiGenerator.kt @@ -9,7 +9,7 @@ class NyaHentaiGenerator : ThemeSourceGenerator { override val themeClass = "NyaHentai" - override val baseVersionCode: Int = 1 + override val baseVersionCode: Int = 2 override val sources = listOf( MultiLang("NyaHentai", "https://nyahentai.com", listOf("en","ja", "zh", "all"), isNsfw = true, className = "NyaHentaiFactory", overrideVersionCode = 3), diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiUrlActivity.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiUrlActivity.kt new file mode 100644 index 000000000..dc5647a80 --- /dev/null +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/nyahentai/NyaHentaiUrlActivity.kt @@ -0,0 +1,42 @@ +package eu.kanade.tachiyomi.multisrc.nyahentai + +import android.app.Activity +import android.content.ActivityNotFoundException +import android.content.Intent +import android.os.Bundle +import android.util.Log +import eu.kanade.tachiyomi.multisrc.nyahentai.NyaHentai +import kotlin.system.exitProcess + +/** + * Springboard that accepts https://www.manhuagui.com/comic/xxx intents and redirects them to + * the main tachiyomi process. The idea is to not install the intent filter unless + * you have this extension installed, but still let the main tachiyomi app control + * things. + */ +class NyaHentaiUrlActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val pathSegments = intent?.data?.pathSegments + if (pathSegments != null && pathSegments.size > 1) { + val titleid = pathSegments[1] + val mainIntent = Intent().apply { + action = "eu.kanade.tachiyomi.SEARCH" + putExtra("query", "${NyaHentai.PREFIX_ID_SEARCH}$titleid") + putExtra("filter", packageName) + } + + try { + startActivity(mainIntent) + } catch (e: ActivityNotFoundException) { + Log.e("NyaHentaiUrlActivity", e.toString()) + } + } else { + Log.e("NyaHentaiUrlActivity", "could not parse uri from intent $intent") + } + + finish() + exitProcess(0) + } +}