ZeistManga: Add popular tab and more manga details + add sources (#19031)
* Update ZeistManga * Wrong order * Add more sources * Lint * Add MikoRoku * Lint again * Finally fix search * Finally fix search * Use correct parser for search
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 110 KiB |
|
@ -0,0 +1,41 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.pt.animexnovel
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class AnimeXNovel : ZeistManga("AnimeXNovel", "https://www.animexnovel.com", "pt-BR") {
|
||||||
|
|
||||||
|
override val mangaCategory: String = "Manga"
|
||||||
|
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val mangas = document.select("div.PopularPosts div.grid > figure").map { element ->
|
||||||
|
SManga.create().apply {
|
||||||
|
thumbnail_url = element.selectFirst("img")!!.attr("abs:src")
|
||||||
|
title = element.selectFirst("figcaption > a")!!.text()
|
||||||
|
setUrlWithoutDomain(element.selectFirst("figcaption > a")!!.attr("href"))
|
||||||
|
}
|
||||||
|
}.filter { it.title.contains("[Mangá]") }
|
||||||
|
|
||||||
|
return MangasPage(mangas, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val mangaDetailsSelectorDescription = "div.bc-fff.s1 > h3:contains(Sinopse) ~ div[style=text-align: justify;]"
|
||||||
|
|
||||||
|
private val chapterListSelector = "div:has(> .list-judul:contains(Lista de Capítulos)) div#latest ul > li, div.tab:has(> label:contains(Lista de Capítulos)) div.tab-content ul > li"
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val chapters = document.select(chapterListSelector)
|
||||||
|
return chapters.map {
|
||||||
|
SChapter.create().apply {
|
||||||
|
name = it.select("a").text()
|
||||||
|
setUrlWithoutDomain(it.select("a").attr("href"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 91 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.pt.guildatierdraw
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
|
||||||
|
class GuildaTierDraw : ZeistManga("Guilda Tier Draw", "https://www.guildatierdraw.com", "pt-BR") {
|
||||||
|
override val mangaDetailsSelectorDescription = "#Sinopse"
|
||||||
|
}
|
|
@ -2,12 +2,20 @@ package eu.kanade.tachiyomi.extension.ar.hijala
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.Genre
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.Genre
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
class Hijala : ZeistManga("Hijala", "https://hijala.blogspot.com", "ar") {
|
class Hijala : ZeistManga("Hijala", "https://hijala.blogspot.com", "ar") {
|
||||||
|
|
||||||
override val hasFilters = true
|
override val hasFilters = true
|
||||||
override val hasLanguageFilter = false
|
override val hasLanguageFilter = false
|
||||||
|
|
||||||
|
override val supportsLatest = false
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request = latestUpdatesRequest(page)
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage = latestUpdatesParse(response)
|
||||||
|
|
||||||
override fun getGenreList(): List<Genre> = listOf(
|
override fun getGenreList(): List<Genre> = listOf(
|
||||||
Genre("أكشن", "Action"),
|
Genre("أكشن", "Action"),
|
||||||
Genre("أثارة", "Thriller"),
|
Genre("أثارة", "Thriller"),
|
||||||
|
|
|
@ -7,12 +7,14 @@ import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistMangaDto
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistMangaDto
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistMangaIntl
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistMangaIntl
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
@ -30,6 +32,27 @@ class KomikRealm : ZeistManga(
|
||||||
|
|
||||||
override val chapterCategory = ""
|
override val chapterCategory = ""
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
val url = apiUrl("Project")
|
||||||
|
.addQueryParameter("orderby", "updated")
|
||||||
|
.addQueryParameter("max-results", "12")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return GET(url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
val jsonString = response.body.string()
|
||||||
|
val result = json.decodeFromString<ZeistMangaDto>(jsonString)
|
||||||
|
|
||||||
|
val mangas = result.feed?.entry.orEmpty()
|
||||||
|
.filter { it.category.orEmpty().any { category -> category.term == "Series" } }
|
||||||
|
.filter { !it.category.orEmpty().any { category -> category.term == "Anime" } }
|
||||||
|
.map { it.toSManga(baseUrl) }
|
||||||
|
|
||||||
|
return MangasPage(mangas, false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val profileManga = document.select(".bigcontent")
|
val profileManga = document.select(".bigcontent")
|
||||||
|
@ -54,12 +77,6 @@ class KomikRealm : ZeistManga(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStatus(element: String): Int = when (element.lowercase()) {
|
|
||||||
"ongoing" -> SManga.ONGOING
|
|
||||||
"completed" -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 84 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.ar.mangasoul
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
|
||||||
|
class MangaSoul : ZeistManga("Manga Soul", "https://www.manga-soul.com", "ar") {
|
||||||
|
override val mangaDetailsSelectorInfo = ".y6x11p, .y6x11p > b > span"
|
||||||
|
}
|
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 85 KiB |
|
@ -0,0 +1,26 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.id.mikoroku
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class MikoRoku : ZeistManga("MikoRoku", "https://www.mikoroku.web.id", "id") {
|
||||||
|
|
||||||
|
override val popularMangaSelector = "div.PopularPosts article"
|
||||||
|
override val popularMangaSelectorTitle = ".post-title a"
|
||||||
|
override val popularMangaSelectorUrl = ".post-title a"
|
||||||
|
|
||||||
|
override val pageListSelector = "article#reader div.separator a"
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
with(document.selectFirst("div.section#main div.widget header")!!) {
|
||||||
|
thumbnail_url = selectFirst("img")!!.attr("abs:src")
|
||||||
|
genre = select("aside dl:has(dt:contains(Genre)) dd a")
|
||||||
|
.joinToString { it.text() }
|
||||||
|
status = parseStatus(selectFirst("span[data-status]")!!.text())
|
||||||
|
}
|
||||||
|
description = document.select("div.section#main div.widget div.grid #synopsis").text()
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 216 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.tr.mikrokosmosfansub
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
|
class MikrokosmosFansub : ZeistManga("Mikrokosmos Fansub", "https://mikrokosmosfb.blogspot.com", "tr") {
|
||||||
|
|
||||||
|
override val pageListSelector = "div.check-box > script"
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val script = document.select(pageListSelector)
|
||||||
|
val content = script.html().substringAfter("const content = `").substringBefore("`;")
|
||||||
|
val images = Jsoup.parse(content).select("a")
|
||||||
|
return images.select("img[src]").mapIndexed { i, img ->
|
||||||
|
Page(i, "", img.attr("abs:src"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 241 KiB |
|
@ -1,9 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.muslosnosekai
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
|
||||||
|
|
||||||
class MuslosNoSekai : ZeistManga("Muslos No Sekai", "https://muslosnosekai.blogspot.com", "es") {
|
|
||||||
|
|
||||||
override val hasFilters = true
|
|
||||||
override val hasLanguageFilter = false
|
|
||||||
}
|
|
|
@ -1,8 +1,10 @@
|
||||||
package eu.kanade.tachiyomi.extension.id.shiyurasub
|
package eu.kanade.tachiyomi.extension.id.shiyurasub
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
||||||
class ShiyuraSub : ZeistManga("ShiyuraSub", "https://shiyurasub.blogspot.com", "id") {
|
class ShiyuraSub : ZeistManga("ShiyuraSub", "https://shiyurasub.blogspot.com", "id") {
|
||||||
|
@ -10,6 +12,11 @@ class ShiyuraSub : ZeistManga("ShiyuraSub", "https://shiyurasub.blogspot.com", "
|
||||||
override val hasFilters = true
|
override val hasFilters = true
|
||||||
override val hasLanguageFilter = false
|
override val hasLanguageFilter = false
|
||||||
|
|
||||||
|
override val supportsLatest = false
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request = latestUpdatesRequest(page)
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage = latestUpdatesParse(response)
|
||||||
|
|
||||||
override val pageListSelector = "main.content article.container"
|
override val pageListSelector = "main.content article.container"
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
|
|
|
@ -1,69 +1,13 @@
|
||||||
package eu.kanade.tachiyomi.extension.id.sobatmanku
|
package eu.kanade.tachiyomi.extension.id.sobatmanku
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
||||||
class SobatManKu : ZeistManga("SobatManKu", "https://www.sobatmanku19.site", "id") {
|
class SobatManKu : ZeistManga("SobatManKu", "https://www.sobatmanku19.site", "id") {
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override val hasFilters = true
|
override val hasFilters = true
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/search/label/Update", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
|
||||||
val doc = response.asJsoup()
|
|
||||||
val selector = doc.select(".grid.gtc-f141a > div")
|
|
||||||
val mangas = selector.map { element ->
|
|
||||||
|
|
||||||
SManga.create().apply {
|
|
||||||
element.select("a:nth-child(2)").let {
|
|
||||||
title = it.text()
|
|
||||||
setUrlWithoutDomain(it.attr("href"))
|
|
||||||
}
|
|
||||||
thumbnail_url = element.select("img").first()!!.attr("abs:src")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MangasPage(mangas, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
|
||||||
return SManga.create().apply {
|
|
||||||
thumbnail_url = profileManga.selectFirst("img")!!.attr("abs:src")
|
|
||||||
description = profileManga.select("#synopsis").text()
|
|
||||||
genre = profileManga.select("div.mt-15 > a[rel=tag]").joinToString { it.text() }
|
|
||||||
|
|
||||||
val infoElement = profileManga.select(".y6x11p")
|
|
||||||
infoElement.forEach {
|
|
||||||
val descText = it.select("span.dt").text()
|
|
||||||
when (it.ownText().trim()) {
|
|
||||||
"Status" -> {
|
|
||||||
status = parseStatus(descText)
|
|
||||||
}
|
|
||||||
|
|
||||||
"Author" -> {
|
|
||||||
author = descText
|
|
||||||
}
|
|
||||||
|
|
||||||
"Artist" -> {
|
|
||||||
artist = descText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
return super.chapterListParse(response).onEach {
|
return super.chapterListParse(response).onEach {
|
||||||
// fix some chapter name
|
// fix some chapter name
|
||||||
|
@ -72,10 +16,4 @@ class SobatManKu : ZeistManga("SobatManKu", "https://www.sobatmanku19.site", "id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStatus(element: String): Int = when (element.lowercase()) {
|
|
||||||
"ongoing" -> SManga.ONGOING
|
|
||||||
"completed" -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.id.tooncubus
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
||||||
|
@ -14,7 +13,7 @@ class Tooncubus : ZeistManga("Tooncubus", "https://www.tooncubus.top", "id") {
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
return response.asJsoup().selectFirst("ul.series-chapterlist")!!.select("div.flexch-infoz").map { element ->
|
return response.asJsoup().selectFirst("ul.series-chapterlist")!!.select("div.flexch-infoz").map { element ->
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
name = element.select("span")!!.text()
|
name = element.select("span").text()
|
||||||
url = element.select("a").attr("href") // The website uses another domain for reading
|
url = element.select("a").attr("href") // The website uses another domain for reading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,14 +22,4 @@ class Tooncubus : ZeistManga("Tooncubus", "https://www.tooncubus.top", "id") {
|
||||||
override fun pageListRequest(chapter: SChapter) = GET(chapter.url, headers)
|
override fun pageListRequest(chapter: SChapter) = GET(chapter.url, headers)
|
||||||
|
|
||||||
override fun getChapterUrl(chapter: SChapter) = chapter.url
|
override fun getChapterUrl(chapter: SChapter) = chapter.url
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
|
||||||
return SManga.create().apply {
|
|
||||||
thumbnail_url = profileManga.selectFirst("img")!!.attr("src")
|
|
||||||
genre = profileManga.select("div.mt-15 > a[rel=tag]")
|
|
||||||
.joinToString { it.text() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 83 KiB |
|
@ -0,0 +1,15 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.pt.tyrantscans
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class TyrantScans : ZeistManga("Tyrant Scans", "https://www.tyrantscans.com", "pt-BR") {
|
||||||
|
|
||||||
|
override val supportsLatest = false
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request = latestUpdatesRequest(page)
|
||||||
|
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage = latestUpdatesParse(response)
|
||||||
|
}
|
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 82 KiB |
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
@ -24,13 +25,34 @@ abstract class ZeistManga(
|
||||||
override val lang: String,
|
override val lang: String,
|
||||||
) : HttpSource() {
|
) : HttpSource() {
|
||||||
|
|
||||||
override val supportsLatest = false
|
override val supportsLatest = true
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val intl by lazy { ZeistMangaIntl(lang) }
|
private val intl by lazy { ZeistMangaIntl(lang) }
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||||
|
.add("Referer", "$baseUrl/")
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request = GET(baseUrl, headers)
|
||||||
|
|
||||||
|
protected open val popularMangaSelector = "div.PopularPosts div.grid > figure"
|
||||||
|
protected open val popularMangaSelectorTitle = "figcaption > a"
|
||||||
|
protected open val popularMangaSelectorUrl = "figcaption > a"
|
||||||
|
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val mangas = document.select(popularMangaSelector).map { element ->
|
||||||
|
SManga.create().apply {
|
||||||
|
thumbnail_url = element.selectFirst("img")!!.attr("abs:src")
|
||||||
|
title = element.selectFirst(popularMangaSelectorTitle)!!.text()
|
||||||
|
setUrlWithoutDomain(element.selectFirst(popularMangaSelectorUrl)!!.attr("href"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MangasPage(mangas, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
val startIndex = maxMangaResults * (page - 1) + 1
|
val startIndex = maxMangaResults * (page - 1) + 1
|
||||||
val url = apiUrl()
|
val url = apiUrl()
|
||||||
.addQueryParameter("orderby", "published")
|
.addQueryParameter("orderby", "published")
|
||||||
|
@ -41,7 +63,7 @@ abstract class ZeistManga(
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun latestUpdatesParse(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)
|
||||||
|
|
||||||
|
@ -59,9 +81,6 @@ abstract class ZeistManga(
|
||||||
return MangasPage(mangalist, false)
|
return MangasPage(mangalist, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used.")
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used.")
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val startIndex = maxMangaResults * (page - 1) + 1
|
val startIndex = maxMangaResults * (page - 1) + 1
|
||||||
val url = apiUrl()
|
val url = apiUrl()
|
||||||
|
@ -70,7 +89,8 @@ abstract class ZeistManga(
|
||||||
|
|
||||||
if (query.isNotBlank()) {
|
if (query.isNotBlank()) {
|
||||||
url.addQueryParameter("q", query)
|
url.addQueryParameter("q", query)
|
||||||
return GET(url.build(), headers)
|
val searchUrl = url.build().toString().replaceLast("q=", "q=label:$mangaCategory+")
|
||||||
|
return GET(searchUrl, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
filters.forEach { filter ->
|
filters.forEach { filter ->
|
||||||
|
@ -103,20 +123,65 @@ abstract class ZeistManga(
|
||||||
return GET(url.build(), headers)
|
return GET(url.build(), headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
override fun searchMangaParse(response: Response) = latestUpdatesParse(response)
|
||||||
|
|
||||||
|
protected open val statusSelectorList = listOf(
|
||||||
|
"Status",
|
||||||
|
"Estado",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open val authorSelectorList = listOf(
|
||||||
|
"Author",
|
||||||
|
"Autor",
|
||||||
|
"الكاتب",
|
||||||
|
"Yazar",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open val artisSelectorList = listOf(
|
||||||
|
"Artist",
|
||||||
|
"Artista",
|
||||||
|
"الرسام",
|
||||||
|
"Çizer",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open val mangaDetailsSelector = ".grid.gtc-235fr"
|
||||||
|
protected open val mangaDetailsSelectorDescription = "#synopsis"
|
||||||
|
protected open val mangaDetailsSelectorGenres = "div.mt-15 > a[rel=tag]"
|
||||||
|
protected open val mangaDetailsSelectorInfo = ".y6x11p"
|
||||||
|
protected open val mangaDetailsSelectorInfoTitle = "strong"
|
||||||
|
protected open val mangaDetailsSelectorInfoDescription = "span.dt"
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
val profileManga = document.selectFirst(mangaDetailsSelector)!!
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
thumbnail_url = profileManga.selectFirst("img")!!.attr("abs:src")
|
thumbnail_url = profileManga.selectFirst("img")!!.attr("abs:src")
|
||||||
description = profileManga.select("#synopsis").text()
|
description = profileManga.select(mangaDetailsSelectorDescription).text()
|
||||||
genre = profileManga.select("div.mt-15 > a[rel=tag]")
|
genre = profileManga.select(mangaDetailsSelectorGenres)
|
||||||
.joinToString { it.text() }
|
.joinToString { it.text() }
|
||||||
|
|
||||||
|
val infoElement = profileManga.select(mangaDetailsSelectorInfo)
|
||||||
|
infoElement.forEach { element ->
|
||||||
|
val infoText = element.ownText().trim().ifEmpty { element.selectFirst(mangaDetailsSelectorInfoTitle)?.text()?.trim() ?: "" }
|
||||||
|
val descText = element.select(mangaDetailsSelectorInfoDescription).text().trim()
|
||||||
|
when {
|
||||||
|
statusSelectorList.any { infoText.contains(it) } -> {
|
||||||
|
status = parseStatus(descText)
|
||||||
|
}
|
||||||
|
|
||||||
|
authorSelectorList.any { infoText.contains(it) } -> {
|
||||||
|
author = descText
|
||||||
|
}
|
||||||
|
|
||||||
|
artisSelectorList.any { infoText.contains(it) } -> {
|
||||||
|
artist = descText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open val chapterCategory = "Chapter"
|
protected open val chapterCategory: String = "Chapter"
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
@ -197,7 +262,7 @@ abstract class ZeistManga(
|
||||||
return url.toString()
|
return url.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
open val pageListSelector = "div.check-box div.separator"
|
protected open val pageListSelector = "div.check-box div.separator"
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
@ -209,7 +274,9 @@ abstract class ZeistManga(
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Not used.")
|
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Not used.")
|
||||||
|
|
||||||
open fun apiUrl(feed: String = "Series"): HttpUrl.Builder {
|
protected open val mangaCategory: String = "Series"
|
||||||
|
|
||||||
|
open fun apiUrl(feed: String = mangaCategory): 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")
|
||||||
|
@ -229,6 +296,9 @@ abstract class ZeistManga(
|
||||||
return FilterList(emptyList())
|
return FilterList(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterList.add(Filter.Header(intl.filterWarning))
|
||||||
|
filterList.add(Filter.Separator())
|
||||||
|
|
||||||
if (hasStatusFilter) filterList.add(StatusList(intl.statusFilterTitle, getStatusList()))
|
if (hasStatusFilter) filterList.add(StatusList(intl.statusFilterTitle, getStatusList()))
|
||||||
if (hasTypeFilter) filterList.add(TypeList(intl.typeFilterTitle, getTypeList()))
|
if (hasTypeFilter) filterList.add(TypeList(intl.typeFilterTitle, getTypeList()))
|
||||||
if (hasLanguageFilter) filterList.add(LanguageList(intl.languageFilterTitle, getLanguageList()))
|
if (hasLanguageFilter) filterList.add(LanguageList(intl.languageFilterTitle, getLanguageList()))
|
||||||
|
@ -306,6 +376,48 @@ abstract class ZeistManga(
|
||||||
Language("English", "English"),
|
Language("English", "English"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
protected open val statusOnGoingList = listOf(
|
||||||
|
"ongoing",
|
||||||
|
"en curso",
|
||||||
|
"ativo",
|
||||||
|
"lançando",
|
||||||
|
"مستمر",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open val statusCompletedList = listOf(
|
||||||
|
"completed",
|
||||||
|
"completo",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open val statusHiatusList = listOf(
|
||||||
|
"hiatus",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open val statusCancelledList = listOf(
|
||||||
|
"cancelled",
|
||||||
|
"dropped",
|
||||||
|
"dropado",
|
||||||
|
"abandonado",
|
||||||
|
"cancelado",
|
||||||
|
)
|
||||||
|
|
||||||
|
protected open fun parseStatus(element: String): Int = when (element.lowercase().trim()) {
|
||||||
|
in statusOnGoingList -> SManga.ONGOING
|
||||||
|
in statusCompletedList -> SManga.COMPLETED
|
||||||
|
in statusHiatusList -> SManga.ON_HIATUS
|
||||||
|
in statusCancelledList -> SManga.CANCELLED
|
||||||
|
else -> SManga.UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.replaceLast(oldValue: String, newValue: String): String {
|
||||||
|
val lastIndexOf = lastIndexOf(oldValue)
|
||||||
|
return if (lastIndexOf == -1) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
substring(0, lastIndexOf) + newValue + substring(lastIndexOf + oldValue.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val maxMangaResults = 20
|
private const val maxMangaResults = 20
|
||||||
private const val maxChapterResults = 999999
|
private const val maxChapterResults = 999999
|
||||||
|
|
|
@ -9,18 +9,26 @@ class ZeistMangaGenerator : ThemeSourceGenerator {
|
||||||
|
|
||||||
override val themeClass = "ZeistManga"
|
override val themeClass = "ZeistManga"
|
||||||
|
|
||||||
override val baseVersionCode: Int = 7
|
override val baseVersionCode: Int = 8
|
||||||
|
|
||||||
override val sources = listOf(
|
override val sources = listOf(
|
||||||
|
SingleLang("AnimeXNovel", "https://www.animexnovel.com", "pt-BR"),
|
||||||
SingleLang("Asupan Komik", "https://www.asupankomik.my.id", "id", overrideVersionCode = 1),
|
SingleLang("Asupan Komik", "https://www.asupankomik.my.id", "id", overrideVersionCode = 1),
|
||||||
|
SingleLang("Eleven Scanlator", "https://elevenscanlator.blogspot.com", "pt-BR"),
|
||||||
|
SingleLang("Guilda Tier Draw", "https://www.guildatierdraw.com", "pt-BR", isNsfw = true),
|
||||||
SingleLang("Hijala", "https://hijala.blogspot.com", "ar"),
|
SingleLang("Hijala", "https://hijala.blogspot.com", "ar"),
|
||||||
SingleLang("KLManhua", "https://klmanhua.blogspot.com", "id", isNsfw = true),
|
SingleLang("KLManhua", "https://klmanhua.blogspot.com", "id", isNsfw = true),
|
||||||
SingleLang("Manga Ai Land", "https://manga-ai-land.blogspot.com", "ar"),
|
|
||||||
SingleLang("Muslos No Sekai", "https://muslosnosekai.blogspot.com", "es"),
|
|
||||||
SingleLang("ShiyuraSub", "https://shiyurasub.blogspot.com", "id"),
|
|
||||||
SingleLang("Tooncubus", "https://www.tooncubus.top", "id", isNsfw = true),
|
|
||||||
SingleLang("SobatManKu", "https://www.sobatmanku19.site", "id"),
|
|
||||||
SingleLang("KomikRealm", "https://www.komikrealm.my.id", "id"),
|
SingleLang("KomikRealm", "https://www.komikrealm.my.id", "id"),
|
||||||
|
SingleLang("Loner Translations", "https://loner-tl.blogspot.com", "ar"),
|
||||||
|
SingleLang("Manga Ai Land", "https://manga-ai-land.blogspot.com", "ar"),
|
||||||
|
SingleLang("Manga Soul", "https://www.manga-soul.com", "ar", isNsfw = true),
|
||||||
|
SingleLang("MikoRoku", "https://www.mikoroku.web.id", "id", isNsfw = true),
|
||||||
|
SingleLang("Mikrokosmos Fansub", "https://mikrokosmosfb.blogspot.com", "tr", isNsfw = true),
|
||||||
|
SingleLang("ShiyuraSub", "https://shiyurasub.blogspot.com", "id"),
|
||||||
|
SingleLang("SobatManKu", "https://www.sobatmanku19.site", "id"),
|
||||||
|
SingleLang("Tooncubus", "https://www.tooncubus.top", "id", isNsfw = true),
|
||||||
|
SingleLang("Tyrant Scans", "https://www.tyrantscans.com", "pt-BR"),
|
||||||
|
SingleLang("Yokai", "https://yokai-team.blogspot.com", "ar"),
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|