mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
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…
Reference in a new issue