From 68e02edc1df6b7bb569ffcb13b74fe0d9a863cbb Mon Sep 17 00:00:00 2001 From: Claudemirovsky <63046606+Claudemirovsky@users.noreply.github.com> Date: Tue, 29 Aug 2023 09:06:28 -0300 Subject: [PATCH] fix(en/animeflix): Fix popular & latest animes page (#2094) --- src/en/animeflix/build.gradle | 10 +- .../animeextension/en/animeflix/AnimeFlix.kt | 214 ++++++++---------- 2 files changed, 104 insertions(+), 120 deletions(-) diff --git a/src/en/animeflix/build.gradle b/src/en/animeflix/build.gradle index 959011743..df7bf6e73 100644 --- a/src/en/animeflix/build.gradle +++ b/src/en/animeflix/build.gradle @@ -1,12 +1,14 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlinx-serialization' +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.serialization) +} ext { extName = 'AnimeFlix' pkgNameSuffix = 'en.animeflix' extClass = '.AnimeFlix' - extVersionCode = 5 + extVersionCode = 6 libVersion = '13' } diff --git a/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt b/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt index b2b752af1..a8ba4a106 100644 --- a/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt +++ b/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.animeextension.en.animeflix import android.app.Application -import android.content.SharedPreferences import android.util.Base64 import androidx.preference.ListPreference import androidx.preference.PreferenceScreen @@ -45,26 +44,27 @@ class AnimeFlix : ConfigurableAnimeSource, ParsedAnimeHttpSource() { private val json: Json by injectLazy() - private val preferences: SharedPreferences by lazy { + private val preferences by lazy { Injekt.get().getSharedPreferences("source_$id", 0x0000) } // ============================== Popular =============================== + override fun popularAnimeRequest(page: Int) = GET("$baseUrl/page/$page/") - override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/page/$page/") + override fun popularAnimeSelector() = "div#content_box > div.post-cards > article" - override fun popularAnimeSelector(): String = "div#page > div#content_box > article" - - override fun popularAnimeFromElement(element: Element): SAnime = SAnime.create().apply { + override fun popularAnimeFromElement(element: Element) = SAnime.create().apply { setUrlWithoutDomain(element.selectFirst("a")!!.attr("href")) - thumbnail_url = element.selectFirst("img")!!.attr("src") + // prevent base64 images + thumbnail_url = element.selectFirst("img")!!.run { + attr("data-pagespeed-high-res-src").ifEmpty { attr("src") } + } title = element.selectFirst("header")!!.text() } - override fun popularAnimeNextPageSelector(): String = "div.nav-links > span.current ~ a" + override fun popularAnimeNextPageSelector() = "div.nav-links > a.next" // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/latest-release/page/$page/") override fun latestUpdatesSelector(): String = popularAnimeSelector() @@ -74,7 +74,6 @@ class AnimeFlix : ConfigurableAnimeSource, ParsedAnimeHttpSource() { override fun latestUpdatesNextPageSelector(): String = popularAnimeNextPageSelector() // =============================== Search =============================== - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { val cleanQuery = query.replace(" ", "+").lowercase() @@ -97,7 +96,6 @@ class AnimeFlix : ConfigurableAnimeSource, ParsedAnimeHttpSource() { override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector() // ============================== Filters =============================== - override fun getFilterList(): AnimeFilterList = AnimeFilterList( AnimeFilter.Header("Text search ignores filters"), GenreFilter(), @@ -141,133 +139,122 @@ class AnimeFlix : ConfigurableAnimeSource, ParsedAnimeHttpSource() { } // =========================== Anime Details ============================ + override fun animeDetailsParse(document: Document) = SAnime.create().apply { + title = document.selectFirst("div.single_post > header > h1")!!.text() + thumbnail_url = document.selectFirst("img.imdbwp__img")?.attr("src") - override fun animeDetailsParse(document: Document): SAnime { - val animeInfo = document.select("div.thecontent h3:contains(Anime Info) ~ ul li").joinToString("\n") { it.text() } - - return SAnime.create().apply { - title = document.selectFirst("div.single_post > header > h1")!!.text() - description = document.select("div.thecontent h3:contains(Summary) ~ p:not(:has(*)):not(:empty)").joinToString("\n\n") { it.ownText() } + "\n\n$animeInfo" + val infosDiv = document.selectFirst("div.thecontent h3:contains(Anime Info) ~ ul")!! + status = when (infosDiv.getInfo("Status").toString()) { + "Completed" -> SAnime.COMPLETED + "Currently Airing" -> SAnime.ONGOING + else -> SAnime.UNKNOWN } + artist = infosDiv.getInfo("Studios") + author = infosDiv.getInfo("Producers") + genre = infosDiv.getInfo("Genres") + val animeInfo = infosDiv.select("li").joinToString("\n") { it.text() } + description = document.select("div.thecontent h3:contains(Summary) ~ p:not(:has(*)):not(:empty)") + .joinToString("\n\n") { it.ownText() } + "\n\n$animeInfo" } + private fun Element.getInfo(info: String) = + selectFirst("li:contains($info)")?.ownText()?.trim() + // ============================== Episodes ============================== + val seasonRegex by lazy { Regex("""season (\d+)""", RegexOption.IGNORE_CASE) } + val qualityRegex by lazy { """(\d+)p""".toRegex() } override fun fetchEpisodeList(anime: SAnime): Observable> { - val document = client.newCall(GET(baseUrl + anime.url)).execute().asJsoup() - val episodeList = mutableListOf() - val serversList = mutableListOf>() - val seasonRegex = Regex("""season (\d+)""", RegexOption.IGNORE_CASE) - val qualityRegex = """(\d+)p""".toRegex() - val driveList = mutableListOf>() + val document = client.newCall(GET(baseUrl + anime.url)).execute() + .use { it.asJsoup() } val seasonList = document.select("div.inline > h3:contains(Season),div.thecontent > h3:contains(Season)") - if (seasonList.distinctBy { seasonRegex.find(it.text())!!.groupValues[1] }.size > 1) { + val episodeList = if (seasonList.distinctBy { seasonRegex.find(it.text())!!.groupValues[1] }.size > 1) { val seasonsLinks = document.select("div.thecontent p:has(span:contains(Gdrive))").groupBy { seasonRegex.find(it.previousElementSibling()!!.text())!!.groupValues[1] - }.values.toList() - seasonsLinks.forEach { season -> + } - val serverListSeason = mutableListOf>() - - season.forEach { - val quality = qualityRegex.find(it.previousElementSibling()!!.text())?.groupValues?.get(1) ?: "Unknown quality" - val seasonNumber = seasonRegex.find(it.previousElementSibling()!!.text())!!.groupValues[1] + seasonsLinks.flatMap { (seasonNumber, season) -> + val serverListSeason = season.map { + val previousText = it.previousElementSibling()!!.text() + val quality = qualityRegex.find(previousText)?.groupValues?.get(1) ?: "Unknown quality" val url = it.selectFirst("a")!!.attr("href") - val episodesDocument = client.newCall(GET(url)).execute().asJsoup() - serverListSeason.add( - episodesDocument.select("div.entry-content > h3 > a").map { - EpUrl(quality, it.attr("href"), "Season $seasonNumber ${it.text()}") - }, - ) + val episodesDocument = client.newCall(GET(url)).execute() + .use { it.asJsoup() } + episodesDocument.select("div.entry-content > h3 > a").map { + EpUrl(quality, it.attr("href"), "Season $seasonNumber ${it.text()}") + } } - transpose(serverListSeason).forEachIndexed { index, serverList -> - episodeList.add( - SEpisode.create().apply { - name = serverList.first().name - episode_number = (index + 1).toFloat() - setUrlWithoutDomain( - json.encodeToString(serverList), - ) - }, - ) - } + transposeEpisodes(serverListSeason) } } else { - document.select("div.thecontent p:has(span:contains(Gdrive))").forEach { + val driveList = document.select("div.thecontent p:has(span:contains(Gdrive))").map { val quality = qualityRegex.find(it.previousElementSibling()!!.text())?.groupValues?.get(1) ?: "Unknown quality" - driveList.add(Pair(it.selectFirst("a")!!.attr("href"), quality)) + Pair(it.selectFirst("a")!!.attr("href"), quality) } // Load episodes - driveList.forEach { drive -> - val episodesDocument = client.newCall(GET(drive.first)).execute().asJsoup() - serversList.add( - episodesDocument.select("div.entry-content > h3 > a").map { - EpUrl(drive.second, it.attr("href"), it.text()) - }, - ) + val serversList = driveList.map { drive -> + val episodesDocument = client.newCall(GET(drive.first)).execute() + .use { it.asJsoup() } + episodesDocument.select("div.entry-content > h3 > a").map { + EpUrl(drive.second, it.attr("href"), it.text()) + } } - transpose(serversList).forEachIndexed { index, serverList -> - episodeList.add( - SEpisode.create().apply { - name = serverList.first().name - episode_number = (index + 1).toFloat() - setUrlWithoutDomain( - json.encodeToString(serverList), - ) - }, - ) - } + transposeEpisodes(serversList) } return Observable.just(episodeList.reversed()) } + private fun transposeEpisodes(serversList: List>) = + transpose(serversList).mapIndexed { index, serverList -> + SEpisode.create().apply { + name = serverList.first().name + episode_number = (index + 1).toFloat() + setUrlWithoutDomain(json.encodeToString(serverList)) + } + } + override fun episodeListSelector(): String = throw Exception("Not Used") override fun episodeFromElement(element: Element): SEpisode = throw Exception("Not Used") // ============================ Video Links ============================= - override fun fetchVideoList(episode: SEpisode): Observable> { - val videoList = mutableListOf