Update animevost source (#970)

* fix(animevost): video link parser

animevost.org removes download buttons for some European regions

* feat(animevost): add mirror for animevost.org

* feat(animevost): add filters by genre and sorting

* fix(animevost): fix episodes direction

* fix typo

* fix(animevost): fix description; add additional information

* Mass-bump on extensions

* update animevost source

* Revert "Mass-bump on extensions"

This reverts commit 68799e86d0.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Vitalij Nykyforenko
2022-10-23 12:58:03 -04:00
committed by GitHub
parent 2ad1c30263
commit 086b777ba0
4 changed files with 49 additions and 108 deletions

View File

@ -1,12 +1,11 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext { ext {
extName = 'Animevost' extName = 'Animevost'
pkgNameSuffix = 'ru.animevost' pkgNameSuffix = 'ru.animevost'
extClass = '.Animevost' extClass = '.Animevost'
extVersionCode = 6 extVersionCode = 7
libVersion = '13' libVersion = '13'
} }

View File

@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.animesource.AnimeSourceFactory
class Animevost : AnimeSourceFactory { class Animevost : AnimeSourceFactory {
override fun createSources(): List<AnimeSource> = listOf<AnimeSource>( override fun createSources(): List<AnimeSource> = listOf<AnimeSource>(
AnimevostSource("Animevost", "https://animevost.org", "https://api.animevost.org"), AnimevostSource("Animevost", "https://animevost.org"),
AnimevostSource("Animevost Mirror", "https://v2.vost.pw", "https://api.animevost.org") AnimevostSource("Animevost Mirror", "https://v2.vost.pw")
) )
} }

View File

@ -4,8 +4,6 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.ru.animevost.dto.AnimeDetailsDto
import eu.kanade.tachiyomi.animeextension.ru.animevost.dto.Data
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -13,12 +11,8 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
@ -26,13 +20,19 @@ import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.lang.Exception import java.lang.Exception
import kotlin.math.roundToInt
class AnimevostSource(override val name: String, override val baseUrl: String, private val baseApiUrl: String) : data class AnimeDescription(
val year: String? = null,
val type: String? = null,
val rating: Int? = null,
val votes: Int? = null,
val description: String? = null,
)
class AnimevostSource(override val name: String, override val baseUrl: String) :
ConfigurableAnimeSource, ParsedAnimeHttpSource() { ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private enum class SortBy(val by: String) { private enum class SortBy(val by: String) {
RATING("rating"), RATING("rating"),
@ -47,11 +47,6 @@ class AnimevostSource(override val name: String, override val baseUrl: String, p
DESC("desc"), DESC("desc"),
} }
private val json = Json {
isLenient = true
ignoreUnknownKeys = true
}
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
@ -97,43 +92,37 @@ class AnimevostSource(override val name: String, override val baseUrl: String, p
return POST(url.toString(), headers, body.build()) return POST(url.toString(), headers, body.build())
} }
private fun parseAnimeIdFromUrl(url: String): String = url.split("/").last().split("-").first()
// Anime details // Anime details
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> { override fun animeDetailsParse(document: Document): SAnime {
val animeId = parseAnimeIdFromUrl(anime.url) val anime = SAnime.create()
return client.newCall(GET("$baseApiUrl/animevost/api/v0.2/GetInfo/$animeId")) val animeContent = document.select(".shortstory > .shortstoryContent td:first-of-type")
.asObservableSuccess() anime.thumbnail_url = "$baseUrl/${animeContent.select("img:first-of-type").attr("src")}"
.map { response -> anime.genre = animeContent.select("p:nth-of-type(2)").text().replace("Жанр: ", "")
animeDetailsParse(response).apply { initialized = true } anime.author = animeContent.select("p:nth-of-type(5) a").text()
} val description = animeContent.select("p:nth-of-type(6) > span").text()
}
override fun animeDetailsParse(response: Response): SAnime { val year = animeContent.select("p:nth-of-type(1)").text().replace("Год выхода: ", "")
val animeData = json.decodeFromString(AnimeDetailsDto.serializer(), response.body!!.string()).data?.first() val rating = animeContent.select(".current-rating").text().toInt()
val anime = SAnime.create().apply { val type = animeContent.select("p:nth-of-type(3)").text().replace("Тип: ", "")
title = animeData?.title!! val votes = animeContent.select("div:nth-of-type(2) span span").text().toInt()
if (animeData.preview != null) { anime.title = document.select(".shortstory > .shortstoryHead h1").text()
thumbnail_url = "$baseUrl/" + animeData.preview
}
author = animeData.director
description = formatDescription(animeData)
if (animeData.timer != null) {
status = if (animeData.timer > 0) SAnime.ONGOING else SAnime.COMPLETED
}
genre = animeData.genre
}
anime.description = formatDescription(
AnimeDescription(
year,
type,
rating,
votes,
description
)
)
return anime return anime
} }
private fun formatDescription(animeData: Data): String { private fun formatDescription(animeData: AnimeDescription): String {
var description = "" var description = ""
if (animeData.year != null) { if (animeData.year != null) {
@ -141,9 +130,9 @@ class AnimevostSource(override val name: String, override val baseUrl: String, p
} }
if (animeData.rating != null && animeData.votes != null) { if (animeData.rating != null && animeData.votes != null) {
val rating = (animeData.rating.toDouble() / animeData.votes.toDouble()).roundToInt() val rating = 5 * animeData.rating / 100
description += "Рейтинг: ${"★".repeat(rating)}${"☆".repeat((5 - rating).coerceAtLeast(0))} (Голосов: ${animeData.votes})\n" description += "Рейтинг: ${"★".repeat(rating)}${"☆".repeat(Math.max(5 - rating, 0))} (Голосов: ${animeData.votes})\n"
} }
if (animeData.type != null) { if (animeData.type != null) {
@ -159,38 +148,29 @@ class AnimevostSource(override val name: String, override val baseUrl: String, p
return description return description
} }
override fun animeDetailsParse(document: Document) = throw Exception("not used")
// Episode // Episode
override fun episodeFromElement(element: Element) = throw Exception("not used") override fun episodeFromElement(element: Element) = throw Exception("not used")
override fun episodeListSelector() = throw Exception("not used") override fun episodeListSelector() = throw Exception("not used")
override fun episodeListRequest(anime: SAnime): Request {
val animeId = parseAnimeIdFromUrl(anime.url)
return GET("$baseApiUrl/animevost/api/v0.2/GetInfo/$animeId")
}
override fun episodeListParse(response: Response): List<SEpisode> { override fun episodeListParse(response: Response): List<SEpisode> {
val animeData = json.decodeFromString(AnimeDetailsDto.serializer(), response.body!!.string()).data?.first() val animePage = response.asJsoup()
var episodeScript = animePage.select(".shortstoryContent > script:nth-of-type(2)").html()
episodeScript = episodeScript.substring(episodeScript.indexOf("var data = {") + 12)
val episodes = episodeScript.substring(0, episodeScript.indexOf(",};")).replace("\"", "").split(",")
val episodeList = mutableListOf<SEpisode>() val episodeList = mutableListOf<SEpisode>()
if (animeData?.series != null) { episodes.forEachIndexed { index, entry ->
val series = Json.parseToJsonElement(animeData.series.replace("'", "\"")).jsonObject.toMap() episodeList.add(
SEpisode.create().apply {
series.entries.forEachIndexed { index, entry -> val id = entry.split(":")[1]
episodeList.add( name = entry.split(":")[0]
SEpisode.create().apply { episode_number = index.toFloat()
val id = entry.value.toString().replace("\"", "") url = "/frame5.php?play=$id&old=1"
name = entry.key }
episode_number = index.toFloat() )
url = "/frame5.php?play=$id&old=1"
}
)
}
} }
return episodeList.reversed() return episodeList.reversed()

View File

@ -1,38 +0,0 @@
package eu.kanade.tachiyomi.animeextension.ru.animevost.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class AnimeDetailsDto(
@SerialName("data")
val data: List<Data>? = null,
)
@Serializable
data class Data(
@SerialName("description")
val description: String? = null,
@SerialName("director")
val director: String? = null,
@SerialName("urlImagePreview")
val preview: String? = null,
@SerialName("year")
val year: String? = null,
@SerialName("genre")
val genre: String? = null,
@SerialName("id")
val id: Int? = null,
@SerialName("timer")
val timer: Int? = null,
@SerialName("title")
val title: String? = null,
@SerialName("type")
val type: String? = null,
@SerialName("series")
val series: String? = null,
@SerialName("rating")
val rating: Int? = null,
@SerialName("votes")
val votes: Int? = null,
)