diff --git a/app/src/main/java/com/antoniegil/astronia/player/UrlInterceptor.kt b/app/src/main/java/com/antoniegil/astronia/player/UrlInterceptor.kt index 40d249a..4f1ad3d 100644 --- a/app/src/main/java/com/antoniegil/astronia/player/UrlInterceptor.kt +++ b/app/src/main/java/com/antoniegil/astronia/player/UrlInterceptor.kt @@ -27,7 +27,6 @@ object UrlInterceptor { throw NetworkBlockedException("HTTP $httpCode: Network blocked or restricted") } - val finalUrl = response.request.url.toString() val content = response.body.string() if (!content.trim().startsWith("#EXTM3U")) { @@ -35,14 +34,14 @@ object UrlInterceptor { if (contentLower.startsWith(", + val finalUrl: String + ) + suspend fun parseM3U8FromUrl(url: String): Result> = withContext(Dispatchers.IO) { val httpsUrl = NetworkUtils.convertToHttps(url) try { - val channels = fetchM3U8Channels(httpsUrl) - Result.Success(channels) + val result = fetchM3U8Channels(httpsUrl) + if (result.channels.isEmpty()) { + val singleChannel = listOf( + M3U8Channel( + id = "${result.finalUrl.hashCode()}_0", + name = result.finalUrl.substringAfterLast("/").substringBeforeLast(".").ifEmpty { + result.finalUrl.substringAfterLast("/").substringBefore("?").ifEmpty { "Stream" } + }, + url = result.finalUrl + ) + ) + return@withContext Result.Success(singleChannel) + } + Result.Success(result.channels) } catch (e: Exception) { if (httpsUrl != url) { try { - val channels = fetchM3U8Channels(url) - Result.Success(channels) + val result = fetchM3U8Channels(url) + if (result.channels.isEmpty()) { + val singleChannel = listOf( + M3U8Channel( + id = "${result.finalUrl.hashCode()}_0", + name = result.finalUrl.substringAfterLast("/").substringBeforeLast(".").ifEmpty { + result.finalUrl.substringAfterLast("/").substringBefore("?").ifEmpty { "Stream" } + }, + url = result.finalUrl + ) + ) + return@withContext Result.Success(singleChannel) + } + Result.Success(result.channels) } catch (fallbackException: Exception) { Result.Error(fallbackException, "Failed to fetch M3U8 from URL: ${fallbackException.message}") } @@ -102,7 +131,7 @@ object M3U8Parser { } } - private fun fetchM3U8Channels(url: String): List { + private fun fetchM3U8Channels(url: String): FetchResult { val request = Request.Builder().url(url).build() val response = client.newCall(request).execute() @@ -110,6 +139,8 @@ object M3U8Parser { throw Exception("HTTP ${response.code}") } + val finalUrl = response.request.url.toString() + val contentLength = response.body.contentLength() if (contentLength > PlayerConstants.M3U8_MAX_SIZE_BYTES) { response.close() @@ -173,7 +204,7 @@ object M3U8Parser { } } - return channels + return FetchResult(channels, finalUrl) } private fun extractChannelName(line: String): String { diff --git a/app/src/main/java/com/antoniegil/astronia/viewmodel/PlayerViewModel.kt b/app/src/main/java/com/antoniegil/astronia/viewmodel/PlayerViewModel.kt index 542cffb..4a23a32 100644 --- a/app/src/main/java/com/antoniegil/astronia/viewmodel/PlayerViewModel.kt +++ b/app/src/main/java/com/antoniegil/astronia/viewmodel/PlayerViewModel.kt @@ -107,7 +107,6 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) localPlayer?.stop() viewModelScope.launch { - android.util.Log.d("PlayerViewModel", "loadChannels called: url=$url") _uiState.value = _uiState.value.copy( channels = emptyList(), isLoadingChannels = true, @@ -133,7 +132,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) url.startsWith("rtmp") || url.startsWith("rtsp") -> { repository.parseM3U8FromUrl(url).onSuccess { channels -> parsedChannels = channels - isM3U8Playlist = channels.size > 1 + isM3U8Playlist = channels.size >= 1 }.onError { _, _ -> } } @@ -145,7 +144,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) if (content.contains("#EXTM3U")) { repository.parseM3U8FromContent(content).onSuccess { channels -> parsedChannels = channels - isM3U8Playlist = channels.size > 1 + isM3U8Playlist = channels.size >= 1 } } } @@ -155,7 +154,7 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) url.contains("#EXTM3U") -> { repository.parseM3U8FromContent(url).onSuccess { channels -> parsedChannels = channels - isM3U8Playlist = channels.size > 1 + isM3U8Playlist = channels.size >= 1 } } } @@ -360,10 +359,15 @@ class PlayerViewModel(application: Application) : AndroidViewModel(application) fun saveHistory() { val state = _uiState.value - if (state.playlistUrl.isNotEmpty() && state.videoTitle.isNotEmpty()) { + val watchTime = watchTimeTracker.getAccumulatedTime() + if (watchTime == 0L) { + return + } + val urlToSave = state.playlistUrl.ifEmpty { state.currentChannelUrl } + if (urlToSave.isNotEmpty() && state.videoTitle.isNotEmpty()) { HistoryManager.addOrUpdateHistory( getApplication(), - state.playlistUrl, + urlToSave, state.videoTitle, state.currentChannelUrl, state.currentChannelId