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)
+ }
+}