fix(fr/franime): Fix internal anime list (#2214)
This commit is contained in:
@ -8,7 +8,7 @@ ext {
|
|||||||
extName = 'FrAnime'
|
extName = 'FrAnime'
|
||||||
pkgNameSuffix = 'fr.franime'
|
pkgNameSuffix = 'fr.franime'
|
||||||
extClass = '.FrAnime'
|
extClass = '.FrAnime'
|
||||||
extVersionCode = 7
|
extVersionCode = 8
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
@ -37,48 +37,83 @@ class FrAnime : AnimeHttpSource() {
|
|||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
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 json: Json by injectLazy()
|
||||||
|
|
||||||
private val database by lazy {
|
private val database by lazy {
|
||||||
client.newCall(GET("$baseApiUrl/animes/")).execute()
|
client.newCall(GET("$baseApiUrl/animes/", headers)).execute()
|
||||||
.use { it.body.string() }
|
.use { it.body.string() }
|
||||||
.let { json.decodeFromString<Array<Anime>>(it) }
|
.let { json.decodeFromString<List<Anime>>(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<AnimesPage> {
|
||||||
|
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<SAnime> = Observable.just(anime)
|
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> = Observable.just(anime)
|
||||||
|
|
||||||
override fun animeDetailsParse(response: Response): SAnime = throw Exception("not used")
|
override fun animeDetailsParse(response: Response): SAnime = throw Exception("not used")
|
||||||
|
|
||||||
// === Episodes
|
// ============================== Episodes ==============================
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
||||||
val url = (baseUrl + anime.url).toHttpUrl()
|
val url = (baseUrl + anime.url).toHttpUrl()
|
||||||
val stem = url.encodedPathSegments.last()
|
val stem = url.encodedPathSegments.last()
|
||||||
val language = url.queryParameter("lang") ?: "vo"
|
val language = url.queryParameter("lang") ?: "vo"
|
||||||
val season = url.queryParameter("s")?.toIntOrNull() ?: 1
|
val season = url.queryParameter("s")?.toIntOrNull() ?: 1
|
||||||
val animeData = database.first { titleToUrl(it.originalTitle) == stem }
|
val animeData = database.first { titleToUrl(it.originalTitle) == stem }
|
||||||
val episodes = mutableListOf<SEpisode>()
|
val episodes = animeData.seasons[season - 1].episodes
|
||||||
animeData.seasons[season - 1].episodes.forEachIndexed { index, episode ->
|
.mapIndexedNotNull { index, episode ->
|
||||||
val players = (if (language == "vo") episode.languages.vo else episode.languages.vf).players
|
val players = when (language) {
|
||||||
if (players.isNotEmpty()) {
|
"vo" -> episode.languages.vo
|
||||||
episodes += SEpisode.create().apply {
|
else -> episode.languages.vf
|
||||||
|
}.players
|
||||||
|
|
||||||
|
if (players.isEmpty()) return@mapIndexedNotNull null
|
||||||
|
|
||||||
|
SEpisode.create().apply {
|
||||||
setUrlWithoutDomain(anime.url + "&ep=${index + 1}")
|
setUrlWithoutDomain(anime.url + "&ep=${index + 1}")
|
||||||
name = episode.title
|
name = episode.title
|
||||||
episode_number = index.toFloat()
|
episode_number = (index + 1).toFloat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Observable.just(episodes.sortedByDescending { it.episode_number })
|
return Observable.just(episodes.sortedByDescending { it.episode_number })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> = throw Exception("not used")
|
override fun episodeListParse(response: Response): List<SEpisode> = throw Exception("not used")
|
||||||
|
|
||||||
// === Players
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
||||||
val url = (baseUrl + episode.url).toHttpUrl()
|
val url = (baseUrl + episode.url).toHttpUrl()
|
||||||
val seasonNumber = url.queryParameter("s")?.toIntOrNull() ?: 1
|
val seasonNumber = url.queryParameter("s")?.toIntOrNull() ?: 1
|
||||||
@ -106,63 +141,23 @@ class FrAnime : AnimeHttpSource() {
|
|||||||
return Observable.just(videos)
|
return Observable.just(videos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Latest
|
// ============================= Utilities ==============================
|
||||||
|
private fun pagesToAnimesPage(pages: List<Anime>, page: Int): Observable<AnimesPage> {
|
||||||
override fun fetchLatestUpdates(page: Int): Observable<AnimesPage> {
|
val chunks = pages.chunked(50)
|
||||||
val pages = database.reversed().toList().chunked(50)
|
val hasNextPage = chunks.size > page
|
||||||
val hasNextPage = pages.size > page
|
val entries = pageToSAnimes(chunks.getOrNull(page - 1) ?: emptyList())
|
||||||
val entries = pageToSAnimes(pages.getOrNull(page - 1))
|
|
||||||
return Observable.just(AnimesPage(entries, hasNextPage))
|
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")
|
private fun pageToSAnimes(page: List<Anime>): List<SAnime> {
|
||||||
|
return page.flatMap { anime ->
|
||||||
// === Popular
|
anime.seasons.flatMapIndexed { index, season ->
|
||||||
|
val seasonTitle = anime.title + if (anime.seasons.size > 1) " S${index + 1}" else ""
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> {
|
val hasVostfr = season.episodes.any { ep -> ep.languages.vo.players.isNotEmpty() }
|
||||||
val pages = database.sortedByDescending { it.note }.chunked(50)
|
val hasVf = season.episodes.any { ep -> ep.languages.vf.players.isNotEmpty() }
|
||||||
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<AnimesPage> {
|
|
||||||
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<Anime>?): List<SAnime> {
|
|
||||||
val entries = mutableListOf<SAnime>()
|
|
||||||
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() }
|
|
||||||
|
|
||||||
// I want to die for writing this
|
// I want to die for writing this
|
||||||
val languages = listOfNotNull(
|
val languages = listOfNotNull(
|
||||||
@ -170,20 +165,19 @@ class FrAnime : AnimeHttpSource() {
|
|||||||
if (hasVf) Triple("VF", "vf", hasVostfr) else null,
|
if (hasVf) Triple("VF", "vf", hasVostfr) else null,
|
||||||
)
|
)
|
||||||
|
|
||||||
languages.forEach { lang ->
|
languages.map { lang ->
|
||||||
entries += SAnime.create().apply {
|
SAnime.create().apply {
|
||||||
title = seasonTitle + if (lang.third) " (${lang.first})" else ""
|
title = seasonTitle + if (lang.third) " (${lang.first})" else ""
|
||||||
thumbnail_url = it.poster
|
thumbnail_url = anime.poster
|
||||||
genre = it.genres.joinToString()
|
genre = anime.genres.joinToString()
|
||||||
status = parseStatus(it.status, it.seasons.size, index + 1)
|
status = parseStatus(anime.status, anime.seasons.size, index + 1)
|
||||||
description = it.description
|
description = anime.description
|
||||||
setUrlWithoutDomain("/anime/${titleToUrl(it.originalTitle)}?lang=${lang.second}&s=${index + 1}")
|
setUrlWithoutDomain("/anime/${titleToUrl(anime.originalTitle)}?lang=${lang.second}&s=${index + 1}")
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entries
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStatus(statusString: String?, seasonCount: Int = 1, season: Int = 1): Int {
|
private fun parseStatus(statusString: String?, seasonCount: Int = 1, season: Int = 1): Int {
|
||||||
|
Reference in New Issue
Block a user