diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 001ee701..919ccbd2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.KotlinModule import com.lagradost.cloudstream3.animeproviders.ShiroProvider +import com.lagradost.cloudstream3.utils.ExtractorLink import java.util.* import kotlin.collections.ArrayList @@ -51,7 +52,8 @@ abstract class MainAPI { return null } - open fun loadLinks(data: Any, id: Int): Boolean { + // callback is fired once a link is found, will return true if method is executed successfully + open fun loadLinks(data: Any, isCasting : Boolean, callback: (ExtractorLink) -> Unit): Boolean { return false } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt b/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt index f5266777..ea592c15 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ParCollections.kt @@ -1,5 +1,7 @@ package com.lagradost.cloudstream3 +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking import java.util.* import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -25,4 +27,8 @@ fun Iterable.pmap( exec.awaitTermination(1, TimeUnit.DAYS) return ArrayList(destination) +} + +fun List.apmap(f: suspend (A) -> B): List = runBlocking { + map { async { f(it) } }.map { it.await() } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt index 5a8ab982..91197a09 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt @@ -3,6 +3,8 @@ package com.lagradost.cloudstream3.animeproviders import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.extractors.Vidstream import java.net.URLEncoder import java.util.* import kotlin.collections.ArrayList @@ -153,7 +155,7 @@ class ShiroProvider : MainAPI() { val episodeCount = i.episodeCount.toInt() returnValue.add(AnimeSearchResponse( - i.name.replace("Dubbed",""), // i.english ?: i.canonicalTitle, + i.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle, "$mainUrl/${i.slug}", i.slug, this.name, @@ -202,4 +204,13 @@ class ShiroProvider : MainAPI() { null, ) } + + override fun loadLinks(data: Any, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean { + if (data is ShiroEpisodes) { + return Vidstream().getUrl(data._id, isCasting) { + callback.invoke(it) + } + } + return false + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index 0b542369..725a2387 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -10,24 +10,24 @@ import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.getApiFromName +import com.lagradost.cloudstream3.utils.ExtractorLink import kotlinx.android.synthetic.main.result_episode.view.* class EpisodeAdapter( - activity: Activity, - animeList: ArrayList, - resView: RecyclerView, + private var activity: Activity, + var cardList: ArrayList, + val resView: RecyclerView, + val clickCallback: (ResultEpisode) -> Unit ) : RecyclerView.Adapter() { - var cardList = animeList - private var activity: Activity = activity - var resView: RecyclerView? = resView override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return CardViewHolder( LayoutInflater.from(parent.context).inflate(R.layout.result_episode, parent, false), activity, - resView!! + resView, + clickCallback ) } @@ -44,13 +44,14 @@ class EpisodeAdapter( } class CardViewHolder - constructor(itemView: View, _activity: Activity, resView: RecyclerView) : RecyclerView.ViewHolder(itemView) { + constructor(itemView: View, _activity: Activity, resView: RecyclerView, clickCallback: (ResultEpisode) -> Unit) : RecyclerView.ViewHolder(itemView) { val activity = _activity val episode_view_procentage: View = itemView.episode_view_procentage val episode_view_procentage_off: View = itemView.episode_view_procentage_off val episode_text: TextView = itemView.episode_text val episode_extra: ImageView = itemView.episode_extra val episode_play: ImageView = itemView.episode_play + val clickCallback = clickCallback fun bind(card: ResultEpisode) { episode_text.text = card.name ?: "Episode ${card.episode}" @@ -67,7 +68,7 @@ class EpisodeAdapter( setWidth(episode_view_procentage_off, 1 - card.watchProgress) episode_play.setOnClickListener { - getApiFromName(card.apiName).loadLinks(card.data, card.id) + clickCallback.invoke(card) } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index d7832f9c..2707334c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -19,6 +19,7 @@ import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.request.RequestOptions.bitmapTransform +import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.AnimeLoadResponse import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.R @@ -26,6 +27,8 @@ import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar import com.lagradost.cloudstream3.UIHelper.getStatusBarHeight import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.observe +import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.utils.ExtractorLink import jp.wasabeef.glide.transformations.BlurTransformation import kotlinx.android.synthetic.main.fragment_result.* import kotlinx.android.synthetic.main.fragment_search.* @@ -70,17 +73,17 @@ class ResultFragment : Fragment() { super.onViewCreated(view, savedInstanceState) activity?.fixPaddingStatusbar(result_scroll) activity?.fixPaddingStatusbar(result_barstatus) - // activity?.fixPaddingStatusbar(result_toolbar) + // activity?.fixPaddingStatusbar(result_toolbar) val url = arguments?.getString("url") val slug = arguments?.getString("slug") val apiName = arguments?.getString("apiName") result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY -> - if(result_poster_blur == null) return@OnScrollChangeListener + if (result_poster_blur == null) return@OnScrollChangeListener result_poster_blur.alpha = maxOf(0f, (0.3f - scrollY / 1000f)) result_barstatus.alpha = scrollY / 200f - result_barstatus.visibility = if(scrollY > 0) View.VISIBLE else View.GONE + result_barstatus.visibility = if (scrollY > 0) View.VISIBLE else View.GONE }) result_toolbar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24) @@ -123,7 +126,9 @@ class ResultFragment : Fragment() { it, ArrayList(), result_episodes, - ) + ) { + viewModel.loadEpisode(it) + } } result_episodes.adapter = adapter diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt index d142eb95..495210f6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt @@ -9,17 +9,34 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.MainAPI import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.utils.ExtractorLink import kotlinx.coroutines.launch class ResultViewModel : ViewModel() { private val _resultResponse: MutableLiveData> = MutableLiveData() val resultResponse: LiveData> get() = _resultResponse - fun load(url: String, apiName:String) = viewModelScope.launch { + fun load(url: String, apiName: String) = viewModelScope.launch { val data = safeApiCall { getApiFromName(apiName).load(url) } _resultResponse.postValue(data) } + + val allEpisodes : MutableLiveData>> = MutableLiveData() + private val _episodeResponse: MutableLiveData> = MutableLiveData() + val episodeResponse: LiveData> get() = _episodeResponse + + fun loadEpisode(episode: ResultEpisode) = viewModelScope.launch { + if(allEpisodes.value?.contains(episode.id) == true) { + allEpisodes.value?.remove(episode.id) + } + val data = safeApiCall { + getApiFromName(episode.apiName).loadLinks(episode.data, false) { //TODO IMPLEMENT CASTING + allEpisodes.value?.get(episode.id)?.add(it) + } + } + _episodeResponse.postValue(data) + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index be0e33e8..dd1a51d2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.cloudstream3.extractors.StreamTape import com.lagradost.cloudstream3.utils.extractors.XStreamCdn data class ExtractorLink( + val source: String, val name: String, val url: String, val referer: String, @@ -32,7 +33,7 @@ fun getAndUnpack(string: String): String? { return JsUnpacker(packedText).unpack() } -val APIS: Array = arrayOf( +val extractorApis: Array = arrayOf( //AllProvider(), Shiro(), Mp4Upload(), @@ -41,6 +42,17 @@ val APIS: Array = arrayOf( XStreamCdn() ) +fun getExtractorApiFromName(name: String): ExtractorApi { + for (api in extractorApis) { + if (api.name == name) return api + } + return extractorApis[0] +} + +fun requireReferer(name: String): Boolean { + return getExtractorApiFromName(name).requiresReferer +} + fun httpsify(url: String): String { return if (url.startsWith("//")) "https:$url" else url } @@ -52,7 +64,7 @@ abstract class ExtractorApi { abstract fun getUrl(url: String, referer: String? = null): List? - open fun getExtractorUrl(id: String): String{ + open fun getExtractorUrl(id: String): String { return id } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt index 9340e042..0dcdd040 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt @@ -19,6 +19,7 @@ class MixDrop : ExtractorApi() { srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> return listOf( ExtractorLink( + name, name, httpsify(link), url, diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt index f7f7ae99..188e9735 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt @@ -15,6 +15,7 @@ class Mp4Upload : ExtractorApi() { srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> return listOf( ExtractorLink( + name, name, link, url, diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt index 93c2b603..df668356 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt @@ -38,6 +38,7 @@ class MultiQuality : ExtractorApi() { m3u8Regex.findAll(this.text).forEach { match -> extractedLinksList.add( ExtractorLink( + name, "$name ${match.groupValues[1]}p", urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0], url, @@ -51,6 +52,7 @@ class MultiQuality : ExtractorApi() { } else if (extractedUrl.endsWith(".mp4")) { extractedLinksList.add( ExtractorLink( + name, "$name ${sourceMatch.groupValues[2]}", extractedUrl, url.replace(" ", "%20"), diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Shiro.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Shiro.kt index 903e017f..ed113f8a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Shiro.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Shiro.kt @@ -20,6 +20,7 @@ class Shiro : ExtractorApi() { Jsoup.parse(res).select("source").firstOrNull()?.attr("src")?.replace("&", "?")?.let { return listOf( ExtractorLink( + name, name, it.replace(" ", "%20"), "https://cherry.subsplea.se/", diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt index a8c15955..f284c779 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt @@ -20,6 +20,7 @@ class StreamTape : ExtractorApi() { val extractedUrl = "https://streamtape.com/get_video?${it.groupValues[1]}".replace("""" + '""", "") return listOf( ExtractorLink( + name, name, extractedUrl, url, diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt index 2a3abebc..1d61c40e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt @@ -1,9 +1,8 @@ package com.lagradost.cloudstream3.utils.extractors +import com.lagradost.cloudstream3.pmap import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.APIS -import com.lagradost.cloudstream3.utils.extractors.MultiQuality -import com.lagradost.cloudstream3.utils.extractors.Shiro +import com.lagradost.cloudstream3.utils.extractorApis import org.jsoup.Jsoup class Vidstream { @@ -13,9 +12,10 @@ class Vidstream { private fun getExtractorUrl(id: String): String { return "$mainUrl/streaming.php?id=$id" } + private val normalApis = arrayListOf(Shiro(), MultiQuality()) // https://gogo-stream.com/streaming.php?id=MTE3NDg5 - fun getUrl(id: String, isCasting: Boolean = false): List { + fun getUrl(id: String, isCasting: Boolean = false, callback: (ExtractorLink) -> Unit) : Boolean { try { val url = getExtractorUrl(id) with(khttp.get(url)) { @@ -23,15 +23,11 @@ class Vidstream { val primaryLinks = document.select("ul.list-server-items > li.linkserver") val extractedLinksList: MutableList = mutableListOf() - // --- Shiro --- - val shiroUrl = Shiro().getExtractorUrl(id) - val shiroSource = Shiro().getUrl(shiroUrl) - shiroSource?.forEach { extractedLinksList.add(it) } - // --- MultiQuality --- - val multiQualityUrl = MultiQuality().getExtractorUrl(id) - val multiQualitySource = MultiQuality().getUrl(multiQualityUrl) - multiQualitySource?.forEach { extractedLinksList.add(it) } - // -------------------- + normalApis.pmap { api -> + val url = api.getExtractorUrl(id) + val source = api.getUrl(url) + source?.forEach { callback.invoke(it) } + } // All vidstream links passed to extractors primaryLinks.forEach { element -> @@ -39,21 +35,21 @@ class Vidstream { //val name = element.text() // Matches vidstream links with extractors - APIS.filter { !it.requiresReferer || !isCasting}.forEach { api -> + extractorApis.filter { !it.requiresReferer || !isCasting}.pmap { api -> if (link.startsWith(api.mainUrl)) { val extractedLinks = api.getUrl(link, url) if (extractedLinks?.isNotEmpty() == true) { extractedLinks.forEach { - extractedLinksList.add(it) + callback.invoke(it) } } } } } - return extractedLinksList + return true } } catch (e: Exception) { - return listOf() + return false } } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt index f0af4ce5..acf8896b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt @@ -51,6 +51,7 @@ class XStreamCdn : ExtractorApi() { it.data.forEach { data -> extractedLinksList.add( ExtractorLink( + name, "$name ${data.label}", data.file, url,