chore(src/all): Remove animeui (#3181)

This commit is contained in:
Secozzi 2024-04-26 10:26:42 +00:00 committed by GitHub
parent 316d4a1240
commit a4f9576f6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 0 additions and 614 deletions

View File

@ -1,7 +0,0 @@
ext {
extName = 'AnimeUI'
extClass = '.AnimeUI'
extVersionCode = 2
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,255 +0,0 @@
package eu.kanade.tachiyomi.animeextension.all.animeui
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parseAs
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
class AnimeUI : ConfigurableAnimeSource, AnimeHttpSource() {
override val name = "AnimeUI"
override val baseUrl = "https://animeui.com"
override val lang = "all"
override val supportsLatest = true
private val json: Json by injectLazy()
override val id: Long = 7372747480486811746L
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private val apiHeaders = headers.newBuilder().apply {
add("Accept", "application/json, text/plain, */*")
add("Host", baseUrl.toHttpUrl().host)
add("Referer", "$baseUrl/")
}.build()
private val docHeaders = headers.newBuilder().apply {
add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
add("Host", baseUrl.toHttpUrl().host)
}.build()
private val titlePref by lazy { preferences.getString(PREF_TITLE_LANG_KEY, PREF_TITLE_LANG_DEFAULT)!! }
// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/api/home-list", apiHeaders)
override fun popularAnimeParse(response: Response): AnimesPage {
val animeList = response.parseAs<HomeListResponse>().trendingAnimes.map { it.toSAnime(baseUrl, titlePref) }
return AnimesPage(animeList, false)
}
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int): Request = popularAnimeRequest(page)
override fun latestUpdatesParse(response: Response): AnimesPage {
val animeList = response.parseAs<HomeListResponse>().latestAnimes.map { it.toSAnime(baseUrl, titlePref) }
return AnimesPage(animeList, false)
}
// =============================== Search ===============================
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = AnimeUIFilters.getSearchParameters(filters)
val url = "$baseUrl/api/directory".toHttpUrl().newBuilder().apply {
addQueryParameter("page", page.toString())
addQueryParameter("genres", params.genres)
addQueryParameter("years", params.year)
addQueryParameter("types", params.types)
addQueryParameter("status", params.status)
addQueryParameter("title", query)
addQueryParameter("category", params.category)
}.build().toString()
return GET(url, headers = apiHeaders)
}
override fun searchAnimeParse(response: Response): AnimesPage {
val data = response.parseAs<DirectoryResponse>()
val animeList = data.animes.map { it.toSAnime(baseUrl, titlePref) }
return AnimesPage(animeList, data.page < data.pages)
}
// ============================== Filters ===============================
override fun getFilterList() = AnimeUIFilters.FILTER_LIST
// =========================== Anime Details ============================
override fun animeDetailsRequest(anime: SAnime) = GET(baseUrl + anime.url, docHeaders)
override fun animeDetailsParse(response: Response): SAnime {
val document = response.asJsoup()
val data = document.selectFirst("script#__NEXT_DATA__")?.data() ?: return SAnime.create()
return json.decodeFromString<AnimeData>(data).props.pageProps.animeData.toSAnime()
}
// ============================== Episodes ==============================
override fun episodeListRequest(anime: SAnime): Request = animeDetailsRequest(anime)
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
val data = document.selectFirst("script#__NEXT_DATA__")?.data() ?: return emptyList()
return json.decodeFromString<AnimeData>(data).props.pageProps.animeData.episodes.map {
it.toSEpisode(response.request.url.pathSegments.last())
}.reversed()
}
// ============================ Video Links =============================
override fun videoListRequest(episode: SEpisode): Request = GET(baseUrl + episode.url, headers = docHeaders)
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val data = document.selectFirst("script#__NEXT_DATA__")?.data() ?: return emptyList()
val parsed = json.decodeFromString<EpisodeData>(data).props.pageProps.episodeData
val subtitleList = parsed.subtitlesJson?.let {
json.decodeFromString<List<SubtitleObject>>(it).map { s ->
Track("$baseUrl/api${s.url}", s.subtitle_name)
}.sortSubs()
} ?: emptyList()
val cid = parsed.episode.cid
return parsed.servers.filter { it.status == 1 }.map {
val url = it.url.toHttpUrl()
val videoUrl = url.newBuilder().addPathSegment(cid).build().toString()
val videoHeaders = headers.newBuilder().apply {
add("Accept", "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5")
add("Connection", "keep-alive")
add("Referer", "$baseUrl/")
}.build()
Video(videoUrl, it.name, videoUrl, headers = videoHeaders, subtitleTracks = subtitleList)
}
}
// ============================= Utilities ==============================.
private fun Iterable<Track>.sortSubs(): List<Track> {
val sub = preferences.getString(PREF_SUB_LANG_KEY, PREF_SUB_LANG_DEFAULT)!!
return this.sortedWith(
compareBy<Track>(
{ it.lang.startsWith(sub, true) },
{ it.lang.contains(sub, true) },
).thenByDescending { it.lang },
).reversed()
}
override fun List<Video>.sort(): List<Video> {
val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!!
return sortedWith(
compareBy { it.quality.contains(server, true) },
).reversed()
}
companion object {
private const val PREF_TITLE_LANG_KEY = "preferred_title_lang"
private const val PREF_TITLE_LANG_DEFAULT = "default"
private const val PREF_SERVER_KEY = "preferred_server"
private const val PREF_SERVER_DEFAULT = "Tokyo"
private val SERVER_LIST = arrayOf(
"Tokyo", "Kyoto", "Nagoya", "Sendai", "Sagara",
"Nara", "Osaka", "Web", "Noshiro",
)
private const val PREF_SUB_LANG_KEY = "preferred_sub_lang"
private const val PREF_SUB_LANG_DEFAULT = "English"
private val LOCALE_LIST = arrayOf(
"English",
"Spanish",
"European Spanish",
"Portuguese",
"Deutsch",
"French",
"Italian",
"Russian",
"Arabic",
)
}
// ============================== Settings ==============================
override fun setupPreferenceScreen(screen: PreferenceScreen) {
ListPreference(screen.context).apply {
key = PREF_TITLE_LANG_KEY
title = "Preferred title language"
entries = arrayOf("Site Default", "English", "Japanese")
entryValues = arrayOf(PREF_TITLE_LANG_DEFAULT, "english", "native")
setDefaultValue(PREF_TITLE_LANG_DEFAULT)
summary = "%s"
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
Toast.makeText(screen.context, "Restart Aniyomi to apply new setting.", Toast.LENGTH_LONG).show()
preferences.edit().putString(key, entry).commit()
}
}.also(screen::addPreference)
ListPreference(screen.context).apply {
key = PREF_SUB_LANG_KEY
title = "Preferred subtitle language"
entries = LOCALE_LIST
entryValues = LOCALE_LIST
setDefaultValue(PREF_SUB_LANG_DEFAULT)
summary = "%s"
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
preferences.edit().putString(key, entry).commit()
}
}.also(screen::addPreference)
ListPreference(screen.context).apply {
key = PREF_SERVER_KEY
title = "Preferred server"
entries = SERVER_LIST
entryValues = SERVER_LIST
setDefaultValue(PREF_SERVER_DEFAULT)
summary = "%s"
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
preferences.edit().putString(key, entry).commit()
}
}.also(screen::addPreference)
}
}

View File

@ -1,146 +0,0 @@
package eu.kanade.tachiyomi.animeextension.all.animeui
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import kotlinx.serialization.Serializable
import kotlin.math.ceil
import kotlin.math.floor
@Serializable
data class HomeListResponse(
val latestAnimes: List<AnimeObject>,
val trendingAnimes: List<AnimeObject>,
)
@Serializable
data class DirectoryResponse(
val animes: List<AnimeObject>,
val page: Int,
val pages: Int,
)
@Serializable
data class AnimeObject(
val title: String,
val title_english: String? = null,
val title_japanese: String? = null,
val slug: String,
val img_url: String,
) {
fun toSAnime(baseUrl: String, titlePref: String): SAnime = SAnime.create().apply {
thumbnail_url = "$baseUrl/_next/image?url=/api/images$img_url&w=640&q=75"
title = when (titlePref) {
"native" -> title_japanese
"english" -> title_english
else -> this@AnimeObject.title
} ?: this@AnimeObject.title
url = "/anime/$slug"
}
}
@Serializable
data class AnimeData(
val props: PropsObject,
) {
@Serializable
data class PropsObject(
val pageProps: PagePropsObject,
) {
@Serializable
data class PagePropsObject(
val animeData: AnimeDataObject,
) {
@Serializable
data class AnimeDataObject(
val anime: AnimeInfo,
val genres: List<String>? = null,
val episodes: List<EpisodeObject>,
) {
@Serializable
data class AnimeInfo(
val synopsis: String? = null,
val type_name: String? = null,
val rating_name: String? = null,
val year: Int? = null,
val season_name: String? = null,
val status_id: Int? = null,
)
fun toSAnime(): SAnime = SAnime.create().apply {
description = buildString {
anime.synopsis?.let { append(it + "\n\n") }
anime.type_name?.let { append("Type: $it\n") }
anime.year?.let {
append("Release: $it ${anime.season_name ?: ""}\n")
}
anime.rating_name?.let { append(it) }
}
status = when (anime.status_id) {
2 -> SAnime.ONGOING
3 -> SAnime.COMPLETED
else -> SAnime.UNKNOWN
}
genre = genres?.joinToString(", ")
}
@Serializable
data class EpisodeObject(
val title: String? = null,
val number: Float,
val cid: String,
) {
fun toSEpisode(animeSlug: String): SEpisode = SEpisode.create().apply {
val epName = if (floor(number) == ceil(number)) {
number.toInt().toString()
} else {
number.toString()
}
name = "Ep. $epName${title?.let { " - $it" } ?: ""}"
episode_number = number
url = "/watch/$animeSlug/$epName"
}
}
}
}
}
}
@Serializable
data class EpisodeData(
val props: PropsObject,
) {
@Serializable
data class PropsObject(
val pageProps: PagePropsObject,
) {
@Serializable
data class PagePropsObject(
val episodeData: EpisodeDataObject,
) {
@Serializable
data class EpisodeDataObject(
val episode: EpisodeInfoObject,
val servers: List<ServerObject>,
val subtitlesJson: String? = null,
) {
@Serializable
data class EpisodeInfoObject(
val cid: String,
)
@Serializable
data class ServerObject(
val name: String,
val url: String,
val status: Int,
)
}
}
}
}
@Serializable
data class SubtitleObject(
val url: String,
val subtitle_name: String,
)

View File

@ -1,206 +0,0 @@
package eu.kanade.tachiyomi.animeextension.all.animeui
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
object AnimeUIFilters {
open class QueryPartFilter(
displayName: String,
val vals: Array<Pair<String, String>>,
) : AnimeFilter.Select<String>(
displayName,
vals.map { it.first }.toTypedArray(),
) {
fun toQueryPart() = vals[state].second
}
open class CheckBoxFilterList(name: String, values: List<CheckBox>) : AnimeFilter.Group<AnimeFilter.CheckBox>(name, values)
private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state)
private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
return this.filterIsInstance<R>().joinToString("") {
(it as QueryPartFilter).toQueryPart()
}
}
inline fun <reified R> AnimeFilterList.getFirst(): R {
return first { it is R } as R
}
inline fun <reified R> AnimeFilterList.parseCheckbox(
options: Array<Pair<String, String>>,
): String {
return (getFirst<R>() as CheckBoxFilterList).state
.filter { it.state }
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
.filter(String::isNotBlank)
.joinToString(",")
}
class GenresFilter : CheckBoxFilterList(
"Genres",
AnimeUIFiltersData.GENRES.map { CheckBoxVal(it.first, false) },
)
class YearFilter : CheckBoxFilterList(
"Year",
AnimeUIFiltersData.YEARS.map { CheckBoxVal(it.first, false) },
)
class TypesFilter : CheckBoxFilterList(
"Types",
AnimeUIFiltersData.TYPES.map { CheckBoxVal(it.first, false) },
)
class StatusFilter : CheckBoxFilterList(
"Status",
AnimeUIFiltersData.STATUS.map { CheckBoxVal(it.first, false) },
)
class CategoryFilter : QueryPartFilter("Category", AnimeUIFiltersData.CATEGORY)
val FILTER_LIST get() = AnimeFilterList(
GenresFilter(),
YearFilter(),
TypesFilter(),
StatusFilter(),
CategoryFilter(),
)
data class FilterSearchParams(
val genres: String = "",
val year: String = "",
val types: String = "",
val status: String = "",
val category: String = "",
)
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
if (filters.isEmpty()) return FilterSearchParams()
return FilterSearchParams(
filters.parseCheckbox<GenresFilter>(AnimeUIFiltersData.GENRES),
filters.parseCheckbox<YearFilter>(AnimeUIFiltersData.YEARS),
filters.parseCheckbox<TypesFilter>(AnimeUIFiltersData.TYPES),
filters.parseCheckbox<StatusFilter>(AnimeUIFiltersData.STATUS),
filters.asQueryPart<CategoryFilter>(),
)
}
private object AnimeUIFiltersData {
val GENRES = arrayOf(
Pair("Action", "1"),
Pair("Adventure", "2"),
Pair("Comedy", "3"),
Pair("Cyberpunk", "14"),
Pair("Demons", "16"),
Pair("Drama", "4"),
Pair("Ecchi", "15"),
Pair("Fantasy", "6"),
Pair("Harem", "17"),
Pair("Hentai", "21"),
Pair("Historical", "20"),
Pair("Horror", "9"),
Pair("Isekai", "22"),
Pair("Josei", "18"),
Pair("Magic", "7"),
Pair("Martial Arts", "19"),
Pair("Mecha", "24"),
Pair("Military", "23"),
Pair("Music", "25"),
Pair("Mystery", "10"),
Pair("Police", "26"),
Pair("Post-Apocalyptic", "27"),
Pair("Psychological", "11"),
Pair("Romance", "12"),
Pair("School", "28"),
Pair("Sci-Fi", "13"),
Pair("Seinen", "29"),
Pair("Shoujo", "30"),
Pair("Shounen", "31"),
Pair("Slice of Life", "5"),
Pair("Space", "32"),
Pair("Sports", "33"),
Pair("Super Power", "34"),
Pair("Supernatural", "8"),
Pair("Thriller", "39"),
Pair("Tragedy", "35"),
Pair("Vampire", "36"),
Pair("Yaoi", "38"),
Pair("Yuri", "37"),
)
val YEARS = arrayOf(
Pair("1988", "1988"),
Pair("1997", "1997"),
Pair("1998", "1998"),
Pair("2001", "2001"),
Pair("2004", "2004"),
Pair("2005", "2005"),
Pair("2006", "2006"),
Pair("2007", "2007"),
Pair("2008", "2008"),
Pair("2009", "2009"),
Pair("2010", "2010"),
Pair("2011", "2011"),
Pair("2012", "2012"),
Pair("2013", "2013"),
Pair("2014", "2014"),
Pair("2015", "2015"),
Pair("2016", "2016"),
Pair("2017", "2017"),
Pair("2018", "2018"),
Pair("2019", "2019"),
Pair("2020", "2020"),
Pair("2021", "2021"),
Pair("2022", "2022"),
Pair("2023", "2023"),
Pair("2024", "2024"),
)
val TYPES = arrayOf(
Pair("TV", "1"),
Pair("ONA", "2"),
Pair("OVA", "3"),
Pair("BD", "4"),
Pair("Special", "5"),
Pair("Movie", "6"),
)
val STATUS = arrayOf(
Pair("Currently Airing", "2"),
Pair("Finished Airing", "3"),
Pair("Not Yet Released", "1"),
)
val CATEGORY = arrayOf(
Pair("ALL", ""),
Pair("#", "0-9"),
Pair("A", "A"),
Pair("B", "B"),
Pair("C", "C"),
Pair("D", "D"),
Pair("E", "E"),
Pair("F", "F"),
Pair("G", "G"),
Pair("H", "H"),
Pair("I", "I"),
Pair("J", "J"),
Pair("K", "K"),
Pair("L", "L"),
Pair("M", "M"),
Pair("N", "N"),
Pair("O", "O"),
Pair("P", "P"),
Pair("Q", "Q"),
Pair("R", "R"),
Pair("S", "S"),
Pair("T", "T"),
Pair("U", "U"),
Pair("V", "V"),
Pair("X", "X"),
Pair("Y", "Y"),
Pair("Z", "Z"),
)
}
}