Update ZeistManga (#15390)
* Update ZeistManga * Linting * More Linting * Update Filters * Apply requested changes
This commit is contained in:
parent
ee4b27f60c
commit
a736f20dd0
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.multisrc.zeistmanga
|
package eu.kanade.tachiyomi.multisrc.zeistmanga
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
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.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
@ -25,7 +26,9 @@ abstract class ZeistManga(
|
|||||||
) : ParsedHttpSource() {
|
) : ParsedHttpSource() {
|
||||||
|
|
||||||
override val supportsLatest = false
|
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 chapterFeedRegex = """clwd\.run\('([^']+)'""".toRegex()
|
||||||
open val scriptSelector = "#clwd > script"
|
open val scriptSelector = "#clwd > script"
|
||||||
open val imgSelector = "img[src]"
|
open val imgSelector = "img[src]"
|
||||||
@ -38,12 +41,10 @@ abstract class ZeistManga(
|
|||||||
?.groupValues?.get(1)
|
?.groupValues?.get(1)
|
||||||
?: throw Exception("Failed to find chapter feed")
|
?: throw Exception("Failed to find chapter feed")
|
||||||
|
|
||||||
val url = apiUrl(feed)
|
return apiUrl("Chapter")
|
||||||
.addQueryParameter("start-index", "2") // Only get chapters
|
.addPathSegments(feed)
|
||||||
.addQueryParameter("max-results", "999999") // Get all chapters
|
.addQueryParameter("max-results", "999999") // Get all chapters
|
||||||
.build()
|
.build().toString()
|
||||||
|
|
||||||
return url.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
@ -51,15 +52,12 @@ abstract class ZeistManga(
|
|||||||
|
|
||||||
val url = getChaptersUrl(document)
|
val url = getChaptersUrl(document)
|
||||||
|
|
||||||
// Call JSON API
|
|
||||||
val req = GET(url, headers)
|
val req = GET(url, headers)
|
||||||
val res = client.newCall(req).execute()
|
val res = client.newCall(req).execute()
|
||||||
|
|
||||||
// Parse JSON API response
|
|
||||||
val jsonString = res.body.string()
|
val jsonString = res.body.string()
|
||||||
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
|
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
|
||||||
|
|
||||||
// Transform JSON response into List<SChapter>
|
|
||||||
return result.feed?.entry?.map { it.toSChapter(baseUrl) }
|
return result.feed?.entry?.map { it.toSChapter(baseUrl) }
|
||||||
?: throw Exception("Failed to parse from chapter API")
|
?: throw Exception("Failed to parse from chapter API")
|
||||||
}
|
}
|
||||||
@ -108,6 +106,18 @@ abstract class ZeistManga(
|
|||||||
throw UnsupportedOperationException("Not used.")
|
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 {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
@ -115,6 +125,8 @@ abstract class ZeistManga(
|
|||||||
thumbnail_url = profileManga.selectFirst("img")!!.attr("src")
|
thumbnail_url = profileManga.selectFirst("img")!!.attr("src")
|
||||||
description = profileManga.select("#synopsis").text()
|
description = profileManga.select("#synopsis").text()
|
||||||
status = SManga.UNKNOWN
|
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 {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val jsonString = response.body.string()
|
val jsonString = response.body.string()
|
||||||
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
|
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
|
||||||
// Transform JSON response into List<SManga>
|
|
||||||
val mangas = result.feed!!.entry?.map { it.toSManga(baseUrl) }
|
val mangas = result.feed?.entry.orEmpty()
|
||||||
val mangalist = mangas!!.toMutableList()
|
.filter { !it.category.orEmpty().any { category -> category.term == "Anime" } } // Skip animes
|
||||||
|
.map { it.toSManga(baseUrl) }
|
||||||
|
|
||||||
|
val mangalist = mangas.toMutableList()
|
||||||
if (mangas.size == maxResults + 1) {
|
if (mangas.size == maxResults + 1) {
|
||||||
mangalist.removeLast()
|
mangalist.removeLast()
|
||||||
return MangasPage(mangalist, true)
|
return MangasPage(mangalist, true)
|
||||||
@ -146,34 +161,140 @@ abstract class ZeistManga(
|
|||||||
.addQueryParameter("start-index", startIndex.toString())
|
.addQueryParameter("start-index", startIndex.toString())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return GET(url.toString(), headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaSelector(): String = ".grid.gtc-f141a > div"
|
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
||||||
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 searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val url = "$baseUrl/search".toHttpUrl().newBuilder()
|
val startIndex = maxResults * (page - 1) + 1
|
||||||
.addQueryParameter("q", query)
|
val url = apiUrl()
|
||||||
.build()
|
.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 {
|
open fun apiUrl(feed: String = "Series"): HttpUrl.Builder {
|
||||||
return "$baseUrl/feeds/posts/default/-/".toHttpUrl().newBuilder()
|
return "$baseUrl/feeds/posts/default/-/".toHttpUrl().newBuilder()
|
||||||
.addPathSegment(feed)
|
.addPathSegment(feed)
|
||||||
.addQueryParameter("alt", "json")
|
.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 {
|
companion object {
|
||||||
private const val maxResults = 20
|
private const val maxResults = 20
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ data class ZeistMangaFeedDto(
|
|||||||
data class ZeistMangaEntryDto(
|
data class ZeistMangaEntryDto(
|
||||||
val title: ZeistMangaEntryTitleDto? = null,
|
val title: ZeistMangaEntryTitleDto? = null,
|
||||||
val published: ZeistMangaEntryPublishedDto? = null,
|
val published: ZeistMangaEntryPublishedDto? = null,
|
||||||
|
val category: List<ZeistMangaEntryCategory>? = emptyList(),
|
||||||
@SerialName("link") val url: List<ZeistMangaEntryLink>? = emptyList(),
|
@SerialName("link") val url: List<ZeistMangaEntryLink>? = emptyList(),
|
||||||
val content: ZeistMangaEntryContentDto? = null,
|
val content: ZeistMangaEntryContentDto? = null,
|
||||||
) {
|
) {
|
||||||
@ -77,3 +78,8 @@ data class ZeistMangaEntryLink(
|
|||||||
val rel: String,
|
val rel: String,
|
||||||
val href: String,
|
val href: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ZeistMangaEntryCategory(
|
||||||
|
val term: String,
|
||||||
|
)
|
||||||
|
@ -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
|
||||||
|
}
|
@ -9,7 +9,7 @@ class ZeistMangaGenerator : ThemeSourceGenerator {
|
|||||||
|
|
||||||
override val themeClass = "ZeistManga"
|
override val themeClass = "ZeistManga"
|
||||||
|
|
||||||
override val baseVersionCode: Int = 3
|
override val baseVersionCode: Int = 4
|
||||||
|
|
||||||
override val sources = listOf(
|
override val sources = listOf(
|
||||||
SingleLang("DatGarScanlation", "https://datgarscanlation.blogspot.com", "es"),
|
SingleLang("DatGarScanlation", "https://datgarscanlation.blogspot.com", "es"),
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user