Remove MM and add SM, MU on MangaSar (#14615)

* Remove MM and add SM on MangaSar.

* Add MU as source as well.
This commit is contained in:
Alessandro Jean 2022-12-20 12:19:46 -03:00 committed by GitHub
parent 00099ca121
commit df8f6857f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 131 deletions

View File

@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.extension.pt.mangasup
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSar
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element
class MangasUp : MangaSar(
"MangásUp",
"https://mangasup.net",
"pt-BR"
) {
override fun chapterListPaginatedRequest(mangaUrl: String, page: Int): Request {
return GET(baseUrl + mangaUrl, headers)
}
override fun chapterListParse(response: Response): List<SChapter> {
return response.asJsoup()
.select("ul.full-chapters-list > li > a")
.map(::chapterFromElement)
}
private fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = element.selectFirst("span.cap-text")!!.text()
date_upload = element.selectFirst("span.chapter-date")?.text()?.toDate() ?: 0L
setUrlWithoutDomain(element.attr("href"))
}
}

View File

@ -1,123 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.meusmangas
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSar
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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element
class MeusMangas : MangaSar(
"Meus Mangás",
"https://meusmangas.net",
"pt-BR"
) {
override fun popularMangaSelector() = "ul.sidebar-popular li.popular-treending"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.selectFirst("h4.title").text()
thumbnail_url = element.selectFirst("div.tumbl img").attr("src")
setUrlWithoutDomain(element.selectFirst("a").attr("abs:href"))
}
override fun latestUpdatesRequest(page: Int): Request {
val newHeaders = headersBuilder()
.add("X-Requested-With", "XMLHttpRequest")
.build()
val pagePath = if (page > 1) "page/$page" else ""
return GET("$baseUrl/$pagePath", newHeaders)
}
override fun latestUpdatesParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangaList = document.select("li.item_news-manga")
.map(::latestMangaFromElement)
val hasNextPage = document.select("div.loadmore.morepage").firstOrNull() != null
return MangasPage(mangaList, hasNextPage)
}
private fun latestMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("h3.entry-title a").text()
thumbnail_url = element.select("img.manga").attr("src")
setUrlWithoutDomain(element.select("a").first().attr("abs:href"))
}
override fun mangaDetailsParse(response: Response): SManga {
val document = response.asJsoup()
val infoElement = document.selectFirst("div.box-single:has(div.mangapage)")
return SManga.create().apply {
title = infoElement.selectFirst("h1.kw-title").text()
author = infoElement.selectFirst("div.mdq.author").text().trim()
description = infoElement.selectFirst("div.sinopse-page").text()
genre = infoElement.select("div.generos a.widget-btn").joinToString { it.text() }
status = infoElement.selectFirst("span.mdq").text().toStatus()
thumbnail_url = infoElement.selectFirst("div.thumb img").attr("abs:src")
}
}
override fun chapterListPaginatedRequest(mangaUrl: String, page: Int): Request {
val newHeaders = headersBuilder()
.add("X-Requested-With", "XMLHttpRequest")
.build()
return GET("$baseUrl$mangaUrl/page/$page", newHeaders)
}
override fun chapterListParse(response: Response): List<SChapter> {
var document = response.asJsoup()
val chapterList = document.select(chapterListSelector())
.map(::chapterFromElement)
.toMutableList()
val mangaUrl = response.request.url.toString()
.substringAfter(baseUrl)
.substringBefore("/page")
var hasNextPage = document.select(chapterListNextPageSelector())
.firstOrNull()
while (hasNextPage != null) {
val page = hasNextPage.attr("href")
.substringAfter("page/")
.toInt()
val nextRequest = chapterListPaginatedRequest(mangaUrl, page)
val nextResponse = client.newCall(nextRequest).execute()
document = nextResponse.asJsoup()
chapterList += document.select(chapterListSelector())
.map(::chapterFromElement)
hasNextPage = document.select(chapterListNextPageSelector())
.firstOrNull()
}
return chapterList
}
private fun chapterListSelector() = "ul.list-of-chapters li > a"
private fun chapterListNextPageSelector() = "ul.content-pagination li.active + li:not(.next) a"
private fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = element.select("span.cap-text").text()
date_upload = element.select("span.chapter-date").text().toDate()
setUrlWithoutDomain(element.attr("abs:href"))
}
private fun String.toStatus(): Int = when (this) {
"Em andamento" -> SManga.ONGOING
"Completo" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
}

View File

@ -0,0 +1,136 @@
package eu.kanade.tachiyomi.extension.pt.seemangas
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSar
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSarLatestDto
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSarReaderDto
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
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.util.asJsoup
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.FormBody
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element
class Seemangas : MangaSar(
"Seemangas",
"https://seemangas.com",
"pt-BR"
) {
override fun popularMangaSelector() = "ul.sidebar-popular li.popular-treending"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.selectFirst("h4.title").text()
thumbnail_url = element.selectFirst("div.tumbl img").attr("data-lazy-src")
setUrlWithoutDomain(element.selectFirst("a").attr("abs:href"))
}
override fun latestUpdatesRequest(page: Int): Request {
val payload = FormBody.Builder()
.add("action", "get_lancamentos")
.add("pagina", page.toString())
.build()
val newHeaders = headersBuilder()
.add("Content-Length", payload.contentLength().toString())
.add("Content-Type", payload.contentType().toString())
.add("X-Requested-With", "XMLHttpRequest")
.build()
return POST("$baseUrl/wp-admin/admin-ajax.php", newHeaders, payload)
}
override fun latestUpdatesParse(response: Response): MangasPage {
val result = response.parseAs<MangaSarLatestDto>()
val latestMangas = result.releases
.map(::latestUpdatesFromObject)
.distinctBy { it.url }
return MangasPage(latestMangas, hasNextPage = result.releases.isNotEmpty())
}
override fun mangaDetailsParse(response: Response): SManga {
val document = response.asJsoup()
val infoElement = document.selectFirst("div.box-single:has(div.mangapage)")
return SManga.create().apply {
title = infoElement.selectFirst("h1.kw-title").text()
author = infoElement.selectFirst("div.mdq.author").text().trim()
description = infoElement.selectFirst("div.sinopse-page").text()
genre = infoElement.select("div.generos a.widget-btn").joinToString { it.text() }
status = infoElement.selectFirst("span.mdq").text().toStatus()
thumbnail_url = infoElement.selectFirst("div.thumb img").attr("abs:data-lazy-src")
}
}
override fun chapterListPaginatedRequest(mangaUrl: String, page: Int): Request {
return GET(baseUrl + mangaUrl, headers)
}
override fun chapterListParse(response: Response): List<SChapter> {
return response.asJsoup()
.select("ul.full-chapters-list > li > a")
.map(::chapterFromElement)
}
private fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = element.selectFirst("span.cap-text")!!.text()
date_upload = element.selectFirst("span.chapter-date")?.text()?.toDate() ?: 0L
setUrlWithoutDomain(element.attr("href"))
}
override fun pageListApiRequest(chapterUrl: String, serieId: String, token: String): Request {
val chapterId = CHAPTER_ID_REGEX.find(chapterUrl)!!.groupValues[1]
val payload = FormBody.Builder()
.add("action", "get_image_list")
.add("id_serie", chapterId)
.add("secury", token)
.build()
val newHeaders = apiHeadersBuilder()
.add("Content-Length", payload.contentLength().toString())
.add("Content-Type", payload.contentType().toString())
.set("Referer", chapterUrl)
.build()
return POST("$baseUrl/wp-admin/admin-ajax.php", newHeaders, payload)
}
override fun pageListParse(response: Response): List<Page> {
val document = response.asJsoup()
val apiParams = document.selectFirst("script:containsData(id_serie)")?.data()
?: throw Exception(TOKEN_NOT_FOUND)
val chapterUrl = response.request.url.toString()
val infoReader = apiParams
.substringAfter("{")
.substringBeforeLast("}")
val readerParams = json.parseToJsonElement("{$infoReader}").jsonObject
val serieId = readerParams["id_serie"]!!.jsonPrimitive.content
val token = readerParams["token"]!!.jsonPrimitive.content
val apiRequest = pageListApiRequest(chapterUrl, serieId, token)
val apiResponse = client.newCall(apiRequest).execute().parseAs<MangaSarReaderDto>()
return apiResponse.images
.filter { it.url.startsWith("http") }
.mapIndexed { i, page -> Page(i, chapterUrl, page.url) }
}
private fun String.toStatus(): Int = when (this) {
"Em andamento" -> SManga.ONGOING
"Completo" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
companion object {
private val CHAPTER_ID_REGEX = "(\\d+)$".toRegex()
}
}

View File

@ -50,7 +50,7 @@ abstract class MangaSar(
.add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", "$baseUrl/")
private fun apiHeadersBuilder(): Headers.Builder = headersBuilder()
protected fun apiHeadersBuilder(): Headers.Builder = headersBuilder()
.set("Accept", ACCEPT)
.add("X-Requested-With", "XMLHttpRequest")
@ -100,12 +100,12 @@ abstract class MangaSar(
.map(::latestUpdatesFromObject)
.distinctBy { it.url }
val hasNextPage = result.page.toInt() < result.totalPage
val hasNextPage = result.page.toInt() < result.totalPage!!
return MangasPage(latestMangas, hasNextPage)
}
private fun latestUpdatesFromObject(release: MangaSarReleaseDto) = SManga.create().apply {
protected fun latestUpdatesFromObject(release: MangaSarReleaseDto) = SManga.create().apply {
title = release.name.withoutEntities()
thumbnail_url = release.image
url = release.link
@ -200,7 +200,7 @@ abstract class MangaSar(
setUrlWithoutDomain(chapter.link)
}
private fun pageListApiRequest(chapterUrl: String, serieId: String, token: String): Request {
protected open fun pageListApiRequest(chapterUrl: String, serieId: String, token: String): Request {
val newHeaders = apiHeadersBuilder()
.set("Referer", chapterUrl)
.build()
@ -296,6 +296,6 @@ abstract class MangaSar(
private val DATE_FORMATTER by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) }
private const val TOKEN_NOT_FOUND = "Não foi possível obter o token de leitura."
const val TOKEN_NOT_FOUND = "Não foi possível obter o token de leitura."
}
}

View File

@ -2,13 +2,14 @@ package eu.kanade.tachiyomi.multisrc.mangasar
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import kotlinx.serialization.json.JsonPrimitive
@Serializable
data class MangaSarLatestDto(
val page: String,
val releases: List<MangaSarReleaseDto> = emptyList(),
@SerialName("total_page") val totalPage: Int
@JsonNames("lancamentos") val releases: List<MangaSarReleaseDto> = emptyList(),
@SerialName("total_page") val totalPage: Int? = 0
)
@Serializable

View File

@ -14,7 +14,8 @@ class MangaSarGenerator : ThemeSourceGenerator {
override val sources = listOf(
SingleLang("Fire Mangás", "https://firemangas.com", "pt-BR", className = "FireMangas"),
SingleLang("Mangazim", "https://mangazim.com", "pt-BR"),
SingleLang("Meus Mangás", "https://meusmangas.net", "pt-BR", isNsfw = true, className = "MeusMangas", overrideVersionCode = 2)
SingleLang("MangásUp", "https://mangasup.net", "pt-BR", className = "MangasUp"),
SingleLang("Seemangas", "https://seemangas.com", "pt-BR", isNsfw = true)
)
companion object {