diff --git a/multisrc/overrides/mangasar/default/additional.gradle.kts b/multisrc/overrides/mangasar/default/additional.gradle.kts new file mode 100644 index 000000000..10beb8157 --- /dev/null +++ b/multisrc/overrides/mangasar/default/additional.gradle.kts @@ -0,0 +1,4 @@ + +dependencies { + implementation project(':lib-ratelimit') +} diff --git a/src/pt/mangatube/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/mangasar/default/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/pt/mangatube/res/mipmap-hdpi/ic_launcher.png rename to multisrc/overrides/mangasar/default/res/mipmap-hdpi/ic_launcher.png diff --git a/multisrc/overrides/mangasar/default/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/mangasar/default/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..aa7edff85 Binary files /dev/null and b/multisrc/overrides/mangasar/default/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/mangasar/default/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/mangasar/default/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..0dfe9e075 Binary files /dev/null and b/multisrc/overrides/mangasar/default/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/mangasar/default/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/mangasar/default/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..1690d709e Binary files /dev/null and b/multisrc/overrides/mangasar/default/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/mangasar/default/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/mangasar/default/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..39f7dda6a Binary files /dev/null and b/multisrc/overrides/mangasar/default/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/mangasar/default/res/web_hi_res_512.png b/multisrc/overrides/mangasar/default/res/web_hi_res_512.png new file mode 100644 index 000000000..5b26d20e5 Binary files /dev/null and b/multisrc/overrides/mangasar/default/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/mangasar/mangatube/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/mangasar/mangatube/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..5f3c83a4c Binary files /dev/null and b/multisrc/overrides/mangasar/mangatube/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/pt/mangatube/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/mangasar/mangatube/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/pt/mangatube/res/mipmap-mdpi/ic_launcher.png rename to multisrc/overrides/mangasar/mangatube/res/mipmap-mdpi/ic_launcher.png diff --git a/src/pt/mangatube/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/mangasar/mangatube/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/pt/mangatube/res/mipmap-xhdpi/ic_launcher.png rename to multisrc/overrides/mangasar/mangatube/res/mipmap-xhdpi/ic_launcher.png diff --git a/src/pt/mangatube/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/mangasar/mangatube/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/pt/mangatube/res/mipmap-xxhdpi/ic_launcher.png rename to multisrc/overrides/mangasar/mangatube/res/mipmap-xxhdpi/ic_launcher.png diff --git a/src/pt/mangatube/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/mangasar/mangatube/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/pt/mangatube/res/mipmap-xxxhdpi/ic_launcher.png rename to multisrc/overrides/mangasar/mangatube/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/pt/mangatube/res/web_hi_res_512.png b/multisrc/overrides/mangasar/mangatube/res/web_hi_res_512.png similarity index 100% rename from src/pt/mangatube/res/web_hi_res_512.png rename to multisrc/overrides/mangasar/mangatube/res/web_hi_res_512.png diff --git a/multisrc/overrides/mangasar/mangatube/src/MangaTube.kt b/multisrc/overrides/mangasar/mangatube/src/MangaTube.kt new file mode 100644 index 000000000..876dc3952 --- /dev/null +++ b/multisrc/overrides/mangasar/mangatube/src/MangaTube.kt @@ -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() +} diff --git a/multisrc/overrides/mangasar/meusmangas/src/MeusMangas.kt b/multisrc/overrides/mangasar/meusmangas/src/MeusMangas.kt new file mode 100644 index 000000000..8c443ff53 --- /dev/null +++ b/multisrc/overrides/mangasar/meusmangas/src/MeusMangas.kt @@ -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 + } +} diff --git a/src/pt/mangatube/src/eu/kanade/tachiyomi/extension/pt/mangatube/MangaTube.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSar.kt similarity index 87% rename from src/pt/mangatube/src/eu/kanade/tachiyomi/extension/pt/mangatube/MangaTube.kt rename to multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSar.kt index 4440e5bd6..960b8b25b 100644 --- a/src/pt/mangatube/src/eu/kanade/tachiyomi/extension/pt/mangatube/MangaTube.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSar.kt @@ -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.POST import eu.kanade.tachiyomi.source.model.FilterList @@ -24,27 +23,22 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Element +import org.jsoup.parser.Parser import rx.Observable import uy.kohesive.injekt.injectLazy import java.text.ParseException import java.text.SimpleDateFormat import java.util.Locale -import java.util.concurrent.TimeUnit -class MangaTube : HttpSource() { - - override val name = "MangaTube" - - override val baseUrl = "https://mangatube.site" - - override val lang = "pt-BR" +abstract class MangaSar( + override val name: String, + override val baseUrl: String, + override val lang: String +) : HttpSource() { override val supportsLatest = true - override val client: OkHttpClient = network.cloudflareClient.newBuilder() - .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) - .addInterceptor(::searchIntercept) - .build() + override val client: OkHttpClient = network.cloudflareClient override fun headersBuilder(): Headers.Builder = Headers.Builder() .add("Accept", ACCEPT_HTML) @@ -66,13 +60,16 @@ class MangaTube : HttpSource() { override fun popularMangaParse(response: Response): MangasPage { val document = response.asJsoup() - val mangas = document.select("div:contains(Populares) ~ ul.mangasList li div.gridbox") + val mangas = document.select(popularMangaSelector()) .map(::popularMangaFromElement) 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() thumbnail_url = element.select("div.thumb img").first()!!.attr("abs:src") setUrlWithoutDomain(element.select("a").first()!!.attr("href")) @@ -92,18 +89,19 @@ class MangaTube : HttpSource() { } 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 .map(::latestUpdatesFromObject) + .distinctBy { it.url } val hasNextPage = result.page.toInt() < result.totalPage return MangasPage(latestMangas, hasNextPage) } - private fun latestUpdatesFromObject(release: MangaTubeReleaseDto) = SManga.create().apply { - title = release.name + private fun latestUpdatesFromObject(release: MangaSarReleaseDto) = SManga.create().apply { + title = release.name.withoutEntities() thumbnail_url = release.image url = release.link } @@ -118,14 +116,14 @@ class MangaTube : HttpSource() { } 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) return MangasPage(searchResults, hasNextPage = false) } - private fun searchMangaFromObject(manga: MangaTubeTitleDto) = SManga.create().apply { + private fun searchMangaFromObject(manga: MangaSarTitleDto) = SManga.create().apply { title = manga.title thumbnail_url = manga.image setUrlWithoutDomain(manga.url) @@ -164,7 +162,7 @@ class MangaTube : HttpSource() { override fun chapterListParse(response: Response): List<SChapter> { 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()) { return emptyList() @@ -191,7 +189,7 @@ class MangaTube : HttpSource() { 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) + (if (chapter.name.isString) " - " + chapter.name.content else "") chapter_number = chapter.number.floatOrNull ?: -1f @@ -224,7 +222,7 @@ class MangaTube : HttpSource() { val apiRequest = pageListApiRequest(chapterUrl, serieId, token) val apiResponse = client.newCall(apiRequest).execute().let { - json.decodeFromString<MangaTubeReaderDto>(it.body!!.string()) + json.decodeFromString<MangaSarReaderDto>(it.body!!.string()) } return apiResponse.images @@ -245,7 +243,7 @@ class MangaTube : HttpSource() { 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/")) { val homeRequest = popularMangaRequest(1) 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 { private const val ACCEPT = "application/json, text/plain, */*" private const val ACCEPT_HTML = "text/html,application/xhtml+xml,application/xml;q=0.9," + diff --git a/src/pt/mangatube/src/eu/kanade/tachiyomi/extension/pt/mangatube/MangaTubeDto.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSarDto.kt similarity index 62% rename from src/pt/mangatube/src/eu/kanade/tachiyomi/extension/pt/mangatube/MangaTubeDto.kt rename to multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSarDto.kt index 9e9e678d1..3974adb19 100644 --- a/src/pt/mangatube/src/eu/kanade/tachiyomi/extension/pt/mangatube/MangaTubeDto.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSarDto.kt @@ -1,39 +1,39 @@ -package eu.kanade.tachiyomi.extension.pt.mangatube +package eu.kanade.tachiyomi.multisrc.mangasar import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonPrimitive @Serializable -data class MangaTubeLatestDto( +data class MangaSarLatestDto( val page: String, - val releases: List<MangaTubeReleaseDto> = emptyList(), + val releases: List<MangaSarReleaseDto> = emptyList(), @SerialName("total_page") val totalPage: Int ) @Serializable -data class MangaTubeReleaseDto( +data class MangaSarReleaseDto( val image: String, val link: String, val name: String ) @Serializable -data class MangaTubeTitleDto( +data class MangaSarTitleDto( @SerialName("img") val image: String, val title: String, val url: String ) @Serializable -data class MangaTubePaginatedChaptersDto( - val chapters: List<MangaTubeChapterDto>? = emptyList(), +data class MangaSarPaginatedChaptersDto( + val chapters: List<MangaSarChapterDto>? = emptyList(), @SerialName("pagina") val page: Int, @SerialName("total_pags") val totalPages: Int ) @Serializable -data class MangaTubeChapterDto( +data class MangaSarChapterDto( @SerialName("date_created") val dateCreated: String, val link: String, @SerialName("chapter_name") val name: JsonPrimitive, @@ -41,11 +41,11 @@ data class MangaTubeChapterDto( ) @Serializable -data class MangaTubeReaderDto( - val images: List<MangaTubePageDto> = emptyList() +data class MangaSarReaderDto( + val images: List<MangaSarPageDto> = emptyList() ) @Serializable -data class MangaTubePageDto( +data class MangaSarPageDto( val url: String ) diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSarGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSarGenerator.kt new file mode 100644 index 000000000..b2aa25992 --- /dev/null +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangasar/MangaSarGenerator.kt @@ -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() + } + } +} + diff --git a/src/pt/mangatube/AndroidManifest.xml b/src/pt/mangatube/AndroidManifest.xml deleted file mode 100644 index 30deb7f79..000000000 --- a/src/pt/mangatube/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest package="eu.kanade.tachiyomi.extension" /> diff --git a/src/pt/mangatube/build.gradle b/src/pt/mangatube/build.gradle deleted file mode 100644 index 3cad5f847..000000000 --- a/src/pt/mangatube/build.gradle +++ /dev/null @@ -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" -