diff --git a/lib-multisrc/mangaesp/build.gradle.kts b/lib-multisrc/mangaesp/build.gradle.kts index 590e23558..213cd2b08 100644 --- a/lib-multisrc/mangaesp/build.gradle.kts +++ b/lib-multisrc/mangaesp/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("lib-multisrc") } -baseVersionCode = 1 +baseVersionCode = 2 dependencies { api(project(":lib:i18n")) diff --git a/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEsp.kt b/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEsp.kt index 04634f7d5..afdb15678 100644 --- a/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEsp.kt +++ b/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEsp.kt @@ -73,7 +73,7 @@ abstract class MangaEsp( return MangasPage(mangas, false) } - private var comicsList = mutableListOf() + protected var comicsList = mutableListOf() override fun fetchSearchManga( page: Int, @@ -93,7 +93,7 @@ abstract class MangaEsp( override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException() - private fun searchMangaParse(response: Response, page: Int, query: String, filters: FilterList): MangasPage { + protected open fun searchMangaParse(response: Response, page: Int, query: String, filters: FilterList): MangasPage { val document = response.asJsoup() val script = document.select("script:containsData(self.__next_f.push)").joinToString { it.data() } val jsonString = MANGA_LIST_REGEX.find(script)?.groupValues?.get(1) @@ -105,7 +105,7 @@ abstract class MangaEsp( private var filteredList = mutableListOf() - private fun parseComicsList(page: Int, query: String, filterList: FilterList): MangasPage { + protected open fun parseComicsList(page: Int, query: String, filterList: FilterList): MangasPage { if (page == 1) { filteredList.clear() @@ -228,21 +228,21 @@ abstract class MangaEsp( override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException() - private fun Element.imgAttr(): String = when { + protected open fun Element.imgAttr(): String = when { hasAttr("data-lazy-src") -> attr("abs:data-lazy-src") hasAttr("data-src") -> attr("abs:data-src") hasAttr("data-cfsrc") -> attr("abs:data-cfsrc") else -> attr("abs:src") } - private fun String.unescape(): String { + fun String.unescape(): String { return UNESCAPE_REGEX.replace(this, "$1") } companion object { private val UNESCAPE_REGEX = """\\(.)""".toRegex() - private val MANGA_LIST_REGEX = """self\.__next_f\.push\(.*data\\":(\[.*trending.*])\}""".toRegex() + val MANGA_LIST_REGEX = """self\.__next_f\.push\(.*data\\":(\[.*trending.*])\}""".toRegex() private val MANGA_DETAILS_REGEX = """self\.__next_f\.push\(.*data\\":(\{.*lastChapters.*\}).*\\"numFollow""".toRegex() - private const val MANGAS_PER_PAGE = 15 + const val MANGAS_PER_PAGE = 15 } } diff --git a/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEspDto.kt b/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEspDto.kt index 1e0917abd..a844ed863 100644 --- a/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEspDto.kt +++ b/lib-multisrc/mangaesp/src/eu/kanade/tachiyomi/multisrc/mangaesp/MangaEspDto.kt @@ -44,7 +44,9 @@ class SeriesDto( val trending: TrendingDto? = null, @SerialName("autors") private val authors: List = emptyList(), private val artists: List = emptyList(), - + @Suppress("unused") // Used in some sources + @SerialName("idioma") + val language: String? = null, ) { fun toSManga(): SManga { return SManga.create().apply { diff --git a/src/es/eternalmangas/build.gradle b/src/all/eternalmangas/build.gradle similarity index 82% rename from src/es/eternalmangas/build.gradle rename to src/all/eternalmangas/build.gradle index 95a07f9cb..102c6b8aa 100644 --- a/src/es/eternalmangas/build.gradle +++ b/src/all/eternalmangas/build.gradle @@ -1,6 +1,6 @@ ext { extName = 'EternalMangas' - extClass = '.EternalMangas' + extClass = '.EternalMangasFactory' themePkg = 'mangaesp' baseUrl = 'https://eternalmangas.com' overrideVersionCode = 0 diff --git a/src/es/eternalmangas/res/mipmap-hdpi/ic_launcher.png b/src/all/eternalmangas/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/es/eternalmangas/res/mipmap-hdpi/ic_launcher.png rename to src/all/eternalmangas/res/mipmap-hdpi/ic_launcher.png diff --git a/src/es/eternalmangas/res/mipmap-mdpi/ic_launcher.png b/src/all/eternalmangas/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/es/eternalmangas/res/mipmap-mdpi/ic_launcher.png rename to src/all/eternalmangas/res/mipmap-mdpi/ic_launcher.png diff --git a/src/es/eternalmangas/res/mipmap-xhdpi/ic_launcher.png b/src/all/eternalmangas/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/es/eternalmangas/res/mipmap-xhdpi/ic_launcher.png rename to src/all/eternalmangas/res/mipmap-xhdpi/ic_launcher.png diff --git a/src/es/eternalmangas/res/mipmap-xxhdpi/ic_launcher.png b/src/all/eternalmangas/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/es/eternalmangas/res/mipmap-xxhdpi/ic_launcher.png rename to src/all/eternalmangas/res/mipmap-xxhdpi/ic_launcher.png diff --git a/src/es/eternalmangas/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/eternalmangas/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/es/eternalmangas/res/mipmap-xxxhdpi/ic_launcher.png rename to src/all/eternalmangas/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/all/eternalmangas/src/eu/kanade/tachiyomi/extension/all/eternalmangas/EternalMangas.kt b/src/all/eternalmangas/src/eu/kanade/tachiyomi/extension/all/eternalmangas/EternalMangas.kt new file mode 100644 index 000000000..5d433267a --- /dev/null +++ b/src/all/eternalmangas/src/eu/kanade/tachiyomi/extension/all/eternalmangas/EternalMangas.kt @@ -0,0 +1,82 @@ +package eu.kanade.tachiyomi.extension.all.eternalmangas + +import eu.kanade.tachiyomi.multisrc.mangaesp.MangaEsp +import eu.kanade.tachiyomi.multisrc.mangaesp.SeriesDto +import eu.kanade.tachiyomi.multisrc.mangaesp.TopSeriesDto +import eu.kanade.tachiyomi.network.POST +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.util.asJsoup +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import okhttp3.FormBody +import okhttp3.Response + +open class EternalMangas( + lang: String, + private val internalLang: String, +) : MangaEsp( + "EternalMangas", + "https://eternalmangas.com", + lang, +) { + + override fun popularMangaParse(response: Response): MangasPage { + val body = response.body.string() + val responseData = json.decodeFromString(body) + + val topDaily = responseData.response.topDaily.flatten().map { it.data } + val topWeekly = responseData.response.topWeekly.flatten().map { it.data } + val topMonthly = responseData.response.topMonthly.flatten().map { it.data } + + val mangas = (topDaily + topWeekly + topMonthly).distinctBy { it.slug } + .filter { it.language == internalLang } + .map { it.toSManga() } + + return MangasPage(mangas, false) + } + + override fun latestUpdatesParse(response: Response): MangasPage { + val responseData = json.decodeFromString(response.body.string()) + val mangas = responseData.updates[internalLang]?.flatten()?.map { it.toSManga() } ?: emptyList() + return MangasPage(mangas, false) + } + + override fun searchMangaParse(response: Response, page: Int, query: String, filters: FilterList): MangasPage { + val document = response.asJsoup() + val script = document.select("script:containsData(self.__next_f.push)").joinToString { it.data() } + val jsonString = MANGA_LIST_REGEX.find(script)?.groupValues?.get(1) + ?: throw Exception(intl["comics_list_error"]) + val unescapedJson = jsonString.unescape() + comicsList = json.decodeFromString>(unescapedJson) + .filter { it.language == internalLang } + .toMutableList() + return parseComicsList(page, query, filters) + } + + override fun pageListParse(response: Response): List { + var document = response.asJsoup() + + document.selectFirst("body > form[method=post]")?.let { + val action = it.attr("action") + val inputs = it.select("input") + + val form = FormBody.Builder() + inputs.forEach { input -> + form.add(input.attr("name"), input.attr("value")) + } + + document = client.newCall(POST(action, headers, form.build())).execute().asJsoup() + } + + return document.select("main > img").mapIndexed { i, img -> + Page(i, imageUrl = img.imgAttr()) + } + } + + @Serializable + class LatestUpdatesDto( + val updates: Map>>, + ) +} diff --git a/src/all/eternalmangas/src/eu/kanade/tachiyomi/extension/all/eternalmangas/EternalMangasFactory.kt b/src/all/eternalmangas/src/eu/kanade/tachiyomi/extension/all/eternalmangas/EternalMangasFactory.kt new file mode 100644 index 000000000..74e63afbc --- /dev/null +++ b/src/all/eternalmangas/src/eu/kanade/tachiyomi/extension/all/eternalmangas/EternalMangasFactory.kt @@ -0,0 +1,15 @@ +package eu.kanade.tachiyomi.extension.all.eternalmangas + +import eu.kanade.tachiyomi.source.SourceFactory + +class EternalMangasFactory : SourceFactory { + override fun createSources() = listOf( + EternalMangasES(), + EternalMangasEN(), + EternalMangasPTBR(), + ) +} + +class EternalMangasES : EternalMangas("es", "es") +class EternalMangasEN : EternalMangas("en", "en") +class EternalMangasPTBR : EternalMangas("pt-BR", "pt") diff --git a/src/es/eternalmangas/src/eu/kanade/tachiyomi/extension/es/eternalmangas/EternalMangas.kt b/src/es/eternalmangas/src/eu/kanade/tachiyomi/extension/es/eternalmangas/EternalMangas.kt deleted file mode 100644 index 72b77a913..000000000 --- a/src/es/eternalmangas/src/eu/kanade/tachiyomi/extension/es/eternalmangas/EternalMangas.kt +++ /dev/null @@ -1,5 +0,0 @@ -package eu.kanade.tachiyomi.extension.es.eternalmangas - -import eu.kanade.tachiyomi.multisrc.mangaesp.MangaEsp - -class EternalMangas : MangaEsp("EternalMangas", "https://eternalmangas.com", "es")