From 48f1bac534bd0bf870acb56e20bb83b650b13ff4 Mon Sep 17 00:00:00 2001
From: imper1aldev <23511335+imper1aldev@users.noreply.github.com>
Date: Wed, 8 Jan 2025 14:50:22 -0600
Subject: [PATCH] fix(src/es): PelisPlusPh & MonosChinos fixes (#497)

* PelisPlusPh fixes

Closes #489

* MonosChinos fixes

Closes #450
---
 src/es/monoschinos/build.gradle               |   2 +-
 .../es/monoschinos/MonosChinos.kt             | 109 ++++++++++--------
 .../es/monoschinos/MonosChinosFilters.kt      |  82 +++++++++----
 src/es/pelisplushd/build.gradle               |   2 +-
 .../es/pelisplushd/Pelisplushd.kt             |   2 +
 .../es/pelisplushd/PelisplushdFactory.kt      |   2 +-
 .../es/pelisplushd/Pelisplusph.kt             |   7 +-
 .../es/pelisplushd/Pelisplusto.kt             |   2 +
 8 files changed, 130 insertions(+), 78 deletions(-)

diff --git a/src/es/monoschinos/build.gradle b/src/es/monoschinos/build.gradle
index a22dc4c4..e716c223 100644
--- a/src/es/monoschinos/build.gradle
+++ b/src/es/monoschinos/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'MonosChinos'
     extClass = '.MonosChinos'
-    extVersionCode = 29
+    extVersionCode = 30
 }
 
 apply from: "$rootDir/common.gradle"
diff --git a/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinos.kt b/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinos.kt
index 9adcbbcf..9f786cbe 100644
--- a/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinos.kt
+++ b/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinos.kt
@@ -24,7 +24,6 @@ import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.util.asJsoup
 import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
-import eu.kanade.tachiyomi.util.parseAs
 import okhttp3.FormBody
 import okhttp3.Request
 import okhttp3.Response
@@ -37,7 +36,7 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
 
     override val name = "MonosChinos"
 
-    override val baseUrl = "https://monoschinos2.com"
+    override val baseUrl = "https://monoschinos2.net"
 
     override val id = 6957694006954649296
 
@@ -80,7 +79,7 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
             status = document.select(".lh-sm .ms-2").eachText().let { items ->
                 when {
                     items.any { it.contains("Finalizado") } -> SAnime.COMPLETED
-                    items.any { it.contains("Estreno") } -> SAnime.ONGOING
+                    items.any { it.contains("En emision") || it.contains("Estreno") } -> SAnime.ONGOING
                     else -> SAnime.UNKNOWN
                 }
             }
@@ -88,12 +87,12 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
         return animeDetails
     }
 
-    override fun popularAnimeRequest(page: Int) = GET("$baseUrl/animes?p=$page", headers)
+    override fun popularAnimeRequest(page: Int) = GET("$baseUrl/animes?pag=$page", headers)
 
     override fun popularAnimeParse(response: Response): AnimesPage {
         val document = response.asJsoup()
         val elements = document.select(".ficha_efecto a")
-        val nextPage = document.select(".pagination [rel=\"next\"]").any()
+        val nextPage = document.select(".pagination [title=\"Siguiente página\"]").any()
         val animeList = elements.map { element ->
             SAnime.create().apply {
                 title = element.selectFirst(".title_cap")!!.text()
@@ -106,13 +105,13 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
 
     override fun latestUpdatesParse(response: Response) = popularAnimeParse(response)
 
-    override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/emision?p=$page", headers)
+    override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/animes?estado=en+emision&pag=$page", headers)
 
     override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
         val params = MonosChinosFilters.getSearchParameters(filters)
         return when {
-            query.isNotBlank() -> GET("$baseUrl/buscar?q=$query", headers)
-            params.filter.isNotBlank() -> GET("$baseUrl/animes${params.getQuery()}&p=$page", headers)
+            query.isNotBlank() -> GET("$baseUrl/animes?buscar=$query&pag=$page", headers)
+            params.filter.isNotBlank() -> GET("$baseUrl/animes${params.getQuery()}&pag=$page", headers)
             else -> popularAnimeRequest(page)
         }
     }
@@ -121,31 +120,50 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
 
     override fun episodeListParse(response: Response): List<SEpisode> {
         val document = response.asJsoup()
-        val token = document.select("meta[name='csrf-token']").attr("content")
-        val capListLink = document.select(".caplist").attr("data-ajax")
         val referer = document.location()
+        val dt = document.select("#dt")
 
-        val detail = getEpisodeDetails(capListLink, token, referer)
-        val total = detail.eps.size
-        val perPage = detail.perpage ?: return emptyList()
+        val total = dt.attr("data-e").toInt()
+        val perPage = 50.0
         val pages = (total / perPage).ceilPage()
+        val i = dt.attr("data-i")
+        val u = dt.attr("data-u")
 
+        var pageIdx = 1
         return (1..pages).parallelCatchingFlatMapBlocking {
-            getEpisodePage(detail.paginateUrl ?: "", it, token, referer).caps.mapIndexed { idx, ep ->
-                val episodeNumber = (ep.episodio ?: (idx + 1))
-                SEpisode.create().apply {
-                    name = "Capítulo $episodeNumber"
-                    episode_number = episodeNumber.toFloat()
-                    setUrlWithoutDomain(ep.url ?: "")
-                }
-            }
-        }.reversed()
+            val formBody = FormBody.Builder()
+                .add("acc", "episodes")
+                .add("i", i)
+                .add("u", u)
+                .add("p", pageIdx.toString())
+                .build()
+
+            val request = Request.Builder()
+                .url("$baseUrl/ajax_pagination")
+                .post(formBody)
+                .header("accept", "application/json, text/javascript, */*; q=0.01")
+                .header("accept-language", "es-419,es;q=0.8")
+                .header("content-type", "application/x-www-form-urlencoded; charset=UTF-8")
+                .header("origin", baseUrl)
+                .header("referer", referer)
+                .header("x-requested-with", "XMLHttpRequest")
+                .build()
+            pageIdx++
+
+            client.newCall(request).execute().getEpisodes()
+        }
     }
 
-    private fun getEpisodeDetails(capListLink: String, token: String, referer: String): EpisodesDto {
-        val formBody = FormBody.Builder().add("_token", token).build()
+    override fun videoListParse(response: Response): List<Video> {
+        val document = response.asJsoup()
+        val i = document.select(".opt").attr("data-encrypt")
+        val referer = document.location()
+        val formBody = FormBody.Builder()
+            .add("acc", "opt")
+            .add("i", i)
+            .build()
         val request = Request.Builder()
-            .url(capListLink)
+            .url("$baseUrl/ajax_pagination")
             .post(formBody)
             .header("accept", "application/json, text/javascript, */*; q=0.01")
             .header("accept-language", "es-419,es;q=0.8")
@@ -155,31 +173,9 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
             .header("x-requested-with", "XMLHttpRequest")
             .build()
 
-        return client.newCall(request).execute().parseAs<EpisodesDto>()
-    }
+        val serverDocument = client.newCall(request).execute().asJsoup()
 
-    private fun getEpisodePage(paginateUrl: String, page: Int, token: String, referer: String): EpisodeInfoDto {
-        val formBodyEp = FormBody.Builder()
-            .add("_token", token)
-            .add("p", "$page")
-            .build()
-        val requestEp = Request.Builder()
-            .url(paginateUrl)
-            .post(formBodyEp)
-            .header("accept", "application/json, text/javascript, */*; q=0.01")
-            .header("accept-language", "es-419,es;q=0.8")
-            .header("content-type", "application/x-www-form-urlencoded; charset=UTF-8")
-            .header("origin", baseUrl)
-            .header("referer", referer)
-            .header("x-requested-with", "XMLHttpRequest")
-            .build()
-
-        return client.newCall(requestEp).execute().parseAs<EpisodeInfoDto>()
-    }
-
-    override fun videoListParse(response: Response): List<Video> {
-        val document = response.asJsoup()
-        return document.select("[data-player]")
+        return serverDocument.select("[data-player]")
             .map { String(Base64.decode(it.attr("data-player"), Base64.DEFAULT)) }
             .parallelCatchingFlatMapBlocking { serverVideoResolver(it) }
     }
@@ -242,6 +238,21 @@ class MonosChinos : ConfigurableAnimeSource, AnimeHttpSource() {
 
     private fun Double.ceilPage(): Int = if (this % 1 == 0.0) this.toInt() else ceil(this).toInt()
 
+    private fun Response.getEpisodes(): List<SEpisode> {
+        val document = this.asJsoup()
+        return document.select(".ko").mapIndexed { idx, it ->
+            val episodeNumber = try {
+                it.select("h2").text().substringAfter("Capítulo").trim().toFloat()
+            } catch (e: Exception) { idx + 1f }
+
+            SEpisode.create().apply {
+                name = it.select(".fs-6").text()
+                episode_number = episodeNumber
+                setUrlWithoutDomain(it.attr("abs:href"))
+            }
+        }
+    }
+
     override fun setupPreferenceScreen(screen: PreferenceScreen) {
         ListPreference(screen.context).apply {
             key = PREF_SERVER_KEY
diff --git a/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinosFilters.kt b/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinosFilters.kt
index 3fba586b..520b6e09 100644
--- a/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinosFilters.kt
+++ b/src/es/monoschinos/src/eu/kanade/tachiyomi/animeextension/es/monoschinos/MonosChinosFilters.kt
@@ -54,86 +54,118 @@ object MonosChinosFilters {
         if (filters.isEmpty()) return FilterSearchParams()
         return FilterSearchParams(
             filters.parseCheckbox<GenresFilter>(DoramasytFiltersData.GENRES, "genero") +
+                filters.parseCheckbox<YearsFilter>(DoramasytFiltersData.YEARS, "anio") +
                 filters.parseCheckbox<TypesFilter>(DoramasytFiltersData.TYPES, "tipo") +
-                filters.asQueryPart<YearsFilter>("fecha") +
-                filters.asQueryPart<LettersFilter>("letra"),
+                filters.asQueryPart<StatusFilter>("estado") +
+                filters.asQueryPart<SortFilter>("orden"),
         )
     }
 
     val FILTER_LIST get() = AnimeFilterList(
         AnimeFilter.Header("La busqueda por texto ignora el filtro"),
         GenresFilter(),
-        TypesFilter(),
         YearsFilter(),
-        LettersFilter(),
+        TypesFilter(),
+        StatusFilter(),
+        SortFilter(),
     )
 
     class GenresFilter : CheckBoxFilterList("Género", DoramasytFiltersData.GENRES.map { CheckBoxVal(it.first, false) })
 
+    class YearsFilter : CheckBoxFilterList("Año", DoramasytFiltersData.YEARS.map { CheckBoxVal(it.first, false) })
+
     class TypesFilter : CheckBoxFilterList("Tipo", DoramasytFiltersData.TYPES.map { CheckBoxVal(it.first, false) })
 
-    class YearsFilter : QueryPartFilter("Año", DoramasytFiltersData.YEARS)
+    class StatusFilter : QueryPartFilter("Estado", DoramasytFiltersData.STATUS)
 
-    class LettersFilter : QueryPartFilter("Letra", DoramasytFiltersData.LETTER)
+    class SortFilter : QueryPartFilter("Orden", DoramasytFiltersData.SORT)
 
     private object DoramasytFiltersData {
         val TYPES = arrayOf(
-            Pair("<Selecionar>", ""),
-            Pair("Pelicula", "pelicula"),
             Pair("Anime", "anime"),
+            Pair("Audio Japonés", "audio-japones"),
+            Pair("Corto", "corto"),
+            Pair("Donghua", "donghua"),
+            Pair("Especial", "especial"),
+            Pair("Ona", "ona"),
+            Pair("Ova", "ova"),
+            Pair("Película", "pelicula"),
+            Pair("Película 1080p", "pelicula-1080p"),
+            Pair("TV", "tv"),
+            Pair("Sin Censura", "sin-censura"),
         )
 
-        val YEARS = arrayOf(Pair("<Seleccionar>", "")) + (1982..Calendar.getInstance().get(Calendar.YEAR)).map { Pair("$it", "$it") }.reversed().toTypedArray()
+        val STATUS = arrayOf(
+            Pair("Todos", ""),
+            Pair("En emisión", "en-emision"),
+            Pair("Finalizado", "finalizado"),
+        )
 
-        val LETTER = arrayOf(Pair("<Seleccionar>", "")) + ('A'..'Z').map { Pair("$it", "$it") }.toTypedArray()
+        val YEARS = (1968..Calendar.getInstance().get(Calendar.YEAR)).map { Pair("$it", "$it") }.reversed().toTypedArray()
 
         val GENRES = arrayOf(
-            Pair("<Selecionar>", ""),
             Pair("Acción", "accion"),
+            Pair("Aenime", "aenime"),
+            Pair("Anime Latino", "anime-latino"),
+            Pair("Artes Marciales", "artes-marciales"),
             Pair("Aventura", "aventura"),
+            Pair("Aventuras", "aventuras"),
+            Pair("Blu-ray", "blu-ray"),
             Pair("Carreras", "carreras"),
+            Pair("Castellano", "castellano"),
             Pair("Ciencia Ficción", "ciencia-ficcion"),
             Pair("Comedia", "comedia"),
             Pair("Cyberpunk", "cyberpunk"),
+            Pair("Demencia", "demencia"),
+            Pair("Dementia", "dementia"),
+            Pair("Demonios", "demonios"),
             Pair("Deportes", "deportes"),
             Pair("Drama", "drama"),
             Pair("Ecchi", "ecchi"),
             Pair("Escolares", "escolares"),
+            Pair("Espacial", "espacial"),
             Pair("Fantasía", "fantasia"),
             Pair("Gore", "gore"),
             Pair("Harem", "harem"),
+            Pair("Historia paralela", "historia-paralela"),
+            Pair("Historico", "historico"),
             Pair("Horror", "horror"),
+            Pair("Infantil", "infantil"),
             Pair("Josei", "josei"),
+            Pair("Juegos", "juegos"),
+            Pair("Latino", "latino"),
             Pair("Lucha", "lucha"),
             Pair("Magia", "magia"),
             Pair("Mecha", "mecha"),
             Pair("Militar", "militar"),
             Pair("Misterio", "misterio"),
+            Pair("Monogatari", "monogatari"),
             Pair("Música", "musica"),
+            Pair("Parodia", "parodia"),
             Pair("Parodias", "parodias"),
+            Pair("Policía", "policia"),
             Pair("Psicológico", "psicologico"),
+            Pair("Recuentos de la vida", "recuentos-de-la-vida"),
             Pair("Recuerdos de la vida", "recuerdos-de-la-vida"),
+            Pair("Romance", "romance"),
+            Pair("Samurai", "samurai"),
             Pair("Seinen", "seinen"),
             Pair("Shojo", "shojo"),
             Pair("Shonen", "shonen"),
+            Pair("Shoujo", "shoujo"),
+            Pair("Shounen", "shounen"),
             Pair("Sobrenatural", "sobrenatural"),
+            Pair("Superpoderes", "superpoderes"),
+            Pair("Suspenso", "suspenso"),
+            Pair("Terror", "terror"),
             Pair("Vampiros", "vampiros"),
             Pair("Yaoi", "yaoi"),
             Pair("Yuri", "yuri"),
-            Pair("Latino", "latino"),
-            Pair("Espacial", "espacial"),
-            Pair("Histórico", "historico"),
-            Pair("Samurai", "samurai"),
-            Pair("Artes Marciales", "artes-marciales"),
-            Pair("Demonios", "demonios"),
-            Pair("Romance", "romance"),
-            Pair("Dementia", "dementia"),
-            Pair(" Policía", "policia"),
-            Pair("Castellano", "castellano"),
-            Pair("Historia paralela", "historia-paralela"),
-            Pair("Aenime", "aenime"),
-            Pair("Blu-ray", "blu-ray"),
-            Pair("Monogatari", "monogatari"),
+        )
+
+        val SORT = arrayOf(
+            Pair("Descendente", "desc"),
+            Pair("Ascendente", "asc"),
         )
     }
 }
diff --git a/src/es/pelisplushd/build.gradle b/src/es/pelisplushd/build.gradle
index edabfe2c..6da4424b 100644
--- a/src/es/pelisplushd/build.gradle
+++ b/src/es/pelisplushd/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'Pelisplushd'
     extClass = '.PelisplushdFactory'
-    extVersionCode = 59
+    extVersionCode = 60
 }
 
 apply from: "$rootDir/common.gradle"
diff --git a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplushd.kt b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplushd.kt
index 1ddaf869..2f26c25d 100644
--- a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplushd.kt
+++ b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplushd.kt
@@ -39,6 +39,8 @@ import uy.kohesive.injekt.api.get
 
 open class Pelisplushd(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
 
+    override val id: Long = 1400819034564144238L
+
     override val lang = "es"
 
     override val supportsLatest = false
diff --git a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/PelisplushdFactory.kt b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/PelisplushdFactory.kt
index 0a0d39a4..7f6d3707 100644
--- a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/PelisplushdFactory.kt
+++ b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/PelisplushdFactory.kt
@@ -7,6 +7,6 @@ class PelisplushdFactory : AnimeSourceFactory {
     override fun createSources(): List<AnimeSource> = listOf(
         Pelisplushd("PelisPlusHD", "https://pelisplushd.bz"),
         Pelisplusto("PelisPlusTo", "https://ww3.pelisplus.to"),
-        Pelisplusph("PelisPlusPh", "https://www.pelisplushd.ph"),
+        Pelisplusph("PelisPlusPh", "https://ww5.pelisplushd.pe"),
     )
 }
diff --git a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusph.kt b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusph.kt
index aaf7d33f..e724edba 100644
--- a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusph.kt
+++ b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusph.kt
@@ -16,6 +16,8 @@ import org.jsoup.nodes.Element
 
 class Pelisplusph(override val name: String, override val baseUrl: String) : Pelisplushd(name, baseUrl) {
 
+    override val id: Long = 4917265654298497443L
+
     override val supportsLatest = false
 
     companion object {
@@ -52,7 +54,7 @@ class Pelisplusph(override val name: String, override val baseUrl: String) : Pel
         anime.title = document.selectFirst(".info-content h1")!!.text()
         document.select(".info-content p").map { p ->
             if (p.select(".content-type").text().contains("Sinópsis:")) {
-                anime.description = p.select(".sinopsis")!!.text()
+                anime.description = p.select(".sinopsis").text()
             }
             if (p.select(".content-type").text().contains("Géneros:")) {
                 anime.genre = p.select(".content-type-a a").joinToString { it.text() }
@@ -60,6 +62,9 @@ class Pelisplusph(override val name: String, override val baseUrl: String) : Pel
             if (p.select(".content-type").text().contains("Reparto:")) {
                 anime.artist = p.select(".content-type ~ span").text().substringBefore(",")
             }
+            if (p.select(".content-type").text().contains("Actores:")) {
+                anime.artist = p.select(".content-type ~ span").text().substringBefore(",")
+            }
         }
         anime.status =
             if (document.location().contains("/serie/")) SAnime.UNKNOWN else SAnime.COMPLETED
diff --git a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusto.kt b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusto.kt
index 20aff832..76e685ee 100644
--- a/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusto.kt
+++ b/src/es/pelisplushd/src/eu/kanade/tachiyomi/animeextension/es/pelisplushd/Pelisplusto.kt
@@ -23,6 +23,8 @@ import uy.kohesive.injekt.injectLazy
 
 class Pelisplusto(override val name: String, override val baseUrl: String) : Pelisplushd(name, baseUrl) {
 
+    override val id: Long = 1705636111422561130L
+
     private val json: Json by injectLazy()
 
     override val supportsLatest = false