mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-17 07:21:58 +00:00
ref: adjust url building to be in parity with addon protocol
This commit is contained in:
parent
ab0fc039b9
commit
bd84bd9b56
6 changed files with 82 additions and 29 deletions
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.nuvio.app.features.addons
|
||||||
|
|
||||||
|
internal fun addonTransportBaseUrl(manifestUrl: String): String =
|
||||||
|
manifestUrl.substringBefore("?").removeSuffix("/manifest.json")
|
||||||
|
|
||||||
|
internal fun buildAddonResourceUrl(
|
||||||
|
manifestUrl: String,
|
||||||
|
resource: String,
|
||||||
|
type: String,
|
||||||
|
id: String,
|
||||||
|
extraPathSegment: String? = null,
|
||||||
|
): String {
|
||||||
|
val encodedId = id.encodeAddonPathSegment()
|
||||||
|
val baseUrl = addonTransportBaseUrl(manifestUrl)
|
||||||
|
return if (extraPathSegment.isNullOrEmpty()) {
|
||||||
|
"$baseUrl/$resource/$type/$encodedId.json"
|
||||||
|
} else {
|
||||||
|
"$baseUrl/$resource/$type/$encodedId/$extraPathSegment.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun String.encodeAddonPathSegment(): String =
|
||||||
|
buildString {
|
||||||
|
encodeToByteArray().forEach { byte ->
|
||||||
|
val value = byte.toInt() and 0xFF
|
||||||
|
val char = value.toChar()
|
||||||
|
if (
|
||||||
|
char in 'a'..'z' ||
|
||||||
|
char in 'A'..'Z' ||
|
||||||
|
char in '0'..'9' ||
|
||||||
|
char == '-' ||
|
||||||
|
char == '_' ||
|
||||||
|
char == '.' ||
|
||||||
|
char == '~'
|
||||||
|
) {
|
||||||
|
append(char)
|
||||||
|
} else {
|
||||||
|
append('%')
|
||||||
|
append(ADDON_URL_HEX[value shr 4])
|
||||||
|
append(ADDON_URL_HEX[value and 0x0F])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ADDON_URL_HEX = "0123456789ABCDEF"
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.nuvio.app.features.catalog
|
package com.nuvio.app.features.catalog
|
||||||
|
|
||||||
import com.nuvio.app.features.addons.AddonCatalog
|
import com.nuvio.app.features.addons.AddonCatalog
|
||||||
|
import com.nuvio.app.features.addons.buildAddonResourceUrl
|
||||||
import com.nuvio.app.features.addons.httpGetText
|
import com.nuvio.app.features.addons.httpGetText
|
||||||
import com.nuvio.app.features.home.HomeCatalogParser
|
import com.nuvio.app.features.home.HomeCatalogParser
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
|
|
@ -122,21 +123,19 @@ internal fun buildCatalogUrl(
|
||||||
search: String?,
|
search: String?,
|
||||||
skip: Int?,
|
skip: Int?,
|
||||||
): String {
|
): String {
|
||||||
val baseUrl = manifestUrl
|
|
||||||
.substringBefore("?")
|
|
||||||
.removeSuffix("/manifest.json")
|
|
||||||
|
|
||||||
val extraParts = buildList {
|
val extraParts = buildList {
|
||||||
if (!search.isNullOrBlank()) add("search=${search.encodeCatalogExtra()}")
|
if (!search.isNullOrBlank()) add("search=${search.encodeCatalogExtra()}")
|
||||||
if (!genre.isNullOrBlank()) add("genre=${genre.encodeCatalogExtra()}")
|
if (!genre.isNullOrBlank()) add("genre=${genre.encodeCatalogExtra()}")
|
||||||
if (skip != null && skip > 0) add("skip=$skip")
|
if (skip != null && skip > 0) add("skip=$skip")
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (extraParts.isEmpty()) {
|
return buildAddonResourceUrl(
|
||||||
"$baseUrl/catalog/$type/$catalogId.json"
|
manifestUrl = manifestUrl,
|
||||||
} else {
|
resource = "catalog",
|
||||||
"$baseUrl/catalog/$type/$catalogId/${extraParts.joinToString(separator = "&")}.json"
|
type = type,
|
||||||
}
|
id = catalogId,
|
||||||
|
extraPathSegment = extraParts.joinToString(separator = "&").ifBlank { null },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.encodeCatalogExtra(): String =
|
private fun String.encodeCatalogExtra(): String =
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.nuvio.app.features.details
|
||||||
import co.touchlab.kermit.Logger
|
import co.touchlab.kermit.Logger
|
||||||
import com.nuvio.app.features.addons.AddonManifest
|
import com.nuvio.app.features.addons.AddonManifest
|
||||||
import com.nuvio.app.features.addons.AddonRepository
|
import com.nuvio.app.features.addons.AddonRepository
|
||||||
|
import com.nuvio.app.features.addons.buildAddonResourceUrl
|
||||||
import com.nuvio.app.features.addons.httpGetText
|
import com.nuvio.app.features.addons.httpGetText
|
||||||
import com.nuvio.app.features.mdblist.MdbListMetadataService
|
import com.nuvio.app.features.mdblist.MdbListMetadataService
|
||||||
import com.nuvio.app.features.mdblist.MdbListSettingsRepository
|
import com.nuvio.app.features.mdblist.MdbListSettingsRepository
|
||||||
|
|
@ -217,10 +218,12 @@ object MetaDetailsRepository {
|
||||||
id: String,
|
id: String,
|
||||||
includeMdbList: Boolean,
|
includeMdbList: Boolean,
|
||||||
): MetaDetails? {
|
): MetaDetails? {
|
||||||
val baseUrl = manifest.transportUrl
|
val url = buildAddonResourceUrl(
|
||||||
.substringBefore("?")
|
manifestUrl = manifest.transportUrl,
|
||||||
.removeSuffix("/manifest.json")
|
resource = "meta",
|
||||||
val url = "$baseUrl/meta/$type/$id.json"
|
type = type,
|
||||||
|
id = id,
|
||||||
|
)
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
TmdbSettingsRepository.ensureLoaded()
|
TmdbSettingsRepository.ensureLoaded()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.nuvio.app.features.player
|
||||||
import co.touchlab.kermit.Logger
|
import co.touchlab.kermit.Logger
|
||||||
import com.nuvio.app.core.build.AppFeaturePolicy
|
import com.nuvio.app.core.build.AppFeaturePolicy
|
||||||
import com.nuvio.app.features.addons.AddonRepository
|
import com.nuvio.app.features.addons.AddonRepository
|
||||||
|
import com.nuvio.app.features.addons.buildAddonResourceUrl
|
||||||
import com.nuvio.app.features.addons.httpGetText
|
import com.nuvio.app.features.addons.httpGetText
|
||||||
import com.nuvio.app.features.details.MetaDetailsRepository
|
import com.nuvio.app.features.details.MetaDetailsRepository
|
||||||
import com.nuvio.app.features.plugins.PluginRepository
|
import com.nuvio.app.features.plugins.PluginRepository
|
||||||
|
|
@ -215,11 +216,12 @@ object PlayerStreamsRepository {
|
||||||
val job = scope.launch {
|
val job = scope.launch {
|
||||||
val addonJobs = streamAddons.map { addon ->
|
val addonJobs = streamAddons.map { addon ->
|
||||||
async {
|
async {
|
||||||
val encodedId = videoId.replace("%", "%25").replace(" ", "%20")
|
val url = buildAddonResourceUrl(
|
||||||
val baseUrl = addon.manifest.transportUrl
|
manifestUrl = addon.manifest.transportUrl,
|
||||||
.substringBefore("?")
|
resource = "stream",
|
||||||
.removeSuffix("/manifest.json")
|
type = type,
|
||||||
val url = "$baseUrl/stream/$type/$encodedId.json"
|
id = videoId,
|
||||||
|
)
|
||||||
|
|
||||||
val displayName = addon.addonName
|
val displayName = addon.addonName
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.nuvio.app.features.player
|
package com.nuvio.app.features.player
|
||||||
|
|
||||||
import com.nuvio.app.features.addons.AddonRepository
|
import com.nuvio.app.features.addons.AddonRepository
|
||||||
|
import com.nuvio.app.features.addons.buildAddonResourceUrl
|
||||||
import com.nuvio.app.features.addons.httpGetText
|
import com.nuvio.app.features.addons.httpGetText
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
@ -49,8 +50,12 @@ object SubtitleRepository {
|
||||||
subtitleResource.idPrefixes.any { videoId.startsWith(it) }
|
subtitleResource.idPrefixes.any { videoId.startsWith(it) }
|
||||||
if (!prefixMatch) continue
|
if (!prefixMatch) continue
|
||||||
|
|
||||||
val baseUrl = manifest.transportUrl.substringBeforeLast("/manifest.json")
|
val subtitleUrl = buildAddonResourceUrl(
|
||||||
val subtitleUrl = "$baseUrl/subtitles/$type/$videoId.json"
|
manifestUrl = manifest.transportUrl,
|
||||||
|
resource = "subtitles",
|
||||||
|
type = type,
|
||||||
|
id = videoId,
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val response = withContext(Dispatchers.Default) {
|
val response = withContext(Dispatchers.Default) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.nuvio.app.features.streams
|
||||||
import co.touchlab.kermit.Logger
|
import co.touchlab.kermit.Logger
|
||||||
import com.nuvio.app.core.build.AppFeaturePolicy
|
import com.nuvio.app.core.build.AppFeaturePolicy
|
||||||
import com.nuvio.app.features.addons.AddonRepository
|
import com.nuvio.app.features.addons.AddonRepository
|
||||||
|
import com.nuvio.app.features.addons.buildAddonResourceUrl
|
||||||
import com.nuvio.app.features.addons.httpGetText
|
import com.nuvio.app.features.addons.httpGetText
|
||||||
import com.nuvio.app.features.details.MetaDetailsRepository
|
import com.nuvio.app.features.details.MetaDetailsRepository
|
||||||
import com.nuvio.app.features.player.PlayerSettingsRepository
|
import com.nuvio.app.features.player.PlayerSettingsRepository
|
||||||
|
|
@ -237,11 +238,12 @@ object StreamsRepository {
|
||||||
|
|
||||||
streamAddons.forEach { addon ->
|
streamAddons.forEach { addon ->
|
||||||
launch {
|
launch {
|
||||||
val encodedId = videoId.encodeForPath()
|
val url = buildAddonResourceUrl(
|
||||||
val baseUrl = addon.manifest.transportUrl
|
manifestUrl = addon.manifest.transportUrl,
|
||||||
.substringBefore("?")
|
resource = "stream",
|
||||||
.removeSuffix("/manifest.json")
|
type = type,
|
||||||
val url = "$baseUrl/stream/$type/$encodedId.json"
|
id = videoId,
|
||||||
|
)
|
||||||
log.d { "Fetching streams from: $url" }
|
log.d { "Fetching streams from: $url" }
|
||||||
|
|
||||||
val displayName = addon.addonName
|
val displayName = addon.addonName
|
||||||
|
|
@ -420,10 +422,6 @@ object StreamsRepository {
|
||||||
activeRequestKey = null
|
activeRequestKey = null
|
||||||
_uiState.value = StreamsUiState()
|
_uiState.value = StreamsUiState()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode id segment so colons and slashes don't break URL path parsing on addons
|
|
||||||
private fun String.encodeForPath(): String =
|
|
||||||
replace("%", "%25").replace(" ", "%20")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class InstalledStreamAddonTarget(
|
private data class InstalledStreamAddonTarget(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue