From 87212199613e02d92cdf99b5f46b98c501e88a1e Mon Sep 17 00:00:00 2001 From: Claudemirovsky <63046606+Claudemirovsky@users.noreply.github.com> Date: Tue, 19 Sep 2023 03:44:20 -0300 Subject: [PATCH] fix(fr/franime): Fix internal anime list (#2214) --- src/fr/franime/build.gradle | 2 +- .../animeextension/fr/franime/FrAnime.kt | 146 +++++++++--------- 2 files changed, 71 insertions(+), 77 deletions(-) diff --git a/src/fr/franime/build.gradle b/src/fr/franime/build.gradle index ff1416071..7528ec30e 100644 --- a/src/fr/franime/build.gradle +++ b/src/fr/franime/build.gradle @@ -8,7 +8,7 @@ ext { extName = 'FrAnime' pkgNameSuffix = 'fr.franime' extClass = '.FrAnime' - extVersionCode = 7 + extVersionCode = 8 libVersion = '13' containsNsfw = true } diff --git a/src/fr/franime/src/eu/kanade/tachiyomi/animeextension/fr/franime/FrAnime.kt b/src/fr/franime/src/eu/kanade/tachiyomi/animeextension/fr/franime/FrAnime.kt index 8a074a59e..98be16c11 100644 --- a/src/fr/franime/src/eu/kanade/tachiyomi/animeextension/fr/franime/FrAnime.kt +++ b/src/fr/franime/src/eu/kanade/tachiyomi/animeextension/fr/franime/FrAnime.kt @@ -37,48 +37,83 @@ class FrAnime : AnimeHttpSource() { override val client: OkHttpClient = network.cloudflareClient - override fun headersBuilder() = super.headersBuilder().add("Referer", "$baseUrl/") + override fun headersBuilder() = super.headersBuilder() + .add("Referer", "$baseUrl/") + .add("Origin", baseUrl) private val json: Json by injectLazy() private val database by lazy { - client.newCall(GET("$baseApiUrl/animes/")).execute() + client.newCall(GET("$baseApiUrl/animes/", headers)).execute() .use { it.body.string() } - .let { json.decodeFromString>(it) } + .let { json.decodeFromString>(it) } } - // === Anime Details + // ============================== Popular =============================== + override fun fetchPopularAnime(page: Int) = + pagesToAnimesPage(database.sortedByDescending { it.note }, page) + override fun popularAnimeParse(response: Response) = throw Exception("not used") + + override fun popularAnimeRequest(page: Int) = throw Exception("not used") + + // =============================== Latest =============================== + override fun fetchLatestUpdates(page: Int) = pagesToAnimesPage(database.reversed(), page) + + override fun latestUpdatesParse(response: Response): AnimesPage = throw Exception("not used") + + override fun latestUpdatesRequest(page: Int): Request = throw Exception("not used") + + // =============================== Search =============================== + override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable { + val pages = database.filter { + it.title.contains(query, true) || + it.originalTitle.contains(query, true) || + it.titlesAlt.en?.contains(query, true) == true || + it.titlesAlt.enJp?.contains(query, true) == true || + it.titlesAlt.jaJp?.contains(query, true) == true || + titleToUrl(it.originalTitle).contains(query) + } + return pagesToAnimesPage(pages, page) + } + + override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("not used") + + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("not used") + + // =========================== Anime Details ============================ override fun fetchAnimeDetails(anime: SAnime): Observable = Observable.just(anime) override fun animeDetailsParse(response: Response): SAnime = throw Exception("not used") - // === Episodes - + // ============================== Episodes ============================== override fun fetchEpisodeList(anime: SAnime): Observable> { val url = (baseUrl + anime.url).toHttpUrl() val stem = url.encodedPathSegments.last() val language = url.queryParameter("lang") ?: "vo" val season = url.queryParameter("s")?.toIntOrNull() ?: 1 val animeData = database.first { titleToUrl(it.originalTitle) == stem } - val episodes = mutableListOf() - animeData.seasons[season - 1].episodes.forEachIndexed { index, episode -> - val players = (if (language == "vo") episode.languages.vo else episode.languages.vf).players - if (players.isNotEmpty()) { - episodes += SEpisode.create().apply { + val episodes = animeData.seasons[season - 1].episodes + .mapIndexedNotNull { index, episode -> + val players = when (language) { + "vo" -> episode.languages.vo + else -> episode.languages.vf + }.players + + if (players.isEmpty()) return@mapIndexedNotNull null + + SEpisode.create().apply { setUrlWithoutDomain(anime.url + "&ep=${index + 1}") name = episode.title - episode_number = index.toFloat() + episode_number = (index + 1).toFloat() } } - } return Observable.just(episodes.sortedByDescending { it.episode_number }) } override fun episodeListParse(response: Response): List = throw Exception("not used") - // === Players - + // ============================ Video Links ============================= override fun fetchVideoList(episode: SEpisode): Observable> { val url = (baseUrl + episode.url).toHttpUrl() val seasonNumber = url.queryParameter("s")?.toIntOrNull() ?: 1 @@ -106,63 +141,23 @@ class FrAnime : AnimeHttpSource() { return Observable.just(videos) } - // === Latest - - override fun fetchLatestUpdates(page: Int): Observable { - val pages = database.reversed().toList().chunked(50) - val hasNextPage = pages.size > page - val entries = pageToSAnimes(pages.getOrNull(page - 1)) + // ============================= Utilities ============================== + private fun pagesToAnimesPage(pages: List, page: Int): Observable { + val chunks = pages.chunked(50) + val hasNextPage = chunks.size > page + val entries = pageToSAnimes(chunks.getOrNull(page - 1) ?: emptyList()) return Observable.just(AnimesPage(entries, hasNextPage)) } - override fun latestUpdatesParse(response: Response): AnimesPage = throw Exception("not used") + private val titleRegex by lazy { Regex("[^A-Za-z0-9 ]") } + private fun titleToUrl(title: String) = titleRegex.replace(title, "").replace(" ", "-").lowercase() - override fun latestUpdatesRequest(page: Int): Request = throw Exception("not used") - - // === Popular - - override fun fetchPopularAnime(page: Int): Observable { - val pages = database.sortedByDescending { it.note }.chunked(50) - val hasNextPage = pages.size > page - val entries = pageToSAnimes(pages.getOrNull(page - 1)) - return Observable.just(AnimesPage(entries, hasNextPage)) - } - - override fun popularAnimeParse(response: Response) = throw Exception("not used") - - override fun popularAnimeRequest(page: Int) = throw Exception("not used") - - // === Search - - override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable { - val pages = database.filter { - it.title.contains(query, true) || - it.originalTitle.contains(query, true) || - it.titlesAlt.en?.contains(query, true) == true || - it.titlesAlt.enJp?.contains(query, true) == true || - it.titlesAlt.jaJp?.contains(query, true) == true || - titleToUrl(it.originalTitle).contains(query) - }.chunked(50) - val hasNextPage = pages.size > page - val entries = pageToSAnimes(pages.getOrNull(page - 1)) - return Observable.just(AnimesPage(entries, hasNextPage)) - } - - override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("not used") - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("not used") - - // === Utils - - private fun titleToUrl(title: String): String = Regex("[^A-Za-z0-9 ]").replace(title, "").replace(" ", "-").lowercase() - - private fun pageToSAnimes(page: List?): List { - val entries = mutableListOf() - page?.forEach { - for ((index, season) in it.seasons.withIndex()) { - val seasonTitle = it.title + if (it.seasons.size > 1) " S${index + 1}" else "" - val hasVostfr = season.episodes.fold(false) { v, e -> v or e.languages.vo.players.isNotEmpty() } - val hasVf = season.episodes.fold(false) { v, e -> v or e.languages.vf.players.isNotEmpty() } + private fun pageToSAnimes(page: List): List { + return page.flatMap { anime -> + anime.seasons.flatMapIndexed { index, season -> + val seasonTitle = anime.title + if (anime.seasons.size > 1) " S${index + 1}" else "" + val hasVostfr = season.episodes.any { ep -> ep.languages.vo.players.isNotEmpty() } + val hasVf = season.episodes.any { ep -> ep.languages.vf.players.isNotEmpty() } // I want to die for writing this val languages = listOfNotNull( @@ -170,20 +165,19 @@ class FrAnime : AnimeHttpSource() { if (hasVf) Triple("VF", "vf", hasVostfr) else null, ) - languages.forEach { lang -> - entries += SAnime.create().apply { + languages.map { lang -> + SAnime.create().apply { title = seasonTitle + if (lang.third) " (${lang.first})" else "" - thumbnail_url = it.poster - genre = it.genres.joinToString() - status = parseStatus(it.status, it.seasons.size, index + 1) - description = it.description - setUrlWithoutDomain("/anime/${titleToUrl(it.originalTitle)}?lang=${lang.second}&s=${index + 1}") + thumbnail_url = anime.poster + genre = anime.genres.joinToString() + status = parseStatus(anime.status, anime.seasons.size, index + 1) + description = anime.description + setUrlWithoutDomain("/anime/${titleToUrl(anime.originalTitle)}?lang=${lang.second}&s=${index + 1}") initialized = true } } } } - return entries } private fun parseStatus(statusString: String?, seasonCount: Int = 1, season: Int = 1): Int {