Merged with dark25 (#636)
* merge merged lib, lib-multisrc, all, ar, de, en, es, fr, hi, id, it, pt, tr src from dark25 * patch
This commit is contained in:
parent
9f385108fc
commit
1384df62f3
350 changed files with 12176 additions and 1064 deletions
15
src/es/animenix/build.gradle
Normal file
15
src/es/animenix/build.gradle
Normal file
|
@ -0,0 +1,15 @@
|
|||
ext {
|
||||
extName = 'Animenix'
|
||||
extClass = '.Animenix'
|
||||
themePkg = 'dooplay'
|
||||
baseUrl = 'https://animenix.com'
|
||||
overrideVersionCode = 8
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib:filemoon-extractor"))
|
||||
implementation(project(":lib:streamwish-extractor"))
|
||||
implementation(project(":lib:universal-extractor"))
|
||||
}
|
BIN
src/es/animenix/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/es/animenix/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
BIN
src/es/animenix/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/es/animenix/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
src/es/animenix/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/es/animenix/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
src/es/animenix/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/es/animenix/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8 KiB |
BIN
src/es/animenix/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/es/animenix/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,215 @@
|
|||
package eu.kanade.tachiyomi.animeextension.es.animenix
|
||||
|
||||
import androidx.preference.CheckBoxPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
|
||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||
import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
|
||||
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Animenix : DooPlay(
|
||||
"es",
|
||||
"Animenix",
|
||||
"https://animenix.com",
|
||||
) {
|
||||
|
||||
// ============================== Popular ===============================
|
||||
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/ratings/$page")
|
||||
|
||||
override fun popularAnimeSelector() = latestUpdatesSelector()
|
||||
|
||||
override fun popularAnimeNextPageSelector() = latestUpdatesNextPageSelector()
|
||||
|
||||
// =============================== Search ===============================
|
||||
|
||||
// ============================== Episodes ==============================
|
||||
override val episodeMovieText = "Película"
|
||||
|
||||
override fun videoListParse(response: Response): List<Video> {
|
||||
val players = response.asJsoup().select("li.dooplay_player_option")
|
||||
return players.flatMap { player ->
|
||||
runCatching {
|
||||
val link = getPlayerUrl(player)
|
||||
getPlayerVideos(link)
|
||||
}.getOrElse { emptyList() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPlayerUrl(player: Element): String {
|
||||
val body = FormBody.Builder()
|
||||
.add("action", "doo_player_ajax")
|
||||
.add("post", player.attr("data-post"))
|
||||
.add("nume", player.attr("data-nume"))
|
||||
.add("type", player.attr("data-type"))
|
||||
.build()
|
||||
return client.newCall(POST("$baseUrl/wp-admin/admin-ajax.php", headers, body))
|
||||
.execute()
|
||||
.let { response ->
|
||||
response.body.string()
|
||||
.substringAfter("\"embed_url\":\"")
|
||||
.substringBefore("\",")
|
||||
.replace("\\", "")
|
||||
}
|
||||
}
|
||||
|
||||
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
|
||||
private val streamWishExtractor by lazy { StreamWishExtractor(headers = headers, client = client) }
|
||||
private val universalExtractor by lazy { UniversalExtractor(client) }
|
||||
|
||||
private fun getPlayerVideos(link: String): List<Video> {
|
||||
return when {
|
||||
link.contains("filemoon") -> filemoonExtractor.videosFromUrl(link)
|
||||
link.contains("swdyu") -> streamWishExtractor.videosFromUrl(link)
|
||||
link.contains("wishembed") || link.contains("cdnwish") || link.contains("flaswish") || link.contains("sfastwish") || link.contains("streamwish") || link.contains("asnwish") -> streamWishExtractor.videosFromUrl(link)
|
||||
else -> universalExtractor.videosFromUrl(link, headers)
|
||||
}
|
||||
}
|
||||
|
||||
// =========================== Anime Details ============================
|
||||
override fun Document.getDescription(): String {
|
||||
return select("$additionalInfoSelector div.wp-content p")
|
||||
.eachText()
|
||||
.joinToString("\n")
|
||||
}
|
||||
|
||||
override val additionalInfoItems = listOf("Título", "Temporadas", "Episodios", "Duración media")
|
||||
|
||||
// =============================== Latest ===============================
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/ver/page/$page", headers)
|
||||
|
||||
override fun latestUpdatesNextPageSelector() = "div.pagination > *:last-child:not(span):not(.current)"
|
||||
|
||||
// =============================== Search ===============================
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
val params = AnimenixFilters.getSearchParameters(filters)
|
||||
val path = when {
|
||||
params.genre.isNotBlank() -> {
|
||||
if (params.genre in listOf("tendencias", "ratings")) {
|
||||
"/" + params.genre
|
||||
} else {
|
||||
"/genero/${params.genre}"
|
||||
}
|
||||
}
|
||||
params.language.isNotBlank() -> "/genero/${params.language}"
|
||||
params.year.isNotBlank() -> "/release/${params.year}"
|
||||
params.movie.isNotBlank() -> {
|
||||
if (params.movie == "pelicula") {
|
||||
"/pelicula"
|
||||
} else {
|
||||
"/genero/${params.movie}"
|
||||
}
|
||||
}
|
||||
else -> buildString {
|
||||
append(
|
||||
when {
|
||||
query.isNotBlank() -> "/?s=$query"
|
||||
params.letter.isNotBlank() -> "/letra/${params.letter}/?"
|
||||
else -> "/tendencias/?"
|
||||
},
|
||||
)
|
||||
|
||||
append(
|
||||
if (contains("tendencias")) {
|
||||
"&get=${when (params.type){
|
||||
"anime" -> "serie"
|
||||
"pelicula" -> "pelicula"
|
||||
else -> "todos"
|
||||
}}"
|
||||
} else {
|
||||
"&tipo=${params.type}"
|
||||
},
|
||||
)
|
||||
|
||||
if (params.isInverted) append("&orden=asc")
|
||||
}
|
||||
}
|
||||
|
||||
return if (path.startsWith("/?s=")) {
|
||||
GET("$baseUrl/page/$page$path")
|
||||
} else if (path.startsWith("/letra") || path.startsWith("/tendencias")) {
|
||||
val before = path.substringBeforeLast("/")
|
||||
val after = path.substringAfterLast("/")
|
||||
GET("$baseUrl$before/page/$page/$after")
|
||||
} else {
|
||||
GET("$baseUrl$path/page/$page")
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== Filters ===============================
|
||||
override val fetchGenres = false
|
||||
|
||||
override fun getFilterList() = AnimenixFilters.FILTER_LIST
|
||||
|
||||
// ============================== Settings ==============================
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
super.setupPreferenceScreen(screen) // Quality preference
|
||||
|
||||
val langPref = ListPreference(screen.context).apply {
|
||||
key = PREF_LANG_KEY
|
||||
title = PREF_LANG_TITLE
|
||||
entries = PREF_LANG_ENTRIES
|
||||
entryValues = PREF_LANG_VALUES
|
||||
setDefaultValue(PREF_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()
|
||||
}
|
||||
}
|
||||
|
||||
val vrfIterceptPref = CheckBoxPreference(screen.context).apply {
|
||||
key = PREF_VRF_INTERCEPT_KEY
|
||||
title = PREF_VRF_INTERCEPT_TITLE
|
||||
summary = PREF_VRF_INTERCEPT_SUMMARY
|
||||
setDefaultValue(PREF_VRF_INTERCEPT_DEFAULT)
|
||||
}
|
||||
|
||||
screen.addPreference(vrfIterceptPref)
|
||||
screen.addPreference(langPref)
|
||||
}
|
||||
|
||||
// ============================= Utilities ==============================
|
||||
override fun String.toDate() = 0L
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString(prefQualityKey, prefQualityDefault)!!
|
||||
val lang = preferences.getString(PREF_LANG_KEY, PREF_LANG_DEFAULT)!!
|
||||
return sortedWith(
|
||||
compareBy(
|
||||
{ it.quality.contains(lang) },
|
||||
{ it.quality.contains(quality) },
|
||||
),
|
||||
).reversed()
|
||||
}
|
||||
|
||||
override val prefQualityValues = arrayOf("480p", "720p", "1080p")
|
||||
override val prefQualityEntries = prefQualityValues
|
||||
|
||||
companion object {
|
||||
private const val PREF_LANG_KEY = "preferred_lang"
|
||||
private const val PREF_LANG_TITLE = "Preferred language"
|
||||
private const val PREF_LANG_DEFAULT = "SUB"
|
||||
private val PREF_LANG_ENTRIES = arrayOf("SUB", "All", "ES", "LAT")
|
||||
private val PREF_LANG_VALUES = arrayOf("SUB", "", "ES", "LAT")
|
||||
|
||||
private const val PREF_VRF_INTERCEPT_KEY = "vrf_intercept"
|
||||
private const val PREF_VRF_INTERCEPT_TITLE = "Intercept VRF links (Requiere Reiniciar)"
|
||||
private const val PREF_VRF_INTERCEPT_SUMMARY = "Intercept VRF links and open them in the browser"
|
||||
private const val PREF_VRF_INTERCEPT_DEFAULT = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package eu.kanade.tachiyomi.animeextension.es.animenix
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
|
||||
object AnimenixFilters {
|
||||
|
||||
open class UriPartFilter(
|
||||
displayName: String,
|
||||
val vals: Array<Pair<String, String>>,
|
||||
) : AnimeFilter.Select<String>(
|
||||
displayName,
|
||||
vals.map { it.first }.toTypedArray(),
|
||||
) {
|
||||
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.getFirst(): R {
|
||||
return first { it is R } as R
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.asUriPart(): String {
|
||||
return getFirst<R>().let {
|
||||
(it as UriPartFilter).toUriPart()
|
||||
}
|
||||
}
|
||||
|
||||
class InvertedResultsFilter : AnimeFilter.CheckBox("Invertir resultados", false)
|
||||
class TypeFilter : UriPartFilter("Tipo", AnimesOnlineNinjaData.TYPES)
|
||||
class LetterFilter : UriPartFilter("Filtrar por letra", AnimesOnlineNinjaData.LETTERS)
|
||||
|
||||
class GenreFilter : UriPartFilter("Generos", AnimesOnlineNinjaData.GENRES)
|
||||
class YearFilter : UriPartFilter("Año", AnimesOnlineNinjaData.YEARS)
|
||||
|
||||
class OtherOptionsGroup : AnimeFilter.Group<UriPartFilter>(
|
||||
"Otros filtros",
|
||||
listOf(
|
||||
GenreFilter(),
|
||||
YearFilter(),
|
||||
),
|
||||
)
|
||||
|
||||
private inline fun <reified R> AnimeFilter.Group<UriPartFilter>.getItemUri(): String {
|
||||
return state.first { it is R }.toUriPart()
|
||||
}
|
||||
|
||||
val FILTER_LIST get() = AnimeFilterList(
|
||||
InvertedResultsFilter(),
|
||||
TypeFilter(),
|
||||
LetterFilter(),
|
||||
AnimeFilter.Separator(),
|
||||
AnimeFilter.Header("Estos filtros no afectan a la busqueda por texto"),
|
||||
OtherOptionsGroup(),
|
||||
)
|
||||
|
||||
data class FilterSearchParams(
|
||||
val isInverted: Boolean = false,
|
||||
val type: String = "",
|
||||
val letter: String = "",
|
||||
val genre: String = "",
|
||||
val language: String = "",
|
||||
val year: String = "",
|
||||
val movie: String = "",
|
||||
)
|
||||
|
||||
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
|
||||
if (filters.isEmpty()) return FilterSearchParams()
|
||||
|
||||
val others = filters.getFirst<OtherOptionsGroup>()
|
||||
|
||||
return FilterSearchParams(
|
||||
filters.getFirst<InvertedResultsFilter>().state,
|
||||
filters.asUriPart<TypeFilter>(),
|
||||
filters.asUriPart<LetterFilter>(),
|
||||
others.getItemUri<GenreFilter>(),
|
||||
others.getItemUri<YearFilter>(),
|
||||
)
|
||||
}
|
||||
|
||||
private object AnimesOnlineNinjaData {
|
||||
val EVERY = Pair("Seleccionar", "")
|
||||
|
||||
val TYPES = arrayOf(
|
||||
Pair("Seleccionar", ""),
|
||||
Pair("Anime", "anime"),
|
||||
Pair("Peliculas", "pelicula"),
|
||||
)
|
||||
|
||||
val LETTERS = arrayOf(EVERY) + ('a'..'z').map {
|
||||
Pair(it.toString(), it.toString())
|
||||
}.toTypedArray()
|
||||
|
||||
val GENRES = arrayOf(
|
||||
EVERY,
|
||||
Pair("Acción", "accion"),
|
||||
Pair("Action", "action"),
|
||||
Pair("Action-Adventure", "action-adventure"),
|
||||
Pair("Aventura", "aventura"),
|
||||
Pair("Adventure", "adventure"),
|
||||
Pair("Animación", "animacion"),
|
||||
Pair("Animation", "animation"),
|
||||
Pair("Aventura (Torrent)", "aventura-torrent"),
|
||||
Pair("Bélica", "belica"),
|
||||
Pair("Ciencia Ficción", "ciencia-ficcion"),
|
||||
Pair("Comedia", "comedia"),
|
||||
Pair("Comedy", "comedy"),
|
||||
Pair("Crimen", "crimen"),
|
||||
Pair("Demonios", "demonios"),
|
||||
Pair("Deportes", "deportes"),
|
||||
Pair("Documental", "documental"),
|
||||
Pair("Drama", "drama"),
|
||||
Pair("Ecchi", "ecchi"),
|
||||
Pair("En Emisión", "en-emision"),
|
||||
Pair("Escolares", "escolares"),
|
||||
Pair("Familia", "familia"),
|
||||
Pair("Fantasía", "fantasia"),
|
||||
Pair("Fantasy", "fantasy"),
|
||||
Pair("Harem", "harem"),
|
||||
Pair("Historia", "historia"),
|
||||
Pair("Histórico", "historico"),
|
||||
Pair("History", "history"),
|
||||
Pair("Horror", "horror"),
|
||||
Pair("Kids", "kids"),
|
||||
Pair("Magia", "magia"),
|
||||
Pair("Misterio", "misterio"),
|
||||
Pair("Música", "musica"),
|
||||
Pair("Parodia", "parodia"),
|
||||
Pair("Película de TV", "pelicula-de-tv"),
|
||||
Pair("Reality", "reality"),
|
||||
Pair("Recuerdos de la Vida", "recuerdos-de-la-vida"),
|
||||
Pair("Romance", "romance"),
|
||||
Pair("Sci-Fi Fantasy", "sci-fi-fantasy"),
|
||||
Pair("Science Fiction", "science-fiction"),
|
||||
Pair("Seinen", "seinen"),
|
||||
Pair("Shojo", "shojo"),
|
||||
Pair("Shounen", "shounen"),
|
||||
Pair("Soap", "soap"),
|
||||
Pair("Sobrenatural", "sobrenatural"),
|
||||
Pair("Suspense", "suspense"),
|
||||
Pair("Terror", "terror"),
|
||||
Pair("Thriller", "thriller"),
|
||||
Pair("War & Politics", "war-politics"),
|
||||
Pair("Western", "western"),
|
||||
Pair("Yaoi", "yaoi"),
|
||||
Pair("Yuri", "yuri"),
|
||||
)
|
||||
val YEARS = arrayOf(EVERY) + (2024 downTo 1979).map {
|
||||
Pair(it.toString(), it.toString())
|
||||
}.toTypedArray()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue