mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Added sflix downloads, fixed some sflix sources and added image caching (#128)
Waited long enough and it seems to work fine, I will just revert if this fucks up :)
This commit is contained in:
parent
96b5c9658d
commit
596f659a29
14 changed files with 112 additions and 56 deletions
4
.github/workflows/prerelease.yml
vendored
4
.github/workflows/prerelease.yml
vendored
|
@ -15,10 +15,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 8
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
|
4
.github/workflows/pull_request.yml
vendored
4
.github/workflows/pull_request.yml
vendored
|
@ -7,10 +7,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 8
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="delegatedBuild" value="true" />
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK" />
|
||||
</project>
|
|
@ -35,7 +35,7 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
versionCode 27
|
||||
versionName "1.9.11"
|
||||
versionName "1.9.12"
|
||||
|
||||
resValue "string", "app_version",
|
||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||
|
@ -105,6 +105,8 @@ dependencies {
|
|||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
|
||||
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
||||
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
|
|
|
@ -3,10 +3,7 @@ package com.lagradost.cloudstream3.extractors
|
|||
import com.lagradost.cloudstream3.network.get
|
||||
import com.lagradost.cloudstream3.network.text
|
||||
import com.lagradost.cloudstream3.network.url
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import java.net.URI
|
||||
|
||||
class AsianLoad : ExtractorApi() {
|
||||
|
@ -17,8 +14,6 @@ class AsianLoad : ExtractorApi() {
|
|||
override val requiresReferer: Boolean
|
||||
get() = true
|
||||
|
||||
private val urlRegex = Regex("""(.*?)([^/]+$)""")
|
||||
private val m3u8UrlRegex = Regex("""RESOLUTION=\d*x(\d*).*\n(.*\.m3u8)""")
|
||||
private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*?["'](.*?)["']""")
|
||||
override fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
@ -27,21 +22,25 @@ class AsianLoad : ExtractorApi() {
|
|||
val extractedUrl = sourceMatch.groupValues[1]
|
||||
// Trusting this isn't mp4, may fuck up stuff
|
||||
if (URI(extractedUrl).path.endsWith(".m3u8")) {
|
||||
with(get(extractedUrl, referer = this.url)) {
|
||||
m3u8UrlRegex.findAll(this.text).forEach { match ->
|
||||
M3u8Helper().m3u8Generation(
|
||||
M3u8Helper.M3u8Stream(
|
||||
extractedUrl,
|
||||
headers = mapOf("referer" to this.url)
|
||||
), true
|
||||
)
|
||||
.forEach { stream ->
|
||||
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
"$name ${match.groupValues[1]}p",
|
||||
urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[2],
|
||||
"$name $qualityString",
|
||||
stream.streamUrl,
|
||||
url,
|
||||
getQualityFromName(match.groupValues[1]),
|
||||
isM3u8 = true
|
||||
getQualityFromName(stream.quality.toString()),
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
} else if (extractedUrl.endsWith(".mp4")) {
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
|
|
|
@ -45,11 +45,12 @@ class WcoStream : ExtractorApi() {
|
|||
if (mapped.success) {
|
||||
mapped.media.sources.forEach {
|
||||
if (it.file.contains("m3u8")) {
|
||||
hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file, null)).forEach { stream ->
|
||||
hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file, null), true).forEach { stream ->
|
||||
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name + if (stream.quality != null) " - ${stream.quality}" else "",
|
||||
"$name $qualityString",
|
||||
stream.streamUrl,
|
||||
"",
|
||||
getQualityFromName(stream.quality.toString()),
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.lagradost.cloudstream3.network.WebViewResolver
|
|||
import com.lagradost.cloudstream3.network.get
|
||||
import com.lagradost.cloudstream3.network.text
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
@ -29,7 +30,7 @@ class SflixProvider : MainAPI() {
|
|||
get() = true
|
||||
|
||||
override val hasDownloadSupport: Boolean
|
||||
get() = false
|
||||
get() = true
|
||||
|
||||
override val supportedTypes: Set<TvType>
|
||||
get() = setOf(
|
||||
|
@ -257,21 +258,39 @@ class SflixProvider : MainAPI() {
|
|||
)
|
||||
|
||||
data class SourceObject(
|
||||
@JsonProperty("sources") val sources: List<Sources1?>?,
|
||||
@JsonProperty("sources_1") val sources1: List<Sources1?>?,
|
||||
@JsonProperty("sources_2") val sources2: List<Sources1?>?,
|
||||
@JsonProperty("sourcesBackup") val sourcesBackup: List<Sources1?>?,
|
||||
@JsonProperty("tracks") val tracks: List<Tracks?>?
|
||||
)
|
||||
|
||||
private fun Sources1.toExtractorLink(): ExtractorLink? {
|
||||
private fun Sources1.toExtractorLink(name: String): List<ExtractorLink>? {
|
||||
return this.file?.let {
|
||||
val isM3u8 = URI(this.file).path.endsWith(".m3u8") || this.type.equals("hls", ignoreCase = true)
|
||||
if (isM3u8) {
|
||||
M3u8Helper().m3u8Generation(M3u8Helper.M3u8Stream(this.file, null), true).map { stream ->
|
||||
val qualityString = if ((stream.quality ?: 0) == 0) label ?: "" else "${stream.quality}p"
|
||||
ExtractorLink(
|
||||
this@SflixProvider.name,
|
||||
"${this@SflixProvider.name} $qualityString $name",
|
||||
stream.streamUrl,
|
||||
mainUrl,
|
||||
getQualityFromName(stream.quality.toString()),
|
||||
true
|
||||
)
|
||||
}
|
||||
} else {
|
||||
listOf(ExtractorLink(
|
||||
this@SflixProvider.name,
|
||||
this.label?.let { "${this@SflixProvider.name} - $it" } ?: this@SflixProvider.name,
|
||||
it,
|
||||
this@SflixProvider.mainUrl,
|
||||
getQualityFromName(this.label ?: ""),
|
||||
URI(this.file).path.endsWith(".m3u8") || this.label.equals("hls", ignoreCase = true),
|
||||
)
|
||||
getQualityFromName(this.type ?: ""),
|
||||
false,
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,18 +338,15 @@ class SflixProvider : MainAPI() {
|
|||
|
||||
val mapped = mapper.readValue<SourceObject>(sources)
|
||||
|
||||
mapped.sources1?.forEach {
|
||||
it?.toExtractorLink()?.let { extractorLink ->
|
||||
callback.invoke(
|
||||
extractorLink
|
||||
)
|
||||
}
|
||||
}
|
||||
mapped.sources2?.forEach {
|
||||
it?.toExtractorLink()?.let { extractorLink ->
|
||||
callback.invoke(
|
||||
extractorLink
|
||||
val list = listOf(
|
||||
mapped.sources1 to "source 1",
|
||||
mapped.sources2 to "source 2",
|
||||
mapped.sources to "source 0",
|
||||
mapped.sourcesBackup to "source 3"
|
||||
)
|
||||
list.forEach { subList ->
|
||||
subList.first?.forEach {
|
||||
it?.toExtractorLink(subList.second)?.forEach(callback)
|
||||
}
|
||||
}
|
||||
mapped.tracks?.forEach {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package com.lagradost.cloudstream3.network
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.net.http.SslError
|
||||
import android.webkit.*
|
||||
import com.lagradost.cloudstream3.AcraApplication
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -26,6 +24,7 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
|||
@SuppressLint("SetJavaScriptEnabled")
|
||||
suspend fun resolveUsingWebView(request: Request): Request? {
|
||||
val url = request.url.toString()
|
||||
println("Initial web-view request: $url")
|
||||
var webView: WebView? = null
|
||||
|
||||
fun destroyWebView() {
|
||||
|
@ -43,6 +42,7 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
|||
webView = WebView(
|
||||
AcraApplication.context ?: throw RuntimeException("No base context in WebViewResolver")
|
||||
).apply {
|
||||
settings.cacheMode
|
||||
settings.javaScriptEnabled = true
|
||||
}
|
||||
|
||||
|
@ -62,10 +62,15 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
|||
10,
|
||||
TimeUnit.MINUTES
|
||||
)
|
||||
println("Web-view request finished: $webViewUrl")
|
||||
destroyWebView()
|
||||
}
|
||||
return super.shouldInterceptRequest(view, request)
|
||||
}
|
||||
|
||||
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
|
||||
handler?.proceed() // Ignore ssl issues
|
||||
}
|
||||
}
|
||||
|
||||
webView?.loadUrl(url)
|
||||
|
@ -83,6 +88,7 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
|||
loop += 1
|
||||
}
|
||||
|
||||
println("Web-view timeout after ${totalTime / 1000}s")
|
||||
destroyWebView()
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.bumptech.glide.GlideBuilder
|
||||
import com.bumptech.glide.annotation.GlideModule
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.module.AppGlideModule
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
|
||||
@GlideModule
|
||||
class GlideModule : AppGlideModule() {
|
||||
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
||||
super.applyOptions(context, builder)
|
||||
builder.apply {
|
||||
RequestOptions()
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.signature(ObjectKey(System.currentTimeMillis().toShort()))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,8 @@ import kotlin.math.pow
|
|||
class M3u8Helper {
|
||||
private val ENCRYPTION_DETECTION_REGEX = Regex("#EXT-X-KEY:METHOD=([^,]+),")
|
||||
private val ENCRYPTION_URL_IV_REGEX = Regex("#EXT-X-KEY:METHOD=([^,]+),URI=\"([^\"]+)\"(?:,IV=(.*))?")
|
||||
private val QUALITY_REGEX = Regex("""#EXT-X-STREAM-INF:(?:(?:.*?(?:RESOLUTION=\d+x(\d+)).*?\s+(.*))|(?:.*?\s+(.*)))""")
|
||||
private val QUALITY_REGEX =
|
||||
Regex("""#EXT-X-STREAM-INF:(?:(?:.*?(?:RESOLUTION=\d+x(\d+)).*?\s+(.*))|(?:.*?\s+(.*)))""")
|
||||
private val TS_EXTENSION_REGEX = Regex("""(.*\.ts.*)""")
|
||||
|
||||
fun absoluteExtensionDetermination(url: String): String? {
|
||||
|
@ -78,7 +79,7 @@ class M3u8Helper {
|
|||
return !url.contains("https://") && !url.contains("http://")
|
||||
}
|
||||
|
||||
fun m3u8Generation(m3u8: M3u8Stream): List<M3u8Stream> {
|
||||
fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean): List<M3u8Stream> {
|
||||
val generate = sequence {
|
||||
val m3u8Parent = getParentLink(m3u8.streamUrl)
|
||||
val response = get(m3u8.streamUrl, headers = m3u8.headers).text
|
||||
|
@ -99,7 +100,7 @@ class M3u8Helper {
|
|||
m3u8Link,
|
||||
quality.toIntOrNull(),
|
||||
m3u8.headers
|
||||
)
|
||||
), false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -111,6 +112,15 @@ class M3u8Helper {
|
|||
)
|
||||
)
|
||||
}
|
||||
if (returnThis) {
|
||||
yield(
|
||||
M3u8Stream(
|
||||
m3u8.streamUrl,
|
||||
0,
|
||||
m3u8.headers
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return generate.toList()
|
||||
}
|
||||
|
@ -131,7 +141,7 @@ class M3u8Helper {
|
|||
}
|
||||
val headers = selected.headers
|
||||
|
||||
val streams = qualities.map { m3u8Generation(it) }.flatten()
|
||||
val streams = qualities.map { m3u8Generation(it, false) }.flatten()
|
||||
//val sslVerification = if (headers.containsKey("ssl_verification")) headers["ssl_verification"].toBoolean() else true
|
||||
|
||||
val secondSelection = selectBest(streams.ifEmpty { listOf(selected) })
|
||||
|
|
|
@ -96,7 +96,7 @@ object UIHelper {
|
|||
fun ImageView?.setImage(url : String?) {
|
||||
if(this == null || url.isNullOrBlank()) return
|
||||
try {
|
||||
Glide.with(this.context)
|
||||
GlideApp.with(this.context)
|
||||
.load(GlideUrl(url))
|
||||
.into(this)
|
||||
} catch (e : Exception) {
|
||||
|
|
|
@ -202,7 +202,7 @@ object VideoDownloadManager {
|
|||
return cachedBitmaps[url]
|
||||
}
|
||||
|
||||
val bitmap = Glide.with(this)
|
||||
val bitmap = GlideApp.with(this)
|
||||
.asBitmap()
|
||||
.load(url).into(720, 720)
|
||||
.get()
|
||||
|
|
Loading…
Reference in a new issue