diff --git a/app/src/main/kotlin/com/arflix/tv/data/repository/LauncherContinueWatchingRepository.kt b/app/src/main/kotlin/com/arflix/tv/data/repository/LauncherContinueWatchingRepository.kt index 9ae20af3a..f994f7e8c 100644 --- a/app/src/main/kotlin/com/arflix/tv/data/repository/LauncherContinueWatchingRepository.kt +++ b/app/src/main/kotlin/com/arflix/tv/data/repository/LauncherContinueWatchingRepository.kt @@ -42,7 +42,8 @@ class LauncherContinueWatchingRepository @Inject constructor( private val profileManager: ProfileManager, private val traktRepository: TraktRepository, private val watchHistoryRepository: WatchHistoryRepository, - private val streamRepository: StreamRepository + private val streamRepository: StreamRepository, + private val mediaRepository: MediaRepository ) { companion object { private const val TAG = "LauncherCW" @@ -99,6 +100,7 @@ class LauncherContinueWatchingRepository @Inject constructor( private suspend fun loadPublisherItems(): List { val installedAddons = streamRepository.installedAddons.first() val primaryItems = runCatching { traktRepository.getContinueWatching() }.getOrDefault(emptyList()) + val filteredPrimary = primaryItems.filterNot { item -> SportsAddonCapabilities.isLiveStreamOrSportsItem( mediaType = item.mediaType, @@ -108,43 +110,67 @@ class LauncherContinueWatchingRepository @Inject constructor( addons = installedAddons ) } - if (filteredPrimary.isNotEmpty()) { - return filteredPrimary.take(Constants.MAX_CONTINUE_WATCHING) - } - val historyFallback = runCatching { watchHistoryRepository.getContinueWatching() }.getOrDefault(emptyList()) - return historyFallback - .sortedByDescending { it.updated_at ?: it.paused_at.orEmpty() } - .map { entry -> - ContinueWatchingItem( - id = entry.show_tmdb_id, - title = entry.title.orEmpty(), - mediaType = if (entry.media_type == "tv") MediaType.TV else MediaType.MOVIE, - progress = (entry.progress * 100f).toInt().coerceIn(0, 99), - season = entry.season, - episode = entry.episode, - episodeTitle = entry.episode_title, - posterPath = entry.poster_path, - backdropPath = entry.backdrop_path, - resumePositionSeconds = entry.position_seconds, - durationSeconds = entry.duration_seconds, - streamAddonId = entry.stream_addon_id - ) - } - .filterNot { item -> - SportsAddonCapabilities.isLiveStreamOrSportsItem( - mediaType = item.mediaType, - id = item.id, - streamAddonId = item.streamAddonId, - title = item.title, - addons = installedAddons - ) - } - .distinctBy { "${it.mediaType}:${it.id}:${it.season ?: -1}:${it.episode ?: -1}" } - .take(Constants.MAX_CONTINUE_WATCHING) - } + val selectedItems = if (filteredPrimary.isNotEmpty()) { + filteredPrimary.take(Constants.MAX_CONTINUE_WATCHING) + } else { + val historyFallback = runCatching { watchHistoryRepository.getContinueWatching() }.getOrDefault(emptyList()) + historyFallback + .sortedByDescending { it.updated_at ?: it.paused_at.orEmpty() } + .map { entry -> + ContinueWatchingItem( + id = entry.show_tmdb_id, + title = entry.title.orEmpty(), + mediaType = if (entry.media_type == "tv") MediaType.TV else MediaType.MOVIE, + progress = (entry.progress * 100f).toInt().coerceIn(0, 99), + season = entry.season, + episode = entry.episode, + episodeTitle = entry.episode_title, + posterPath = entry.poster_path, + backdropPath = entry.backdrop_path, + resumePositionSeconds = entry.position_seconds, + durationSeconds = entry.duration_seconds, + streamAddonId = entry.stream_addon_id + ) + } + .filterNot { item -> + SportsAddonCapabilities.isLiveStreamOrSportsItem( + mediaType = item.mediaType, + id = item.id, + streamAddonId = item.streamAddonId, + title = item.title, + addons = installedAddons + ) + } + .distinctBy { "${it.mediaType}:${it.id}:${it.season ?: -1}:${it.episode ?: -1}" } + .take(Constants.MAX_CONTINUE_WATCHING) + } + return selectedItems.map { item -> + val localizedTitle = runCatching { + if (item.mediaType == MediaType.TV) { + mediaRepository.getTvDetails(item.id).title + } else { + mediaRepository.getMovieDetails(item.id).title + } + }.getOrNull()?.takeIf { it.isNotBlank() } ?: item.title + + val resolvedEpisodeTitle = runCatching { + if (item.mediaType == MediaType.TV && item.season != null && item.episode != null) { + val episodes = mediaRepository.getSeasonEpisodes(item.id, item.season) + episodes.firstOrNull { it.episodeNumber == item.episode }?.name + } else { + null + } + }.getOrNull()?.takeIf { it.isNotBlank() } ?: item.episodeTitle + item.copy( + title = localizedTitle, + episodeTitle = resolvedEpisodeTitle + ) + } + } + @RequiresApi(Build.VERSION_CODES.O) private fun syncPublishedRows(items: List) { val channelId = ensurePreviewChannel() ?: return