Move MT to multisrc and add a new source. (#8478)

This commit is contained in:
Alessandro Jean 2021-08-09 07:58:15 -03:00 committed by GitHub
parent b4a80e6085
commit ab8ea9ddb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 138 additions and 56 deletions

View File

@ -0,0 +1,4 @@
dependencies {
implementation project(':lib-ratelimit')
}

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,18 @@
package eu.kanade.tachiyomi.extension.pt.mangatube
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSar
import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaTube : MangaSar(
"MangaTube",
"https://mangatube.site",
"pt-BR"
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::searchIntercept)
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
}

View File

@ -0,0 +1,52 @@
package eu.kanade.tachiyomi.extension.pt.meusmangas
import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangasar.MangaSar
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
import okhttp3.Response
import org.jsoup.nodes.Element
import java.util.concurrent.TimeUnit
@Nsfw
class MeusMangas : MangaSar(
"Meus Mangás",
"https://meusmangas.net",
"pt-BR"
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::searchIntercept)
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
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 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.touchcarousel a.widget-btn").joinToString { it.text() }
status = infoElement.selectFirst("span.mdq").text().toStatus()
thumbnail_url = infoElement.selectFirst("div.thumb img").attr("abs:src")
}
}
private fun String.toStatus(): Int = when (this) {
"Em andamento" -> SManga.ONGOING
"Completo" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
}

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.extension.pt.mangatube package eu.kanade.tachiyomi.multisrc.mangasar
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
@ -24,27 +23,22 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.parser.Parser
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit
class MangaTube : HttpSource() { abstract class MangaSar(
override val name: String,
override val name = "MangaTube" override val baseUrl: String,
override val lang: String
override val baseUrl = "https://mangatube.site" ) : HttpSource() {
override val lang = "pt-BR"
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.addInterceptor(::searchIntercept)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder() override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", ACCEPT_HTML) .add("Accept", ACCEPT_HTML)
@ -66,13 +60,16 @@ class MangaTube : HttpSource() {
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup() val document = response.asJsoup()
val mangas = document.select("div:contains(Populares) ~ ul.mangasList li div.gridbox") val mangas = document.select(popularMangaSelector())
.map(::popularMangaFromElement) .map(::popularMangaFromElement)
return MangasPage(mangas, hasNextPage = false) return MangasPage(mangas, hasNextPage = false)
} }
private fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { protected open fun popularMangaSelector(): String =
"div:contains(Populares) ~ ul.mangasList li div.gridbox"
protected open fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("div.title a").first()!!.text() title = element.select("div.title a").first()!!.text()
thumbnail_url = element.select("div.thumb img").first()!!.attr("abs:src") thumbnail_url = element.select("div.thumb img").first()!!.attr("abs:src")
setUrlWithoutDomain(element.select("a").first()!!.attr("href")) setUrlWithoutDomain(element.select("a").first()!!.attr("href"))
@ -92,18 +89,19 @@ class MangaTube : HttpSource() {
} }
override fun latestUpdatesParse(response: Response): MangasPage { override fun latestUpdatesParse(response: Response): MangasPage {
val result = json.decodeFromString<MangaTubeLatestDto>(response.body!!.string()) val result = json.decodeFromString<MangaSarLatestDto>(response.body!!.string())
val latestMangas = result.releases val latestMangas = result.releases
.map(::latestUpdatesFromObject) .map(::latestUpdatesFromObject)
.distinctBy { it.url }
val hasNextPage = result.page.toInt() < result.totalPage val hasNextPage = result.page.toInt() < result.totalPage
return MangasPage(latestMangas, hasNextPage) return MangasPage(latestMangas, hasNextPage)
} }
private fun latestUpdatesFromObject(release: MangaTubeReleaseDto) = SManga.create().apply { private fun latestUpdatesFromObject(release: MangaSarReleaseDto) = SManga.create().apply {
title = release.name title = release.name.withoutEntities()
thumbnail_url = release.image thumbnail_url = release.image
url = release.link url = release.link
} }
@ -118,14 +116,14 @@ class MangaTube : HttpSource() {
} }
override fun searchMangaParse(response: Response): MangasPage { override fun searchMangaParse(response: Response): MangasPage {
val result = json.decodeFromString<Map<String, MangaTubeTitleDto>>(response.body!!.string()) val result = json.decodeFromString<Map<String, MangaSarTitleDto>>(response.body!!.string())
val searchResults = result.values.map(::searchMangaFromObject) val searchResults = result.values.map(::searchMangaFromObject)
return MangasPage(searchResults, hasNextPage = false) return MangasPage(searchResults, hasNextPage = false)
} }
private fun searchMangaFromObject(manga: MangaTubeTitleDto) = SManga.create().apply { private fun searchMangaFromObject(manga: MangaSarTitleDto) = SManga.create().apply {
title = manga.title title = manga.title
thumbnail_url = manga.image thumbnail_url = manga.image
setUrlWithoutDomain(manga.url) setUrlWithoutDomain(manga.url)
@ -164,7 +162,7 @@ class MangaTube : HttpSource() {
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val mangaUrl = response.request.header("Referer")!!.substringAfter(baseUrl) val mangaUrl = response.request.header("Referer")!!.substringAfter(baseUrl)
var result = json.decodeFromString<MangaTubePaginatedChaptersDto>(response.body!!.string()) var result = json.decodeFromString<MangaSarPaginatedChaptersDto>(response.body!!.string())
if (result.chapters.isNullOrEmpty()) { if (result.chapters.isNullOrEmpty()) {
return emptyList() return emptyList()
@ -191,7 +189,7 @@ class MangaTube : HttpSource() {
return chapters return chapters
} }
private fun chapterFromObject(chapter: MangaTubeChapterDto): SChapter = SChapter.create().apply { private fun chapterFromObject(chapter: MangaSarChapterDto): SChapter = SChapter.create().apply {
name = "Cap. " + (if (chapter.number.booleanOrNull != null) "0" else chapter.number.content) + name = "Cap. " + (if (chapter.number.booleanOrNull != null) "0" else chapter.number.content) +
(if (chapter.name.isString) " - " + chapter.name.content else "") (if (chapter.name.isString) " - " + chapter.name.content else "")
chapter_number = chapter.number.floatOrNull ?: -1f chapter_number = chapter.number.floatOrNull ?: -1f
@ -224,7 +222,7 @@ class MangaTube : HttpSource() {
val apiRequest = pageListApiRequest(chapterUrl, serieId, token) val apiRequest = pageListApiRequest(chapterUrl, serieId, token)
val apiResponse = client.newCall(apiRequest).execute().let { val apiResponse = client.newCall(apiRequest).execute().let {
json.decodeFromString<MangaTubeReaderDto>(it.body!!.string()) json.decodeFromString<MangaSarReaderDto>(it.body!!.string())
} }
return apiResponse.images return apiResponse.images
@ -245,7 +243,7 @@ class MangaTube : HttpSource() {
return GET(page.imageUrl!!, newHeaders) return GET(page.imageUrl!!, newHeaders)
} }
private fun searchIntercept(chain: Interceptor.Chain): Response { protected fun searchIntercept(chain: Interceptor.Chain): Response {
if (chain.request().url.toString().contains("/search/")) { if (chain.request().url.toString().contains("/search/")) {
val homeRequest = popularMangaRequest(1) val homeRequest = popularMangaRequest(1)
val document = chain.proceed(homeRequest).asJsoup() val document = chain.proceed(homeRequest).asJsoup()
@ -278,6 +276,10 @@ class MangaTube : HttpSource() {
} }
} }
private fun String.withoutEntities(): String {
return Parser.unescapeEntities(this, true)
}
companion object { companion object {
private const val ACCEPT = "application/json, text/plain, */*" private const val ACCEPT = "application/json, text/plain, */*"
private const val ACCEPT_HTML = "text/html,application/xhtml+xml,application/xml;q=0.9," + private const val ACCEPT_HTML = "text/html,application/xhtml+xml,application/xml;q=0.9," +

View File

@ -1,39 +1,39 @@
package eu.kanade.tachiyomi.extension.pt.mangatube package eu.kanade.tachiyomi.multisrc.mangasar
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonPrimitive
@Serializable @Serializable
data class MangaTubeLatestDto( data class MangaSarLatestDto(
val page: String, val page: String,
val releases: List<MangaTubeReleaseDto> = emptyList(), val releases: List<MangaSarReleaseDto> = emptyList(),
@SerialName("total_page") val totalPage: Int @SerialName("total_page") val totalPage: Int
) )
@Serializable @Serializable
data class MangaTubeReleaseDto( data class MangaSarReleaseDto(
val image: String, val image: String,
val link: String, val link: String,
val name: String val name: String
) )
@Serializable @Serializable
data class MangaTubeTitleDto( data class MangaSarTitleDto(
@SerialName("img") val image: String, @SerialName("img") val image: String,
val title: String, val title: String,
val url: String val url: String
) )
@Serializable @Serializable
data class MangaTubePaginatedChaptersDto( data class MangaSarPaginatedChaptersDto(
val chapters: List<MangaTubeChapterDto>? = emptyList(), val chapters: List<MangaSarChapterDto>? = emptyList(),
@SerialName("pagina") val page: Int, @SerialName("pagina") val page: Int,
@SerialName("total_pags") val totalPages: Int @SerialName("total_pags") val totalPages: Int
) )
@Serializable @Serializable
data class MangaTubeChapterDto( data class MangaSarChapterDto(
@SerialName("date_created") val dateCreated: String, @SerialName("date_created") val dateCreated: String,
val link: String, val link: String,
@SerialName("chapter_name") val name: JsonPrimitive, @SerialName("chapter_name") val name: JsonPrimitive,
@ -41,11 +41,11 @@ data class MangaTubeChapterDto(
) )
@Serializable @Serializable
data class MangaTubeReaderDto( data class MangaSarReaderDto(
val images: List<MangaTubePageDto> = emptyList() val images: List<MangaSarPageDto> = emptyList()
) )
@Serializable @Serializable
data class MangaTubePageDto( data class MangaSarPageDto(
val url: String val url: String
) )

View File

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.multisrc.mangasar
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class MangaSarGenerator : ThemeSourceGenerator {
override val themePkg = "mangasar"
override val themeClass = "MangaSar"
override val baseVersionCode: Int = 4
override val sources = listOf(
SingleLang("MangaTube", "https://mangatube.site", "pt-BR"),
SingleLang("Meus Mangás", "https://meusmangas.net", "pt-BR", isNsfw = true, className = "MeusMangas")
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
MangaSarGenerator().createAll()
}
}
}

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -1,18 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'MangaTube'
pkgNameSuffix = 'pt.mangatube'
extClass = '.MangaTube'
extVersionCode = 3
libVersion = '1.2'
}
dependencies {
implementation project(':lib-ratelimit')
}
apply from: "$rootDir/common.gradle"