From dd53ca23bb190d0797a1fe2ba8cdca1c35a16c7c Mon Sep 17 00:00:00 2001 From: imper1aldev <23511335+imper1aldev@users.noreply.github.com> Date: Mon, 2 Sep 2024 02:33:43 -0600 Subject: [PATCH] fix(src/es): Change domain for DoramasYT Closes #181 --- src/es/doramasyt/build.gradle | 7 +- .../animeextension/es/doramasyt/Doramasyt.kt | 410 +++++++++--------- .../es/doramasyt/DoramasytDto.kt | 29 ++ .../es/doramasyt/DoramasytFilters.kt | 117 +++++ .../extractors/SolidFilesExtractor.kt | 27 -- 5 files changed, 349 insertions(+), 241 deletions(-) create mode 100644 src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/DoramasytDto.kt create mode 100644 src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/DoramasytFilters.kt delete mode 100644 src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/extractors/SolidFilesExtractor.kt diff --git a/src/es/doramasyt/build.gradle b/src/es/doramasyt/build.gradle index 5423041d..f73ca3a5 100644 --- a/src/es/doramasyt/build.gradle +++ b/src/es/doramasyt/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Doramasyt' extClass = '.Doramasyt' - extVersionCode = 13 + extVersionCode = 14 } apply from: "$rootDir/common.gradle" @@ -10,4 +10,9 @@ dependencies { implementation(project(':lib:uqload-extractor')) implementation(project(':lib:streamtape-extractor')) implementation(project(':lib:okru-extractor')) + implementation(project(':lib:voe-extractor')) + implementation(project(':lib:filemoon-extractor')) + implementation(project(':lib:streamwish-extractor')) + implementation(project(':lib:dood-extractor')) + implementation(project(':lib:mixdrop-extractor')) } diff --git a/src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/Doramasyt.kt b/src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/Doramasyt.kt index d3774bc6..762c2f86 100644 --- a/src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/Doramasyt.kt +++ b/src/es/doramasyt/src/eu/kanade/tachiyomi/animeextension/es/doramasyt/Doramasyt.kt @@ -2,34 +2,41 @@ package eu.kanade.tachiyomi.animeextension.es.doramasyt import android.app.Application import android.content.SharedPreferences -import android.util.Log +import android.util.Base64 import androidx.preference.ListPreference import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.SolidFilesExtractor import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource -import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilterList +import eu.kanade.tachiyomi.animesource.model.AnimesPage import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SEpisode import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource +import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource +import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor +import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor +import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor +import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor +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 -import org.jsoup.nodes.Document import org.jsoup.nodes.Element import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.math.ceil -class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() { +class Doramasyt : ConfigurableAnimeSource, AnimeHttpSource() { override val name = "Doramasyt" - override val baseUrl = "https://doramasyt.com" + override val baseUrl = "https://www.doramasyt.com" override val lang = "es" @@ -39,241 +46,203 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() { Injekt.get().getSharedPreferences("source_$id", 0x0000) } - override fun popularAnimeSelector(): String = "div.col-lg-2.col-md-4.col-6 div.animes" + companion object { + private const val PREF_QUALITY_KEY = "preferred_quality" + private const val PREF_QUALITY_DEFAULT = "1080" + private val QUALITY_LIST = arrayOf("1080", "720", "480", "360") - override fun popularAnimeRequest(page: Int): Request = GET("https://doramasyt.com/doramas/?p=$page") - - override fun popularAnimeFromElement(element: Element): SAnime { - val anime = SAnime.create() - anime.setUrlWithoutDomain( - element.select("div.anithumb a").attr("href"), + private const val PREF_SERVER_KEY = "preferred_server" + private const val PREF_SERVER_DEFAULT = "Filemoon" + private val SERVER_LIST = arrayOf( + "Voe", + "StreamWish", + "Okru", + "Upload", + "FileLions", + "Filemoon", + "DoodStream", + "MixDrop", + "Streamtape", ) - anime.title = element.select("div.animedtls p").text() - anime.thumbnail_url = element.select(" div.anithumb a img").attr("src") - anime.description = element.select("div.animedtls p").text() - return anime } - override fun popularAnimeNextPageSelector(): String = "ul.pagination li:last-child a" + override fun animeDetailsParse(response: Response): SAnime { + val document = response.asJsoup() + val animeDetails = SAnime.create().apply { + title = document.selectFirst(".flex-column h1.text-capitalize")?.text() ?: "" + description = document.selectFirst(".h-100 .mb-3 p")?.text() + genre = document.select(".lh-lg span").joinToString { it.text() } + thumbnail_url = document.selectFirst(".gap-3 img")?.getImageUrl() + 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 + else -> SAnime.UNKNOWN + } + } + } + return animeDetails + } + + override fun popularAnimeRequest(page: Int) = GET("$baseUrl/doramas?p=$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 animeList = elements.map { element -> + SAnime.create().apply { + title = element.selectFirst(".title_cap")!!.text() + thumbnail_url = element.selectFirst("img")?.getImageUrl() + setUrlWithoutDomain(element.attr("abs:href")) + } + } + return AnimesPage(animeList, nextPage) + } + + override fun latestUpdatesParse(response: Response) = popularAnimeParse(response) + + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/emision?p=$page", headers) + + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { + val params = DoramasytFilters.getSearchParameters(filters) + return when { + query.isNotBlank() -> GET("$baseUrl/buscar?q=$query", headers) + params.filter.isNotBlank() -> GET("$baseUrl/doramas${params.getQuery()}&p=$page", headers) + else -> popularAnimeRequest(page) + } + } + + override fun searchAnimeParse(response: Response) = popularAnimeParse(response) override fun episodeListParse(response: Response): List { - return super.episodeListParse(response).reversed() + 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 detail = getEpisodeDetails(capListLink, token, referer) + val total = detail.eps.size + val perPage = detail.perpage ?: return emptyList() + val pages = (total / perPage).ceilPage() + + 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() } - override fun episodeListSelector(): String = "div.mainrowdiv.pagesdiv div.jpage div.col-item" + private fun getEpisodeDetails(capListLink: String, token: String, referer: String): EpisodesDto { + val formBody = FormBody.Builder().add("_token", token).build() + val request = Request.Builder() + .url(capListLink) + .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() - override fun episodeFromElement(element: Element): SEpisode { - val episode = SEpisode.create() - val epNum = getNumberFromEpsString(element.select("a div.flimss div.dtlsflim p").text()) - Log.i("bruh ep", element.select("a").attr("href")) - val formatedEp = when { - epNum.isNotEmpty() -> epNum.toFloatOrNull() ?: 1F - else -> 1F - } - episode.setUrlWithoutDomain(element.select("a").attr("href")) - episode.episode_number = formatedEp - episode.name = "Episodio $formatedEp" - - return episode + return client.newCall(request).execute().parseAs() } - private fun getNumberFromEpsString(epsStr: String): String { - return epsStr.filter { it.isDigit() } + 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() } override fun videoListParse(response: Response): List