mirror of
https://github.com/keiyoushi/extensions-source.git
synced 2024-11-22 10:22:47 +01:00
Akuma: Add Filters, Add Factory for specific language, Improve manga description and tags (#3351)
* 1. Add language for manga description 2. Add a custom preference to choice if show gender as text or icon * fix code style * revert extra formatting * change preference into switch * remove unused import, increase extVersionCode * Add filter, split into specific languages * Apply suggestions from code review * Change Filter style, Add Filter, Add exclude syntax * Change Code Style * Remove RateLimit Preference, Remove Syntax Filter --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
parent
bfef7faafb
commit
c47b9d852d
@ -1,7 +1,7 @@
|
||||
ext {
|
||||
extName = 'Akuma'
|
||||
extClass = '.Akuma'
|
||||
extVersionCode = 1
|
||||
extClass = '.AkumaFactory'
|
||||
extVersionCode = 2
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
package eu.kanade.tachiyomi.extension.all.akuma
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
@ -20,16 +26,19 @@ import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
|
||||
class Akuma : ParsedHttpSource() {
|
||||
class Akuma(
|
||||
override val lang: String,
|
||||
private val akumaLang: String,
|
||||
) : ConfigurableSource, ParsedHttpSource() {
|
||||
|
||||
override val name = "Akuma"
|
||||
|
||||
override val baseUrl = "https://akuma.moe"
|
||||
|
||||
override val lang = "all"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
private var nextHash: String? = null
|
||||
@ -38,6 +47,12 @@ class Akuma : ParsedHttpSource() {
|
||||
|
||||
private val ddosGuardIntercept = DDosGuardInterceptor(network.client)
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
private var iconified = preferences.getBoolean(PREF_TAG_GENDER_ICON, false)
|
||||
|
||||
override val client: OkHttpClient = network.client.newBuilder()
|
||||
.addInterceptor(ddosGuardIntercept)
|
||||
.addInterceptor(::tokenInterceptor)
|
||||
@ -102,12 +117,19 @@ class Akuma : ParsedHttpSource() {
|
||||
.add("view", "3")
|
||||
.build()
|
||||
|
||||
return if (page == 1) {
|
||||
val url = baseUrl.toHttpUrlOrNull()!!.newBuilder()
|
||||
|
||||
if (page == 1) {
|
||||
nextHash = null
|
||||
POST(baseUrl, headers, payload)
|
||||
} else {
|
||||
POST("$baseUrl/?cursor=$nextHash", headers, payload)
|
||||
url.addQueryParameter("cursor", nextHash)
|
||||
}
|
||||
if (lang != "all") {
|
||||
// append like `q=language:english$`
|
||||
url.addQueryParameter("q", "language:$akumaLang$")
|
||||
}
|
||||
|
||||
return POST(url.toString(), headers, payload)
|
||||
}
|
||||
|
||||
override fun popularMangaSelector() = ".post-loop li"
|
||||
@ -154,8 +176,39 @@ class Akuma : ParsedHttpSource() {
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val request = popularMangaRequest(page)
|
||||
|
||||
val finalQuery = buildString {
|
||||
append(query)
|
||||
if (lang != "all") {
|
||||
append(" language:", akumaLang, "$")
|
||||
}
|
||||
filters.filterIsInstance<TextFilter>().forEach { filter ->
|
||||
if (filter.state.isBlank()) return@forEach
|
||||
filter.state.split(",").forEach {
|
||||
// append like `a:"eye-covering bang"$`
|
||||
if (it.startsWith("-")) {
|
||||
append(" -", filter.identifier, ":", it.trim().substring(1))
|
||||
} else {
|
||||
append(" ", filter.identifier, ":", it.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
filters.filterIsInstance<OptionFilter>().firstOrNull()?.let {
|
||||
val filter = options[it.state].second
|
||||
if (filter.isNotBlank()) {
|
||||
append(" opt:", filter)
|
||||
}
|
||||
}
|
||||
filters.filterIsInstance<CategoryFilter>().firstOrNull()?.state?.forEach {
|
||||
if (it.isIncluded()) {
|
||||
append(" category:\"", it.name, "\"$")
|
||||
} else if (it.isExcluded()) {
|
||||
append(" -category:\"", it.name, "\"$")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val url = request.url.newBuilder()
|
||||
.addQueryParameter("q", query.trim())
|
||||
.setQueryParameter("q", finalQuery)
|
||||
.build()
|
||||
|
||||
return request.newBuilder()
|
||||
@ -168,14 +221,45 @@ class Akuma : ParsedHttpSource() {
|
||||
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
||||
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
|
||||
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
title = document.select(".entry-title").text()
|
||||
thumbnail_url = document.select(".img-thumbnail").attr("abs:src")
|
||||
author = document.select("li.meta-data > span.artist + span.value").text()
|
||||
genre = document.select(".info-list a").joinToString { it.text() }
|
||||
description = document.select(".pages span.value").text() + " Pages"
|
||||
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
|
||||
status = SManga.COMPLETED
|
||||
override fun mangaDetailsParse(document: Document) = with(document) {
|
||||
SManga.create().apply {
|
||||
title = select(".entry-title").text()
|
||||
thumbnail_url = select(".img-thumbnail").attr("abs:src")
|
||||
|
||||
author = select(".group~.value").eachText().joinToString()
|
||||
artist = select(".artist~.value").eachText().joinToString()
|
||||
|
||||
val characters = select(".character~.value").eachText()
|
||||
val parodies = select(".parody~.value").eachText()
|
||||
val males = select(".male~.value")
|
||||
.map { it.text() + if (iconified) " ♂" else " (male)" }
|
||||
val females = select(".female~.value")
|
||||
.map { it.text() + if (iconified) " ♀" else " (female)" }
|
||||
// show all in tags for quickly searching
|
||||
|
||||
genre = (characters + parodies + males + females).joinToString()
|
||||
description = buildString {
|
||||
append(
|
||||
"Full English and Japanese title: \n",
|
||||
select(".entry-title").text(),
|
||||
"\n",
|
||||
select(".entry-title+span").text(),
|
||||
"\n\n",
|
||||
)
|
||||
|
||||
// translated should show up in the description
|
||||
append("Language: ", select(".language~.value").text(), "\n")
|
||||
append("Pages: ", select(".pages .value").text(), "\n")
|
||||
append("Upload Date: ", select(".date .value>time").text(), "\n")
|
||||
append("Categories: ", selectFirst(".info-list .value")?.text() ?: "Unknown", "\n\n")
|
||||
|
||||
// show followings for easy to reference
|
||||
append("Parodies: ", parodies.joinToString(), "\n")
|
||||
append("Characters: ", characters.joinToString(), "\n")
|
||||
}
|
||||
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
|
||||
status = SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
@ -208,8 +292,66 @@ class Akuma : ParsedHttpSource() {
|
||||
return document.select(".entry-content img").attr("abs:src")
|
||||
}
|
||||
|
||||
override fun getFilterList(): FilterList = FilterList(
|
||||
Filter.Header("Separate tags with commas (,)"),
|
||||
Filter.Header("Prepend with dash (-) to exclude"),
|
||||
TextFilter("Female Tags", "female"),
|
||||
TextFilter("Male Tags", "male"),
|
||||
CategoryFilter(),
|
||||
TextFilter("Groups", "group"),
|
||||
TextFilter("Artists", "artist"),
|
||||
TextFilter("Parody", "parody"),
|
||||
TextFilter("Characters", "character"),
|
||||
Filter.Header("Filter by pages, for example: (>20)"),
|
||||
TextFilter("Pages", "pages"),
|
||||
Filter.Header("Search in favorites, read, or commented"),
|
||||
OptionFilter(),
|
||||
)
|
||||
|
||||
private class CategoryFilter : Filter.Group<CategoryFilter.TagTriState>("Categories", values()) {
|
||||
class TagTriState(name: String) : TriState(name)
|
||||
private companion object {
|
||||
fun values() = listOf(
|
||||
TagTriState("doujinshi"),
|
||||
TagTriState("manga"),
|
||||
TagTriState("artist cg"),
|
||||
TagTriState("game cg"),
|
||||
TagTriState("west"),
|
||||
TagTriState("non-h"),
|
||||
TagTriState("gallery"),
|
||||
TagTriState("cosplay"),
|
||||
TagTriState("asian pron"),
|
||||
TagTriState("misc"),
|
||||
)
|
||||
}
|
||||
}
|
||||
private class TextFilter(placeholder: String, val identifier: String) : Filter.Text(placeholder)
|
||||
private class OptionFilter :
|
||||
Filter.Select<String>("Options", options.map { it.first }.toTypedArray())
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_TAG_GENDER_ICON
|
||||
title = "Show gender as text or icon in tags (requires refresh)"
|
||||
summaryOff = "Show gender as text"
|
||||
summaryOn = "Show gender as icon"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
iconified = newValue == true
|
||||
true
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PREFIX_ID = "id:"
|
||||
private const val PREF_TAG_GENDER_ICON = "pref_tag_gender_icon"
|
||||
private val options = listOf(
|
||||
"None" to "",
|
||||
"Favorited only" to "favorited",
|
||||
"Read only" to "read",
|
||||
"Commented only" to "commented",
|
||||
)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
|
||||
|
@ -0,0 +1,35 @@
|
||||
package eu.kanade.tachiyomi.extension.all.akuma
|
||||
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
class AkumaFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
Akuma("all", "all"),
|
||||
Akuma("en", "english"),
|
||||
Akuma("id", "indonesian"),
|
||||
Akuma("jv", "javanese"),
|
||||
Akuma("ca", "catalan"),
|
||||
Akuma("ceb", "cebuano"),
|
||||
Akuma("cs", "czech"),
|
||||
Akuma("da", "danish"),
|
||||
Akuma("de", "german"),
|
||||
Akuma("et", "estonian"),
|
||||
Akuma("es", "spanish"),
|
||||
Akuma("eo", "esperanto"),
|
||||
Akuma("fr", "french"),
|
||||
Akuma("it", "italian"),
|
||||
Akuma("hi", "hindi"),
|
||||
Akuma("hu", "hungarian"),
|
||||
Akuma("pl", "polish"),
|
||||
Akuma("pt", "portuguese"),
|
||||
Akuma("vi", "vietnamese"),
|
||||
Akuma("tr", "turkish"),
|
||||
Akuma("ru", "russian"),
|
||||
Akuma("uk", "ukrainian"),
|
||||
Akuma("ar", "arabic"),
|
||||
Akuma("ko", "korean"),
|
||||
Akuma("zh", "chinese"),
|
||||
Akuma("ja", "japanese"),
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user