From 734c7a1e85509204fb6ad7967c610082597ced71 Mon Sep 17 00:00:00 2001
From: KenjieDec <65448230+KenjieDec@users.noreply.github.com>
Date: Wed, 17 Jul 2024 17:26:00 +0700
Subject: [PATCH] Panda Chaika: Add Character Filter, Fix Sort Filters, Add ID
search (#4049)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add Character Filter, ID search
* Fix Sort Filters
* Apply Suggestions
*
* Apply Suggestion
* typo fix
---
src/all/pandachaika/AndroidManifest.xml | 23 ++++++
src/all/pandachaika/build.gradle | 2 +-
.../extension/all/pandachaika/PandaChaika.kt | 82 +++++++++++++++++++
.../all/pandachaika/PandaChaikaDto.kt | 43 ++++++----
.../all/pandachaika/PandaChaikaFilters.kt | 7 +-
.../all/pandachaika/PandaChaikaUrlActivity.kt | 34 ++++++++
6 files changed, 172 insertions(+), 19 deletions(-)
create mode 100644 src/all/pandachaika/AndroidManifest.xml
create mode 100644 src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaUrlActivity.kt
diff --git a/src/all/pandachaika/AndroidManifest.xml b/src/all/pandachaika/AndroidManifest.xml
new file mode 100644
index 000000000..3fa96d78f
--- /dev/null
+++ b/src/all/pandachaika/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/all/pandachaika/build.gradle b/src/all/pandachaika/build.gradle
index 6c786858b..69fcca671 100644
--- a/src/all/pandachaika/build.gradle
+++ b/src/all/pandachaika/build.gradle
@@ -1,7 +1,7 @@
ext {
extName = 'PandaChaika'
extClass = '.PandaChaikaFactory'
- extVersionCode = 1
+ extVersionCode = 2
isNsfw = true
}
diff --git a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaika.kt b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaika.kt
index 0ba95d632..a86187594 100644
--- a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaika.kt
+++ b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaika.kt
@@ -1,6 +1,8 @@
package eu.kanade.tachiyomi.extension.all.pandachaika
import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.network.asObservable
+import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
@@ -42,6 +44,9 @@ class PandaChaika(
private val json: Json by injectLazy()
+ private val fakkuRegex = Regex("""(?:https?://)?(?:www\.)?fakku\.net/hentai/""")
+ private val ehentaiRegex = Regex("""(?:https?://)?e-hentai\.org/g/""")
+
// Popular
override fun popularMangaRequest(page: Int): Request {
return GET("$baseSearchUrl/?tags=$searchLang&sort=rating&apply=&json=&page=$page", headers)
@@ -73,6 +78,76 @@ class PandaChaika(
}
}
+ override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable {
+ return when {
+ query.startsWith(PREFIX_ID_SEARCH) -> {
+ val id = query.removePrefix(PREFIX_ID_SEARCH).toInt()
+ client.newCall(GET("$baseUrl/api?archive=$id", headers))
+ .asObservable()
+ .map { response ->
+ searchMangaByIdParse(response, id)
+ }
+ }
+ query.startsWith(PREFIX_EHEN_ID_SEARCH) -> {
+ val id = query.removePrefix(PREFIX_EHEN_ID_SEARCH).replace(ehentaiRegex, "")
+ val baseLink = "https://e-hentai.org/g/"
+ val fullLink = baseSearchUrl.toHttpUrl().newBuilder().apply {
+ addQueryParameter("qsearch", baseLink + id)
+ addQueryParameter("json", "")
+ }.build()
+ client.newCall(GET(fullLink, headers))
+ .asObservableSuccess()
+ .map {
+ val archive = it.parseAs().archives.getOrNull(0)?.toSManga() ?: throw Exception("Not Found")
+ MangasPage(listOf(archive), false)
+ }
+ }
+ query.startsWith(PREFIX_FAK_ID_SEARCH) -> {
+ val slug = query.removePrefix(PREFIX_FAK_ID_SEARCH).replace(fakkuRegex, "")
+ val baseLink = "https://www.fakku.net/hentai/"
+ val fullLink = baseSearchUrl.toHttpUrl().newBuilder().apply {
+ addQueryParameter("qsearch", baseLink + slug)
+ addQueryParameter("json", "")
+ }.build()
+ client.newCall(GET(fullLink, headers))
+ .asObservableSuccess()
+ .map {
+ val archive = it.parseAs().archives.getOrNull(0)?.toSManga() ?: throw Exception("Not Found")
+ MangasPage(listOf(archive), false)
+ }
+ }
+ query.startsWith(PREFIX_SOURCE_SEARCH) -> {
+ val url = query.removePrefix(PREFIX_SOURCE_SEARCH)
+ client.newCall(GET("$baseSearchUrl/?qsearch=$url&json=", headers))
+ .asObservableSuccess()
+ .map {
+ val archive = it.parseAs().archives.getOrNull(0)?.toSManga() ?: throw Exception("Not Found")
+ MangasPage(listOf(archive), false)
+ }
+ }
+
+ else -> super.fetchSearchManga(page, query, filters)
+ }
+ }
+
+ private fun searchMangaByIdParse(response: Response, id: Int = 0): MangasPage {
+ val title = response.parseAs().title
+ val fullLink = baseSearchUrl.toHttpUrl().newBuilder().apply {
+ addQueryParameter("qsearch", title)
+ addQueryParameter("json", "")
+ }.build()
+ val archive = client.newCall(GET(fullLink, headers))
+ .execute()
+ .parseAs().archives
+ .find {
+ it.id == id
+ }
+ ?.toSManga()
+ ?: throw Exception("Invalid ID")
+
+ return MangasPage(listOf(archive), false)
+ }
+
override fun searchMangaParse(response: Response): MangasPage {
val library = response.parseAs()
@@ -250,4 +325,11 @@ class PandaChaika(
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
override fun pageListParse(response: Response): List = throw UnsupportedOperationException()
override fun mangaDetailsParse(response: Response): SManga = throw UnsupportedOperationException()
+
+ companion object {
+ const val PREFIX_ID_SEARCH = "id:"
+ const val PREFIX_FAK_ID_SEARCH = "fakku:"
+ const val PREFIX_EHEN_ID_SEARCH = "ehentai:"
+ const val PREFIX_SOURCE_SEARCH = "source:"
+ }
}
diff --git a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaDto.kt b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaDto.kt
index 17ce374a0..0fcf6751d 100644
--- a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaDto.kt
+++ b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaDto.kt
@@ -8,7 +8,7 @@ import java.util.Date
import java.util.Locale
val dateReformat = SimpleDateFormat("EEEE, d MMM yyyy HH:mm (z)", Locale.ENGLISH)
-fun filterTags(include: String = "", exclude: List = emptyList(), tags: List): String {
+fun filterTags(include: String = "", exclude: List = emptyList(), tags: List): String? {
return tags.filter { it.startsWith("$include:") && exclude.none { substring -> it.startsWith("$substring:") } }
.joinToString {
it.substringAfter(":").replace("_", " ").split(" ").joinToString(" ") { s ->
@@ -16,13 +16,13 @@ fun filterTags(include: String = "", exclude: List = emptyList(), tags:
if (sr.isLowerCase()) sr.titlecase(Locale.getDefault()) else sr.toString()
}
}
- }
+ }.takeIf { it.isNotBlank() }
}
fun getReadableSize(bytes: Double): String {
return when {
- bytes >= 300 * 1024 * 1024 -> "${"%.2f".format(bytes / (1024.0 * 1024.0 * 1024.0))} GB"
- bytes >= 100 * 1024 -> "${"%.2f".format(bytes / (1024.0 * 1024.0))} MB"
- bytes >= 1024 -> "${"%.2f".format(bytes / (1024.0))} KB"
+ bytes >= 300 * 1000 * 1000 -> "${"%.2f".format(bytes / (1000.0 * 1000.0 * 1000.0))} GB"
+ bytes >= 100 * 1000 -> "${"%.2f".format(bytes / (1000.0 * 1000.0))} MB"
+ bytes >= 1000 -> "${"%.2f".format(bytes / (1000.0))} kB"
else -> "$bytes B"
}
}
@@ -31,13 +31,14 @@ fun getReadableSize(bytes: Double): String {
class Archive(
val download: String,
val posted: Long,
+ val title: String,
)
@Serializable
class LongArchive(
private val thumbnail: String,
private val title: String,
- private val id: Int,
+ val id: Int,
private val posted: Long?,
private val public_date: Long?,
private val filecount: Int,
@@ -50,35 +51,47 @@ class LongArchive(
val groups = filterTags("group", tags = tags)
val artists = filterTags("artist", tags = tags)
val publishers = filterTags("publisher", tags = tags)
+ val characters = filterTags("character", tags = tags)
val male = filterTags("male", tags = tags)
val female = filterTags("female", tags = tags)
val others = filterTags(exclude = listOf("female", "male", "artist", "publisher", "group", "parody"), tags = tags)
val parodies = filterTags("parody", tags = tags)
+ var appended = false
+
url = id.toString()
title = this@LongArchive.title
thumbnail_url = thumbnail
- author = groups.ifEmpty { artists }
+ author = groups ?: artists
artist = artists
genre = listOf(male, female, others).joinToString()
description = buildString {
append("Uploader: ", uploader.ifEmpty { "Anonymous" }, "\n")
- publishers.takeIf { it.isNotBlank() }?.let {
- append("Publishers: ", it, "\n\n")
+ publishers?.let {
+ append("Publishers: ", it, "\n")
}
- parodies.takeIf { it.isNotBlank() }?.let {
- append("Parodies: ", it, "\n\n")
+ append("\n")
+
+ parodies?.let {
+ append("Parodies: ", it, "\n")
+ appended = true
}
- male.takeIf { it.isNotBlank() }?.let {
+ characters?.let {
+ append("Characters: ", it, "\n")
+ appended = true
+ }
+ if (appended) append("\n")
+
+ male?.let {
append("Male tags: ", it, "\n\n")
}
- female.takeIf { it.isNotBlank() }?.let {
+ female?.let {
append("Female tags: ", it, "\n\n")
}
- others.takeIf { it.isNotBlank() }?.let {
+ others?.let {
append("Other tags: ", it, "\n\n")
}
- title_jpn?.let { append("Japanese Title: ", it, "\n") }
+ title_jpn?.takeIf { it.isNotEmpty() }?.let { append("Japanese Title: ", it, "\n") }
append("Pages: ", filecount, "\n")
append("File Size: ", getReadableSize(filesize), "\n")
diff --git a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaFilters.kt b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaFilters.kt
index 4c6f31c22..40f1cc67c 100644
--- a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaFilters.kt
+++ b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaFilters.kt
@@ -17,6 +17,7 @@ fun getFilters(): FilterList {
TextFilter("Female Tags", "female"),
TextFilter("Artists", "artist"),
TextFilter("Parodies", "parody"),
+ TextFilter("Characters", "character"),
Filter.Separator(),
TextFilter("Reason", "reason"),
TextFilter("Uploader", "reason"),
@@ -52,11 +53,11 @@ private val getTypes = listOf(
private val getSortsList: List> = listOf(
Pair("Public Date", "public_date"),
- Pair("Posted Date", "posted_date"),
+ Pair("Posted Date", "posted"),
Pair("Title", "title"),
Pair("Japanese Title", "title_jpn"),
Pair("Rating", "rating"),
- Pair("Images", "images"),
- Pair("File Size", "size"),
+ Pair("Images", "filecount"),
+ Pair("File Size", "filesize"),
Pair("Category", "category"),
)
diff --git a/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaUrlActivity.kt b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaUrlActivity.kt
new file mode 100644
index 000000000..e4b53c05e
--- /dev/null
+++ b/src/all/pandachaika/src/eu/kanade/tachiyomi/extension/all/pandachaika/PandaChaikaUrlActivity.kt
@@ -0,0 +1,34 @@
+package eu.kanade.tachiyomi.extension.all.pandachaika
+
+import android.app.Activity
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import kotlin.system.exitProcess
+
+class PandaChaikaUrlActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val pathSegments = intent?.data?.pathSegments
+ if (pathSegments != null && pathSegments.size > 2) {
+ val id = "${pathSegments[1]}/${pathSegments[2]}"
+ val mainIntent = Intent().apply {
+ action = "eu.kanade.tachiyomi.SEARCH"
+ putExtra("query", "${PandaChaika.PREFIX_ID_SEARCH}$id")
+ putExtra("filter", packageName)
+ }
+
+ try {
+ startActivity(mainIntent)
+ } catch (e: ActivityNotFoundException) {
+ Log.e("KoharuUrlActivity", "Could not start activity", e)
+ }
+ } else {
+ Log.e("KoharuUrlActivity", "Could not parse URI from intent $intent")
+ }
+
+ finish()
+ exitProcess(0)
+ }
+}