ComickLive | Add option to manually input tags (#11448)
* Add option to manually input tags * Update Comick.kt * Apply AwkwardPeak's Suggestions * comma * transforming serializer on property --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
parent
f817f7b049
commit
91115ac93f
@ -1,7 +1,7 @@
|
||||
ext {
|
||||
extName = 'Comick (Unoriginal)'
|
||||
extClass = '.ComickFactory'
|
||||
extVersionCode = 2
|
||||
extVersionCode = 3
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.all.comicklive
|
||||
import android.util.Log
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
@ -114,38 +115,50 @@ class Comick(
|
||||
|
||||
private var nextCursor: String? = null
|
||||
|
||||
private val spaceSlashRegex = Regex("[ /]")
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
if (page == 1) {
|
||||
nextCursor = null
|
||||
}
|
||||
|
||||
val url = "$baseUrl/api/search".toHttpUrl().newBuilder().apply {
|
||||
addQueryParameter("order_by", filters.firstInstance<SortFilter>().selected)
|
||||
addQueryParameter("order_direction", "desc")
|
||||
filters.firstInstance<SortFilter>().let {
|
||||
addQueryParameter("order_by", it.selected)
|
||||
addQueryParameter("order_direction", if (it.state!!.ascending) "asc" else "desc")
|
||||
}
|
||||
filters.firstInstanceOrNull<GenreFilter>()?.let { genre ->
|
||||
genre.included.forEach {
|
||||
addQueryParameter("genres[]", it)
|
||||
addQueryParameter("genres", it)
|
||||
}
|
||||
genre.excluded.forEach {
|
||||
addQueryParameter("excludes[]", it)
|
||||
addQueryParameter("excludes", it)
|
||||
}
|
||||
}
|
||||
filters.firstInstanceOrNull<TagFilterText>()?.let { text ->
|
||||
text.state.split(",").filter(String::isNotBlank).forEach {
|
||||
val value = it.trim().lowercase().replace(spaceSlashRegex, "-")
|
||||
addQueryParameter(
|
||||
if (value.startsWith("-")) "excluded_tags" else "tags",
|
||||
value.replaceFirst("-", ""),
|
||||
)
|
||||
}
|
||||
}
|
||||
filters.firstInstanceOrNull<TagFilter>()?.let { tag ->
|
||||
tag.included.forEach {
|
||||
addQueryParameter("tags[]", it)
|
||||
addQueryParameter("tags", it)
|
||||
}
|
||||
tag.excluded.forEach {
|
||||
addQueryParameter("excluded_tags[]", it)
|
||||
addQueryParameter("excluded_tags", it)
|
||||
}
|
||||
}
|
||||
filters.firstInstance<DemographicFilter>().checked.forEach {
|
||||
addQueryParameter("demographic[]", it)
|
||||
addQueryParameter("demographic", it)
|
||||
}
|
||||
filters.firstInstance<CreatedAtFilter>().selected?.let {
|
||||
addQueryParameter("time", it)
|
||||
}
|
||||
filters.firstInstance<TypeFilter>().checked.forEach {
|
||||
addQueryParameter("country[]", it)
|
||||
addQueryParameter("country", it)
|
||||
}
|
||||
filters.firstInstance<MinimumChaptersFilter>().state.let {
|
||||
if (it.isNotBlank()) {
|
||||
@ -208,8 +221,8 @@ class Comick(
|
||||
val filters: MutableList<Filter<*>> = mutableListOf(
|
||||
SortFilter(),
|
||||
DemographicFilter(),
|
||||
CreatedAtFilter(),
|
||||
TypeFilter(),
|
||||
CreatedAtFilter(),
|
||||
MinimumChaptersFilter(),
|
||||
StatusFilter(),
|
||||
ContentRatingFilter(),
|
||||
@ -221,7 +234,16 @@ class Comick(
|
||||
GET("$baseUrl/api/metadata", headers, CacheControl.FORCE_CACHE),
|
||||
).await()
|
||||
|
||||
// the cache only request fails if it was not cached already
|
||||
val getTags = preferences.getBoolean(GET_TAGS, true)
|
||||
|
||||
val textTags: List<Filter<*>> = listOf(
|
||||
Filter.Separator(),
|
||||
Filter.Header("Separate tags with commas (,)"),
|
||||
Filter.Header("Prepend with dash (-) to exclude"),
|
||||
TagFilterText(),
|
||||
Filter.Separator(),
|
||||
)
|
||||
|
||||
if (!response.isSuccessful) {
|
||||
metadataClient.newCall(
|
||||
GET("$baseUrl/api/metadata", headers, CacheControl.FORCE_NETWORK),
|
||||
@ -236,10 +258,16 @@ class Comick(
|
||||
},
|
||||
)
|
||||
|
||||
if (!getTags) {
|
||||
filters.addAll(
|
||||
index = 2,
|
||||
textTags,
|
||||
)
|
||||
}
|
||||
filters.addAll(
|
||||
index = 0,
|
||||
listOf(
|
||||
Filter.Header("Press 'reset' to load genres and tags"),
|
||||
Filter.Header("Press 'reset' to load genres ${if (getTags) "and tags" else ""}"),
|
||||
Filter.Separator(),
|
||||
),
|
||||
)
|
||||
@ -251,23 +279,37 @@ class Comick(
|
||||
} catch (e: Throwable) {
|
||||
Log.e(name, "Unable to parse filters", e)
|
||||
|
||||
if (!getTags) {
|
||||
filters.addAll(
|
||||
index = 2,
|
||||
textTags,
|
||||
)
|
||||
}
|
||||
filters.addAll(
|
||||
index = 0,
|
||||
listOf(
|
||||
Filter.Header("Failed to parse genres and tags"),
|
||||
Filter.Header("Failed to parse genres ${if (getTags) "and tags" else ""}"),
|
||||
Filter.Separator(),
|
||||
),
|
||||
)
|
||||
return@runBlocking FilterList(filters)
|
||||
}
|
||||
|
||||
filters.addAll(
|
||||
index = 1,
|
||||
listOf(
|
||||
GenreFilter(data.genres),
|
||||
TagFilter(data.tags),
|
||||
),
|
||||
filters.add(
|
||||
index = 3,
|
||||
GenreFilter(data.genres),
|
||||
)
|
||||
if (!getTags) {
|
||||
filters.addAll(
|
||||
index = 4,
|
||||
textTags,
|
||||
)
|
||||
} else {
|
||||
filters.add(
|
||||
index = 4,
|
||||
TagFilter(data.tags),
|
||||
)
|
||||
}
|
||||
return@runBlocking FilterList(filters)
|
||||
}
|
||||
|
||||
@ -300,7 +342,7 @@ class Comick(
|
||||
if (data.titles.isNotEmpty()) {
|
||||
append("\n\n Alternative Titles: \n")
|
||||
data.titles.forEach {
|
||||
append(it.title, "\n")
|
||||
append("- ", it.title.trim(), "\n")
|
||||
}
|
||||
}
|
||||
}.trim()
|
||||
@ -383,8 +425,17 @@ class Comick(
|
||||
summary = "%s"
|
||||
setDefaultValue("0")
|
||||
}.also(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = GET_TAGS
|
||||
title = "Tags Input Type"
|
||||
summaryOn = "Tags will be in a form of scrollable list"
|
||||
summaryOff = "Tags will need to be inputted manually"
|
||||
setDefaultValue(true)
|
||||
}.also(screen::addPreference)
|
||||
}
|
||||
}
|
||||
|
||||
private val domains = arrayOf("https://comick.live", "https://comick.art")
|
||||
private const val DOMAIN_PREF = "domain_pref"
|
||||
private const val GET_TAGS = "get_tags"
|
||||
|
||||
@ -3,6 +3,11 @@ package eu.kanade.tachiyomi.extension.all.comicklive
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonTransformingSerializer
|
||||
|
||||
@Serializable
|
||||
class Data<T>(
|
||||
@ -60,6 +65,7 @@ class ComicData(
|
||||
@SerialName("md_comic_md_genres")
|
||||
val genres: List<Genres>,
|
||||
@SerialName("md_titles")
|
||||
@Serializable(with = TitleTransform::class)
|
||||
val titles: List<Title>,
|
||||
) {
|
||||
@Serializable
|
||||
@ -79,6 +85,15 @@ class ComicData(
|
||||
)
|
||||
}
|
||||
|
||||
object TitleTransform : JsonTransformingSerializer<List<ComicData.Title>>(
|
||||
ListSerializer(ComicData.Title.serializer()),
|
||||
) {
|
||||
override fun transformDeserialize(element: JsonElement): JsonElement {
|
||||
if (element !is JsonObject) return element
|
||||
return JsonArray(element.values.toList())
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ChapterList(
|
||||
val data: List<Chapter>,
|
||||
|
||||
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.all.comicklive
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import java.util.Calendar
|
||||
import kotlin.collections.filter
|
||||
|
||||
abstract class SelectFilter(
|
||||
name: String,
|
||||
@ -38,16 +39,21 @@ abstract class TriStateGroupFilter(
|
||||
val excluded get() = state.filter { it.isExcluded() }.map { it.slug }
|
||||
}
|
||||
|
||||
class SortFilter : SelectFilter(
|
||||
name = "Sort",
|
||||
options = listOf(
|
||||
"Latest" to "created_at",
|
||||
"Popular" to "user_follow_count",
|
||||
"Highest Rating" to "rating",
|
||||
"Last Uploaded" to "uploaded",
|
||||
),
|
||||
private val getSortsList = listOf(
|
||||
"Latest" to "created_at",
|
||||
"Popular" to "user_follow_count",
|
||||
"Highest Rating" to "rating",
|
||||
"Last Uploaded" to "uploaded",
|
||||
)
|
||||
|
||||
class SortFilter : Filter.Sort(
|
||||
name = "Sort",
|
||||
values = getSortsList.map { it.first }.toTypedArray(),
|
||||
state = Selection(0, false),
|
||||
) {
|
||||
val selected get() = state?.let { getSortsList[it.index] }?.second.takeIf { it?.isNotEmpty() ?: false }
|
||||
}
|
||||
|
||||
class GenreFilter(genres: List<Metadata.Name>) : TriStateGroupFilter(
|
||||
name = "Genre",
|
||||
options = genres.map { it.name to it.slug },
|
||||
@ -58,6 +64,10 @@ class TagFilter(tags: List<Metadata.Name>) : TriStateGroupFilter(
|
||||
options = tags.map { it.name to it.slug },
|
||||
)
|
||||
|
||||
class TagFilterText : Filter.Text(
|
||||
name = "Tags",
|
||||
)
|
||||
|
||||
class DemographicFilter : CheckBoxGroup(
|
||||
name = "Demographic",
|
||||
options = listOf(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user