Initial commit

This commit is contained in:
almightyhak 2024-06-20 11:54:12 +07:00
commit 98ed7e8839
2263 changed files with 108711 additions and 0 deletions

View file

@ -0,0 +1,18 @@
ext {
extName = 'AsyaAnimeleri'
extClass = '.AsyaAnimeleri'
themePkg = 'animestream'
baseUrl = 'https://asyaanimeleri.com'
overrideVersionCode = 3
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:vk-extractor"))
implementation(project(":lib:okru-extractor"))
implementation(project(":lib:sibnet-extractor"))
implementation(project(":lib:gdriveplayer-extractor"))
implementation(project(":lib:dood-extractor"))
// implementation(project(":lib:dailymotion-extractor"))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,145 @@
package eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.CountryFilter
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.GenresFilter
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.NetworkFilter
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.OrderFilter
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.StatusFilter
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.StudioFilter
import eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri.AsyaAnimeleriFilters.TypeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.gdriveplayerextractor.GdrivePlayerExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.sibnetextractor.SibnetExtractor
import eu.kanade.tachiyomi.lib.vkextractor.VkExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters
import eu.kanade.tachiyomi.network.GET
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class AsyaAnimeleri : AnimeStream(
"tr",
"AsyaAnimeleri",
"https://asyaanimeleri.com",
) {
override val animeListUrl = "$baseUrl/series"
override val dateFormatter by lazy {
SimpleDateFormat("MMMM dd, yyyy", Locale("tr"))
}
override val client by lazy {
network.client.newBuilder()
.addInterceptor(ShittyProtectionInterceptor(network.client))
.build()
}
// =============================== Search ===============================
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = AsyaAnimeleriFilters.getSearchParameters(filters)
return if (query.isNotEmpty()) {
GET("$baseUrl/page/$page/?s=$query")
} else {
val additional = params.run { listOf(genres, studios, countries, networks) }
.filter(String::isNotBlank)
.joinToString("&")
val url = "$animeListUrl/?$additional".toHttpUrl().newBuilder()
.addQueryParameter("page", "$page")
.addIfNotBlank("status", params.status)
.addIfNotBlank("type", params.type)
.addIfNotBlank("order", params.order)
.build()
GET(url.toString(), headers)
}
}
// ============================== Filters ===============================
override val filtersSelector = "div.filter.dropdown > ul"
override fun getFilterList(): AnimeFilterList {
return if (AnimeStreamFilters.filterInitialized()) {
AnimeFilterList(
GenresFilter("Tür"),
StudioFilter("Stüdyo"),
CountryFilter("Ülke"),
NetworkFilter(""),
AnimeFilter.Separator(),
StatusFilter("Durum"),
TypeFilter("Tip"),
OrderFilter("Sirala"),
)
} else {
AnimeFilterList(AnimeFilter.Header(filtersMissingWarning))
}
}
// =========================== Anime Details ============================
override val animeStatusText = "Durum"
override fun parseStatus(statusString: String?): Int {
return when (statusString?.trim()?.lowercase()) {
"tamamlandı" -> SAnime.COMPLETED
"devam ediyor" -> SAnime.ONGOING
else -> SAnime.UNKNOWN
}
}
// ============================== Episodes ==============================
override val episodePrefix = "Bölüm"
// ============================ Video Links =============================
override val prefQualityValues = arrayOf("1080p", "720p", "480p", "360p", "240p", "144p")
override val prefQualityEntries = prefQualityValues
private val vkExtractor by lazy { VkExtractor(client, headers) }
private val okruExtractor by lazy { OkruExtractor(client) }
private val sibnetExtractor by lazy { SibnetExtractor(client) }
private val gdrivePlayerExtractor by lazy { GdrivePlayerExtractor(client) }
private val doodExtractor by lazy { DoodExtractor(client) }
// private val dailyExtractor by lazy { DailymotionExtractor(client, headers) }
override fun getVideoList(url: String, name: String): List<Video> {
return when (name.lowercase().trim()) {
"vk" -> vkExtractor.videosFromUrl(url)
"ok.ru" -> okruExtractor.videosFromUrl(url)
"sibnet" -> sibnetExtractor.videosFromUrl(url)
// "daily" -> dailyExtractor.videosFromUrl(url)
"dood", "doodstream" -> doodExtractor.videoFromUrl(url)?.let(::listOf) ?: emptyList()
"gdrive" -> {
val newUrl = "https://gdriveplayer.to/embed2.php?link=$url"
gdrivePlayerExtractor.videosFromUrl(newUrl, "Gdrive", headers)
}
else -> emptyList()
}
}
// ============================= Utilities ==============================
private fun HttpUrl.Builder.addIfNotBlank(query: String, value: String) = apply {
if (value.isNotBlank()) {
addQueryParameter(query, value)
}
}
// Overriding to prevent removing the ?resize part.
// Without it, some images simply don't load (????)
// Turkish source moment. That's why i prefer greeks.
override fun Element.getImageUrl(): String? {
return when {
hasAttr("data-src") -> attr("abs:data-src")
hasAttr("data-lazy-src") -> attr("abs:data-lazy-src")
hasAttr("srcset") -> attr("abs:srcset").substringBefore(" ")
else -> attr("abs:src")
}
}
}

View file

@ -0,0 +1,54 @@
package eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.CheckBoxFilterList
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.QueryPartFilter
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.asQueryPart
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.filterInitialized
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.getPairListByIndex
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.parseCheckbox
object AsyaAnimeleriFilters {
internal class GenresFilter(name: String) : CheckBoxFilterList(name, GENRES_LIST)
internal class StudioFilter(name: String) : CheckBoxFilterList(name, STUDIO_LIST)
internal class CountryFilter(name: String) : CheckBoxFilterList(name, COUNTRY_LIST)
internal class NetworkFilter(name: String) : CheckBoxFilterList(name, NETWORK_LIST)
internal class StatusFilter(name: String) : QueryPartFilter(name, STATUS_LIST)
internal class TypeFilter(name: String) : QueryPartFilter(name, TYPE_LIST)
internal class OrderFilter(name: String) : QueryPartFilter(name, ORDER_LIST)
internal data class FilterSearchParams(
val genres: String = "",
val studios: String = "",
val countries: String = "",
val networks: String = "",
val status: String = "",
val type: String = "",
val order: String = "",
)
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
if (filters.isEmpty() || !filterInitialized()) return FilterSearchParams()
return FilterSearchParams(
filters.parseCheckbox<GenresFilter>(GENRES_LIST, "genre"),
filters.parseCheckbox<StudioFilter>(STUDIO_LIST, "studio"),
filters.parseCheckbox<CountryFilter>(COUNTRY_LIST, "country"),
filters.parseCheckbox<NetworkFilter>(NETWORK_LIST, "network"),
filters.asQueryPart<StatusFilter>(),
filters.asQueryPart<TypeFilter>(),
filters.asQueryPart<OrderFilter>(),
)
}
private val GENRES_LIST by lazy { getPairListByIndex(0) }
private val STUDIO_LIST by lazy { getPairListByIndex(2) }
private val COUNTRY_LIST by lazy { getPairListByIndex(3) }
private val NETWORK_LIST by lazy { getPairListByIndex(4) }
private val STATUS_LIST by lazy { getPairListByIndex(5) }
private val TYPE_LIST by lazy { getPairListByIndex(6) }
private val ORDER_LIST by lazy { getPairListByIndex(7) }
}

View file

@ -0,0 +1,73 @@
package eu.kanade.tachiyomi.animeextension.tr.asyaanimeleri
import app.cash.quickjs.QuickJs
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Cookie
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.IOException
class ShittyProtectionInterceptor(private val client: OkHttpClient) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
// ignore non-protected requests
if (response.code != 202) return response
return try {
chain.proceed(bypassProtection(request, response))
} catch (e: Throwable) {
// Because OkHttp's enqueue only handles IOExceptions, wrap the exception so that
// we don't crash the entire app
e.printStackTrace()
throw IOException(e)
}
}
private fun bypassProtection(request: Request, response: Response): Request {
val doc = response.asJsoup()
val script = doc.selectFirst("script:containsData(slowAES)")!!.data()
val slowAES = doc.selectFirst("script[src*=min.js]")!!.attr("abs:src").let { url ->
client.newCall(GET(url)).execute().body.string()
}
val patchedScript = slowAES + "\n" + ADDITIONAL_FUNCTIONS + script
.replace("document.cookie=", "")
.replace("location.href", "// ")
val cookieString = QuickJs.create().use {
it.evaluate(patchedScript)?.toString()
}!!
val cookie = Cookie.parse(request.url, cookieString)!!
client.cookieJar.saveFromResponse(request.url, listOf(cookie))
val headers = request.headers.newBuilder()
.add("Cookie", cookie.toString())
.build()
return GET(request.url.toString(), headers)
}
companion object {
private val ADDITIONAL_FUNCTIONS get() = """
// QJS doesnt have atob(b64dec) >:(
atob = function(s) {
var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(i=0;i<64;i++){e[A.charAt(i)]=i;}
for(x=0;x<L;x++){
c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
}
return r;
};
""".trimIndent()
}
}