forked from recloudstream/cloudstream
		
	Merge remote-tracking branch 'origin/master'
# Conflicts: # app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmpertuttiProvider.kt
This commit is contained in:
		
						commit
						c7531faceb
					
				
					 13 changed files with 176 additions and 136 deletions
				
			
		|  | @ -108,7 +108,7 @@ dependencies { | ||||||
| 
 | 
 | ||||||
|     //implementation "io.karn:khttp-android:0.1.2" //okhttp instead |     //implementation "io.karn:khttp-android:0.1.2" //okhttp instead | ||||||
| //    implementation 'org.jsoup:jsoup:1.13.1' | //    implementation 'org.jsoup:jsoup:1.13.1' | ||||||
| //    implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3" |     implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1" | ||||||
| 
 | 
 | ||||||
|     implementation "androidx.preference:preference-ktx:1.2.0" |     implementation "androidx.preference:preference-ktx:1.2.0" | ||||||
| 
 | 
 | ||||||
|  | @ -156,7 +156,7 @@ dependencies { | ||||||
|     // Networking |     // Networking | ||||||
| //    implementation "com.squareup.okhttp3:okhttp:4.9.2" | //    implementation "com.squareup.okhttp3:okhttp:4.9.2" | ||||||
| //    implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1" | //    implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1" | ||||||
|     implementation 'com.github.Blatzar:NiceHttp:0.2.0' |     implementation 'com.github.Blatzar:NiceHttp:0.3.2' | ||||||
| 
 | 
 | ||||||
|     // Util to skip the URI file fuckery 🙏 |     // Util to skip the URI file fuckery 🙏 | ||||||
|     implementation "com.github.tachiyomiorg:unifile:17bec43" |     implementation "com.github.tachiyomiorg:unifile:17bec43" | ||||||
|  |  | ||||||
|  | @ -21,6 +21,9 @@ import androidx.navigation.NavOptions | ||||||
| import androidx.navigation.fragment.NavHostFragment | import androidx.navigation.fragment.NavHostFragment | ||||||
| import androidx.navigation.ui.setupWithNavController | import androidx.navigation.ui.setupWithNavController | ||||||
| import androidx.preference.PreferenceManager | import androidx.preference.PreferenceManager | ||||||
|  | import com.fasterxml.jackson.databind.DeserializationFeature | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper | ||||||
|  | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper | ||||||
| import com.google.android.gms.cast.framework.* | import com.google.android.gms.cast.framework.* | ||||||
| import com.google.android.material.navigationrail.NavigationRailView | import com.google.android.material.navigationrail.NavigationRailView | ||||||
| import com.jaredrummler.android.colorpicker.ColorPickerDialogListener | import com.jaredrummler.android.colorpicker.ColorPickerDialogListener | ||||||
|  | @ -75,6 +78,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.navigate | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.requestRW | import com.lagradost.cloudstream3.utils.UIHelper.requestRW | ||||||
| import com.lagradost.cloudstream3.utils.USER_PROVIDER_API | import com.lagradost.cloudstream3.utils.USER_PROVIDER_API | ||||||
| import com.lagradost.nicehttp.Requests | import com.lagradost.nicehttp.Requests | ||||||
|  | import com.lagradost.nicehttp.ResponseParser | ||||||
| import kotlinx.android.synthetic.main.activity_main.* | import kotlinx.android.synthetic.main.activity_main.* | ||||||
| import kotlinx.android.synthetic.main.fragment_result_swipe.* | import kotlinx.android.synthetic.main.fragment_result_swipe.* | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
|  | @ -83,6 +87,7 @@ import kotlinx.coroutines.withContext | ||||||
| import org.schabi.newpipe.extractor.NewPipe | import org.schabi.newpipe.extractor.NewPipe | ||||||
| import java.io.File | import java.io.File | ||||||
| import kotlin.concurrent.thread | import kotlin.concurrent.thread | ||||||
|  | import kotlin.reflect.KClass | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| const val VLC_PACKAGE = "org.videolan.vlc" | const val VLC_PACKAGE = "org.videolan.vlc" | ||||||
|  | @ -98,7 +103,29 @@ const val VLC_EXTRA_DURATION_OUT = "extra_duration" | ||||||
| const val VLC_LAST_ID_KEY = "vlc_last_open_id" | const val VLC_LAST_ID_KEY = "vlc_last_open_id" | ||||||
| 
 | 
 | ||||||
| // Short name for requests client to make it nicer to use | // Short name for requests client to make it nicer to use | ||||||
| var app = Requests().apply { | 
 | ||||||
|  | var app = Requests(responseParser = object : ResponseParser { | ||||||
|  |     val mapper: ObjectMapper = jacksonObjectMapper().configure( | ||||||
|  |         DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, | ||||||
|  |         false | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     override fun <T : Any> parse(text: String, kClass: KClass<T>): T { | ||||||
|  |         return mapper.readValue(text, kClass.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun <T : Any> parseSafe(text: String, kClass: KClass<T>): T? { | ||||||
|  |         return try { | ||||||
|  |             mapper.readValue(text, kClass.java) | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             null | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun writeValueAsString(obj: Any): String { | ||||||
|  |         return mapper.writeValueAsString(obj) | ||||||
|  |     } | ||||||
|  | }).apply { | ||||||
|     defaultHeaders = mapOf("user-agent" to USER_AGENT) |     defaultHeaders = mapOf("user-agent" to USER_AGENT) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -312,7 +312,7 @@ class AllAnimeProvider : MainAPI() { | ||||||
|         @JsonProperty("episodeIframeHead") val episodeIframeHead: String |         @JsonProperty("episodeIframeHead") val episodeIframeHead: String | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private fun getM3u8Qualities( |     private suspend fun getM3u8Qualities( | ||||||
|         m3u8Link: String, |         m3u8Link: String, | ||||||
|         referer: String, |         referer: String, | ||||||
|         qualityName: String, |         qualityName: String, | ||||||
|  |  | ||||||
|  | @ -91,7 +91,7 @@ class KawaiifuProvider : MainAPI() { | ||||||
|         val title = soup.selectFirst(".title")!!.text() |         val title = soup.selectFirst(".title")!!.text() | ||||||
|         val tags = soup.select(".table a[href*=\"/tag/\"]").map { tag -> tag.text() } |         val tags = soup.select(".table a[href*=\"/tag/\"]").map { tag -> tag.text() } | ||||||
|         val description = soup.select(".sub-desc p") |         val description = soup.select(".sub-desc p") | ||||||
|             .filter { it.select("strong").isEmpty() && it.select("iframe").isEmpty() } |             .filter { it -> it.select("strong").isEmpty() && it.select("iframe").isEmpty() } | ||||||
|             .joinToString("\n") { it.text() } |             .joinToString("\n") { it.text() } | ||||||
|         val year = url.split("/").filter { it.contains("-") }[0].split("-")[1].toIntOrNull() |         val year = url.split("/").filter { it.contains("-") }[0].split("-")[1].toIntOrNull() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -72,7 +72,7 @@ class WatchCartoonOnlineProvider : MainAPI() { | ||||||
|             ).text |             ).text | ||||||
|         document = Jsoup.parse(response) |         document = Jsoup.parse(response) | ||||||
|         items = document.select("#catlist-listview2 > ul > li") |         items = document.select("#catlist-listview2 > ul > li") | ||||||
|             .filter { it?.text() != null && !it.text().toString().contains("Episode") } |             .filter { it -> it?.text() != null && !it.text().toString().contains("Episode") } | ||||||
| 
 | 
 | ||||||
|         for (item in items) { |         for (item in items) { | ||||||
|             val titleHeader = item.selectFirst("a") |             val titleHeader = item.selectFirst("a") | ||||||
|  |  | ||||||
|  | @ -144,7 +144,7 @@ class AltadefinizioneProvider : MainAPI() { | ||||||
|         val doc = app.get(data).document |         val doc = app.get(data).document | ||||||
|         if (doc.select("div.guardahd-player").isNullOrEmpty()) { |         if (doc.select("div.guardahd-player").isNullOrEmpty()) { | ||||||
|             val videoUrl = |             val videoUrl = | ||||||
|                 doc.select("input").filter { it.hasAttr("data-mirror") }.last().attr("value") |                 doc.select("input").last { it.hasAttr("data-mirror") }.attr("value") | ||||||
|             loadExtractor(videoUrl, data, subtitleCallback, callback) |             loadExtractor(videoUrl, data, subtitleCallback, callback) | ||||||
|             doc.select("#mirrors > li > a").forEach { |             doc.select("#mirrors > li > a").forEach { | ||||||
|                 loadExtractor(fixUrl(it.attr("data-target")), data, subtitleCallback, callback) |                 loadExtractor(fixUrl(it.attr("data-target")), data, subtitleCallback, callback) | ||||||
|  |  | ||||||
|  | @ -126,7 +126,7 @@ class CineblogProvider : MainAPI() { | ||||||
|             val episodeList = ArrayList<Episode>() |             val episodeList = ArrayList<Episode>() | ||||||
|             document.select("#seasons > div").reversed().map { element -> |             document.select("#seasons > div").reversed().map { element -> | ||||||
|                 val season = element.selectFirst("div.se-q > span.se-t")!!.text().toInt() |                 val season = element.selectFirst("div.se-q > span.se-t")!!.text().toInt() | ||||||
|                 element.select("div.se-a > ul > li").filter { it.text()!="There are still no episodes this season" }.map{ episode -> |                 element.select("div.se-a > ul > li").filter { it -> it.text()!="There are still no episodes this season" }.map{ episode -> | ||||||
|                     val href = episode.selectFirst("div.episodiotitle > a")!!.attr("href") |                     val href = episode.selectFirst("div.episodiotitle > a")!!.attr("href") | ||||||
|                     val epNum =episode.selectFirst("div.numerando")!!.text().substringAfter("-").filter { it.isDigit() }.toIntOrNull() |                     val epNum =episode.selectFirst("div.numerando")!!.text().substringAfter("-").filter { it.isDigit() }.toIntOrNull() | ||||||
|                     val epTitle = episode.selectFirst("div.episodiotitle > a")!!.text() |                     val epTitle = episode.selectFirst("div.episodiotitle > a")!!.text() | ||||||
|  | @ -160,7 +160,7 @@ class CineblogProvider : MainAPI() { | ||||||
|             ) |             ) | ||||||
|         } else { |         } else { | ||||||
|             val actors: List<ActorData> = |             val actors: List<ActorData> = | ||||||
|                 document.select("div.person").filter{it.selectFirst("div.img > a > img")?.attr("src")!!.contains("/no/cast.png").not()}.map { actordata -> |                 document.select("div.person").filter{ it -> it.selectFirst("div.img > a > img")?.attr("src")!!.contains("/no/cast.png").not()}.map { actordata -> | ||||||
|                     val actorName = actordata.selectFirst("div.data > div.name > a")!!.text() |                     val actorName = actordata.selectFirst("div.data > div.name > a")!!.text() | ||||||
|                     val actorImage : String? = actordata.selectFirst("div.img > a > img")?.attr("src") |                     val actorImage : String? = actordata.selectFirst("div.img > a > img")?.attr("src") | ||||||
|                     val roleActor = actordata.selectFirst("div.data > div.caracter")!!.text() |                     val roleActor = actordata.selectFirst("div.data > div.caracter")!!.text() | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| package com.lagradost.cloudstream3.movieproviders | package com.lagradost.cloudstream3.movieproviders | ||||||
| 
 |  | ||||||
| import androidx.core.text.parseAsHtml | import androidx.core.text.parseAsHtml | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addRating | import com.lagradost.cloudstream3.LoadResponse.Companion.addRating | ||||||
|  | @ -65,8 +64,7 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|         val url = "$mainUrl/?s=$queryformatted" |         val url = "$mainUrl/?s=$queryformatted" | ||||||
|         val doc = app.get(url).document |         val doc = app.get(url).document | ||||||
|         return doc.select("ul.posts > li").map { |         return doc.select("ul.posts > li").map { | ||||||
|             val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(") |             val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(").substringBeforeLast("[") | ||||||
|                 .substringBeforeLast("[") |  | ||||||
|             val link = it.selectFirst("a")!!.attr("href") |             val link = it.selectFirst("a")!!.attr("href") | ||||||
|             val image = it.selectFirst("a")!!.attr("data-thumbnail") |             val image = it.selectFirst("a")!!.attr("data-thumbnail") | ||||||
|             val quality = getQualityFromString(it.selectFirst("div.hd")?.text()) |             val quality = getQualityFromString(it.selectFirst("div.hd")?.text()) | ||||||
|  | @ -90,36 +88,28 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|         val title = document.selectFirst("#content > h1")!!.text().substringBeforeLast("(") |         val title = document.selectFirst("#content > h1")!!.text().substringBeforeLast("(") | ||||||
|             .substringBeforeLast("[") |             .substringBeforeLast("[") | ||||||
| 
 | 
 | ||||||
|         val description = |         val description = document.selectFirst("i.fa.fa-file-text-o.fa-fw")?.parent()?.nextSibling()?.toString()?.parseAsHtml().toString() | ||||||
|             document.selectFirst("i.fa.fa-file-text-o.fa-fw")?.parent()?.nextSibling()?.toString() |  | ||||||
|                 ?.parseAsHtml().toString() |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         val rating = document.selectFirst("div.rating > div.value")?.text() |         val rating = document.selectFirst("div.rating > div.value")?.text() | ||||||
| 
 | 
 | ||||||
|         val year = |         val year = | ||||||
|             document.selectFirst("#content > h1")?.text()?.substringAfterLast("(") |             document.selectFirst("#content > h1")?.text()?.substringAfterLast("(")?.filter { it.isDigit() }?.toIntOrNull() ?: | ||||||
|                 ?.filter { it.isDigit() }?.toIntOrNull() |             description.substringAfter("trasmessa nel").take(6).filter { it.isDigit() }.toIntOrNull() ?: | ||||||
|                 ?: description.substringAfter("trasmessa nel").take(6).filter { it.isDigit() } |             (document.selectFirst("i.fa.fa-calendar.fa-fw")?.parent()?.nextSibling() as Element?)?.text()?.substringAfterLast(" ")?.filter { it.isDigit() }?.toIntOrNull() | ||||||
|                     .toIntOrNull() ?: (document.selectFirst("i.fa.fa-calendar.fa-fw")?.parent() |  | ||||||
|                     ?.nextSibling() as Element?)?.text()?.substringAfterLast(" ") |  | ||||||
|                     ?.filter { it.isDigit() }?.toIntOrNull() |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         val poster = document.selectFirst("div.meta > div > img")?.attr("data-src") |         val poster = document.selectFirst("div.meta > div > img")?.attr("data-src") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         val trailerurl = |         val trailerurl = document.selectFirst("div.youtube-player")?.attr("data-id")?.let{ urldata-> | ||||||
|             document.selectFirst("div.youtube-player")?.attr("data-id")?.let { urldata -> |  | ||||||
|             "https://www.youtube.com/watch?v=$urldata" |             "https://www.youtube.com/watch?v=$urldata" | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (type == TvType.TvSeries) { |         if (type == TvType.TvSeries) { | ||||||
| 
 | 
 | ||||||
|             val episodeList = ArrayList<Episode>() |             val episodeList = ArrayList<Episode>() | ||||||
|             document.select("div.accordion-item") |             document.select("div.accordion-item").filter{it.selectFirst("#season > ul > li.s_title > span")!!.text().isNotEmpty()}.map { element -> | ||||||
|                 .filter { it.selectFirst("#season > ul > li.s_title > span")!!.text().isNotEmpty() } |  | ||||||
|                 .map { element -> |  | ||||||
|                 val season = |                 val season = | ||||||
|                     element.selectFirst("#season > ul > li.s_title > span")!!.text().toInt() |                     element.selectFirst("#season > ul > li.s_title > span")!!.text().toInt() | ||||||
|                 element.select("div.episode-wrap").map { episode -> |                 element.select("div.episode-wrap").map { episode -> | ||||||
|  | @ -157,10 +147,8 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|             val urls0 = document.select("div.embed-player") |             val urls0 = document.select("div.embed-player") | ||||||
|             val urls = if (urls0.isNotEmpty()){ |             val urls = if (urls0.isNotEmpty()){ | ||||||
|                     urls0.map { it.attr("data-id") }.toJson() |                     urls0.map { it.attr("data-id") }.toJson() | ||||||
|             } else { |  | ||||||
|                 document.select("#info > ul > li ").mapNotNull { it.selectFirst("a")?.attr("href") } |  | ||||||
|                     .toJson() |  | ||||||
|                 } |                 } | ||||||
|  |             else{ document.select("#info > ul > li ").mapNotNull { it.selectFirst("a")?.attr("href") }.toJson() } | ||||||
| 
 | 
 | ||||||
|             return newMovieLoadResponse( |             return newMovieLoadResponse( | ||||||
|                 title, |                 title, | ||||||
|  | @ -185,18 +173,15 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|         when{ |         when{ | ||||||
|             uri.contains("/tv/") -> uri = uri.replace("/tv/", "/tva/") |             uri.contains("/tv/") -> uri = uri.replace("/tv/", "/tva/") | ||||||
|             uri.contains("delta") -> uri = uri.replace("/delta/", "/adelta/") |             uri.contains("delta") -> uri = uri.replace("/delta/", "/adelta/") | ||||||
|             (uri.contains("/ga/") || uri.contains("/ga2/")) -> uri = |             (uri.contains("/ga/") || uri.contains("/ga2/")) -> uri = base64Decode(uri.split('/').last()).trim() | ||||||
|                 base64Decode(uri.split('/').last()).trim() |             uri.contains("/speedx/") -> uri = uri.replace("http://linkup.pro/speedx", "http://speedvideo.net") | ||||||
|             uri.contains("/speedx/") -> uri = |  | ||||||
|                 uri.replace("http://linkup.pro/speedx", "http://speedvideo.net") |  | ||||||
|             else -> { |             else -> { | ||||||
|                 r = app.get(uri, allowRedirects = true) |                 r = app.get(uri, allowRedirects = true) | ||||||
|                 uri = r.url |                 uri = r.url | ||||||
|                 val link = |                 val link = | ||||||
|                     Regex("<iframe[^<>]*src=\\'([^'>]*)\\'[^<>]*>").find(r.text)?.value |                     Regex("<iframe[^<>]*src=\\'([^'>]*)\\'[^<>]*>").find(r.text)?.value ?: | ||||||
|                         ?: Regex("""action="(?:[^/]+.*?/[^/]+/([a-zA-Z0-9_]+))">""").find(r.text)?.value |                     Regex("""action="(?:[^/]+.*?/[^/]+/([a-zA-Z0-9_]+))">""").find(r.text)?.value ?: | ||||||
|                         ?: Regex("""href","((.|\\n)*?)"""").findAll(r.text) |                     Regex("""href","((.|\\n)*?)"""").findAll(r.text).elementAtOrNull(1)?.groupValues?.get(1) | ||||||
|                             .elementAtOrNull(1)?.groupValues?.get(1) |  | ||||||
| 
 | 
 | ||||||
|                 if (link!=null) { |                 if (link!=null) { | ||||||
|                     uri = link |                     uri = link | ||||||
|  | @ -211,8 +196,7 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|         if (r==null){ |         if (r==null){ | ||||||
|             r = app.get( |             r = app.get( | ||||||
|                 uri, |                 uri, | ||||||
|                 allowRedirects = false |                 allowRedirects = false) | ||||||
|             ) |  | ||||||
|             if (r.headers["location"]!= null){ |             if (r.headers["location"]!= null){ | ||||||
|                 uri = r.headers["location"].toString() |                 uri = r.headers["location"].toString() | ||||||
|             } |             } | ||||||
|  | @ -220,7 +204,8 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|         if (uri.contains("snip.")) { |         if (uri.contains("snip.")) { | ||||||
|             if (uri.contains("out_generator")) { |             if (uri.contains("out_generator")) { | ||||||
|                 uri = Regex("url=(.*)\$").find(uri)!!.value |                 uri = Regex("url=(.*)\$").find(uri)!!.value | ||||||
|             } else if (uri.contains("/decode/")) { |             } | ||||||
|  |             else if (uri.contains("/decode/")) { | ||||||
|                 uri = app.get(uri, allowRedirects = true).url |                 uri = app.get(uri, allowRedirects = true).url | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -238,11 +223,13 @@ class FilmpertuttiProvider : MainAPI() { | ||||||
|             if (id.contains("buckler")){ |             if (id.contains("buckler")){ | ||||||
|                 val id2 = unshorten_linkup(id).trim().replace("/v/","/e/").replace("/f/","/e/") |                 val id2 = unshorten_linkup(id).trim().replace("/v/","/e/").replace("/f/","/e/") | ||||||
|                 loadExtractor(id2, data, subtitleCallback, callback) |                 loadExtractor(id2, data, subtitleCallback, callback) | ||||||
|             } else if (id.contains("isecure")) { |             } | ||||||
|  |             else if (id.contains("isecure")){ | ||||||
|                 val doc1 = app.get(id).document |                 val doc1 = app.get(id).document | ||||||
|                 val id2 = doc1.selectFirst("iframe")!!.attr("src") |                 val id2 = doc1.selectFirst("iframe")!!.attr("src") | ||||||
|                 loadExtractor(id2, data, subtitleCallback, callback) |                 loadExtractor(id2, data, subtitleCallback, callback) | ||||||
|             } else { |             } | ||||||
|  |             else{ | ||||||
|                 loadExtractor(id, data, subtitleCallback, callback) |                 loadExtractor(id, data, subtitleCallback, callback) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,8 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addActors | ||||||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration | import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration | ||||||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer | ||||||
| import com.lagradost.cloudstream3.animeproviders.ZoroProvider | import com.lagradost.cloudstream3.animeproviders.ZoroProvider | ||||||
|  | import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||||
|  | import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||||
| import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall | import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson | ||||||
|  | @ -584,7 +586,7 @@ open class SflixProvider : MainAPI() { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // For re-use in Zoro |         // For re-use in Zoro | ||||||
|         private fun Sources.toExtractorLink( |         private suspend fun Sources.toExtractorLink( | ||||||
|             caller: MainAPI, |             caller: MainAPI, | ||||||
|             name: String, |             name: String, | ||||||
|             extractorData: String? = null, |             extractorData: String? = null, | ||||||
|  | @ -595,8 +597,15 @@ open class SflixProvider : MainAPI() { | ||||||
|                     "hls", |                     "hls", | ||||||
|                     ignoreCase = true |                     ignoreCase = true | ||||||
|                 ) |                 ) | ||||||
|                 if (isM3u8) { |                 return if (isM3u8) { | ||||||
|                     M3u8Helper().m3u8Generation(M3u8Helper.M3u8Stream(this.file, null), null) |                     suspendSafeApiCall { | ||||||
|  |                         M3u8Helper().m3u8Generation( | ||||||
|  |                             M3u8Helper.M3u8Stream( | ||||||
|  |                                 this.file, | ||||||
|  |                                 null, | ||||||
|  |                                 mapOf("Referer" to "https://mzzcloud.life/") | ||||||
|  |                             ), false | ||||||
|  |                         ) | ||||||
|                             .map { stream -> |                             .map { stream -> | ||||||
|                                 ExtractorLink( |                                 ExtractorLink( | ||||||
|                                     caller.name, |                                     caller.name, | ||||||
|  | @ -608,6 +617,18 @@ open class SflixProvider : MainAPI() { | ||||||
|                                     extractorData = extractorData |                                     extractorData = extractorData | ||||||
|                                 ) |                                 ) | ||||||
|                             } |                             } | ||||||
|  |                     } ?: listOf( | ||||||
|  |                         // Fallback if m3u8 extractor fails | ||||||
|  |                         ExtractorLink( | ||||||
|  |                             caller.name, | ||||||
|  |                             "${caller.name} $name", | ||||||
|  |                             this.file, | ||||||
|  |                             caller.mainUrl, | ||||||
|  |                             getQualityFromName(this.label), | ||||||
|  |                             isM3u8, | ||||||
|  |                             extractorData = extractorData | ||||||
|  |                         ) | ||||||
|  |                     ) | ||||||
|                 } else { |                 } else { | ||||||
|                     listOf( |                     listOf( | ||||||
|                         ExtractorLink( |                         ExtractorLink( | ||||||
|  |  | ||||||
|  | @ -398,7 +398,7 @@ class StreamingcommunityProvider : MainAPI() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     private fun getM3u8Qualities( |     private suspend fun getM3u8Qualities( | ||||||
|         m3u8Link: String, |         m3u8Link: String, | ||||||
|         referer: String, |         referer: String, | ||||||
|         qualityName: String, |         qualityName: String, | ||||||
|  |  | ||||||
|  | @ -163,7 +163,7 @@ class TantifilmProvider : MainAPI() { | ||||||
|             val actors: List<ActorData>? = if (Linkactor.isNotEmpty()) { |             val actors: List<ActorData>? = if (Linkactor.isNotEmpty()) { | ||||||
|                 val actorpage = app.get(Linkactor + "cast/").document |                 val actorpage = app.get(Linkactor + "cast/").document | ||||||
|                 actorpage.select("article.membro-cast").filter { |                 actorpage.select("article.membro-cast").filter { | ||||||
|                     it.selectFirst("img") |                     it -> it.selectFirst("img") | ||||||
|                         ?.attr("src") != "https://www.filmtv.it/imgbank/DUMMY/no_portrait.jpg" |                         ?.attr("src") != "https://www.filmtv.it/imgbank/DUMMY/no_portrait.jpg" | ||||||
|                 }.mapNotNull { |                 }.mapNotNull { | ||||||
|                     val name = it.selectFirst("div.info > h3")!!.text() |                     val name = it.selectFirst("div.info > h3")!!.text() | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ import kotlin.math.pow | ||||||
| class M3u8Helper { | class M3u8Helper { | ||||||
|     companion object { |     companion object { | ||||||
|         private val generator = M3u8Helper() |         private val generator = M3u8Helper() | ||||||
|         fun generateM3u8( |         suspend fun generateM3u8( | ||||||
|             source: String, |             source: String, | ||||||
|             streamUrl: String, |             streamUrl: String, | ||||||
|             referer: String, |             referer: String, | ||||||
|  | @ -116,17 +116,15 @@ class M3u8Helper { | ||||||
|         return !url.contains("https://") && !url.contains("http://") |         return !url.contains("https://") && !url.contains("http://") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean?): List<M3u8Stream> { |     suspend fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean?): List<M3u8Stream> { | ||||||
|         val generate = sequence { |         val list = mutableListOf<M3u8Stream>() | ||||||
|  | 
 | ||||||
|         val m3u8Parent = getParentLink(m3u8.streamUrl) |         val m3u8Parent = getParentLink(m3u8.streamUrl) | ||||||
|             val response = runBlocking { |         val response = app.get(m3u8.streamUrl, headers = m3u8.headers, verify = false).text | ||||||
|                 app.get(m3u8.streamUrl, headers = m3u8.headers).text |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|         var hasAnyContent = false |         var hasAnyContent = false | ||||||
|         for (match in QUALITY_REGEX.findAll(response)) { |         for (match in QUALITY_REGEX.findAll(response)) { | ||||||
|             hasAnyContent = true |             hasAnyContent = true | ||||||
| 
 |  | ||||||
|             var (quality, m3u8Link, m3u8Link2) = match.destructured |             var (quality, m3u8Link, m3u8Link2) = match.destructured | ||||||
|             if (m3u8Link.isEmpty()) m3u8Link = m3u8Link2 |             if (m3u8Link.isEmpty()) m3u8Link = m3u8Link2 | ||||||
|             if (absoluteExtensionDetermination(m3u8Link) == "m3u8") { |             if (absoluteExtensionDetermination(m3u8Link) == "m3u8") { | ||||||
|  | @ -136,36 +134,33 @@ class M3u8Helper { | ||||||
|                 if (quality.isEmpty()) { |                 if (quality.isEmpty()) { | ||||||
|                     println(m3u8.streamUrl) |                     println(m3u8.streamUrl) | ||||||
|                 } |                 } | ||||||
|                     yieldAll( |                 list += m3u8Generation( | ||||||
|                         m3u8Generation( |  | ||||||
|                     M3u8Stream( |                     M3u8Stream( | ||||||
|                         m3u8Link, |                         m3u8Link, | ||||||
|                         quality.toIntOrNull(), |                         quality.toIntOrNull(), | ||||||
|                         m3u8.headers |                         m3u8.headers | ||||||
|                     ), false |                     ), false | ||||||
|                 ) |                 ) | ||||||
|                     ) | 
 | ||||||
|             } |             } | ||||||
|                 yield( |             list += M3u8Stream( | ||||||
|                     M3u8Stream( |  | ||||||
|                 m3u8Link, |                 m3u8Link, | ||||||
|                 quality.toIntOrNull(), |                 quality.toIntOrNull(), | ||||||
|                 m3u8.headers |                 m3u8.headers | ||||||
|             ) |             ) | ||||||
|                 ) | 
 | ||||||
|         } |         } | ||||||
|         if (returnThis ?: !hasAnyContent) { |         if (returnThis ?: !hasAnyContent) { | ||||||
|                 yield( |             list += M3u8Stream( | ||||||
|                     M3u8Stream( |  | ||||||
|                 m3u8.streamUrl, |                 m3u8.streamUrl, | ||||||
|                 Qualities.Unknown.value, |                 Qualities.Unknown.value, | ||||||
|                 m3u8.headers |                 m3u8.headers | ||||||
|             ) |             ) | ||||||
|                 ) |  | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         return list | ||||||
|     } |     } | ||||||
|         return generate.toList() | 
 | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     data class HlsDownloadData( |     data class HlsDownloadData( | ||||||
|         val bytes: ByteArray, |         val bytes: ByteArray, | ||||||
|  | @ -174,7 +169,7 @@ class M3u8Helper { | ||||||
|         val errored: Boolean = false |         val errored: Boolean = false | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     fun hlsYield(qualities: List<M3u8Stream>, startIndex: Int = 0): Iterator<HlsDownloadData> { |     suspend fun hlsYield(qualities: List<M3u8Stream>, startIndex: Int = 0): Iterator<HlsDownloadData> { | ||||||
|         if (qualities.isEmpty()) return listOf( |         if (qualities.isEmpty()) return listOf( | ||||||
|             HlsDownloadData( |             HlsDownloadData( | ||||||
|                 byteArrayOf(), |                 byteArrayOf(), | ||||||
|  | @ -196,7 +191,13 @@ class M3u8Helper { | ||||||
|         val secondSelection = selectBest(streams.ifEmpty { listOf(selected) }) |         val secondSelection = selectBest(streams.ifEmpty { listOf(selected) }) | ||||||
|         if (secondSelection != null) { |         if (secondSelection != null) { | ||||||
|             val m3u8Response = |             val m3u8Response = | ||||||
|                 runBlocking { app.get(secondSelection.streamUrl, headers = headers).text } |                 runBlocking { | ||||||
|  |                     app.get( | ||||||
|  |                         secondSelection.streamUrl, | ||||||
|  |                         headers = headers, | ||||||
|  |                         verify = false | ||||||
|  |                     ).text | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|             var encryptionUri: String? |             var encryptionUri: String? | ||||||
|             var encryptionIv = byteArrayOf() |             var encryptionIv = byteArrayOf() | ||||||
|  | @ -215,7 +216,7 @@ class M3u8Helper { | ||||||
| 
 | 
 | ||||||
|                 encryptionIv = match.component3().toByteArray() |                 encryptionIv = match.component3().toByteArray() | ||||||
|                 val encryptionKeyResponse = |                 val encryptionKeyResponse = | ||||||
|                     runBlocking { app.get(encryptionUri, headers = headers) } |                     runBlocking { app.get(encryptionUri, headers = headers, verify = false) } | ||||||
|                 encryptionData = encryptionKeyResponse.body?.bytes() ?: byteArrayOf() |                 encryptionData = encryptionKeyResponse.body?.bytes() ?: byteArrayOf() | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -238,7 +239,8 @@ class M3u8Helper { | ||||||
| 
 | 
 | ||||||
|                     while (lastYield != c) { |                     while (lastYield != c) { | ||||||
|                         try { |                         try { | ||||||
|                             val tsResponse = runBlocking { app.get(url, headers = headers) } |                             val tsResponse = | ||||||
|  |                                 runBlocking { app.get(url, headers = headers, verify = false) } | ||||||
|                             var tsData = tsResponse.body?.bytes() ?: byteArrayOf() |                             var tsData = tsResponse.body?.bytes() ?: byteArrayOf() | ||||||
| 
 | 
 | ||||||
|                             if (encryptionState) { |                             if (encryptionState) { | ||||||
|  |  | ||||||
|  | @ -38,6 +38,7 @@ import com.lagradost.cloudstream3.utils.DataStore.removeKey | ||||||
| import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute | import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
| import kotlinx.coroutines.delay | import kotlinx.coroutines.delay | ||||||
|  | import kotlinx.coroutines.runBlocking | ||||||
| import kotlinx.coroutines.withContext | import kotlinx.coroutines.withContext | ||||||
| import okhttp3.internal.closeQuietly | import okhttp3.internal.closeQuietly | ||||||
| import java.io.BufferedInputStream | import java.io.BufferedInputStream | ||||||
|  | @ -1129,7 +1130,9 @@ object VideoDownloadManager { | ||||||
| 
 | 
 | ||||||
|         if (!stream.resume!!) realIndex = 0 |         if (!stream.resume!!) realIndex = 0 | ||||||
|         val fileLengthAdd = stream.fileLength!! |         val fileLengthAdd = stream.fileLength!! | ||||||
|         val tsIterator = m3u8Helper.hlsYield(listOf(m3u8), realIndex) |         val tsIterator = runBlocking { | ||||||
|  |             m3u8Helper.hlsYield(listOf(m3u8), realIndex) | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         val displayName = getDisplayName(name, extension) |         val displayName = getDisplayName(name, extension) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue