fix(ar/asia2tv): Fix video extractor + add more extractors (#2422)
This commit is contained in:
@ -1,18 +1,23 @@
|
|||||||
apply plugin: 'com.android.application'
|
plugins {
|
||||||
apply plugin: 'kotlin-android'
|
alias(libs.plugins.android.application)
|
||||||
|
alias(libs.plugins.kotlin.android)
|
||||||
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
extName = 'asia2tv'
|
extName = 'asia2tv'
|
||||||
pkgNameSuffix = 'ar.asia2tv'
|
pkgNameSuffix = 'ar.asia2tv'
|
||||||
extClass = '.Asia2TV'
|
extClass = '.Asia2TV'
|
||||||
extVersionCode = 14
|
extVersionCode = 15
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(':lib-streamtape-extractor'))
|
|
||||||
implementation(project(':lib-okru-extractor'))
|
|
||||||
implementation(project(':lib-dood-extractor'))
|
implementation(project(':lib-dood-extractor'))
|
||||||
|
implementation(project(':lib-okru-extractor'))
|
||||||
|
implementation(project(':lib-streamtape-extractor'))
|
||||||
|
implementation(project(':lib-streamwish-extractor'))
|
||||||
|
implementation(project(':lib-uqload-extractor'))
|
||||||
|
implementation(project(':lib-vidbom-extractor'))
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -14,8 +14,15 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|||||||
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
|
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
|
||||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||||
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.lib.uqloadextractor.UqloadExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
|
||||||
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.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
@ -30,7 +37,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override val name = "Asia2TV"
|
override val name = "Asia2TV"
|
||||||
|
|
||||||
override val baseUrl = "https://asia2tv.net"
|
override val baseUrl = "https://ww1.asia2tv.pw"
|
||||||
|
|
||||||
override val lang = "ar"
|
override val lang = "ar"
|
||||||
|
|
||||||
@ -42,8 +49,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================== popular =======================
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
override fun popularAnimeSelector(): String = "div.postmovie-photo a[title]"
|
override fun popularAnimeSelector(): String = "div.postmovie-photo a[title]"
|
||||||
|
|
||||||
override fun popularAnimeNextPageSelector(): String = "div.nav-links a.next"
|
override fun popularAnimeNextPageSelector(): String = "div.nav-links a.next"
|
||||||
@ -58,8 +64,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return anime
|
return anime
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================== episodes =======================
|
// ============================== Episodes ==============================
|
||||||
|
|
||||||
override fun episodeListSelector() = "div.loop-episode a"
|
override fun episodeListSelector() = "div.loop-episode a"
|
||||||
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> {
|
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||||
@ -73,39 +78,51 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return episode
|
return episode
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================== video urls =======================
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun videoListSelector() = "ul.server-list-menu li"
|
override fun videoListSelector() = "ul.server-list-menu li"
|
||||||
|
|
||||||
override fun videoListRequest(episode: SEpisode): Request {
|
override fun videoListRequest(episode: SEpisode): Request {
|
||||||
val document = client.newCall(GET(baseUrl + episode.url)).execute().asJsoup()
|
val document = client.newCall(GET(baseUrl + episode.url)).execute()
|
||||||
|
.use { it.asJsoup() }
|
||||||
val link = document.selectFirst("div.loop-episode a.current")!!.attr("href")
|
val link = document.selectFirst("div.loop-episode a.current")!!.attr("href")
|
||||||
return GET(link)
|
return GET(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.asJsoup()
|
val document = response.use { it.asJsoup() }
|
||||||
val videoList = mutableListOf<Video>()
|
return document.select(videoListSelector()).parallelCatchingFlatMap {
|
||||||
document.select(videoListSelector()).forEach {
|
|
||||||
val url = it.attr("data-server")
|
val url = it.attr("data-server")
|
||||||
if (url.contains("dood")) {
|
getVideosFromUrl(url)
|
||||||
val videosFromURL = DoodExtractor(client).videoFromUrl(url)
|
}
|
||||||
if (videosFromURL != null) videoList.add(videosFromURL)
|
}
|
||||||
} else if (url.contains("ok")) {
|
|
||||||
val videosFromURL = OkruExtractor(client).videosFromUrl(url)
|
private val doodExtractor by lazy { DoodExtractor(client) }
|
||||||
videoList.addAll(videosFromURL)
|
private val okruExtractor by lazy { OkruExtractor(client) }
|
||||||
} else if (url.contains("streamtape")) {
|
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
|
||||||
val videosFromURL = StreamTapeExtractor(client).videoFromUrl(url)
|
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||||
if (videosFromURL != null) videoList.add(videosFromURL)
|
private val uqloadExtractor by lazy { UqloadExtractor(client) }
|
||||||
} else if (url.contains("yodbox")) {
|
private val vidbomExtractor by lazy { VidBomExtractor(client) }
|
||||||
val html = client.newCall(GET(url)).execute().asJsoup()
|
|
||||||
val videoFromURL = html.select("source").attr("src")
|
private fun getVideosFromUrl(url: String): List<Video> {
|
||||||
if (videoFromURL.isNotEmpty()) {
|
return when {
|
||||||
videoList.add(Video(videoFromURL, "Yodbox: mirror", videoFromURL))
|
"dood" in url || "ds2play" in url -> doodExtractor.videosFromUrl(url)
|
||||||
|
"ok.ru" in url || "odnoklassniki.ru" in url -> okruExtractor.videosFromUrl(url)
|
||||||
|
"streamtape" in url -> streamtapeExtractor.videoFromUrl(url)?.let(::listOf)
|
||||||
|
STREAM_WISH_DOMAINS.any(url::contains) -> streamwishExtractor.videosFromUrl(url)
|
||||||
|
"uqload" in url -> uqloadExtractor.videosFromUrl(url)
|
||||||
|
VID_BOM_DOMAINS.any(url::contains) -> vidbomExtractor.videosFromUrl(url)
|
||||||
|
"youdbox" in url || "yodbox" in url -> {
|
||||||
|
client.newCall(GET(url)).execute().use {
|
||||||
|
val doc = it.asJsoup()
|
||||||
|
val videoUrl = doc.selectFirst("source")?.attr("abs:src")
|
||||||
|
when (videoUrl) {
|
||||||
|
null -> emptyList()
|
||||||
|
else -> listOf(Video(videoUrl, "Yodbox: mirror", videoUrl))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else -> null
|
||||||
return videoList
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun videoFromElement(element: Element): Video = throw Exception("not used")
|
override fun videoFromElement(element: Element): Video = throw Exception("not used")
|
||||||
@ -130,8 +147,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================== search =======================
|
// =============================== Search ===============================
|
||||||
|
|
||||||
override fun searchAnimeSelector(): String = "div.postmovie-photo a[title]"
|
override fun searchAnimeSelector(): String = "div.postmovie-photo a[title]"
|
||||||
|
|
||||||
override fun searchAnimeNextPageSelector(): String = "div.nav-links a.next"
|
override fun searchAnimeNextPageSelector(): String = "div.nav-links a.next"
|
||||||
@ -172,8 +188,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================== details =======================
|
// =========================== Anime Details ============================
|
||||||
|
|
||||||
override fun animeDetailsParse(document: Document): SAnime {
|
override fun animeDetailsParse(document: Document): SAnime {
|
||||||
val anime = SAnime.create()
|
val anime = SAnime.create()
|
||||||
anime.title = document.select("h1 span.title").text()
|
anime.title = document.select("h1 span.title").text()
|
||||||
@ -184,8 +199,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return anime
|
return anime
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================== latest =======================
|
// =============================== Latest ===============================
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector(): String = throw Exception("Not used")
|
override fun latestUpdatesNextPageSelector(): String = throw Exception("Not used")
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SAnime = throw Exception("Not used")
|
override fun latestUpdatesFromElement(element: Element): SAnime = throw Exception("Not used")
|
||||||
@ -194,8 +208,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override fun latestUpdatesSelector(): String = throw Exception("Not used")
|
override fun latestUpdatesSelector(): String = throw Exception("Not used")
|
||||||
|
|
||||||
// ========================== filters =======================
|
// ============================== Filters ===============================
|
||||||
|
|
||||||
override fun getFilterList() = AnimeFilterList(
|
override fun getFilterList() = AnimeFilterList(
|
||||||
AnimeFilter.Header("الفلترات مش هتشتغل لو بتبحث او وهي فاضيه"),
|
AnimeFilter.Header("الفلترات مش هتشتغل لو بتبحث او وهي فاضيه"),
|
||||||
TypeList(typesName),
|
TypeList(typesName),
|
||||||
@ -231,8 +244,7 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Preferences
|
// ============================== Settings ==============================
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val videoQualityPref = ListPreference(screen.context).apply {
|
val videoQualityPref = ListPreference(screen.context).apply {
|
||||||
key = "preferred_quality"
|
key = "preferred_quality"
|
||||||
@ -251,4 +263,19 @@ class Asia2TV : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
screen.addPreference(videoQualityPref)
|
screen.addPreference(videoQualityPref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================= Utilities ==============================
|
||||||
|
private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
|
||||||
|
runBlocking {
|
||||||
|
map {
|
||||||
|
async(Dispatchers.Default) {
|
||||||
|
runCatching { f(it) }.getOrElse { emptyList() }
|
||||||
|
}
|
||||||
|
}.awaitAll().flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val STREAM_WISH_DOMAINS by lazy { listOf("wishfast", "fviplions", "filelions", "streamwish", "dwish") }
|
||||||
|
private val VID_BOM_DOMAINS by lazy { listOf("vidbam", "vadbam", "vidbom", "vidbm") }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user