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:
committed by
GitHub
parent
2ad1c30263
commit
086b777ba0
@ -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'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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,39 +148,30 @@ 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()
|
|
||||||
|
|
||||||
series.entries.forEachIndexed { index, entry ->
|
|
||||||
episodeList.add(
|
episodeList.add(
|
||||||
SEpisode.create().apply {
|
SEpisode.create().apply {
|
||||||
val id = entry.value.toString().replace("\"", "")
|
val id = entry.split(":")[1]
|
||||||
name = entry.key
|
name = entry.split(":")[0]
|
||||||
episode_number = index.toFloat()
|
episode_number = index.toFloat()
|
||||||
url = "/frame5.php?play=$id&old=1"
|
url = "/frame5.php?play=$id&old=1"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return episodeList.reversed()
|
return episodeList.reversed()
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|
||||||
)
|
|
Reference in New Issue
Block a user