mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
sff idk
This commit is contained in:
parent
68605fb563
commit
c5364ecd9a
14 changed files with 92 additions and 35 deletions
|
@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
import com.lagradost.cloudstream3.animeproviders.ShiroProvider
|
import com.lagradost.cloudstream3.animeproviders.ShiroProvider
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
@ -51,7 +52,8 @@ abstract class MainAPI {
|
||||||
return null
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.lagradost.cloudstream3
|
package com.lagradost.cloudstream3
|
||||||
|
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
@ -26,3 +28,7 @@ fun <T, R> Iterable<T>.pmap(
|
||||||
|
|
||||||
return ArrayList<R>(destination)
|
return ArrayList<R>(destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <A, B>List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {
|
||||||
|
map { async { f(it) } }.map { it.await() }
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ package com.lagradost.cloudstream3.animeproviders
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.Vidstream
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
@ -202,4 +204,13 @@ class ShiroProvider : MainAPI() {
|
||||||
null,
|
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
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,24 +10,24 @@ import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import kotlinx.android.synthetic.main.result_episode.view.*
|
import kotlinx.android.synthetic.main.result_episode.view.*
|
||||||
|
|
||||||
|
|
||||||
class EpisodeAdapter(
|
class EpisodeAdapter(
|
||||||
activity: Activity,
|
private var activity: Activity,
|
||||||
animeList: ArrayList<ResultEpisode>,
|
var cardList: ArrayList<ResultEpisode>,
|
||||||
resView: RecyclerView,
|
val resView: RecyclerView,
|
||||||
|
val clickCallback: (ResultEpisode) -> Unit
|
||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
var cardList = animeList
|
|
||||||
private var activity: Activity = activity
|
|
||||||
var resView: RecyclerView? = resView
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return CardViewHolder(
|
return CardViewHolder(
|
||||||
LayoutInflater.from(parent.context).inflate(R.layout.result_episode, parent, false),
|
LayoutInflater.from(parent.context).inflate(R.layout.result_episode, parent, false),
|
||||||
activity,
|
activity,
|
||||||
resView!!
|
resView,
|
||||||
|
clickCallback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,13 +44,14 @@ class EpisodeAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
class CardViewHolder
|
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 activity = _activity
|
||||||
val episode_view_procentage: View = itemView.episode_view_procentage
|
val episode_view_procentage: View = itemView.episode_view_procentage
|
||||||
val episode_view_procentage_off: View = itemView.episode_view_procentage_off
|
val episode_view_procentage_off: View = itemView.episode_view_procentage_off
|
||||||
val episode_text: TextView = itemView.episode_text
|
val episode_text: TextView = itemView.episode_text
|
||||||
val episode_extra: ImageView = itemView.episode_extra
|
val episode_extra: ImageView = itemView.episode_extra
|
||||||
val episode_play: ImageView = itemView.episode_play
|
val episode_play: ImageView = itemView.episode_play
|
||||||
|
val clickCallback = clickCallback
|
||||||
|
|
||||||
fun bind(card: ResultEpisode) {
|
fun bind(card: ResultEpisode) {
|
||||||
episode_text.text = card.name ?: "Episode ${card.episode}"
|
episode_text.text = card.name ?: "Episode ${card.episode}"
|
||||||
|
@ -67,7 +68,7 @@ class EpisodeAdapter(
|
||||||
setWidth(episode_view_procentage_off, 1 - card.watchProgress)
|
setWidth(episode_view_procentage_off, 1 - card.watchProgress)
|
||||||
|
|
||||||
episode_play.setOnClickListener {
|
episode_play.setOnClickListener {
|
||||||
getApiFromName(card.apiName).loadLinks(card.data, card.id)
|
clickCallback.invoke(card)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
import com.bumptech.glide.request.RequestOptions.bitmapTransform
|
import com.bumptech.glide.request.RequestOptions.bitmapTransform
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.AnimeLoadResponse
|
import com.lagradost.cloudstream3.AnimeLoadResponse
|
||||||
import com.lagradost.cloudstream3.LoadResponse
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
import com.lagradost.cloudstream3.R
|
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.UIHelper.getStatusBarHeight
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
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 jp.wasabeef.glide.transformations.BlurTransformation
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
import kotlinx.android.synthetic.main.fragment_search.*
|
import kotlinx.android.synthetic.main.fragment_search.*
|
||||||
|
@ -123,7 +126,9 @@ class ResultFragment : Fragment() {
|
||||||
it,
|
it,
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
result_episodes,
|
result_episodes,
|
||||||
)
|
) {
|
||||||
|
viewModel.loadEpisode(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result_episodes.adapter = adapter
|
result_episodes.adapter = adapter
|
||||||
|
|
|
@ -9,6 +9,7 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.MainAPI
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ResultViewModel : ViewModel() {
|
class ResultViewModel : ViewModel() {
|
||||||
|
@ -22,4 +23,20 @@ class ResultViewModel : ViewModel() {
|
||||||
|
|
||||||
_resultResponse.postValue(data)
|
_resultResponse.postValue(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val allEpisodes : MutableLiveData<HashMap<Int,ArrayList<ExtractorLink>>> = MutableLiveData()
|
||||||
|
private val _episodeResponse: MutableLiveData<Resource<Boolean>> = MutableLiveData()
|
||||||
|
val episodeResponse: LiveData<Resource<Boolean>> 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)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.cloudstream3.extractors.StreamTape
|
||||||
import com.lagradost.cloudstream3.utils.extractors.XStreamCdn
|
import com.lagradost.cloudstream3.utils.extractors.XStreamCdn
|
||||||
|
|
||||||
data class ExtractorLink(
|
data class ExtractorLink(
|
||||||
|
val source: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val url: String,
|
val url: String,
|
||||||
val referer: String,
|
val referer: String,
|
||||||
|
@ -32,7 +33,7 @@ fun getAndUnpack(string: String): String? {
|
||||||
return JsUnpacker(packedText).unpack()
|
return JsUnpacker(packedText).unpack()
|
||||||
}
|
}
|
||||||
|
|
||||||
val APIS: Array<ExtractorApi> = arrayOf(
|
val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||||
//AllProvider(),
|
//AllProvider(),
|
||||||
Shiro(),
|
Shiro(),
|
||||||
Mp4Upload(),
|
Mp4Upload(),
|
||||||
|
@ -41,6 +42,17 @@ val APIS: Array<ExtractorApi> = arrayOf(
|
||||||
XStreamCdn()
|
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 {
|
fun httpsify(url: String): String {
|
||||||
return if (url.startsWith("//")) "https:$url" else url
|
return if (url.startsWith("//")) "https:$url" else url
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ class MixDrop : ExtractorApi() {
|
||||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
return listOf(
|
return listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
name,
|
name,
|
||||||
httpsify(link),
|
httpsify(link),
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -15,6 +15,7 @@ class Mp4Upload : ExtractorApi() {
|
||||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
return listOf(
|
return listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
name,
|
name,
|
||||||
link,
|
link,
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -38,6 +38,7 @@ class MultiQuality : ExtractorApi() {
|
||||||
m3u8Regex.findAll(this.text).forEach { match ->
|
m3u8Regex.findAll(this.text).forEach { match ->
|
||||||
extractedLinksList.add(
|
extractedLinksList.add(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
"$name ${match.groupValues[1]}p",
|
"$name ${match.groupValues[1]}p",
|
||||||
urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0],
|
urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0],
|
||||||
url,
|
url,
|
||||||
|
@ -51,6 +52,7 @@ class MultiQuality : ExtractorApi() {
|
||||||
} else if (extractedUrl.endsWith(".mp4")) {
|
} else if (extractedUrl.endsWith(".mp4")) {
|
||||||
extractedLinksList.add(
|
extractedLinksList.add(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
"$name ${sourceMatch.groupValues[2]}",
|
"$name ${sourceMatch.groupValues[2]}",
|
||||||
extractedUrl,
|
extractedUrl,
|
||||||
url.replace(" ", "%20"),
|
url.replace(" ", "%20"),
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Shiro : ExtractorApi() {
|
||||||
Jsoup.parse(res).select("source").firstOrNull()?.attr("src")?.replace("&", "?")?.let {
|
Jsoup.parse(res).select("source").firstOrNull()?.attr("src")?.replace("&", "?")?.let {
|
||||||
return listOf(
|
return listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
name,
|
name,
|
||||||
it.replace(" ", "%20"),
|
it.replace(" ", "%20"),
|
||||||
"https://cherry.subsplea.se/",
|
"https://cherry.subsplea.se/",
|
||||||
|
|
|
@ -20,6 +20,7 @@ class StreamTape : ExtractorApi() {
|
||||||
val extractedUrl = "https://streamtape.com/get_video?${it.groupValues[1]}".replace("""" + '""", "")
|
val extractedUrl = "https://streamtape.com/get_video?${it.groupValues[1]}".replace("""" + '""", "")
|
||||||
return listOf(
|
return listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
name,
|
name,
|
||||||
extractedUrl,
|
extractedUrl,
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package com.lagradost.cloudstream3.utils.extractors
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.pmap
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.APIS
|
import com.lagradost.cloudstream3.utils.extractorApis
|
||||||
import com.lagradost.cloudstream3.utils.extractors.MultiQuality
|
|
||||||
import com.lagradost.cloudstream3.utils.extractors.Shiro
|
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
class Vidstream {
|
class Vidstream {
|
||||||
|
@ -13,9 +12,10 @@ class Vidstream {
|
||||||
private fun getExtractorUrl(id: String): String {
|
private fun getExtractorUrl(id: String): String {
|
||||||
return "$mainUrl/streaming.php?id=$id"
|
return "$mainUrl/streaming.php?id=$id"
|
||||||
}
|
}
|
||||||
|
private val normalApis = arrayListOf(Shiro(), MultiQuality())
|
||||||
|
|
||||||
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
||||||
fun getUrl(id: String, isCasting: Boolean = false): List<ExtractorLink> {
|
fun getUrl(id: String, isCasting: Boolean = false, callback: (ExtractorLink) -> Unit) : Boolean {
|
||||||
try {
|
try {
|
||||||
val url = getExtractorUrl(id)
|
val url = getExtractorUrl(id)
|
||||||
with(khttp.get(url)) {
|
with(khttp.get(url)) {
|
||||||
|
@ -23,15 +23,11 @@ class Vidstream {
|
||||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
|
|
||||||
// --- Shiro ---
|
normalApis.pmap { api ->
|
||||||
val shiroUrl = Shiro().getExtractorUrl(id)
|
val url = api.getExtractorUrl(id)
|
||||||
val shiroSource = Shiro().getUrl(shiroUrl)
|
val source = api.getUrl(url)
|
||||||
shiroSource?.forEach { extractedLinksList.add(it) }
|
source?.forEach { callback.invoke(it) }
|
||||||
// --- MultiQuality ---
|
}
|
||||||
val multiQualityUrl = MultiQuality().getExtractorUrl(id)
|
|
||||||
val multiQualitySource = MultiQuality().getUrl(multiQualityUrl)
|
|
||||||
multiQualitySource?.forEach { extractedLinksList.add(it) }
|
|
||||||
// --------------------
|
|
||||||
|
|
||||||
// All vidstream links passed to extractors
|
// All vidstream links passed to extractors
|
||||||
primaryLinks.forEach { element ->
|
primaryLinks.forEach { element ->
|
||||||
|
@ -39,21 +35,21 @@ class Vidstream {
|
||||||
//val name = element.text()
|
//val name = element.text()
|
||||||
|
|
||||||
// Matches vidstream links with extractors
|
// Matches vidstream links with extractors
|
||||||
APIS.filter { !it.requiresReferer || !isCasting}.forEach { api ->
|
extractorApis.filter { !it.requiresReferer || !isCasting}.pmap { api ->
|
||||||
if (link.startsWith(api.mainUrl)) {
|
if (link.startsWith(api.mainUrl)) {
|
||||||
val extractedLinks = api.getUrl(link, url)
|
val extractedLinks = api.getUrl(link, url)
|
||||||
if (extractedLinks?.isNotEmpty() == true) {
|
if (extractedLinks?.isNotEmpty() == true) {
|
||||||
extractedLinks.forEach {
|
extractedLinks.forEach {
|
||||||
extractedLinksList.add(it)
|
callback.invoke(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return extractedLinksList
|
return true
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return listOf()
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -51,6 +51,7 @@ class XStreamCdn : ExtractorApi() {
|
||||||
it.data.forEach { data ->
|
it.data.forEach { data ->
|
||||||
extractedLinksList.add(
|
extractedLinksList.add(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
name,
|
||||||
"$name ${data.label}",
|
"$name ${data.label}",
|
||||||
data.file,
|
data.file,
|
||||||
url,
|
url,
|
||||||
|
|
Loading…
Reference in a new issue