fix(ar/mycima): refactor, optimize and fix some stuff (#1992)

This commit is contained in:
adly98
2023-08-02 09:41:07 +03:00
committed by GitHub
parent f48150168c
commit 0aa69e83d8
4 changed files with 146 additions and 68 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'MY CIMA' extName = 'MY CIMA'
pkgNameSuffix = 'ar.mycima' pkgNameSuffix = 'ar.mycima'
extClass = '.MyCima' extClass = '.MyCima'
extVersionCode = 19 extVersionCode = 20
libVersion = '13' libVersion = '13'
} }

View File

@ -2,9 +2,11 @@ package eu.kanade.tachiyomi.animeextension.ar.mycima
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.AppInfo import eu.kanade.tachiyomi.animeextension.ar.mycima.extractors.GoVadExtractor
import eu.kanade.tachiyomi.animeextension.ar.mycima.extractors.UQLoadExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -14,7 +16,10 @@ 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.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers.Companion.toHeaders import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -28,10 +33,6 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "MY Cima" override val name = "MY Cima"
private val defaultBaseUrl = "https://wecima.co"
private val baseUrlPref = "overrideBaseUrl_v${AppInfo.getVersionName()}"
override val baseUrl by lazy { getPrefBaseUrl() } override val baseUrl by lazy { getPrefBaseUrl() }
override val lang = "ar" override val lang = "ar"
@ -123,13 +124,35 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoListParse(response: Response): List<Video> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val iframe = document.selectFirst("iframe")!!.attr("data-lazy-src") return document.select("ul.WatchServersList li btn").parallelMap {
val referer = response.request.url.encodedPath val frameURL = it.attr("data-url")
val newHeaderList = mutableMapOf(Pair("referer", baseUrl + referer)) runCatching {
headers.forEach { newHeaderList[it.first] = it.second } if(it.parent()?.hasClass("MyCimaServer") == true)
val iframeResponse = client.newCall(GET(iframe, newHeaderList.toHeaders())) {
.execute().asJsoup() val referer = response.request.url.encodedPath
return videosFromElement(iframeResponse.selectFirst(videoListSelector())!!) val newHeader = headers.newBuilder().add("referer", baseUrl + referer).build()
val iframeResponse = client.newCall(GET(frameURL, newHeader)).execute().asJsoup()
videosFromElement(iframeResponse.selectFirst(videoListSelector())!!)
} else {
extractVideos(frameURL)
}
}.getOrElse { emptyList() }
}.flatten()
}
private fun extractVideos(url: String): List<Video>{
return when {
GOVAD_REGEX.containsMatchIn(url) -> {
val finalUrl = GOVAD_REGEX.find(url)!!.groupValues[0]
val urlHost = GOVAD_REGEX.find(url)!!.groupValues[1]
GoVadExtractor(client).videosFromUrl("https://www.$finalUrl.html", urlHost)
}
UQLOAD_REGEX.containsMatchIn(url) -> {
val finalUrl = UQLOAD_REGEX.find(url)!!.groupValues[0]
UQLoadExtractor(client).videosFromUrl("https://www.$finalUrl.html")
}
else -> null
} ?: emptyList()
} }
override fun videoListSelector() = "body" override fun videoListSelector() = "body"
@ -139,7 +162,6 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val script = element.select("script") val script = element.select("script")
.firstOrNull { it.data().contains("player.qualityselector({") } .firstOrNull { it.data().contains("player.qualityselector({") }
if (script != null) { if (script != null) {
val scriptV = element.select("script:containsData(source)")
val data = element.data().substringAfter("sources: [").substringBefore("],") val data = element.data().substringAfter("sources: [").substringBefore("],")
val sources = data.split("format: '").drop(1) val sources = data.split("format: '").drop(1)
for (source in sources) { for (source in sources) {
@ -155,21 +177,10 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", null) val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
if (quality != null) { return sortedWith(
val newList = mutableListOf<Video>() compareBy { it.quality.contains(quality) },
var preferred = 0 ).reversed()
for (video in this) {
if (video.quality.contains(quality)) {
newList.add(preferred, video)
preferred++
} else {
newList.add(video)
}
}
return newList
}
return this
} }
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
@ -196,7 +207,7 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
when (filter) { when (filter) {
is SearchCategoryList -> { is SearchCategoryList -> {
val catQ = getSearchCategoryList()[filter.state].query val catQ = getSearchCategoryList()[filter.state].query
val catUrl = "$baseUrl/search/$query/$catQ$page" val catUrl = "$baseUrl/search/$query/" + if(catQ == "page/" && page == 1) "" else "$catQ$page"
return GET(catUrl, headers) return GET(catUrl, headers)
} }
else -> {} else -> {}
@ -208,7 +219,7 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
is CategoryList -> { is CategoryList -> {
if (filter.state > 0) { if (filter.state > 0) {
val catQ = getCategoryList()[filter.state].query val catQ = getCategoryList()[filter.state].query
val catUrl = "$baseUrl/category/$catQ/page/$page" val catUrl = "$baseUrl/$catQ/page/$page/"
return GET(catUrl, headers) return GET(catUrl, headers)
} }
} }
@ -224,12 +235,19 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun animeDetailsParse(document: Document): SAnime { override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.title = document.select("div.Title--Content--Single-begin > h1").text() anime.title = when {
document.selectFirst("li:contains(المسلسل) p") != null -> {
document.select("li:contains(المسلسل) p").text()
}
else -> {
document.select("div.Title--Content--Single-begin > h1").text().substringBefore(" (")
}
}
anime.genre = document.select("li:contains(التصنيف) > p > a, li:contains(النوع) > p > a").joinToString(", ") { it.text() } anime.genre = document.select("li:contains(التصنيف) > p > a, li:contains(النوع) > p > a").joinToString(", ") { it.text() }
anime.description = document.select("div.AsideContext > div.StoryMovieContent, div.PostItemContent").text() anime.description = document.select("div.AsideContext > div.StoryMovieContent").text()
anime.author = document.select("li:contains(شركات الإنتاج) > p > a").joinToString(", ") { it.text() } anime.author = document.select("li:contains(شركات الإنتاج) > p > a").joinToString(", ") { it.text() }
// add alternative name to anime description // add alternative name to anime description
document.select("li:contains( بالعربي) > p, li:contains(معروف) > p").text()?.let { document.select("li:contains( بالعربي) > p, li:contains(معروف) > p").text().let {
if (it.isEmpty().not()) { if (it.isEmpty().not()) {
anime.description += when { anime.description += when {
anime.description!!.isEmpty() -> "Alternative Name: $it" anime.description!!.isEmpty() -> "Alternative Name: $it"
@ -277,45 +295,51 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}.toTypedArray() }.toTypedArray()
private fun getSearchCategoryList() = listOf( private fun getSearchCategoryList() = listOf(
CatUnit("فيلم", "/page/"), CatUnit("فيلم", "page/"),
CatUnit("مسلسل", "list/series/?page_number="), CatUnit("مسلسل", "list/series/?page_number="),
CatUnit("انمى", "list/anime/?page_number="), CatUnit("انمى", "list/anime/?page_number="),
CatUnit("برنامج", "list/tv/?page_number="), CatUnit("برنامج", "list/tv/?page_number="),
) )
private fun getCategoryList() = listOf( private fun getCategoryList() = listOf(
CatUnit("اختر", ""), CatUnit("اختر", ""),
CatUnit("جميع الافلام", "افلام"), CatUnit("جميع الافلام", "category/أفلام/"),
CatUnit("افلام اجنبى", "افلام/10-movies-english-افلام-اجنبي/"), CatUnit("افلام اجنبى", "category/أفلام/10-movies-english-افلام-اجنبي"),
CatUnit("افلام عربى", "افلام/6-arabic-movies-افلام-عربي/"), CatUnit("افلام عربى", "category/أفلام/افلام-عربي-arabic-movies"),
CatUnit("افلام هندى", "افلام/افلام-هندي-indian-movies/"), CatUnit("افلام هندى", "category/أفلام/افلام-هندي-indian-movies"),
CatUnit("افلام تركى", "افلام/افلام-تركى-turkish-films/"), CatUnit("افلام تركى", "category/أفلام/افلام-تركى-turkish-films"),
CatUnit("افلام وثائقية", "افلام/افلام-وثائقية-documentary-films/"), CatUnit("افلام وثائقية", "category/أفلام/افلام-وثائقية-documentary-films"),
CatUnit("افلام انمي", "افلام-كرتون/"), CatUnit("افلام انمي", "category/افلام-كرتون"),
CatUnit("سلاسل افلام", "افلام/10-movies-english-افلام-اجنبي/سلاسل-الافلام-الكاملة-full-pack/"), CatUnit("سلاسل افلام", "category/أفلام/10-movies-english-افلام-اجنبي/سلاسل-الافلام-الكاملة-full-pack"),
CatUnit("مسلسلات", "مسلسلات"), CatUnit("مسلسلات", "category/مسلسلات"),
CatUnit("مسلسلات اجنبى", "مسلسلات/5-series-english-مسلسلات-اجنبي/"), CatUnit("مسلسلات اجنبى", "category/مسلسلات/5-series-english-مسلسلات-اجنبي"),
CatUnit("مسلسلات عربى", "مسلسلات/13-مسلسلات-عربيه-arabic-series/"), CatUnit("مسلسلات عربى", "category/مسلسلات/5-series-english-مسلسلات-اجنبي"),
CatUnit("مسلسلات هندى", "مسلسلات/9-series-indian-مسلسلات-هندية/"), CatUnit("مسلسلات هندى", "category/مسلسلات/9-series-indian-مسلسلات-هندية"),
CatUnit("مسلسلات اسيوى", "مسلسلات/مسلسلات-اسيوية/"), CatUnit("مسلسلات اسيوى", "category/مسلسلات/مسلسلات-اسيوية"),
CatUnit("مسلسلات تركى", "مسلسلات/8-مسلسلات-تركية-turkish-series/"), CatUnit("مسلسلات تركى", "category/مسلسلات/8-مسلسلات-تركية-turkish-series"),
CatUnit("مسلسلات وثائقية", "مسلسلات/مسلسلات-وثائقية-documentary-series/"), CatUnit("مسلسلات وثائقية", "category/مسلسلات/مسلسلات-وثائقية-documentary-series"),
CatUnit("مسلسلات انمي", "مسلسلات-كرتون/"), CatUnit("مسلسلات انمي", "category/مسلسلات-كرتون"),
CatUnit("NETFLIX", "production/netflix"),
CatUnit("WARNER BROS", "production/warner-bros"),
CatUnit("LIONSGATE", "production/lionsgate"),
CatUnit("DISNEY", "production/walt-disney-pictures"),
CatUnit("COLUMBIA", "production/columbia-pictures"),
) )
// preferred quality settings // preferred quality settings
override fun setupPreferenceScreen(screen: PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply { val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply {
key = BASE_URL_PREF_TITLE key = PREF_BASE_URL_KEY
title = BASE_URL_PREF_TITLE title = PREF_BASE_URL_TITLE
summary = BASE_URL_PREF_SUMMARY summary = getPrefBaseUrl()
this.setDefaultValue(defaultBaseUrl) this.setDefaultValue(PREF_BASE_URL_DEFAULT)
dialogTitle = BASE_URL_PREF_TITLE dialogTitle = PREF_BASE_URL_DIALOG_TITLE
dialogMessage = "Default: $defaultBaseUrl" dialogMessage = PREF_BASE_URL_DIALOG_MESSAGE
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->
try { try {
val res = preferences.edit().putString(baseUrlPref, newValue as String).commit() val res = preferences.edit().putString(PREF_BASE_URL_KEY, newValue as String).commit()
Toast.makeText(screen.context, "Restart Aniyomi to apply changes", Toast.LENGTH_LONG).show()
res res
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
@ -324,13 +348,12 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
} }
val videoQualityPref = ListPreference(screen.context).apply { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = PREF_QUALITY_KEY
title = "Preferred quality" title = PREF_QUALITY_TITLE
entries = arrayOf("1080p", "720p", "480p", "360p", "240p") entries = PREF_QUALITY_ENTRIES
entryValues = arrayOf("1080", "720", "480", "360", "240") entryValues = PREF_QUALITY_ENTRIES.map { it.replace("p","") }.toTypedArray()
setDefaultValue("1080") setDefaultValue(PREF_QUALITY_DEFAULT)
summary = "%s" summary = "%s"
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String val selected = newValue as String
val index = findIndexOfValue(selected) val index = findIndexOfValue(selected)
@ -342,10 +365,26 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
screen.addPreference(videoQualityPref) screen.addPreference(videoQualityPref)
} }
private fun getPrefBaseUrl(): String = preferences.getString(baseUrlPref, defaultBaseUrl)!! private fun getPrefBaseUrl(): String = preferences.getString(PREF_BASE_URL_KEY, PREF_BASE_URL_DEFAULT)!!
// ============================= Utilities ===================================
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
runBlocking {
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
}
companion object { companion object {
private const val BASE_URL_PREF_TITLE = "Override BaseUrl" private const val PREF_QUALITY_KEY = "preferred_quality"
private const val BASE_URL_PREF_SUMMARY = "Override default domain with a different one" private const val PREF_QUALITY_TITLE = "Preferred quality"
private const val PREF_QUALITY_DEFAULT = "1080"
private val PREF_QUALITY_ENTRIES = arrayOf("1080p", "720p", "480p", "360p", "240p")
private const val PREF_BASE_URL_DEFAULT = "https://cdn3.wecima.watch"
private const val PREF_BASE_URL_KEY = "default_domain"
private const val PREF_BASE_URL_TITLE = "Enter default domain"
private const val PREF_BASE_URL_DIALOG_TITLE = "Default domain"
private const val PREF_BASE_URL_DIALOG_MESSAGE = "You can change the site domain from here"
private val GOVAD_REGEX = Regex("(v[aie]d[bp][aoe]?m|myvii?d|govad|segavid|v[aei]{1,2}dshar[er]?)\\.(?:com|net|org|xyz)(?::\\d+)?/(?:embed[/-])?([A-Za-z0-9]+)")
private val UQLOAD_REGEX = Regex("(uqload\\.[ic]om?)/(?:embed-)?([0-9a-zA-Z]+)")
} }
} }

View File

@ -0,0 +1,21 @@
package eu.kanade.tachiyomi.animeextension.ar.mycima.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
class GoVadExtractor(private val client:OkHttpClient) {
fun videosFromUrl(url: String, host: String): List<Video> {
val doc = client.newCall(GET(url)).execute().asJsoup()
val script = doc.selectFirst("script:containsData(sources)")!!
val data = script.data().substringAfter("sources: [").substringBefore("],")
return data.split("file:\"").drop(1).map { source ->
val src = source.substringBefore("\"")
val qualityHost = host.replaceFirstChar(Char::uppercase)
var quality = source.substringAfter("label:\"").substringBefore("\"")
if (quality.length > 15) { quality = "480p" }
Video(src, "$qualityHost: $quality", src)
}
}
}

View File

@ -0,0 +1,18 @@
package eu.kanade.tachiyomi.animeextension.ar.mycima.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
class UQLoadExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val check = document.selectFirst("script:containsData(sources)")!!.data()
val videoUrl = check.substringAfter("sources: [\"").substringBefore("\"")
return when{
"soruces" in check -> Video(videoUrl, "UQLoad Mirror", videoUrl).let(::listOf)
else -> emptyList()
}
}
}