Update ZeistManga (#15390)

* Update ZeistManga

* Linting

* More Linting

* Update Filters

* Apply requested changes
This commit is contained in:
seew3l 2023-02-18 15:45:27 -05:00 committed by GitHub
parent ee4b27f60c
commit a736f20dd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 283 additions and 28 deletions

View File

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.multisrc.zeistmanga
import eu.kanade.tachiyomi.network.GET
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
@ -25,7 +26,9 @@ abstract class ZeistManga(
) : ParsedHttpSource() {
override val supportsLatest = false
val json: Json by injectLazy()
open val hasFilters = false
protected val json: Json by injectLazy()
protected val intl by lazy { ZeistMangaIntl(lang) }
open val chapterFeedRegex = """clwd\.run\('([^']+)'""".toRegex()
open val scriptSelector = "#clwd > script"
open val imgSelector = "img[src]"
@ -38,12 +41,10 @@ abstract class ZeistManga(
?.groupValues?.get(1)
?: throw Exception("Failed to find chapter feed")
val url = apiUrl(feed)
.addQueryParameter("start-index", "2") // Only get chapters
return apiUrl("Chapter")
.addPathSegments(feed)
.addQueryParameter("max-results", "999999") // Get all chapters
.build()
return url.toString()
.build().toString()
}
override fun chapterListParse(response: Response): List<SChapter> {
@ -51,15 +52,12 @@ abstract class ZeistManga(
val url = getChaptersUrl(document)
// Call JSON API
val req = GET(url, headers)
val res = client.newCall(req).execute()
// Parse JSON API response
val jsonString = res.body.string()
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
// Transform JSON response into List<SChapter>
return result.feed?.entry?.map { it.toSChapter(baseUrl) }
?: throw Exception("Failed to parse from chapter API")
}
@ -108,6 +106,18 @@ abstract class ZeistManga(
throw UnsupportedOperationException("Not used.")
}
override fun searchMangaFromElement(element: Element): SManga {
throw UnsupportedOperationException("Not used.")
}
override fun searchMangaNextPageSelector(): String? {
throw UnsupportedOperationException("Not used.")
}
override fun searchMangaSelector(): String {
throw UnsupportedOperationException("Not used.")
}
override fun mangaDetailsParse(document: Document): SManga {
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
return SManga.create().apply {
@ -115,6 +125,8 @@ abstract class ZeistManga(
thumbnail_url = profileManga.selectFirst("img")!!.attr("src")
description = profileManga.select("#synopsis").text()
status = SManga.UNKNOWN
genre = profileManga.select("div.mt-15 > a[rel=tag]")
.joinToString { it.text() }
}
}
@ -128,9 +140,12 @@ abstract class ZeistManga(
override fun popularMangaParse(response: Response): MangasPage {
val jsonString = response.body.string()
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
// Transform JSON response into List<SManga>
val mangas = result.feed!!.entry?.map { it.toSManga(baseUrl) }
val mangalist = mangas!!.toMutableList()
val mangas = result.feed?.entry.orEmpty()
.filter { !it.category.orEmpty().any { category -> category.term == "Anime" } } // Skip animes
.map { it.toSManga(baseUrl) }
val mangalist = mangas.toMutableList()
if (mangas.size == maxResults + 1) {
mangalist.removeLast()
return MangasPage(mangalist, true)
@ -146,34 +161,140 @@ abstract class ZeistManga(
.addQueryParameter("start-index", startIndex.toString())
.build()
return GET(url.toString(), headers)
return GET(url, headers)
}
override fun searchMangaSelector(): String = ".grid.gtc-f141a > div"
override fun searchMangaFromElement(element: Element): SManga {
return SManga.create().apply {
setUrlWithoutDomain(element.select(".block").attr("href"))
title = element.selectFirst(".clamp.toe.oh.block")!!.text().trim()
thumbnail_url = element.selectFirst("img")!!.attr("src")
}
}
override fun searchMangaParse(response: Response) = popularMangaParse(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = "$baseUrl/search".toHttpUrl().newBuilder()
.addQueryParameter("q", query)
.build()
val startIndex = maxResults * (page - 1) + 1
val url = apiUrl()
.addQueryParameter("max-results", (maxResults + 1).toString())
.addQueryParameter("start-index", startIndex.toString())
return GET(url.toString(), headers)
if (query.isNotBlank()) {
url.addQueryParameter("q", query)
return GET(url.build(), headers)
}
filters.forEach { filter ->
when (filter) {
is StatusList -> {
url.addPathSegment(filter.selected.value)
}
is TypeList -> {
url.addPathSegment(filter.selected.value)
}
is LanguageList -> {
url.addPathSegment(filter.selected.value)
}
is GenreList -> {
filter.state.forEach { genre ->
when (genre.state) {
true -> url.addPathSegment(genre.value)
false -> {}
}
}
}
else -> {}
}
}
return GET(url.build(), headers)
}
override fun searchMangaNextPageSelector(): String? = null
open fun apiUrl(feed: String = "Series"): HttpUrl.Builder {
return "$baseUrl/feeds/posts/default/-/".toHttpUrl().newBuilder()
.addPathSegment(feed)
.addQueryParameter("alt", "json")
}
override fun getFilterList(): FilterList {
if (!hasFilters) {
return FilterList(emptyList())
}
return FilterList(
Filter.Header(intl.filterWarning),
Filter.Separator(),
StatusList(intl.statusFilterTitle, getStatusList()),
TypeList(intl.typeFilterTitle, getTypeList()),
LanguageList(intl.languageFilterTitle, getLanguageList()),
GenreList(intl.genreFilterTitle, getGenreList()),
)
}
// Theme Default Status
protected open fun getStatusList(): List<Status> = listOf(
Status(intl.statusAll, ""),
Status(intl.statusOngoing, "Ongoing"),
Status(intl.statusCompleted, "Completed"),
Status(intl.statusDropped, "Dropped"),
Status(intl.statusUpcoming, "Upcoming"),
)
// Theme Default Types
protected open fun getTypeList(): List<Type> = listOf(
Type(intl.typeAll, ""),
Type(intl.typeManga, "Manga"),
Type(intl.typeManhua, "Manhua"),
Type(intl.typeManhwa, "Manhwa"),
Type(intl.typeNovel, "Novel"),
)
// Theme Default Genres
protected open fun getGenreList(): List<Genre> = listOf(
Genre("Action", "Action"),
Genre("Adventurer", "Adventurer"),
Genre("Comedy", "Comedy"),
Genre("Dementia", "Dementia"),
Genre("Drama", "Drama"),
Genre("Ecchi", "Ecchi"),
Genre("Fantasy", "Fantasy"),
Genre("Game", "Game"),
Genre("Harem", "Harem"),
Genre("Historical", "Historical"),
Genre("Horror", "Horror"),
Genre("Josei", "Josei"),
Genre("Magic", "Magic"),
Genre("Martial Arts", "Martial Arts"),
Genre("Mecha", "Mecha"),
Genre("Military", "Military"),
Genre("Music", "Music"),
Genre("Mystery", "Mystery"),
Genre("Parody", "Parody"),
Genre("Police", "Police"),
Genre("Psychological", "Psychological"),
Genre("Romance", "Romance"),
Genre("Samurai", "Samurai"),
Genre("School", "School"),
Genre("Sci-fi", "Sci-fi"),
Genre("Seinen", "Seinen"),
Genre("Shoujo", "Shoujo"),
Genre("Shoujo Ai", "Shoujo Ai"),
Genre("Shounen", "Shounen"),
Genre("Slice of Life", "Slice of Life"),
Genre("Space", "Space"),
Genre("Sports", "Sports"),
Genre("Super Power", "Super Power"),
Genre("SuperNatural", "SuperNatural"),
Genre("Thriller", "Thriller"),
Genre("Vampire", "Vampire"),
Genre("Work Life", "Work Life"),
Genre("Yuri", "Yuri"),
)
// Theme Default Languages
protected open fun getLanguageList(): List<Language> = listOf(
Language(intl.languageAll, ""),
Language("Indonesian", "Indonesian"),
Language("English", "English"),
)
companion object {
private const val maxResults = 20
}

View File

@ -31,6 +31,7 @@ data class ZeistMangaFeedDto(
data class ZeistMangaEntryDto(
val title: ZeistMangaEntryTitleDto? = null,
val published: ZeistMangaEntryPublishedDto? = null,
val category: List<ZeistMangaEntryCategory>? = emptyList(),
@SerialName("link") val url: List<ZeistMangaEntryLink>? = emptyList(),
val content: ZeistMangaEntryContentDto? = null,
) {
@ -77,3 +78,8 @@ data class ZeistMangaEntryLink(
val rel: String,
val href: String,
)
@Serializable
data class ZeistMangaEntryCategory(
val term: String,
)

View File

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.multisrc.zeistmanga
import eu.kanade.tachiyomi.source.model.Filter
class Genre(title: String, val value: String) : Filter.CheckBox(title)
class GenreList(title: String, genres: List<Genre>) : Filter.Group<Genre>(title, genres)
class TypeList(title: String, types: List<Type>) : EnhancedSelect<Type>(title, types.toTypedArray())
class LanguageList(title: String, languages: List<Language>) : EnhancedSelect<Language>(title, languages.toTypedArray())
class StatusList(title: String, statuses: List<Status>) : EnhancedSelect<Status>(title, statuses.toTypedArray())
open class EnhancedSelect<T>(name: String, values: Array<T>) : Filter.Select<T>(name, values) {
val selected: T
get() = values[state]
}
data class Status(val name: String, val value: String) {
override fun toString(): String = name
}
data class Type(val name: String, val value: String) {
override fun toString(): String = name
}
data class Language(val name: String, val value: String) {
override fun toString(): String = name
}

View File

@ -9,7 +9,7 @@ class ZeistMangaGenerator : ThemeSourceGenerator {
override val themeClass = "ZeistManga"
override val baseVersionCode: Int = 3
override val baseVersionCode: Int = 4
override val sources = listOf(
SingleLang("DatGarScanlation", "https://datgarscanlation.blogspot.com", "es"),

View File

@ -0,0 +1,102 @@
package eu.kanade.tachiyomi.multisrc.zeistmanga
class ZeistMangaIntl(lang: String) {
val availableLang: String = if (lang in AVAILABLE_LANGS) lang else ENGLISH
// Status Filter
val statusFilterTitle: String = when (availableLang) {
SPANISH -> "Estado"
else -> "Status"
}
val statusAll: String = when (availableLang) {
SPANISH -> "Todos"
else -> "All"
}
val statusOngoing: String = when (availableLang) {
SPANISH -> "En curso"
else -> "Ongoing"
}
val statusCompleted: String = when (availableLang) {
SPANISH -> "Completado"
else -> "Completed"
}
val statusDropped: String = when (availableLang) {
SPANISH -> "Abandonada"
else -> "Dropped"
}
val statusUpcoming: String = when (availableLang) {
SPANISH -> "Próximos"
else -> "Upcoming"
}
// Type Filter
val typeFilterTitle: String = when (availableLang) {
SPANISH -> "Tipo"
else -> "Type"
}
val typeAll: String = when (availableLang) {
SPANISH -> "Todos"
else -> "All"
}
val typeManga: String = when (availableLang) {
SPANISH -> "Manga"
else -> "Manga"
}
val typeManhua: String = when (availableLang) {
SPANISH -> "Manhua"
else -> "Manhua"
}
val typeManhwa: String = when (availableLang) {
SPANISH -> "Manhwa"
else -> "Manhwa"
}
val typeNovel: String = when (availableLang) {
SPANISH -> "Novela"
else -> "Novel"
}
// Language Filter
val languageFilterTitle: String = when (availableLang) {
SPANISH -> "Idioma"
else -> "Language"
}
val languageAll: String = when (availableLang) {
SPANISH -> "Todos"
else -> "All"
}
// Genre Filter
val genreFilterTitle: String = when (availableLang) {
SPANISH -> "Género"
else -> "Genre"
}
// Extra
val filterWarning: String = when (availableLang) {
SPANISH -> "Los filtros serán ignorados si la búsqueda no está vacía."
else -> "Filters will be ignored if the search is not empty."
}
companion object {
const val ENGLISH = "en"
const val SPANISH = "es"
val AVAILABLE_LANGS = arrayOf(ENGLISH, SPANISH)
}
}