fix(src): Multiple updates (#157)

* fix(src): Multiple updates

Closes #93
Closes #1
Closes #133
Closes #142 (Yeah, this extension had a bug but someone closed it before fixing it.)

* Fix(lib/ChillxExtractor)

Closes #153
This commit is contained in:
imper1aldev 2024-08-19 11:12:51 -06:00 committed by GitHub
parent 9fbe135358
commit 112961d8de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
87 changed files with 682 additions and 78 deletions

View file

@ -5,6 +5,8 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES.decryptWithSalt import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES.decryptWithSalt
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.parseAs
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -27,6 +29,7 @@ class ChillxExtractor(private val client: OkHttpClient, private val headers: Hea
// matches "[language]https://...," // matches "[language]https://...,"
private val REGEX_SUBS by lazy { Regex("""\[(.*?)\](.*?)"?\,""") } private val REGEX_SUBS by lazy { Regex("""\[(.*?)\](.*?)"?\,""") }
private const val KEY_SOURCE = "https://rowdy-avocado.github.io/multi-keys/"
} }
fun videoFromUrl(url: String, referer: String, prefix: String = "Chillx - "): List<Video> { fun videoFromUrl(url: String, referer: String, prefix: String = "Chillx - "): List<Video> {
@ -39,7 +42,7 @@ class ChillxExtractor(private val client: OkHttpClient, private val headers: Hea
val master = REGEX_MASTER_JS.find(body)?.groupValues?.get(1) ?: return emptyList() val master = REGEX_MASTER_JS.find(body)?.groupValues?.get(1) ?: return emptyList()
val aesJson = json.decodeFromString<CryptoInfo>(master) val aesJson = json.decodeFromString<CryptoInfo>(master)
val key = getKey(body) val key = fetchKey()
val decryptedScript = decryptWithSalt(aesJson.ciphertext, aesJson.salt, key) val decryptedScript = decryptWithSalt(aesJson.ciphertext, aesJson.salt, key)
.replace("\\n", "\n") .replace("\\n", "\n")
.replace("\\", "") .replace("\\", "")
@ -83,6 +86,11 @@ class ChillxExtractor(private val client: OkHttpClient, private val headers: Hea
) )
} }
@OptIn(ExperimentalSerializationApi::class)
private fun fetchKey(): String {
return client.newCall(GET(KEY_SOURCE)).execute().parseAs<KeysData>().keys.get(0)
}
private fun getKey(body: String): String { private fun getKey(body: String): String {
val (encrypted, pass, offset, index) = REGEX_EVAL_KEY.find(body)!!.groupValues.drop(1) val (encrypted, pass, offset, index) = REGEX_EVAL_KEY.find(body)!!.groupValues.drop(1)
val decrypted = decryptScript(encrypted, pass, offset.toInt(), index.toInt()) val decrypted = decryptScript(encrypted, pass, offset.toInt(), index.toInt())
@ -114,4 +122,10 @@ class ChillxExtractor(private val client: OkHttpClient, private val headers: Hea
val label: String = "", val label: String = "",
val file: String, val file: String,
) )
@Serializable
data class KeysData(
@SerialName("chillx")
val keys: List<String>
)
} }

View file

@ -22,6 +22,8 @@ class VoeExtractor(private val client: OkHttpClient) {
private val base64Regex = Regex("'.*'") private val base64Regex = Regex("'.*'")
private val scriptBase64Regex = "(let|var)\\s+\\w+\\s*=\\s*'(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)';".toRegex()
@Serializable @Serializable
data class VideoLinkDTO(val file: String) data class VideoLinkDTO(val file: String)
@ -36,8 +38,9 @@ class VoeExtractor(private val client: OkHttpClient) {
document = clientDdos.newCall(GET(originalUrl)).execute().asJsoup() document = clientDdos.newCall(GET(originalUrl)).execute().asJsoup()
} }
val script = document.selectFirst("script:containsData(const sources), script:containsData(var sources), script:containsData(wc0)") val alternativeScript = document.select("script").find { scriptBase64Regex.containsMatchIn(it.data()) }?.data()
?.data() val script = document.selectFirst("script:containsData(const sources), script:containsData(var sources), script:containsData(wc0)")?.data()
?: alternativeScript
?: return emptyList() ?: return emptyList()
val playlistUrl = when { val playlistUrl = when {
// Layout 1 // Layout 1
@ -46,10 +49,11 @@ class VoeExtractor(private val client: OkHttpClient) {
if (linkRegex.matches(link)) link else String(Base64.decode(link, Base64.DEFAULT)) if (linkRegex.matches(link)) link else String(Base64.decode(link, Base64.DEFAULT))
} }
// Layout 2 // Layout 2
script.contains("wc0") -> { script.contains("wc0") || alternativeScript != null -> {
val base64 = base64Regex.find(script)!!.value val base64 = base64Regex.find(script)!!.value
val decoded = Base64.decode(base64, Base64.DEFAULT).let(::String) val decoded = Base64.decode(base64, Base64.DEFAULT).let(::String)
json.decodeFromString<VideoLinkDTO>(decoded).file
json.decodeFromString<VideoLinkDTO>(if (alternativeScript != null) decoded.reversed() else decoded).file
} }
else -> return emptyList() else -> return emptyList()
} }

View file

@ -3,7 +3,7 @@ ext {
extClass = '.ChineseAnime' extClass = '.ChineseAnime'
themePkg = 'animestream' themePkg = 'animestream'
baseUrl = 'https://www.chineseanime.vip' baseUrl = 'https://www.chineseanime.vip'
overrideVersionCode = 8 overrideVersionCode = 9
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Jav Guru' extName = 'Jav Guru'
extClass = '.JavGuru' extClass = '.JavGuru'
extVersionCode = 15 extVersionCode = 16
isNsfw = true isNsfw = true
} }

View file

@ -3,7 +3,7 @@ ext {
extClass = '.LMAnime' extClass = '.LMAnime'
themePkg = 'animestream' themePkg = 'animestream'
baseUrl = 'https://lmanime.com' baseUrl = 'https://lmanime.com'
overrideVersionCode = 6 overrideVersionCode = 7
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'SupJav' extName = 'SupJav'
extClass = '.SupJavFactory' extClass = '.SupJavFactory'
extVersionCode = 9 extVersionCode = 10
isNsfw = true isNsfw = true
} }

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Anime4up' extName = 'Anime4up'
extClass = '.Anime4Up' extClass = '.Anime4Up'
extVersionCode = 57 extVersionCode = 58
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Arab Seed' extName = 'Arab Seed'
extClass = '.ArabSeed' extClass = '.ArabSeed'
extVersionCode = 13 extVersionCode = 14
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'asia2tv' extName = 'asia2tv'
extClass = '.Asia2TV' extClass = '.Asia2TV'
extVersionCode = 18 extVersionCode = 19
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Egy Dead' extName = 'Egy Dead'
extClass = '.EgyDead' extClass = '.EgyDead'
extVersionCode = 12 extVersionCode = 13
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Anime-Base' extName = 'Anime-Base'
extClass = '.AnimeBase' extClass = '.AnimeBase'
extVersionCode = 24 extVersionCode = 25
isNsfw = true isNsfw = true
} }

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Anime-Loads' extName = 'Anime-Loads'
extClass = '.AnimeLoads' extClass = '.AnimeLoads'
extVersionCode = 15 extVersionCode = 16
isNsfw = true isNsfw = true
} }

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Cinemathek' extClass = '.Cinemathek'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://cinemathek.net' baseUrl = 'https://cinemathek.net'
overrideVersionCode = 20 overrideVersionCode = 21
isNsfw = true isNsfw = true
} }

View file

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

View file

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

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Kinoking' extClass = '.Kinoking'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://kinoking.cc' baseUrl = 'https://kinoking.cc'
overrideVersionCode = 21 overrideVersionCode = 22
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Moflix-Stream' extName = 'Moflix-Stream'
extClass = '.MoflixStream' extClass = '.MoflixStream'
extVersionCode = 8 extVersionCode = 9
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

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

View file

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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,279 @@
package eu.kanade.tachiyomi.animeextension.en.animegg
import android.annotation.SuppressLint
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
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.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.parallelCatchingFlatMapBlocking
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.util.Locale
class AnimeGG : ConfigurableAnimeSource, AnimeHttpSource() {
override val name = "AnimeGG"
override val baseUrl = "https://www.animegg.org"
override val lang = "en"
override val supportsLatest = true
private val json: Json by injectLazy()
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
companion object {
private const val PREF_LANGUAGE_KEY = "preferred_language"
private const val PREF_LANGUAGE_DEFAULT = "[SUBBED]"
private val LANGUAGE_LIST = arrayOf("[SUBBED]", "[DUBBED]", "[RAW]")
private const val PREF_QUALITY_KEY = "preferred_quality"
private const val PREF_QUALITY_DEFAULT = "1080"
private val QUALITY_LIST = arrayOf("1080", "720", "480", "360")
private const val PREF_SERVER_KEY = "preferred_server"
private const val PREF_SERVER_DEFAULT = "AnimeGG"
private val SERVER_LIST = arrayOf("AnimeGG")
}
override fun animeDetailsParse(response: Response): SAnime {
val document = response.asJsoup()
val animeDetails = SAnime.create().apply {
title = document.selectFirst(".media-body h1")?.text()?.trim() ?: ""
status = if (document.location().contains("/series/")) SAnime.UNKNOWN else SAnime.COMPLETED
description = document.selectFirst(".ptext")?.text()
genre = document.select(".tagscat a").joinToString { it.text() }
thumbnail_url = document.selectFirst(".media .media-object")?.attr("abs:src")
document.select(".infoami span").map { it.text() }.map { textContent ->
when {
"Status" in textContent -> status = parseStatus(textContent)
}
}
}
return animeDetails
}
private fun parseStatus(span: String): Int {
val status = span.substringAfter("Status:").trim()
return when {
"Completed" in status -> SAnime.COMPLETED
"Ongoing" in status -> SAnime.ONGOING
else -> SAnime.UNKNOWN
}
}
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/popular-series?sortBy=hits&sortDirection=DESC&ongoing&limit=50&start=0", headers)
override fun popularAnimeParse(response: Response): AnimesPage {
val document = response.asJsoup()
val elements = document.select(".fea")
val animeList = elements.map { element ->
SAnime.create().apply {
title = element.selectFirst(".rightpop a")?.text()?.trim() ?: ""
thumbnail_url = element.selectFirst("img")?.attr("abs:src")
setUrlWithoutDomain(element.select(".rightpop a").attr("abs:href"))
}
}
return AnimesPage(animeList, false)
}
override fun latestUpdatesParse(response: Response) = popularAnimeParse(response)
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/popular-series?sortBy=createdAt&sortDirection=DESC&ongoing&limit=50&start=0", headers)
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when {
query.isNotBlank() -> GET("$baseUrl/search/?q=$query", headers)
genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}/page/$page", headers)
else -> popularAnimeRequest(page)
}
}
override fun searchAnimeParse(response: Response): AnimesPage {
val document = response.asJsoup()
val elements = document.select(".mse")
val animeList = elements.map { element ->
SAnime.create().apply {
title = element.selectFirst(".first h2")?.text()?.trim() ?: ""
thumbnail_url = element.selectFirst("img")?.attr("abs:src")
setUrlWithoutDomain(element.attr("abs:href"))
}
}
return AnimesPage(animeList, false)
}
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
return document.select(".newmanga li div").mapIndexed { idx, episode ->
val episodeNumber = episode.selectFirst(".anm_det_pop strong")?.getEpNumber() ?: (idx + 1F)
val title = episode.select(".anititle").text()
SEpisode.create().apply {
episode_number = episodeNumber
name = when {
episodeNumber.formatEp() in title -> episode.select(".anititle").text()
else -> "Episode ${episodeNumber.formatEp()} - ${episode.select(".anititle").text()}"
}
scanlator = episode.select(".btn-xs").joinToString { it.text() }
setUrlWithoutDomain(episode.select(".anm_det_pop").attr("abs:href"))
}
}
}
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
return document.select("iframe").parallelCatchingFlatMapBlocking {
val mode = when (it.closest(".tab-pane")?.attr("id")) {
"subbed-Animegg" -> "[SUBBED]"
"dubbed-Animegg" -> "[DUBBED]"
"raw-Animegg" -> "[RAW]"
else -> ""
}
val link = it.attr("abs:src")
val embedPlayer = client.newCall(GET(link)).execute().asJsoup()
val scriptData = embedPlayer.selectFirst("script:containsData(var videoSources =)")?.data() ?: return@parallelCatchingFlatMapBlocking emptyList()
val host = link.toHttpUrl().host
val videoHeaders = headers.newBuilder().add("referer", "https://$host").build()
val jsonString = fixJsonString(scriptData.substringAfter("var videoSources = ").substringBefore(";"))
json.decodeFromString<Array<GgVideo>>(jsonString).map { video ->
val videoUrl = "https://$host${video.file}"
Video(videoUrl, "$mode AnimeGG:${video.label}", videoUrl, headers = videoHeaders)
}
}
}
private fun fixJsonString(jsonString: String): String {
return jsonString.replace(Regex("""(\w+):"""), """"$1":""")
.replace(Regex("""(:\s)([^{\[}\]":\s,]+)"""), """$1"$2"""")
.replace(Regex("""(:\s)("[^"]*")"""), """$1$2""")
}
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!!
val lang = preferences.getString(PREF_LANGUAGE_KEY, PREF_LANGUAGE_DEFAULT)!!
return this.sortedWith(
compareBy(
{ it.quality.contains(lang) },
{ it.quality.contains(server, true) },
{ it.quality.contains(quality) },
{ Regex("""(\d+)p""").find(it.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 },
),
).reversed()
}
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter(),
)
private class GenreFilter : UriPartFilter(
"Genre",
arrayOf(
Pair("<Seleccionar>", ""),
Pair("Películas", "peliculas"),
Pair("Series", "series"),
),
)
private fun Element?.getEpNumber(): Float? {
val input = this?.text() ?: return null
val regex = Regex("""(\d+(\.\d+)?)(?:-\d+(\.\d+)?)?$""")
val matchResult = regex.find(input)
return matchResult?.groupValues?.get(1)?.toFloatOrNull()
}
@SuppressLint("DefaultLocale")
private fun Float.formatEp(): String {
return if (this % 1 == 0.0f) {
String.format(Locale.US, "%.0f", this)
} else {
String.format(Locale.US, "%.1f", this)
}
}
private 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
}
@Serializable
data class GgVideo(
val file: String,
val label: String,
)
override fun setupPreferenceScreen(screen: PreferenceScreen) {
ListPreference(screen.context).apply {
key = PREF_LANGUAGE_KEY
title = "Preferred language"
entries = LANGUAGE_LIST
entryValues = LANGUAGE_LIST
setDefaultValue(PREF_LANGUAGE_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)
ListPreference(screen.context).apply {
key = PREF_QUALITY_KEY
title = "Preferred quality"
entries = QUALITY_LIST
entryValues = QUALITY_LIST
setDefaultValue(PREF_QUALITY_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

@ -3,7 +3,7 @@ ext {
extClass = '.AnimeKhor' extClass = '.AnimeKhor'
themePkg = 'animestream' themePkg = 'animestream'
baseUrl = 'https://animekhor.xyz' baseUrl = 'https://animekhor.xyz'
overrideVersionCode = 3 overrideVersionCode = 4
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Animenosub' extClass = '.Animenosub'
themePkg = 'animestream' themePkg = 'animestream'
baseUrl = 'https://animenosub.com' baseUrl = 'https://animenosub.com'
overrideVersionCode = 5 overrideVersionCode = 6
isNsfw = true isNsfw = true
} }

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Gogoanime' extName = 'Gogoanime'
extClass = '.GogoAnime' extClass = '.GogoAnime'
extVersionCode = 83 extVersionCode = 84
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Multimovies' extClass = '.Multimovies'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://multimovies.art' baseUrl = 'https://multimovies.art'
overrideVersionCode = 17 overrideVersionCode = 18
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'AnimeFLV' extName = 'AnimeFLV'
extClass = '.AnimeFlv' extClass = '.AnimeFlv'
extVersionCode = 55 extVersionCode = 56
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -8,4 +8,5 @@ apply from: "$rootDir/common.gradle"
dependencies { dependencies {
implementation(project(':lib:streamtape-extractor')) implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:streamwish-extractor'))
} }

View file

@ -12,9 +12,9 @@ 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.lib.streamtapeextractor.StreamTapeExtractor import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
@ -117,15 +117,22 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun episodeFromElement(element: Element) = throw UnsupportedOperationException() override fun episodeFromElement(element: Element) = throw UnsupportedOperationException()
// ============================ Video Links =============================
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
override fun videoListParse(response: Response): List<Video> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("#partes div.container li.subtab div.parte").forEach { script -> document.select("#partes div.container li.subtab div.parte").forEach { script ->
val jsonString = script.attr("data") val jsonString = script.attr("data")
val jsonUnescape = unescapeJava(jsonString)!!.replace("\\", "") val jsonUnescape = unescapeJava(jsonString)!!.replace("\\", "")
val url = jsonUnescape.substringAfter("src=\"").substringBefore("\"").replace("\\\\", "\\") val url = fetchUrls(jsonUnescape).firstOrNull()?.replace("\\\\", "\\") ?: ""
if (url.contains("streamtape")) { if (url.contains("streamtape") || url.contains("tape") || url.contains("stp")) {
StreamTapeExtractor(client).videoFromUrl(url)?.let { videoList.add(it) } streamtapeExtractor.videosFromUrl(url).also(videoList::addAll)
}
if (url.contains("wish") || url.contains("fviplions") || url.contains("obeywish")) {
streamwishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll)
} }
} }
return videoList return videoList
@ -147,6 +154,12 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return processed return processed
} }
private fun fetchUrls(text: String?): List<String> {
if (text.isNullOrEmpty()) return listOf()
val linkRegex = "(http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\\/~+#-]*[\\w@?^=%&\\/~+#-])".toRegex()
return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
}
override fun animeDetailsParse(document: Document): SAnime { override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.thumbnail_url = document.selectFirst("#anime figure img.cover")!!.attr("abs:src") anime.thumbnail_url = document.selectFirst("#anime figure img.cover")!!.attr("abs:src")

View file

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

View file

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

View file

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

View file

@ -0,0 +1,14 @@
ext {
extName = 'Cine24h'
extClass = '.Cine24h'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:fastream-extractor'))
implementation(project(':lib:dood-extractor'))
implementation(project(':lib:filemoon-extractor'))
implementation(project(':lib:voe-extractor'))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,272 @@
package eu.kanade.tachiyomi.animeextension.es.cine24h
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
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.Video
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.fastreamextractor.FastreamExtractor
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Calendar
open class Cine24h : ConfigurableAnimeSource, AnimeHttpSource() {
override val name = "Cine24h"
override val baseUrl = "https://cine24h.online"
override val lang = "es"
override val supportsLatest = true
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
companion object {
private const val PREF_QUALITY_KEY = "preferred_quality"
private const val PREF_QUALITY_DEFAULT = "1080"
private val QUALITY_LIST = arrayOf("1080", "720", "480", "360")
private const val PREF_SERVER_KEY = "preferred_server"
private const val PREF_SERVER_DEFAULT = "Voe"
private val SERVER_LIST = arrayOf("Voe", "Fastream", "Filemoon", "Doodstream")
}
override fun animeDetailsParse(response: Response): SAnime {
val document = response.asJsoup()
val animeDetails = SAnime.create().apply {
description = document.selectFirst(".Single .Description")?.text()
genre = document.select(".Single .InfoList a").joinToString { it.text() }
thumbnail_url = document.selectFirst(".Single .Image img")?.getImageUrl()?.replace("/w185/", "/w500/")
if (document.location().contains("/movie/")) {
status = SAnime.COMPLETED
} else {
val statusText = document.select(".InfoList .AAIco-adjust").map { it.text() }
.find { "En Producción:" in it }?.substringAfter("En Producción:")?.trim()
status = when (statusText) { "" -> SAnime.ONGOING else -> SAnime.COMPLETED }
}
}
return animeDetails
}
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/peliculas-mas-vistas/page/$page", headers)
override fun popularAnimeParse(response: Response): AnimesPage {
val document = response.asJsoup()
val elements = document.select(".TPost a:not([target])")
val nextPage = document.select(".wp-pagenavi .next").any()
val animeList = elements.map { element ->
val lang = element.select(".Langu .sprite").attr("class").lowercase()
val titleItem = element.selectFirst(".Title")?.text()?.trim() ?: ""
val link = element.attr("abs:href")
val prefix = when {
lang.contains("sub") || titleItem.lowercase().contains("(sub)") || link.contains("-sub") -> "\uD83C\uDDFA\uD83C\uDDF8 "
lang.contains("lat") || titleItem.lowercase().contains("(lat)") || link.contains("-lat") -> "\uD83C\uDDF2\uD83C\uDDFD "
lang.contains("esp") || titleItem.lowercase().contains("(es)") || link.contains("-es") -> "\uD83C\uDDEA\uD83C\uDDF8 "
else -> ""
}
SAnime.create().apply {
title = prefix + titleItem
thumbnail_url = element.selectFirst(".Image img")?.getImageUrl()?.replace("/w185/", "/w300/")
setUrlWithoutDomain(link)
}
}
return AnimesPage(animeList, nextPage)
}
override fun latestUpdatesParse(response: Response) = popularAnimeParse(response)
override fun latestUpdatesRequest(page: Int): Request {
val currentYear = Calendar.getInstance().get(Calendar.YEAR)
return GET("$baseUrl/page/$page/?s=trfilter&trfilter=1&years%5B0%5D=$currentYear#038;trfilter=1&years%5B0%5D=$currentYear", headers)
}
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when {
query.isNotBlank() -> GET("$baseUrl/page/$page/?s=$query", headers)
genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}/page/$page", headers)
else -> popularAnimeRequest(page)
}
}
override fun searchAnimeParse(response: Response) = popularAnimeParse(response)
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
return if (document.location().contains("/movie/")) {
listOf(
SEpisode.create().apply {
episode_number = 1f
name = "PELÍCULA"
scanlator = document.select(".AAIco-date_range").text().trim()
setUrlWithoutDomain(document.location())
},
)
} else {
var episodeCounter = 1F
document.select(".AABox").flatMap { season ->
val noSeason = season.select(".Title").text().substringAfter("Temporada").trim()
season.select(".AABox .TPTblCn tr").map { ep ->
SEpisode.create().apply {
episode_number = episodeCounter++
name = "T$noSeason - E${ep.select(".Num").text().trim()} - ${ep.select(".MvTbTtl a").text().trim()}"
scanlator = ep.select(".MvTbTtl span").text()
setUrlWithoutDomain(ep.select(".MvTbTtl a").attr("abs:href"))
}
}
}.reversed()
}
}
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
return document.select(".TPlayerTb").map { org.jsoup.nodes.Entities.unescape(it.html()) }.parallelCatchingFlatMapBlocking {
val urlEmbed = it.substringAfter("src=\"").substringBefore("\"").replace("&#038;", "&")
val link = client.newCall(GET(urlEmbed)).execute().asJsoup().selectFirst("iframe")?.attr("src") ?: ""
serverVideoResolver(link)
}
}
/*--------------------------------Video extractors------------------------------------*/
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
private val doodExtractor by lazy { DoodExtractor(client) }
private val voeExtractor by lazy { VoeExtractor(client) }
private fun serverVideoResolver(url: String): List<Video> {
val embedUrl = url.lowercase()
return when {
embedUrl.contains("fastream") -> {
val link = if (url.contains("emb.html")) "https://fastream.to/embed-${url.split("/").last()}.html" else url
FastreamExtractor(client, headers).videosFromUrl(link)
}
embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:")
embedUrl.contains("voe") -> voeExtractor.videosFromUrl(url)
embedUrl.contains("dood") -> doodExtractor.videosFromUrl(url)
else -> emptyList()
}
}
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!!
return this.sortedWith(
compareBy(
{ it.quality.contains(server, true) },
{ it.quality.contains(quality) },
{ Regex("""(\d+)p""").find(it.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 },
),
).reversed()
}
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter(),
)
private class GenreFilter : UriPartFilter(
"Género",
arrayOf(
Pair("<Seleccionar>", ""),
Pair("Películas", "peliculas"),
Pair("Series", "series"),
Pair("Acción", "category/accion"),
Pair("Animación", "category/animacion"),
Pair("Anime", "category/anime"),
Pair("Aventura", "category/aventura"),
Pair("Bélica", "category/belica"),
Pair("Ciencia ficción", "category/ciencia-ficcion"),
Pair("Comedia", "category/comedia"),
Pair("Crimen", "category/crimen"),
Pair("Documental", "category/documental"),
Pair("Drama", "category/drama"),
Pair("Familia", "category/familia"),
Pair("Fantasía", "category/fantasia"),
Pair("Gerra", "category/gerra"),
Pair("Historia", "category/historia"),
Pair("Misterio", "category/misterio"),
Pair("Música", "category/musica"),
Pair("Navidad", "category/navidad"),
Pair("Película de TV", "category/pelicula-de-tv"),
Pair("Romance", "category/romance"),
Pair("Suspenso", "category/suspense"),
Pair("Terror", "category/terror"),
Pair("Western", "category/western"),
),
)
private 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
}
protected open fun org.jsoup.nodes.Element.getImageUrl(): String? {
return when {
isValidUrl("data-src") -> attr("abs:data-src")
isValidUrl("data-lazy-src") -> attr("abs:data-lazy-src")
isValidUrl("srcset") -> attr("abs:srcset").substringBefore(" ")
isValidUrl("src") -> attr("abs:src")
else -> ""
}
}
protected open fun org.jsoup.nodes.Element.isValidUrl(attrName: String): Boolean {
if (!hasAttr(attrName)) return false
return !attr(attrName).contains("data:image/")
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
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)
ListPreference(screen.context).apply {
key = PREF_QUALITY_KEY
title = "Preferred quality"
entries = QUALITY_LIST
entryValues = QUALITY_LIST
setDefaultValue(PREF_QUALITY_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,7 +1,7 @@
ext { ext {
extName = 'CineCalidad' extName = 'CineCalidad'
extClass = '.CineCalidad' extClass = '.CineCalidad'
extVersionCode = 1 extVersionCode = 2
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Cineplus123' extClass = '.Cineplus123'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://cineplus123.org' baseUrl = 'https://cineplus123.org'
overrideVersionCode = 0 overrideVersionCode = 1
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Cuevana' extName = 'Cuevana'
extClass = '.CuevanaFactory' extClass = '.CuevanaFactory'
extVersionCode = 32 extVersionCode = 33
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'HentaiLA' extName = 'HentaiLA'
extClass = '.Hentaila' extClass = '.Hentaila'
extVersionCode = 24 extVersionCode = 25
isNsfw = true isNsfw = true
} }

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'HentaiTk' extName = 'HentaiTk'
extClass = '.Hentaitk' extClass = '.Hentaitk'
extVersionCode = 1 extVersionCode = 2
isNsfw = true isNsfw = true
} }

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'LACartoons' extName = 'LACartoons'
extClass = '.Lacartoons' extClass = '.Lacartoons'
extVersionCode = 3 extVersionCode = 4
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Pelisplushd' extName = 'Pelisplushd'
extClass = '.PelisplushdFactory' extClass = '.PelisplushdFactory'
extVersionCode = 56 extVersionCode = 57
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'TioanimeH' extName = 'TioanimeH'
extClass = '.TioanimeHFactory' extClass = '.TioanimeHFactory'
extVersionCode = 17 extVersionCode = 18
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Tiodonghua' extClass = '.Tiodonghua'
themePkg = 'animestream' themePkg = 'animestream'
baseUrl = 'https://anime.tiodonghua.com' baseUrl = 'https://anime.tiodonghua.com'
overrideVersionCode = 3 overrideVersionCode = 4
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Wiflix' extClass = '.Wiflix'
themePkg = 'datalifeengine' themePkg = 'datalifeengine'
baseUrl = 'https://wiflix.voto' baseUrl = 'https://wiflix.voto'
overrideVersionCode = 6 overrideVersionCode = 7
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -3,7 +3,7 @@ ext {
extClass = '.AnimeSAGA' extClass = '.AnimeSAGA'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://www.animesaga.in' baseUrl = 'https://www.animesaga.in'
overrideVersionCode = 9 overrideVersionCode = 10
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

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

View file

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

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Bakashi' extClass = '.Bakashi'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://bakashi.tv' baseUrl = 'https://bakashi.tv'
overrideVersionCode = 11 overrideVersionCode = 12
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -3,7 +3,7 @@ ext {
extClass = '.Pobreflix' extClass = '.Pobreflix'
themePkg = 'dooplay' themePkg = 'dooplay'
baseUrl = 'https://pobreflix1.art' baseUrl = 'https://pobreflix1.art'
overrideVersionCode = 9 overrideVersionCode = 10
isNsfw = true isNsfw = true
} }

View file

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

View file

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

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'TR Anime Izle' extName = 'TR Anime Izle'
extClass = '.TRAnimeIzle' extClass = '.TRAnimeIzle'
extVersionCode = 17 extVersionCode = 18
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Türk Anime TV' extName = 'Türk Anime TV'
extClass = '.TurkAnime' extClass = '.TurkAnime'
extVersionCode = 24 extVersionCode = 25
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"