Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(src/pt): General refactorations + Purge AnimeTV #2458

Merged
merged 4 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.FormBody
import okhttp3.Request
Expand Down Expand Up @@ -43,49 +42,101 @@ class AniDong : ParsedAnimeHttpSource() {
}

// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET(baseUrl)

override fun popularAnimeSelector() = "article.top10_animes_item > a"

override fun popularAnimeFromElement(element: Element) = SAnime.create().apply {
setUrlWithoutDomain(element.attr("href"))
title = element.attr("title")
thumbnail_url = element.selectFirst("img")?.attr("src")
}

override fun popularAnimeNextPageSelector() = null
override fun popularAnimeRequest(page: Int) = GET(baseUrl)
override fun popularAnimeSelector() = "article.top10_animes_item > a"

// ============================== Episodes ==============================
override fun episodeFromElement(element: Element): SEpisode {
throw UnsupportedOperationException("Not used.")
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/lancamentos/page/$page/")

override fun latestUpdatesSelector() = "article.main_content_article > a"

override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element)

override fun latestUpdatesNextPageSelector() = "div.paginacao > a.next"

// =============================== Search ===============================
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
val id = query.removePrefix(PREFIX_SEARCH)
client.newCall(GET("$baseUrl/anime/$id"))
.asObservableSuccess()
.map(::searchAnimeByIdParse)
} else {
super.fetchSearchAnime(page, query, filters)
}
}

override fun episodeListSelector(): String {
throw UnsupportedOperationException("Not used.")
private fun searchAnimeByIdParse(response: Response): AnimesPage {
val details = animeDetailsParse(response.use { it.asJsoup() })
return AnimesPage(listOf(details), false)
}

override fun episodeListParse(response: Response): List<SEpisode> {
val doc = getRealDoc(response.asJsoup())
override fun getFilterList() = AniDongFilters.FILTER_LIST

private val nonce by lazy {
client.newCall(GET("$baseUrl/?js_global=1&ver=6.2.2")).execute()
.use { it.body.string() }
.substringAfter("search_nonce")
.substringAfter("'")
.substringBefore("'")
}

override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = AniDongFilters.getSearchParameters(filters)

val id = doc.selectFirst("link[rel=shortlink]")!!.attr("href").substringAfter("=")
val body = FormBody.Builder()
.add("action", "show_videos")
.add("anime_id", id)
.build()
.add("letra", "")
.add("action", "show_animes_ajax")
.add("nome", query)
.add("status", params.status)
.add("formato", params.format)
.add("search_nonce", nonce)
.add("paged", page.toString())
.apply {
params.genres.forEach { add("generos[]", it) }
}.build()

val res = client.newCall(POST("$baseUrl/api", headers = apiHeaders, body = body)).execute()
val data = json.decodeFromString<EpisodeListDto>(res.body.string())
return POST("$baseUrl/wp-admin/admin-ajax.php", headers = apiHeaders, body = body)
}

return buildList {
data.episodes.forEach { add(episodeFromObject(it, "Episódio")) }
data.movies.forEach { add(episodeFromObject(it, "Filme")) }
data.ovas.forEach { add(episodeFromObject(it, "OVA")) }
sortByDescending { it.episode_number }
override fun searchAnimeParse(response: Response): AnimesPage {
val searchData: SearchResultDto = response.use { it.body.string() }
.takeIf { it.trim() != "402" }
?.let(json::decodeFromString)
?: return AnimesPage(emptyList(), false)

val animes = searchData.animes.map {
SAnime.create().apply {
setUrlWithoutDomain(it.url)
title = it.title
thumbnail_url = it.thumbnail_url
}
}

val hasNextPage = searchData.pages > 1 && searchData.animes.size == 10

return AnimesPage(animes, hasNextPage)
}

private fun episodeFromObject(episode: EpisodeDto, prefix: String) = SEpisode.create().apply {
setUrlWithoutDomain(episode.epi_url)
episode_number = episode.epi_num.toFloatOrNull() ?: 0F
name = "$prefix ${episode.epi_num}"
override fun searchAnimeSelector(): String {
throw UnsupportedOperationException("Not used.")
}

override fun searchAnimeFromElement(element: Element): SAnime {
throw UnsupportedOperationException("Not used.")
}

override fun searchAnimeNextPageSelector(): String? {
throw UnsupportedOperationException("Not used.")
}

// =========================== Anime Details ============================
Expand All @@ -95,9 +146,9 @@ class AniDong : ParsedAnimeHttpSource() {

setUrlWithoutDomain(doc.location())
title = infos.selectFirst("div > h3")!!.ownText()
thumbnail_url = infos.selectFirst("img")!!.attr("src")
thumbnail_url = infos.selectFirst("img")?.attr("src")
genre = infos.select("div[itemprop=genre] a").eachText().joinToString()
artist = infos.selectFirst("div[itemprop=productionCompany]")!!.text()
artist = infos.selectFirst("div[itemprop=productionCompany]")?.text()

status = doc.selectFirst("div:contains(Status) span")?.text().let {
when {
Expand All @@ -109,19 +160,55 @@ class AniDong : ParsedAnimeHttpSource() {
}

description = buildString {
infos.selectFirst("div.anime_name + div.anime_info")?.text()?.let {
infos.selectFirst("div.anime_name + div.anime_info")?.text()?.also {
append("Nomes alternativos: $it\n")
}

doc.selectFirst("div[itemprop=description]")?.text()?.let {
doc.selectFirst("div[itemprop=description]")?.text()?.also {
append("\n$it")
}
}
}

// ============================== Episodes ==============================
override fun episodeListSelector(): String {
throw UnsupportedOperationException("Not used.")
}

override fun episodeFromElement(element: Element): SEpisode {
throw UnsupportedOperationException("Not used.")
}

override fun episodeListParse(response: Response): List<SEpisode> {
val doc = getRealDoc(response.use { it.asJsoup() })

val id = doc.selectFirst("link[rel=shortlink]")!!.attr("href").substringAfter("=")
val body = FormBody.Builder()
.add("action", "show_videos")
.add("anime_id", id)
.build()

val res = client.newCall(POST("$baseUrl/api", apiHeaders, body)).execute()
.use { it.body.string() }
val data = json.decodeFromString<EpisodeListDto>(res)

return buildList {
data.episodes.forEach { add(episodeFromObject(it, "Episódio")) }
data.movies.forEach { add(episodeFromObject(it, "Filme")) }
data.ovas.forEach { add(episodeFromObject(it, "OVA")) }
sortByDescending { it.episode_number }
}
}

private fun episodeFromObject(episode: EpisodeDto, prefix: String) = SEpisode.create().apply {
setUrlWithoutDomain(episode.epi_url)
episode_number = episode.epi_num.toFloatOrNull() ?: 0F
name = "$prefix ${episode.epi_num}"
}

// ============================ Video Links =============================
override fun videoListParse(response: Response): List<Video> {
val doc = response.asJsoup()
val doc = response.use { it.asJsoup() }
return doc.select("div.player_option").flatMap {
val url = it.attr("data-playerlink")
val playerName = it.text().trim()
Expand Down Expand Up @@ -158,97 +245,13 @@ class AniDong : ParsedAnimeHttpSource() {
throw UnsupportedOperationException("Not used.")
}

// =============================== Search ===============================
override fun searchAnimeFromElement(element: Element): SAnime {
throw UnsupportedOperationException("Not used.")
}

override fun searchAnimeNextPageSelector(): String? {
throw UnsupportedOperationException("Not used.")
}

override fun searchAnimeParse(response: Response): AnimesPage {
val searchData: SearchResultDto = response.use { it.body.string() }
.takeIf { it.trim() != "402" }
?.let(json::decodeFromString)
?: return AnimesPage(emptyList<SAnime>(), false)

val animes = searchData.animes.map {
SAnime.create().apply {
setUrlWithoutDomain(it.url)
title = it.title
thumbnail_url = it.thumbnail_url
}
}

val hasNextPage = searchData.pages > 1 && searchData.animes.size == 10

return AnimesPage(animes, hasNextPage)
}

override fun getFilterList() = AniDongFilters.FILTER_LIST

private val nonce by lazy {
client.newCall(GET("$baseUrl/?js_global=1&ver=6.2.2")).execute()
.use { it.body.string() }
.substringAfter("search_nonce")
.substringAfter("'")
.substringBefore("'")
}

override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = AniDongFilters.getSearchParameters(filters)

val body = FormBody.Builder()
.add("letra", "")
.add("action", "show_animes_ajax")
.add("nome", query)
.add("status", params.status)
.add("formato", params.format)
.add("search_nonce", nonce)
.add("paged", page.toString())
.apply {
params.genres.forEach { add("generos[]", it) }
}.build()

return POST("$baseUrl/wp-admin/admin-ajax.php", headers = apiHeaders, body = body)
}

override fun searchAnimeSelector(): String {
throw UnsupportedOperationException("Not used.")
}

override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
val id = query.removePrefix(PREFIX_SEARCH)
client.newCall(GET("$baseUrl/anime/$id"))
.asObservableSuccess()
.map(::searchAnimeByIdParse)
} else {
super.fetchSearchAnime(page, query, filters)
}
}

private fun searchAnimeByIdParse(response: Response): AnimesPage {
val details = animeDetailsParse(response.asJsoup())
return AnimesPage(listOf(details), false)
}

// =============================== Latest ===============================
override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element)

override fun latestUpdatesNextPageSelector() = "div.paginacao > a.next"

override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/lancamentos/page/$page/")

override fun latestUpdatesSelector() = "article.main_content_article > a"

// ============================= Utilities ==============================
private fun getRealDoc(document: Document): Document {
if (!document.location().contains("/video/")) return document

return document.selectFirst(".episodioControleItem:has(i.ri-grid-fill)")?.let {
client.newCall(GET(it.attr("href"), headers)).execute().asJsoup()
client.newCall(GET(it.attr("href"), headers)).execute()
.use { req -> req.asJsoup() }
} ?: document
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ object AniDongFilters {
options: Array<Pair<String, String>>,
): List<String> {
return (getFirst<R>() as CheckBoxFilterList).state
.asSequence()
.filter { it.state }
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
.filter(String::isNotBlank)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList

object AFFilters {

open class QueryPartFilter(
displayName: String,
val vals: Array<Pair<String, String>>,
Expand All @@ -16,9 +15,7 @@ object AFFilters {
}

private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
return first { it is R }.let {
(it as QueryPartFilter).toQueryPart()
}
return (first { it is R } as QueryPartFilter).toQueryPart()
}

class GenreFilter : QueryPartFilter("Gênero", AFFiltersData.GENRES)
Expand Down
Loading