LibreTube/app/src/main/java/com/github/libretube/helpers/ProxyHelper.kt
2023-07-20 15:02:13 +02:00

88 lines
3.1 KiB
Kotlin

package com.github.libretube.helpers
import com.github.libretube.api.CronetHelper
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.constants.PreferenceKeys
import java.net.HttpURLConnection
import java.net.URL
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
object ProxyHelper {
fun fetchProxyUrl() {
CoroutineScope(Dispatchers.IO).launch {
runCatching {
RetrofitInstance.api.getConfig().imageProxyUrl?.let {
PreferenceHelper.putString(PreferenceKeys.IMAGE_PROXY_URL, it)
}
}
}
}
fun rewriteUrl(url: String?): String? {
val proxyUrl = PreferenceHelper.getString(PreferenceKeys.IMAGE_PROXY_URL, "")
.toHttpUrlOrNull() ?: return url
return url?.toHttpUrlOrNull()?.newBuilder()
?.host(proxyUrl.host)
?.port(proxyUrl.port)
?.toString()
}
/**
* Detect whether the proxy should be used or not for a given stream URL based on user preferences
*/
suspend fun unwrapStreamUrl(url: String): String {
return if (useYouTubeSourceWithoutProxy(url)) unwrapUrl(url) else url
}
suspend fun useYouTubeSourceWithoutProxy(url: String) = when {
!PreferenceHelper.getBoolean(PreferenceKeys.DISABLE_VIDEO_IMAGE_PROXY, false) -> false
PreferenceHelper.getBoolean(PreferenceKeys.FALLBACK_PIPED_PROXY, true) -> {
// check whether the URL has content available, and disable proxy if that's the case
isUrlUsable(unwrapUrl(url))
}
else -> true
}
fun unwrapImageUrl(url: String) = if (
!PreferenceHelper.getBoolean(PreferenceKeys.DISABLE_VIDEO_IMAGE_PROXY, false)
) {
url
} else {
unwrapUrl(url)
}
/**
* Convert a proxied Piped url to a YouTube url that's not proxied
*/
fun unwrapUrl(url: String, unwrap: Boolean = true) = url.toHttpUrlOrNull()
?.takeIf { unwrap }?.let {
val host = it.queryParameter("host")
// if there's no host parameter specified, there's no way to unwrap the URL
// and the proxied one must be used. That's the case if using LBRY.
if (host.isNullOrEmpty()) return@let url
it.newBuilder()
.host(host)
.removeAllQueryParameters("host")
.build()
.toString()
} ?: url
/**
* Parse the Piped url to a YouTube url (or not) based on preferences
*/
private suspend fun isUrlUsable(url: String): Boolean = withContext(Dispatchers.IO) {
return@withContext runCatching {
val connection = CronetHelper.cronetEngine.openConnection(URL(url)) as HttpURLConnection
connection.requestMethod = "HEAD"
val isSuccess = connection.responseCode == 200
connection.disconnect()
return@runCatching isSuccess
}.getOrDefault(false)
}
}