From 1bc17dae1040743f55437ce59ca77ca2d9cece6e Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 16 Nov 2023 16:27:43 +0100 Subject: [PATCH 1/5] Trailers: extract to TmdbTools2, add for shows. --- .../movies/details/MovieTrailersLoader.kt | 50 +--------- .../seriesguide/tmdbapi/TmdbTools2.kt | 93 +++++++++++++++++++ 2 files changed, 95 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/battlelancer/seriesguide/movies/details/MovieTrailersLoader.kt b/app/src/main/java/com/battlelancer/seriesguide/movies/details/MovieTrailersLoader.kt index dc4967541e..bce51195a1 100644 --- a/app/src/main/java/com/battlelancer/seriesguide/movies/details/MovieTrailersLoader.kt +++ b/app/src/main/java/com/battlelancer/seriesguide/movies/details/MovieTrailersLoader.kt @@ -4,13 +4,8 @@ package com.battlelancer.seriesguide.movies.details import android.content.Context -import com.battlelancer.seriesguide.SgApp -import com.battlelancer.seriesguide.movies.MoviesSettings.getMoviesLanguage -import com.battlelancer.seriesguide.util.Errors +import com.battlelancer.seriesguide.tmdbapi.TmdbTools2 import com.uwetrottmann.androidutils.GenericSimpleLoader -import com.uwetrottmann.tmdb2.entities.Videos -import com.uwetrottmann.tmdb2.enumerations.VideoType -import timber.log.Timber /** * Loads a YouTube movie trailer from TMDb. Tries to get a local trailer, if not falls back to @@ -20,48 +15,7 @@ class MovieTrailersLoader(context: Context, private val tmdbId: Int) : GenericSimpleLoader(context) { override fun loadInBackground(): String? { - // try to get a local trailer - val trailer = getTrailerVideoId( - getMoviesLanguage(context), "get local movie trailer" - ) - if (trailer != null) { - return trailer - } - Timber.d("Did not find a local movie trailer.") - - // fall back to default language trailer - return getTrailerVideoId(null, "get default movie trailer") - } - - private fun getTrailerVideoId(language: String?, action: String): String? { - val moviesService = SgApp.getServicesComponent(context).moviesService() - try { - val response = moviesService.videos(tmdbId, language).execute() - if (response.isSuccessful) { - return extractTrailer(response.body()) - } else { - Errors.logAndReport(action, response) - } - } catch (e: Exception) { - Errors.logAndReport(action, e) - } - return null + return TmdbTools2().getMovieTrailerYoutubeId(context, tmdbId) } - private fun extractTrailer(videos: Videos?): String? { - val results = videos?.results - if (results == null || results.size == 0) { - return null - } - - // Pick the first YouTube trailer - for (video in results) { - val videoId = video.key - if (video.type == VideoType.TRAILER && "YouTube" == video.site - && !videoId.isNullOrEmpty()) { - return videoId - } - } - return null - } } \ No newline at end of file diff --git a/app/src/main/java/com/battlelancer/seriesguide/tmdbapi/TmdbTools2.kt b/app/src/main/java/com/battlelancer/seriesguide/tmdbapi/TmdbTools2.kt index ef298f158e..2f41f8127a 100644 --- a/app/src/main/java/com/battlelancer/seriesguide/tmdbapi/TmdbTools2.kt +++ b/app/src/main/java/com/battlelancer/seriesguide/tmdbapi/TmdbTools2.kt @@ -5,6 +5,7 @@ package com.battlelancer.seriesguide.tmdbapi import android.content.Context import com.battlelancer.seriesguide.SgApp +import com.battlelancer.seriesguide.movies.MoviesSettings import com.battlelancer.seriesguide.provider.SgRoomDatabase import com.battlelancer.seriesguide.util.Errors import com.battlelancer.seriesguide.util.isRetryError @@ -26,16 +27,19 @@ import com.uwetrottmann.tmdb2.entities.TmdbDate import com.uwetrottmann.tmdb2.entities.TvEpisode import com.uwetrottmann.tmdb2.entities.TvShow import com.uwetrottmann.tmdb2.entities.TvShowResultsPage +import com.uwetrottmann.tmdb2.entities.Videos import com.uwetrottmann.tmdb2.entities.WatchProviders import com.uwetrottmann.tmdb2.enumerations.AppendToResponseItem import com.uwetrottmann.tmdb2.enumerations.ExternalSource import com.uwetrottmann.tmdb2.enumerations.SortBy +import com.uwetrottmann.tmdb2.enumerations.VideoType import com.uwetrottmann.tmdb2.services.PeopleService import com.uwetrottmann.tmdb2.services.TvEpisodesService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import retrofit2.awaitResponse import retrofit2.create +import timber.log.Timber import java.util.Calendar import java.util.Date @@ -224,6 +228,95 @@ class TmdbTools2 { return null } + fun getShowTrailerYoutubeId( + context: Context, + showTmdbId: Int, + languageCode: String + ): Result { + val action = "get show trailer" + val tmdb = SgApp.getServicesComponent(context.applicationContext).tmdb() + return runCatching { + tmdb.tvService() + .videos(showTmdbId, languageCode) + .execute() + }.mapError { + Errors.logAndReport(action, it) + if (it.isRetryError()) TmdbRetry else TmdbStop + }.andThen { + if (it.isSuccessful) { + val results = it.body()?.results + if (results != null) { + return@andThen Ok(extractTrailer(it.body())) + } else { + Errors.logAndReport(action, it, "results is null") + } + } else { + Errors.logAndReport(action, it) + } + return@andThen Err(TmdbStop) + } + } + + /** + * Loads a YouTube movie trailer from TMDb. Tries to get a local trailer, if not falls back to + * English. + */ + fun getMovieTrailerYoutubeId( + context: Context, + movieTmdbId: Int + ): String? { + // try to get a local trailer + val trailer = getMovieTrailerYoutubeId( + context, movieTmdbId, MoviesSettings.getMoviesLanguage(context), "get local movie trailer" + ) + if (trailer != null) { + return trailer + } + Timber.d("Did not find a local movie trailer.") + + // fall back to default language trailer + return getMovieTrailerYoutubeId( + context, movieTmdbId, null, "get default movie trailer" + ) + } + + private fun getMovieTrailerYoutubeId( + context: Context, + movieTmdbId: Int, + languageCode: String?, + action: String + ): String? { + val moviesService = SgApp.getServicesComponent(context).moviesService() + try { + val response = moviesService.videos(movieTmdbId, languageCode).execute() + if (response.isSuccessful) { + return extractTrailer(response.body()) + } else { + Errors.logAndReport(action, response) + } + } catch (e: Exception) { + Errors.logAndReport(action, e) + } + return null + } + + private fun extractTrailer(videos: Videos?): String? { + val results = videos?.results + if (results == null || results.size == 0) { + return null + } + + // Pick the first YouTube trailer + for (video in results) { + val videoId = video.key + if (video.type == VideoType.TRAILER && "YouTube" == video.site + && !videoId.isNullOrEmpty()) { + return videoId + } + } + return null + } + suspend fun getShowWatchProviders( tmdb: Tmdb, language: String, From 7993945d3e6dc48621f1a15a31111d3c4fece6b4 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 16 Nov 2023 16:42:37 +0100 Subject: [PATCH 2/5] Trailers: add trailer button to add show dialog. --- .../search/discover/AddShowDialogFragment.kt | 12 ++++++++++ .../search/discover/AddShowDialogViewModel.kt | 8 +++++++ app/src/main/res/layout/dialog_addshow.xml | 23 ++++++++++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogFragment.kt b/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogFragment.kt index 656a8b53dd..908e483f48 100644 --- a/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogFragment.kt +++ b/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogFragment.kt @@ -26,6 +26,7 @@ import com.battlelancer.seriesguide.ui.OverviewActivity import com.battlelancer.seriesguide.ui.dialogs.L10nDialogFragment import com.battlelancer.seriesguide.util.ImageTools import com.battlelancer.seriesguide.util.LanguageTools +import com.battlelancer.seriesguide.util.ServiceUtils import com.battlelancer.seriesguide.util.TextTools import com.battlelancer.seriesguide.util.TimeTools import com.battlelancer.seriesguide.util.ViewTools @@ -152,6 +153,17 @@ class AddShowDialogFragment : AppCompatDialogFragment() { this.binding?.textViewAddDescription?.isGone = false populateShowViews(show) } + model.trailer.observe(this) { videoId -> + this.binding?.buttonAddTrailer?.apply { + if (videoId != null) { + setOnClickListener { ServiceUtils.openYoutube(videoId, requireContext()) } + isEnabled = true + } else { + setOnClickListener(null) + isEnabled = false + } + } + } model.watchProvider.observe(this) { watchInfo -> this.binding?.buttonAddStreamingSearch?.let { val providerInfo = StreamingSearch.configureButton(it, watchInfo, false) diff --git a/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogViewModel.kt b/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogViewModel.kt index f860b81cf6..e190266d6e 100644 --- a/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogViewModel.kt +++ b/app/src/main/java/com/battlelancer/seriesguide/shows/search/discover/AddShowDialogViewModel.kt @@ -17,6 +17,7 @@ import com.battlelancer.seriesguide.SgApp import com.battlelancer.seriesguide.shows.database.SgShow2 import com.battlelancer.seriesguide.shows.tools.GetShowTools.GetShowError.GetShowDoesNotExist import com.battlelancer.seriesguide.streaming.StreamingSearch +import com.battlelancer.seriesguide.tmdbapi.TmdbTools2 import com.github.michaelbull.result.onFailure import com.github.michaelbull.result.onSuccess import kotlinx.coroutines.Dispatchers @@ -35,6 +36,7 @@ class AddShowDialogViewModel( val languageCode = MutableLiveData() val showDetails: LiveData + val trailer: LiveData init { // Set original value for region. @@ -66,6 +68,12 @@ class AddShowDialogViewModel( } } } + this.trailer = languageCode.switchMap { languageCode -> + liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) { + TmdbTools2().getShowTrailerYoutubeId(application, showTmdbId, languageCode) + .onSuccess { emit(it) } + } + } } private val watchInfoMediator = MediatorLiveData().apply { diff --git a/app/src/main/res/layout/dialog_addshow.xml b/app/src/main/res/layout/dialog_addshow.xml index ffc6488018..cf1b40d7dc 100644 --- a/app/src/main/res/layout/dialog_addshow.xml +++ b/app/src/main/res/layout/dialog_addshow.xml @@ -1,4 +1,8 @@ + + + + +