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: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Animevost'
pkgNameSuffix = 'ru.animevost'
extClass = '.Animevost'
extVersionCode = 6
extVersionCode = 7
libVersion = '13'
}

View File

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

View File

@ -4,8 +4,6 @@ import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
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.model.AnimeFilter
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.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
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.json.Json
import kotlinx.serialization.json.jsonObject
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
@ -26,13 +20,19 @@ import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
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() {
private enum class SortBy(val by: String) {
RATING("rating"),
@ -47,11 +47,6 @@ class AnimevostSource(override val name: String, override val baseUrl: String, p
DESC("desc"),
}
private val json = Json {
isLenient = true
ignoreUnknownKeys = true
}
private val preferences: SharedPreferences by lazy {
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())
}
private fun parseAnimeIdFromUrl(url: String): String = url.split("/").last().split("-").first()
// Anime details
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
val animeId = parseAnimeIdFromUrl(anime.url)
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
return client.newCall(GET("$baseApiUrl/animevost/api/v0.2/GetInfo/$animeId"))
.asObservableSuccess()
.map { response ->
animeDetailsParse(response).apply { initialized = true }
}
}
val animeContent = document.select(".shortstory > .shortstoryContent td:first-of-type")
anime.thumbnail_url = "$baseUrl/${animeContent.select("img:first-of-type").attr("src")}"
anime.genre = animeContent.select("p:nth-of-type(2)").text().replace("Жанр: ", "")
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 animeData = json.decodeFromString(AnimeDetailsDto.serializer(), response.body!!.string()).data?.first()
val anime = SAnime.create().apply {
title = animeData?.title!!
val year = animeContent.select("p:nth-of-type(1)").text().replace("Год выхода: ", "")
val rating = animeContent.select(".current-rating").text().toInt()
val type = animeContent.select("p:nth-of-type(3)").text().replace("Тип: ", "")
val votes = animeContent.select("div:nth-of-type(2) span span").text().toInt()
if (animeData.preview != null) {
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.title = document.select(".shortstory > .shortstoryHead h1").text()
anime.description = formatDescription(
AnimeDescription(
year,
type,
rating,
votes,
description
)
)
return anime
}
private fun formatDescription(animeData: Data): String {
private fun formatDescription(animeData: AnimeDescription): String {
var description = ""
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) {
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) {
@ -159,38 +148,29 @@ class AnimevostSource(override val name: String, override val baseUrl: String, p
return description
}
override fun animeDetailsParse(document: Document) = throw Exception("not used")
// Episode
override fun episodeFromElement(element: Element) = 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> {
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>()
if (animeData?.series != null) {
val series = Json.parseToJsonElement(animeData.series.replace("'", "\"")).jsonObject.toMap()
series.entries.forEachIndexed { index, entry ->
episodeList.add(
SEpisode.create().apply {
val id = entry.value.toString().replace("\"", "")
name = entry.key
episode_number = index.toFloat()
url = "/frame5.php?play=$id&old=1"
}
)
}
episodes.forEachIndexed { index, entry ->
episodeList.add(
SEpisode.create().apply {
val id = entry.split(":")[1]
name = entry.split(":")[0]
episode_number = index.toFloat()
url = "/frame5.php?play=$id&old=1"
}
)
}
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,
)