mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-23 10:12:06 +00:00
feat: save resolved links in memory
This commit is contained in:
parent
2e35652e81
commit
e85ea4f322
2 changed files with 119 additions and 3 deletions
|
|
@ -64,6 +64,13 @@ internal class CloudLibraryStore(
|
||||||
?: return CloudLibraryPlaybackResult.MissingCredentials
|
?: return CloudLibraryPlaybackResult.MissingCredentials
|
||||||
val api = providerApis.firstOrNull { it.provider.id == item.providerId }
|
val api = providerApis.firstOrNull { it.provider.id == item.providerId }
|
||||||
?: return CloudLibraryPlaybackResult.Failed()
|
?: return CloudLibraryPlaybackResult.Failed()
|
||||||
|
file.playbackUrl?.takeIf { it.isNotBlank() }?.let { url ->
|
||||||
|
return CloudLibraryPlaybackResult.Success(
|
||||||
|
url = url,
|
||||||
|
filename = file.name.takeIf { it.isNotBlank() },
|
||||||
|
videoSizeBytes = file.sizeBytes,
|
||||||
|
)
|
||||||
|
}
|
||||||
return api.resolvePlayback(
|
return api.resolvePlayback(
|
||||||
apiKey = credential.apiKey,
|
apiKey = credential.apiKey,
|
||||||
item = item,
|
item = item,
|
||||||
|
|
@ -186,7 +193,26 @@ object CloudLibraryRepository {
|
||||||
if (!DebridSettingsRepository.snapshot().cloudLibraryEnabled) {
|
if (!DebridSettingsRepository.snapshot().cloudLibraryEnabled) {
|
||||||
return CloudLibraryPlaybackResult.Failed("Cloud library is disabled.")
|
return CloudLibraryPlaybackResult.Failed("Cloud library is disabled.")
|
||||||
}
|
}
|
||||||
return store.resolvePlayback(item, file)
|
val result = store.resolvePlayback(item, file)
|
||||||
|
if (result is CloudLibraryPlaybackResult.Success) {
|
||||||
|
rememberResolvedPlaybackUrl(item = item, file = file, url = result.url)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rememberResolvedPlaybackUrl(
|
||||||
|
item: CloudLibraryItem,
|
||||||
|
file: CloudLibraryFile,
|
||||||
|
url: String,
|
||||||
|
) {
|
||||||
|
if (url.isBlank()) return
|
||||||
|
_uiState.update { current ->
|
||||||
|
current.withResolvedPlaybackUrl(
|
||||||
|
item = item,
|
||||||
|
file = file,
|
||||||
|
url = url,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun connectedCloudCredentials(): List<DebridServiceCredential> =
|
private fun connectedCloudCredentials(): List<DebridServiceCredential> =
|
||||||
|
|
@ -248,3 +274,35 @@ internal fun CloudLibraryUiState.findPlaybackTargetForProgress(
|
||||||
val singleFile = singleItem.playableFiles.singleOrNull() ?: return null
|
val singleFile = singleItem.playableFiles.singleOrNull() ?: return null
|
||||||
return CloudLibraryPlaybackTarget(item = singleItem, file = singleFile)
|
return CloudLibraryPlaybackTarget(item = singleItem, file = singleFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun CloudLibraryUiState.withResolvedPlaybackUrl(
|
||||||
|
item: CloudLibraryItem,
|
||||||
|
file: CloudLibraryFile,
|
||||||
|
url: String,
|
||||||
|
): CloudLibraryUiState {
|
||||||
|
val normalizedUrl = url.trim().takeIf { it.isNotBlank() } ?: return this
|
||||||
|
val targetItemKey = item.stableKey
|
||||||
|
val targetFileKey = file.stableKey
|
||||||
|
var didUpdate = false
|
||||||
|
val updatedProviders = providers.map { providerState ->
|
||||||
|
if (providerState.providerId != item.providerId) return@map providerState
|
||||||
|
val updatedItems = providerState.items.map { candidateItem ->
|
||||||
|
if (candidateItem.stableKey != targetItemKey) return@map candidateItem
|
||||||
|
val updatedFiles = candidateItem.files.map { candidateFile ->
|
||||||
|
if (candidateFile.stableKey != targetFileKey) {
|
||||||
|
candidateFile
|
||||||
|
} else {
|
||||||
|
didUpdate = true
|
||||||
|
candidateFile.copy(playbackUrl = normalizedUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
candidateItem.copy(files = updatedFiles)
|
||||||
|
}
|
||||||
|
providerState.copy(items = updatedItems)
|
||||||
|
}
|
||||||
|
return if (didUpdate) {
|
||||||
|
copy(providers = updatedProviders)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,59 @@ class CloudLibraryStoreTest {
|
||||||
assertEquals(item.playableFiles.single(), target.file)
|
assertEquals(item.playableFiles.single(), target.file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve playback reuses already resolved file url`() = runBlocking {
|
||||||
|
val provider = cloudProvider(id = "premiumize", name = "Premiumize")
|
||||||
|
val api = FakeCloudProviderApi(
|
||||||
|
provider = provider,
|
||||||
|
items = emptyList(),
|
||||||
|
)
|
||||||
|
val store = CloudLibraryStore(
|
||||||
|
credentialsProvider = {
|
||||||
|
listOf(DebridServiceCredential(provider, "token"))
|
||||||
|
},
|
||||||
|
providerApis = listOf(api),
|
||||||
|
)
|
||||||
|
val item = cloudItem(provider, "ready")
|
||||||
|
val file = item.playableFiles.single().copy(playbackUrl = "https://cached.example/video.mkv")
|
||||||
|
|
||||||
|
val result = store.resolvePlayback(item = item, file = file)
|
||||||
|
|
||||||
|
assertTrue(result is CloudLibraryPlaybackResult.Success)
|
||||||
|
assertEquals("https://cached.example/video.mkv", result.url)
|
||||||
|
assertEquals(0, api.resolvePlaybackCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolved playback url is remembered in cloud library state`() {
|
||||||
|
val provider = cloudProvider(id = "torbox", name = "TorBox")
|
||||||
|
val item = cloudItem(provider, "29773238")
|
||||||
|
val file = item.playableFiles.single()
|
||||||
|
val state = CloudLibraryUiState(
|
||||||
|
isLoaded = true,
|
||||||
|
providers = listOf(
|
||||||
|
CloudLibraryProviderState(
|
||||||
|
provider = provider,
|
||||||
|
items = listOf(item),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val updated = state.withResolvedPlaybackUrl(
|
||||||
|
item = item,
|
||||||
|
file = file,
|
||||||
|
url = "https://resolved.example/movie.mkv",
|
||||||
|
)
|
||||||
|
|
||||||
|
val target = assertNotNull(
|
||||||
|
updated.findPlaybackTargetForProgress(
|
||||||
|
contentId = item.stableKey,
|
||||||
|
videoId = item.playbackVideoId(file),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assertEquals("https://resolved.example/movie.mkv", target.file.playbackUrl)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `provider poster urls are mapped for cloud services`() {
|
fun `provider poster urls are mapped for cloud services`() {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|
@ -155,6 +208,9 @@ private class FakeCloudProviderApi(
|
||||||
override val provider: DebridProvider,
|
override val provider: DebridProvider,
|
||||||
private val items: List<CloudLibraryItem>,
|
private val items: List<CloudLibraryItem>,
|
||||||
) : CloudLibraryProviderApi {
|
) : CloudLibraryProviderApi {
|
||||||
|
var resolvePlaybackCalls: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
override suspend fun listItems(apiKey: String): Result<List<CloudLibraryItem>> =
|
override suspend fun listItems(apiKey: String): Result<List<CloudLibraryItem>> =
|
||||||
Result.success(items)
|
Result.success(items)
|
||||||
|
|
||||||
|
|
@ -162,8 +218,10 @@ private class FakeCloudProviderApi(
|
||||||
apiKey: String,
|
apiKey: String,
|
||||||
item: CloudLibraryItem,
|
item: CloudLibraryItem,
|
||||||
file: CloudLibraryFile,
|
file: CloudLibraryFile,
|
||||||
): CloudLibraryPlaybackResult =
|
): CloudLibraryPlaybackResult {
|
||||||
CloudLibraryPlaybackResult.Success(url = "https://example.test/${item.id}/${file.id}")
|
resolvePlaybackCalls += 1
|
||||||
|
return CloudLibraryPlaybackResult.Success(url = "https://example.test/${item.id}/${file.id}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cloudProvider(id: String, name: String): DebridProvider =
|
private fun cloudProvider(id: String, name: String): DebridProvider =
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue