diff --git a/app/src/main/java/com/nuvio/tv/data/mapper/StreamMapper.kt b/app/src/main/java/com/nuvio/tv/data/mapper/StreamMapper.kt index 33e9332c..7b6a23ff 100644 --- a/app/src/main/java/com/nuvio/tv/data/mapper/StreamMapper.kt +++ b/app/src/main/java/com/nuvio/tv/data/mapper/StreamMapper.kt @@ -18,7 +18,8 @@ fun StreamDto.toDomain(addonName: String, addonLogo: String?): Stream = Stream( externalUrl = externalUrl, behaviorHints = behaviorHints?.toDomain(), addonName = addonName, - addonLogo = addonLogo + addonLogo = addonLogo, + sources = sources ) fun BehaviorHintsDto.toDomain(): StreamBehaviorHints = StreamBehaviorHints( diff --git a/app/src/main/java/com/nuvio/tv/domain/model/Stream.kt b/app/src/main/java/com/nuvio/tv/domain/model/Stream.kt index 99cb137f..e55347ea 100644 --- a/app/src/main/java/com/nuvio/tv/domain/model/Stream.kt +++ b/app/src/main/java/com/nuvio/tv/domain/model/Stream.kt @@ -17,7 +17,8 @@ data class Stream( val externalUrl: String?, val behaviorHints: StreamBehaviorHints?, val addonName: String, - val addonLogo: String? + val addonLogo: String?, + val sources: List? = null ) { /** * Returns the primary stream source URL diff --git a/app/src/main/java/com/nuvio/tv/ui/navigation/NuvioNavHost.kt b/app/src/main/java/com/nuvio/tv/ui/navigation/NuvioNavHost.kt index d22675fb..de38f923 100644 --- a/app/src/main/java/com/nuvio/tv/ui/navigation/NuvioNavHost.kt +++ b/app/src/main/java/com/nuvio/tv/ui/navigation/NuvioNavHost.kt @@ -479,7 +479,8 @@ fun NuvioNavHost( addonLogo = playbackInfo.addonLogo, streamDescription = playbackInfo.streamDescription, infoHash = playbackInfo.infoHash, - fileIdx = playbackInfo.fileIdx + fileIdx = playbackInfo.fileIdx, + sources = playbackInfo.sources ) ) } @@ -517,7 +518,8 @@ fun NuvioNavHost( addonLogo = playbackInfo.addonLogo, streamDescription = playbackInfo.streamDescription, infoHash = playbackInfo.infoHash, - fileIdx = playbackInfo.fileIdx + fileIdx = playbackInfo.fileIdx, + sources = playbackInfo.sources ) ) { popUpTo(Screen.Stream.route) { inclusive = true } diff --git a/app/src/main/java/com/nuvio/tv/ui/navigation/Screen.kt b/app/src/main/java/com/nuvio/tv/ui/navigation/Screen.kt index a9b04010..31a10159 100644 --- a/app/src/main/java/com/nuvio/tv/ui/navigation/Screen.kt +++ b/app/src/main/java/com/nuvio/tv/ui/navigation/Screen.kt @@ -62,7 +62,7 @@ sealed class Screen(val route: String) { return "stream/$encodedVideoId/$encodedContentTypePath/$encodedTitle?poster=$encodedPoster&backdrop=$encodedBackdrop&logo=$encodedLogo&season=${season ?: ""}&episode=${episode ?: ""}&episodeName=$encodedEpisodeName&genres=$encodedGenres&year=$encodedYear&contentId=$encodedContentId&contentName=$encodedContentName&runtime=${runtime ?: ""}&manualSelection=$manualSelection&returnToDetailOnBack=$returnToDetailOnBack&returnToHomeOnBack=$returnToHomeOnBack&startFromBeginning=$startFromBeginning" } } - data object Player : Screen("player/{streamUrl}/{title}?streamName={streamName}&year={year}&headers={headers}&contentId={contentId}&contentType={contentType}&contentName={contentName}&poster={poster}&backdrop={backdrop}&logo={logo}&videoId={videoId}&season={season}&episode={episode}&episodeTitle={episodeTitle}&bingeGroup={bingeGroup}&autoPlayNav={autoPlayNav}&returnToDetailOnBack={returnToDetailOnBack}&returnToHomeOnBack={returnToHomeOnBack}&filename={filename}&videoHash={videoHash}&videoSize={videoSize}&startFromBeginning={startFromBeginning}&addonName={addonName}&addonLogo={addonLogo}&streamDescription={streamDescription}&infoHash={infoHash}&fileIdx={fileIdx}") { + data object Player : Screen("player/{streamUrl}/{title}?streamName={streamName}&year={year}&headers={headers}&contentId={contentId}&contentType={contentType}&contentName={contentName}&poster={poster}&backdrop={backdrop}&logo={logo}&videoId={videoId}&season={season}&episode={episode}&episodeTitle={episodeTitle}&bingeGroup={bingeGroup}&autoPlayNav={autoPlayNav}&returnToDetailOnBack={returnToDetailOnBack}&returnToHomeOnBack={returnToHomeOnBack}&filename={filename}&videoHash={videoHash}&videoSize={videoSize}&startFromBeginning={startFromBeginning}&addonName={addonName}&addonLogo={addonLogo}&streamDescription={streamDescription}&infoHash={infoHash}&fileIdx={fileIdx}&sources={sources}") { private fun encode(value: String): String = URLEncoder.encode(value, "UTF-8").replace("+", "%20") @@ -94,7 +94,8 @@ sealed class Screen(val route: String) { addonLogo: String? = null, streamDescription: String? = null, infoHash: String? = null, - fileIdx: Int? = null + fileIdx: Int? = null, + sources: List? = null ): String { val encodedUrl = encode(streamUrl) val encodedTitle = encode(title) @@ -118,7 +119,8 @@ sealed class Screen(val route: String) { val encodedAddonLogo = addonLogo?.let { encode(it) } ?: "" val encodedStreamDescription = streamDescription?.let { encode(it) } ?: "" val encodedInfoHash = infoHash ?: "" - return "player/$encodedUrl/$encodedTitle?streamName=$encodedStreamName&year=$encodedYear&headers=$encodedHeaders&contentId=$encodedContentId&contentType=$encodedContentType&contentName=$encodedContentName&poster=$encodedPoster&backdrop=$encodedBackdrop&logo=$encodedLogo&videoId=$encodedVideoId&season=${season ?: ""}&episode=${episode ?: ""}&episodeTitle=$encodedEpisodeTitle&bingeGroup=$encodedBingeGroup&autoPlayNav=$autoPlayNav&returnToDetailOnBack=$returnToDetailOnBack&returnToHomeOnBack=$returnToHomeOnBack&filename=$encodedFilename&videoHash=$encodedVideoHash&videoSize=${videoSize ?: ""}&startFromBeginning=$startFromBeginning&addonName=$encodedAddonName&addonLogo=$encodedAddonLogo&streamDescription=$encodedStreamDescription&infoHash=$encodedInfoHash&fileIdx=${fileIdx ?: ""}" + val encodedSources = sources?.let { encode(org.json.JSONArray(it).toString()) } ?: "" + return "player/$encodedUrl/$encodedTitle?streamName=$encodedStreamName&year=$encodedYear&headers=$encodedHeaders&contentId=$encodedContentId&contentType=$encodedContentType&contentName=$encodedContentName&poster=$encodedPoster&backdrop=$encodedBackdrop&logo=$encodedLogo&videoId=$encodedVideoId&season=${season ?: ""}&episode=${episode ?: ""}&episodeTitle=$encodedEpisodeTitle&bingeGroup=$encodedBingeGroup&autoPlayNav=$autoPlayNav&returnToDetailOnBack=$returnToDetailOnBack&returnToHomeOnBack=$returnToHomeOnBack&filename=$encodedFilename&videoHash=$encodedVideoHash&videoSize=${videoSize ?: ""}&startFromBeginning=$startFromBeginning&addonName=$encodedAddonName&addonLogo=$encodedAddonLogo&streamDescription=$encodedStreamDescription&infoHash=$encodedInfoHash&fileIdx=${fileIdx ?: ""}&sources=$encodedSources" } } data object Search : Screen("search") diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerNavigationArgs.kt b/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerNavigationArgs.kt index 5539607b..75af9258 100644 --- a/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerNavigationArgs.kt +++ b/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerNavigationArgs.kt @@ -1,6 +1,7 @@ package com.nuvio.tv.ui.screens.player import androidx.lifecycle.SavedStateHandle +import org.json.JSONArray import java.net.URLDecoder internal data class PlayerNavigationArgs( @@ -28,8 +29,23 @@ internal data class PlayerNavigationArgs( val addonLogo: String?, val streamDescription: String?, val infoHash: String?, - val fileIdx: Int? + val fileIdx: Int?, + val sourcesJson: String? ) { + val torrentTrackers: List + get() { + val json = sourcesJson ?: return emptyList() + return try { + val arr = JSONArray(json) + (0 until arr.length()) + .mapNotNull { arr.optString(it) } + .filter { it.startsWith("tracker:") } + .map { it.removePrefix("tracker:") } + } catch (_: Exception) { + emptyList() + } + } + companion object { fun from(savedStateHandle: SavedStateHandle): PlayerNavigationArgs { fun decodedOrNull(key: String): String? { @@ -63,7 +79,8 @@ internal data class PlayerNavigationArgs( addonLogo = decodedOrNull("addonLogo"), streamDescription = decodedOrNull("streamDescription"), infoHash = savedStateHandle.get("infoHash")?.takeIf { it.isNotEmpty() }, - fileIdx = savedStateHandle.get("fileIdx")?.toIntOrNull() + fileIdx = savedStateHandle.get("fileIdx")?.toIntOrNull(), + sourcesJson = decodedOrNull("sources") ) } } diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt b/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt index d0def6c8..75e5cf33 100644 --- a/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt +++ b/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt @@ -667,7 +667,8 @@ class StreamScreenViewModel @Inject constructor( addonName = stream.addonName, addonLogo = stream.addonLogo, streamDescription = stream.description, - fileIdx = stream.fileIdx + fileIdx = stream.fileIdx, + sources = stream.sources ) val url = playbackInfo.url @@ -724,5 +725,6 @@ data class StreamPlaybackInfo( val addonName: String? = null, val addonLogo: String? = null, val streamDescription: String? = null, - val fileIdx: Int? = null + val fileIdx: Int? = null, + val sources: List? = null )