Add MultiScr "ZeistManga" and DatGarScan (#14491)

* Add MultiScr "ZeistManga" and DatGarScan

* Fix Lint Errors

* More Fix Lint Errors

* Change HttpSource to ParsedHttpSource

* Make DTO

* Fix Lint Errors

* Improve search

* Fix Lint Errors

* Back to old search method

* Back to old search method

* Refactor code and fixes

* Refactor code and fixes

* Refactor code and fixes

* Refactor code and fixes

* Apply Requested Changes

* Fix Lint
This commit is contained in:
Seew 2022-12-11 08:08:50 -05:00 committed by GitHub
parent 420b9930a0
commit 3d08779674
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 275 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@ -0,0 +1,172 @@
package eu.kanade.tachiyomi.multisrc.zeistmanga
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy
abstract class ZeistManga(
override val name: String,
override val baseUrl: String,
override val lang: String
) : ParsedHttpSource() {
override val supportsLatest = false
private val json: Json by injectLazy()
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
// Find chapter feed name (ZeistManga v5)
val script = document.selectFirst("#clwd > script")
val feed = chapterFeedRegex
.find(script.html())
?.groupValues?.get(1)
?: throw Exception("Failed to find chapter feed")
val url = apiUrl(feed)
.addQueryParameter("start-index", "2") // Only get chapters
.addQueryParameter("max-results", "999999") // Get all chapters
.build()
// Call JSON API
val req = GET(url.toString(), 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")
}
override fun imageUrlParse(document: Document): String {
throw UnsupportedOperationException("Not used.")
}
override fun latestUpdatesParse(response: Response): MangasPage {
throw UnsupportedOperationException("Not used.")
}
override fun latestUpdatesRequest(page: Int): Request {
throw UnsupportedOperationException("Not used.")
}
override fun chapterFromElement(element: Element): SChapter {
throw UnsupportedOperationException("Not used.")
}
override fun chapterListSelector(): String {
throw UnsupportedOperationException("Not used.")
}
override fun latestUpdatesFromElement(element: Element): SManga {
throw UnsupportedOperationException("Not used.")
}
override fun latestUpdatesNextPageSelector(): String? {
throw UnsupportedOperationException("Not used.")
}
override fun latestUpdatesSelector(): String {
throw UnsupportedOperationException("Not used.")
}
override fun popularMangaFromElement(element: Element): SManga {
throw UnsupportedOperationException("Not used.")
}
override fun popularMangaNextPageSelector(): String? {
throw UnsupportedOperationException("Not used.")
}
override fun popularMangaSelector(): String {
throw UnsupportedOperationException("Not used.")
}
override fun mangaDetailsParse(document: Document): SManga {
val profileManga = document.selectFirst(".grid.gtc-235fr")
return SManga.create().apply {
title = profileManga.selectFirst("h1.mt-0.mb-6.fs-20").text()
thumbnail_url = profileManga.selectFirst("img").attr("src")
description = profileManga.selectFirst("#synopsis").text()
status = SManga.UNKNOWN
}
}
override fun pageListParse(document: Document): List<Page> {
val images = document.selectFirst(".check-box")
return images.select("img").mapIndexed { i, img ->
Page(i, "", img.attr("src"))
}
}
override fun popularMangaParse(response: Response): MangasPage {
val jsonString = response.body?.string().orEmpty()
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()
if (mangas.size == maxResults + 1) {
mangalist.removeLast()
return MangasPage(mangalist, true)
}
return MangasPage(mangalist, false)
}
override fun popularMangaRequest(page: Int): Request {
val startIndex = maxResults * (page - 1) + 1
val url = apiUrl()
.addQueryParameter("orderby", "published")
.addQueryParameter("max-results", (maxResults + 1).toString())
.addQueryParameter("start-index", startIndex.toString())
.build()
return GET(url.toString(), 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 searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = "$baseUrl/search".toHttpUrl().newBuilder()
.addQueryParameter("q", query)
.build()
return GET(url.toString(), headers)
}
override fun searchMangaNextPageSelector(): String? = null
private fun apiUrl(feed: String = "Series"): HttpUrl.Builder {
return "$baseUrl/feeds/posts/default/-/".toHttpUrl().newBuilder()
.addPathSegment(feed)
.addQueryParameter("alt", "json")
}
companion object {
private const val maxResults = 20
private val chapterFeedRegex = """clwd\.run\('([^']+)'""".toRegex()
}
}

View File

@ -0,0 +1,79 @@
package eu.kanade.tachiyomi.multisrc.zeistmanga
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.jsoup.Jsoup
import java.text.SimpleDateFormat
import java.util.Locale
private val DATE_FORMATTER by lazy {
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
}
private fun parseDate(dateStr: String): Long {
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
.getOrNull() ?: 0L
}
@Serializable
data class ZeistMangaDto(
val feed: ZeistMangaFeedDto? = null,
)
@Serializable
data class ZeistMangaFeedDto(
val entry: List<ZeistMangaEntryDto>? = emptyList()
)
@Serializable
data class ZeistMangaEntryDto(
val title: ZeistMangaEntryTitleDto? = null,
val published: ZeistMangaEntryPublishedDto? = null,
@SerialName("link") val url: List<ZeistMangaEntryLink>? = emptyList(),
val content: ZeistMangaEntryContentDto? = null
) {
fun toSManga(baseurl: String): SManga = SManga.create().apply {
title = this@ZeistMangaEntryDto.title!!.t
url = getChapterLink(this@ZeistMangaEntryDto.url!!).substringAfter(baseurl)
thumbnail_url = getThumbnail(this@ZeistMangaEntryDto.content!!)
}
fun toSChapter(baseurl: String): SChapter = SChapter.create().apply {
name = this@ZeistMangaEntryDto.title!!.t
url = getChapterLink(this@ZeistMangaEntryDto.url!!).substringAfter(baseurl)
val chapterDate = this@ZeistMangaEntryDto.published!!.t.trim()
date_upload = parseDate(chapterDate)
}
private fun getChapterLink(list: List<ZeistMangaEntryLink>): String {
return list.first { it.rel == "alternate" }.href
}
private fun getThumbnail(html: ZeistMangaEntryContentDto): String {
val document = Jsoup.parse(html.t)
return document.selectFirst("img").attr("src")
}
}
@Serializable
data class ZeistMangaEntryTitleDto(
@SerialName("\$t") val t: String
)
@Serializable
data class ZeistMangaEntryPublishedDto(
@SerialName("\$t") val t: String
)
@Serializable
data class ZeistMangaEntryContentDto(
@SerialName("\$t") val t: String
)
@Serializable
data class ZeistMangaEntryLink(
val rel: String,
val href: String
)

View File

@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.multisrc.zeistmanga
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class ZeistMangaGenerator : ThemeSourceGenerator {
override val themePkg = "zeistmanga"
override val themeClass = "ZeistManga"
override val baseVersionCode: Int = 1
override val sources = listOf(
SingleLang("DatGarScanlation", "https://datgarscanlation.blogspot.com", "es"),
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
ZeistMangaGenerator().createAll()
}
}
}