Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ kotlinxCollectionsImmutable = "0.4.0"
kotlinxCoroutinesCore = "1.10.2"
kotlinxDatetime = "0.8.0"
kotlinxSerializationJson = "1.11.0"
ktor = "3.5.0"
lifecycleKtx = "2.10.0"
material = "1.14.0"
media3 = "1.9.3"
Expand Down Expand Up @@ -95,6 +96,7 @@ kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collec
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
ktor-http = { module = "io.ktor:ktor-http", version.ref = "ktor" }
lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleKtx" }
lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleKtx" }
material = { module = "com.google.android.material:material", version.ref = "material" }
Expand Down
1 change: 1 addition & 0 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ kotlin {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.serialization.json) // JSON Parser
implementation(libs.ktor.http)
implementation(libs.jsoup) // HTML Parser
implementation(libs.rhino) // Run JavaScript
implementation(libs.newpipeextractor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.Coroutines.mainWork
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
import com.lagradost.nicehttp.requestCreator
import io.ktor.http.Url
import io.ktor.http.decodeURLPart
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import java.net.URI

/**
* When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...)
Expand Down Expand Up @@ -211,7 +212,7 @@ actual class WebViewResolver actual constructor(
* */
return@runBlocking try {
when {
blacklistedFiles.any { URI(webViewUrl).path.contains(it) } || webViewUrl.endsWith(
blacklistedFiles.any { Url(webViewUrl).encodedPath.decodeURLPart().contains(it) } || webViewUrl.endsWith(
"/favicon.ico"
) -> WebResourceResponse(
"image/png",
Expand Down
39 changes: 21 additions & 18 deletions library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import com.lagradost.cloudstream3.utils.Coroutines.mainWork
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF
import com.lagradost.nicehttp.RequestBodyTypes
import io.ktor.http.Url
import io.ktor.http.URLBuilder
import io.ktor.http.encodedPath
import io.ktor.http.takeFrom
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
Expand All @@ -35,7 +39,6 @@ import kotlinx.datetime.format.byUnicodePattern
import kotlinx.datetime.format.char
import kotlinx.datetime.format.parse
import kotlinx.datetime.toInstant
import java.net.URI
import java.util.EnumSet
import kotlinx.serialization.json.Json
import kotlin.io.encoding.Base64
Expand Down Expand Up @@ -176,9 +179,9 @@ object APIHolder {
// To get the key
suspend fun getCaptchaToken(url: String, key: String, referer: String? = null): String? {
try {
val uri = URI.create(url)
val _url = Url(url)
val domain = base64Encode(
(uri.scheme + "://" + uri.host + ":443").encodeToByteArray(),
(_url.protocol.name + "://" + _url.host + ":443").encodeToByteArray(),
).replace("\n", "").replace("=", ".")

val vToken =
Expand Down Expand Up @@ -1330,23 +1333,23 @@ fun getQualityFromString(string: String?): SearchQuality? {
* ```
*/
fun MainAPI.updateUrl(url: String): String {
try {
val original = URI(url)
val updated = URI(mainUrl)

// URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
return URI(
updated.scheme,
original.userInfo,
updated.host,
updated.port,
original.path,
original.query,
original.fragment
).toString()
return try {
val original = Url(url)
val updated = Url(mainUrl)

URLBuilder().apply {
takeFrom(updated)
user = original.user
password = original.password
encodedPath = original.encodedPath
fragment = original.fragment

Comment thread
Luna712 marked this conversation as resolved.
parameters.clear()
parameters.appendAll(original.parameters)
}.buildString()
} catch (t: Throwable) {
logError(t)
return url
url
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import java.net.URI
import io.ktor.http.Url
import io.ktor.http.decodeURLPart
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
Expand Down Expand Up @@ -45,11 +46,11 @@ open class ByseSX : ExtractorApi() {
}

private fun getBaseUrl(url: String): String {
return URI(url).let { "${it.scheme}://${it.host}" }
return Url(url).let { "${it.protocol.name}://${it.host}" }
}

private fun getCodeFromUrl(url: String): String {
val path = URI(url).path ?: ""
val path = Url(url).encodedPath.decodeURLPart()
return path.trimEnd('/').substringAfterLast('/')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.StringUtils.decodeUri
import com.lagradost.cloudstream3.utils.StringUtils.decodeUrl
import com.lagradost.cloudstream3.utils.newExtractorLink

open class Cda : ExtractorApi() {
Expand Down Expand Up @@ -64,7 +64,7 @@ open class Cda : ExtractorApi() {
.replace("_QWE", "")
.replace("_Q5", "")
.replace("_IKSDE", "")
a = a.decodeUri()
a = a.decodeUrl()
a = a.map { char ->
if (char.code in 33..126) {
return@map (33 + (char.code + 14) % 94).toChar().toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import okhttp3.HttpUrl.Companion.toHttpUrl
import io.ktor.http.Url

// deobfuscated from https://hglink.to/main.js?v=1.1.3 using https://deobfuscate.io/
private val mirrors = arrayOf(
Expand Down Expand Up @@ -90,12 +90,12 @@ abstract class CineMMRedirect : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val videoId = url.toHttpUrl().encodedPath
val videoId = Url(url).encodedPath
val mirror = mirrors.random()

// re-use existing extractors by calling the ExtractorApi
// of the randomly selected mirror URL
val mirrorUrlWithVideoId = "https://$mirror$videoId"
loadExtractor(mirrorUrlWithVideoId, referer, subtitleCallback, callback)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import com.lagradost.cloudstream3.newSubtitleFile
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import java.net.URI


import io.ktor.http.Url
import io.ktor.http.decodeURLPart

class Geodailymotion : Dailymotion() {
override val name = "GeoDailymotion"
Expand Down Expand Up @@ -57,7 +56,6 @@ open class Dailymotion : ExtractorApi() {
}
}


private fun getEmbedUrl(url: String): String? {
if (url.contains("/embed/") || url.contains("/video/")) return url
if (url.contains("geo.dailymotion.com")) {
Expand All @@ -67,9 +65,8 @@ open class Dailymotion : ExtractorApi() {
return null
}


private fun getVideoId(url: String): String? {
val path = URI(url).path
val path = Url(url).encodedPath.decodeURLPart()
val id = path.substringAfter("/video/")
return if (id.matches(videoIdRegex)) id else null
}
Expand All @@ -82,7 +79,6 @@ open class Dailymotion : ExtractorApi() {
return generateM3u8(name, streamLink, "").forEach(callback)
}


data class MetaData(
val qualities: Map<String, List<Quality>>?,
val subtitles: SubtitlesWrapper?
Expand All @@ -102,5 +98,4 @@ open class Dailymotion : ExtractorApi() {
val label: String,
val urls: List<String>
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.newExtractorLink
import java.net.URI
import io.ktor.http.Url

class Doodspro : DoodLaExtractor() {
override var mainUrl = "https://doods.pro"
Expand Down Expand Up @@ -138,8 +138,6 @@ open class DoodLaExtractor : ExtractorApi() {
}

private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
return Url(url).let { "${it.protocol.name}://${it.host}" }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import java.net.URI
import io.ktor.http.Url

class Techinmind: GDMirrorbot() {
override var name = "Techinmind Cloud AIO"
Expand Down Expand Up @@ -103,7 +103,7 @@ open class GDMirrorbot : ExtractorApi() {
}

private fun getBaseUrl(url: String): String {
return URI(url).let { "${it.scheme}://${it.host}" }
return Url(url).let { "${it.protocol.name}://${it.host}" }
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import com.lagradost.cloudstream3.utils.newExtractorLink
import java.net.URI
import io.ktor.http.Url

class HubCloud : ExtractorApi() {
override val name = "Hub-Cloud"
Expand All @@ -24,7 +24,7 @@ class HubCloud : ExtractorApi() {
) {
val tag = "HubCloud"
val realUrl = url.takeIf {
try { URI(it).toURL(); true } catch (e: Exception) { Log.e(tag, "Invalid URL: ${e.message}"); false }
try { Url(it); true } catch (e: Exception) { Log.e(tag, "Invalid URL: ${e.message}"); false }
} ?: return

val baseUrl=getBaseUrl(realUrl)
Expand Down Expand Up @@ -161,7 +161,7 @@ class HubCloud : ExtractorApi() {

private fun getBaseUrl(url: String): String {
return try {
URI(url).let { "${it.scheme}://${it.host}" }
Url(url).let { "${it.protocol.name}://${it.host}" }
} catch (_: Exception) {
""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.newSubtitleFile
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.StringUtils.decodeUri
import com.lagradost.cloudstream3.utils.StringUtils.decodeUrl
import com.lagradost.cloudstream3.utils.newExtractorLink
import org.jsoup.nodes.Document

Expand Down Expand Up @@ -96,7 +96,7 @@ open class InternetArchive : ExtractorApi() {
if (mediaUrl.isNotEmpty()) {
val name = if (mediaUrl.count() > 1) {
val fileExtension = mediaUrl.substringAfterLast(".")
val fileNameCleaned = fileName.decodeUri().substringBeforeLast('.')
val fileNameCleaned = fileName.decodeUrl().substringBeforeLast('.')
"$fileNameCleaned ($fileExtension)"
} else this.name
callback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import java.net.URI
import io.ktor.http.Url

open class Streamplay : ExtractorApi() {
override val name = "Streamplay"
Expand All @@ -22,9 +22,7 @@ open class Streamplay : ExtractorApi() {
) {
val request = app.get(url, referer = referer)
val redirectUrl = request.url
val mainServer = URI(redirectUrl).let {
"${it.scheme}://${it.host}"
}
val mainServer = Url(redirectUrl).let { "${it.protocol.name}://${it.host}" }
val key = redirectUrl.substringAfter("embed-").substringBefore(".html")
val token =
request.document.select("script").find { it.data().contains("sitekey:") }?.data()
Expand Down Expand Up @@ -79,4 +77,4 @@ open class Streamplay : ExtractorApi() {
@JsonProperty("label") val label: String? = null,
)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLinkType
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.fixUrl
import com.lagradost.cloudstream3.utils.newExtractorLink
import java.net.URI
import io.ktor.http.Url
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
Expand Down Expand Up @@ -84,7 +84,7 @@ open class VidStack : ExtractorApi() {

private fun getBaseUrl(url: String): String {
return try {
URI(url).let { "${it.scheme}://${it.host}" }
Url(url).let { "${it.protocol.name}://${it.host}" }
} catch (e: Exception) {
Log.e("Vidstack", "getBaseUrl fallback: ${e.message}")
mainUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.newExtractorLink
import io.ktor.http.Url
import org.jsoup.nodes.Document
import java.net.URI
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
Expand Down Expand Up @@ -88,8 +88,8 @@ object GogoHelper {
val foundKey = secretKey ?: getKey(base64Decode(id) + foundIv) ?: return@safeApiCall
val foundDecryptKey = secretDecryptKey ?: foundKey

val uri = URI(iframeUrl)
val mainUrl = "https://" + uri.host
val url = Url(iframeUrl)
val mainUrl = "https://${url.host}"

val encryptedId = cryptoHandler(id, foundIv, foundKey)
val encryptRequestData = if (isUsingAdaptiveData) {
Expand Down
Loading